Operators?
Table of Contents
Operators are an integral part of modern programming, Concurnas dedicates much of its syntax to supporting operators. Most of these operators are 'universal' and widely used outside of conventional programming, such as those concerning arithmetic and basic mathematics, some are more specific to programming in general such as bit shift related operators and some are unique to modern programming languages such as the null safety related operators.
Concurnas also dedicates much support to operator overloading, this helps facilitate the construction of domain specific languages within Concurnas.
Supported Operators?
Concurnas supports the following extensive set of operators:
Class 
Operator 
Token 
Description 
Example 
Input types 
Return type 
Associativity 

Sizeof 
Sizeof 
sizeof 
Calculate the off heap size of the operand 
sizeof "myString" => 128 
Object 
Long 
Left to right 
Contains 
In 
in, not in 
Check if the left hand operand is in the right hand operand 
1 in [1 2 3 4 5] => true 
Any Array or Collection of Component type 
Boolean 
Left to right 
Not 
Not 
not 
Flips boolean value of right hand operand 
not true => false 
Boolean 
Boolean 
Right to left 
Postfix 
Increment 
++ 
Increments operand by 1 
expr++ 
Integral 
Integral 
Left to right 
Decremement 
 
Decrements operand by 1 
expr 
Integral 
Integral 
Left to right 

Prefix 
Increment 
++ 
Increments operand by 1 
++epxr 
Integral 
Integral 
Right to left 
Decremement 
 
Decrements operand by 1 
expr 
Integral 
Integral 
Right to left 

Positive 
+ 
Positive value of operand 
+10 => 10 
Integral 
Integral 
Right to left 

Negative 
 
Negative value of operand 
10 => 10 
Integral 
Integral 
Right to left 

Multiplicative 
Multiplication 
* 
Multiplies left and right hand side operands 
2*2 => 4 
Integral 
Integral 
Left to right 
Power 
** 
Raises left operand to the power of right operand 
3**2 => 9 
Integral 
Integral 
Right to left 

Division 
/ 
Divides left hand operand by right hand operand 
10/3 => 3 
Integral 
Integral 
Left to right 

Modulus 
mod 
The remainder of the division operator applied to the operands as above 
10 mod 3 => 1 
Integral 
Integral 
Left to right 

Additive 
Addition 
+ 
Adds the left and right hand side operands 
2 + 2 => 4, "hi" + "there" => "hi there" 
Integral or String 
Integral or String 
Left to right 
Subtraction 
 
Subtracts the right hand operand from the left hand operand 
2  4 => 2 
Integral 
Integral 
Left to right 

Bitshift 
Left shift 
<< 
The left operands value is moved left by the number of bits specified by the right operand. 
0b001 << 2 => 4 (0b100) 
Integral 
Integral 
Left to right 
Right Shift 
>> 
The left operands value is moved right by the number of bits specified by the right operand. 
0b100 >> 2 => 7 (0b111) 
Integral 
Integral 
Left to right 

Unsigned right shift 
>>> 
As above but shifted values are filled with zeros 
0b100 >> 2 => 1 (0b001) 
Integral 
Integral 
Left to right 

Complement 
comp 
Complement of a single expression 
comp 0b0001 => 14 (0b1110) 
Integral 
Integral 
Right to left 

Relational 
Less than 
< 
Check if the left hand operand is less than the right hand operand 
2 < 4 => true 
Integral 
Integral 
Left to right 
Greater than 
> 
Check if the left hand operand is greater than the right hand operand 
2 > 4 => false 
Integral 
Integral 
Left to right 

Less than or equal 
<== 
Check if the left hand operand is less than or equal to the right hand operand 
2 <== 2 => true 
Integral 
Integral 
Left to right 

Greater than or equal 
>== 
Check if the left hand operand is greater than or equal to the right hand operand 
2 >== 2 => true 
Integral 
Integral 
Left to right 

