4. Operators

To make it easier to write Pike, and to make the code somewhat shorter, some functions can be called with just one or two characters in the code. These functions are called operators and we have already seen how they work in plenty of examples. In this chapter I will describe in detail what they do. The operators are divided into categories depending on their function, but beware that some operators have meanings that go way beyond the scope of the category they are in.

4.1. Arithmetic operators

The arithmetic operators are the simplest ones, since they work just like you remember from math in school. The arithmetic operators are:

FunctionSyntaxIdentifierReturns
Additiona + b`+the sum of a and b
Subtractiona - b`-b subtracted from a
Negation- a`-minus a
Multiplicationa * b`*a multiplied by b
Divisiona / b`/a divided by b
Moduloa % b`%the remainder of a division between a and b
Exponentiationa ** b`**the result of raising a to the b:th power

The third column, "Identifier" is the name of the function that actually evaluates the operation. For instance, a + b can also be written as `+(a, b). I will show you how useful this can be at the end of this chapter.

When applied to integers or floats these operators do exactly what they are supposed to do. The only operator in the list not known from basic math is the modulo operator. The modulo operator returns the remainder from an integer division. It is the same as calculating a - floor(a / b) * b. floor rounds the value down to closest lower integer value. Note that the call to floor isn't needed when operating on integers, since dividing two integers will return the result as an integer and it is always rounded down. For instance, 8 / 3 would return 2.

If all arguments to the operator are integers, the result will also be an integer. If one is a float and the other is an integer, the result will be a float. If both arguments are float, the result will of course be a float.

However, there are more types in Pike than integers and floats. Here is the complete list of combinations of types you can use with these operators:

OperationReturned typeReturned value
int + int
intthe sum of the two values
float + int
int + float
float + float
floatthe sum of the two values
string + string
int + string
float + string
string + int
string + float
stringIn this case, any int or float is first converted to a string. Then the two strings are concatenated and the resulting string is returned.
array + array
arrayThe two arrays are concatenated into a new array and that new array is returned.
mapping + mapping
mappingA mapping with all the index-value pairs from both mappings is returned. If an index is present in both mappings the index-value pair from the right mapping will be used.
multiset + multiset
multisetA multiset with all the indices from both multisets is returned.
int - int
intThe right value subtracted from the left.
float - int
int - float
float - float
floatThe right value subtracted from the left.
string - string
stringA copy of the left string with all occurrences of the right string removed.
array - array
arrayA copy of the left array with all elements present in the right array removed. Example: ({2,1,4,5,3,6,7}) - ({3,5,1}) will return ({2,4,6,7}).
mapping - mapping
mappingA new mapping with all index-value pairs from the left mapping, except those indices that are also present in the right mapping.
multiset - multiset
multisetA copy of the left multiset without any index present in the left multiset.
- int
intSame as 0 - int.
- float
floatSame as 0 - float.
int * int
intthe product of the two values
float * int
int * float
float * float
floatthe product of the two values
array(string) * string
stringAll the strings in the array are concatenated with the string on the right in between each string. Example: ({"foo","bar"})*"-" will return "foo-bar".
array(array) * array
arrayAll the arrays in the left array are concatenated with the array on the right in between each array. Example: ({ ({"foo"}) ,({"bar"})})*({"-"}) will return ({ "foo","-","bar" }).
string * int
stringThis operation will concatenate the string N times. Example: "foo"*3 will return "foofoofoo".
string * float
stringThis operation will concatenate the string X times. Example: "foo"*2.5 will return "foofoofo".
array * int
stringThis operation will concatenate the array N times. Example: ({"foo"})*3 will return ({"foo","foo","foo"}).
array * float
stringThis operation will concatenate the array X times. Example: ({1,2,3})*2.5 will return ({1,2,3,1,2,3,1,2}).
int / int
intThe right integer divided by the left integer rounded towards minus infinity.
float / int
int / float
float / float
floatThe right value divided by the left value.
string / string
array(string)In symmetry with the multiplication operator, the division operator can split a string into pieces. The right string will be split at every occurrence of the right string and an array containing the results will be returned. Example: "foo-bar"/"-" will return ({"foo","bar"})
string / int
array(string)This will split the string into pieces. The size of the pieces is given by the integer. Only complete pieces will be included in the result, the 'reminder' is discarded. Example: "foo-bar"/2 will return ({"fo","o-","ba"})
string / float
array(string)This is similar to dividing a string with an integer, but it allows fraction-sized segments and the reminder will always be included. Example: "foo-bar"/2.5 will return ({"fo","o-b","ar"})
array / int
array(array)This is similar to dividing a string with an integer, but splits an array. Example: ({1,2,3,4,5,6,7})/2 will return ({({1,2}),({3,4}),({5,6})})
array / float
array(array)You should be able to predict what this does by now. :) Example: ({1,2,3,4,5,6,7,8})/2.5 will return ({({1,2}),({3,4,5}),({6,7}),({8})})
int % int
intThe remainder of a division. If a and b are integers, a%b is the same as a-(a/b)*b
float % float
int % float
float % int
floatThe remainder of a division. If a and b are floats, a%b is the same as a-floor(a/b)*b
string % int
stringThe remainder of a string division. Example: "foo-bar"%2 will return "r"
array % int
stringThe remainder of an array division. Example: ({1,2,3,4,5,6,7})%2 will return ({7})

Method`+

mixed`+(mixedarg)
mixed`+(objectarg, mixed ... more)
int`+(intarg, int ... more)
float`+(float|intarg, float|int ... more)
string`+(string|float|intarg, string|float|int ... more)
array`+(arrayarg, array ... more)
mapping`+(mappingarg, mapping ... more)
multiset`+(multisetarg, multiset ... more)

Description

Addition/concatenation.

Every expression with the + operator becomes a call to this function, i.e. a+b is the same as predef::`+(a,b). Longer + expressions are normally optimized to one call, so e.g. a+b+c becomes predef::`+(a,b,c).

Returns

If there's a single argument, that argument is returned.

If arg is an object with only one reference and an lfun::`+=(), that function is called with the rest of the arguments, and its result is returned.

Otherwise, if arg is an object with an lfun::`+(), that function is called with the rest of the arguments, and its result is returned.

Otherwise, if any of the other arguments is an object that has an lfun::``+(), the first such function is called with the arguments leading up to it, and `+() is then called recursively with the result and the rest of the arguments.

Otherwise, if arg is UNDEFINED and the other arguments are either arrays, mappings or multisets, the first argument is ignored and the remaining are added together as described below. This is useful primarily when appending to mapping values since m[x] += ({foo}) will work even if m[x] doesn't exist yet.

