Learn
Lesson 18

Operators

Every operator in one place, including the two OSL rules that surprise people: left-to-right maths and loose string equality.

You've met most operators along the way. This lesson collects them, and spells out the two places where OSL deliberately differs from other languages.

Arithmetic, left to right#

OperatorDoesExample
+ - *add, subtract, multiply2 * 3 is 6
/divide exactly7 / 2 is 3.5
%remainder7 % 2 is 1
^power2 ^ 10 is 1024
* on a stringrepeat"ab" * 3 is "ababab"

OSL evaluates mixed arithmetic from left to right. It doesn't do multiplication before addition:

osl
log 10 + 2 * 3

That line prints 36, because it means (10 + 2) * 3, and it also earns a PrecedenceWarning from the compiler. Write the grouping out and the warning goes away:

main.osl
log (10 + 2) * 3
log 10 + (2 * 3)
Click the code to edit it

The first line of the unbracketed version is (10 + 2) * 3. This is a deliberate choice: one simple rule instead of a precedence table to remember. The compiler warns whenever you mix operators without brackets, so you're never caught out silently. Bracket what you mean.

Joining#

OperatorDoes
++joins as text, or merges two arrays or two objects
+ on two stringsjoins them
main.osl
log "n = " ++ 4
log [1, 2] ++ [3]
log {a: 1} ++ {b: 2}
Click the code to edit it

Comparison#

OperatorMeans
== !=equal, not equal (loose)
=== !==equal, not equal (strict)
< <= > >=ordering
inis a member of

Loose equality compares strings without case, and lets numbers and numeric text meet. Strict equality wants the same type and the same characters:

main.osl
log "Yes" == "yes"
log "Yes" === "yes"
log [1, 2] == [1, 2]
log 3 in [1, 2, 3]
log "b" in "abc"
Click the code to edit it

Arrays and objects compare by their contents. Class instances compare by identity: two different instances are never equal, even if their fields match.

Logic#

OperatorMeans
andboth
oreither
!not
??the left side, or the right side if the left is null

and and or stop as soon as they know the answer, so the right side may never run. When you mix and and or, bracket them; the compiler warns if you don't.

Assignment#

Every arithmetic and joining operator has an assigning form: +=, -=, *=, /=, %=, ^= and ++=. x++ and x-- add or take one. Two more deal with null:

main.osl
string? name = null
name ??= "guest"
log name

string? stored = "kept"
string? edit = null
stored =?? edit
log stored
Click the code to edit it
  • a ??= b sets a to b only if a is null.
  • a =?? b sets a to b only if b is not null, which is handy for applying optional changes.

Ranges, choices and pipes#

FormGives
1 to 5the array [1,2,3,4,5], both ends included
if c then a else ba or b depending on c
x |> ff(x)

Bits#

& and, | or, ^^ exclusive or, << and >> shift. These work on whole numbers.

main.osl
log 12 & 10
log 12 | 10
log 12 ^^ 10
log 1 << 4
Click the code to edit it

Pointers#

@name makes a pointer to a variable, so a function can change the variable itself. std:ptr reads and writes through it. This is rare in everyday code and mostly matters when working with Go libraries:

main.osl
import "std:ptr"

def bump(*int n) (
  ptr.set(n, ptr.deref(n) + 1)
)

int count = 1
bump(@count)
log count
Click the code to edit it
Quick check

What does log 2 + 3 * 4 print?

Quick check

What is "OSL" == "osl"?

Your turn

Fix the formula

The area of a ring is π times the outer radius squared, minus π times the inner radius squared. This program prints the wrong number because the brackets are in the wrong place. Move them so it prints the right area, rounded.

main.osl
Ctrl Enter runs
Expected output
50
0 of 24 lessons done