Instance of 
Instance of 
is, isnot, is not 
Check if the left handoperand is (or is not) a subtype of the right hand type operand 
expr is not Object => false 
Object, Type 
Boolean 
Left to right 
Cast 
Cast 
as 
Cast left operand to be type of right hand type operand 
expr as MyClass => expr is now of type MyClass 
Object, Type 
Object 
Left to right 
Equality 
Structurally equal 
== 
Check if the value of the left and right hand operands are equal 
10 == 10 => true 
Any 
Boolean 
Left to right 
Structurally not equal 
<> 
Check if the value of the left and right hand operands are not equal 
10 <> 9 => true 
Any 
Boolean 
Left to right 

Referential equality 
&== 
Check if the object on the left and right hand operands are the same 
Integer(1) &== Integer(1) => false 
Any 
Boolean 
Left to right 

Referentially not equal 
&<> 
Check if the object on the left and right hand operands are not the same 
Integer(1) &<> Integer(1) => true 
Any 
Boolean 
Left to right 

Bitwise 
Bitwise and 
band 
Compares each bit of the operands and returns 1 for each if they are both 1 
0b110 band 0b101 => 0b100 
Integral 
Integral 
Left to right 
Bitwise or 
bor 
Compares each bit of the operands and returns 1 for each if either equals 1 
0b110 bor 0b101 => 0b111 
Integral 
Integral 
Left to right 

Bitwise exclusive or 
bxor 
Compares each bit of the operands and returns 1 for each if either but not both equals 1 
0b110 bxor 0b101 => 0b011 
Integral 
Integral 
Left to right 

Logical and 
and 
and 
Check if the left and right hand operands both resolve to true 
true and false => false 
Boolean 
Boolean 
Left to right 
Logical or 
or 
or 
Check if either the left and right hand operands both resolve to true 
true or false => true 
Boolean 
Boolean 
Left to right 
Ternary 
If expression 
x if y else z 
Return x operand if y operand resolves to true otherwise return z operand 
8 if true else 9 => 8 
Any, Boolean, Any 
Any 
Left to right 
Invoke 
Invoke 
obj(args?) 
Call the invoke method on object with provided methods 
afunc(); afunc2(1, 'arg2') 
Object 
Any 
Left to right 
Null Safety 
Not null assertion 
?? 
Throws a Null Pointer Exception if left hand side is null, otherwise returns no null type 
maybeNull?? 
Object? 
Object 
Left to right 
Elvis operator^{1} 
?: 
Returns left hand side if it is not null, otherwise the right hand side expression will be evaluated and returned 
maybeNull?:otherwise 
Object? 
Object 
Left to right 

Assignment 
Assignment 
= 
Vanilla assignment 
a = 10 
Integral 
Integral 
Right to left 
Compound Assignment 
Addition Assign 
+= 
Apply addition operator to left and right operands and set value to left operand 
a += 10 
Integral or String 
Integral or String 
Right to left 
Subtract Assign 
= 
As above but subtraction 
a = 10 
Integral 
Integral 
Right to left 

Mutliply Assign 
*= 
As above but multiplication 
a *= 2 
Integral 
Integral 
Right to left 

Divide Assign 
/= 
As above but division 
a /= 13 
Integral 
Integral 
Right to left 

Power Assign 
**= 
As above but power 
a **= 2 
Integral 
Integral 
Right to left 

Mod Assign 
mod= 
As above but mod 
a mod= 15 
Integral 
Integral 
Right to left 

Bitwise And Assign 
band= 
As above but bitwise and 
a bor= 16 
Integral 
Integral 
Right to left 

Bitwise Or Assign 
bor= 
As above but bitwise or 
a bor= 17 
Integral 
Integral 
Right to left 

Bitwise Xor Assign 
bxor= 
As above but bitwise xor 
a bxor= 17 
Integral 
Integral 
Right to left 

Complement Assign 
comp= 
As above but complement 
a comp= 19 
Integral 
Integral 
Right to left 

Left shift Assign 
<<= 
As above but left shift 
a <<= 20 
Integral 
Integral 
Right to left 

Right Shift Assign 
>>= 
As above but right shift 
a >>= 21 
Integral 
Integral 
Right to left 

