Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

LSL ignoring the rest of the IF statements?

Yonke Ming
Fat Laughing Hyena
Join date: 18 Jun 2005
Posts: 16
08-15-2005 10:29
Well, I recently made a new game and I noticed that something was off. For some reason, when I add more than some if statements, it doesn't even check them all.

CODE

if (commandstring == "greens")
{
++greenteam;
}

else if (commandstring == "greenl")
{
--greenteam;
}

else if (commandstring == "reds")
{
++redteam;
}
else if (commandstring == "redl")
{
--redteam;
}
else if (commandstring == "blues")
{
++blueteam;
}
else if (commandstring == "bluel")
{
--blueteam;
}
else if (commandstring == "yellows")
{
++yellowteam;
}
else if (commandstring == "yellowl")
{
--yellowteam;
}
else if (commandstring == "blacks")
{
++blackteam;
}
else if (commandstring == "blackl")
{
--blackteam;
}


Now the odd part is that it just checks the first four if statements and ignores the rest. I don't know, but it may just be that there is an error with LSL. Please help. I don't want to knock it down to two teams only.
_____________________
I like Hyenas...

...Especially the soft, fat, squishy, and silly ones!
Jillian Callahan
Rotary-winged Neko Girl
Join date: 24 Jun 2004
Posts: 3,766
08-15-2005 10:57
That's what "else" means - once a true condition is found, it ignores the rest.
_____________________
Malachi Petunia
Gentle Miscreant
Join date: 21 Sep 2003
Posts: 3,414
08-15-2005 11:05
I just put your posted code into a test rig
CODE
integer greenteam = 0;
integer redteam = 0;
integer blueteam = 0;
integer yellowteam = 0;
integer blackteam = 0;

// testInput should net green+2. black+1, blue+1, red-1, yellow+0
list testInput = ["greens", "greens", "blacks", "blues", "yellows", "redl", "yellowl", "blacks", "blackl"];


parseCommand(string commandstring) {
if (commandstring == "greens") {
++greenteam;
} else if (commandstring == "greenl") {
--greenteam;
} else if (commandstring == "reds") {
++redteam;
} else if (commandstring == "redl") {
--redteam;
} else if (commandstring == "blues") {
++blueteam;
} else if (commandstring == "bluel") {
--blueteam;
} else if (commandstring == "yellows") {
++yellowteam;
} else if (commandstring == "yellowl") {
--yellowteam;
} else if (commandstring == "blacks") {
++blackteam;
} else if (commandstring == "blackl") {
--blackteam;
}
}

dumpScores() {
llSay(0, "greenteam " + ((string) greenteam));
llSay(0, "redteam " + ((string) redteam));
llSay(0, "blueteam " + ((string) blueteam));
llSay(0, "yellowteam " + ((string) yellowteam));
llSay(0, "blackteam " + ((string) blackteam));
}

testParse() {
llSay(0, "before testParse");
dumpScores();

integer len = llGetListLength(testInput);
integer i;
for(i = 0; i < len; i++) {
parseCommand(llList2String(testInput, i));
}

llSay(0, "after testParse");
dumpScores();
}

default {
touch(integer c) {
testParse();
}
}
Which works as expected. My guess is that your commandstrings might have "1" (ones) instead of "l"s (ells) at the end.

It would be much more elegant to use something like changeScore(integer teamNumber, integer delta) with list holding the scores, but that's another topic.
Yonke Ming
Fat Laughing Hyena
Join date: 18 Jun 2005
Posts: 16
08-15-2005 11:14
Yeah but that's it.

You see, what's happening with mine that it ignores the others, so if I put "blacks", it just ignores it as if I never had an if branch for it in the first place.
_____________________
I like Hyenas...

...Especially the soft, fat, squishy, and silly ones!
Malachi Petunia
Gentle Miscreant
Join date: 21 Sep 2003
Posts: 3,414
08-15-2005 12:16
The contents of parseCommand were cut and pasted from your post, I didn't change a letter, so the if statements are working as they should. I have to say that I don't understand what the trouble is, but the chained if...elses are working properly.

Please don't read this as an insult, but from your example, it looks as if you are new to programming. That's ok, we all have to start sometime. Very often new programmers will think that there is something wrong with the compiler because it isn't doing what they expect. Almost always, it is their expectation that is incorrect.

If you want to describe the problem using more words, I will try and help you further.
Seagel Neville
Far East User
Join date: 2 Jan 2005
Posts: 1,476
08-15-2005 20:08
Hi Yonke,

I'm not sure what you want to do, either. But Jillian seemd to tell you to replace "else if" by "if". So you can do....

if
if
if
if
if
_____________________
:) Seagel Neville :)
Christopher Omega
Oxymoron
Join date: 28 Mar 2003
Posts: 1,828
08-15-2005 21:47
Make sure you're using "==" and *not* "=" in your conditional statements. It seems to be that way from the code you posted to the thread, but just-in-case, check over the code you're actually using IW.
==Chris
_____________________
October 3rd is the Day Against DRM (Digital Restrictions Management), learn more at http://www.defectivebydesign.org/what_is_drm
a lost user
Join date: ?
Posts: ?
08-16-2005 07:14
There are two main reasons to use "else if":

1. To reduce the amount of processing by ignoring all the rest of the IF conditions once it finds one that is correct. or,
2. To ignore the rest of the IF conditions when changing a variable that is checked by the remaining IF conditions, for example:

CODE

if(money == 100)
{
money -= 50;
}
else if(money < 100)
{
money -= 25;
}


