<p>I noticed C++ has operator overloading syntax with just the operator names:</p>
<pre><code>T&amp; operator +(T&amp; lhs, T&amp; rhs) {
    return /* ... */;
}
</code></pre>
<p>However, there are 2 distinct operators that are both <code>++</code> and <code>--</code>. One being a suffix and one being a prefix. C++ syntax has no way to distinguish them with the syntax, so instead one of them uses an unused <code>int</code> parameter. But this seems ungraceful.</p>
<p>What would be a good alternative syntax for operator overloading that could unambiguously distinguish unary <code>+</code> with binary <code>+</code> and also distinguish <code>++x</code> from <code>x++</code> without hacks such as unused parameters?</p>

<syntax><operators><operator-overloading>
What alternatives are there for C++ operator overloading syntax?
CC BY-SA 4.0
2023-06-29T12:54:14.473Z
The _advantage_ of the C++ style syntax is not having to remember made-up names for all the operators (like `__add__` in Python for example), although unfortunately you do end up with some cases like mentioned in this question.
CoffeeTableEspresso
CC BY-SA 4.0
2023-08-18T10:25:34.363Z
The evil answer would be `T &operator(T &t)++;`
Simon Richter
<h1>Rust-style traits</h1>
<p>In Rust, operator overloading is implemented using core traits built into the language, which allow the operators to be named, without conflicting with methods which have the same name (e.g., you may want <code>x.add()</code> to be different from the <code>+</code> overload, maybe if <code>x</code> is a set).</p>
<p>This would look something like:</p>
<pre><code>impl core::ops::Add for T {
    fn add(...) -&gt; T { ... }
}
</code></pre>
<p>The advantage of this is that, unless the <code>core::ops::Add</code> trait is <code>use</code>d in a file, this <code>add</code> method will not be accessable. This allows other <code>add</code> functions to be implemented on <code>T</code> without conflict.</p>
<p><a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2021&amp;gist=4902aa8acad0ad9673a2aba3e17f062e" rel="noreferrer">Demo</a></p>

CC BY-SA 4.0
2023-05-16T20:25:08.177Z
2023-05-16T20:25:08.177Z
rydwolf
<h1>Using names instead</h1>
<p>To rectify this problem, you can use names instead of symbols for the names of operator functions. For example, take a look at Kotlin:</p>
<pre class="lang-kotlin prettyprint-override"><code>operator fun inc(): X {
    // ++a/a++
}
operator fun plus(other: Y): Z {
    // a + b
}
</code></pre>

