Difference between revisions of "LSL Operators"

From Second Life Wiki
Jump to navigation Jump to search
m (word correction)
m (caught two missing references to Wikipedia, added appropriate template)
 
(25 intermediate revisions by 13 users not shown)
Line 1: Line 1:
{{LSL Header|ml=*}}
{{LSL Header|ml=*}}
Operators are used to cause an operation (or mathematical action) to be performed on one (such as !) or two operands. The easy and common example is 1 + 2 where 1 and 2 are operands, and the '''+''' is the operator.
Operators are used to cause an operation (or mathematical action) to be performed on one (such as !) or two operands. The easy and common example is 1 + 2 where 1 and 2 are operands, and the '''+''' is the operator. This concept can be extended much further with LSL since operands can be variables with the special case of the assignment operators requiring that the left hand side be a variable.


This concept can be extended much further with LSL since operands can be variables with the special case of the assignment operators requiring that the left hand side be a variable.
The following table lists the operators in descending order of evaluation, i.e. higher in the table means higher evaluation precedence. Multiple operators on the same line share evaluation precedence. Parenthesize an expression if you need to force an evaluation order.


{| bgcolor="#FFFFFF" border="1"  cellspacing="2" cellpadding="6"
{| bgcolor="#FFFFFF" border="1"  cellspacing="2" cellpadding="6"
Line 10: Line 10:
! Usage Example
! Usage Example
|-  
|-  
| () || Parentheses || a * (b + c)
| <code>()</code>
|| parentheses: grouping and evaluation precedence
|| <code>integer val = a * (b + c);</code>
|-
|-
| [] || Brackets: list constructor || [a, 2, "this", 0.01]
| <code>[]</code>
|| brackets: list constructor
|| <code>list lst = [a, 2, "this", 0.01];</code>
|-
|-
| (''type'') || Typecasting || message = "The result is:" + (string) result;
| <code>(''type'')</code>
|| typecasting
|| <code>string message = "The result is:" + (string)result;</code>
|-  
|-  
| ! ~ ++ -- || Logical-NOT, Bitwise-NOT, Increment, Decrement || counter++;
| <code>!</code> <code>~</code> <code>++</code> <code>--</code>
|| logical NOT, bitwise NOT, increment, decrement
|| <code>counter++;</code>
|-
|-
| * / % || Multiply/Dot-Product, Divide, Modulus/Cross-Product  || rollover = (count + 1)%5;
| <code>*</code> <code>/</code> <code>%</code>
|| multiply/dot product, divide, modulus/cross product
|| <code>integer rollover = (count + 1) % 5;</code>
|-
|-
| - ||   Subtraction  || one = 3 - 2;
| <code>-</code>
|| subtraction, negation
|| <code>integer one = 3 - 2;</code>
<code>integer neg_one = -1;</code>
|-
|-
| + || Addition or joining Strings || two = 1+1;
| <code>+</code>
text = "Hello" + "World";
|| addition, string concatenation
|| <code>integer two = 1 + 1;</code>
<code>string text = "Hello" + " world";</code>
|-
|-
| + || Concatenation or joining Lists || myList = [1, 2, 3] + [4, 5];
| <code>+</code>
newList = oldList + addList;
|| list concatenation
|| <code>list myList = [1, 2, 3] + [4, 5];</code>
<code>list newList = oldList + addList;</code>
|-
|-
| << >> || Left Shift, Right Shift  || eight = 4 << 1;
| <code>&lt;&lt;</code> <code>&gt;&gt;</code>
|| {{Wikipedia|Arithmetic_shift|arithmetic}} left shift, {{Wikipedia|Arithmetic_shift|arithmetic}} right shift
|| <code>integer eight = 4 &lt;&lt; 1;</code>
<code>integer neg_one = -2 &gt;&gt; 1;</code>
|-
|-
| < <= > >= || Less Than, Less Than Or Equal To,
| <code>&lt;</code> <code>&lt;=</code> <code>&gt;</code> <code>&gt;=</code>
Greater Than, Greater Than or Equal To 
|| less than, less than or equal to, greater than, greater than or equal to
|| isFalse = (6 <= 4);
|| <code>integer isFalse = (6 &lt;= 4);</code>
|-
|-
| == != || Comparison Equal, Comparison Not Equal  || isFalse = ("this" == "that");
| <code>==</code> <code>!=</code>
|| comparison: equal, not equal
|| <code>integer isFalse = ("this" == "that");</code>
|-
|-
| & || Bitwise AND || zero = 4 & 2;
| <code>&</code>
four = 4 & 4;
|| bitwise AND
|| <code>integer zero = 4 & 2;</code>
<code>integer four = 4 & 4;</code>
|-
|-
| ^ || Bitwise XOR || zero = 4 ^ 4;
| <code>^</code>
six = 4 ^ 2;
|| bitwise XOR
|| <code>integer zero = 4 ^ 4;</code>
<code>integer six = 4 ^ 2;</code>
|-
|-
| <nowiki>|</nowiki> || Bitwise OR || four = 4 <nowiki>|</nowiki> 4;
| <code><nowiki>|</nowiki></code>
six = 4 <nowiki>|</nowiki> 2;
|| bitwise OR
|| <code>integer four = 4 <nowiki>|</nowiki> 4;</code>
<code>integer six = 4 <nowiki>|</nowiki> 2;</code>
|-
|-
| <nowiki>||</nowiki> || Logical OR || isTrue = (FALSE <nowiki>||</nowiki> TRUE);
| <code>&&</code> <code><nowiki>||</nowiki></code>
|| logical AND, logical OR
|| <code>integer isFalse = (FALSE && TRUE);</code>
<code>integer isTrue = (FALSE <nowiki>||</nowiki> TRUE);</code>
|-
|-
| &&  ||Logical AND  || isFalse = (FALSE && TRUE);
| <code>=</code> <code>+=</code> <code>-=</code> <code>*=</code> <code>/=</code> <code>%=</code>
|-
|| assignment
| = += -= *= /= %= || Assignment  || four = 4;
|| <code>integer four = 4;</code>
<code>integer eight = four; eight *= 2;</code>
|}
|}