If you just used two if statements, in the same order as above', then both would be called. And as for reducing processing, that should be pretty self-explanatory: if you have 20 separate IF conditions, and it finds a match in the second IF statement, it still needs to check through all the remaining 18 IF statements.

If I am doing a basic 'if this or that':
CODE

if(blahblah)
{
// do whatever when blahblah is TRUE
}
else
{
// do whatever when blahblah is FALSE
}


On the other hand, if I was doing something like in this question's example. I would most likely use separate IF statements.

CODE

parseCommand(string commandstring)
{
if(commandstring == "greens")
{
greenteam++;
return;
}

if(commandstring == "greenl")
{
greenteam--;
return;
}

if(commandstring == "reds")
{
redteam++;
return;
}

if(commandstring == "redl")
{
redteam--;
return;
}
}


The return statement here is actually breaking out of the function if a condition is met, so no additional processing is required once a match is found. Some people will disagree and say that using else if's makes the code easier to read and all that.. but that is provided you were taught to read code that way. In the end, this performs exactly the same way as the else if version. return; also works inside any of the system events such as listen(), sensor(), touch() and so on.

The point of return is actually to return a value from a function but it can be used like this to return nothing as well.

If you want to, you can also use the jump command to jump to the bottom of the function instead of returning out of the function, like:

CODE

parseCommand(string commandstring)
{
if(commandstring == "greens")
{
greenteam++;
jump end;
}

if(commandstring == "greenl")
{
greenteam--;
jump end;
}

if(commandstring == "reds")
{
redteam++;
jump end;
}

if(commandstring == "redl")
{
redteam--;
jump end;
}
@end;
// do stuff after finding a match int he IF statements
}


But whatever works for you I guess...
Malachi Petunia
Gentle Miscreant
Join date: 21 Sep 2003
Posts: 3,414
08-16-2005 07:53
I don't know about LSL particularly, but a good compiler should generate the same code for the chained, else ifs, the if-returns, and the if-jumps, all of which are faster than the sequential ifs for the reasons Gaz noted.

Just to be pedantic, the approach is inflexible. Here is how I would do it (uncompiled, untested code):
CODE
list teamColors = ["red", "yellow", "green", "blue", "black"];
list teamScores = [ 0, 0, 0, 0, 0 ];

// scoreTeam - add delta to the score for team color
//
scoreTeam(string color, integer delta) {
integer i = llListFindList(teamColors, [color]);

if(i < 0) {
debug("invalid color " + color + " in scoreTeam");
return;
}

integer teamScore = llList2Integer(teamScores, i);
teamScore += delta;

teamScores = llListReplaceList(teamScores, [teamScore], i, i);
}
You could get more tricky with strided instead of parallel lists, but I don't think the complexity would be worth it.
a lost user
Join date: ?
Posts: ?
08-16-2005 08:08
Not really sure which would cause more load or not to be honest but LSL doesn't optimise when it compiles. So it's not like a C/C++ compiler in that sense. For example:
for(i = 0; i < llGetInventoryNumber(INVENTORY_OBJECT); i++)
{
}

To cycle through all the object in the contents of an object actually puts a lot more load on the server than doing:

integer total_objects = llGetInventoryNumber(INVENTORY_OBJECT);
for(i = 0; i < total_objects; i++)
{
}

Because in the second example, llGetInventoryNumber() is only being called once. In a C/C++ compiler, this would not matter as it would all be compiled and optmised. This is at least my understanding of how LSL works based on what I have seen myself and what I have discussed with other scripters and Linden employees.

In a vaccuum, any method that works is fine.. but when there are another 500+ scripts running on the same sim, all competing for CPU cycles, it matters a lot about even the smallest amount of load.
Malachi Petunia
Gentle Miscreant
Join date: 21 Sep 2003
Posts: 3,414
08-16-2005 10:26
Gaz, you are indeed correct about LSL not being a highly optimized complier, and your example of not hoisting loop invariants out (llGetInventoryNumber in your example) is dead on as LSL doesn't know it is a loop invariant.

I can't figure how you would implement (or mis-implement) a byte code compiler that doesn't translate if(p) q; else if(r) s; so that "r" is evaluated if "p" is true, but then again, the boolean operators don't short circuit. But this is testable.

I'm just rambling now.
Malachi Petunia
Gentle Miscreant
Join date: 21 Sep 2003
Posts: 3,414
08-16-2005 10:49
CODE
string bool2string(integer bool) {
if(bool)
return "true";
else
return "false";
}

integer p(integer bool) {
llSay(0, "p(" + bool2string(bool) + ") called.");
return bool;
}

integer r(integer bool) {
llSay(0, "r(" + bool2string(bool) + ") called.");
return bool;
}

noop(string s) {
llSay(0, "noop(" + s + ")");
}

testJumps() {
llSay(0, "test one: should say 'p(true) / noop(p)'");
if( p(TRUE) ) {
noop("p");
} else if( r(TRUE) ) {
noop("r");
}

llSay(0, "test two: should say 'p(false) / r(true) / noop(r)'");
if( p(FALSE) ) {
noop("p");
} else if ( r(TRUE) ) {
noop("r");
}

llSay(0, "test three: should say 'p(false) / r(false)'");
if( p(FALSE) ) {
noop("p");
} else if ( r(FALSE) ) {
noop("r");
}
}

default {
touch(integer c) {
testJumps();
}
}
outputs as expected:
test one: should say 'p(true) / noop(p)'
p(true) called.
noop(p)
test two: should say 'p(false) / r(true) / noop(r)'
p(false) called.
r(true) called.
noop(r)
test three: should say 'p(false) / r(false)'
p(false) called.
r(false) called.