Overloaded operators: Difference between revisions
Content added Content deleted
(Added precision regarding types.) |
Thundergnat (talk | contribs) (→{{header|Raku}}: Add a Raku example) |
||
Line 90: | Line 90: | ||
} |
} |
||
<!--</lang>--> |
<!--</lang>--> |
||
=={{header|Raku}}== |
|||
While it is very easy to overload operators in Raku, it isn't really common... |
|||
at least, not in the traditional sense. One of the founding principles of Raku is |
|||
that: "Different things should look different". It follows that "Similar things |
|||
should look similar". |
|||
To pick out one tiny example: Adding numbery things together shouldn't be easily confusable with concatenating |
|||
strings. Instead, Raku has the "concatenation" operator: ~ for joining stringy |
|||
things together. |
|||
Using a numeric-ish operator implies that you want a numeric-ish answer... so Raku |
|||
will try very hard to give you what you ask for, no matter what operands you |
|||
pass it. |
|||
Raku operators have multiple candidates to try to fulfil your request and will |
|||
try to coerce the operands to a sensible value. |
|||
Addition: |
|||
<lang perl6>say 3 + 5; # Int plus Int |
|||
say 3.0 + 0.5e1; # Rat plus Num |
|||
say '3' + 5; # Str plus Int |
|||
say 3 + '5'; # Int plus Str |
|||
say '3' + '5'; # Str plus Str |
|||
say '3.0' + '0.5e1'; # Str plus Str |
|||
say (2, 3, 4) + [5, 6]; # List plus Array</lang> |
|||
{{out}} |
|||
<pre>8 |
|||
8 |
|||
8 |
|||
8 |
|||
8 |
|||
8 |
|||
5 # a list or array evaluated numerically returns the number of elements</pre> |
|||
Concatenation: |
|||
<lang perl6>say 3 ~ 5; # Int concatenate Int |
|||
say 3.0 ~ 0.5e1; # Rat concatenate Num |
|||
say '3' ~ 5; # Str concatenate Int |
|||
say 3 ~ '5'; # Int concatenate Str |
|||
say '3' ~ '5'; # Str concatenate Str |
|||
say '3.0' ~ '0.5e1'; # Str concatenate Str |
|||
say (2, 3, 4) ~ [5, 6]; # List concatenate Array</lang> |
|||
{{out}} |
|||
<pre>35 |
|||
35 |
|||
35 |
|||
35 |
|||
35 |
|||
3.00.5e1 |
|||
2 3 45 6 # default stringification, then concatenate</pre> |
|||
There is nothing preventing you from overloading or overriding existing |
|||
operators. Raku firmly believes in not putting pointless restrictions on |
|||
what you can and can not do. Why make it hard to do the "wrong" thing when |
|||
we make it so easy to do it right? |
|||
There is no real impetus to "overload" existing operators to do ''different'' |
|||
things, it is '''very''' easy to add new operators in Raku, and nearly '''any''' |
|||
Unicode character or combination may used to define it. They may be infix, |
|||
prefix, postfix, (or post-circumfix!) The precedence, associativity and arity |
|||
are all easily defined. |
|||
Borrowed from the [[Nimber_arithmetic#Raku|Nimber arithmetic]] task: |
|||
New operators, defined in place. Arity is two (almost all infix operators are |
|||
take two arguments), precedence is set equivalent to similar existing operators, |
|||
default (right) associativity. The second, ⊗, actually uses itself to define |
|||
itself. |
|||
<lang perl6>sub infix:<⊕> (Int $x, Int $y) is equiv(&infix:<+>) { $x +^ $y } |
|||
sub infix:<⊗> (Int $x, Int $y) is equiv(&infix:<×>) { |
|||
return $x × $y if so $x|$y < 2; |
|||
my $h = exp $x.lsb, 2; |
|||
return $h ⊗ $y ⊕ (($x ⊕ $h) ⊗ $y) if $x > $h; |
|||
return $y ⊗ $x if $y.lsb < $y.msb; |
|||
return $x × $y unless my $comp = $x.lsb +& $y.lsb; |
|||
$h = exp $comp.lsb, 2; |
|||
(($x +> $h) ⊗ ($y +> $h)) ⊗ (3 +< ($h - 1)) |
|||
} |
|||
say 123 ⊗ 456;</lang> |
|||
{{out}} |
|||
<pre>31562</pre> |
|||
That's all well and good, but suppose you have a new class, say, a Line class, and |
|||
you want to be able to do arithmetic on Lines. No need to override the built |
|||
in arithmetic operators, just add a multi candidate to do the right thing. A multi |
|||
allows ''adding'' a new definition of the operator without disturbing the existing ones. |
|||
Very, '''very''' basic Line class: |
|||
<lang perl6>class Line { |
|||
has @.start; |
|||
has @.end; |
|||
method gist { "Line: start: {self.start.join: ','} end: {self.end.join: ','}" } |
|||
} |
|||
# New infix + operator to add two Lines together |
|||
multi infix:<+> (Line $x, Line $y) { |
|||
Line.new( |
|||
:start( |
|||
sqrt($x.start[0]² + $y.start[0]²), |
|||
sqrt($x.start[1]² + $y.start[1]²) |
|||
), |
|||
:end( |
|||
sqrt($x.end[0]² + $y.end[0]²), |
|||
sqrt($x.end[1]² + $y.end[1]²) |
|||
) |
|||
) |
|||
} |
|||
# In operation: |
|||
say Line.new(:start(-4,7), :end(5,0)) + Line.new(:start(1,1), :end(2,3));</lang> |
|||
{{out}} |
|||
<pre>Line: start: 4.123105625617661,7.0710678118654755 end: 5.385164807134504,3</pre> |
|||
=={{header|Wren}}== |
=={{header|Wren}}== |