Difference between revisions of "If"

From Second Life Wiki
Jump to navigation Jump to search
m (Replaced old <LSL> block with <source lang="lsl2">)
 
(24 intermediate revisions by 6 users not shown)
Line 1: Line 1:
{{#vardefine:p__desc|
{{#if:
}}{{#vardefine:p_condition_desc|If this executes as true then branch is executed.
 
}}{{#vardefine:p_condition_d_desc|If this executes as true then '''branch''' is executed.
{{#vardefine:p_branch_desc|Can be either a single statement, a block statement, or a null statement.}}
}}{{#vardefine:p_branch_desc|Can be either a single statement, a block statement, or a null statement.
 
{{#vardefine:p_condition_hover|If this executes as true then branch is executed.}}
{{#vardefine:p_condition_d_hover| If this executes as true then branch_true is executed otherwise branch_false is executed.}}
 
{{#vardefine:p_condition_desc|If this executes as true then {{LSLP|branch}} is executed.}}
{{#vardefine:p_condition_d_desc| If this executes as true then {{LSLP|branch|branch_true}} is executed otherwise {{LSLP|branch|branch_false}} is executed.}}
 
}}{{LSL_Conditional
}}{{LSL_Conditional
|statement=if
|statement=if
Line 11: Line 17:
|statement_title=if ( {{LSL Param|condition}} ) {{LSL Param|branch}}
|statement_title=if ( {{LSL Param|condition}} ) {{LSL Param|branch}}
|extras=
|extras=
{{!}}
<div id="box">
<div id="box">
== if ( {{LSL Param|condition_d|condition}} ) {{LSL Param|branch|branch_true}} else {{LSL Param|branch|branch_false}} ==
== if ( {{LSL Param|condition_d|condition}} ) {{LSL Param|branch|branch_true}} else {{LSL Param|branch|branch_false}} ==
<div style="padding: 0.5em;">
<div style="padding: 0.5em;">
{{{!}}
{{{!}}
{{LSL DefineRow||condition|{{#var:p_condition_desc}}}}
{{LSL DefineRow||condition|{{#var:p_condition_d_desc}}}}
{{LSL DefineRow||branch_true|{{#var:p_branch_desc}}}}
{{LSL DefineRow||branch_true|{{#var:p_branch_desc}}}}
{{LSL DefineRow||branch_false|{{#var:p_branch_desc}}}}
{{LSL DefineRow||branch_false|{{#var:p_branch_desc}}}}
{{!}}}
{{!}}}
There seems to be no limit anymore (or very high > 120) for else-if chains.
</div>
</div>
</div>
</div>
|notes=Operators in LSL do NOT short circuit. For example:
|spec=
{{{!}} style="border-width: 0px;border-spacing: 0px;"
{{{!}} style="border-width: 0px;border-spacing: 0px;"
{{!}}
{{!}}Operators in LSL do NOT [http://en.wikipedia.org/wiki/Short-circuit_evaluation short circuit]. For example:
<pre>
<source lang="lsl2">// A simple method to say if the method was called.
// A simple method to say if the method was called.
integer test()
integer test() {
{
     llOwnerSay("Test method called!");
     llOwnerSay("Test method called!");
   
     return TRUE;
     return TRUE;
}
}


default {
default
     touch_start(integer total_number) {
{
         if (FALSE && test()) { // If short-circuit optimized then the test() should never be called.
     touch_start(integer total_number)
            // Will never get here.
    {
         if (FALSE && test())
        { // If short-circuit optimized then the test() should never be called.
          // Will never get here.
         }
         }
     }
     }
}
}</source>
</pre>
{{!}}}
{{!}}}
In a short-circuited language if the left-hand side of a logical AND (&&) is FALSE the right-hand side is never tested since the entire test would always return a FALSE output no matter what the value of the right-hand side. Since LSL is not short circuited, both the left and the right-hand sides are tested all the time.
In a short-circuited language if the left-hand side of a logical AND (&&) is FALSE the right-hand side is never tested since the entire test would always return a FALSE output no matter what the value of the right-hand side. Since LSL is not short circuited, both the left and the right-hand sides are tested all the time.
This can be simulated by using a nested if structure:
This can be simulated by using a nested if structure:
{{{!}} style="border-width: 0px;border-spacing: 0px;"
 
{{!}}
<source lang="lsl2">default
<pre>
{
default {
     touch_start(integer total_number)
     touch_start(integer total_number) {
    {
         if (FALSE) {
         if (FALSE)
             if (test()) {
        {
             if (test())
            {
               // Will never get here.
               // Will never get here.
             }
             }
         }
         }
     }
     }
}
}</source>
</pre>
{{!}}}
|examples=Simple inline if statement:
|examples=Simple inline if statement:
<pre>
<source lang="lsl2">if (a == 1) c = b;</source>
if (a == 1) c = b;
 
</pre>
Simple block if statement:
Simple block if statement:
<pre>
<source lang="lsl2">if (a == 1)
if (a == 1)
{
{
     // Do something here.
     // Do something here.
}
}</source>
</pre>
 
Complex if/else block (only one line of text will be said by this example)
<source lang="lsl2">if (a == "Loren") {
    llSay(0, "Lorem ipsum sic amet!");
} else if (a == "Bob") {
    llSay(0, "Babble dabble rabble rouse.");
} else {
    llSay(0, "Gobbledygook?  or English?");
}</source>
 
Compounded if statement:
Compounded if statement:
<pre>
<source lang="lsl2">if (a == 1 && b == c)
if (a == 1 && b == c)
{
{
     // more here.
     // more here.
}
}</source>
</pre>
 
Nested if statements:
Nested if statements:
<pre>
<source lang="lsl2">if (a == 1)
if (a == 1)
{
{
     if (b == c)
     if (b == c)
Line 84: Line 97:
         // more here.
         // more here.
     }
     }
}
}</source>
</pre>


Watch out for misplaced semicolons.  They can, and will, cause strange things to happen.
Watch out for misplaced semicolons.  They can, and will, cause strange things to happen.
For instance: If you place a semicolon between an if statement and a code block, the if statement will not control the execution of the block.
For instance: If you place a semicolon between an if statement and a code block, the if statement will not control the execution of the block.
 
<source lang="lsl2">if (a == "Loren");
<pre>
if (a == "Loren");
{
{
     llSay(0, "Lorem ipsum sic amet!");
     llSay(0, "Lorem ipsum sic amet!");
}
}</source>
</pre>
 
This code will execute in the following order:
This code will execute in the following order:


Line 102: Line 112:


Another problem happens when someone forgets to use the curly braces.
Another problem happens when someone forgets to use the curly braces.
<pre>
<source lang="lsl2">if (a == "Loren")
if (a == "Loren")
     llSay(0, "Lorem ipsum sic amet!");
     llSay(0, "Lorem ipsum sic amet!");
     llSay(0, "I don't know what it means either...");
     llSay(0, "I don't know what it means either...");</source>
</pre>


The assumption is that because the indentation makes it "look" like both llSay commands are controlled by the if statement, that they are.  In fact, if <code>a</code> was equal to "Joe" then all that would be said is "I don't know what it means either..."
The assumption is that because the indentation makes it "look" like both llSay commands are controlled by the if statement, that they are.  In fact, if <code>a</code> was equal to "Joe" then all that would be said is "I don't know what it means either..."


===The {{=}}/{{=}}{{=}} Mistakes===
There is common error to mistake  == operator for =, due to  ignorance or simply mistyping, e.g.
<source lang="lsl2">if (av_id = llGetOwner())//<-- This is likely a mistake
        llSay(0,"It's my owner!");</source>
will send message regardles what value of va_id was , because it equal to if(llGetOwner()).
There is trick , invented by C programmers ages ago how to avoid this bug  -  to make habit to put constant or other expression to which you cannot assign value(e.g. function call or  result of some operation) in front of comparison - that will save you from mistake. It's very nasty error to make and hard to debug in big code.
<source lang="lsl2">if(llGetOwner() == av_id)
          llSay(0,"It's my owner!");</source>
In this case mistake will result in compile error.
<source lang="lsl2">if(llGetOwner() = av_id)//<-- will not compile
          llSay(0,"It's my owner!");</source>
The syntax checker [[lslint]] will report a warning when it encounters this usage (to silence the warning wrap the statement in parentheses).
However the best way to communicate the intended behavior to the reader is to place a comment on the same line.
<source lang="lsl2">if ((av_id = llGetOwner()))//<-- This syntax communicates to the syntax checker that this is the intended behavior.
        llSay(0,"It's my owner!");</source>


|helpers
|helpers
Line 120: Line 151:
|mode
|mode
|deprecated
|deprecated
|cat1
|cat1=Conditional
|cat2
|cat2
|cat3
|cat3
|cat4
|cat4
}}
}}

Latest revision as of 02:03, 22 January 2015

if ( condition ) branch

•  condition If this executes as true then branch is executed.
•  branch Can be either a single statement, a block statement, or a null statement.

if ( condition ) branch_true else branch_false

•  condition If this executes as true then branch_true is executed otherwise branch_false is executed.
•  branch_true Can be either a single statement, a block statement, or a null statement.
•  branch_false Can be either a single statement, a block statement, or a null statement.

There seems to be no limit anymore (or very high > 120) for else-if chains.

Specification

Conditional Types
Type Condition
integer True if it is not zero.
float True if it is not zero.[1]
string True if its length is not zero.
key True only if it is a valid key and not NULL_KEY.
vector True if the vector is not ZERO_VECTOR.
rotation True if the rotation is not ZERO_ROTATION.
list True if the length is not zero. Note that correct behavior is only seen with Mono-compiled scripts; LSO-compiled scripts incorrectly resolve to false if the list is non-empty: BUG-230728

Operators in LSL do NOT short circuit. For example:
// A simple method to say if the method was called.
integer test()
{
    llOwnerSay("Test method called!");
    return TRUE;
}

default
{
    touch_start(integer total_number)
    {
        if (FALSE && test())
        { // If short-circuit optimized then the test() should never be called.
          // Will never get here.
        }
    }
}

In a short-circuited language if the left-hand side of a logical AND (&&) is FALSE the right-hand side is never tested since the entire test would always return a FALSE output no matter what the value of the right-hand side. Since LSL is not short circuited, both the left and the right-hand sides are tested all the time. This can be simulated by using a nested if structure:

default
{
    touch_start(integer total_number)
    {
        if (FALSE)
        {
            if (test())
            {
              // Will never get here.
            }
        }
    }
}

Examples

Simple inline if statement:

if (a == 1) c = b;

Simple block if statement:

if (a == 1)
{
    // Do something here.
}

Complex if/else block (only one line of text will be said by this example)

if (a == "Loren") {
    llSay(0, "Lorem ipsum sic amet!");
} else if (a == "Bob") {
    llSay(0, "Babble dabble rabble rouse.");
} else {
    llSay(0, "Gobbledygook?  or English?");
}

Compounded if statement:

if (a == 1 && b == c)
{
    // more here.
}

Nested if statements:

if (a == 1)
{
    if (b == c)
    {
        // more here.
    }
}

Watch out for misplaced semicolons. They can, and will, cause strange things to happen. For instance: If you place a semicolon between an if statement and a code block, the if statement will not control the execution of the block.

if (a == "Loren");
{
    llSay(0, "Lorem ipsum sic amet!");
}

This code will execute in the following order:

  1. The line if (a == "Loren"); will execute; the semicolon will tell LSL that this is a simple inline if statement.
  2. Next it meets the start of the code block and will execute the contents, in this case saying "Lorem ipsum sic amet!", no matter what the outcome of the above if statement.

Another problem happens when someone forgets to use the curly braces.

if (a == "Loren")
    llSay(0, "Lorem ipsum sic amet!");
    llSay(0, "I don't know what it means either...");

The assumption is that because the indentation makes it "look" like both llSay commands are controlled by the if statement, that they are. In fact, if a was equal to "Joe" then all that would be said is "I don't know what it means either..."

The =/== Mistakes

There is common error to mistake == operator for =, due to ignorance or simply mistyping, e.g.

if (av_id = llGetOwner())//<-- This is likely a mistake
         llSay(0,"It's my owner!");

will send message regardles what value of va_id was , because it equal to if(llGetOwner()).

There is trick , invented by C programmers ages ago how to avoid this bug - to make habit to put constant or other expression to which you cannot assign value(e.g. function call or result of some operation) in front of comparison - that will save you from mistake. It's very nasty error to make and hard to debug in big code.

if(llGetOwner() == av_id)
          llSay(0,"It's my owner!");

In this case mistake will result in compile error.

if(llGetOwner() = av_id)//<-- will not compile
          llSay(0,"It's my owner!");

The syntax checker lslint will report a warning when it encounters this usage (to silence the warning wrap the statement in parentheses). However the best way to communicate the intended behavior to the reader is to place a comment on the same line.

if ((av_id = llGetOwner()))//<-- This syntax communicates to the syntax checker that this is the intended behavior.
         llSay(0,"It's my owner!");

Deep Notes

Search JIRA for related Issues

Footnotes

  1. ^ The OpenSim LSL compiler will not do this implicitly. You will need to use an explicit check.