<p>Haskell has support for declaring custom infix operators, including their precedence and associativity. In addition, any identifier can be used as binary infix operator by placing it between backquotes. Have other languages picked this up or has the downside of creating too many custom infix operators made language designers stay clear of this?</p>
<ul>
<li><a href="https://github.com/haskell-implementations/gofer/blob/master/simple.prelude#L28-L40" rel="noreferrer">https://github.com/haskell-implementations/gofer/blob/master/simple.prelude#L28-L40</a></li>
</ul>
<pre class="lang-hs prettyprint-override"><code>-- Operator precedence table: -----------------------------------------------

infixl 9 !!
infixr 9 .
infixr 8 ^
infixl 7 *
infix  7 /, `div`, `quot`, `rem`, `mod`
infixl 6 +, -
infix  5 \\
infixr 5 ++, :
infix  4 ==, /=, &lt;, &lt;=, &gt;=, &gt;
infix  4 `elem`, `notElem`
infixr 3 &amp;&amp;
infixr 2 ||
infixr 0 $
</code></pre>
<p>I am more familiar with OCaml which can define and re-define infix operators but precedence and associativity is determined by the prefix of the operator. There is no support for using regular functions in infix positions. I like Haskell's more general and systematic approach but wonder how much it has spread beyond Haskell.</p>
<p>Addendum: I’ve asked moderators to turn this into a Community Wiki because there is no single perfect answer. The question collects how languages support the declaration of infix operators and each is interesting in its own right.</p>

<syntax><haskell><syntactic-sugar>
Declaring infix operators like Haskell's in other languages?
<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 is copy&amp;pasted from <a href="https://langdev.stackexchange.com/a/1759/854">https://langdev.stackexchange.com/a/1759/854</a></p>

CC BY-SA 4.0
2023-08-17T18:55:09.180Z
2023-08-17T20:46:50.723Z
2023-08-17T20:46:50.723Z
Jörg W Mittag
<h1>Swift</h1>
<p>Swift allows users to declare their own infix operators, and even custom precedence groups:</p>
<pre class="lang-swift prettyprint-override"><code>// here’s the fun little dance Swift makes you do to import the C stdlib:
#if canImport(Darwin)
import Darwin
#elseif canImport(Glibc)
import Glibc
#elseif canImport(WASILibc)
import WASILibc
#elseif canImport(ucrt)
import ucrt
#else
#error(&quot;unsupported platform&quot;)
#endif
// All that to get a pow function!

precedencegroup ExponentiationPrecedence {
  higherThan: MultiplicationPrecedence
  associativity: right
}

infix operator ** : ExponentiationPrecedence

extension Double {
  static func ** (lhs: Double, rhs: Double) -&gt; Double {
    pow(lhs, rhs)
  }
}
</code></pre>
<p>There are some restrictions on what an operator name can be, as I described in <a href="https://langdev.stackexchange.com/a/1189/15">this answer</a>. The short version is that it has to be punctuation and that certain characters are reserved.</p>

