PDA

View Full Version : The funny thing about "else if"



IQAndreas
December 7th, 2009, 05:16 AM
Just noticed something funny a few weeks back.

To recap, if statements can be written without brackets. If this is done, the very next line is executed, that only that line if the query is met. Same thing after 'else'.

if (you.areGay == true)
me.runAway();
else
me.befriend(you);Now, many languages have "else if" as "ifelse" or something instead, all one word. However, let's take a look at how Flash does it:

if (you.areGay == true)
me.runAway();
else if (you.areGay == false)
me.befriend(you);Notice something funny? Really, the above line can be interpreted as "if, then one line that is executed" followed by "else, then one line that is executed". On that one line, just so happens to be another if statement. If you put several else if statements in a row, you get the following:

if (you.areGay == true)
me.runAwayAndDontTurnMyBackOnYou();
else if (you.areBi == true)
me.runAway();
else if (you.areSociopath == true)
me.runFaster();
else
me.befriend(you);Notice that all the if statements in the above code are really if statements followed by one line, which is another if statement, followed by another one line if statement after the else, etc. When you add proper brackets, you will get the exact same results as below:

if (you.areGay == true)
{
me.runAwayAndDontTurnMyBackOnYou();
}
else
{
if (you.areBi == true)
{
me.runAway();
}
else
{
if (you.areSociopath == true)
{
me.runFaster();
}
else
{
me.befriend(you);
}
}
}Of course, I prefer the 8 lines to 22, so it is quite convenient.


Is my guess on how it works and compiles correct? Or is Flash smart enough to treat "else if" differently"?

lewi-p
December 7th, 2009, 05:28 AM
Turn 8 lines into 4 lines...


if (you.areGay == true) me.runAwayAndDontTurnMyBackOnYou();
else if (you.areBi == true) me.runAway();
else if (you.areSociopath == true) me.runFaster();
else me.befriend(you);

lewi-p

kadaj
December 7th, 2009, 05:38 AM
Now, many languages have "else if" as "ifelse" or something instead, all one word.elif => else if
and #elif is in C as a pre processor way back..

[edit]
but i think flash (AS 3.0) doesn't have some thing similar.
Do we really need elif? Isn't else if sufficient?
Python is having elif. Is typing 3 extra characters so hefty? May be programmers are unconditionally getting lazy day by day.

IQAndreas
December 7th, 2009, 05:42 AM
So true, and I think that actually describes it better:

if (you.areGay == true) me.runAwayAndDontTurnMyBackOnYou();
else <--START IF#2 if (you.areBi == true) me.runAway();
else <--START IF#3 if (you.areSociopath == true) me.runFaster();
else me.befriend(you);
But do you see the point I am trying to make? Really "else if" is a one line if statement after an else statement.

kadaj
December 7th, 2009, 05:55 AM
that's obvious.

IQAndreas
December 7th, 2009, 06:40 AM
that's obvious.
Either I'm not really making my point clear, or I'm the only one who finds this fascinating, both of which are very likely.

If the AS3 creators had used a statement like "ifelse", that means that the entire line of if statements would be sequential and all related, like a "switch" statement.

However, it seems that this approach causes the if statements to become completely unrelated to oneanother, and are no more than nested if statements.


For some reason, I find this really fascinating, and I would often like to get inside the head of some of the people who developed AS3 to find out what they were thinking and why they used a certain approach. :sigh: I guess I'm the only one who feels this way. I find the thought process behind code more interesting and rewarding than the actual code.

Shaedo
December 7th, 2009, 08:45 AM
So I was wondering about it. Timing it out is would seem that your conclusions are sound. run the code below to see (funny how SLOW running a switch is, its quicker to run lots of plain if statements!)

I would point out that ';' is a new line rather than a 'carriage return's which is only a new line as far as displaying the code (I am sure you know that I am just pointing it out).

155 // plain if else
155 // if else written out with excessive {}
203 // if (without the else)
233 // switch statements

<EDIT>
my point being that it works better than a flash switch statement which is quite slow
</EDIT>


import flash.utils.getTimer;

var t:Number;
var n:Number=2;
var c:uint=20000000;

t=getTimer();
for(var i:uint=0;i<c;i++)
{
if(n==1)n=1;
else if(n==2)n=2;
else if(n==3)n=3;
else if(n==4)n=4;
}
trace(getTimer()-t);

