Skip to content

Expressions

Expressions

An expression is any construct that produces a value. Expressions include any combination of literal values, function or method calls, assignment expressions, object constructors, as well as arithmetical, relational and logical operations.

Arithmetic operators

Morpho provides the standard binary arithmetic operators

Operator Description
+ Addition
- Subtraction
* Multiplication
/ Division
^ Exponentiation

Hence, Morpho can be used, among other things, as an (over-engineered) pocket calculator like so:

print 2^8-1

Comparison operators

Comparisons between expressions can be achieved using relational operators,

Operator Description
< Less than
> Greater than
== Equal to
!= Not equal to
<= Less than or equal to
>= Greater than or equal to

all of which return true or false. Not all expressions can be compared; Complex numbers for example, can be tested for equality but not compared so

print 1im < 2 // Invalid

throws a InvldOp error. Equality tests are more complicated than they appear. Comparisons of objects are only equal if they refer exactly to the same object, so

print [1,2,3] == [1,2,3]

prints false because two different Lists are created and compared, even though their contents are identical. A few object types support "deep" equality comparison, such as Strings and Tuples. Hence

print (1,2,3) == (1,2,3)
print "Hello" == "Hello"

both print true.

Logical operators

Finally, Morpho provides the logical operators

::: center :::

which implement the Boolean algebra. All of these operators consider the two values false and nil to be false; any other value is considered to be true. This is very different from C and some other languages, where the integer value 0, and sometime even other values, are also considered to be false. In Morpho, 0 (like any other number) is considered to be true.

Like C, however, the logical operators do not always cause evaluate both operands to be evaluated. If the left operand of the AND operator is false, for example, the right hand operand is not evaluated because the expression is manifestly false. You can see this explicitly in the following example

fn f() {
  print "f was evaluated!"
  return true
}

print true && f() // f is evaluated
print false && f() // f is not evaluated

Conversely, if the left operand of the OR operator || is true, the right hand operand isn't evaluated because it's clear the composite expression must be true.

print true || f() //  f is not evaluated
print false || f() // f is evaluated

Since the NOT operator * has only one operand, it is always evaluated. \section{Assignment} The contents of variables can be changed using assignment expressions. The operator \lstinline=! is used to indicate assignment: the operator on the left hand is called the assignment target and is the variable or component to be modified; the operand on the right hand side is the value to be assigned.

An assignment statement can be as simple as assigning a value

foo = 1

or could involve changing the contents of a collection using index notation

foo[0] = 1

A common use of assignment is to capture the return value of a function

foo = sin(Pi/4)

Morpho also provides a number of shorthand assignment operators that retrieve and modify the contents of an assignment target and then store the result back in the same target:

  • += Increments the target by a given value, e.g. foo += 1

  • -= Decrements the target by a given value, e.g. foo -= 1

  • *= Multiplies the target by a given value, e.g. foo *= 2

  • /= Divides the target by a given value, e.g. foo /= 2

These shorthand operators are provided purely for the convenience of the programmer and each is entirely equivalent to a regular longhand assignment, e.g.

foo += 1

could equally be written as

foo = foo + 1

Because assignment operators in Morpho are expressions, they evaluate to a value which is always the value assigned. Hence

var a = 1
print a+=1

prints 2 which is the value of a+1

Other expressions

There are a few other types of expression and associated operators that are presented elsewhere in the book:

  • The Range constructors .., ... are discussed in Section [sec:Ranges]{reference-type="ref" reference="sec:Ranges"}.

  • Function calls are introduced in Chapter Functions.

  • Method calls are denoted by a single dot . and are explained in Section XXX.

Precedence

Compound expressions like 1 + 2 * 3 may appear ambiguous at first sight because it is not obviously clear which of (1 + 2) * 3 = 9 or 1 + (2 * 3) = 7 is meant. Running this example

print 1 + 2 * 3

prints 7 rather than 9 because the multiplication operator * binds to its operands with higher precedence than the addition operator +. The order of precedence in Morpho is as follows

::: center ::: tabular |c|c|l| & Operators &\ Highest & . & Method call\ & ^ & Power\ & -, * & Unary minus, NOT\tabularnewline \hline & \lstinline*!,/ & Multiplication and division\ & +,- & Addition and subtraction\ & .., ... & Range constructor\ & <, >, <=, >= & Comparison\ & ==, =* & Equality tests\tabularnewline \hline & \lstinline&&! & AND\ & || & OR\ Lowest & =, +=, -=, *=, /= & Assignment\ ::: :::

The programmer is always free to use parentheses to control the order of evaluation, so

print (1 + 2) * 3

indeed prints 9. It is recommended to do so even if an expression is formally correct, but challenging for the reader to parse.