Overloaded operators: Difference between revisions

From Rosetta Code
Content added Content deleted
(Overloaded operators en FreeBASIC)
m (→‎{{header|Wren}}: Minor tidy)
 
(8 intermediate revisions by 5 users not shown)
Line 10: Line 10:


Many commands have multiple [[6502_Assembly#Addressing_Modes| addressing modes]], which alter the way a command is executed. On the 6502 most of these are in fact different opcodes, using the same mnemonic.
Many commands have multiple [[6502_Assembly#Addressing_Modes| addressing modes]], which alter the way a command is executed. On the 6502 most of these are in fact different opcodes, using the same mnemonic.
<lang 6502asm>LDA #$80 ;load the value 0x80 (decimal 128) into the accumulator.
<syntaxhighlight lang="6502asm">LDA #$80 ;load the value 0x80 (decimal 128) into the accumulator.
LDA $80 ;load the value stored at zero page memory address $80
LDA $80 ;load the value stored at zero page memory address $80
LDA $2080 ;load the value stored at absolute memory address $2080.
LDA $2080 ;load the value stored at absolute memory address $2080.
LDA $80,x ;load the value stored at memory address ($80+x).
LDA $80,x ;load the value stored at memory address ($80+x).
LDA ($80,x) ;use the values stored at $80+x and $81+x as a 16-bit memory address to load from.
LDA ($80,x) ;use the values stored at $80+x and $81+x as a 16-bit memory address to load from.
LDA ($80),y ;use the values stored at $80 and $81 as a 16-bit memory address to load from. Load from that address + y.</lang>
LDA ($80),y ;use the values stored at $80 and $81 as a 16-bit memory address to load from. Load from that address + y.</syntaxhighlight>

=={{header|68000 Assembly}}==
Most assemblers will interpret instructions such as <code>MOVE</code>, <code>ADD</code>, etc. according to the operand types provided.
<syntaxhighlight lang="68000devpac">MOVE.L D0,A0 ;assembles the same as MOVEA.L D0,A0
EOR.W #%1100000000000000,D5 ;assembles the same as EORI.W #%1100000000000000,D5
CMP.W myAddress,D4 ;assembles the same as CMPM.W myAddress,D4</syntaxhighlight>

If you use <code>MOVE.W</code> with an address register as the destination, the CPU will sign-extend the value once it's loaded into the address register. In other words, a word that is $8000 or "more" will get padded to the left with Fs, whereas anything $7FFF or less will be padded with zeroes.
<syntaxhighlight lang="68000devpac">MOVE.W #$9001,A0 ;equivalent of MOVEA.L #$FFFF9001,A0
MOVE.W #$200,A1 ;equivalent of MOVEA.L #$00000200,A1</syntaxhighlight>

=={{header|Ada}}==
Many Ada standard libraries overload operators. The following examples are taken from the Ada Language Reference Manual describing operators for vector and matrix types:

<syntaxhighlight lang="ada">type Real_Vector is array (Integer range <>) of Real'Base;
type Real_Matrix is array (Integer range <>, Integer range <>) of Real'Base;
-- Real_Vector arithmetic operations
function "+" (Right : Real_Vector) return Real_Vector;
function "-" (Right : Real_Vector) return Real_Vector;
function "abs" (Right : Real_Vector) return Real_Vector;
function "+" (Left, Right : Real_Vector) return Real_Vector;
function "-" (Left, Right : Real_Vector) return Real_Vector;
function "*" (Left, Right : Real_Vector) return Real'Base;
function "abs" (Right : Real_Vector) return Real'Base;
-- Real_Vector scaling operations
function "*" (Left : Real'Base; Right : Real_Vector)
return Real_Vector;
function "*" (Left : Real_Vector; Right : Real'Base)
return Real_Vector;
function "/" (Left : Real_Vector; Right : Real'Base)
return Real_Vector;
-- Real_Matrix arithmetic operations
function "+" (Right : Real_Matrix) return Real_Matrix;
function "-" (Right : Real_Matrix) return Real_Matrix;
function "abs" (Right : Real_Matrix) return Real_Matrix;
function Transpose (X : Real_Matrix) return Real_Matrix;
function "+" (Left, Right : Real_Matrix) return Real_Matrix;
function "-" (Left, Right : Real_Matrix) return Real_Matrix;
function "*" (Left, Right : Real_Matrix) return Real_Matrix;
function "*" (Left, Right : Real_Vector) return Real_Matrix;
function "*" (Left : Real_Vector; Right : Real_Matrix)
return Real_Vector;
function "*" (Left : Real_Matrix; Right : Real_Vector)
return Real_Vector;
-- Real_Matrix scaling operations
function "*" (Left : Real'Base; Right : Real_Matrix)
return Real_Matrix;
function "*" (Left : Real_Matrix; Right : Real'Base)
return Real_Matrix;
function "/" (Left : Real_Matrix; Right : Real'Base)
return Real_Matrix;</syntaxhighlight>

The following examples are from the Ada package Ada.Numerics.Generic_Complex_Types

<syntaxhighlight lang="ada"> function "+" (Right : Complex) return Complex;
function "-" (Right : Complex) return Complex;
function Conjugate (X : Complex) return Complex;

function "+" (Left, Right : Complex) return Complex;
function "-" (Left, Right : Complex) return Complex;
function "*" (Left, Right : Complex) return Complex;
function "/" (Left, Right : Complex) return Complex;

function "**" (Left : Complex; Right : Integer) return Complex;

function "+" (Right : Imaginary) return Imaginary;
function "-" (Right : Imaginary) return Imaginary;
function Conjugate (X : Imaginary) return Imaginary renames "-";
function "abs" (Right : Imaginary) return Real'Base;

function "+" (Left, Right : Imaginary) return Imaginary;
function "-" (Left, Right : Imaginary) return Imaginary;
function "*" (Left, Right : Imaginary) return Real'Base;
function "/" (Left, Right : Imaginary) return Real'Base;

function "**" (Left : Imaginary; Right : Integer) return Complex;

function "<" (Left, Right : Imaginary) return Boolean;
function "<=" (Left, Right : Imaginary) return Boolean;
function ">" (Left, Right : Imaginary) return Boolean;
function ">=" (Left, Right : Imaginary) return Boolean;

function "+" (Left : Complex; Right : Real'Base) return Complex;
function "+" (Left : Real'Base; Right : Complex) return Complex;
function "-" (Left : Complex; Right : Real'Base) return Complex;
function "-" (Left : Real'Base; Right : Complex) return Complex;
function "*" (Left : Complex; Right : Real'Base) return Complex;
function "*" (Left : Real'Base; Right : Complex) return Complex;
function "/" (Left : Complex; Right : Real'Base) return Complex;
function "/" (Left : Real'Base; Right : Complex) return Complex;

function "+" (Left : Complex; Right : Imaginary) return Complex;
function "+" (Left : Imaginary; Right : Complex) return Complex;
function "-" (Left : Complex; Right : Imaginary) return Complex;
function "-" (Left : Imaginary; Right : Complex) return Complex;
function "*" (Left : Complex; Right : Imaginary) return Complex;
function "*" (Left : Imaginary; Right : Complex) return Complex;
function "/" (Left : Complex; Right : Imaginary) return Complex;
function "/" (Left : Imaginary; Right : Complex) return Complex;

function "+" (Left : Imaginary; Right : Real'Base) return Complex;
function "+" (Left : Real'Base; Right : Imaginary) return Complex;
function "-" (Left : Imaginary; Right : Real'Base) return Complex;
function "-" (Left : Real'Base; Right : Imaginary) return Complex;
function "*" (Left : Imaginary; Right : Real'Base) return Imaginary;
function "*" (Left : Real'Base; Right : Imaginary) return Imaginary;
function "/" (Left : Imaginary; Right : Real'Base) return Imaginary;
function "/" (Left : Real'Base; Right : Imaginary) return Imaginary;</syntaxhighlight>


=={{header|ALGOL 68}}==
=={{header|ALGOL 68}}==
Line 23: Line 131:
For new dyadic operators, the priority must be specified (though some implementations provide a default).
For new dyadic operators, the priority must be specified (though some implementations provide a default).
In both cases this is done with a PRIO declaration.
In both cases this is done with a PRIO declaration.
<lang algol68>BEGIN
<syntaxhighlight lang="algol68">BEGIN
# Algol 68 allows operator overloading, both of existing operators and new ones #
# Algol 68 allows operator overloading, both of existing operators and new ones #
# Programmer defined operators can be a "bold word" (uppercase word) or a symbol #
# Programmer defined operators can be a "bold word" (uppercase word) or a symbol #
Line 53: Line 161:
OP + = ( INT a, BOOL b )INT: IF b THEN a + 1 ELSE a FI;
OP + = ( INT a, BOOL b )INT: IF b THEN a + 1 ELSE a FI;
print( ( TOSTRING a + " ""+"" " + TOSTRING ( a = 10 ) + " = " + TOSTRING ( a + ( a = 10 ) ), newline ) )
print( ( TOSTRING a + " ""+"" " + TOSTRING ( a = 10 ) + " = " + TOSTRING ( a + ( a = 10 ) ), newline ) )
END</lang>
END</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 65: Line 173:


For example, <code>⌊</code> is Floor in the monadic case:
For example, <code>⌊</code> is Floor in the monadic case:
<lang bqn> ⌊4.5
<syntaxhighlight lang="bqn"> ⌊4.5
4</lang>
4</syntaxhighlight>
But in the dyadic case, it becomes Minimum:
But in the dyadic case, it becomes Minimum:
<lang bqn> 4 ⌊ 3
<syntaxhighlight lang="bqn"> 4 ⌊ 3
3</lang>
3</syntaxhighlight>


=={{header|C++}}==
=={{header|C++}}==
Line 75: Line 183:


And yes, I know subtracting cuboids can give negative volumes. It's theoretically possible (remember volume or triple integrals ? ).
And yes, I know subtracting cuboids can give negative volumes. It's theoretically possible (remember volume or triple integrals ? ).
<lang cpp>
<syntaxhighlight lang="cpp">
//Aamrun, 4th October 2021
//Aamrun, 4th October 2021


Line 154: Line 262:
return 0;
return 0;
}
}
</syntaxhighlight>
</lang>
{{out}}
{{out}}
<pre>
<pre>
Line 165: Line 273:
=={{header|F_Sharp|F#}}==
=={{header|F_Sharp|F#}}==
For those who complain that they can't follow my F# examples perhaps if I do the following it will help them.
For those who complain that they can't follow my F# examples perhaps if I do the following it will help them.
<lang fsharp>
<syntaxhighlight lang="fsharp">
// Overloaded operators. Nigel Galloway: September 16th., 2021
// Overloaded operators. Nigel Galloway: September 16th., 2021
let (+) (n:int) (g:int) = n-g
let (+) (n:int) (g:int) = n-g
printfn "%d" (23+7)
printfn "%d" (23+7)
</syntaxhighlight>
</lang>
{{out}}
{{out}}
<pre>
<pre>
Line 180: Line 288:
The following example overloads the member operators <code>Cast</code>(Cast) and <code>*=</code>(Multiply And Assign) for objects of a user-defined type.
The following example overloads the member operators <code>Cast</code>(Cast) and <code>*=</code>(Multiply And Assign) for objects of a user-defined type.


<lang freebasic>Type Rational
<syntaxhighlight lang="freebasic">Type Rational
As Integer numerator, denominator
As Integer numerator, denominator
Line 204: Line 312:
r1 *= r2
r1 *= r2
Dim As Double d = r1
Dim As Double d = r1
Print r1, d</lang>
Print r1, d</syntaxhighlight>




Line 225: Line 333:


Note that `+` is symmetric except for its restriction to object x object, as illustrated by:
Note that `+` is symmetric except for its restriction to object x object, as illustrated by:
<lang jq>{"a":1} + {"a": 2} #=> {"a": 2}
<syntaxhighlight lang="jq">{"a":1} + {"a": 2} #=> {"a": 2}


{"a":2} + {"a": 1} #=> {"a": 1}</lang>
{"a":2} + {"a": 1} #=> {"a": 1}</syntaxhighlight>
Most of the other operators that are usually thought of as "arithmetic" are also overloaded, notably:
Most of the other operators that are usually thought of as "arithmetic" are also overloaded, notably:
<pre>
<pre>
Line 239: Line 347:


The comparison operators can also be used on non-JSON entities as well, e.g.
The comparison operators can also be used on non-JSON entities as well, e.g.
<syntaxhighlight lang="jq">
<lang jq>
0 < infinite #=> true
0 < infinite #=> true
nan < 0 #=> true
nan < 0 #=> true
</syntaxhighlight>
</lang>


The logical operators (`and`, `or`, `not`) are also defined for all JSON entities, their logic being
The logical operators (`and`, `or`, `not`) are also defined for all JSON entities, their logic being
Line 252: Line 360:
`length/0` is defined on all JSON entities except `true` and `false`. Note that it is defined
`length/0` is defined on all JSON entities except `true` and `false`. Note that it is defined
as the absolute value on JSON numbers, and that:
as the absolute value on JSON numbers, and that:
<lang jq>nan|length #=> null</lang>
<syntaxhighlight lang="jq">nan|length #=> null</syntaxhighlight>


It is also worth pointing out that a single name/arity function can have multiple definitions within
It is also worth pointing out that a single name/arity function can have multiple definitions within
Line 258: Line 366:
directly accessible. The functionality of the "outer" definition, however, can be accessed indirectly,
directly accessible. The functionality of the "outer" definition, however, can be accessed indirectly,
as illustrated by the following contrived example:
as illustrated by the following contrived example:
<lang jq>def foo:
<syntaxhighlight lang="jq">def foo:
def outer_length: length;
def outer_length: length;
def length: outer_length | tostring;
def length: outer_length | tostring;
[outer_length, length];
[outer_length, length];


"x" | foo #=> [1, "1"]</lang>
"x" | foo #=> [1, "1"]</syntaxhighlight>


=={{header|Julia}}==
=={{header|Julia}}==
Most operators in Julia's base syntax are in fact just syntactic sugar for function calls. In particular, the symbols:
Most operators in Julia's base syntax are in fact just syntactic sugar for function calls. In particular, the symbols:
<lang julia>
<syntaxhighlight lang="julia">
* / ÷ % & ⋅ ∘ × ∩ ∧ ⊗ ⊘ ⊙ ⊚ ⊛ ⊠ ⊡ ⊓ ∗ ∙ ∤ ⅋ ≀ ⊼ ⋄ ⋆ ⋇ ⋉ ⋊ ⋋ ⋌ ⋏ ⋒ ⟑ ⦸ ⦼ ⦾ ⦿ ⧶ ⧷ ⨇ ⨰ ⨱ ⨲ ⨳ ⨴ ⨵ ⨶ ⨷ ⨸ ⨻
* / ÷ % & ⋅ ∘ × ∩ ∧ ⊗ ⊘ ⊙ ⊚ ⊛ ⊠ ⊡ ⊓ ∗ ∙ ∤ ⅋ ≀ ⊼ ⋄ ⋆ ⋇ ⋉ ⋊ ⋋ ⋌ ⋏ ⋒ ⟑ ⦸ ⦼ ⦾ ⦿ ⧶ ⧷ ⨇ ⨰ ⨱ ⨲ ⨳ ⨴ ⨵ ⨶ ⨷ ⨸ ⨻
⨼ ⨽ ⩀ ⩃ ⩄ ⩋ ⩍ ⩎ ⩑ ⩓ ⩕ ⩘ ⩚ ⩜ ⩞ ⩟ ⩠ ⫛ ⊍ ▷ ⨝ ⟕ ⟖ ⟗
⨼ ⨽ ⩀ ⩃ ⩄ ⩋ ⩍ ⩎ ⩑ ⩓ ⩕ ⩘ ⩚ ⩜ ⩞ ⩟ ⩠ ⫛ ⊍ ▷ ⨝ ⟕ ⟖ ⟗
</syntaxhighlight>
</lang>
are parsed in the same precedence as the multiplication operator function *, and the symbols:
are parsed in the same precedence as the multiplication operator function *, and the symbols:
<lang julia>
<syntaxhighlight lang="julia">
+ - ⊕ ⊖ ⊞ ⊟ ∪ ∨ ⊔ ± ∓ ∔ ∸ ≏ ⊎ ⊻ ⊽ ⋎ ⋓ ⧺ ⧻ ⨈ ⨢ ⨣ ⨤ ⨥ ⨦ ⨧ ⨨ ⨩ ⨪ ⨫ ⨬ ⨭ ⨮ ⨹ ⨺ ⩁ ⩂ ⩅ ⩊ ⩌ ⩏ ⩐ ⩒ ⩔ ⩖ ⩗ ⩛ ⩝ ⩡ ⩢ ⩣
+ - ⊕ ⊖ ⊞ ⊟ ∪ ∨ ⊔ ± ∓ ∔ ∸ ≏ ⊎ ⊻ ⊽ ⋎ ⋓ ⧺ ⧻ ⨈ ⨢ ⨣ ⨤ ⨥ ⨦ ⨧ ⨨ ⨩ ⨪ ⨫ ⨬ ⨭ ⨮ ⨹ ⨺ ⩁ ⩂ ⩅ ⩊ ⩌ ⩏ ⩐ ⩒ ⩔ ⩖ ⩗ ⩛ ⩝ ⩡ ⩢ ⩣
</syntaxhighlight>
</lang>
are parsed as infix operators with the same precedence as +. There are many other operator symbols that can be used as prefix or as infix operators once defined as a function in Julia.
are parsed as infix operators with the same precedence as +. There are many other operator symbols that can be used as prefix or as infix operators once defined as a function in Julia.
<br /><br />
<br /><br />
As a language, much of Julia is organized around the concept of multiple dispatch. Because the language dispatches function calls according to the types of the function arguments, even the base arithmetic operators are in fact overloaded operators in Julia.
As a language, much of Julia is organized around the concept of multiple dispatch. Because the language dispatches function calls according to the types of the function arguments, even the base arithmetic operators are in fact overloaded operators in Julia.
For example,<lang julia>2 * 3</lang> is sent to the function *(x::Int, y::Int)::Int, whereas <lang julia>2.0 * 3.0</lang>
For example,<syntaxhighlight lang="julia">2 * 3</syntaxhighlight> is sent to the function *(x::Int, y::Int)::Int, whereas <syntaxhighlight lang="julia">2.0 * 3.0</syntaxhighlight>
is dispatched to the overloaded function *(x::Float64, y::Float64)::Float64. Similarly, string concatenation in Julia is with * rather than +, so "hello " * "world" is dispatched to the overloaded function *(x::String, y::String)::String, and other types such as matrices also have arithmetic operators overloaded in base Julia:
is dispatched to the overloaded function *(x::Float64, y::Float64)::Float64. Similarly, string concatenation in Julia is with * rather than +, so "hello " * "world" is dispatched to the overloaded function *(x::String, y::String)::String, and other types such as matrices also have arithmetic operators overloaded in base Julia:
<lang julia>julia> x = [1 2; 3 4]; y = [50 60; 70 80]; x + y
<syntaxhighlight lang="julia">julia> x = [1 2; 3 4]; y = [50 60; 70 80]; x + y
2×2 Matrix{Int64}:
2×2 Matrix{Int64}:
51 62
51 62
73 84
73 84
</syntaxhighlight>
</lang>
Users may define their own overloaded functions in similar ways, whether or not such operators are already used in base Julia. In general, it is considered bad practice, and as "type piracy", to define a user overloaded operator which dispatches on the same types for which base Julia has already defined the same function. Instead, user defined types can be best made to have analogous operators defined for
Users may define their own overloaded functions in similar ways, whether or not such operators are already used in base Julia. In general, it is considered bad practice, and as "type piracy", to define a user overloaded operator which dispatches on the same types for which base Julia has already defined the same function. Instead, user defined types can be best made to have analogous operators defined for
the new type so as to leverage existing code made for analogous base types. This can allow generic functions to use new types in efficient and constructive ways.
the new type so as to leverage existing code made for analogous base types. This can allow generic functions to use new types in efficient and constructive ways.
Line 290: Line 398:
=== A simple example ===
=== A simple example ===
The code below is just given as a simplistic example, since in practice the body of such simple one-liner functions would most likely be used without the overloading syntax.
The code below is just given as a simplistic example, since in practice the body of such simple one-liner functions would most likely be used without the overloading syntax.
<lang julia>
<syntaxhighlight lang="julia">
import Base.-
import Base.-


Line 301: Line 409:
@show [2, 3, 4, 3, 1, 7] - 3 # [2, 3, 4, 3, 1, 7] - 3 = [2, 4, 1, 7]
@show [2, 3, 4, 3, 1, 7] - 3 # [2, 3, 4, 3, 1, 7] - 3 = [2, 4, 1, 7]
@show "world" - 'o' # "world" - 'o' = "wrld"
@show "world" - 'o' # "world" - 'o' = "wrld"
</syntaxhighlight>
</lang>

=={{header|Mathematica}}/{{header|Wolfram Language}}==
Define a custom vector object and define how plus works on these objects:
<syntaxhighlight lang="mathematica">vec[{a_, b_}] + vec[{c_, d_}] ^:= vec[{a + c, b + d}]
vec[{4, 7}] + vec[{9, 3}]</syntaxhighlight>
{{out}}
<pre>vec[{13, 10}]</pre>


=={{header|Nim}}==
=={{header|Nim}}==
Nim allows overloading of operators. There is no restrictions regarding types of arguments when overloading an operator. For instance, we may define a vector type and addition of vectors:
Nim allows overloading of operators. There is no restrictions regarding types of arguments when overloading an operator. For instance, we may define a vector type and addition of vectors:


<lang Nim>type Vector = tuple[x, y, z: float]
<syntaxhighlight lang="nim">type Vector = tuple[x, y, z: float]


func `+`(a, b: Vector): Vector = (a.x + b.x, a.y + b.y, a.z + b.z)
func `+`(a, b: Vector): Vector = (a.x + b.x, a.y + b.y, a.z + b.z)


echo (1.0, 2.0, 3.0) + (4.0, 5.0, 6.0) # print (x: 5.0, y: 7.0, z: 9.0)</lang>
echo (1.0, 2.0, 3.0) + (4.0, 5.0, 6.0) # print (x: 5.0, y: 7.0, z: 9.0)</syntaxhighlight>


The list of predefined operators with their precedence can be found here: https://rosettacode.org/wiki/Operator_precedence#Nim
The list of predefined operators with their precedence can be found here: https://rosettacode.org/wiki/Operator_precedence#Nim
Line 322: Line 437:
For instance, we may define an operator <code>^^</code> the following way:
For instance, we may define an operator <code>^^</code> the following way:


<lang Nim>func `^^`(a, b: int): int = a * a + b * b</lang>
<syntaxhighlight lang="nim">func `^^`(a, b: int): int = a * a + b * b</syntaxhighlight>


To determine the precedence of user-defined operators, Nim defines a set of rules:
To determine the precedence of user-defined operators, Nim defines a set of rules:
Line 343: Line 458:
so that they can be used on members of that class(package). Also see 'Zeckendorf arithmetic' where overloading
so that they can be used on members of that class(package). Also see 'Zeckendorf arithmetic' where overloading
is used on Zeckendorf numbers.
is used on Zeckendorf numbers.
<syntaxhighlight lang="perl">use v5.36;
<lang perl>#!/usr/bin/perl

use strict; # https://rosettacode.org/wiki/Overloaded_operators
use warnings;

my $x = Ones->new( 15 );
my $y = Ones->new( 4 );

my $z = $x + $y;
print "$x + $y = $z\n";
$z = $x - $y;
print "$x - $y = $z\n";
$z = $x * $y;
print "$x * $y = $z\n";
$z = $x / $y;
print "$x / $y = $z\n";


package Ones;
package Ones;
use overload qw("" asstring + add - subtract * multiply / divide);
use overload qw("" asstring + add - subtract * multiply / divide);


sub new ( $class, $value ) { bless \('1' x $value), ref $class || $class }
sub new
sub asstring ($self, $other, $) { $$self }
{
sub asdecimal ($self, $other, $) { length $$self }
my ( $class, $value ) = @_;
bless \('1' x $value), ref $class || $class;
sub add ($self, $other, $) { bless \($$self . $$other), ref $self }
sub subtract ($self, $other, $) { bless \($$self =~ s/$$other//r), ref $self }
}
sub multiply ($self, $other, $) { bless \($$self =~ s/1/$$other/gr), ref $self }

sub divide ($self, $other, $) { $self->new( $$self =~ s/$$other/$$other/g ) }
sub asstring
{
my ($self, $other, $swap) = @_;
$$self;
}

sub asdecimal
{
my ($self, $other, $swap) = @_;
length $$self;
}

sub add
{
my ($self, $other, $swap) = @_;
bless \($$self . $$other), ref $self;
}

sub subtract
{
my ($self, $other, $swap) = @_;
bless \($$self =~ s/$$other//r), ref $self;
}


package main;
sub multiply
{
my ($self, $other, $swap) = @_;
bless \($$self =~ s/1/$$other/gr), ref $self;
}


my($x,$y,$z) = ( Ones->new(15), Ones->new(4) );
sub divide
$z = $x + $y; say "$x + $y = $z";
{
my ($self, $other, $swap) = @_;
$z = $x - $y; say "$x - $y = $z";
$z = $x * $y; say "$x * $y = $z";
$self->new( $$self =~ s/$$other/$$other/g );
$z = $x / $y; say "$x / $y = $z";</syntaxhighlight>
}</lang>
{{out}}
{{out}}
<pre>
<pre>
Line 432: Line 506:
Inline assembly mnemonics have multiple implicit addressing modes as per the standard intel syntax.
Inline assembly mnemonics have multiple implicit addressing modes as per the standard intel syntax.


<!--<lang Phix>(phixonline)-->
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%g\n"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3.5</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- 6.5</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%g\n"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3.5</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- 6.5</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%t\n"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3.5</span> <span style="color: #0000FF;">></span> <span style="color: #000000;">3</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- true</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%t\n"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3.5</span> <span style="color: #0000FF;">></span> <span style="color: #000000;">3</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- true</span>
Line 450: Line 524:
mov eax,1 -- etc
mov eax,1 -- etc
}
}
<!--</lang>-->
<!--</syntaxhighlight>-->


=={{header|Raku}}==
=={{header|Raku}}==
While it is very easy to overload operators in Raku, it isn't really common...
While it is very easy to overload operators in Raku, it isn't really common...
at least, not in the traditional sense. Or it's extremely common... It depends on how you view it.
at least, not in the traditional sense. Or it's extremely common... It depends on how you view it.

First off, do not confuse "symbol reuse" with operator overloading. Multiplication * and exponentiation ** operators both use an asterisk, but one is not an overload of the other. A single asterisk is not the same as two. In fact the term * (whatever) also exists, but differs from both. The parser is smart enough to know when a term or an operator is expected and will select the correct one (or warn if they are not in the correct position).

For example:

<syntaxhighlight lang="raku" line>1, 2, 1, * ** * * * … *</syntaxhighlight>

is a perfectly cromulent sequence definition in Raku. A little odd perhaps, but completely sensible. (It's the sequence starting with givens 1,2,1, with each term after the value of the term 3 terms back, raised to the power of the term two terms back, multiplied by the value one term back, continuing for some undefined number of terms. - Whatever to the whatever times whatever until whatever.)




One of the founding principles of Raku is that: "Different things should look different". It follows that "Similar things should look similar".
One of the founding principles of Raku is that: "Different things should look different". It follows that "Similar things should look similar".
Line 470: Line 554:


Addition:
Addition:
<lang perl6>say 3 + 5; # Int plus Int
<syntaxhighlight lang="raku" line>say 3 + 5; # Int plus Int
say 3.0 + 0.5e1; # Rat plus Num
say 3.0 + 0.5e1; # Rat plus Num
say '3' + 5; # Str plus Int
say '3' + 5; # Str plus Int
Line 476: Line 560:
say '3' + '5'; # Str plus Str
say '3' + '5'; # Str plus Str
say '3.0' + '0.5e1'; # Str plus Str
say '3.0' + '0.5e1'; # Str plus Str
say (2, 3, 4) + [5, 6]; # List plus Array</lang>
say (2, 3, 4) + [5, 6]; # List plus Array</syntaxhighlight>


+ is a numeric operator so every thing is evaluated numerically if possible
+ is a numeric operator so every thing is evaluated numerically if possible
Line 490: Line 574:


Concatenation:
Concatenation:
<lang perl6>say 3 ~ 5; # Int concatenate Int
<syntaxhighlight lang="raku" line>say 3 ~ 5; # Int concatenate Int
say 3.0 ~ 0.5e1; # Rat concatenate Num
say 3.0 ~ 0.5e1; # Rat concatenate Num
say '3' ~ 5; # Str concatenate Int
say '3' ~ 5; # Str concatenate Int
Line 496: Line 580:
say '3' ~ '5'; # Str concatenate Str
say '3' ~ '5'; # Str concatenate Str
say '3.0' ~ '0.5e1'; # Str concatenate Str
say '3.0' ~ '0.5e1'; # Str concatenate Str
say (2, 3, 4) ~ [5, 6]; # List concatenate Array</lang>
say (2, 3, 4) ~ [5, 6]; # List concatenate Array</syntaxhighlight>


~ is a Stringy operator so everything is evaluated as a string (numerics are evaluated numerically then coerced to a string).
~ is a Stringy operator so everything is evaluated as a string (numerics are evaluated numerically then coerced to a string).
Line 507: Line 591:
3.00.5e1
3.00.5e1
2 3 45 6 # default stringification, then concatenate</pre>
2 3 45 6 # default stringification, then concatenate</pre>



There is nothing preventing you from overloading or overriding existing
There is nothing preventing you from overloading or overriding existing
Line 518: Line 603:
prefix, postfix, (or post-circumfix!) The precedence, associativity and arity
prefix, postfix, (or post-circumfix!) The precedence, associativity and arity
are all easily defined. An operator at heart is just a subroutine with funny calling conventions.
are all easily defined. An operator at heart is just a subroutine with funny calling conventions.



Borrowed from the [[Nimber_arithmetic#Raku|Nimber arithmetic]] task:
Borrowed from the [[Nimber_arithmetic#Raku|Nimber arithmetic]] task:
Line 526: Line 612:
itself.
itself.


<lang perl6>sub infix:<⊕> (Int $x, Int $y) is equiv(&infix:<+>) { $x +^ $y }
<syntaxhighlight lang="raku" line>sub infix:<⊕> (Int $x, Int $y) is equiv(&infix:<+>) { $x +^ $y }


sub infix:<⊗> (Int $x, Int $y) is equiv(&infix:<×>) {
sub infix:<⊗> (Int $x, Int $y) is equiv(&infix:<×>) {
Line 538: Line 624:
}
}


say 123 ⊗ 456;</lang>
say 123 ⊗ 456;</syntaxhighlight>
{{out}}
{{out}}
<pre>31562</pre>
<pre>31562</pre>


Base Raku has 27 different operator precedence levels for built-ins. You could theoretically give a new operator an absolute numeric precedence but it would be difficult to predict exactly what the relative precedence would be. Instead, precedence is set by setting a relative precedence; either equivalent to an existing operator, or, by setting it tighter(higher) or looser(lower) precedence than an existing operator. When tighter or looser precedence is specified, a whole new precedence level is created squeezed in between the named level and its immediate successor (predecessor). The task [[Exponentiation_with_infix_operators_in_(or_operating_on)_the_base#Raku|Exponentiation with infix operators in (or operating on) the base]] demonstrates three different operators that nominally do the same thing, but may yield different results due to differing precedence levels.




Line 549: Line 638:


Very, '''very''' basic Line class:
Very, '''very''' basic Line class:
<lang perl6>class Line {
<syntaxhighlight lang="raku" line>class Line {
has @.start;
has @.start;
has @.end;
has @.end;
Line 569: Line 658:


# In operation:
# In operation:
say Line.new(:start(-4,7), :end(5,0)) + Line.new(:start(1,1), :end(2,3));</lang>
say Line.new(:start(-4,7), :end(5,0)) + Line.new(:start(1,1), :end(2,3));</syntaxhighlight>


{{out}}
{{out}}
Line 587: Line 676:


<br>Note that some REXXes may also have other characters (glyphs) for the negation operator &nbsp; (not) &nbsp; such as: &nbsp; &nbsp; <big>^</big> &nbsp; and/or &nbsp; <big>¬</big> &nbsp; glyphs.
<br>Note that some REXXes may also have other characters (glyphs) for the negation operator &nbsp; (not) &nbsp; such as: &nbsp; &nbsp; <big>^</big> &nbsp; and/or &nbsp; <big>¬</big> &nbsp; glyphs.
<lang rexx>/*REXX pgm shows overloading of some operators: prefix/addition/subtraction/concatenate.*/
<syntaxhighlight lang="rexx">/*REXX pgm shows overloading of some operators: prefix/addition/subtraction/concatenate.*/
say '──positive prefix──'
say '──positive prefix──'
say +5 /* positive prefix integer */
say +5 /* positive prefix integer */
Line 713: Line 802:
say '1' && (0) /* binary XOR'ed binary */
say '1' && (0) /* binary XOR'ed binary */


exit 0 /*stick a fork in it, we're all done. */</lang>
exit 0 /*stick a fork in it, we're all done. */</syntaxhighlight>
{{out|output|text=&nbsp; when using the internal default input:}}
{{out|output|text=&nbsp; when using the internal default input:}}
<pre>
<pre>
Line 842: Line 931:


However, whilst it is very useful for classes representing mathematical objects, it should otherwise be used sparingly as code can become unreadable if it is used inappropriately.
However, whilst it is very useful for classes representing mathematical objects, it should otherwise be used sparingly as code can become unreadable if it is used inappropriately.
<lang ecmascript>import "/date" for Date
<syntaxhighlight lang="wren">import "./date" for Date


var s1 = "Rosetta "
var s1 = "Rosetta "
Line 862: Line 951:
var d2 = Date.new(2021, 9, 13)
var d2 = Date.new(2021, 9, 13)
var i1 = (d2 - d1).days
var i1 = (d2 - d1).days
System.print("i1 = %(i1) days")</lang>
System.print("i1 = %(i1) days")</syntaxhighlight>


{{out}}
{{out}}

Latest revision as of 10:32, 9 January 2024

Overloaded operators is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

An overloaded operator can be used on more than one data type, or represents a different action depending on the context. For example, if your language lets you use "+" for adding numbers and concatenating strings, then one would say that the "+" operator is overloaded.

Task

Demonstrate overloaded operators in your language, by showing the different types of data they can or cannot operate on, and the results of each operation.



6502 Assembly

Many commands have multiple addressing modes, which alter the way a command is executed. On the 6502 most of these are in fact different opcodes, using the same mnemonic.

LDA #$80    ;load the value 0x80 (decimal 128) into the accumulator.
LDA $80     ;load the value stored at zero page memory address $80
LDA $2080   ;load the value stored at absolute memory address $2080.
LDA $80,x   ;load the value stored at memory address ($80+x).
LDA ($80,x) ;use the values stored at $80+x and $81+x as a 16-bit memory address to load from.
LDA ($80),y ;use the values stored at $80 and $81 as a 16-bit memory address to load from. Load from that address + y.

68000 Assembly

Most assemblers will interpret instructions such as MOVE, ADD, etc. according to the operand types provided.

MOVE.L D0,A0  ;assembles the same as MOVEA.L D0,A0
EOR.W #%1100000000000000,D5     ;assembles the same as EORI.W #%1100000000000000,D5
CMP.W myAddress,D4              ;assembles the same as CMPM.W myAddress,D4

If you use MOVE.W with an address register as the destination, the CPU will sign-extend the value once it's loaded into the address register. In other words, a word that is $8000 or "more" will get padded to the left with Fs, whereas anything $7FFF or less will be padded with zeroes.

MOVE.W #$9001,A0 ;equivalent of MOVEA.L #$FFFF9001,A0
MOVE.W #$200,A1  ;equivalent of MOVEA.L #$00000200,A1

Ada

Many Ada standard libraries overload operators. The following examples are taken from the Ada Language Reference Manual describing operators for vector and matrix types:

type Real_Vector is array (Integer range <>) of Real'Base;
type Real_Matrix is array (Integer range <>, Integer range <>) of Real'Base;
-- Real_Vector arithmetic operations
   function "+"   (Right : Real_Vector)       return Real_Vector;
   function "-"   (Right : Real_Vector)       return Real_Vector;
   function "abs" (Right : Real_Vector)       return Real_Vector;
   function "+"   (Left, Right : Real_Vector) return Real_Vector;
   function "-"   (Left, Right : Real_Vector) return Real_Vector;
   function "*"   (Left, Right : Real_Vector) return Real'Base;
   function "abs" (Right : Real_Vector)       return Real'Base;
   -- Real_Vector scaling operations
   function "*" (Left : Real'Base;   Right : Real_Vector)
      return Real_Vector;
   function "*" (Left : Real_Vector; Right : Real'Base)
      return Real_Vector;
   function "/" (Left : Real_Vector; Right : Real'Base)
      return Real_Vector;
   -- Real_Matrix arithmetic operations
   function "+"       (Right : Real_Matrix) return Real_Matrix;
   function "-"       (Right : Real_Matrix) return Real_Matrix;
   function "abs"     (Right : Real_Matrix) return Real_Matrix;
   function Transpose (X     : Real_Matrix) return Real_Matrix;
   function "+" (Left, Right : Real_Matrix) return Real_Matrix;
   function "-" (Left, Right : Real_Matrix) return Real_Matrix;
   function "*" (Left, Right : Real_Matrix) return Real_Matrix;
   function "*" (Left, Right : Real_Vector) return Real_Matrix;
   function "*" (Left : Real_Vector; Right : Real_Matrix)
      return Real_Vector;
   function "*" (Left : Real_Matrix; Right : Real_Vector)
      return Real_Vector;
   -- Real_Matrix scaling operations
   function "*" (Left : Real'Base;   Right : Real_Matrix)
      return Real_Matrix;
   function "*" (Left : Real_Matrix; Right : Real'Base)
      return Real_Matrix;
   function "/" (Left : Real_Matrix; Right : Real'Base)
      return Real_Matrix;

The following examples are from the Ada package Ada.Numerics.Generic_Complex_Types

   function "+"       (Right : Complex) return Complex;
   function "-"       (Right : Complex) return Complex;
   function Conjugate (X     : Complex) return Complex;

   function "+" (Left, Right : Complex) return Complex;
   function "-" (Left, Right : Complex) return Complex;
   function "*" (Left, Right : Complex) return Complex;
   function "/" (Left, Right : Complex) return Complex;

   function "**" (Left : Complex; Right : Integer) return Complex;

   function "+"       (Right : Imaginary) return Imaginary;
   function "-"       (Right : Imaginary) return Imaginary;
   function Conjugate (X     : Imaginary) return Imaginary renames "-";
   function "abs"     (Right : Imaginary) return Real'Base;

   function "+" (Left, Right : Imaginary) return Imaginary;
   function "-" (Left, Right : Imaginary) return Imaginary;
   function "*" (Left, Right : Imaginary) return Real'Base;
   function "/" (Left, Right : Imaginary) return Real'Base;

   function "**" (Left : Imaginary; Right : Integer) return Complex;

   function "<"  (Left, Right : Imaginary) return Boolean;
   function "<=" (Left, Right : Imaginary) return Boolean;
   function ">"  (Left, Right : Imaginary) return Boolean;
   function ">=" (Left, Right : Imaginary) return Boolean;

   function "+" (Left : Complex;   Right : Real'Base) return Complex;
   function "+" (Left : Real'Base; Right : Complex)   return Complex;
   function "-" (Left : Complex;   Right : Real'Base) return Complex;
   function "-" (Left : Real'Base; Right : Complex)   return Complex;
   function "*" (Left : Complex;   Right : Real'Base) return Complex;
   function "*" (Left : Real'Base; Right : Complex)   return Complex;
   function "/" (Left : Complex;   Right : Real'Base) return Complex;
   function "/" (Left : Real'Base; Right : Complex)   return Complex;

   function "+" (Left : Complex;   Right : Imaginary) return Complex;
   function "+" (Left : Imaginary; Right : Complex)   return Complex;
   function "-" (Left : Complex;   Right : Imaginary) return Complex;
   function "-" (Left : Imaginary; Right : Complex)   return Complex;
   function "*" (Left : Complex;   Right : Imaginary) return Complex;
   function "*" (Left : Imaginary; Right : Complex)   return Complex;
   function "/" (Left : Complex;   Right : Imaginary) return Complex;
   function "/" (Left : Imaginary; Right : Complex)   return Complex;

   function "+" (Left : Imaginary; Right : Real'Base) return Complex;
   function "+" (Left : Real'Base; Right : Imaginary) return Complex;
   function "-" (Left : Imaginary; Right : Real'Base) return Complex;
   function "-" (Left : Real'Base; Right : Imaginary) return Complex;
   function "*" (Left : Imaginary; Right : Real'Base) return Imaginary;
   function "*" (Left : Real'Base; Right : Imaginary) return Imaginary;
   function "/" (Left : Imaginary; Right : Real'Base) return Imaginary;
   function "/" (Left : Real'Base; Right : Imaginary) return Imaginary;

ALGOL 68

This overrides the standard integer + operator (as in the F# sample) and provides an overloaded TOSTRING operator. Also, the + operator is overloaded to operate on an INT left-hand operand and a BOOL right-hand operand.
Though not shown here, it is also possible to change the priorities of existing dyadic operators. For new dyadic operators, the priority must be specified (though some implementations provide a default). In both cases this is done with a PRIO declaration.

BEGIN
    # Algol 68 allows operator overloading, both of existing operators and new ones  #
    # Programmer defined operators can be a "bold word" (uppercase word) or a symbol #
    # Symbolic operators can be one or two characters, optionally followed by := or  #
    # =:, =: can also be defined as an operator (Allowed in Algol 68G, possibly not  #
    # in other implementations)                                                      #
    # the characters allowed in a symbolic operator depends on the implementation    #
    # but would include +, -, *, /, <, =, >                                          #

    # define a new TOSTRING operator and overload it #
    OP TOSTRING = ( INT  n )STRING: whole( n, 0 ); # returns a string representation of n in the minimum width #
    OP TOSTRING = ( BOOL b )STRING: IF b THEN "true" ELSE "false" FI;
    # overide a standard operator #
    INT a = 10, b = 11, c = 21;
    BEGIN
        OP + = ( INT a, INT b )INT: a - b;
        # + between strings is a standard operator that does string concation #
        print( ( TOSTRING a + " ""+"" " + TOSTRING b + " = " + TOSTRING ( a + b ) + " = " + TOSTRING c + "? " + TOSTRING ( ( a + b ) = c )
               , newline
               )
             )
    END;
    # same print, with the stndard + #
    print( ( TOSTRING a + "  +  " + TOSTRING b + " = " + TOSTRING ( a + b ) + " = " + TOSTRING c + "? " + TOSTRING ( ( a + b ) = c )
           , newline
           )
         );
    # overload + to allow a BOOL to be added to an INT #
    OP + = ( INT a, BOOL b )INT: IF b THEN a + 1 ELSE a FI;
    print( ( TOSTRING a + " ""+"" " + TOSTRING ( a = 10 ) + " = " + TOSTRING ( a + ( a = 10 ) ), newline ) )
END
Output:
10 "+" 11 = -1 = 21? false
10  +  11 = 21 = 21? true
10 "+" true = 11

BQN

What would generally be called operators in other languages are the basic functions in BQN. Nearly all functions have overloads, and the monadic and dyadic cases are generally inter-related.

For example, is Floor in the monadic case:

   4.5
4

But in the dyadic case, it becomes Minimum:

   4  3
3

C++

Operator overloading is one of the classic features of C++, but truth be told, I am writing such code after 20 years.......

And yes, I know subtracting cuboids can give negative volumes. It's theoretically possible (remember volume or triple integrals ? ).

//Aamrun, 4th October 2021

#include <iostream>
using namespace std;

class Cuboid {
   
   private:
      double length;    
      double breadth;    
      double height;    
   
   public:
      double getVolume(void) {
         return length * breadth * height;
      }
      void setLength( double l ) {
         length = l;
      }
      void setBreadth( double b ) {
         breadth = b;
      }
      void setHeight( double h ) {
         height = h;
      }
      

      Cuboid operator +(const Cuboid& c) {
         Cuboid biggerCuboid;
         biggerCuboid.length = this->length + c.length;
         biggerCuboid.breadth = this->breadth + c.breadth;
         biggerCuboid.height = this->height + c.height;
         return biggerCuboid;
      }
      
      Cuboid operator -(const Cuboid& c) {
         Cuboid smallerCuboid;
         smallerCuboid.length = this->length - c.length;
         smallerCuboid.breadth = this->breadth - c.breadth;
         smallerCuboid.height = this->height - c.height;
         return smallerCuboid;
      }
};

int main() {
   Cuboid c1;               
   Cuboid c2;               
   Cuboid c3;               
   double volume = 0.0;    

   c1.setLength(6.0); 
   c1.setBreadth(7.0); 
   c1.setHeight(5.0);
 
   c2.setLength(12.0); 
   c2.setBreadth(13.0); 
   c2.setHeight(10.0);
 
   volume = c1.getVolume();
   std::cout << "Volume of 1st cuboid : " << volume <<endl;
 
   volume = c2.getVolume();
   std::cout << "Volume of 2nd cuboid : " << volume <<endl;

   //Adding the two cuboids
   c3 = c1 + c2;

   volume = c3.getVolume();
   std::cout << "Volume of 3rd cuboid after adding : " << volume <<endl;
   
   //Subtracting the two cuboids
   c3 = c1 - c2;

   volume = c3.getVolume();
   std::cout << "Volume of 3rd cuboid after subtracting : " << volume <<endl;

   return 0;
}
Output:
Volume of 1st cuboid : 210
Volume of 2nd cuboid : 1560
Volume of 3rd cuboid after adding : 5400
Volume of 3rd cuboid after subtracting : -180

F#

For those who complain that they can't follow my F# examples perhaps if I do the following it will help them.

// Overloaded operators. Nigel Galloway: September 16th., 2021
let (+) (n:int) (g:int) = n-g
printfn "%d" (23+7)
Output:
16

FreeBASIC

Operators can be overloaded by default, so the Overload keyword is not needed when declaring custom operators. At least one of the operator's parameters must be of a user-defined type (after all, operators with built-in type parameters are already defined).

The following example overloads the member operators Cast(Cast) and *=(Multiply And Assign) for objects of a user-defined type.

Type Rational
    As Integer numerator, denominator
    
    Declare Operator Cast () As Double
    Declare Operator Cast () As String
    Declare Operator *= (Byref rhs As Rational)
End Type

Operator Rational.cast () As Double
    Return numerator / denominator
End Operator

Operator Rational.cast () As String
    Return numerator & "/" & denominator
End Operator

Operator Rational.*= (Byref rhs As Rational)
      numerator *= rhs.numerator
    denominator *= rhs.denominator
End Operator

Dim As Rational r1 = (2, 3), r2 = (3, 4)
r1 *= r2
Dim As Double d = r1
Print r1, d


jq

Works with: jq

Works with gojq, the Go implementation of jq

Many of jq's built-in operators are "overloaded" in the sense that they can be used on more than one built-in jq data type, these being: "null", "boolean", "string", "object" and "array".

The prime example of an overloaded operator in jq is `+`, which is defined on:

null x ANY # additive zero
ANY x null # additive zero
number x number # addition
array x array  # concatenation
object x object # coalesence

Note that `+` is symmetric except for its restriction to object x object, as illustrated by:

{"a":1} + {"a": 2} #=> {"a": 2}

{"a":2} + {"a": 1} #=> {"a": 1}

Most of the other operators that are usually thought of as "arithmetic" are also overloaded, notably:

-: array x array  # e.g. [1,2,1] - [1] #=> [2]
*: string x number # e.g. "a" * 3   #=> "aaa"
/: string x string # e.g. "a/b/c" / "/"' #=> ["a","b","c"]

The comparison operators (<, <=, ==, >=, >) are defined for all JSON entities and thus can be thought of as being overloaded, but this is only because jq defines a total order on JSON entities.

The comparison operators can also be used on non-JSON entities as well, e.g.

0 < infinite #=> true
nan < 0 #=> true

The logical operators (`and`, `or`, `not`) are also defined for all JSON entities, their logic being based on the idea that the only "falsey" values are `false` and `null`.

Whether a function (meaning a given name/arity pair) is "overloaded" or not depends entirely on its definition, it being understood that jq functions with the same name but different arities can have entirely unrelated definitions.

`length/0` is defined on all JSON entities except `true` and `false`. Note that it is defined as the absolute value on JSON numbers, and that:

nan|length #=> null

It is also worth pointing out that a single name/arity function can have multiple definitions within a single program, but normal scoping rules apply so that in any one context, only one definition is directly accessible. The functionality of the "outer" definition, however, can be accessed indirectly, as illustrated by the following contrived example:

def foo:
  def outer_length: length;
  def length: outer_length | tostring;
  [outer_length, length];

"x" | foo #=> [1, "1"]

Julia

Most operators in Julia's base syntax are in fact just syntactic sugar for function calls. In particular, the symbols:

* / ÷ % &   ×                              ⦿             
                       

are parsed in the same precedence as the multiplication operator function *, and the symbols:

+ -        ±                                           

are parsed as infix operators with the same precedence as +. There are many other operator symbols that can be used as prefix or as infix operators once defined as a function in Julia.

As a language, much of Julia is organized around the concept of multiple dispatch. Because the language dispatches function calls according to the types of the function arguments, even the base arithmetic operators are in fact overloaded operators in Julia.

For example,

2 * 3

is sent to the function *(x::Int, y::Int)::Int, whereas

2.0 * 3.0

is dispatched to the overloaded function *(x::Float64, y::Float64)::Float64. Similarly, string concatenation in Julia is with * rather than +, so "hello " * "world" is dispatched to the overloaded function *(x::String, y::String)::String, and other types such as matrices also have arithmetic operators overloaded in base Julia:

julia> x = [1 2; 3 4]; y = [50 60; 70 80]; x + y
2×2 Matrix{Int64}:
 51  62
 73  84

Users may define their own overloaded functions in similar ways, whether or not such operators are already used in base Julia. In general, it is considered bad practice, and as "type piracy", to define a user overloaded operator which dispatches on the same types for which base Julia has already defined the same function. Instead, user defined types can be best made to have analogous operators defined for the new type so as to leverage existing code made for analogous base types. This can allow generic functions to use new types in efficient and constructive ways.

A simple example

The code below is just given as a simplistic example, since in practice the body of such simple one-liner functions would most likely be used without the overloading syntax.

import Base.-

""" overload - operator on vectors to return new vector from which all == subelem element are removed """
-(vec, subelem) where T =  [elem for elem in vec if elem != subelem]

""" overload - operator on strings to return new string from which all == char c are removed """
-(s::String, c::Char) = String([ch for ch in s if ch != c])

@show [2, 3, 4, 3, 1, 7] - 3    # [2, 3, 4, 3, 1, 7] - 3 = [2, 4, 1, 7]
@show "world" - 'o'             # "world" - 'o' = "wrld"

Mathematica/Wolfram Language

Define a custom vector object and define how plus works on these objects:

vec[{a_, b_}] + vec[{c_, d_}] ^:= vec[{a + c, b + d}]
vec[{4, 7}] + vec[{9, 3}]
Output:
vec[{13, 10}]

Nim

Nim allows overloading of operators. There is no restrictions regarding types of arguments when overloading an operator. For instance, we may define a vector type and addition of vectors:

type Vector = tuple[x, y, z: float]

func `+`(a, b: Vector): Vector = (a.x + b.x, a.y + b.y, a.z + b.z)

echo (1.0, 2.0, 3.0) + (4.0, 5.0, 6.0)  # print (x: 5.0, y: 7.0, z: 9.0)

The list of predefined operators with their precedence can be found here: https://rosettacode.org/wiki/Operator_precedence#Nim

Nim allows also user defined operators which must be composed using the following characters:

= + - * / < > @ $ ~ &  % | !  ? ^ .  : \

For instance, we may define an operator ^^ the following way:

func `^^`(a, b: int): int = a * a + b * b

To determine the precedence of user-defined operators, Nim defines a set of rules:

Unary operators always bind stronger than any binary operator: $a + b is ($a) + b and not $(a + b).

If an unary operator's first character is @ it is a sigil-like operator which binds stronger than a primarySuffix: @x.abc is parsed as (@x).abc whereas $x.abc is parsed as $(x.abc).

For binary operators that are not keywords, the precedence is determined by the following rules:

Operators ending in either ->, ~> or => are called arrow like, and have the lowest precedence of all operators.

If the operator ends with = and its first character is none of <, >, !, =, ~, ?, it is an assignment operator which has the second-lowest precedence.

Otherwise, precedence is determined by the first character.

Perl

See 'perldoc overload' for perl's overload capabilities. This example defines a class(package) that represent non-negative numbers as a string of 1's and overloads the basic math operators so that they can be used on members of that class(package). Also see 'Zeckendorf arithmetic' where overloading is used on Zeckendorf numbers.

use v5.36;

package Ones;
use overload qw("" asstring + add - subtract * multiply / divide);

sub new       ( $class, $value ) { bless \('1' x $value), ref $class || $class  }
sub asstring  ($self, $other, $) { $$self                                       }
sub asdecimal ($self, $other, $) { length $$self                                }
sub add       ($self, $other, $) { bless \($$self . $$other),         ref $self }
sub subtract  ($self, $other, $) { bless \($$self =~ s/$$other//r),   ref $self }
sub multiply  ($self, $other, $) { bless \($$self =~ s/1/$$other/gr), ref $self }
sub divide    ($self, $other, $) { $self->new( $$self =~ s/$$other/$$other/g )  }

package main;

my($x,$y,$z) = ( Ones->new(15), Ones->new(4) );
$z = $x + $y; say "$x + $y = $z";
$z = $x - $y; say "$x - $y = $z";
$z = $x * $y; say "$x * $y = $z";
$z = $x / $y; say "$x / $y = $z";
Output:
111111111111111 + 1111 = 1111111111111111111
111111111111111 - 1111 = 11111111111
111111111111111 * 1111 = 111111111111111111111111111111111111111111111111111111111111
111111111111111 / 1111 = 111

Phix

Phix does not allow operator overloading and it is not possible to define new operators.
(Fairly weak arguments for, pretty strong against, any few minutes saved typing something in the first time are almost always lost the first time it needs to be maintained, if you want my opinion)

The standard arithmetic operators accept (mixed) integer and floating point values without casting.

The relational operators accept integer, float, string, and sequence values.

The logical operators only accept atoms, however there are 40-something sq_xxx() builtins that can be used
to perform all the builtin operations on any mix of integer, float, string, or sequence values.

Subscripts and concatenation work equivalently on strings and sequences, and in fact concatenation on integers and floats.

Any parameter can be integer, float, string, or sequence if it is declared as an object.

For example printf() can accept [a file number, format string and] a single atom or a sequence of objects,
it being wise to wrap lone strings in {} to ensure you get the whole thing not just the first letter.

Inline assembly mnemonics have multiple implicit addressing modes as per the standard intel syntax.

printf(1,"%g\n",3.5 + 3)                -- 6.5
printf(1,"%t\n",3.5 > 3)                -- true
printf(1,"%t\n","a" = "a")              -- true
printf(1,"%t\n",{1} = {2})              -- false
printf(1,"%V\n",{{1} & {2}})            -- {1,2}
printf(1,"%V\n",{1 & 2.3})              -- {1,2.3}
printf(1,"%V\n",{"a" & "b"})            -- "ab"
printf(1,"%V\n",{"AB"[2] & {1,2}[1]})   -- {66,1}

integer i
#ilASM{ lea eax,[i]
        mov [eax],ebx
        mov [i],ebx
        mov [i],0
        mov eax,ebx
        mov eax,1   -- etc
      } 

Raku

While it is very easy to overload operators in Raku, it isn't really common... at least, not in the traditional sense. Or it's extremely common... It depends on how you view it.

First off, do not confuse "symbol reuse" with operator overloading. Multiplication * and exponentiation ** operators both use an asterisk, but one is not an overload of the other. A single asterisk is not the same as two. In fact the term * (whatever) also exists, but differs from both. The parser is smart enough to know when a term or an operator is expected and will select the correct one (or warn if they are not in the correct position).

For example:

1, 2, 1, * ** * * * … *

is a perfectly cromulent sequence definition in Raku. A little odd perhaps, but completely sensible. (It's the sequence starting with givens 1,2,1, with each term after the value of the term 3 terms back, raised to the power of the term two terms back, multiplied by the value one term back, continuing for some undefined number of terms. - Whatever to the whatever times whatever until whatever.)


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:

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

+ is a numeric operator so every thing is evaluated numerically if possible

Output:
8
8
8
8
8
8
5 # a list or array evaluated numerically returns the number of elements


Concatenation:

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

~ is a Stringy operator so everything is evaluated as a string (numerics are evaluated numerically then coerced to a string).

Output:
35
35
35
35
35
3.00.5e1
2 3 45 6 # default stringification, then concatenate


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. An operator at heart is just a subroutine with funny calling conventions.


Borrowed from the Nimber arithmetic task:

New operators, defined in place. Arity is two (almost all infix operators take two arguments), precedence is set equivalent to similar existing operators, default (right) associativity. The second, ⊗, actually uses itself to define itself.

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 123456;
Output:
31562


Base Raku has 27 different operator precedence levels for built-ins. You could theoretically give a new operator an absolute numeric precedence but it would be difficult to predict exactly what the relative precedence would be. Instead, precedence is set by setting a relative precedence; either equivalent to an existing operator, or, by setting it tighter(higher) or looser(lower) precedence than an existing operator. When tighter or looser precedence is specified, a whole new precedence level is created squeezed in between the named level and its immediate successor (predecessor). The task Exponentiation with infix operators in (or operating on) the base demonstrates three different operators that nominally do the same thing, but may yield different results due to differing precedence levels.


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:

class Line {
    has @.start;
    has @.end;
}

# New infix + multi to add two Lines together, for some bogus definition of add
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));
Output:
Line.new(start => [4.123105625617661e0, 7.0710678118654755e0], end => [5.385164807134504e0, 3e0])

To be fair, all of this easy power in a bad programmers hands can lead to incomprehensible code... but bad programmers can be bad in any language.

REXX

A lot of the examples were taken from the Raku examples.

The REXX language has the "normal"   (as say, compared with PL/I)   overloading of:

  •   the prefix operators   (+ and -)   which are shared with the addition and subtraction operators,
  •   the multiplication operator   (*)   is "shared" with the exponentiation operator   (**),
  •   the "or" operator   (|)   is "shared" with the concatenation operator   (||),
  •   the "and" operator   (&)   is "shared" with the "XOR" (eXclusive OR) operator   (&&),   and
  •   the "negation" operator   (\)   is "shared" with the "not" logical comparison operator,   as in:       if  a\=b  then  ...


Note that some REXXes may also have other characters (glyphs) for the negation operator   (not)   such as:     ^   and/or   ¬   glyphs.

/*REXX pgm shows overloading of some operators: prefix/addition/subtraction/concatenate.*/
say '──positive prefix──'
say  +5                                          /* positive  prefix integer            */
say  + 5                                         /* positive  prefix integer            */
say  ++6                                         /* positive  prefix integer            */
say  ++ 6                                        /* positive  prefix integer            */
say  +++7                                        /* positive  prefix integer            */
say  +++ 7                                       /* positive  prefix integer            */
say  + + + + 8                                   /* positive  prefix integer            */
say  + (9)                                       /* positive  prefix integer            */

say '──negative prefix──'
say  -1                                          /* negative  prefix integer            */
say  - 1                                         /* negative  prefix integer            */
say  --2                                         /* negative  prefix integer            */
say  -- 2                                        /* negative  prefix integer            */
say  ---3                                        /* negative  prefix integer            */
say  --- 3                                       /* negative  prefix integer            */
say  - - - - 4                                   /* negative  prefix integer            */
say  - (9)                                       /* negative  prefix integer            */

say '───addition───'
say  3     +   5                                 /* integer   plus  integer             */
say  3     +   (5)                               /* integer   plus  integer             */
say  3.0   +   0.5e1                             /* rational  plus  number              */
say '3'    +   5                                 /* string    plus  integer             */
say  3     +  ' 5 '                              /* integer   plus  string              */
say  3     +  '5'                                /* integer   plus  string              */
say '3'    +  '5'                                /* string    plus  string              */
say '3'    +  "5"                                /* string    plus  string              */
say '3.0'  +  '0.5e1'                            /* string    plus  string              */

say '──subtraction──'
say  3     -   5                                 /* integer   minus  integer            */
say  3     -   (5)                               /* integer   minus  integer            */
say  3.0   -   0.5e1                             /* rational  minus  number             */
say '3'    -   5                                 /* string    minus  integer            */
say  3     -  '5'                                /* integer   minus  string             */
say  3     -  ' 5 '                              /* integer   minus  string             */
say '3'    -  '5'                                /* string    minus  string             */
say '3'    -  "5"                                /* string    minus  string             */
say '3.0'  -  '0.5e1'                            /* string    minus  string             */

say '──concatenation──'
say  3     ||   5                                /* integer   concatenated  integer     */
say  3     ||   (5)                              /* integer   concatenated  integer     */
say  3.0   ||   0.5e1                            /* rational  concatenated  number      */
say '3'    ||   5                                /* string    concatenated  integer     */
say  3     ||  '5'                               /* integer   concatenated  string      */
say '3'    ||  '5'                               /* string    concatenated  string      */
say "3"    ||  "5"                               /* string    concatenated  string      */
say '3.0'  | | '0.5e1'                           /* string    concatenated  string      */
say  3     ||  ' 5 '.                            /* integer   concatenated  strings     */

say '────abutment────'
say  3          5                                /* integer   abutted  integer          */
say  3          (5)                              /* integer   abutted  integer          */
say  3.0        0.5e1                            /* rational  abutted  number           */
say '3'         5                                /* string    abutted  integer          */
say  3         '5'                               /* integer   abutted  string           */
say '3'        '5'                               /* string    abutted  string           */
say "3"        "5"                               /* string    abutted  string           */
say  3         ' 5 '.                            /* integer   abutted  strings          */

say '──multiplication──'
say  3     *    5                                /* integer   multiplied  integer       */
say  3     *    (5)                              /* integer   multiplied  integer       */
say  3.0   *    0.5e1                            /* rational  multiplied  number        */
say '3'    *    5                                /* string    multiplied  integer       */
say  3     *   '5'                               /* integer   multiplied  string        */
say '3'    *   '5'                               /* string    multiplied  string        */
say "3"    *   "5"                               /* string    multiplied  string        */
say '3.0'  *   '0.5e1'                           /* string    multiplied  string        */

say '──exponentation──'
say  3     **   5                                /* integer  exponetiated integer       */
say  3     **   (5)                              /* integer  exponetiated integer       */
say  3     * *  5                                /* integer  exponetiated integer       */
say  3.0   **   0.5e1                            /* rational exponetiated number        */
say '3'    **   5                                /* string   exponetiated integer       */
say  3     **  '5'                               /* integer  exponetiated string        */
say '3'    **  '5'                               /* string   exponetiated string        */
say "3"    **  "5"                               /* string   exponetiated string        */
say '3.0'  **  '0.5e1'                           /* string   exponetiated string        */

say '────division────'
say  3     /    5                                /* integer  divided  integer           */
say  3     /    (5)                              /* integer  divided  integer           */
say  3.0   /    0.5e1                            /* rational divided  number            */
say '3'    /    5                                /* string   divided  integer           */
say  3     /   '5'                               /* integer  divided  string            */
say '3'    /   '5'                               /* string   divided  string            */
say "3"    /   "5"                               /* string   divided  string            */
say '3.0'  /   '0.5e1'                           /* string   divided  string            */

say '─────not────'
say  \0                                          /* (not)        invert  binary         */
say  \1                                          /* (not)        invert  binary         */
say  \ 1                                         /* (not)        invert  binary         */
say  \ (0)                                       /* (not)        invert  binary         */
say  \ 1                                         /* (not)        invert  binary         */
say  \ (0)                                       /* (not)        invert  binary         */
say  \\ 0                                        /* (not) (not)  invert  binary         */
say  \ \ 1                                       /* (not) (not)  invert  binary         */

say '─────or─────'
say  0     |    0                                /* binary   OR'ed  binary              */
say  0     |    1                                /* binary   OR'ed  binary              */
say '0'    |   "1"                               /* binary   OR'ed  binary              */
say '1'    |    0                                /* binary   OR'ed  binary              */
say '1'    |   (0)                               /* binary   OR'ed  binary              */

say '─────and────'
say  0     &    0                                /* binary   AND'ed  binary             */
say  0     &    1                                /* binary   AND'ed  binary             */
say '0'    &   "1"                               /* binary   AND'ed  binary             */
say '1'    &    0                                /* binary   AND'ed  binary             */
say '1'    &   (0)                               /* binary   AND'ed  binary             */

say '─────XOR────'
say  0     &&    0                               /* binary   XOR'ed  binary             */
say  0     &&    1                               /* binary   XOR'ed  binary             */
say '0'    &&   "1"                              /* binary   XOR'ed  binary             */
say '1'    &&    0                               /* binary   XOR'ed  binary             */
say '1'    &&   (0)                              /* binary   XOR'ed  binary             */

exit 0                                           /*stick a fork in it,  we're all done. */
output   when using the internal default input:
──positive prefix──
5
5
6
6
7
7
8
9
──negative prefix──
-1
-1
2
2
-3
-3
4
-9
───addition───
8
8
8.0
8
8
8
8
8
8.0
──subtraction──
-2
-2
-2.0
-2
-2
-2
-2
-2
-2.0
──concatenation──
35
35
3.00.5E1
35
35
35
35
3.00.5e1
3 5 .
────abutment────
3 5
3 5
3.0 0.5E1
3 5
3 5
3 5
3 5
3  5 .
──multiplication──
15
15
15.0
15
15
15
15
15.0
──exponentation──
243
243
243
243
243
243
243
243
243
────division────
0.6
0.6
0.6
0.6
0.6
0.6
0.6
0.6
─────not────
1
0
0
1
0
1
0
1
─────or─────
0
1
1
1
1
─────and────
0
0
0
0
0
─────XOR────
0
1
1
1
1

Wren

Library: Wren-date


All of Wren's operators can be overloaded except: &&, ||, ?: and =. It is not possible to create new operators from scratch.

When an operator is overloaded it retains the same arity, precedence and associativity as it has when used in its 'natural' sense.

The standard library contains several instances of overloading the + and * operators which are demonstrated below.

Otherwise, operator overloading can be used without restriction in user defined classes.

However, whilst it is very useful for classes representing mathematical objects, it should otherwise be used sparingly as code can become unreadable if it is used inappropriately.

import "./date" for Date

var s1 = "Rosetta "
var s2 = "code"
var s3 = s1 + s2          // + operator used to concatenate two strings
System.print("s3 = %(s3)")

var s4 = "a" * 20         // * operator used to provide string repetition
System.print("s4 = %(s4)")

var l1 = [1, 2, 3] + [4]  // + operator used to concatenate two lists
System.print("l1 = %(l1)")

var l2 = ["a"] * 8        // * operator used to create a new list by repeating another
System.print("l2 = %(l2)")

// the user defined class Date overloads the - operator to provide the interval between two dates
var d1 = Date.new(2021, 9, 11)
var d2 = Date.new(2021, 9, 13)
var i1 = (d2 - d1).days
System.print("i1 = %(i1) days")
Output:
s3 = Rosetta code
s4 = aaaaaaaaaaaaaaaaaaaa
l1 = [1, 2, 3, 4]
l2 = [a, a, a, a, a, a, a, a]
i1 = 2 days