The modern and fun way to program.
Smudge supports all of the common operators for C-like programming languages (see more. They can be grouped in:
(
and )
, .
(dot), ,
(comma), etc).+
, /
, |
, %
, etc.)||
and &&
)<
, >
, ==
, etc.)=
, +=
, *=
, <<=
, etc.)unary-
, ~
, !
, pre++
, pre--
, etc.).post++
and post--
)There are three more operators that you can rarely find in other programming languages:
null(xxx)
xxx
is null
xxx ?: yyy
xxx
is null
, its value will be rejected and yyy
will be used instead.ref(xxx)
xxx
.Note: don’t mix up the elvis and the conditional operator! This one has another syntax:
/*
* Will result 'expr1' if the `codition` is
* verified, `expr2` otherwise.
*/
condition ? expr1 : expr2
Another important fact about operators is their priority (or precedence):
While in some cases it’s very easy to understand an expression, like in this example:
/*
* 1) computes 2 * y
* 2) divides by 5
* 3) adds x
* 4) stores the result in val
*/
val = x + 2 * y / 5;
Sometimes it could be more complicated (and could cause some bugs):
/*
* Wat?
*/
val = x && 5 == a || b ? x : y || z % 2 != 0;
So we can fix this by:
Unlike Java, Smudge does support operator overloading, so you can define the behavoir of a box or class instance when an overloadable operator is called on it. And it’s so easy!
Note: Classes is the topic of the next page, so to fully understand this paragraph, you can treat them before and then return here.
operator +
A plus sign can be used in different kinds of expressions:
a + b
++a
a++
a += b
+a
Anyway, cases (2), (3) and (4) are automatically translated to case (1) in the following way:
++a -> (a = a + 1)
a++ -> [a, a = a + 1].get(0) // Not really
a += b -> a = a + b
So, there are only two different behaviors of operator +
:
a + b
+a
Case (2) is sometimes used when you need to convert an object to an integer,
though std.cast::int(x)
is recommended.
Here’s an example of overloading:
import std.io, std.cast;
/*
* WrInt is an integer wrapper.
*/
class WrInt {
var val;
func new(v = 0) val = v;
func +(x, is_unary){
// unary+ overload (#1)
if(is_unary)
return val;
// addition overload (#2)
return WrInt(val + x);
}
func to_string // WrInt can be converted to string
return cast.string(val);
}
func main {
var obj = WrInt(5),
obj2 = obj + 100, // calling #2
obj3 = obj2 + +obj, // calling both #1 and #2
obj4 = obj3++, // calling #2
obj5 = +obj2, // calling #1
obj6 = +obj3; // calling #1
/*
* Note: in the following line
* operator+ is called on the string,
* not on an instance of WrInt
*/
io.println(
"obj = " + obj + "\n"
"obj2 = " + obj2 + "\n"
"obj3 = " + obj3 + "\n"
"obj4 = " + obj4 + "\n"
"obj5 = " + obj5 + "\n"
"obj6 = " + obj6
);
}
OUTPUT, as expected:
obj = 0
obj2 = 100
obj3 = -100
obj4 = 100
obj5 = -100
Some notes about the println call:
\n
is an escape sequence.+
between strings "\n"
and "objN = "
is not necessary
because Smudge tokenizer automatically concatenates near string literals.As we’ve seen, we can distinguish an operator+
call from an operator unary+
one thanks to a second parameter is_unary
:
is_unary
is set to null
.null
, while is_unary
is set to true
(integer 1
).The above implementation is just too simply to be used in real applications,
because it doesn’t support additions like WrInt + WrInt
and WrInt + not integer
will print meaningless error messages.
To fix these issues we can use std.cast::kin()
combined with std.system::sterr()
and
std.cast::desc()
to check the operand type:
import std.io, std.cast, std.system;
// ...
func +(x, is_unary){
if(is_unary)
return val;
if(cast.kin(this, x)) // if x is an instance of WrInt
return WrInt(val + x.val);
else if(cast.kin(123, x)) // if x is an integer
return WrInt(x + val);
// exits printing the stack trace and the message
system.sterr("'operator+' between "
+ cast.desc(this) + " and "
+ cast.desc(x) + " is not supported.");
}
// ...
The operator -
works like the operator +
, while others operators support only
a behavoir, so they will have zero or one parameters.
They’re all overloaded with the syntax (like any other normal function):
func OPERATOR (PARAMETERS) CODE
Here is the list of all overloadable operators (where rhs means Right Hand Side and CODE is omitted):
// As we've seen
func + (rhs, is_unary);
func - (rhs, is_unary);
// Function call & array subscripting
func () (args...);
func [] (args...);
// Other operators
func ~ ();
func * (rhs);
func / (rhs);
func % (rhs);
func << (rhs);
func >> (rhs);
func > (rhs);
func >= (rhs);
func < (rhs);
func <= (rhs);
func == (rhs);
func != (rhs);
func & (rhs);
func | (rhs);
func ^ (rhs);
Here’s the priority table (where priority 0 is the highest):
Feel free to consult this table while reading (or worse, writing) some difficult code.
Operator | Type | Priority | Overload? | Described |
---|---|---|---|---|
. |
Syn | 0 | No | Find inside object |
{} |
Syn | 0 | No | Group some lines of code together |
[] |
Syn | 0 | Yes: [] |
Array subscripting |
() |
Syn | 0 | Yes: () |
Function call |
[] |
Syn | 0 | No | Create list |
() |
Syn | 0 | No | Create tuple |
, |
Syn | 0 | No | Split parts of an expression |
++ |
Post | 0 | Yes: + |
Postfix increment |
-- |
Post | 0 | Yes: - |
Postfix decrement |
++ |
Pre | 1 | Yes: + |
Prefix increment |
-- |
Pre | 1 | Yes: - |
Prefix decrement |
+ |
Pre | 1 | Yes: + |
Unary plus |
- |
Pre | 1 | Yes: - |
Unary minus |
~ |
Pre | 1 | Yes: ~ |
Complement operator |
! |
Pre | 1 | No | NOT operator |
* |
Math | 2 | Yes: * |
Multiply |
/ |
Math | 2 | Yes: / |
Divide |
% |
Math | 2 | Yes: % |
Modulo |
+ |
Math | 3 | Yes: + |
Addition |
- |
Math | 3 | Yes: - |
Subtraction |
<< |
Math | 4 | Yes: << |
Left bit-shift |
>> |
Math | 4 | Yes: >> |
Right bit-shift |
> |
Cmp | 5 | Yes: > |
Greater |
>= |
Cmp | 5 | Yes: >= |
Greater or equal |
< |
Cmp | 5 | Yes: < |
Less |
<= |
Cmp | 5 | Yes: <= |
Less or equal |
== |
Cmp | 6 | Yes: == |
Equal |
!= |
Cmp | 6 | Yes: != |
Not equal |
& |
Math | 7 | Yes: & |
AND operator |
^ |
Math | 8 | Yes: ^ |
XOR operator |
| |
Math | 9 | Yes: | |
OR operator |
&& |
Log | 10 | No | Logical AND operator |
|| |
Log | 11 | No | logical OR operator |
?: |
Syn | 12 | No | Elvis operator |
?: |
Syn | 12 | No | Ternal conditional operator |
= |
Assign | 13 | No | Assign |
+= |
Assign | 13 | No | Addition and assign |
-= |
Assign | 13 | No | Subtraction and assign |
*= |
Assign | 13 | No | Assign |
/= |
Assign | 13 | No | Division and assign |
%= |
Assign | 13 | No | Modulo assign |
&= |
Assign | 13 | No | AND and assign |
^= |
Assign | 13 | No | XOR and assign |
|= |
Assign | 13 | No | OR and assign |
<<= |
Assign | 13 | No | Left bit-shift and assign |
>>= |
Assign | 13 | No | Right bit-shift and assign |
, |
Syn | 14 | No | Comma |
; |
Syn | 15 | No | Semicolon |
Previous | Home | Next |