Unsigned right shift Assign 
>>>= 
As above but unsigned right shift 
a >>>= 22 
Integral 
Integral 
Right to left 
The majority of these operators operate upon primitive or boxed primitive types. The integral (or 'numerical') types are defined as: int
, long
, short
, char
and byte
and their equivalent boxed object variants: Integer
, Long
, Short
, Character
and Byte
respectfully.
Sizeof?
The sizeof
operator is designed for working with off heap memory. It provides us an indication of the size in bytes that any object (including arrays) will consume when serialized into a byte format as par the scheme referenced within its optional qualifier. For example, when working on the gpu we can use a qualifier as follows:
leAr = [1 2 3 4 5 6 7 8 9 10]
gpusize = sizeof<gpus.gpusizeof> leAr//size of leAr on the gpu
If no qualifier is provided then the default off heap serialization built into Concurnas is used:
leAr = [1 2 3 4 5 6 7 8 9 10]
gpusize = sizeof leAr//size of leAr as par default scheme
Defining a sizeof qualifier?
If we were to design a customized object serialization scheme, it can be beneficial to implement a sizeof qualifier such that clients of our custom scheme are able to know the size in bytes that objects will consume if serialized via our scheme. This can be easily achieved by defining a function taking a single Object as input and returning a value of type int
. For example:
def sizeofCustomScheme(some Object) int{
//some logic...
return 1//in this example every object is 1 byte large
}
This can then be used via qualification of the sizeof operator as par above.
Contains?
The contains class of operator consists of two variants, in
and not in
. in
can be used with common data collection structures including: lists, sets and arrays to test to see if a value on its left hand side is within the expression of one of the aforementioned data structures on the right hand side. If it's present a boolean
value of true
is returned, otherwise false
. not in
returns true
if the value on the left is not present within the data structure.
alist = [1,2,3,4,5]
within = 2 in alist
in
may be used in a similar way with maps in order to examine whether a key is present within the map. For example:
amap = {2 > 23, 3 > 67. 1 > 55}
within = 2 in amap
The in
keyword has special meaning when used within the context of an iterator style for loop, this is documented in the Iterator style for section.
Supporting contains?
Any class may support the operator in
by providing a contains method, this is discussed in more detail in the operator overloading section.
Not?
The not
keyword simply flips the booleanarity of a value of boolean
type. true
becomes false
and vice versa.
Postfix?
Concurnas supports the usual set of postfix operators one would expect from a modern programming language. Namely the increment ++
and decrement 
operators appearing on the right hand side of an integral expression consisting of a variable, list or array reference. These operators are applied in place. The operators may be used in a place where a value is expected to be returned from it, in which case the previous value of the variable prior to the increment or decrement operator being applied will be returned:
avar = 10
anarray = [1 2 3 4 5]
avar++
anarray[0]
prevvar = avar++
prevarray = anarray[0]
Prefix?
The prefix operators behave in a similar manner as the postfix operators though with the addition of the negation: 
operator. Unlike the others, the negation: 
operator is not applied in place and will always return a value. The operators may be used in a place where a value is expected to be returned from it, in which case the value of the variable post operator application will be returned:
avar = 10
anarray = [1 2 3 4 5]
++avar
anarray[0]
newvar = ++avar
newarray = anarray[0]
anothervar = 10
negative = anothervar//negative == 10
Multiplicative?
Concurnas supports the standard set of multiplicative operators which can act upon two, potentially differing, integral types, multiplication: *
, division: /
, power: **
and modulus: mod
. For example:
mul = 3*2 //==6
div = 12/2 //==6
pow = 3**2 //==9
pow = 9**2 //square root
modu = 10 mod 4 //==2
Attempting to divide by zero with two non floating point (either float
or double
) values will result in an exception of type java.lang.ArithmeticException
being thrown. Attempting to divide by zero with at least one floating point value will result in: Infinity
being returned. 0./0.
will resolve to NaN
.
In situations where the left and right types of the multiplicative operator differ, the more general type shall be used for the return type. For example:
div1 = 13/2f //==6.5 (float)
div2 = 13/2. //==6.5 (double)
div3 = 13f/2. //==6.5 (double)
mulong = 100*10L //1000L (long)
mulong = 100L*10. //1000. (double)
Division and power gotacha?
Often new and even experienced programmers will come across the following sort of problem:
assert 13/2 == 6.5 //fails!
The above fails because 13/2
for integers resolves to 6
and not 6.5
. Perhaps this is the answer desired, but to obtain the 'correct answer' of 6.5
, what we are looking for is a floating point calculation and this can be achieved by casting either of the arguments to the division operator to a floating point type, either float or double:
assert 13./2 == 6.5 //expected asnwer
Additive?
Concurnas supports addition: +
and subtraction 
. These are straightforward and the rules concerning generalization of numerical types as par the multiplicative operators above apply. Examples:
addition = 1+1
subtraction = 11
Additionally, the addition operator +
can be used for String concatenation. This is described in more detail in the The String concatenation operator \lstinline!+! section.
Bitshift?
Concurnas supports bit shift operators for integral types. They operate on a bit pattern, given by the left hand operand and a number of positions to shift by the right hand operand.
<<
 Left shift. Shifts a bit pattern to the left.>>>
 Unsigned right shift. Shifts a bit pattern to the right. Shifts a zero to the leftmost position.>>
 Right shift. Shifts a bit pattern to the right. Leftmost bit is shifted contingent on sign extension.
