Unconditional Contest

Win A Free Book
A while back, I had a little piece on getting rid of conditional statements. Since that time, I’ve been writing scripts that have reduced the number of conditionals significantly, and we thought it might be fun to have a little contest with the prize, a free, signed copy of our design pattern book.

Alternatives to Conditional Statements

In thinking about this issue, the Boolean is the key–much in the same way as it is with conditional statements. One way to handle a simple if..else conditional is by multiplying a Boolean changed to an unsigned integer. For example, if you want to use the color black and some other color to signify a state you could have something like the following:

var clr:uint=0x00aa00;
var cond:uint;
var good:Boolean;
good=e.info.code=="NetConnection.Connect.Success";
cond=uint(good);
clr=clr * cond;
//Now the color value can be passed as a parameter to a "connection light."

The clr variable can now be green or black. If the connection is successful, the cond variable resolves to 1; otherwise it resolves to 0. If you multiply by 0, the results are always 0. Also, 1 multiplied by any number always resolves as the original number. Since the color black is 0 (0×000000), if the connection is not successful the color black is generated, but if it is successful and generates a 1, it multiplies the green value (0×00aa00) by 1 and gets 0×00aa00. The alternative is something like:

var clr:uint
if(e.info.code=="NextConnection.Connect.Successful")
{
     clr=0x00aa00;
}
{
else
{
      clr=0x0000;
}

Of course a ternary would have been even quicker–coding wise, but it probably has a similar under-the-hood cost and encapsulation break out.

Non-Conditional Switch Statement

In playing around with conditionals, I decided to see if I could create a switch-like statement–or set of statements that worked like switch. The following is what I came up with:

package 
{
	import flash.display.Sprite;
	import flash.display.Shape;
 
	public class NoConSwitch extends Sprite
	{
		private var freeSwitch:String;
		private var freeSet:Array;
		private var freeCase:uint;
		private var rec:Shape;
 
		public function NoConSwitch ()
		{
			freeSet=[0x0000, 0xaa0000,0x00aa00,0x0000aa,0x800080];
 
			freeSwitch="Green";
			freeSwitch=freeSwitch.toLowerCase();
 
			freeCase=uint(freeSwitch=="red")*1;
			freeCase+=uint(freeSwitch=="green")*2;
			freeCase+=uint(freeSwitch=="blue")*3;
			freeCase+=uint(freeSwitch=="purple")*4;
 
			doRectangle (freeSet[freeCase]);
		}
 
		private function doRectangle (clr:uint)
		{
			rec=new Shape();
			rec.graphics.beginFill (clr);
			rec.graphics.lineStyle (.25,0x000000);
			rec.graphics.drawRect (80,40,400,300);
			addChild (rec);
		}
	}
}

Granted that my non-conditional switch statement may not have the flexibility of a standard switch statement, but it does the job I’d normally do with a switch statement.

Back to the contest

I’m sure that anyone reading this can come up with more ways to get around using conditional statements. So to enter the contest, just use the Comments section of this Post to respond with an idea of your own (including a working example in ActionScript 3.0) that shows an alternative to a conditional statement that does the same thing without using a conditional statement. You can enter as many times as you want by January 31, 2008. On February 1, we’ll announce the winner and send a book to you.

The Unconditional Contest by Bill Sanders, unless otherwise expressly stated, is licensed under a Creative Commons Attribution 3.0 United States License.

16 Responses to “Unconditional Contest”


  1. 1 Keith Peters

    I think one of the best ways to avoid conditionals is by mapping the possible conditions to specific data. Here’s a simple example:

    import flash.ui.Keyboard;
     
    var keys:Array = new Array();
    keys[Keyboard.UP] = new Point(0, -5);
    keys[Keyboard.DOWN] = new Point(0, 5);
    keys[Keyboard.LEFT] = new Point(-5, 0);
    keys[Keyboard.RIGHT] = new Point(5, 0);
     
    stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
     
    function onKeyDown(event:KeyboardEvent):void
    {
    	if(keys[event.keyCode] != null)
    	{
    		mc.x += keys[event.keyCode].x;
    		mc.y += keys[event.keyCode].y;
    	}
    }
  2. 2 Keith Peters

    Or you could go all out and map functions themselves:

    import flash.ui.Keyboard;
     
    var keys:Array = new Array();
    keys[Keyboard.UP] = moveUp;
    keys[Keyboard.DOWN] = moveDown;
    keys[Keyboard.LEFT] = moveLeft;
    keys[Keyboard.RIGHT] = moveRight;
     
    stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
     
    function onKeyDown(event:KeyboardEvent):void
    {
    	if(keys[event.keyCode] != null)
    	{
    		keys[event.keyCode]();
    	}
    }
     
    function moveUp():void
    {
    	mc.y -= 5;
    }
    function moveDown():void
    {
    	mc.y += 5;
    }
    function moveLeft():void
    {
    	mc.x -= 5;
    }
    function moveRight():void
    {
    	mc.x += 5;
    }

    This looks kind of ugly in this simple example, but is essentially what things like service locators do.

  3. 3 Keith Peters

    Just realized I left a conditional in there. You can substitute the if with a try catch, like so:

    function onKeyDown(event:KeyboardEvent):void {
    	try
    	{
    		keys[event.keyCode]();
    	}
    	catch(e:TypeError)
    	{
    	}
    }
  4. 4 Dusty

    Keith:

    Some guys at Realeyes did some testing, and found that try statements were much slower than any other statements. If we’re just trying to get rid of if statements, but still need to check for null, a while(keys[event.keyCode] != null) would give much better performance.

    However, try and while statements used in this fashion are the same thing as a conditional, in an academic sense, so it may be better to initialize every possible key value upon initialization to ensure that there is no null value. This would greatly simplify the logic.

  5. 5 robs

    omg bill

    are you serious?? sorry, but this is the worst code i’ve ever seen. :(
    this is really bad practice and certainly not the intention of the state design pattern.

  6. 6 Bill Sanders

    Dusty,

    It’d be great if you guys at Realeyes provided an entry in our Unconditional Contest.

    Bill

  7. 7 Bill Sanders

    Hi Robs,

    I may have skewed the whole idea of substituting alternatives to conventional conditional statements with some other kind of thinking. I do not believe I ever said that this was an intention of State Design Patterns. Rather, they stood as a common example where state classes with a full set of different states could be found without relying on conditional statements. Jonathan Kaye had a great comment on that.

    For a second (or even longer) forget about State DPs. Rather, consider problem-solving without using conditional statements. What are some different ways you could do that? This is a heuristic exercise to come up with better solutions and algorithms.

    As for the “worst code” you’ve ever seen–that’s not the point. See if you can create any kind of statement that works to have the branching effect of a conditional without using a conditional statement. It’s harder than you may think.

    Thanks,
    Bill

  8. 8 roozbeh
    var i:int=0;
    var down:int=0;
    var step:int=1;
    var max:int=100;
    var min:int=-100;
     
    addEventListener(Event.ENTER_FRAME,onEnter);
     
    function onEnter(event:Event):void
    {
    	upbtn.addEventListener(MouseEvent.MOUSE_DOWN,_down);
    	upbtn.addEventListener(MouseEvent.MOUSE_UP,_up);
    	downbtn.addEventListener(MouseEvent.MOUSE_DOWN,_down);
    	downbtn.addEventListener(MouseEvent.MOUSE_UP,_up);
     
    	i+=(down)*int(i+down=min);
    	tf.text=i.toString();
    }
     
    function _down(event:MouseEvent):void
    {
    	down=((int(event.target.name=="upbtn")*step)+(int(event.target.name=="downbtn")*-step));
    }
    function _up(event:Event):void
    {
     
    	down=0;
    }
  9. 9 roozbeh

    I guess some characters (greater than, less than, and,..) are eliminated from my code which seems to be due to avoiding XSS. I have uploaded the .fla :

    var i:int=0;
    var down:int=0;
    var step:int=1;
    var max:int=100;
    var min:int=-100;
     
    addEventListener (Event.ENTER_FRAME,onEnter);
     
    function onEnter (event:Event):void
    {
    	upbtn.addEventListener (MouseEvent.MOUSE_DOWN,_down);
    	upbtn.addEventListener (MouseEvent.MOUSE_UP,_up);
    	downbtn.addEventListener (MouseEvent.MOUSE_DOWN,_down);
    	downbtn.addEventListener (MouseEvent.MOUSE_UP,_up);
     
    	i+=(down)*int(i+down<=max&&i+down>=min);
    	tf.text=i.toString();
    }
     
    function _down (event:MouseEvent):void
    {
    	down=((int(event.target.name=="upbtn")*step)+(int(event.target.name=="downbtn")*-step));
    }
    function _up (event:Event):void
    {
     
    	down=0;
    }

    http://rapidshare.com/files/82584763/roozbeh.fla.html

  10. 10 Harry B. Garland

    I was looking at this line of code that attempts to evade conditionals:

    down=((int(event.target.name=="upbtn")*step)
         +(int(event.target.name=="downbtn")*-step))

    It does not evade conditionals, it just simply rephrases conditionals. It still contains a “==” and that is a conditional. The correct way to express that code is this:

    if(event.target.name=="upbtn")
       down=step
    else if(event.target.name=="downbtn")
       down=-step
    else
       down=0

    You gain nothing by trying to stuff lots of functionality on a single line of code. In fact, by putting on one line of code, the program will always execute 2 conditionals (checking for upbtn and downbtn), but by using the “if” statement, it will only check the downbtn if the upbtn conditional is false. And it does not go through the extra step of typecasting a boolean into an integer.

    A better way yet is to create a different listener function for up vs. down so that you really can eliminate the conditional.

  11. 11 Bill Sanders

    Hi Harry,

    Your visit is an honor, and I’m glad you could drop by.

    I’m probably at fault for not clarifying better my attempt to look at problem solving without using conditionals. It certainly was not to save coding (or stuff less or more in a line.) One of the criticisms of the State DP is that it takes a lot of classes and coding in the absence of conditional statements. The whole exercise is a heuristic one to create better algorithms which I picked up in an OOPSLA conference.

    More interesting is your comment about the equality operator being a conditional. I’ve always considered it a Boolean, but in an expression, I suppose it might be a conditional.

    var x:uint = 5;
    var w:uint = 7;
    var z:uint = 5;

    x==w evaluates to false
    x==z evaluates to true

    A conditional would be:

    if(x==w)
    {
        someVar=ture;
    }
    else
    {
       someVar=false;
    }

    However, you’re saying that the equality operator performs a conditional, and it seems to. In effect the equality operator is saying:

    “If a and b are equal, then send out true, else, they get a false”

    This feature is masked because the equality operator is often part of the if/else statement.

    Nice.

    Bill

  12. 12 roozbeh

    just tell me what part of the code you think somehow uses a condition and I will eliminate it :)

    var i:Number=0;
    var down:Number=0;
    var step:Number=1;
    var max:Number=100;
    var min:Number=0;
     
    addEventListener(Event.ENTER_FRAME,onEnter);
     
    function onEnter(event:Event):void
    {
     
    	//upbtn and downbtn are movieclips
    	upbtn.addEventListener(MouseEvent.MOUSE_DOWN,_down);
    	upbtn.addEventListener(MouseEvent.MOUSE_UP,_up);
    	upbtn.addEventListener(MouseEvent.ROLL_OUT,_up);
    	downbtn.addEventListener(MouseEvent.MOUSE_DOWN,_down);
    	downbtn.addEventListener(MouseEvent.MOUSE_UP,_up);
    	downbtn.addEventListener(MouseEvent.ROLL_OUT,_up);
     
    	upbtn.buttonMode=true;
    	downbtn.buttonMode=true;
     
    	i+=(down)*int(i+down<=max&&i+down>=min);
    	tf.text=String(i);
     
    	upbtn["k"]=+1;
    	downbtn["k"]=-1;
     
    }
     
    function _down(event:MouseEvent):void
    {
    	down=(event.target.k*step);
    }
    function _up(event:Event):void
    {
     
    	down=0;
    }
  13. 13 john page
    /* work around for else if conditional */
     
    //Ok, so this only works if you append a zero or one
    //to the end of your string. but it does get around the 'if else' dont it?
    //yes its not very fancy...but Thanks for letting me participate.
    //Best, John Page
     
    var test:String = "test me"+1;
     
    function BooleanFactory(arg):Number{
     
    	var State=0;
     
    	for(var i=0; i&lt;arg.length; i++){
    		if(arg.substr(-1) == 1){
    			State=1;
    			}
    		}
    		trace('State '+State)
    		return State;
    };
     
     
    circumventConditional();
     
    function circumventConditional(){
     
    		var c:Number = BooleanFactory(test);
     
    		c * 1
    		var a = 1;
     
    		while(a == c){
    		trace('State == true, trace called, State value=  '+c)
    		break;
    		}
     
    		while(a != c){
    		trace('State == false, call some other function instead, State value= '+c);
    		break;
    		}
     
     
    };
  14. 14 john page
    /* work around for else if conditional */
     
    //Ok, so this only works if you append a zero or one
    //to the end of your string. but it does get around the ‘if else’ dont it?
    //yes its not very fancy…but Thanks for letting me participate.
    //Best, John Page
     
    //DUH!, just realized I dont need c * 1
     
    var test:String = “test me”+1;
     
    function BooleanFactory(arg):Number{
     
    var State=0;
     
    for(var i=0; i&lt;arg.length; i++){
    if(arg.substr(-1) == 1){
    State=1;
    }
    }
    trace(’State ‘+State)
    return State;
    };
     
    circumventConditional();
     
    function circumventConditional(){
     
    var c:Number = BooleanFactory(test);
     
    var a = 1;
     
    while(a == c){
    trace(’State == true, trace called, State value= ‘+c)
    break;
    }
     
    while(a != c){
    trace(’State == false, call some other function instead, State value= ‘+c);
    break;
    }
     
    };
  15. 15 john

    Ok, sorry for so many posts…. yeah its the code of a maniac hehe… anyways I i tried & fixed it .. realized I didnt need alot of things…Its a great exercise in that it makes you think…it really is not easy…

    //Thanks, John Page
     
    var test:String = "test me"+1;
     
    function BooleanFactory(arg):Number{
     
    		var State=0;
     
    		if(arg.substr(-1) == 1){
    			State=1;
    		}
     
    		return State;
    };
     
     
    circumventConditional();
     
    function circumventConditional(){
     
    		var c:Number = BooleanFactory(test);
     
    		var a = 1;
     
    		while(a * c){
    		trace('State == true, trace called, State value=  '+c)
    		break;
    		}
     
    		while(a &gt; c){
    		trace('State == false, call some other function instead, State value= '+c);
    		break;
    		}
     
     
    };
  16. 16 john page

    AS3 example I edited from tutorial….

    package{

    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;

    //abstract class

    public class AnimatingProperties extends Sprite{

    private var _sprite:Sprite;
    private var _k:Number=0.1;
    private var _damp:Number=0.9;
    private var _scaleVel:Number=0;
    private var _targetScale:Number=1;
    private var _click:Number=0;

    public function AS3CB(){

    _sprite = new Sprite();
    _sprite.graphics.beginFill(0×0000,100);
    _sprite.graphics.drawRect(-50,-50,100,100);
    _sprite.graphics.endFill();
    _sprite.x=100;
    _sprite.y=100;
    addChild(_sprite);
    addEventListener(Event.ENTER_FRAME,onEnterFrame);
    _sprite.addEventListener(MouseEvent.CLICK,onClick);
    };

    public function onEnterFrame(event:Event):void{
    _scaleVel += (_targetScale - _sprite.scaleX) * _k;
    _sprite.scaleX += _scaleVel;
    _sprite.scaleY = _sprite.scaleX;
    _scaleVel *= _damp;
    };

    public function onClick(event:MouseEvent):void{

    /**———TRYING TO AVOID USING IF ELSE ETC————**/
    _click++;

    var b = _click >= 2;

    _targetScale = _targetScale * 2 - .5

    while(b){
    _targetScale -= _targetScale -= .5 * 2;
    _click = 0;
    break;
    }

    };

    }
    }

Leave a Reply