CC BY-SA 4.0
2023-08-17T21:34:16.843Z
2023-08-17T21:34:16.843Z
Bbrk24
CC BY-SA 4.0
2023-08-19T15:44:27.773Z
I knew I had seen a language that made precedence grouping a partial order; I just couldn't put my finger on which one it was. I think this is my favorite approach to order-of-operations. There's no obscure "Remember, `+` is precedence level 6" or whatever; it's all just relative.
Silvio Mayolo
CC BY-SA 4.0
2023-08-19T16:31:37.503Z
@SilvioMayolo: Fortress has a partial order as well, and pre-dates Swift. Operators which have no defined relative precedence cannot be used together in the same expression without explicit parentheses. You can use whitespace to *validate* the precedence, but not to *change* it, i.e. whitespace does not change the meaning of an expression, but it can cause a compile error. E.g., `1+2*3`, `1 + 2 * 3`, and `1 + 2*3` are all valid, but `1+2 * 3` is a compile error. Raku defines operator precedence relative, just like Fortress and Swift, but I believe the order is total.
Jörg W Mittag
CC BY-SA 4.0
2023-08-19T23:32:38.207Z
Swift is whitespace-sensitive but not to that extent. Like `2 -1` is illegal because it parses as two tokens (`2`, `-1`), but both `2 - 1` and `2-1` parse as three tokens (`2`, `-`, `1`) and are accepted.
Bbrk24
<h2>Prolog</h2>
<p>Prolog has an operator grammar. There are 51 operators built in, and users can declare their own.</p>
<p>You declare an operator like this:</p>
<pre><code>:- op( 1150,  fx, mode ).
:- op( 1050, xfy, -&gt; ).
:- op(  900,  fy, \+ ).
:- op(  700, xfx, = ).
:- op(  550, xfy, : ).
:- op(  500, yfx, - ).
:- op(  500, yfx, + ).
:- op(  200,  fy, - ).
</code></pre>
<p>The three arguments to the <code>op/3</code> declaration are the <em>precedence</em> (an integer between 0 and 1200), the <em>fixity</em>, and the operator symbol or name.</p>
<p>The fixity is one of <code>xf</code>, <code>yf</code>, <code>xfx</code>, <code>xfy</code>, <code>yfx</code>, <code>yfy</code>, <code>fy</code> or <code>fx</code>. You can interpret <code>f</code> as being the position of the operator, and <code>x</code> and <code>y</code> the positions of its operands. A <code>y</code> operand means that in that position, a term with precedence less than or equal to the precedence of this functor should occur. An <code>x</code> operands means that the precedence of that term must be strictly less than that of the functor. A basic term, or a term in parentheses, has predecedence 0.</p>
<p>So, for example, consider the infix <code>+</code> and <code>-</code> operators. They have the same precedence, and both have fixity <code>yfx</code>. Informally, this means that both operators are left-associative, so this:</p>
<pre><code>a - b + c - d
</code></pre>
<p>parses as (and could be equivalently written as):</p>
<pre><code>'-'('+'('-'(a,b),c),d)
</code></pre>
<p>Similarly, in this example, the <code>:</code> operator is right-associative, and the <code>=</code> operator is non-associative.</p>
<p>Both prefix and suffix operators are supported and, as you can see with the <code>-</code> operator, the same symbols can be used for both an infix operator and a prefix operator. In Prolog, these are <em>different</em> operators; one is <code>-/1</code> (i.e. minus with one argument) and the other is <code>-/2</code> (i.e. minus with two arguments).</p>
<p>Readers who know some things about parsing will note that it's possible to declare combinations of operators that are formally ambiguous. Parsing Prolog is nontrivial, and there are two competing standards (Edinburgh and ISO) which handle potential ambiguities in different ways.</p>

CC BY-SA 4.0
2023-08-18T14:11:03.770Z
2023-08-18T14:17:06.367Z
2023-08-18T14:17:06.367Z
Pseudonym
<p>Kotlin has the ability to create infix functions:</p>
<pre class="lang-kotlin prettyprint-override"><code>infix fun Int.foo(x: Int) = this + x * x

2 foo 3 // 11
</code></pre>
<p>Nothing super special like Scala. Just add an <code>infix</code> modifier and you're done. However, all infix functions are at the same precedence and it cannot be modified.</p>

CC BY-SA 4.0
2023-08-17T13:38:52.670Z
2023-08-17T19:08:04.300Z
2023-08-17T19:08:04.300Z
Seggan
<p><a href="https://raku.org" rel="nofollow noreferrer">Raku</a> allows not only prefix, suffix, and infix, but also &quot;circumfix&quot; and &quot;postcircumfix&quot; operators. Circumfix means things like <code>%&lt;code&gt;%</code>, and postcircumfix means things like <code>code%&lt;code&gt;%</code>. The <a href="https://docs.raku.org/language/optut" rel="nofollow noreferrer">tutorial</a> gives these examples:</p>
<pre><code>sub postcircumfix:&lt;⸨ ⸩&gt;( Positional <span class="math-container">$a, Whatever ) {
    say $a[0], '…', $</span>a[*-1]
}
 
[1,2,3,4]⸨*⸩;      # OUTPUT: «1…4␤» 
 
constant term:&lt;♥&gt; = &quot;♥&quot;; # We don't want to quote &quot;love&quot;, do we? 
sub circumfix:&lt;α ω&gt;( <span class="math-container">$a ) {
    say „$</span>a is the beginning and the end.“
};
 