Example:
def shifty(){
a = 17
x1 = a << 2
x2 = a >> 2
x3 = a >>> 2
[x1, x2, x3]
}
shifty() //resolves to => [68, 4, 4]
Relational?
The main relational operators in Concurnas are less than: <
, greater than: >
, less than or equal:<==
and greater than or equal: >==
. These operate upon two integral types. And return a boolean
type. Examples:
lt = 1 < 2
gt = 3 > 2
lteq = 1 <== 2
gteq = 3 ==> 2
Instance of and Cast?
The instance of or cast operators may not be overloaded. They are covered in more detail in theCasting and Checking Types chapter.
Equality?
Concurnas supports two variants of equality, structural equality (as: equal: ==
and not equal: <>
) and referential equality (denoted by prefixing the equality operator with an ampersand: &
). The structural equality operators may operate upon any type, whereas the referential quality operators may only operate upon Objects. For all operator variants, they return a boolean value indicating equality. Let's look at some examples of structural equality:
eq = 10 == 10 //true
eq2 = 10 <> 12 //true
eq3 (1>3) == false //resolves to true
When it comes to structural equality for objects this is achieved by calling the equals method on the left hand side object and passing it the object on the right hand side as an argument. Note that in Concurnas this equality method is automatically created for all Objects and it resolves to provide structural equality, this behaviour can be user overridden to provide different behaviour. More details of this can be found in the Automatically generated equals and hashcode methods section. Examples:
class Person(name String)
d1 = Person('dave')
d2 = Person('dave')
f3 = Person('freddy')
assert d1 == d2 //struturally equal
assert d1 <> f3 //struturally not equal
assert d1 &== d1 //object is referentially equal to itself!
assert d1 &<> d2 //d1 and d2 though structurally equal (above) are not referentially equal
Bitwise operators?
The major bitwise operators take two integral types as input. The following operators are supported:
band
 bitwise andbor
 bitwse orbxor
 bitwise exclusive or
