let greetings = "Hello, " ++ "world"
Lense supports operators with a special kind of operator overloading. There are two types of operators : intrinsic and definable.
Intrinsic operators are native to the language and their behavior cannot be redefined. On the other hand, the set of available operators for redefinition is limited ( we do not what symbolic noise ) but extended enough to be useful in a mathematical or engineering context. Definable operators are translated to method calls. Intrinsic operators are not translated to method calls.
Operands are never changed during these operations.
Symbols are gathered from different sources and most are familiar and available in other programming languages.
For arithmetic operations we need unique symbols. Not always there are enough symbols available. For example, we can use the ^
symbol do exponentiation,
but then we do not have a good symbol for the XOR operation, traditionally also denoted ^
. So, in this cases where the same symbol
may be used, we prefer the single symbol for the commutative operation and the double symbol for the non commutative operation.
So we use ^
for XOR and ^^
for exponentiation.
Note
|
Other languages use ** for exponentiation. This makes parsing more difficult, and produces a rather confusing code when using multiplications
together with exponentiation, so ^^ symbol was selected instead;
|
Lense, distinguishes "sum" - a commutative operation - and "concatenation" - a non commutative operation. So +
denotes "sum" and ++
denotes "concatenation".
Strings, and other objects are concatenated as
let greetings = "Hello, " ++ "world"
Note
|
Not all double symbols imply non-commutativity. For example, == is commutative. The double symbol rule applies to arithmetic operators that have the two forms.
For example, & denotes commutative AND operation while , && denotes non commutative, short-circuit AND operation.
|
Intrinsic operators cannot be redefined and are specially handled by the compiler.
Operator |
Example |
|
|
|
Determines if two objects have the same identity. Only objects of type |
|
|
Determines if two objects have not the same identity. Only objects of type |
|
|
Does nothing. An infix |
|
|
a and b must be |
|
|
a and b must be |
|
|
a must be |
interval operators |
|
Interval between 2 and 5, including 2 and excluding 5. |
Interval operators allow to include of exclude the start and ending values
|
Interval start, including the value |
|
Interval start, not including the value |
|
Interval end, including the value |
|
Interval end, not including the value |
This operator test for the first term to be true. In the positive case returns the second term. Otherwise returns the third.
let c = (a == b) ? 1 : 4;
This operator compares the second term with the other ones according to the comparison operators use in between them an returns true if both sides are true
let isTeenager = 13 <= x <= 19;
This operator is equivalent to
let isTeenager = 13 <= x && x <= 19
but, we do not need to use the &&
operator nor type the variable x
twice.
Also this operator is equivalent to
let isTeenager = x in |[ 13 , 19 ]|;
but we do not need to create and interval object to test x
against it.
Lense supports operator overloading by means of assigning an operator to a method. For example,
let a = 2 + 3;
transforms to the plus
method
let a = 2.plus(3);
Since operators are methods, this means operators are polymorphic and that the resulting type depends on the original types.
For example, summing a Natural with a Natural results in a Natural, but summing a Natural with an Integer results in an Integer, since the argument can be negative.
So Natural, for example, defines two methods called plus
that correspond with the '+' operator;
public plus(other : Natural): Natural;
public plus(other : Integer): Integer;
The compiler will use the most specific one given the type of the argument.
Here is a list of all supported operators and their equivalent methods
Operator |
Example |
Equivalent method call |
Commutative |
Description |
|
|
|
Yes |
Determines if two instances are equal. |
|
|
|
Yes |
Determines if two instances are not equal. |
|
|
|
Yes |
Sums two values and returns a third value. If the result overloads the current representation, the result is a promoted representation |
|
|
|
Yes |
Sums two values and returns a third value. If the result overloads the current representation, the value wrap around to a negative number |
|
|
|
No |
Concatenates two values and returns a third value. |
|
|
|
No |
Subtracts two values and returns a third value. If the result overloads the current representation, the result is a promoted representation |
|
|
|
No |
Subtracts two values and returns a third value. If the result overloads the current representation, the value wrap around to a negative number |
|
|
|
Yes |
Multiplies the two values and returns in a third value. If the result overloads the current representation, the result is a promoted representation |
|
|
|
Yes |
Multiplies the two values and returns in a third value.If the result overloads the current representation, the value wrap around to a negative number |
|
|
|
No |
Raises the base - the first operand - to the power of the exponent - the second operand. |
|
|
|
No |
Divides the two values and returns a third value. |
|
|
|
No |
Performs whole division the two values and returns a third value. The operand values are not changed in any way. |
|
|
|
n/a |
Returns the symmetric value. Keep in mind the type needs not be closed for subtraction. For |
|
|
|
n/a |
Returns the complement of the value. For |
|
|
|
No |
Divides the two values and returns the remainder of integer division. Note that it always should be true that |
|
|
|
Yes |
Injucts the two values and returns a third value. For binary forms, this implements a bitwise AND. For sets this implements intersection |
|
|
|
Yes |
Dijuncts the two values and returns a third value. For binary forms, this implements a bitwise OR . For sets this implements union |
|
|
|
Yes |
Exclusively Dijuncts the two values and returns a third value. For binary forms, this implements a bitwise XOR |
|
|
|
No |
Compared the order of the values of a and b. Returns |
|
|
|
No |
Returns |
|
|
|
No |
Returns |
|
|
|
No |
Returns |
|
|
|
No |
Returns |
|
|
|
No |
Returns a Progression that starts at a and ends at b, and contains b. |
|
|
|
No |
Returns a Progression that starts at a and ends at b, but not contains b. |
|
|
|
No |
The arithmetic right shift operator returns a value equivalent to the original with bits moved to the right n times. This is equivalent to division by 2 n times for positive numeric values. |
|
|
|
No |
The arithmetic left shift operator returns a value equivalent to the original with bits moved to the left n times. This is equivalent to multiplication by 2 n times for positive numeric values. |
empty space |
|
|
No |
This is an operator with no symbol that means the two operands are simply "put together". This may mean a kind of multiplication like in |
Consider the following operator statement:
mutable let a = 3;
a+=5;
The +=
is a composed assignment operator. Where the a+=5
statement is equivalent to:
mutable let a : Integer = 3;
a = a + 5;
All composed assignment operator are decomposed by the compiler in an assignment an a call to the root operator.
|
|
|
|
|
|
|
|
|
|
Remember that assignments are statements in Lense, so the following code does not compile:
mutable let a : Integer = 3;
if (a+=5 > 7){ // does not compile
// do something
}
This one does:
mutable let a : Integer = 3;
a+=5;
if (a > 7){
// do something
}
Lense does not support increment and decrement operators, but options for the most common uses.
for
loopsIs common in other languages to use the increment operator in for loop like this:
for (int i = 0; i < someLength; i++){
... // do something with i
}
In Lense you can use ranges like:
for (let i in 0 ..< someLength){
... // do something with i
}
Another common use, is to increment a variable when some condition is true, for example, when counting.
int counter = 0;
if (someCondition){
count++;
}
This can be written using the +=
composed assignment operator as:
mutable let counter = 0;
if (someCondition){
count += 1;
}
or if you need to be further explicit:
mutable let counter = 0;
if (someCondition){
count = count + 1;
}