'''Note:''' Unlike most other languages that use the C-style <code>&&</code> and <code>||</code> operators, '''both''' operands are '''always''' evaluated.  For example,
<syntaxhighlight lang="lsl2">if (TRUE || 1/0) llSay(PUBLIC_CHANNEL, "Aha!");</syntaxhighlight>
: will cause a Math Error rather than say "Aha!"
'''Note:''' The <code>++</code> (increment) and <code>--</code> (decrement) operators have two versions, pre- and post-. The ''pre''-increment (or ''pre''-decrement) operator increments (or decrements) its operand by 1; the value of the expression is the incremented (or decremented) value. The ''post''-increment (or ''post''-decrement) operator increases (or decreases) the value of its operand by 1, but the value of the expression is the operand's original value ''prior'' to the operation.
<syntaxhighlight lang="lsl2">integer count = 0;
if( ++count == 1 ) // 'count' is incremented then evaluated.
    llSay(PUBLIC_CHANNEL, "Aha"); // message will be said.</syntaxhighlight>


'''Note:''' Unlike most, if not all, other languages that use the C style '''&&''' and '''||''' operators, '''both''' operands are '''always''' evaluated. For example,
<syntaxhighlight lang="lsl2">integer count = 0;
if( count++ == 1 ) // 'count' is evaluated then incremented.
    llSay(PUBLIC_CHANNEL, "Aha"); // message will not be said.</syntaxhighlight>


<lsl>if (TRUE || 1/0) llSay( 0, "Aha!" );</lsl>  
'''Note:''' In most programming languages, and in the LSL bitwise operators, the AND operator has greater precedence than the OR operator. However, the LSL logical operators <nowiki>||</nowiki> and <nowiki>&&</nowiki> have ''the same'' precedence. For example:


will cause a Math Error rather than say "Aha".
<syntaxhighlight lang="lsl2">1 || 1 && 0  // result: 0 because it's the same as (1 || 1) && 0</syntaxhighlight>
<syntaxhighlight lang="lsl2">1 | 1 & 0    // result: 1 because it's the same as 1 | (1 & 0)</syntaxhighlight>


'''Note:''' The ++ (increment) and -- (decrement) have their effect on their number either before or after the number is evaluated when used in conditions dependent on whether they are before or after the number.
'''Note:''' The order of evaluation is from right to left.  If the value of x starts as 1 then the first two conditions below evaluate false and the second two evaluate true:


<lsl>integer count;
<syntaxhighlight lang="lsl2">(x && (x = 0) == 0 && x)</syntaxhighlight>
if(!(++count)) // Is incremented then evaluated.
<syntaxhighlight lang="lsl2">(x && (x = 0) == 0 && x == 0)</syntaxhighlight>
llSay(0, "Aha"); // Will not be said.</lsl>
<syntaxhighlight lang="lsl2">(x == 0 && (x = 0) == 0)</syntaxhighlight>
<syntaxhighlight lang="lsl2">(x == 0 && (x = 0) == 0 && x)</syntaxhighlight>