These operators are commonly used in order to apply masks. Example:
def pprint(xx int) => '0x' + String.format("%8s", Integer.toBinaryString((xx+256) % 256)).replace(" ", "0")
value = 0b00010101
bitmask = 0b00000001
pprint(value band bitmask) // > 0x00000001
pprint(value bor bitmask)// > 0x00010101
pprint(value bxor bitmask)// > 0x00010100
Complement?
The comp
operator can be used on an integral type in order to derive the complement of a single expression. Every 0
is flipped to a 1
and vice versa. Example:
orig byte = 0b00000011
complement= comp orig
Integer.toBinaryString((complement+256) % 256) // resolves to: '11111100'  which is the complement of the input byte.
Logical and/or?
Concurnas supports the logical and
and or
operators which can be used in order to chain together boolean
expressions. Naturally, both arguments to these operators must be of boolean
type. More then one and
or or
may be chained together. The operators both return boolean
values. Examples:
orand1 = 2 == 3 or 3>1
orand2 = 2 == 3 or 3>1 or 22>1 or 3 < 9
orand3 = 2>1 and 4>1
Short circuiting?
Short circuiting is a logical optimization in which the second argument to an operator is executed or evaluated only if the first argument does not suffice to determine the value of the expression. This sometimes catches people out when they expect all arguments of an operator to be evaluated.
For a chain of or
operators, evaluated left to right, as soon as one argument evaluates to true
, the value true
is returned (otherwise false
), similarly for the and
operator, evaluated left to right, as soon as an argument evaluates to false
, false
is returned (otherwise true
).
def eval1(toRet boolean) => toRet
def eval2(toRet boolean) => toRet
def toCall(toRet boolean) => toRet
shortcir = eval1(false) or eval1(true) or toCall(true)//toCall will never be called!
shortcir = eval1(true) and eval1(false) and toCall(true)//toCall will never be called!
Ternary?
The Ternary operator x if test else z
can be thought of as a handy shorthand for the slightly more verbose: if(test){ x }else{ z }
(in fact, under the hoot the Ternary operator is translated into this more verbose form). x
and z
must both return a value (of any type) and test
must resolve to a value of boolean
type. Example:
def test() => true
result = 12 if test() else 99
Invoke?
Concurnas allows an invoke
method to be defined for all objects, this permits the following syntax to be used in order to call this invoke
method as an operator, with optional arguments:
class FormatPlus{
def invoke(a int, b int) => "{a} + {b}"
}
fmt = FormatPlus()
fmt(12, 13)//returns: "12 + 13"
This can occasionally be useful tool to use when defining domain specific languages.
Null safety?
The null safety operators are documented in detail in the Null Safety section.
Assignment?
Variable assignment is covered in detail in the Variable assignment chapter. The assignment operator may be overloaded, this is described in the Overloading the assignment operator section, in the case of an overloaded assignment operator being defined for a type, the escaped assign of: \\=
will suppress this behaviour when a value is assigned.
Compound assignment?
Here we concern ourselves with compound assignment applied to a variable which has already been defined. These are: +=
, =
, *=
, /=
, **=
, mod=
, or=
, and=
, <<=
, >>=
, >>>=
, band=
, bor=
, bxor=
. Taking the addition assignment operator, +=
as an example, the following two statements are functionally identical:
a1 = a2 = 10
a1 += 1
a2 = a2 + 1
assert a1 == a2
That is to say, a1 += 1
is essentially shorthand for: a1 = a1 + 1
.
The compound assignment operators may be applied to array reference operations as follows:
a1 = [1 2 3]
a1[0] += 1
assert a1 == [2 2 3]
Again, a1[0] += 1
is essentially shorthand for: a1[0] = a1[0] + 1
.
Parentheses?
In Concurnas, parentheses can be used or order disambiguate expressions composed of multiple operators. They may also be used in a "no operation" capacity in order to make code easier to read. For example:
orand4 = not (2>1 and 4>1)
Operator Overloading?
Concurnas provides a mechanism by which the aforementioned operators can be supported for object types in addition to the primitives (and boxed versions thereof) above. This functionality can be extremely useful when implementing Domain Specific Languages. The following operators can be overloaded:
Class 
Operator 
Normal Token 
Method name 
Alt Name 
Type overloaded 
Notes 

Assign 
Assignment 
= 
assign 
= 
Left 
Use \= variant of assign to avoid calling overloaded operator 
Unassign 
unassign 
Left 
Where variable of type x implements unassign, use x: to avoid calling unassign operator 

Compound Assign 
Addition Assign 
+= 
plusAssign 
+= 
Left 

Negation Assign 
= 
minusAssign 
= 
Left 

Multiply Assign 
*= 
mulAssign 
*= 
Left 

Divide Assign 
/= 
divAssign 
/= 
Left 

Power Assign 
**= 
powAssign 
**= 
Left 

mod Assign 
mod= 
modAssign 
mod= 
Left 

or Assign 
or= 
orAssign 
or= 
Left 