t=getTimer();
for(var j:uint=0;j<c;j++)
{
if(n==1)n=1;
else
{
if(n==2)n=2;
else
{
if(n==3)n=3;
else
{
if(n==4)n=4;
}
}
}
}
trace(getTimer()-t);

t=getTimer();
for(var k:uint=0;k<c;k++)
{
if(n==1)n=1;
if(n==2)n=2;
if(n==3)n=3;
if(n==4)n=4;
}
trace(getTimer()-t);

t=getTimer();
for(var l:uint=0;l<c;l++)
{
switch (n)
{
case 1:
n=1;
break;
case 2:
n=2;
break;
case 3:
n=3;
break;
case 4:
n=4;
break;
}
}
trace(getTimer()-t);

glosrfc
December 7th, 2009, 10:06 AM
They're not actually "if statements followed by one line, which is another if statement, followed by another one line if statement after the else, etc." because each subsequent if statement is dependent upon the outcome of the previous if statement. To put it another way, using the else if statement allows logical branching with the final outcome entirely dependent on the previous outcomes.

If they were just if statements following on from another if statement etc then you would write it as this:

if (you.areGay == true)
me.runAwayAndDontTurnMyBackOnYou();
if (you.areBi == true)
me.runAway();
if (you.areSociopath == true)
me.runFaster();
else
me.befriend(you);
However, the preceding code example is not dependent so it's possible to be both a sociopathological gay and bi at the same time. In the real world, there's no reason why that can't actually be true. By using the else statement you effectively limit the options because of this dependency...so that, if you're gay, you're saying it's impossible for you to be a sociopath as well. In my experience, people aren't always that clear-cut.

On the subject of timings, it's also worth bearing in mind that the order in which you check your if statements can have a significant bearing on the result. Once an if condition is evaluated to true, Flash will ignore all subsequent if statements. So you can speed things up by making sure that the expected outcome is the condition that is checked first...followed by the next expected outcome...and the next...and so on.

Finally, you can also replace all of the else if text by using the tertiary logical operator and putting everything on one line:

you.areGay ? me.runAwayAndDontTurnMyBackOnYou() : you.areBi ? me.runAway() : you.areSociopath ? me.runFaster() : me.befriend(you);

Swooter
December 7th, 2009, 10:08 AM
Even shorter:


(you.areGay)?me.runAway():me.befriend(you);

glosrfc
December 7th, 2009, 10:20 AM
It's not actually shorter* because it's just a simple if statement in tertiary form, i.e. it's not dependent on the other else if conditions of you.areBi and you.areSociopath.
Having said that, it could still be shorter as the brackets are superfluous ;)

you.areGay?me.runAway():me.befriend(you);

* Unless it was a deliberately humorous expression of your personal lifestyle choice!

nook
December 7th, 2009, 12:46 PM
Not very p.c. example code..

Krilnon
December 7th, 2009, 01:05 PM
In some other languages, such as C and Java, else if literally just means else followed by if - so no syntactic sugar is needed or provided. This works since when an else is followed by one statement (in this case the if), it doesn't need any braces.


I would often like to get inside the head of some of the people who developed AS3 to find out what they were thinking and why they used a certain approach.

JavaScript/ActionScript/ECMAScript just uses that syntax because C (and therefore Java) did:

JavaScript borrows most of its syntax from Java, but also inherits from Awk and Perl, with some indirect influence from Self in its object prototype system.

The ECMAScript-262 context-free grammar also makes it fairly explicit that else if is just a combination of an else and a new if, since there is only one relevant production in the entire grammar:

IfStatement :
if ( Expression ) Statement else Statement
if ( Expression ) Statement


I guess I'm the only one who feels this way.

Don't flatter yourself. ;) As of now, this thread only has about 100 views (a small fraction of the ≈6.8 billion people in the world).

Aurelien
December 7th, 2009, 05:01 PM
I had a good laugh with these lines of code, thank you !

Also, while it is shorter to remove the brackets, remember this only works with one-line statements which end with a semi-colon.

IQAndreas
December 7th, 2009, 05:19 PM
They're not actually "if statements followed by one line, which is another if statement, followed by another one line if statement after the else, etc." because each subsequent if statement is dependent upon the outcome of the previous if statement.
Sorry, let me rephrase that. It didn't really come out right, but I was thinking this in my head:
"They are if statements, the else clause of that if statement followed by one line, which is another if statement, containing an else clause followed by another one line if statement, etc."

