language
language copied to clipboard
Infix function
Being able to add an infix
keyword before methods in order to be able to use them like a method b
instead of a.method(b)
would make the syntax cleaner in cases where both a
and b
have the same role/importance in the operation, such as in most mathematical forms.
In contrast to #607, this feature request doesn't aim to allow any arbitrary character as operators but instead only the usual method identifiers. Here are some examples of how the syntax could be used:
- Dot products like
vec dot otherVec
instead ofvec.dot(otherVec)
. - Ranges like
1 to 5
or2 until 5
instead of1.to(5)
and2.until(5)
, just like in Kotlin.
After this, make operators proper functions, so, for example a + b
would be +(a, b)
infixed function. This would allow for cleaner code like [1, 2, 3].reduce(+)
instead of [1, 2, 3].fold((a, b) => a + b)
.
The big issues here are:
- Parsing
- Precedence
Dart currently combine both for operators. They have special grammar rules that both ensure that x + y
is parsed as that, and that the precedence of +
is different from *
.
If we allow any identifier to be used as an infix operator, then we need to parse e1 foo e2
as an operators invocation.
That introduces ambiguity. Currently we can write int foo(x)=>2
to declare a function. However, that can also be parsed as (int) foo ((x)=>2)
which is an "infix operator foo
" applied to the Type
object of int
and a function literal.
"Obviously", Type
doesn't have a foo
operator, but equally obviously we want user-defined operators to work with extensions too, so nothing prevents someone from adding a foo
infix method to Type
. We only know that after parsing, so we can't let parsing rely on knowledge of whether something might be declared as an infix method.
Dart is in the C-syntax family (and, e.g., Kotlin is not), which means that adjacent identifiers only occur in declarations.
Something like int get foo;
is possible to parse, even though get
is not a reserved word, because it can't possibly be anything except a declaration, it's the only case where adjacent identifiers can validly occur. Allowing un-quoted identifiers as infix operators is very, very unlikely to be even possible without a complete overhaul of the entire language syntax.
#607 is much more likely.
So is a quoted syntax like 1 `add` 2
, but that then runs into the issue that all such operators have the same precedence (we really do not want you to declare the precedence, because the need to understand the declarations before we can parse the expressions, and the way Dart type inference works, we need to parse some expressions to find the type of declarations). If all infix methods have the same precedence, then you need a lot of parentheses, and then x.foo(y)
doesn't seem that much worse than (x `foo` y)
.
I understand the appeal, but I don't think this feature carries its weight. It eliminates some punctuation, but that's really all it accomplishes. In return, it opens the door to what can be very difficult to read code. This is valid Scala code:
ape bat cat dog eel fox
How many readers at a glance can tell which of those identifiers are receivers, parameters, or methods?
One of the nice things about Dart (and most other languages) is that even if you don't know what various identifiers resolve to, you can at least mostly visually parse it and understand the nesting structure correctly. I wouldn't want to give that up.
Having ability to do something doesn't means encourage use that for everthing.
if someone use infix function/operator override to writing code like
ape bat cat dog eel fox
that means he/she what that. The author of code should be responsible for what he/she has written not the designer of language. As far as I known Kotlin's ecosystem doesn't appear lots of infix override, ever infix I met is just perfect when it is be used.
For more, your Records
spec may need this infix operator for Pair