and Assign 
and= 
andAssign 
and= 
Left 

left shift Assign 
<<= 
leftShiftAssign 
<<= 
Left 

right shift Assign 
>>= 
rightShiftAssign 
>>= 
Left 

unsigned right shift Assign 
>>>= 
rightShiftU 
>>>= 
Left 

bitwise and Assign 
band= 
bandAssign 
band= 
Left 

bitwise or Assign 
bor= 
borAssign 
bor= 
Left 

bitwise xor Assign 
bxor= 
bxorAssign 
bxor= 
Left 

Not 
Not 
not 
not 
Unary 

Postfix 
Increment 
++ 
inc 
++ 
Unary 

Decremement 
 
dec 
 
Unary 

Prefix 
Increment 
++ 
inc 
++ 
Unary 

Decremement 
 
dec 
 
Unary 

Positive 
+ 
plus 
+ 
Unary 
No arguments specified 

Negative 
 
neg 
 
Unary 
No arguments specified 

Complement 
comp 
comp 
Unary 

Multiplicative 
Multiplication 
* 
mul 
* 
Left 

Power 
** 
pow 
** 
Left 

Division 
/ 
div 
/ 
Left 

Modulus 
mod 
mod 
Left 

Additive 
Addition 
+ 
plus 
+ 
Left 

Subtraction 
 
minus 
 
Left 

Bitshift 
Left shift 
<< 
leftShift 
<< 
Left 

Right Shift 
>> 
rightShift 
>> 
Left 

Unsigned right shift 
>>> 
rightShiftU 
>>> 
Left 

Relational 
Less than 
< 
compareTo 
Left 
a.compareTo(b) < 0 

Greater than 
> 
compareTo 
Left 
a.compareTo(b) > 0 

Less than or equal 
<== 
compareTo 
Left 
a.compareTo(b) <== 0 

Greater than or equal 
>== 
compareTo 
Left 
a.compareTo(b) >== 0 

Equality 
Structurally equal 
== 
equals 
Left 
a.equals(b) 

Structurally not equal 
<> 
equals 
Left 
not a.equals(b) 

Bitwise 
Bitwise and 
band 
band 
Left 

Bitwise or 
bor 
or 
Left 

Bitwise exclusive or 
bxor 
bxor 
Left 

Logical and 
and 
and 
and 
Left 

Logical or 
or 
or 
or 
Left 

Invoke 
Invoke 
a() 
invoke 
Left 
Any number of arguments may be specified 

Lists, Arrays, Maps 
Get 
a[y] 
get 
Left 

Put 
a[y] = z 
put 
Left 

Sublist 
a[y1 ... y2] 
sub 
Left 
a.sub(y1, y2) 

Sublist from 
a[y1 ...] 
subfrom 
Left 
a.subfrom(y1) 

Sublist to 
a[... y2] 
subto 
Left 
a.subto(y2) 

Put sublist 
a[y1 ... y2] = z 
subAssign 
Left 
a.subAssign(y1, y2, z) 

Put sublist from 
a[y1 ...] = z 
subfromAssign 
Left 
a.subfromAssign(y1, z) 

Put sublist to 
a[... y2] = z 
subtoAssign 
Left 
a.subtoAssign(y2, z) 

In 
in 
contains 
Right 
b.contains(a) 