I just consider the "else" clause just to be a part of the if statement.

Am I even making it clear what I'm saying? :| Hm... This thread got a little more attention and repeated information than planned... Sorry guys.



In some other languages, such as C and Java, else if literally just means else followed by if - so no syntactic sugar is needed or provided. This works since when an else is followed by one statement (in this case the if), it doesn't need any braces.
EDIT: Wohoo. I got it right... :P THAT is what I am trying to say.

Scythe
December 7th, 2009, 11:04 PM
I too find all this to be obvious. An if statement modifies the line of code that directly follows it, and brackets are a convenient way to treat multiple lines as a single line as far as if statements are concerned. For statements and while statements behave the same way, though packages, classes, and functions require the brackets.


var n:Number = 1
if (n < 5)
for (var c:int = 0; c < 5; c++)
while (n < c)
n *= 1.5;
trace(n);

This is nothing new. Many languages including C and Java treat statements and brackets the same way. Thus it's only logical that you can include an if statement as part of the else clause of another if statement. This may have fascinated me at some point, but not anymore.

gamera
December 8th, 2009, 07:24 AM
the example you used is sexist.

albino
December 8th, 2009, 09:43 AM
who's example is sexist? Homophobic maybe, but hardly sexist.

I have to admit, I don't find this fascinating at all (although reading through the thread has been fairly interesting) as I just presumed that's all if else statements were; does this happens, if not does this happen, if not this happens.

lope
December 8th, 2009, 06:35 PM
my point being that it works better than a flash switch statement which is quite slow


why would switch be slower than equivalent number of ifs?
i dont get it...
whats the difference?


btw, i just run your code couple of times, first with var declaration as uint in all for loops, then all with int, and with int its like almost twice as faster!




interesting is, when i took your code, and autoformat it, flash did this:


for (var k:int=0; k<c; k++) {
if (n==1) {
n=1;
} else {
if (n==2) {
n=2;
} else {
if (n==3) {
n=3;
} else {
if (n==4) {
n=4;
}
}
}
}
}

but, when i add braces, i do it like this:


for (var j:int=0; j<c; j++) {
if (n==1) {
n=1;
} else if (n==2) {
n=2;
} else if (n==3) {
n=3;
} else if (n==4) {
n=4;
}
}

IQAndreas
December 8th, 2009, 07:04 PM
why would switch be slower than equivalent number of ifs?
i dont get it...
whats the difference?

btw, i just run your code couple of times, first with var declaration as uint in all for loops, then all with int, and with int its like almost twice as faster!
That's just the way flash works, and I complain about it just as much.

Grant Skinner made a few interesting speed comparisons, as well as releasing a speed testing class:
http://www.gskinner.com/blog/archives/2006/06/types_in_as3_in.html

lope
December 8th, 2009, 07:39 PM
thanks, i will read this...
btw, in Shaedo http://www.kirupa.com/forum/styles/kirupaProblue/buttons/viewpost.gif (http://www.kirupa.com/forum/showthread.php?p=2522276#post2522276) code if i change var declaration on the beginning from:

var n:Number=2;

to

var n:int=2;

everything is like 3/4 times faster....

funny stuff :D

BoppreH
December 8th, 2009, 09:26 PM
Suddenly the brackets in the code

if (condition1) {
doSomething()
} else if (condition2) {
doSomethingElse()
}seem awkward and inelegant.

But it was an enlightening experience.

IQAndreas
December 9th, 2009, 05:24 AM
Suddenly the brackets in the code seem awkward and inelegant.
But it was an enlightening experience.
I usually write single line code like this, as there is a chance I might missread single line if functions otherwise:

if (condition1)
{ doSomething(); }
else if (condition2)
{ doSomethingElse(); }

That looks a lot more elegant.

Then I can also throw in trace statements without having to rewrite the entire if statement to include new brackets:

//This will always give the trace statement regardless of condition1
if (condition1)
doSomething(); trace(variable1);

//This will only give the trace statement if condition 2 is met,
//even though it looks similar to the above code
if (condition2)
{ doSomethingElse(); trace(variable2); }

BoppreH
December 9th, 2009, 08:03 AM
I usually write single line code like this, as there is a chance I might missread single line if functions otherwise:

Actually, I don't use brackets around single line conditions, but I was just too lazy to make more useless functions in that example.

far100
December 13th, 2009, 05:12 PM
I trying to think of a code sample to test this out so I haven't come with anything.


var sam:int = (totalPeople > 6)? ((roomSize < 500)?:1000:500)): ((oxyLevel < 200)?:300:200));

ternary operators inside of the ternary operator

Krilnon
December 13th, 2009, 05:19 PM
I trying to think of a code sample to test this out so I haven't come with anything.


var sam:int = (totalPeople > 6)? ((roomSize < 500)?:1000:500)): ((oxyLevel < 200)?:300:200));

ternary operators inside of the ternary operator
You're not using the correct syntax in your example, but yes, you can nest them.

TheCanadian
December 13th, 2009, 05:47 PM
It also gets ridiculously convoluted, but whatever floats your boat.

far100
December 13th, 2009, 05:50 PM
Trying to find correct syntax - saw glosrfc (http://www.kirupa.com/forum/member.php?u=33826) 's post. Duh. My bad.




you.areGay ? me.runAwayAndDontTurnMyBackOnYou() : you.areBi ? me.runAway() : you.areSociopath ? me.runFaster() : me.befriend(you);

glosrfc
December 13th, 2009, 06:32 PM
Convoluted? Pppffttt...
http://www.kirupa.com/forum/showthread.php?t=288385

Now this is ridiculously convoluted:

function isValidDate(day, month, year, code):String{return arguments.length != 3 ? 1 : day < 1 || day > 31 ? 2 : month < 1 || month > 12 ? 3 : (month == 4 || month == 6 || month == 9 || month == 11) && day == 31 ? 4 : month == 2 && (day > ((year = !(year % 4) && (year % 100) || !(year % 400)) ? 29 : 28)) ? 5 + !(!year) : 0;}
function errorMessage(r):Number{return r == 0 ? "Valid date" : r == 1 ? "Invalid date format" : r == 2 ? "Invalid day" : r == 3 ? "Invalid month" : r == 4 ? "April, June, September and November only have 30 days" : r == 5 ? "February only has 28 days": r == 6 && "February only has 29 days in a leap year";};
trace("Checking 31/3/2009: " + errorMessage(isValidDate(31, 3, 2009)));
trace("Checking 31/3/3/2009: " + errorMessage(isValidDate(31, 3, 3, 2009)));
trace("Checking 32/3/2009: " + errorMessage(isValidDate(32, 3, 2009)));
trace("Checking 31/13/2009: " + errorMessage(isValidDate(31, 13, 2009)));
trace("Checking 31/4/2009: " + errorMessage(isValidDate(31, 4, 2009)));
trace("Checking 29/2/2009: " + errorMessage(isValidDate(29, 2, 2009)));
trace("Checking 30/2/2008: " + errorMessage(isValidDate(30, 2, 2008)));
;)

wvxvw
December 13th, 2009, 07:05 PM
If anyone wonders - switch-case is slower then a set of if-else, it's one single operation more then if-else, however, I would use switch-case anyway because it's clearer, and hope for improvement in compiler.

Let's look at switch/if:



a = 5 ? 10 : 8;


gets:



_as3_pushbyte 5
_as3_iffalse offset: 7[#10]
_as3_pushbyte 10
_as3_convert_d
_as3_jump offset: 3[#12]
#10 _as3_pushbyte 8
_as3_convert_d
#12 _as3_convert_d
_as3_setlocal <1>



if (5) a = 10;
else a = 8;

gets:



_as3_pushbyte 5
_as3_iffalse offset: 8[#11]
_as3_pushbyte 10
_as3_convert_d
_as3_setlocal <1>
_as3_jump offset: 4[#14]
#11 _as3_pushbyte 8
_as3_convert_d
_as3_setlocal <1>

The difference is a redundant conversion in the first case and setlocal in the second case. The second should be just a little faster:

Now switch/if:




switch (a) {
case 4:
trace(4);
case 10:
trace(a);
break;
case 8:
trace(a);
break;
default:
trace(a);
}

Gets:




#14 _as3_jump offset: 41[#34]
_as3_label
_as3_findpropstrict trace
_as3_pushbyte 4
_as3_callpropvoid trace(param count:1)
_as3_label
_as3_findpropstrict trace
_as3_getlocal <1>
_as3_callpropvoid trace(param count:1)
_as3_jump offset: 94[#57]
_as3_label
_as3_findpropstrict trace
_as3_getlocal <1>
_as3_callpropvoid trace(param count:1)
_as3_jump offset: 83[#57]
_as3_label
_as3_findpropstrict trace
_as3_getlocal <1>
_as3_callpropvoid trace(param count:1)
_as3_jump offset: 72[#57]
#34 _as3_getlocal <1>
_as3_setlocal <2>
_as3_pushbyte 4
_as3_getlocal <2>
_as3_ifstrictne offset: 6[#41]
_as3_pushbyte 0
_as3_jump offset: 38[#55]
#41 _as3_pushbyte 10
_as3_getlocal <2>
_as3_ifstrictne offset: 6[#46]
_as3_pushbyte 1
_as3_jump offset: 25[#55]
#46 _as3_pushbyte 8
_as3_getlocal <2>
_as3_ifstrictne offset: 6[#51]
_as3_pushbyte 2
_as3_jump offset: 12[#55]
#51 _as3_jump offset: 6[#54]
_as3_pushbyte 3
_as3_jump offset: 2[#55]
#54 _as3_pushbyte 3
#55 _as3_kill <2>
_as3_lookupswitch -66(3)[-96, -88, -77, -66]

Should be something along these lines:




if (a === 4) trace(4);
if (a === 4 || a === 10) {
trace(a);
} else if (a === 8) {
trace(a);
} else {
trace(a);
}

Gets:




#57 _as3_getlocal <1>
_as3_pushbyte 4
_as3_ifstrictne offset: 7[#63]
_as3_findpropstrict trace
_as3_pushbyte 4
_as3_callpropvoid trace(param count:1)
#63 _as3_getlocal <1>
_as3_pushbyte 4
_as3_strictequals
_as3_dup
_as3_iftrue offset: 5[#72]
_as3_pop
_as3_getlocal <1>
_as3_pushbyte 10
_as3_strictequals
#72 _as3_iffalse offset: 10[#77]
_as3_findpropstrict trace
_as3_getlocal <1>
_as3_callpropvoid trace(param count:1)
_as3_jump offset: 23[#87]
#77 _as3_getlocal <1>
_as3_pushbyte 8
_as3_ifstrictne offset: 10[#84]
_as3_findpropstrict trace
_as3_getlocal <1>
_as3_callpropvoid trace(param count:1)
_as3_jump offset: 6[#87]
#84 _as3_findpropstrict trace
_as3_getlocal <1>
_as3_callpropvoid trace(param count:1)

In general switch uses almost the same operators, however, the overall organisation of the code is different. Plus lookupswitch.

Retrieved from here:
http://translate.google.com/translate?hl=en&sl=ru&u=http://www.flasher.ru/forum/showthread.php%3Ft%3D121698%26page%3D2&ei=GYElS6nJOJ7WmwOcm6nEBg&sa=X&oi=translate&ct=result&resnum=1&ved=0CAkQ7gEwAA&prev=/search%3Fq%3D%2522%25D0%25B3%25D0%25BC,%2Bif-%25D1%258B%2B%25D0%25B2%2B%25D0%25B1%25D0%25B8%25D 0%25B7%25D0%25BD%25D0%25B5%25D1%2581-%25D0%25BB%25D0%25BE%25D0%25B3%25D0%25B8%25D0%25BA %25D0%25B5%2B%25D0%25BE%25D1%2581%25D0%25BE%25D0%2 5B1%25D0%25BE%2B%25D0%25BD%25D0%25B5%2B%25D0%25BF% 25D0%25BE%25D0%25B7%25D0%25B0%25D0%25BC%25D0%25B5% 25D0%25BD%25D1%258F%25D0%25B5%25D1%2588%25D1%258C% 2522%26hl%3Den

glosrfc
December 13th, 2009, 07:28 PM
Never mind the differences in speed...I'm still chuckling at the way Google Translator has converted Russian into some kind of Yoda-speak:
"Given that statement? faster than if, it is not."
"Help to wonder what the shelf badge belt "
"teach me, this ignoramus Kungfu"

wvxvw
December 13th, 2009, 07:53 PM
Muahaha :)
Well, all those quotes aren't really related to the test... however I liked the last one. What he was basically asking is how does the person who posted knows how bytecode is generated :)