1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
|
doc ///
Key
"augmented assignment"
Description
Text
Most binary @TO "operators"@ have an associated
@wikipedia "augmented assignment"@ operator that modifies the given object
using the corresponding binary operator. Essentially, @SAMP "x OP= y"@
is equivalent to @SAMP "x = x OP y"@.
Example
x = 2
x += 3
x -= 4
x *= 5
x /= 6
Text
The following augmented assignment operators are supported.
Example
importFrom(Core, "augmentedAssignmentOperators");
augmentedAssignmentOperators
SeeAlso
"installing augmented assignment methods"
///
scan(core "augmentedAssignmentOperators", op -> (
binop := concatenate drop(toSequence toString op, -1);
document {
Key => op,
Headline => "augmented assignment for " | binop,
Usage => "x " | toString op | "y",
"In most cases, ", SAMP ("x " | toString op | " y"),
" is equivalent to ", SAMP("x = x " | binop | " y"),
", unless a method is installed for the class of ",
SAMP "x", ".",
SeeAlso => {
binop,
"augmented assignment",
"installing augmented assignment methods"}}))
doc ///
Key
"installing augmented assignment methods"
Description
Text
In most cases, the default behavior of @TO "augmented assignment"@ gives
the desired result. But in some situations, it may be useful to override
this behavior and install a custom method for a given type.
Consider the following example.
Example
Foo = new SelfInitializingType of MutableList;
net Foo := x -> net x#0;
Foo + Foo := (x, y) -> Foo {x#0 + y#0};
x = Foo {1}
y = Foo {2}
x += y
Text
Note that an intermediate @SAMP "Foo"@ object was created and then
assigned to @SAMP "x"@. Instead, it would be more efficient if @SAMP "x"@
was modified directly.
Example
installMethod(symbol +=, Foo, (x, y) -> (x#0 += y#0; x));
x += y
Text
In some cases, it may be useful to fall back on the default behavior
of the given operator. When this is desired, the installed method should
return the @TO Default@ symbol.
Example
Bar = new SelfInitializingType of List;
net Bar := x -> net x#0#0;
Bar * Bar := (x, y) -> Bar {{x#0#0 * y#0#0}};
installMethod(symbol *=, Bar, (x, y) -> if isMutable x#0 then (
print "using custom method";
x#0#0 *= y#0#0; x) else Default)
x = Bar {new MutableList from {3}}
y = Bar {{4}}
x *= y
y *= x
SeeAlso
"augmented assignment"
"installing methods"
///
doc ///
Key
symbol ??
Headline
null coalescing operator
Usage
x ?? y
Inputs
x:Thing
y:Thing
Outputs
:Thing -- either @VAR "x"@ or @VAR "y"@
Description
Text
If @VAR "x"@ is null or a non-interrupting error, then @VAR "y"@
is returned. When it is an error, the error message is suppressed like
it is with @TO symbol try@.
Example
null ?? 2
1/0 ?? 3
Text
In all other cases, @VAR "x"@ is returned.
Example
5 ?? 6
Text
Note that @VAR "y"@ is lazily evaluated, that is, it is only
evaluated if it is necessary.
The null coalescing operator can be combined with
@TO "augmented assignment"@ as a shortcut for
@M2CODE "if x === null then x = y"@ and
@M2CODE "if not x#?i then x#i = y"@.
Example
x = null
x ??= 2
x ??= 3
x = new MutableList
x#0 ??= 4
peek x
x#0 ??= 5
peek x
Text
It is also possible to install a method for a particular type to
determine whether an instance @VAR "x"@ of that type should be
considered "null" or not. Such a method should return either
@VAR "x"@ or @TO null@
Example
X = new Type of BasicList;
?? X := x -> if #x > 0 then x;
x = new X from {};
y = new X from {5};
x ?? y
y ?? x
Text
It is also possible to use @VAR "??"@ as a prefix operator to call
this method.
Example
?? 2
?? x
??(1/0)
Caveat
Although this operator is "flexible" in the sense that it possible to
install a method to determine the behavior on the left-hand side, it
is not truly flexible like most other binary operators. In particular,
since it is only lazily evaluated, it is not possible to install a method
that uses the value of the right-hand side.
///
|