Not in 
not in 
contains 
Right 
not b.contains(a) 
Implementing and using overloaded operators?
Overloaded operators operate upon the left hand element of an expression unless it is unary where there is only one expression the operator is being applied to, or for the int
and not in
operators where the right hand expression must have the relevant method implemented. The left hand element must support the operator being invoked. For non alphanumerical named operators (e.g. +
, **
etc) the raw alphanumerical operator token may be defined as a method name, or it's alternative longhand name may be used (plus
for +
, mul
for *
etc).
class Complex(real double, imag double){
def +(other Complex) => new Complex(this.real + other.real, this.imag + other.imag)
def +(other double) => new Complex(this.real + other, this.imag)
def +=(other Complex) => this.real += other.real; this.imag += other.imag
def +=(other double) => this.real += other
override toString() => "Complex({real}, {imag})"
}
c1 = Complex(2, 3)
c2 = c1@
c3 = c1@
c4 = Complex(3, 4)
result1 = c1 + c4
result2 = c1 + 10.
c2 += c4 //compound plus assignment
c3 += 10.//compound plus assignment
//result1 == Complex(5.0, 7.0)
//result2 == Complex(12.0, 3.0)
//c2 == Complex(5.0, 7.0)
//c3 == Complex(12.0, 3.0)
Above we see the plus and compound plus assignment operator have been overloaded for the object class: Complex. Note that operator overloading methods themselves may be overloaded with differing argument types(just like regular methods).
Operator overloading via extension functions?
It's possible to implement operator overloading via use of extension functions. this is documented in the Extension functions as operator overloaders section.
Overloading the assignment operator?
The assignment operator, =
can be overloaded. Example:
class AssignOPOverload(value int){
def =(a int){ value = a; }
override toString() => "AssignOPOverload: {value}"
}
obj= new AssignOPOverload(100)
obj= 66
//thing == AssignOPOverload: 66
If the overloaded assign method returns a value then this will be ignored. If you wish to suppress invoking the assign operator then using the escaped assign of: \\=
will suppress this behaviour, and will cause the assignment to behave a normal, assigning whatever is on the right hand side to the variable expressed on the left hand side:
class AssignOPOverload(value int){
def =(a AssignOPOverload){ value = a.value + 10000; }
override toString() => "AssignOPOverload: {value}"
}
inst1 = new AssignOPOverload(100)
inst2 = new AssignOPOverload(100)
inst1 = new AssignOPOverload(22)
inst2 \= new AssignOPOverload(22) //bypass overloaded = operator
//inst1 == AssignOPOverload: 10022
//inst2 == AssignOPOverload: 22
Overloading of the assignment operator is used to great effect with off heap memory and gpu memory interaction.
Unassign?
Just as we can overload the assignment operator, so too can be implicitly overload the 'unassignment operator', consisting of a zero argument method named unassign
returning any non void type. This is best illustrated with an example:
class MyUnassignable{
myvar int
def assign(anint int) => myvar = anint;;
def unassign() => myvar
}
inst = MyUnassignable()
inst = 56
res = inst
//res == 56
If we wish to suppress the unassignment operation this can be achieved by using the :
operator as follows:
class MyUnassignable{
myvar int
def assign(anint int) => myvar = anint;;
def unassign() => myvar
override toString() => 'MyUnassignable {myvar}'
}
inst = MyUnassignable()
inst = 56
res1 = ''+ inst
res2 = '' + inst: //suppress calling of unassign()
res3 = inst:tostring() //suppress calling of unassign()
//res1 == '56'
//res2 == 'MyUnassignable 56'
//res3 == 'MyUnassignable 56'
If we wish to create a ref to a variable of type implementing the unassign()
method, and we wish to avoid 'unassigning' it then we must use an extra :
.
class MyUnassignable{
myvar int
def assign(anint int) => myvar = anint;;
def unassign() => myvar
override toString() => 'MyUnassignable {myvar}'
}
inst = MyUnassignable()
inst = 56
ref MyUnassignable: = inst:: //ordinarily we'd just use 'inst:' to create a ref
Overloading of unassignment is used to great effect with lazy variables.
Assignment operators?
If there is an object returned from an overloaded assignment operator which happens to be a ref type, then Concurnas will await for the assignment on the ref type to take place before continuing with execution. similarly, if the operator overload method being invoked is tagged with the @com.concurnas.lang.DeleteOnUnusedReturn
annotation, then delete will be called on the object returned before continuing with execution.
This applies to the following assignment operators:
The assignment operator:
=
The in place assignment operators:
+=, =, *=, /=, **=, mod=, band=, bor=, bxor=, comp=, <<=, >>=, >>>=
The sublist assignment operators:
[a ... b ] = z, [a ... ] = z, [ ... b ] = z
The escaped assignment operator: \=
is excluded from this behaviour.
Footnotes
^{1}So called as the token looks like the emoticon for Elvis Presley