I've read all of the reference docs and expanded explanation, and have seen the related question.
While I understand the need to re-swap the operands for the curried arguments on the extension method, there is still a practical behavior difference I don't understand. From the perspective of the caller, identical syntax results in confusingly divergent behavior.
Take this trivial example:
class S (s: String):
def ?:(i: I): String = "On S"
class I(i: Int):
def ?:(s: S): String = "On I"
extension (s1: S)
def +:(i1: I): String = "On S"
extension (i1: I)
def +:(s1: S): String = "On I"
In the extension methods, I'm extending (or adding a method to) the target type. For example, the first one adds to S
. So I'd expect the +:
there to behave identically to the ?:
on S above. But in fact it is opposite:
S("foo") ?: I(1) // I is the target and it returns "On I"
S("foo") +: I(1) // S is the target and it returns "On S"
Is this a bug? Or is Scala 3 moving towards a future where the behavior of the class method is wrong here? Basically... how can both of these be correct and unambiguous for newcomers to the language.
Incidentally, this isn't an issue with Scala 2 syntax:
implicit class S1(s: S):
def %:(i: I): String = "On S"
implicit class I1(i: I):
def %:(s: S): String = "On I"
S("foo") ?: I(1) // I is the target and it returns "On I"
S("foo") %: I(1) // I is the target and it returns "On I"
To be clear, I'm not looking for the explanation of the implementation of extension methods that has been provided at the links I referenced above. I understand that aspect.
I'm also not confused about the parenthetical ordering of chained operations with left and right associative methods.
What I don't understand is, from a language design perspective, how can both S("foo") ?: I(1)
and S("foo") +: I(1)
(as given above) both be considered "correct"? They are syntactically identical yet are opposites of each other with regard to determining target and operand.