α♥ω;               # OUTPUT: «♥ is the beginning and the end.␤»
</code></pre>
<p><a href="https://wiki.portal.chalmers.se/agda/pmwiki.php" rel="nofollow noreferrer">Agda</a> goes even further - it has <a href="https://agda.readthedocs.io/en/latest/language/mixfix-operators.html" rel="nofollow noreferrer">&quot;mixfix&quot; operators</a> that allow syntactic constructs as complex as <code>if x then y else z</code> to be defined as custom operators. This is done by defining a function with underscores as placeholders, e.g. <code>if_then_else_</code>:</p>
<pre><code>-- Example function name if_then_else_
if_then_else_ : {A : Set} → Bool → A → A → A
if true then x else y = x
if false then x else y = y
</code></pre>
<p>I'm not sure whether it also allows custom precedence and associativity rules for such complex operators, though.</p>
<p><a href="https://seed7.sourceforge.net/" rel="nofollow noreferrer">Seed7</a> also has <a href="https://seed7.sourceforge.net/manual/syntax.htm" rel="nofollow noreferrer">structured syntax definitions</a> which are very similar, including support for precedence levels for operators that aren't purely infix. The documentation gives this example:</p>
<pre><code>$ syntax expr: .loop.().until.().do.().end.loop   is -&gt; 25;
</code></pre>

CC BY-SA 4.0
2023-08-20T16:20:51.027Z
2023-08-20T16:20:51.027Z
pxeger
CC BY-SA 4.0
2023-08-23T04:57:21.617Z
Agda does indeed allow custom precedence and assoc. Agda parsing is *rather* complicated :P
See: https://agda.readthedocs.io/en/v2.5.2/language/mixfix-operators.html
blueberry
# Declaring infix operators like Haskell's in other languages?
Posted by: username_0 on 2023-08-17
Haskell has support for declaring custom infix operators, including their precedence and associativity. In addition, any identifier can be used as binary infix operator by placing it between backquotes. Have other languages picked this up or has the downside of creating too many custom infix operators made language designers stay clear of this?

https://github.com/haskell-implementations/gofer/blob/master/simple.prelude#L28-L40

-- Operator precedence table: -----------------------------------------------

infixl 9 !!
infixr 9 .
infixr 8 ^
infixl 7 *
infix  7 /, `div`, `quot`, `rem`, `mod`
infixl 6 +, -
infix  5 \\
infixr 5 ++, :
infix  4 ==, /=, <, <=, >=, >
infix  4 `elem`, `notElem`
infixr 3 &&
infixr 2 ||
infixr 0 $

I am more familiar with OCaml which can define and re-define infix operators but precedence and associativity is determined by the prefix of the operator. There is no support for using regular functions in infix positions. I like Haskell's more general and systematic approach but wonder how much it has spread beyond Haskell.
Addendum: I’ve asked moderators to turn this into a Community Wiki because there is no single perfect answer. The question collects how languages support the declaration of infix operators and each is interesting in its own right.
**Tags:** syntax haskell syntactic-sugar
---
## 5 answers
### Answer by username_1 on 2023-08-17. Score: 6
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 is copy&pasted from https://langdev.stackexchange.com/a/1759/854
---
### Answer by username_2 on 2023-08-17. Score: 6
Swift
Swift allows users to declare their own infix operators, and even custom precedence groups:
// here’s the fun little dance Swift makes you do to import the C stdlib:
#if canImport(Darwin)
import Darwin
#elseif canImport(Glibc)
import Glibc
#elseif canImport(WASILibc)
import WASILibc
#elseif canImport(ucrt)
import ucrt
#else
#error("unsupported platform")
#endif
// All that to get a pow function!

precedencegroup ExponentiationPrecedence {
  higherThan: MultiplicationPrecedence
  associativity: right
}

infix operator ** : ExponentiationPrecedence

extension Double {
  static func ** (lhs: Double, rhs: Double) -> Double {
    pow(lhs, rhs)
  }
}