Otherwise the result depends on the argument types:

int|float

The result is the sum of all the arguments. It's a float if any argument is a float.

string|int|float

If any argument is a string, all will be converted to strings and concatenated in order to form the result.

array

The array arguments are concatened in order to form the result.

mapping

The result is like arg but extended with the entries from the other arguments. If the same index (according to hash_value and `==) occur in several arguments, the value from the last one is used.

multiset

The result is like arg but extended with the entries from the other arguments. Subsequences with orderwise equal indices (i.e. where `< returns false) are concatenated into the result in argument order.

The function is not destructive on the arguments - the result is always a new instance.

Note

In Pike 7.0 and earlier the addition order was unspecified.

The treatment of UNDEFINED was new in Pike 7.0.

See also

`-(), lfun::`+(), lfun::``+()


Method`+

mixed`+(mixedo)

Description

Add callback. Returns the union of two trees.


Method`-

mixed`-(mixedarg1)
mixed`-(mixedarg1, mixedarg2, mixed ... extras)
mixed`-(objectarg1, mixedarg2)
mixed`-(mixedarg1, objectarg2)
int`-(intarg1, intarg2)
float`-(floatarg1, int|floatarg2)
float`-(int|floatarg1, floatarg2)
string`-(stringarg1, stringarg2)
array`-(arrayarg1, arrayarg2)
mapping`-(mappingarg1, arrayarg2)
mapping`-(mappingarg1, mappingarg2)
mapping`-(mappingarg1, multisetarg2)
multiset`-(multisetarg1, multisetarg2)

Description

Negation/subtraction/set difference.

Every expression with the - operator becomes a call to this function, i.e. -a is the same as predef::`-(a) and a-b is the same as predef::`-(a,b). Longer - expressions are normally optimized to one call, so e.g. a-b-c becomes predef::`-(a,b,c).

Returns

If there's a single argument, that argument is returned negated. If arg1 is an object with an lfun::`-(), that function is called without arguments, and its result is returned.

If there are more than two arguments the result is: `-(`-(arg1arg2), @extras).

Otherwise, if arg1 is an object with an lfun::`-(), that function is called with arg2 as argument, and its result is returned.

Otherwise, if arg2 is an object with an lfun::``-(), that function is called with arg1 as argument, and its result is returned.

Otherwise the result depends on the argument types:

arg1 can have any of the following types:
int|float

The result is arg1 - arg2, and is a float if either arg1 or arg2 is a float.

string

The result is arg1 with all nonoverlapping occurrences of the substring arg2 removed. In cases with two overlapping occurrences, the leftmost is removed.

array|mapping|multiset

The result is like arg1 but without the elements/indices that match any in arg2 (according to `>, `<, `== and, in the case of mappings, hash_value).

The function is not destructive on the arguments - the result is always a new instance.

Note

In Pike 7.0 and earlier the subtraction order was unspecified.

Note

If this operator is used with arrays or multisets containing objects which implement lfun::`==() but notlfun::`>() and lfun::`<(), the result will be undefined.

See also

`+()


Method`-

mixed`-(mixedo)

Description

Sub[s]tract two trees from each other (key-wise).


Method`*

mixed`*(mixedarg1)
mixed`*(objectarg1, mixedarg2, mixed ... extras)
mixed`*(mixedarg1, objectarg2)
array`*(arrayarg1, intarg2)
array`*(arrayarg1, floatarg2)
string`*(stringarg1, intarg2)
string`*(stringarg1, floatarg2)
string`*(array(string) arg1, stringarg2)
array`*(array(array) arg1, arrayarg2)
float`*(floatarg1, int|floatarg2)
float`*(intarg1, floatarg2)
int`*(intarg1, intarg2)
mixed`*(mixedarg1, mixedarg2, mixed ... extras)

Description

Multiplication/repetition/implosion.

Every expression with the * operator becomes a call to this function, i.e. a*b is the same as predef::`*(a,b). Longer * expressions are normally optimized to one call, so e.g. a*b*c becomes predef::`*(a,b,c).

Returns

If there's a single argument, that argument will be returned.

