What if ActionScript 3.0 had no Conditional Statements? : Part I

Think in Non-Linear Concepts
Other than the fact that nested conditionals can create the worst kind of object binding as each condition sends the program further down the binding rabbit hole, we seem to really need them for working out certain kinds of problems. For example, in a visual game scenario, the user may be faced with choices. Suppose the game state is a crossroad where the player must choose to go North, East, West or South (NEWS). Alternatively, the choice may be video perspectives of different directions. Any one of the choices carries with it a whole set of other states, conditions, capabilities and properties.
One way to handle this kind of choice is with a conditional statement. The following shows two things. First, it shows that when a direction is selected, it typically has more than one thing being affected. (The more than one thing is furnished by “Everything else.”) Second, the binding for each is represented by the conditions within each conditional. (You could do the same thing with a Switch statement, but the binding wouldn’t change.)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | package { import flash.display.Sprite; public class NEWS extends Sprite { private var newsArray:Array = new Array("north","east","west","south"); private var dir:Object; public function NEWS() { for (dir in newsArray) { if(newsArray[dir]=="north") { trace("Hellloo Siberia"); trace("Everything else...."); trace(""); } else if(newsArray[dir]=="east") { trace("Visiting Bejing"); trace("Everything else...."); trace(""); } else if(newsArray[dir]=="west") { trace("Dude! You made it!"); trace("Everything else...."); trace(""); } else if(newsArray[dir]=="south") { trace("¡Recepción a la Argentina!"); trace("Everything else...."); trace(""); } } } } } |
That certainly can solve the issue of generating different responses from different object properties. It’s compact and saves ground-fills of wasted bits. It illustrates a common method of dealing with multiple options. The loop iterates through the object, and each iteration is examined by four conditional statements.
Unconditional Programming
Let’s go back to the NEWS example, and instead of having trace statements representing different directions, this next example uses short videos pointing in different directions. (I live in the woods so the videos are fairly woodsy—but they show the four points of the compass—honest.) I want to make an app with four buttons that plays a video pointing in the selected direction. Plus, I don’t want to use any conditional statements. (Easier than you think.) Click the Play and Download buttons to see a working example and get the code and videos.
![]()

In the next section where we examine the code you will see two things: No conditional statements and a non-linear solution. The user has several choices, and simply by making a choice she/he goes directly to the object desired—a directional video.
The Client, the UI and Requests
Like any good Client class, this client takes care of the UI and makes requests from other classes. Most of it is just providing a non-conditonal and non-linear solution.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | package { import fl.controls.Button; import flash.display.Sprite; import flash.events.MouseEvent; public class Client extends Sprite { private var dummy:Sprite=new Sprite(); private var nBtn:Button=new Button(); private var eBtn:Button=new Button(); private var wBtn:Button=new Button(); private var sBtn:Button=new Button(); private var north:North; private var east:East; private var west:West; private var south:South; public function Client() { nBtn.addEventListener(MouseEvent.CLICK,goNorth); nBtn.width=70; nBtn.x=(550/2)-(nBtn.width/2),nBtn.y=10; nBtn.label = "North"; addChild(nBtn); eBtn.addEventListener(MouseEvent.CLICK,goEast); eBtn.width=70; eBtn.x=550-(eBtn.width+5),eBtn.y=210; eBtn.label = "East"; addChild(eBtn); wBtn.addEventListener(MouseEvent.CLICK,goWest); wBtn.width=70; wBtn.x = 5,wBtn.y = 210; wBtn.label = "West"; addChild(wBtn); sBtn.addEventListener(MouseEvent.CLICK,goSouth); sBtn.width=70; sBtn.x=(550/2)-(sBtn.width/2),sBtn.y=370; sBtn.label = "South"; addChild(sBtn); } private function goNorth(e:MouseEvent) { north=new North(); addChild(north); } private function goEast(e:MouseEvent) { east=new East(); addChild(east); } private function goWest(e:MouseEvent) { west=new West(); addChild(west); } private function goSouth(e:MouseEvent) { south=new South(); addChild(south); } } } |
As you can see from the Client and testing the app, the Client just fires a function that calls one of four classes that run a video. The user makes requests through the buttons that fire methods that call classes. These classes contain what’s required for each of the four states. We’ll use North as a generic example. (The other three classes are identical except for the name of the video they call.)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | package { import flash.net.NetConnection; import flash.net.NetStream; import flash.display.Sprite; import flash.media.Video; import flash.events.NetStatusEvent; public class North extends Sprite { private var nc:NetConnection = new NetConnection(); private var ns:NetStream; private var vid:Video=new Video(); private var hookup:Boolean; private var dir:String="north.f4v"; private var sniffer:Object=new Object(); public function North() { nc.addEventListener(NetStatusEvent.NET_STATUS,doConnect); nc.connect(null); vid.x=137.5, vid.y=80; } private function doConnect(e:NetStatusEvent):void { hookup=(e.info.code=="NetConnection.Connect.Success"); if (hookup) { ns=new NetStream(nc); ns.client=sniffer; sniffer.onMetaData=getMeta; vid.attachNetStream(ns); ns.play(dir); addChild(vid); } } private function getMeta (mdata:Object):void { //Use if metadata required } } } |
The sharp-eyed among you will have spotted the conditional statement. It is fired by the NetConnection.Connect method and is more of a good practice than anything else. I could probably get away without it given that the videos are so small and load quickly; however, it is a good practice to check to make sure that a video is connected. So rather than trying to prove a point at the expense of a good practice, I’ll allow this one conditional to check connections and preserve a good practice. (I’ll also be tracking down another way to do the same thing without a conditional.)
You may be thinking that you could do the whole thing in the Client class by stuffing all the required methods and properties into the Client. You’d be right. In fact, while you’re at it you could stuff improvements in error checking and remove each video as a new one was played. However, as you put more and more into a class, you cease to delegate and continue to bind. Re-use and change becomes difficult because the less delegation you use, the more dependencies you stack up.
Next week, we’ll see how to refactor this set of classes into a state machine and a State design pattern. The State design pattern has a magic Context participant and other features that you’ll enjoy when you begin to abandon linear thinking and give OOP thinking a go.
Related posts:

Bill Sanders
Recent Comments