CC BY-SA 4.0
2023-05-16T17:26:23.007Z
2023-08-21T14:52:38.697Z
2023-08-21T14:52:38.697Z
Seggan
CC BY-SA 4.0
2023-05-17T00:01:45.303Z
Python also takes this approach. For example, `+` is implemented by `__add__` and `__radd__` (a cooperative protocol is used to check the LHS and RHS types for an implementation, and `+=` can be specialized using `__iadd__` (although it does not perform the actual assignment).
Karl Knechtel
CC BY-SA 4.0
2023-08-25T00:33:07.337Z
And while Python doesn't have pre- or post-increment operators, if it did I would expect them to have distinct dunder methods, e.g. `__preinc__` and `__postinc__`.
Barmar
<p>Prefix the operator with its syntactic type. Raku allows the user to define custom operators with virtually any string of symbols (or letters, in fact) as names. The ambiguity is resolved by an explicit declaration at function site of which form of syntax the operator takes.</p>
<pre><code># Prefix ++
sub prefix:&lt;++&gt;($arg) {
  ...
}

# Postfix ++
sub postfix:&lt;++&gt;($arg) {
  ...
}
</code></pre>

CC BY-SA 4.0
2023-05-16T17:41:16.187Z
2023-05-16T17:41:16.187Z
Silvio Mayolo
<h1>The Operator Is An Argument</h1>
<p>In D, a few special method names are reserved for operator overloading, including <code>opUnary</code> and <code>opBinary</code>, and they are used as templates to which the operator is passed as argument.<br />
<a href="https://dlang.org/spec/operatoroverloading.html" rel="noreferrer">https://dlang.org/spec/operatoroverloading.html</a></p>
<p>This means that, for example, <code>+x</code> is interpreted as <code>x.opUnary!&quot;+&quot;</code>, and <code>x + y</code> as <code>x.opBinary!&quot;+&quot;(y)</code>.<br />
This has the major advantage that multiple syntactically related operators can be implemented by a single function template.</p>
<pre><code>struct S
{
    int x;
    S opBinary(string Op)(in S o) const
    {
        mixin(&quot;return S(x&quot;, Op, &quot; o.x);&quot;);
    }
    
    unittest
    {
        const x = S(21);
        const y = S(2);
        const z = x * y;
        assert(z.x == 42);
    }
}
</code></pre>
<p>Another example is that of the cast operator, implemented as <code>opCast</code> where the <em>type</em> is passed as argument.<br />
Combined with CTFE and user-defined overload resolution, it acts similarly to the previous example.</p>
<pre><code>struct S
{
    int x;

    T opCast(T)() const
      if(is(int : T))
    {
        return x;
    }
    T opCast(T: string)() const
    {
        return imported!&quot;std.conv&quot;.to!string(x);
    }

    unittest
    {
        const s = S(42);
        const x = cast(long) s;
        const str = cast(string) s;
        assert(x == 42);
        assert(str == &quot;42&quot;);
    }
}
</code></pre>
<h1><code>x++</code> calls <code>++x</code></h1>
<blockquote>
<p>What would be a good alternative syntax for operator overloading that could [...] distinguish ++x from x++ without hacks such as unused parameters?</p>
</blockquote>
<p><code>x++</code> really means (in GNU C's syntax) <code>({ __auto_type _tmp = x; ++x; _tmp; })</code>.<br />
This is also how both prefix and postfix (inc|dec)rementation operator in D resolve to <code>opUnary</code>.<br />
Naturally, any copy and related semantics can be optimised away via copy elision.</p>

CC BY-SA 4.0
2023-05-30T00:41:09.127Z
2023-06-03T18:22:30.863Z
2023-06-03T18:22:30.863Z
Longinus
<p><a href="/questions/tagged/ruby" class="post-tag" title="show questions tagged &#39;ruby&#39;" aria-label="show questions tagged &#39;ruby&#39;" rel="tag" aria-labelledby="tag-ruby-tooltip-container">ruby</a></p>
<p>In <a href="https://ruby-lang.org/" rel="noreferrer">Ruby</a>, binary infix operators are just <a href="https://wikipedia.org/wiki/Syntactic_sugar" rel="noreferrer">syntactic sugar</a> for <a href="https://wiki.c2.com/?MessagePassing" rel="noreferrer">message sends</a>, i.e. for all binary infix operators <code>ω</code>,</p>
<pre class="lang-ruby prettyprint-override"><code>a ω b
</code></pre>
<p>is syntactic sugar for</p>
<pre class="lang-ruby prettyprint-override"><code>a.ω(b)
</code></pre>
<p>Consequently, since operator expressions are just message sends, they invoke methods just like any other message send and just like any other message send, the name of the method being invoked is the same as the message.</p>
<p>So, <a href="https://docs.ruby-lang.org/en/master/syntax/methods_rdoc.html#label-Method+Names" rel="noreferrer">defining an operator is just defining a method with the same name as the operator</a>. Defining a method named <code>plus</code> looks like this:</p>
<pre class="lang-ruby prettyprint-override"><code>module SomeModule
  def plus(other)
    # do something with `self` and `other`
  end
end
</code></pre>
<p>And thus, defining a method named <code>+</code> looks exactly identical:</p>
<pre class="lang-ruby prettyprint-override"><code>module SomeModule
  def +(other)
    # do something with `self` and `other`
  end
end
</code></pre>
<p>There are, however, some special cases.</p>
<p>Firstly, not all operators can be defined. <code>.</code> (message sending), <code>=</code> (assignment), <code>&amp;&amp;</code> (logical-AND), <code>||</code> (logical-OR), <code>and</code>, <code>or</code>, unary prefix <code>&amp;</code> (unroll an object responding to <code>to_proc</code> into a block), and unary prefix <code>defined?</code> don't translate into message sends and thus cannot be defined. Unary prefix <code>not</code> cannot be defined on its own, but it translates into a message send of <code>!</code>, which means it is always identical to unary prefix <code>!</code> which <em>can</em> be defined.</p>
<p>Second, this scheme obviously only works for binary infix operators. Ruby does not have unary postfix operators, but it does have some unary prefix operators. The ones which can be defined are: <code>+</code>, <code>-</code>, <code>!</code>, and <code>~</code>.</p>
<p>Since there is no binary infix operator named <code>!</code> or <code>~</code>, these are just syntactic sugar for argument-less message sends with the same name as the operator and thus are defined with the same name, similar to binary infix operators:</p>
<pre class="lang-ruby prettyprint-override"><code>not a # is same as
!a    # is same as
a.!
# is defined using
module SomeModule
  def !
    # do something with `self`
  end
end

~a # is same as
a.~
# is defined using
module SomeModule
  def ~
    # do something with `self`
  end
end
</code></pre>
<p>In Ruby, there can be only one method with a particular name in a particular module, so it is not possible to define unary prefix <code>+</code> and <code>-</code> as a parameterless method named <code>+</code> or <code>-</code> since that would clash with the binary infix versions. So, for these two operators, the rule is slightly modified in that they are translated to <code>+@</code> and <code>-@</code>, respectively:</p>
<pre class="lang-ruby prettyprint-override"><code>+a # is same as
a.+@
# is defined using
module SomeModule
  def +@
    # do something with `self`
  end
end

-a # is same as
a.-@
# is defined using
module SomeModule
  def -@
    # do something with `self`
  end
end
</code></pre>
<p>So, long answer short: the way to disambiguate operators with the same name but different arity is to give them different names when defining them.</p>

CC BY-SA 4.0
2023-06-29T03:16:51.267Z
2023-06-29T03:29:16.563Z
2023-06-29T03:29:16.563Z
Jörg W Mittag
<p>In Python the methods become special only because of its name.</p>
<p>For example for <code>+</code>:</p>
<pre class="lang-python prettyprint-override"><code>def __add__(...):
    ...
</code></pre>
<p>Python like methods names:</p>
<ul>
<li><code>+</code> -- <code>__add__</code></li>
<li><code>-</code> -- <code>__sub__</code></li>
<li><code>*</code> -- <code>__mul__</code></li>
<li><code>/</code> -- <code>__div__</code></li>
<li>...</li>
</ul>

CC BY-SA 4.0
2023-06-01T09:32:39.660Z
2023-06-01T09:32:39.660Z
чистов_n
<h1>UpValues in Mathematica</h1>
<p>Mathematica (the Wolfram Language) is based on pattern matching and term rewriting. Functions are defined as rules. For example, when you define a function like this:</p>
<pre><code>f[x_] := x^2
</code></pre>
<p>It defines a rule that says &quot;when you see <code>f[x_]</code>, replace it with <code>x^2</code>&quot;. This rule is associated with the symbol <code>f</code>, and is called a &quot;downvalue&quot; of <code>f</code>.</p>
<p>Mathematica also has &quot;upvalues&quot;, where the rule is associated with a symbol in the function's arguments instead of the function's name. For example, if you define:</p>
<pre><code>f[x] ^:= x^2
</code></pre>
<p>Then the rule is associated with the symbol <code>x</code>, and is called an &quot;upvalue&quot; of <code>x</code>.</p>
<p>Operators in Mathematica are just syntactic sugar for built-in functions. For example, <code>a + b</code> is equivalent to <code>Plus[a, b]</code>. Downvalues for built-in functions are protected, so you can't redefine <code>Plus</code> directly. However, you can define upvalues for your own symbols.</p>
<p>For example, if you want to define your own complex number type, you can define a symbol <code>Comp</code>, and then define addition and multiplication for it:</p>
<pre><code>Comp[a_, b_] + Comp[c_, d_] ^:= Comp[a + c, b + d]
Comp[a_, b_] * Comp[c_, d_] ^:= Comp[a c - b d, a d + b c]
</code></pre>
<p>These rules are associated with the symbol <code>Comp</code> instead of <code>Plus</code> and <code>Times</code>, so they don't conflict with the built-in rules for <code>Plus</code> and <code>Times</code>.</p>

CC BY-SA 4.0
2023-05-17T02:43:11.847Z
2023-05-28T12:17:33.207Z
2023-05-28T12:17:33.207Z
alephalpha
<p>The arguments could be placed next to the operator in relation to their usage, as opposed to in a list afterwards:</p>
<pre><code>(T) ++(T) {
    // Prefix
}

(T) (T)++ {
    // Suffix 
}

(T) +(T) {
    // Unary
}

(T) (T)+(T) {
    // Binary
}
</code></pre>
<p>The types would likely have to be parenthesized to avoid ambiguous syntax.</p>

CC BY-SA 4.0
2023-05-16T17:26:03.467Z
2023-05-16T17:26:03.467Z
CPlus
CC BY-SA 4.0
2023-05-16T17:39:09.680Z
I really like this. Agda does something similar, where the name of a function has underscores in the places that it should expect arguments, so `_++` is the postfix function's name and `++_` is the prefix one. You can also go a little bit crazy: `_≡⟨_⟩_` is a real function from the Agda stdlib that is quite commonly used.
Silvio Mayolo
CC BY-SA 4.0
2023-05-17T00:03:37.453Z
"The types would likely have to be parenthesized to avoid ambiguous syntax." I think this is likely only an issue for languages with relatively expressive type systems. I can see it causing a problem if e.g. `<>` are used to indicate type parametrization.
Karl Knechtel
<p><a href="/questions/tagged/scala" class="post-tag" title="show questions tagged &#39;scala&#39;" aria-label="show questions tagged &#39;scala&#39;" rel="tag" aria-labelledby="tag-scala-tooltip-container">scala</a></p>
<h1>tl;dr</h1>
<p><a href="https://scastie.scala-lang.org/JoergWMittag/Isd0krQpQvCd2wiTwIVRKA" rel="nofollow noreferrer">This is legal, runnable Scala code</a>:</p>
<pre class="lang-scala prettyprint-override"><code>import language.postfixOps

object Foo:
  def +(other: this.type) = &quot;binary infix&quot;
  def +                   = &quot;unary postfix&quot;
  def unary_+             = &quot;unary prefix&quot;

Foo + Foo //=&gt; &quot;binary infix&quot;

Foo +     //=&gt; &quot;unary postfix&quot;

+ Foo     //=&gt; &quot;unary prefix&quot;
</code></pre>
<p>Scala allows calling arbitrary methods with one argument using infix syntax and allows arbitrary operator characters in method names, therefore allowing arbitrary operators to be defined. Associativity and precedence, however, cannot be freely defined, they are based on the method name.</p>
<h1>Scala 2 (Legacy)</h1>
<p><a href="https://scala-lang.org/" rel="nofollow noreferrer">Scala</a> <em>mostly</em> doesn't deal with operators at all. <a href="https://scala-lang.org/files/archive/spec/2.13/06-expressions.html#infix-operations" rel="nofollow noreferrer">There are three rules for method calls</a> which allow Scala to support what &quot;feels like&quot; operators and operator overloading without actually having to deal with special support for operators and operator overloading:</p>
<ol>
<li>The <code>.</code> for method calls can be replaced by whitespace.</li>
<li>When using the method calling syntax from #1, parentheses for a single argument list with a single argument are optional.</li>
<li>A method whose name ends with <code>:</code> is right-associative.</li>
</ol>
<p>So, rule #1 means that I can replace</p>
<pre class="lang-scala prettyprint-override"><code>foo.bar(baz)
</code></pre>
<p>with</p>
<pre class="lang-scala prettyprint-override"><code>foo bar(baz)
</code></pre>
<p>and rule #2 means I can replace <em>that</em> with</p>
<pre class="lang-scala prettyprint-override"><code>foo bar baz
</code></pre>
<p>There is nothing special about <code>bar</code>. <em>Any</em> method call expression with a single argument list with a single argument can be written this way.</p>
<p>Consequently, there is nothing special about</p>
<pre class="lang-scala prettyprint-override"><code>a + b
</code></pre>
<p>It is simply the same as</p>
<pre class="lang-scala prettyprint-override"><code>a.+(b)
</code></pre>
<p>applying rules #1 and #2 from above. <code>+</code> is just a legal name for a method like any other. Scala's rules for identifiers are roughly the same as for other popular languages (alphanumeric, can't start with a number, etc.), <em>except</em> that identifiers can also contain (and be completely composed of) <em>operator characters</em>. When mixing operators and alphanumerics, they need to be separated by an underscore. So, <code>foo</code> is legal <code>++--::::--++!!!****</code> is legal, <code>foo_+</code> is legal.</p>
<p>The third rule means that</p>
<pre class="lang-scala prettyprint-override"><code>a +: b
</code></pre>
<p>is actually equivalent to</p>
<pre class="lang-scala prettyprint-override"><code>b.+:(a)
</code></pre>
<p>or, more precisely (observing left-to-right evaluation):</p>
<pre class="lang-scala prettyprint-override"><code>{ val __unspeakable_name__ = a; b.+:(__unspeakable_name__) }
</code></pre>
<p>This is primarily used to support the standard <code>::</code> operator for <em>prepending</em> an element to a <code>CONS</code> list. Naturally, in a single-dispatch OO language, that must be a method of the <em>list</em> object, but we still want to write the elements in the order they appear in the list:</p>
<pre class="lang-scala prettyprint-override"><code>val list = 1 :: 2 :: 3 :: Nil
// is equivalent to
val list = Nil.::(3).::(2).::(1)
</code></pre>
<p>But what about precedence? And what about unary prefix operators? Okay, that's where my qualification from above comes in, where I wrote Scala &quot;mostly&quot; doesn't deal with operators.</p>
<p>For precedence, the rule is that the precedence is determined by the <em>first character</em> of the operator. I.e. all operators starting with <code>+</code> have the same precedence, all starting with <code>-</code> have the same precedence, and so on. The relative precedence between the starting characters is roughly the &quot;standard&quot; precedence from languages like C or Java, but with some modifications.</p>
<p>For unary prefix operators, Scala does not allow defining new ones. It only allows <code>+</code>, <code>-</code>, <code>~</code>, and <code>!</code>. Unary prefix operator expressions are translated into method calls by prefixing <code>unary_</code> to them, e.g.</p>
<pre class="lang-scala prettyprint-override"><code>+foo
-foo
~foo
!foo
</code></pre>
<p>is equivalent to</p>
<pre class="lang-scala prettyprint-override"><code>foo.unary_+
foo.unary_-
foo.unary_~
foo.unary_!
</code></pre>
<p>Note how the rule that identifiers mixing alphanumeric and operator characters must be separated by an underscore is observed, so these are legal identifiers and can be defined using normal method definition syntax.</p>
<p>Unary postfix operators used to be allowed by simply observing rule #1 from above:</p>
<pre class="lang-ruby prettyprint-override"><code>foo bar
</code></pre>
<p>is equivalent to</p>
<pre class="lang-ruby prettyprint-override"><code>foo.bar
</code></pre>
<p>They are not <em>technically</em> deprecated (yet!) but their use is heavily discouraged. In current versions of Scala, they require an explicit <code>import</code> (or compiler flag), and will generate a compiler warning even if explicitly enabled.</p>
<p>There are a couple of other rules in order to support common use cases for operator overloading:</p>
<ul>
<li>Function application syntax: if there is no method named <code>foo</code> in scope, then <code>foo(bar)</code> translates to <code>foo.apply(bar)</code>. This is used extensively for Factory methods, e.g. Scala has no literal syntax for collections, instead, all collections have companion objects with an <code>apply</code> method, which allows you to construct e.g. a <code>List</code> with <code>List(1, 2, 3, 4)</code>. This is also used for array and map indexing, treating arrays as functions of their indices and maps as functions of their keys (in fact, arrays and maps literally inherit from <code>Function</code>).</li>
<li>Update syntax: <code>foo(bar) = baz</code> translates to <code>foo.update(bar, baz)</code>. Not used extensively, as the Scala community eschews mutability.</li>
<li>Property syntax: If there is no mutable field (<code>var</code>) named <code>bar</code>, then <code>foo.bar = baz</code> translates to <code>foo.bar_=(baz)</code>.</li>
<li>Assignment operators: <code>+=</code>, <code>-=</code>, etc. are just normal method names, so they can be implemented, i.e. <code>a += b</code> translates to <code>a.+=(b)</code>. However, if there is no method named <code>+=</code> but the expression <code>a = a + b</code> type checks, then that translation is chosen. This means <code>+=</code> can be overloaded, but <code>var n = 0; n += 1</code> still works as expected even though <code>Int</code> doesn't define <code>+=</code>.</li>
</ul>
<p>There are some other &quot;magic methods&quot;, but they are not related to operators, specifically:</p>
<ul>
<li><code>for</code> comprehensions de-sugar into calls to <code>foreach</code>, <code>map</code>, <code>flatMap</code>, and <code>withFilter</code>.</li>
<li>Pattern Matching de-sugars into calls to <code>unapply</code> and <code>unapplySeq</code>.</li>
</ul>
<p>An interesting tidbit is that infix notation is also valid for <em>type constructors</em>. Application of a binary type constructor <code>C[A, B]</code> can be written as <code>A C B</code>. This is rarely used but can be useful in the context of type-level programming. For example, the type-constructor <code>=:=[A, B]</code> compiles IFF <code>A</code> and <code>B</code> are equal, and it should be obvious why being able to write it as <code>A =:= B</code> is desirable.</p>
<h1>Scala 3 (Current)</h1>
<p><a href="https://docs.scala-lang.org/scala3/reference/changed-features/operators.html" rel="nofollow noreferrer">Some of the rules above have been tightened up in Scala 3</a>:</p>
<ul>
<li>It is always possible to call a method using infix syntax by enclosing it in backticks, i.e. <code>foo `bar` baz</code> and <code>foo `+` baz</code> are always allowed and are equivalent to <code>foo.bar(baz)</code> and <code>foo.+(baz)</code>.</li>
<li>It is still always possible to call a method whose name consists exclusively of operator characters using infix notation, i.e. <code>a + b</code> is still allowed.</li>
<li>Methods whose name contains alphanumeric characters can only be called using infix notation if they are explicitly marked <code>infix</code> at the definition site: <code>infix def foo(bar: SomeParameterType): SomeResultType</code>. Operator methods don't need an <code>infix</code> modifier.</li>
<li>For operator methods, it is <em>encouraged</em> to use the <code>@targetName</code> annotation which allows you to choose a human-readable name for the method in the actual compiled code. This is especially useful if the name is illegal in the underlying target platform (e.g. the JVM). For example, <code>@targetName(&quot;prepend&quot;) def ++:(other: SomeParameterType): SomeResultType</code> will be compiled into a Java method named <code>prepend</code> whereas without the annotation it would be something like <code>$plus$plus$colon</code>, which would be the name you need to use if you want to call this method from Java, Kotlin, Ruby, or any other JVM language.</li>
</ul>
<p>But the fundamental idea of trying to, as much as possible, treat operators as methods like any other, just with funky names, remains.</p>
<hr />
<p>Disclosure: this answer was copy&amp;pasted to <a href="https://langdev.stackexchange.com/a/2768/854">https://langdev.stackexchange.com/a/2768/854</a></p>

CC BY-SA 4.0
2023-06-29T04:29:59.880Z
2023-08-17T20:47:26.533Z
2023-08-17T20:47:26.533Z
Jörg W Mittag
<p>There is a thing called <a href="https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods" rel="nofollow noreferrer">extension methods</a> in C#. You could add a <code>NewMethod</code> into an <code>ExistingClass</code> using this:</p>
<pre><code>public static ReturnType NewMethod(this ExistingClass ParamName,...) {
    ...
}
</code></pre>
<p>It also has to be in a static class, which is only because they don't want functions outside classes in C#, unimportant to the discussion.</p>
<p>If we are borrowing this <code>this</code> grammar, we could come up with some straightforward ideas. In the class the operator is used upon, we could use:</p>
<pre><code>class Type{
    ReturnType operator++(){
        //postfix ++
    }
    static ReturnType operator++(Type x){
        //prefix ++
        //May not be best.
        //It has ambiguity without the C# assumption that every function has a &quot;this&quot;.
    }
    static ReturnType operator++(this, Type x){
        //prefix ++
        //Alternative, denoting &quot;this&quot; is empty.
    }
}
</code></pre>
<p>Outside a class, we could use:</p>
<pre><code>ReturnType operator++(this Type x){
    //postfix ++
}
ReturnType operator++(Type x){
    //prefix ++
}
</code></pre>
<p>It's like we are using the prefix <code>++</code> like a standalone function and the postfix <code>++</code> like a method, imitating the order of the object and the operator in the two cases.</p>

CC BY-SA 4.0
2023-07-03T11:54:06.290Z
2023-07-03T11:54:06.290Z
user23013
<p>Using the <a href="https://github.com/tyr-lang/stdlib/blob/master/lang/src/operator/properties.tyr" rel="nofollow noreferrer">attribute</a> system to define a prefix or postfix attribute. Distinction from binary operators should and commonly happens over the type system simply by checking the operand count.</p>
<p>The very definition can reuse the syntax of functions replacing the identifier token with an operator token (<a href="https://github.com/tyr-lang/stdlib/blob/923229873df2e8a6373ac22e8940fe5301b9fed3/lang/src/integer.tyr#L20" rel="nofollow noreferrer">example</a>).</p>

CC BY-SA 4.0
2023-08-21T16:06:58.177Z
2023-08-21T16:06:58.177Z
feldentm
# What alternatives are there for C++ operator overloading syntax?
Posted by: username_0 on 2023-05-16
I noticed C++ has operator overloading syntax with just the operator names:
T& operator +(T& lhs, T& rhs) {
    return /* ... */;
}

However, there are 2 distinct operators that are both ++ and --. One being a suffix and one being a prefix. C++ syntax has no way to distinguish them with the syntax, so instead one of them uses an unused int parameter. But this seems ungraceful.
What would be a good alternative syntax for operator overloading that could unambiguously distinguish unary + with binary + and also distinguish ++x from x++ without hacks such as unused parameters?
**Tags:** syntax operators operator-overloading
> **Comments:**
> **username_1**: The _advantage_ of the C++ style syntax is not having to remember made-up names for all the operators (like `__add__` in Python for example), although unfortunately you do end up with some cases like mentioned in this question.  
> **username_2**: The evil answer would be `T &operator(T &t)++;`  
---
## 11 answers
### Answer by username_3 on 2023-05-16. Score: 12 | Accepted answer
Rust-style traits
In Rust, operator overloading is implemented using core traits built into the language, which allow the operators to be named, without conflicting with methods which have the same name (e.g., you may want x.add() to be different from the + overload, maybe if x is a set).
This would look something like:
impl core::ops::Add for T {
    fn add(...) -> T { ... }
}

The advantage of this is that, unless the core::ops::Add trait is used in a file, this add method will not be accessable. This allows other add functions to be implemented on T without conflict.
Demo
---
### Answer by username_4 on 2023-05-16. Score: 12
Using names instead
To rectify this problem, you can use names instead of symbols for the names of operator functions. For example, take a look at Kotlin:
operator fun inc(): X {
    // ++a/a++
}
operator fun plus(other: Y): Z {
    // a + b
}
> **Comments:**
> **username_5** (2023-05-17): Python also takes this approach. For example, `+` is implemented by `__add__` and `__radd__` (a cooperative protocol is used to check the LHS and RHS types for an implementation, and `+=` can be specialized using `__iadd__` (although it does not perform the actual assignment).  
> **username_6** (2023-08-25): And while Python doesn't have pre- or post-increment operators, if it did I would expect them to have distinct dunder methods, e.g. `__preinc__` and `__postinc__`.  
---
### Answer by username_7 on 2023-05-16. Score: 9
Prefix the operator with its syntactic type. Raku allows the user to define custom operators with virtually any string of symbols (or letters, in fact) as names. The ambiguity is resolved by an explicit declaration at function site of which form of syntax the operator takes.
# Prefix ++
sub prefix:<++>($arg) {
  ...
}

# Postfix ++
sub postfix:<++>($arg) {
  ...
}
---
### Answer by username_11 on 2023-05-17. Score: 8
UpValues in Mathematica
Mathematica (the Wolfram Language) is based on pattern matching and term rewriting. Functions are defined as rules. For example, when you define a function like this:
f[x_] := x^2

It defines a rule that says "when you see f[x_], replace it with x^2". This rule is associated with the symbol f, and is called a "downvalue" of f.
Mathematica also has "upvalues", where the rule is associated with a symbol in the function's arguments instead of the function's name. For example, if you define:
f[x] ^:= x^2

Then the rule is associated with the symbol x, and is called an "upvalue" of x.
Operators in Mathematica are just syntactic sugar for built-in functions. For example, a + b is equivalent to Plus[a, b]. Downvalues for built-in functions are protected, so you can't redefine Plus directly. However, you can define upvalues for your own symbols.
For example, if you want to define your own complex number type, you can define a symbol Comp, and then define addition and multiplication for it:
Comp[a_, b_] + Comp[c_, d_] ^:= Comp[a + c, b + d]
Comp[a_, b_] * Comp[c_, d_] ^:= Comp[a c - b d, a d + b c]

These rules are associated with the symbol Comp instead of Plus and Times, so they don't conflict with the built-in rules for Plus and Times.
---
### Answer by username_0 on 2023-05-16. Score: 8
The arguments could be placed next to the operator in relation to their usage, as opposed to in a list afterwards:
(T) ++(T) {
    // Prefix
}

(T) (T)++ {
    // Suffix 
}

(T) +(T) {
    // Unary
}

(T) (T)+(T) {
    // Binary
}

The types would likely have to be parenthesized to avoid ambiguous syntax.
> **Comments:**
> **username_7** (2023-05-16): I really like this. Agda does something similar, where the name of a function has underscores in the places that it should expect arguments, so `_++` is the postfix function's name and `++_` is the prefix one. You can also go a little bit crazy: `_≡⟨_⟩_` is a real function from the Agda stdlib that is quite commonly used.  
> **username_5** (2023-05-17): "The types would likely have to be parenthesized to avoid ambiguous syntax." I think this is likely only an issue for languages with relatively expressive type systems. I can see it causing a problem if e.g. `<>` are used to indicate type parametrization.  
---
### Answer by username_9 on 2023-06-29. Score: 7
scala
tl;dr
This is legal, runnable Scala code:
import language.postfixOps

object Foo:
  def +(other: this.type) = "binary infix"
  def +                   = "unary postfix"
  def unary_+             = "unary prefix"

Foo + Foo //=> "binary infix"

Foo +     //=> "unary postfix"

+ Foo     //=> "unary prefix"

Scala allows calling arbitrary methods with one argument using infix syntax and allows arbitrary operator characters in method names, therefore allowing arbitrary operators to be defined. Associativity and precedence, however, cannot be freely defined, they are based on the method name.
Scala 2 (Legacy)
Scala mostly doesn't deal with operators at all. There are three rules for method calls which allow Scala to support what "feels like" operators and operator overloading without actually having to deal with special support for operators and operator overloading:

The . for method calls can be replaced by whitespace.
When using the method calling syntax from #1, parentheses for a single argument list with a single argument are optional.
A method whose name ends with : is right-associative.

So, rule #1 means that I can replace
foo.bar(baz)

with
foo bar(baz)

and rule #2 means I can replace that with
foo bar baz

There is nothing special about bar. Any method call expression with a single argument list with a single argument can be written this way.
Consequently, there is nothing special about
a + b

It is simply the same as
a.+(b)

applying rules #1 and #2 from above. + is just a legal name for a method like any other. Scala's rules for identifiers are roughly the same as for other popular languages (alphanumeric, can't start with a number, etc.), except that identifiers can also contain (and be completely composed of) operator characters. When mixing operators and alphanumerics, they need to be separated by an underscore. So, foo is legal ++--::::--++!!!**** is legal, foo_+ is legal.
The third rule means that
a +: b

is actually equivalent to
b.+:(a)

or, more precisely (observing left-to-right evaluation):
{ val __unspeakable_name__ = a; b.+:(__unspeakable_name__) }

This is primarily used to support the standard :: operator for prepending an element to a CONS list. Naturally, in a single-dispatch OO language, that must be a method of the list object, but we still want to write the elements in the order they appear in the list:
val list = 1 :: 2 :: 3 :: Nil
// is equivalent to
val list = Nil.::(3).::(2).::(1)

But what about precedence? And what about unary prefix operators? Okay, that's where my qualification from above comes in, where I wrote Scala "mostly" doesn't deal with operators.
For precedence, the rule is that the precedence is determined by the first character of the operator. I.e. all operators starting with + have the same precedence, all starting with - have the same precedence, and so on. The relative precedence between the starting characters is roughly the "standard" precedence from languages like C or Java, but with some modifications.
For unary prefix operators, Scala does not allow defining new ones. It only allows +, -, ~, and !. Unary prefix operator expressions are translated into method calls by prefixing unary_ to them, e.g.
+foo
-foo
~foo
!foo

is equivalent to
foo.unary_+
foo.unary_-
foo.unary_~
foo.unary_!

Note how the rule that identifiers mixing alphanumeric and operator characters must be separated by an underscore is observed, so these are legal identifiers and can be defined using normal method definition syntax.
Unary postfix operators used to be allowed by simply observing rule #1 from above:
foo bar

is equivalent to
foo.bar

They are not technically deprecated (yet!) but their use is heavily discouraged. In current versions of Scala, they require an explicit import (or compiler flag), and will generate a compiler warning even if explicitly enabled.
There are a couple of other rules in order to support common use cases for operator overloading:

Function application syntax: if there is no method named foo in scope, then foo(bar) translates to foo.apply(bar). This is used extensively for Factory methods, e.g. Scala has no literal syntax for collections, instead, all collections have companion objects with an apply method, which allows you to construct e.g. a List with List(1, 2, 3, 4). This is also used for array and map indexing, treating arrays as functions of their indices and maps as functions of their keys (in fact, arrays and maps literally inherit from Function).
Update syntax: foo(bar) = baz translates to foo.update(bar, baz). Not used extensively, as the Scala community eschews mutability.
Property syntax: If there is no mutable field (var) named bar, then foo.bar = baz translates to foo.bar_=(baz).
Assignment operators: +=, -=, etc. are just normal method names, so they can be implemented, i.e. a += b translates to a.+=(b). However, if there is no method named += but the expression a = a + b type checks, then that translation is chosen. This means += can be overloaded, but var n = 0; n += 1 still works as expected even though Int doesn't define +=.

There are some other "magic methods", but they are not related to operators, specifically:

for comprehensions de-sugar into calls to foreach, map, flatMap, and withFilter.
Pattern Matching de-sugars into calls to unapply and unapplySeq.

An interesting tidbit is that infix notation is also valid for type constructors. Application of a binary type constructor C[A, B] can be written as A C B. This is rarely used but can be useful in the context of type-level programming. For example, the type-constructor =:=[A, B] compiles IFF A and B are equal, and it should be obvious why being able to write it as A =:= B is desirable.
Scala 3 (Current)
Some of the rules above have been tightened up in Scala 3:

It is always possible to call a method using infix syntax by enclosing it in backticks, i.e. foo `bar` baz and foo `+` baz are always allowed and are equivalent to foo.bar(baz) and foo.+(baz).
It is still always possible to call a method whose name consists exclusively of operator characters using infix notation, i.e. a + b is still allowed.
Methods whose name contains alphanumeric characters can only be called using infix notation if they are explicitly marked infix at the definition site: infix def foo(bar: SomeParameterType): SomeResultType. Operator methods don't need an infix modifier.
For operator methods, it is encouraged to use the @targetName annotation which allows you to choose a human-readable name for the method in the actual compiled code. This is especially useful if the name is illegal in the underlying target platform (e.g. the JVM). For example, @targetName("prepend") def ++:(other: SomeParameterType): SomeResultType will be compiled into a Java method named prepend whereas without the annotation it would be something like $plus$plus$colon, which would be the name you need to use if you want to call this method from Java, Kotlin, Ruby, or any other JVM language.

But the fundamental idea of trying to, as much as possible, treat operators as methods like any other, just with funky names, remains.

Disclosure: this answer was copy&pasted to https://langdev.stackexchange.com/a/2768/854
---
### Answer by username_8 on 2023-05-30. Score: 6
The Operator Is An Argument
In D, a few special method names are reserved for operator overloading, including opUnary and opBinary, and they are used as templates to which the operator is passed as argument.
https://dlang.org/spec/operatoroverloading.html
This means that, for example, +x is interpreted as x.opUnary!"+", and x + y as x.opBinary!"+"(y).
This has the major advantage that multiple syntactically related operators can be implemented by a single function template.
struct S
{
    int x;
    S opBinary(string Op)(in S o) const
    {
        mixin("return S(x", Op, " o.x);");
    }
    
    unittest
    {
        const x = S(21);
        const y = S(2);
        const z = x * y;
        assert(z.x == 42);
    }
}

Another example is that of the cast operator, implemented as opCast where the type is passed as argument.
Combined with CTFE and user-defined overload resolution, it acts similarly to the previous example.
struct S
{
    int x;

    T opCast(T)() const
      if(is(int : T))
    {
        return x;
    }
    T opCast(T: string)() const
    {
        return imported!"std.conv".to!string(x);
    }

    unittest
    {
        const s = S(42);
        const x = cast(long) s;
        const str = cast(string) s;
        assert(x == 42);
        assert(str == "42");
    }
}

x++ calls ++x

What would be a good alternative syntax for operator overloading that could [...] distinguish ++x from x++ without hacks such as unused parameters?

x++ really means (in GNU C's syntax) ({ __auto_type _tmp = x; ++x; _tmp; }).
This is also how both prefix and postfix (inc|dec)rementation operator in D resolve to opUnary.
Naturally, any copy and related semantics can be optimised away via copy elision.
---
### Answer by username_9 on 2023-06-29. Score: 5
ruby
In Ruby, binary infix operators are just syntactic sugar for message sends, i.e. for all binary infix operators ω,
a ω b

is syntactic sugar for
a.ω(b)

Consequently, since operator expressions are just message sends, they invoke methods just like any other message send and just like any other message send, the name of the method being invoked is the same as the message.
So, defining an operator is just defining a method with the same name as the operator. Defining a method named plus looks like this:
module SomeModule
  def plus(other)
    # do something with `self` and `other`
  end
end

And thus, defining a method named + looks exactly identical:
module SomeModule
  def +(other)
    # do something with `self` and `other`
  end
end

There are, however, some special cases.
Firstly, not all operators can be defined. . (message sending), = (assignment), && (logical-AND), || (logical-OR), and, or, unary prefix & (unroll an object responding to to_proc into a block), and unary prefix defined? don't translate into message sends and thus cannot be defined. Unary prefix not cannot be defined on its own, but it translates into a message send of !, which means it is always identical to unary prefix ! which can be defined.
Second, this scheme obviously only works for binary infix operators. Ruby does not have unary postfix operators, but it does have some unary prefix operators. The ones which can be defined are: +, -, !, and ~.
Since there is no binary infix operator named ! or ~, these are just syntactic sugar for argument-less message sends with the same name as the operator and thus are defined with the same name, similar to binary infix operators:
not a # is same as
!a    # is same as
a.!
# is defined using
module SomeModule
  def !
    # do something with `self`
  end
end

~a # is same as
a.~
# is defined using
module SomeModule
  def ~
    # do something with `self`
  end
end

In Ruby, there can be only one method with a particular name in a particular module, so it is not possible to define unary prefix + and - as a parameterless method named + or - since that would clash with the binary infix versions. So, for these two operators, the rule is slightly modified in that they are translated to +@ and -@, respectively:
+a # is same as
a.+@
# is defined using
module SomeModule
  def +@
    # do something with `self`
  end
end

-a # is same as
a.-@
# is defined using
module SomeModule
  def -@
    # do something with `self`
  end
end

So, long answer short: the way to disambiguate operators with the same name but different arity is to give them different names when defining them.
---
### Answer by username_10 on 2023-06-01. Score: 4
In Python the methods become special only because of its name.
For example for +:
def __add__(...):
    ...

Python like methods names:

+ -- __add__
- -- __sub__
* -- __mul__
/ -- __div__
...
---
### Answer by username_12 on 2023-07-03. Score: 1
There is a thing called extension methods in C#. You could add a NewMethod into an ExistingClass using this:
public static ReturnType NewMethod(this ExistingClass ParamName,...) {
    ...
}

It also has to be in a static class, which is only because they don't want functions outside classes in C#, unimportant to the discussion.
If we are borrowing this this grammar, we could come up with some straightforward ideas. In the class the operator is used upon, we could use:
class Type{
    ReturnType operator++(){
        //postfix ++
    }
    static ReturnType operator++(Type x){
        //prefix ++
        //May not be best.
        //It has ambiguity without the C# assumption that every function has a "this".
    }
    static ReturnType operator++(this, Type x){
        //prefix ++
        //Alternative, denoting "this" is empty.
    }
}

Outside a class, we could use:
ReturnType operator++(this Type x){
    //postfix ++
}
ReturnType operator++(Type x){
    //prefix ++
}

It's like we are using the prefix ++ like a standalone function and the postfix ++ like a method, imitating the order of the object and the operator in the two cases.
---
### Answer by username_13 on 2023-08-21. Score: 1
Using the [attribute](https://github.com/tyr-lang/stdlib/blob/master/lang/src/operator/properties.tyr) system to define a prefix or postfix attribute. Distinction from binary operators should and commonly happens over the type system simply by checking the operand count.

The very definition can reuse the syntax of functions replacing the identifier token with an operator token ([example](https://github.com/tyr-lang/stdlib/blob/923229873df2e8a6373ac22e8940fe5301b9fed3/lang/src/integer.tyr#L20)).
---