There are some restrictions on what an operator name can be, as I described in this answer. The short version is that it has to be punctuation and that certain characters are reserved.
> **Comments:**
> **username_3** (2023-08-19): I knew I had seen a language that made precedence grouping a partial order; I just couldn't put my finger on which one it was. I think this is my favorite approach to order-of-operations. There's no obscure "Remember, `+` is precedence level 6" or whatever; it's all just relative.  
> **username_1** (2023-08-19): @SilvioMayolo: Fortress has a partial order as well, and pre-dates Swift. Operators which have no defined relative precedence cannot be used together in the same expression without explicit parentheses. You can use whitespace to *validate* the precedence, but not to *change* it, i.e. whitespace does not change the meaning of an expression, but it can cause a compile error. E.g., `1+2*3`, `1 + 2 * 3`, and `1 + 2*3` are all valid, but `1+2 * 3` is a compile error. Raku defines operator precedence relative, just like Fortress and Swift, but I believe the order is total.  
> **username_2** (2023-08-19): Swift is whitespace-sensitive but not to that extent. Like `2 -1` is illegal because it parses as two tokens (`2`, `-1`), but both `2 - 1` and `2-1` parse as three tokens (`2`, `-`, `1`) and are accepted.  
---
### Answer by username_4 on 2023-08-18. Score: 6
Prolog
Prolog has an operator grammar. There are 51 operators built in, and users can declare their own.
You declare an operator like this:
:- op( 1150,  fx, mode ).
:- op( 1050, xfy, -> ).
:- op(  900,  fy, \+ ).
:- op(  700, xfx, = ).
:- op(  550, xfy, : ).
:- op(  500, yfx, - ).
:- op(  500, yfx, + ).
:- op(  200,  fy, - ).

The three arguments to the op/3 declaration are the precedence (an integer between 0 and 1200), the fixity, and the operator symbol or name.
The fixity is one of xf, yf, xfx, xfy, yfx, yfy, fy or fx. You can interpret f as being the position of the operator, and x and y the positions of its operands. A y operand means that in that position, a term with precedence less than or equal to the precedence of this functor should occur. An x operands means that the precedence of that term must be strictly less than that of the functor. A basic term, or a term in parentheses, has predecedence 0.
So, for example, consider the infix + and - operators. They have the same precedence, and both have fixity yfx. Informally, this means that both operators are left-associative, so this:
a - b + c - d

parses as (and could be equivalently written as):
'-'('+'('-'(a,b),c),d)

Similarly, in this example, the : operator is right-associative, and the = operator is non-associative.
Both prefix and suffix operators are supported and, as you can see with the - operator, the same symbols can be used for both an infix operator and a prefix operator. In Prolog, these are different operators; one is -/1 (i.e. minus with one argument) and the other is -/2 (i.e. minus with two arguments).
Readers who know some things about parsing will note that it's possible to declare combinations of operators that are formally ambiguous. Parsing Prolog is nontrivial, and there are two competing standards (Edinburgh and ISO) which handle potential ambiguities in different ways.
---
### Answer by username_5 on 2023-08-17. Score: 5
Kotlin has the ability to create infix functions:
infix fun Int.foo(x: Int) = this + x * x

2 foo 3 // 11

Nothing super special like Scala. Just add an infix modifier and you're done. However, all infix functions are at the same precedence and it cannot be modified.
---
### Answer by username_6 on 2023-08-20. Score: 3
Raku allows not only prefix, suffix, and infix, but also "circumfix" and "postcircumfix" operators. Circumfix means things like %%, and postcircumfix means things like code%%. The tutorial gives these examples:
sub postcircumfix:<⸨ ⸩>( Positional $a, Whatever ) {
    say $a[0], '…', $a[*-1]
}
 
[1,2,3,4]⸨*⸩;      # OUTPUT: «1…4␤» 
 
constant term:<♥> = "♥"; # We don't want to quote "love", do we? 
sub circumfix:<α ω>( $a ) {
    say „$a is the beginning and the end.“
};
 
α♥ω;               # OUTPUT: «♥ is the beginning and the end.␤»

Agda goes even further - it has "mixfix" operators that allow syntactic constructs as complex as if x then y else z to be defined as custom operators. This is done by defining a function with underscores as placeholders, e.g. if_then_else_:
-- Example function name if_then_else_
if_then_else_ : {A : Set} → Bool → A → A → A
if true then x else y = x
if false then x else y = y

I'm not sure whether it also allows custom precedence and associativity rules for such complex operators, though.
Seed7 also has structured syntax definitions which are very similar, including support for precedence levels for operators that aren't purely infix. The documentation gives this example:
$ syntax expr: .loop.().until.().do.().end.loop   is -> 25;
> **Comments:**
> **username_7** (2023-08-23): Agda does indeed allow custom precedence and assoc. Agda parsing is *rather* complicated :P
See: https://agda.readthedocs.io/en/v2.5.2/language/mixfix-operators.html  
---