<lsl>integer count;
Both sides are evaluated regardless of the the truth of either side.
if(!(count++)) // Is evaluated then incremented.
llSay(0, "Aha"); // Will be said.</lsl>


==% Modulus==


'''Note:''' The order of precedence of boolean operators is unclear. It is possible that there is a [http://jira.secondlife.com/browse/SVC-779 bug] in the expression parser, making precedence inconsistent, or it may simply be that '''||''' and '''&&''' have equal precedence; testing is inconclusive. Thus, when in doubt, parenthesize.
'''Note:''' Modulus (<code>%</code>), like division, cause a ''Script run-time error. Math Error'' when its second operand equals zero.
'''SubNote:''' As the above bug has been closed as expected behavior, one can only assume the boolean operators have equal precedence.


'''Note:''' The order of evaluation appears to be backwards from most languages.  If the value of x starts as 1 then the first two conditions below evaluate false and the second two evaluate true:
'''Note:''' The <code>%</code> operator only accepts integer (<code>%</code> as modulus) and vector (<code>%</code> as cross product) operands.


<lsl>(x && (x = 0) == 0 && x)</lsl>
The modulus, also known as {{wikipedia|Modulo}}, produces the remainder after the first operand is divided by the second. Mathematically <code>a % b</code> is equivalent to <code>a - (a/b) * b</code>, since integer division <code>a/b</code> is truncated. This is also why the second operand cannot be zero.
<lsl>(x && (x = 0) == 0 && x == 0)</lsl>
<lsl>(x == 0 && (x = 0) == 0)</lsl>
<lsl>(x == 0 && (x = 0) == 0 && x)</lsl>


Both sides are evaluated regardless of the the truth of either side.
The operator can be confusing, even to veteran scripters. The following example(s) may prove useful in understanding how modulus can be used:


* Determine if an integer '''''input''''' is even or odd:
<syntaxhighlight lang="lsl2">
if (input % 2 == 0) // input is even
{
    // do even things
}
else // it's odd
{
    // do odd things
}
</syntaxhighlight>
* In the LSL implementation, the result always has the same sign as the first operand.
** -7 divided by 3 is -2 with a remainder of -1 (3 * -2 = -6, so the difference is -7 - -6 = -7 + 6 = -1), <code>-7 % 3 == -1</code>.
** Conversely, 7 divided by -3 is -2 with a remainder of 1 (-3 * -2 = 6, so the difference is 7 - 6 = 1), <code>7 % -3 == 1</code>.
* If the second operand is known to be a positive power of two, the modulus <code>a % b</code> can be replaced with the bitwise AND operator <code>a & (b-1)</code> which is more efficient.
** <code>7 % 4</code> and <code>7 & 3</code> are both 3.
** However, AND always returns a positive value: <code>-7 % 4 == -3</code>, but <code>-7 & 3 == 1</code>, which is 4 greater than the modulus putting it in the positive. This may or may not be desirable depending on the situation.
* Sometimes taking a modulus of floating point numbers is useful. The formula from the introduction works as long as the quotient is cast to an integer: <code>a - (integer)(a/b) * b</code>.
** Take the fractional part of <code>a</code> (<code>b</code> is 1.0 and can be left out): <code>7.8813 - (integer)(7.8813) == 0.8813</code>.
** Limit an angle <code>a</code> within TWO_PI radians, i.e. a full circle: <code>7.8813 - (integer)(7.8813/TWO_PI) * TWO_PI == 1.598114</code>.


==+ Operator==
'''Note:''' Equality test on lists does not compare contents, only the length.
{| {{Prettytable}}
{| {{Prettytable}}
|+
|+
==+ Operator==
<code>result = left + right</code>
<code>result = left + right</code>
|-{{Hl2}}
|-{{Hl2}}
Line 135: Line 198:
|}
|}


==Shorthand Operators==
{| {{Prettytable}}
{| {{Prettytable}}
|+
|+
==Shorthand Operators==
Alternatives to the simple '=' operator...
Alternatives to the simple '=' operator...
|-{{Hl2}}
|-{{Hl2}}
Line 159: Line 222:
|}
|}


=={{Wikipedia|De Morgan's laws|De Morgan's laws}}==
=={{Wikipedia|De Morgan's laws|w=n}}==
{| {{Prettytable|style=margin-top:0; float:left;}}
{| {{Prettytable|style=margin-top:0; float:left;}}
|+ Bitwise Equivalencies
|+ Bitwise Equivalencies
Line 192: Line 255:
|-
|-
|}
|}
Due to {{Wikipedia|De Morgan's laws|De Morgan's laws}}, by row, code in the '''AND''' column is logically equivalent to code in the '''OR'''. '''a''' and '''b''' need not be variables, they can be expressions. In certain circumstances these equivalencies can be used to simplify complex code. It is important not to confuse the two sets when using them. The first two rows depict De Morgan's laws as it is formulated, the second two build upon it.
Due to {{Wikipedia|De Morgan's laws|w=n}}, by row, code in the '''AND''' column is logically equivalent to code in the '''OR'''. '''a''' and '''b''' need not be variables, they can be expressions. In certain circumstances these equivalencies can be used to simplify complex code. It is important not to confuse the two sets when using them. The first two rows depict De Morgan's laws as it is formulated, the second two build upon it.
 
{{clear}}
 
== Useful Snippets ==
 
Typecasting can also be used if you have to concatenate many parts into a string:
 
<syntaxhighlight lang="lsl2">
// the following twp statements are equivalent:
string message1 = (string)["I have ", 5, " children at the average age of ", 8.2, " years"];
string message2 = "I have 5 children at the average age of 8.200000 years";
</syntaxhighlight>


{{LSLC|}}{{LSLC|Syntax}}{{LSLC|Keywords}}
{{LSLC|}}{{LSLC|Syntax}}{{LSLC|Keywords}}
{{LSLC|FixMe}}<!-- This article is woefully incomplete, it needs more Operator tables -->

Latest revision as of 08:15, 30 April 2024

Operators are used to cause an operation (or mathematical action) to be performed on one (such as !) or two operands. The easy and common example is 1 + 2 where 1 and 2 are operands, and the + is the operator. This concept can be extended much further with LSL since operands can be variables with the special case of the assignment operators requiring that the left hand side be a variable.

The following table lists the operators in descending order of evaluation, i.e. higher in the table means higher evaluation precedence. Multiple operators on the same line share evaluation precedence. Parenthesize an expression if you need to force an evaluation order.

Operator Description Usage Example
() parentheses: grouping and evaluation precedence integer val = a * (b + c);
[] brackets: list constructor list lst = [a, 2, "this", 0.01];
(type) typecasting string message = "The result is:" + (string)result;
! ~ ++ -- logical NOT, bitwise NOT, increment, decrement counter++;
* / % multiply/dot product, divide, modulus/cross product integer rollover = (count + 1) % 5;
- subtraction, negation integer one = 3 - 2;

integer neg_one = -1;

+ addition, string concatenation integer two = 1 + 1;

string text = "Hello" + " world";

+ list concatenation list myList = [1, 2, 3] + [4, 5];

list newList = oldList + addList;

<< >> "Wikipedia logo"arithmetic left shift, "Wikipedia logo"arithmetic right shift integer eight = 4 << 1;

integer neg_one = -2 >> 1;

< <= > >= less than, less than or equal to, greater than, greater than or equal to integer isFalse = (6 <= 4);
== != comparison: equal, not equal integer isFalse = ("this" == "that");
& bitwise AND integer zero = 4 & 2;

integer four = 4 & 4;

^ bitwise XOR integer zero = 4 ^ 4;

integer six = 4 ^ 2;

| bitwise OR integer four = 4 | 4;

integer six = 4 | 2;

&& || logical AND, logical OR integer isFalse = (FALSE && TRUE);

integer isTrue = (FALSE || TRUE);

= += -= *= /= %= assignment integer four = 4;

integer eight = four; eight *= 2;


Note: Unlike most other languages that use the C-style && and || operators, both operands are always evaluated. For example,

if (TRUE || 1/0) llSay(PUBLIC_CHANNEL, "Aha!");
will cause a Math Error rather than say "Aha!"

Note: The ++ (increment) and -- (decrement) operators have two versions, pre- and post-. The pre-increment (or pre-decrement) operator increments (or decrements) its operand by 1; the value of the expression is the incremented (or decremented) value. The post-increment (or post-decrement) operator increases (or decreases) the value of its operand by 1, but the value of the expression is the operand's original value prior to the operation.

integer count = 0;
if( ++count == 1 ) // 'count' is incremented then evaluated.
    llSay(PUBLIC_CHANNEL, "Aha"); // message will be said.
integer count = 0;
if( count++ == 1 ) // 'count' is evaluated then incremented.
    llSay(PUBLIC_CHANNEL, "Aha"); // message will not be said.

Note: In most programming languages, and in the LSL bitwise operators, the AND operator has greater precedence than the OR operator. However, the LSL logical operators || and && have the same precedence. For example:

1 || 1 && 0  // result: 0 because it's the same as (1 || 1) && 0
1 | 1 & 0    // result: 1 because it's the same as 1 | (1 & 0)

Note: The order of evaluation is from right to left. If the value of x starts as 1 then the first two conditions below evaluate false and the second two evaluate true:

(x && (x = 0) == 0 && x)
(x && (x = 0) == 0 && x == 0)
(x == 0 && (x = 0) == 0)
(x == 0 && (x = 0) == 0 && x)

Both sides are evaluated regardless of the the truth of either side.

% Modulus

Note: Modulus (%), like division, cause a Script run-time error. Math Error when its second operand equals zero.

Note: The % operator only accepts integer (% as modulus) and vector (% as cross product) operands.

The modulus, also known as "Wikipedia logo"Modulo, produces the remainder after the first operand is divided by the second. Mathematically a % b is equivalent to a - (a/b) * b, since integer division a/b is truncated. This is also why the second operand cannot be zero.

The operator can be confusing, even to veteran scripters. The following example(s) may prove useful in understanding how modulus can be used:

  • Determine if an integer input is even or odd:
if (input % 2 == 0) // input is even
{
    // do even things
}
else // it's odd
{
    // do odd things
}
  • In the LSL implementation, the result always has the same sign as the first operand.
    • -7 divided by 3 is -2 with a remainder of -1 (3 * -2 = -6, so the difference is -7 - -6 = -7 + 6 = -1), -7 % 3 == -1.
    • Conversely, 7 divided by -3 is -2 with a remainder of 1 (-3 * -2 = 6, so the difference is 7 - 6 = 1), 7 % -3 == 1.
  • If the second operand is known to be a positive power of two, the modulus a % b can be replaced with the bitwise AND operator a & (b-1) which is more efficient.
    • 7 % 4 and 7 & 3 are both 3.
    • However, AND always returns a positive value: -7 % 4 == -3, but -7 & 3 == 1, which is 4 greater than the modulus putting it in the positive. This may or may not be desirable depending on the situation.
  • Sometimes taking a modulus of floating point numbers is useful. The formula from the introduction works as long as the quotient is cast to an integer: a - (integer)(a/b) * b.
    • Take the fractional part of a (b is 1.0 and can be left out): 7.8813 - (integer)(7.8813) == 0.8813.
    • Limit an angle a within TWO_PI radians, i.e. a full circle: 7.8813 - (integer)(7.8813/TWO_PI) * TWO_PI == 1.598114.

+ Operator

Note: Equality test on lists does not compare contents, only the length.

result = left + right
Left Type Right Type Result Type Description
integer integer integer Adds left and right
integer float float Adds left and right
float integer float Adds left and right
string string string Concatenates right onto the end of left.
list * list Concatenates right onto the end of left.
* list list Affixes left onto the start of right.
vector vector vector Adds left and right
rotation rotation rotation Adds left and right
Not useful for combining rotations, use * or / instead.

Shorthand Operators

Alternatives to the simple '=' operator...
Simple assignment operator Shorthand operator
a = a + 1 a += 1
a = a – 1 a -= 1
a = a * (n+1) a *= (n+1)
a = a / (n+1) a /= (n+1)
a = a % b a %= b

"Wikipedia logo"De Morgan's laws

Bitwise Equivalencies
AND OR
~(a & b) ~a | ~b
~a & ~b ~(a | b)
a & ~b ~(~a | b)
~(a & ~b) ~a | b
Boolean Equivalencies
AND OR
!(a && b) !a || !b
!a && !b !(a || b)
a && !b !(!a || b)
!(a && !b) !a || b

Due to "Wikipedia logo"De Morgan's laws, by row, code in the AND column is logically equivalent to code in the OR. a and b need not be variables, they can be expressions. In certain circumstances these equivalencies can be used to simplify complex code. It is important not to confuse the two sets when using them. The first two rows depict De Morgan's laws as it is formulated, the second two build upon it.

Useful Snippets

Typecasting can also be used if you have to concatenate many parts into a string:

// the following twp statements are equivalent:
string message1 = (string)["I have ", 5, " children at the average age of ", 8.2, " years"];
string message2 = "I have 5 children at the average age of 8.200000 years";