If the first argument is an object that implements lfun::`*(), that function will be called with the rest of the arguments.

If there are more than two arguments, the result will be `*(`*(arg1arg2), @extras).

If arg2 is an object that implements lfun::``*(), that function will be called with arg1 as the single argument.

Otherwise the result will be as follows:

arg1 can have any of the following types:
arrayarg2 can have any of the following types:
int|float

The result will be arg1 concatenated arg2 times.

string|array

The result will be the elements of arg1 concatenated with arg2 interspersed.

string

The result will be arg1 concatenated arg2 times.

int|float

The result will be arg1 * arg2, and will be a float if either arg1 or arg2 is a float.

Note

In Pike 7.0 and earlier the multiplication order was unspecified.

See also

`+(), `-(), `/(), lfun::`*(), lfun::``*()


Method`/

mixed`/(objectarg1, mixedarg2)
mixed`/(mixedarg1, objectarg2)
array(string) `/(stringarg1, intarg2)
array(string) `/(stringarg1, floatarg2)
array(array) `/(arrayarg1, intarg2)
array(array) `/(arrayarg1, floatarg2)
array(string) `/(stringarg1, stringarg2)
array(array) `/(arrayarg1, arrayarg2)
float`/(floatarg1, int|floatarg2)
float`/(intarg1, floatarg2)
int`/(intarg1, intarg2)
mixed`/(mixedarg1, mixedarg2, mixed ... extras)

Description

Division/split.

Every expression with the / operator becomes a call to this function, i.e. a/b is the same as predef::`/(a,b).

Returns

If there are more than two arguments, the result will be `/(`/(arg1arg2), @extras).

If arg1 is an object that implements lfun::`/(), that function will be called with arg2 as the single argument.

If arg2 is an object that implements lfun::``/(), that function will be called with arg1 as the single argument.

Otherwise the result will be as follows:

arg1 can have any of the following types:
stringarg2 can have any of the following types:
int|float

The result will be and array of arg1 split in segments of length arg2. If arg2 is negative the splitting will start from the end of arg1.

string

The result will be an array of arg1 split at each occurrence of arg2. Note that the segments that matched against arg2 will not be in the result.

arrayarg2 can have any of the following types:
int|float

The result will be and array of arg1 split in segments of length arg2. If arg2 is negative the splitting will start from the end of arg1.

array

The result will be an array of arg1 split at each occurrence of arg2. Note that the elements that matched against arg2 will not be in the result.

float|int

The result will be arg1 / arg2. If both arguments are int, the result will be truncated to an int. Otherwise the result will be a float.

Note

Unlike in some languages, the function f(x) = x/n (x and n integers) behaves in a well-defined way and is always rounded down. When you increase x, f(x) will increase with one for each n:th increment. For all x, (x + n) / n = x/n + 1; crossing zero is not special. This also means that / and % are compatible, so that a = b*(a/b) + a%b for all a and b.

See also

`%


Method`%

mixed`%(objectarg1, mixedarg2)
mixed`%(mixedarg1, objectarg2)
string`%(stringarg1, intarg2)
array`%(arrayarg1, intarg2)
float`%(floatarg1, float|intarg2)
float`%(intarg1, floatarg2)
int`%(intarg1, intarg2)

Description

Modulo.

Every expression with the % operator becomes a call to this function, i.e. a%b is the same as predef::`%(a,b).

Returns

If arg1 is an object that implements lfun::`%() then that function will be called with arg2 as the single argument.

If arg2 is an object that implements lfun::``%() then that function will be called with arg2 as the single argument.

Otherwise the result will be as follows:

arg1 can have any of the following types:
string|array

If arg2 is positive, the result will be the last `%(sizeof(arg1), arg2) elements of arg1. If arg2 is negative, the result will be the first `%(sizeof(arg1), -arg2) elements of arg1.

int|float

The result will be arg1 - arg2*floor(arg1/arg2). The result will be a float if either arg1 or arg2 is a float, and an int otherwise.

For numbers, this means that

  1. a % b always has the same sign as b (typically b is positive; array size, rsa modulo, etc, and a varies a lot more than b).

  2. The function f(x) = x % n behaves in a sane way; as x increases, f(x) cycles through the values 0,1, ..., n-1, 0, .... Nothing strange happens when you cross zero.

  3. The % operator implements the binary "mod" operation, as defined by Donald Knuth (see the Art of Computer Programming, 1.2.4). It should be noted that Pike treats %-by-0 as an error rather than returning 0, though.

  4. / and % are compatible, so that a == b*floor(a/b) + a%b for all a and b.

See also

`/, floor()


Method`**

object|int|float`**(object|int|floatarg1, object|int|floatarg2)

Description

Exponentiation. Raise arg1 to the power of arg2.

4.2. Comparison operators

The arithmetic operators would be hard to use for anything interesting without the ability to compare the results to each other. For this purpose there are six comparison operators:

FunctionSyntaxIdentifierReturns
Samea == b`==1 if a is the same value as b, 0 otherwise
Not samea != b`!=0 if a is the same value as b, 1 otherwise
Greater thana > b`> 1 if a is greater than b, 0 otherwise
Greater than or equal toa >= b`>=1 if a is greater to or equal to b, 0 otherwise
Lesser thana < b`< 1 if a is lesser than b, 0 otherwise
Lesser than or equal toa <= b`<=1 if a is lesser than or equal to b, 0 otherwise

The == and != operators can be used on any type. For two values to be same they must be the same type. Therefore 1 and 1.0 are not same. Also, for two values of pointer types to be the same the two values must be pointers to the same object. It is not enough that the two objects are of the same size and contain the same data.

The other operators in the table above can only be used with integers, floats and strings. If you compare an integer with a float, the int will be promoted to a float before the comparison. When comparing strings, lexical order is used and the values of the environment variables LC_CTYPE and LC_LANG are respected.


Method`==

bool`==(mixedarg1, mixedarg2, mixed ... extras)

Description

Equality test.

Every expression with the == operator becomes a call to this function, i.e. a==b is the same as predef::`==(a,b).

If more than two arguments are given, each argument is compared with the following one as described below, and the test is successful iff all comparisons are successful.

If the first argument is an object with an lfun::`==(), that function is called with the second as argument, unless the second argument is the same as the first argument. The test is successful iff its result is nonzero (according to `!).

Otherwise, if the second argument is an object with an lfun::`==(), that function is called with the first as argument, and the test is successful iff its result is nonzero (according to `!).

Otherwise, if the arguments are of different types, the test is unsuccessful. Function pointers to programs are automatically converted to program pointers if necessary, though.

Otherwise the test depends on the type of the arguments:

int

Successful iff the two integers are numerically equal.

float

Successful iff the two floats are numerically equal and not NaN.

string

Successful iff the two strings are identical, character for character. (Since all strings are kept unique, this is actually a test whether the arguments point to the same string, and it therefore run in constant time.)

array|mapping|multiset|object|function(:void)|program|type

Successful iff the two arguments point to the same instance.

Returns

Returns 1 if the test is successful, 0 otherwise.

Note

Floats and integers are not automatically converted to test against each other, so e.g. 0==0.0 is false.

Note

Programs are not automatically converted to types to be compared type-wise.

See also

`!(), `!=()


Method`!=

bool`!=(mixedarg1, mixedarg2, mixed ... extras)

Description

Inequality test.

Every expression with the != operator becomes a call to this function, i.e. a!=b is the same as predef::`!=(a,b).

This is the inverse of `==(); see that function for further details.

Returns

Returns 1 if the test is successful, 0 otherwise.

See also

`==()


Method`>

bool`>(mixedarg1, mixedarg2, mixed ... extras)

Description

Greater than test.

Every expression with the > operator becomes a call to this function, i.e. a>b is the same as predef::`>(a,b).

Returns

Returns 1 if the arguments are strictly decreasing, and 0 (zero) otherwise.

See also

`<(), `<=(), `>=()


Method`>=

bool`>=(mixedarg1, mixedarg2, mixed ... extras)

Description

Greater than or equal test.

Every expression with the >= operator becomes a call to this function, i.e. a>=b is the same as predef::`>=(a,b).

Returns

Returns 1 if the test is successful, 0 otherwise.

Note

For total orders, e.g. integers, this is the inverse of `<().

See also

`<=(), `>(), `<()


Method`<

bool`<(mixedarg1, mixedarg2, mixed ... extras)

Description

Less than test.

Every expression with the < operator becomes a call to this function, i.e. a<b is the same as predef::`<(a,b).

Returns

Returns 1 if the test is successful, 0 otherwise.

See also

`<=(), `>(), `>=()


Method`<=

bool`<=(mixedarg1, mixedarg2, mixed ... extras)

Description

Less than or equal test.

Every expression with the <= operator becomes a call to this function, i.e. a<=b is the same as predef::`<=(a,b).

Returns

Returns 1 if the test is successful, 0 otherwise.

Note

For total orders, e.g. integers, this is the inverse of `>().

See also

`<(), `>(), `>=()

4.3. Logical operators

Logical operators are operators that operate with truth values. In Pike any value except zero is considered true. Logical operators are a very basic part of Pike. They can also decide which arguments to evaluate and which not to evaluate. Because of this most of the logical operators do not have any identifiers and can not be called as normal functions. There are four logical operators:

FunctionSyntaxReturns
Anda && bIf a is false, a is returned and b is not evaluated. Otherwise, b is returned.
Ora || bIf a is true, a is returned and b is not evaluated. Otherwise, b is returned.
Not! aReturns 0 if a is true, 1 otherwise.
If-elsea ? b : cIf a is true, b is returned and c is not evaluated. Otherwise c is returned and b is not evaluated.

Method`!

bool`!(object|function(:void) arg)
int(1..1)`!(int(0..0)arg)
int(0..0)`!(mixedarg)

Description

Logical not.

Every expression with the ! operator becomes a call to this function, i.e. !a is the same as predef::`!(a).

It's also used when necessary to test truth on objects, i.e. in a statement if (o) ... where o is an object, the test becomes the equivalent of !!o so that any lfun::`!() the object might have gets called.

Returns

If arg is an object that implements lfun::`!(), that function will be called.

If arg is 0 (zero), a destructed object, or a function in a destructed object, 1 will be returned.

Otherwise 0 (zero) will be returned.

Note

No float is considered false, not even 0.0.

See also

`==(), `!=(), lfun::`!()

4.4. Bitwise/set operators

These operators are used to manipulate bits as members in sets. They can also manipulate arrays, multisets and mappings as sets.

FunctionSyntaxIdentifierReturns
Shift lefta << b`<<Multiplies a by 2, b times.
Shift righta >> b`>>Divides a by 2, b times.
Inverse (not)~ a`~Returns -1-a.
Intersection (and)a & b`&All elements present in both a and b.
Union (or)a | b`|All elements present in a or b.
Symmetric difference (xor)a ^ b`^All elements present in a or b, but not present in both.

The first three operators can only be used with integers and should be pretty obvious.

The other three, intersection, union and symmetric difference, can be used with integers, arrays, multisets and mappings. When used with integers, these operators considers each bit in the integer a separate element. If you do not know about how bits in integers work I suggest you go look it up in some other programming book or just don't use these operators on integers.

When intersection, union or symmetric difference is used on an array each element in the array is considered by itself. So intersecting two arrays will result in an array with all elements that are present in both arrays. Example: ({7,6,4,3,2,1}) & ({1, 23, 5, 4, 7}) will return ({7,4,1}). The order of the elements in the returned array will always be taken from the left array. Elements in multisets are treated the same as elements in arrays. When doing a set operation on a mapping however, only the indices are considered. The values are just copied with the indices. If a particular index is present in both the right and left argument to a set operator, the one from the right side will be used. Example: ([1:2]) | ([1:3]) will return ([1:3]).


Method`<<

int`<<(intarg1, int(0..)arg2)
mixed`<<(objectarg1, int(0..)|objectarg2)
mixed`<<(intarg1, objectarg2)
mixed`<<(floatarg1, int(0..)arg2)

Description

Left shift.

Every expression with the << operator becomes a call to this function, i.e. a<<b is the same as predef::`<<(a,b).

If arg1 is an object that implements lfun::`<<(), that function will be called with arg2 as the single argument.

If arg2 is an object that implements lfun::``<<(), that function will be called with arg1 as the single argument.

If arg1 is a float and arg2 is a non-negative integer, arg1 will be multiplied by 1<<arg2.

Otherwise arg1 will be shifted arg2 bits left.

See also

`>>()


Method`>>

int`>>(intarg1, int(0..)arg2)
mixed`>>(objectarg1, int(0..)|objectarg2)
mixed`>>(intarg1, objectarg2)
float`>>(floatarg1, int(0..)arg2)

Description

Right shift.

Every expression with the >> operator becomes a call to this function, i.e. a>>b is the same as predef::`>>(a,b).

If arg1 is an object that implements lfun::`>>(), that function will be called with arg2 as the single argument.

If arg2 is an object that implements lfun::``>>(), that function will be called with arg1 as the single argument.

If arg1 is a float and arg2 is a non-negative integer, arg1 will be divided by 1<<arg2.

Otherwise arg1 will be shifted arg2 bits right.

See also

`<<()


Method`~

mixed`~(objectarg)
int`~(intarg)
float`~(floatarg)
type`~(type|programarg)
string`~(stringarg)

Description

Complement/inversion.

Every expression with the ~ operator becomes a call to this function, i.e. ~a is the same as predef::`~(a).

Returns

The result will be as follows:

arg can have any of the following types:
object

If arg implements lfun::`~(), that function will be called.

int

The bitwise inverse of arg will be returned.

float

The result will be -1.0 - arg.

type|program

The type inverse of arg will be returned.

string

If arg only contains characters in the range 0 - 255 (8-bit), a string containing the corresponding 8-bit inverses will be returned.

See also

`!(), lfun::`~()


Method`&

mixed`&(mixedarg1)
mixed`&(mixedarg1, mixedarg2, mixed ... extras)
mixed`&(objectarg1, mixedarg2)
mixed`&(mixedarg1, objectarg2)
int`&(intarg1, intarg2)
string`&(stringarg1, stringarg2)
array`&(arrayarg1, arrayarg2)
mapping`&(mappingarg1, mappingarg2)
mapping`&(mappingarg1, arrayarg2)
mapping`&(mappingarg1, multisetarg2)
multiset`&(multisetarg1, multisetarg2)
type`&(type|programarg1, type|programarg2)

Description

Bitwise and/intersection.

Every expression with the & operator becomes a call to this function, i.e. a&b is the same as predef::`&(a,b).

Returns

If there's a single argument, that argument is returned.

If there are more than two arguments the result is: `&(`&(arg1arg2), @extras).

Otherwise, if arg1 is an object with an lfun::`&(), that function is called with arg2 as argument, and its result is returned.

Otherwise, if arg2 is an object with an lfun::``&(), that function is called with arg1 as argument, and its result is returned.

Otherwise the result depends on the argument types:

arg1 can have any of the following types:
int

Bitwise and of arg1 and arg2.

string

The result is a string where each character is the bitwise and of the characters in the same position in arg1 and arg2. The arguments must be strings of the same length.

array|mapping|multiset

The result is like arg1 but only with the elements/indices that match any in arg2 (according to `>, `<, `== and, in the case of mappings, hash_value).

type|program

Type intersection of arg1 and arg2.

The function is not destructive on the arguments - the result is always a new instance.

Note

If this operator is used with arrays or multisets containing objects which implement lfun::`==() but notlfun::`>() and lfun::`<(), the result will be undefined.

See also

`|(), lfun::`&(), lfun::``&()


Method`|

mixed`|(mixedarg1)
mixed`|(mixedarg1, mixedarg2, mixed ... extras)
mixed`|(objectarg1, mixedarg2)
mixed`|(mixedarg1, objectarg2)
int`|(intarg1, intarg2)
string`|(stringarg1, stringarg2)
array`|(arrayarg1, arrayarg2)
mapping`|(mappingarg1, mappingarg2)
multiset`|(multisetarg1, multisetarg2)
type`|(program|typearg1, program|typearg2)

Description

Bitwise or/union.

Every expression with the | operator becomes a call to this function, i.e. a|b is the same as predef::`|(a,b).

Returns

If there's a single argument, that argument is returned.

If there are more than two arguments, the result is: `|(`|(arg1arg2), @extras).

Otherwise, if arg1 is an object with an lfun::`|(), that function is called with arg2 as argument, and its result is returned.

Otherwise, if arg2 is an object with an lfun::``|(), that function is called with arg1 as argument, and its result is returned.

Otherwise the result depends on the argument types:

arg1 can have any of the following types:
int

Bitwise or of arg1 and arg2.

string

The result is a string where each character is the bitwise or of the characters in the same position in arg1 and arg2. The arguments must be strings of the same length.

array

The result is an array with the elements in arg1 concatenated with those in arg2 that doesn't occur in arg1 (according to `>, `<, `==). The order between the elements that come from the same argument is kept.

Every element in arg1 is only matched once against an element in arg2, so if arg2 contains several elements that are equal to each other and are more than their counterparts in arg1, the rightmost remaining elements in arg2 are kept.

mapping

The result is like arg1 but extended with the entries from arg2. If the same index (according to hash_value and `==) occur in both, the value from arg2 is used.

multiset

The result is like arg1 but extended with the entries in arg2 that doesn't already occur in arg1 (according to `>, `< and `==). Subsequences with orderwise equal entries (i.e. where `< returns false) are handled just like the array case above.

type|program

Type union of arg1 and arg2.

The function is not destructive on the arguments - the result is always a new instance.

Note

If this operator is used with arrays or multisets containing objects which implement lfun::`==() but notlfun::`>() and lfun::`<(), the result will be undefined.

See also

`&(), lfun::`|(), lfun::``|()


Method`^

mixed`^(mixedarg1)
mixed`^(mixedarg1, mixedarg2, mixed ... extras)
mixed`^(objectarg1, mixedarg2)
mixed`^(mixedarg1, objectarg2)
int`^(intarg1, intarg2)
string`^(stringarg1, stringarg2)
array`^(arrayarg1, arrayarg2)
mapping`^(mappingarg1, mappingarg2)
multiset`^(multisetarg1, multisetarg2)
type`^(program|typearg1, program|typearg2)

Description

Exclusive or.

Every expression with the ^ operator becomes a call to this function, i.e. a^b is the same as predef::`^(a,b).

Returns

If there's a single argument, that argument is returned.

If there are more than two arguments, the result is: `^(`^(arg1arg2), @extras).

Otherwise, if arg1 is an object with an lfun::`^(), that function is called with arg2 as argument, and its result is returned.

Otherwise, if arg2 is an object with an lfun::``^(), that function is called with arg1 as argument, and its result is returned.

Otherwise the result depends on the argument types:

arg1 can have any of the following types:
int

Bitwise exclusive or of arg1 and arg2.

string

The result is a string where each character is the bitwise exclusive or of the characters in the same position in arg1 and arg2. The arguments must be strings of the same length.

array

The result is an array with the elements in arg1 that doesn't occur in arg2 concatenated with those in arg2 that doesn't occur in arg1 (according to `>, `< and `==). The order between the elements that come from the same argument is kept.

Every element is only matched once against an element in the other array, so if one contains several elements that are equal to each other and are more than their counterparts in the other array, the rightmost remaining elements are kept.

mapping

The result is like arg1 but with the entries from arg1 and arg2 whose indices are different between them (according to hash_value and `==).

multiset

The result is like arg1 but with the entries from arg1 and arg2 that are different between them (according to `>, `< and `==). Subsequences with orderwise equal entries (i.e. where `< returns false) are handled just like the array case above.

type|program

The result is a type computed like this: (arg1&~arg2)|(~arg1&arg2).

The function is not destructive on the arguments - the result is always a new instance.

Note

If this operator is used with arrays or multisets containing objects which implement lfun::`==() but notlfun::`>() and lfun::`<(), the result will be undefined.

See also

`&(), `|(), lfun::`^(), lfun::``^()

4.5. Indexing

The index and range operators are used to retrieve information from a complex data type.

FunctionSyntaxIdentifierReturns
Indexa [ b ]`[]Returns the index b from a.
Safe Indexa [? b ]noneReturns the index b from a, returning 0 instead of an error of a is 0
Lookupa ->identifier`->Looks up the identifier. Same as a["identifier"].
Safe Lookupa ->?identifiernoneLooks up the identifier. Same as a[? "identifier"].
Assign indexa [ b ] = c`[]=;Sets the index b in a to c.
Assign indexa ->identifier = c`->=Sets the index "identifier" in a to c.
Rangea [ b .. c ]`[..]Returns a slice of a starting at the index b and ending at c.
Rangea [ .. c ]`[..]Returns a slice of a starting at the beginning of a and ending at c.
Rangea [ b .. ]`[..]Returns a slice of a from the index b to the end of a.

The index operator can be written in two different ways. It can be written as ob [ index ] or ob->identifier. However, the latter syntax is equal to ob [ "identifier" ].

You can only index strings, arrays, mapping, multisets and objects, and some of these can only be indexed on certain things as shown in this list:

OperationReturns
string[int]
Returns the ascii value of the Nth character in the string.
array[int]
Return the element in the array corresponding to the integer.
array[int]=mixed
Sets the element in the array to the mixed value.
mapping[mixed]
mapping->identifier
Returns the value associated with the index, 0 if it is not found.
mapping[mixed]=mixed
mapping->identifier=mixed
Associate the second mixed value with the first mixed value.
multiset[mixed]
multiset->identifier
Returns 1 if the index (the value between the brackets) is present in the multiset, 0 otherwise.
multiset[mixed]=mixed
multiset->identifier=mixed
If the mixed value is true the index is added to the multiset. Otherwise the index is removed from the multiset.
object[string]
object->identifier
Returns the value of the named identifier in the object.
object[string]=mixed
object->identifier=mixed
Set the given identifier in the object to the mixed value. Only works if the identifier references a variable in the object.
program[string]
program->identifier
Returns the value of the named constant identifier in the program.
string[int..int]
Returns a piece of the string.
array[int..int]
Returns a slice of the array.

When indexing an array or string it is sometimes convenient to access index from the end instead of from the beginning. This function can be performed by using a negative index. Thus  arr[-i]  is the same as arr[sizeof(arr)-i]. Note however that this behavior does not apply to the range operator. Instead the range operator clamps it's arguments to a suitable range. This means that a[b..c] will be treated as follows:

  • If b is less than zero, the range will begin at the start of the array as if b had been zero.
  • If b is greater or equal to sizeof(a) an empty array/string will be returned.
  • If c is less than b, an empty array/string will be returned.
  • If c is greater or equal to sizeof(a) the range will continue to the end of the array/string.
  • No errors are generated in any of the above cases.

Method`[]

mixed`[](objectarg, mixedindex)
mixed`[](objectarg, stringindex)
function(:void) `[](intarg, stringindex)
int`[](stringarg, intindex)
mixed`[](arrayarg, intindex)
mixed`[](arrayarg, mixedindex)
mixed`[](mappingarg, mixedindex)
bool`[](multisetarg, mixedindex)
mixed`[](programarg, stringindex)
mixed`[](objectarg, mixedstart, mixedend)
string`[](stringarg, intstart, intend)
array`[](arrayarg, intstart, intend)

Description

Indexing.

This is the function form of expressions with the [] operator, i.e. a[i] is the same as predef::`[](a,i).

Returns

If arg is an object that implements lfun::`[](), that function is called with the index argument.

Otherwise, the action depends on the type of arg:

arg can have any of the following types:
object

The non-protected (i.e. public) symbol named index is looked up in arg.

int

The bignum function named index is looked up in arg. The bignum functions are the same as those in the Gmp.mpz class.

string

The character at index index in arg is returned as an integer. The first character in the string is at index 0 and the highest allowed index is therefore sizeof(arg)-1. A negative index number accesses the string from the end instead, from -1 for the last char back to -sizeof(arg) for the first.

array

If index is an int, index number index of arg is returned. Allowed index number are in the range [-sizeof(arg)..sizeof(arg)-1]; see the string case above for details.

If index is not an int, an array of all elements in arg indexed with index are returned. I.e. it's the same as doing column(argindex).

mapping

If index exists in arg the corresponding value is returned. Otherwise UNDEFINED is returned.

multiset

If index exists in arg, 1 is returned. Otherwise UNDEFINED is returned.

program

The non-protected (i.e. public) constant symbol index is looked up in arg.

As a compatibility measure, this function also performs range operations if it's called with three arguments. In that case it becomes equivalent to:

`[..] (arg, start, Pike.INDEX_FROM_BEG, end, Pike.INDEX_FROM_BEG)

See `[..] for further details.

Note

An indexing expression in an lvalue context, i.e. where the index is being assigned a new value, uses `[]= instead of this function.

See also

`->(), lfun::`[](), `[]=, `[..]


Method`[]

mixed`[](mixedkey)


Method`->

mixed`->(objectarg, stringindex)
mixed`->(intarg, stringindex)
mixed`->(arrayarg, stringindex)
mixed`->(mappingarg, stringindex)
bool`->(multisetarg, stringindex)
mixed`->(programarg, stringindex)

Description

Arrow indexing.

Every non-lvalue expression with the -> operator becomes a call to this function. a->b is the same as predef::`^(a,"b") where "b" is the symbol b in string form.

This function behaves like `[], except that the index is passed literally as a string instead of being evaluated.

Returns

If arg is an object that implements lfun::`->(), that function will be called with index as the single argument.

Otherwise the result will be as follows:

arg can have any of the following types:
object

The non-protected (ie public) symbol named index will be looked up in arg.

int

The bignum function named index will be looked up in arg.

array

An array of all elements in arg arrow indexed with index will be returned.

mapping

If index exists in arg the corresponding value will be returned. Otherwise UNDEFINED will be returned.

multiset

If index exists in arg, 1 will be returned. Otherwise UNDEFINED will be returned.

program

The non-protected (ie public) constant symbol index will be looked up in arg.

Note

In an expression a->b, the symbol b can be any token that matches the identifier syntax - keywords are disregarded in that context.

Note

An arrow indexing expression in an lvalue context, i.e. where the index is being assigned a new value, uses `->= instead of this function.

See also

`[](), lfun::`->(), ::`->(), `->=


Method`[]=

mixed`[]=(objectarg, mixedindex, mixedval)
mixed`[]=(objectarg, stringindex, mixedval)
mixed`[]=(arrayarg, intindex, mixedval)
mixed`[]=(mappingarg, mixedindex, mixedval)
bool`[]=(multisetarg, mixedindex, boolval)

Description

Index assignment.

Every lvalue expression with the [] operator becomes a call to this function, i.e. a[b]=c is the same as predef::`[]=(a,b,c).

If arg is an object that implements lfun::`[]=(), that function will be called with index and val as the arguments.

arg can have any of the following types:
object

The non-protected (ie public) variable named index will be looked up in arg, and assigned val.

array|mapping

Index index in arg will be assigned val.

multiset

If val is 0 (zero), one occurrance of index in arg will be removed. Otherwise index will be added to arg if it is not already there.

Returns

val will be returned.

Note

An indexing expression in a non-lvalue context, i.e. where the index is being queried instead of assigned, uses `[] instead of this function.

See also

`->=(), lfun::`[]=(), `[]


Method`[]=

mixed`[]=(mixedkey, mixedval)


Method`->=

mixed`->=(objectarg, stringindex, mixedval)
mixed`->=(mappingarg, stringindex, mixedval)
bool`->=(multisetarg, stringindex, boolval)

Description

Arrow index assignment.

Every lvalue expression with the -> operator becomes a call to this function, i.e. a->b=c is the same as predef::`->=(a,"b",c) where "b" is the symbol b in string form.

This function behaves like `[]=, except that the index is passed literally as a string instead of being evaluated.

If arg is an object that implements lfun::`->=(), that function will be called with index and val as the arguments.

arg can have any of the following types:
object

The non-protected (ie public) variable named index will be looked up in arg, and assigned val.

array|mapping

Index index in arg will be assigned val.

multiset

If val is 0 (zero), one occurrance of index in arg will be removed. Otherwise index will be added to arg if it is not already there.

Returns

val will be returned.

Note

In an expression a->b=c, the symbol b can be any token that matches the identifier syntax - keywords are disregarded in that context.

Note

An arrow indexing expression in a non-lvalue context, i.e. where the index is being queried instead of assigned, uses `-> instead of this function.

See also

`[]=(), lfun::`->=(), `->


Method`[..]

mixed`[..](mixeda, intatype, mixedb, intbtype)

See also

predef::`[..]


Method`[..]

mixed`[..](objectarg, mixedstart, intstart_type, mixedend, intend_type)
string`[..](stringarg, intstart, intstart_type, intend, intend_type)
array`[..](arrayarg, intstart, intstart_type, intend, intend_type)

Description

Extracts a subrange.

This is the function form of expressions with the [..] operator. arg is the thing from which the subrange is to be extracted. start is the lower bound of the subrange and end the upper bound.

start_type and end_type specifies how the start and end indices, respectively, are to be interpreted. The types are either Pike.INDEX_FROM_BEG, Pike.INDEX_FROM_END or Pike.OPEN_BOUND. In the last case, the index value is insignificant.

The relation between [..] expressions and this function is therefore as follows:

a[i..j]    <=>	`[..] (a, i,Pike.INDEX_FROM_BEG, j,Pike.INDEX_FROM_BEG)
    a[i..<j]   <=>	`[..] (a, i,Pike.INDEX_FROM_BEG, j,Pike.INDEX_FROM_END)
    a[i..]     <=>	`[..] (a, i,Pike.INDEX_FROM_BEG, 0,Pike.OPEN_BOUND)
    a[<i..j]   <=>	`[..] (a, i,Pike.INDEX_FROM_END, j,Pike.INDEX_FROM_BEG)
    a[<i..<j]  <=>	`[..] (a, i,Pike.INDEX_FROM_END, j,Pike.INDEX_FROM_END)
    a[<i..]    <=>	`[..] (a, i,Pike.INDEX_FROM_END, 0,Pike.OPEN_BOUND)
    a[..j]     <=>	`[..] (a, 0,Pike.OPEN_BOUND, j,Pike.INDEX_FROM_BEG)
    a[..<j]    <=>	`[..] (a, 0,Pike.OPEN_BOUND, j,Pike.INDEX_FROM_END)
    a[..]      <=>	`[..] (a, 0,Pike.OPEN_BOUND, 0,Pike.OPEN_BOUND)

The subrange is specified as follows by the two bounds:

  • If the lower bound refers to an index before the lowest allowable (typically zero) then it's taken as an open bound which starts at the first index (without any error).

  • Correspondingly, if the upper bound refers to an index past the last allowable then it's taken as an open bound which ends at the last index (without any error).

  • If the lower bound is less than or equal to the upper bound, then the subrange is the inclusive range between them, i.e. from and including the element at the lower bound and up to and including the element at the upper bound.

  • If the lower bound is greater than the upper bound then the result is an empty subrange (without any error).

Returns

The returned value depends on the type of arg:

arg can have any of the following types:
string

A string with the characters in the range is returned.

array

An array with the elements in the range is returned.

object

If the object implements lfun::`[..], that function is called with the four remaining arguments.

As a compatibility measure, if the object does not implement lfun::`[..] but lfun::`[] then the latter is called with the bounds transformed to normal from-the-beginning indices in array-like fashion:

`[..] (a, i, Pike.INDEX_FROM_BEG, j, Pike.INDEX_FROM_BEG)

Calls a->`[] (i, j)

`[..] (a, i, Pike.INDEX_FROM_BEG, j, Pike.INDEX_FROM_END)

Calls a->`[] (i, a->_sizeof()-1-j)

`[..] (a, i, Pike.INDEX_FROM_BEG, 0, Pike.OPEN_BOUND)

Calls a->`[] (i, Int.NATIVE_MAX)

`[..] (a, i, Pike.INDEX_FROM_END, j, Pike.INDEX_FROM_BEG)

Calls a->`[] (a->_sizeof()-1-i, j)

`[..] (a, i, Pike.INDEX_FROM_END, j, Pike.INDEX_FROM_END)

Calls a->`[] (a->_sizeof()-1-i, a->_sizeof()-1-j), except that a->_sizeof() is called only once.

`[..] (a, i, Pike.INDEX_FROM_END, 0, Pike.OPEN_BOUND)

Calls a->`[] (a->_sizeof()-1-i, Int.NATIVE_MAX)

`[..] (a, 0, Pike.OPEN_BOUND, j, Pike.INDEX_FROM_BEG)

Calls a->`[] (0, j)

`[..] (a, 0, Pike.OPEN_BOUND, j, Pike.INDEX_FROM_END)

Calls a->`[] (0, a->_sizeof()-1-j)

`[..] (a, 0, Pike.OPEN_BOUND, 0, Pike.OPEN_BOUND)

Calls a->`[] (0, Int.NATIVE_MAX)

Note that Int.NATIVE_MAX might be replaced with an even larger integer in the future.

See also

lfun::`[..], `[]

4.6. The assignment operators

There is really only one assignment operator, but it can be combined with lots of other operators to make the code shorter. An assignment looks like this:


	variable = expression;
The variable can be a local variable, a global variable or an index in an array, object, multiset or mapping. This will of course set the value stored in variable to expression. Note that the above is also an expression which returns the value of the expression. This can be used in some interesting ways:

	variable1 = variable2 = 1; // Assign 1 to both variables
	variable1 =(variable2 = 1); // Same as above

	// Write the value of the expression, if any
	if(variable = expression)
	  write(variable);
Using assignments like this can however be confusing to novice users, or users who come from a Pascal or Basic background. Especially the if statement can be mistaken for if(variable == expression) which would mean something completely different. As I mentioned earlier, the assignment operator can be combined with another operator to form operators that modify the contents of a variable instead of just assigning it. Here is a list of all the combinations:
SyntaxSame asFunction
variable += expressionvariable = variable + expressionAdd expression to variable
variable -= expressionvariable = variable - expressionSubtract expression from variable
variable *= expressionvariable = variable * expressionMultiply variable with expression
variable /= expressionvariable = variable / expressionDivide variable by expression
variable %= expressionvariable = variable % expressionModulo variable by expression
variable <<= expressionvariable = variable << expressionShift variableexpression bits left
variable >>= expressionvariable = variable >> expressionShift variableexpression bits right
variable |= expressionvariable = variable | expressionOr variable with expression
variable &= expressionvariable = variable & expressionAnd variable with expression
variable ^= expressionvariable = variable ^ expressionXor variable with expression

In all of the above expressions variable can actually be any of type of assignable values. Assignable values are also known as lvalues and here is a list of lvalues:

Lvalue typeSyntaxValid assignment type
a local or global variable identifiersame as variable
an element in an array array [ int ]any type
elements in elements in an array array [ string ]any type This is like map(arr, `[]=,string_indexing_element, assignment_element)
an element in an string string [ int ]integer
an element in a mapping mapping[mixed] or mapping->identifierany type
an element in a multiset multiset[mixed] or multiset->identifiertrue / false
a variable in an object object[string] or object->identifiersame type as named variable
a list of lvalues [ lvalue, lvalue ] an array, first value in the array will be assigned to the first lvalue in the list, second value in the array to the second value in the list etc.

4.7. The rest of the operators

Now there are only a couple of operators left. I have grouped them together in this section, not because they are not important, but because they do not fit in any particular categories.

FunctionSyntaxIdentifierReturns
Callinga ( args )`()Calls the function a.
Safe Callinga (? args )`()Calls a, unless a is 0.
splice@ anoneSends each element in the array a as an individual argument to a function call.
Increment++ anoneIncrements a and returns the new value of a.
Decrement-- anoneDecrements a and returns the new value of a.
Post incrementa ++noneIncrements a and returns the old value of a.
Post decrementa --noneDecrements a and returns the old value of a.
casting(type) anoneTries to convert a into a value of the specified type.
Nulla, bnoneEvaluates a and b, then returns b.

The most important of these operators is the calling operator. It is used to call functions. The operator itself is just a set of parenthesis placed after the expression that returns the function. Any arguments to the function should be placed between the parenthesis, separated by commas. We have already seen many examples of this operator, although you might not have realized it was an operator at the time. The function call operator can do more than just calling functions though; if the 'function' is in fact an array, the operator will loop over the array and call each element in the array and returns an array with the results.

If on the other hand, the 'function' is a program, the operator will clone an object from the program and call create() in the new object with the arguments given. In fact, the function clone is implemented like this:


object clone(mixed p, mixed ... args) { ( (program)p )(@args); }
Placing a '?' character immediately after the open parentehsis makes the operator return 0 instead of an error if the function expression evalutates to 0. On the subject of function calls, the splice operator should also be mentioned. The splice operator is an at sign in front of an expression. The expression should always be an array. The splice operator sends each of the elements in the array as a separate argument to the function call. The splice operator can only be used in an argument list for a function call.

Then there are the increment and decrement operators. The increment and decrement operators are somewhat limited: they can only be used on integers. They provide a short and fast way to add or subtract one to an integer. If the operator is written before the variable (++a) the returned value will be what the variable is after the operator has added/subtracted one to it. If the operator is after the variable (a++) it will instead return the value of the variable before it was incremented/decremented.

Casting is used to convert one type to another, not all casts are possible. Here is a list of all casts that actually _do_ anything:

casting fromtooperation
intstringConvert the int to ASCII representation
floatstringConvert the float to ASCII representation
stringintConvert decimal, octal or hexadecimal number to an int. Note that this will only work with decimal numbers in future versions.
stringfloatConvert ASCII number to a float.
stringprogramString is a filename, compile the file and return the program. Results are cached.
stringobjectThis first casts the string to a program, (see above) and then clones the result. Results are cached.
objecttypeThis calls the function 'cast' with a string containing the type as an argument.
stringarraySame as doing values(string)
array(int)stringThis does the inverse of the operation above. Ie. it constructs a string from an array of integers.
arrayarray(type)This recursively casts all values in the array to type.
mappingarraySame as Array.transpose(({indices(mapping),values(mapping)). Example: (array)([1:2,3:4]) will return ({ ({1,2}), ({3,4}) })
multisetarraySame as doing indices(multiset).
intfloatReturns a float with the same value as the integer.
floatintReturns the integer closest to the float.
functionobjectSame as function_object(function).

You can also use the cast operator to tell the compiler things. If a is a variable of type mixed containing an int, then the expression (int)a can be used instead of a and that will tell the compiler that the type of that expression is int.

Last, and in some respect least, is the comma operator. It doesn't do much. In fact, it simply evaluates the two arguments and then returns the right hand one. This operator is mostly useful to produce smaller code, or to make defines that can be used in expressions.


Method`()
Methodcall_function

mixed`()(function(:void) fun, mixed ... args)
mixedcall_function(function(:void) fun, mixed ... args)

Description

Call a function.

Calls the function fun with the arguments specified by args.

See also

lfun::`()()

4.8. Operator precedence

When evaluating an expression, you can always use parenthesis to tell the compiler in which order to evaluate things. Normally, the compiler will evaluate things from left to right, but it will evaluate operators with higher priority before those with lower. The following table shows the relative priority of all the operators in descending order:

(a) a() a[b] a->b a[b..c] ({}) ([]) (<>)
!a ~a (type)a ++a --a
a++ a--
a*b a/b a%b
a+b a-b
a>>b a<<b
a>b a>=b a<b a<=b
a==b a!=b
a&b
a^b
a|b
&&
||
a?b:c
=
@a
,

Examples:

The expressionis evaluated in this order:
 1+2*2  1+(2*2) 
 1+2*2*4  1+((2*2)*4) 
 (1+2)*2*4  ((1+2)*2)*4 
 1+4,c=2|3+5  (1+4),(c=((2|3)+5)) 
 1+5 & 4 == 3  (1+(5 & 4)) == 3 
 c=1,99  (c=1),99 
 !a++ + ~--a() (!(a++)) + (~((--a)())) 

4.9. Operator functions

As mentioned earlier a + b can just as well be written as `+(a, b). Together with the function map which calls a function for every index in an array and the splice operator this can be used to create some very very fast and compact code. Let's look at some examples:

map(arr, `-)
This will return an array with each element negated.
map(text/"\n",`/," ")
This will divide a text into lines, each line will then be mapped through `/ and divided into an array of words.
`+(0, @arr)
This will add all the integers in the array arr together.
int abs(int a) { return ( a>0 ? `+ : `-)(a); }
This is a rather absurd but working function which will return the absolute value of a.