Inconsistent permission for operator overloading when using operators with the syntax "function style" ("(binaryOp) (lhs, rhs)" and "(unaryOp) (operand)")

Question (/ TL; DR)

In the details below, we see that using the syntax of the style ( (unaryOperator)(operand), (binaryOperator)(lhsOperand, rhsOperand)) function to call operator functions seems to override the normal rules for resolving type overloads; an overload simply selects the first (in the order of definition) overload that it can find.

  • This is mistake? Or is it some kind of peculiar, but expected behavior of the syntax call-operator-by-function-style ( (unaryOperator)(operand), (binaryOperator)(lhsOperand, rhsOperand))?

Background

I just read Matt Gallagher's excellent post about some current Swift type checking issues

One of the issues raised in the article is the problems that may arise from the fact that general overloads are not taken into account when resolving operator overloads, given that there are no general alternatives. Gallagher shows one such “question” with the following example

/* note: Swift 3 */
prefix operator %% {}
prefix func %%(_ x: Float) -> Float { return x }
prefix func %%<I: Integer>(_ x: I) -> I { return x }

let y = %%1          // integer literal
print(y.dynamicType) // "Float"

Naturally, we see the same result if we switch places to the two definitions of the operator %%above, i.e.

/* ... same result as above */
prefix operator %% {}
prefix func %%<I: Integer>(_ x: I) -> I { return x }
prefix func %%(_ x: Float) -> Float { return x }

Note also that the aforementioned strictly non-general priority for overload resolution is missing for functions, as Gallagher shows with the following example

/* resolves x to "Int", no matter the order 
   of these two function definitions */
func f(_ x: Float) -> Float { return x }
func f<I: Integer>(_ x: I) -> I { return x }

let x = f(1)
print(x.dynamicType) // "Int"

Additional information related to the issue

Now about the features. We can name binary and unary operations in the style of the function using the syntax (binaryOperator)(lhsOperand, rhsOperand)and (unaryOperator)(operand), respectively. For instance.

let a = (+)(1, 2) // 3
let b = (-)(a)    // -3

, %%, , , ( , ) y , -, , %%.

prefix operator %% {}
prefix func %%(_ x: Float) -> Float { return x }
prefix func %%<I: Integer>(_ x: I) -> I { return x }

let y = (%%)(1)      
print(y.dynamicType) // "Float"

/* swap the order of the definitions ... */
prefix operator %% {}
prefix func %%<I: Integer>(_ x: I) -> I { return x }
prefix func %%(_ x: Float) -> Float { return x }    

let y = (%%)(1)      
print(y.dynamicType) // "Int"

, () %%1, (%%)(1) , , .

prefix operator %% {}
prefix func %%(_ x: Double) -> Double { return x }  
prefix func %%<I: Integer>(_ x: I) -> I { return x }
prefix func %%(_ x: Float) -> Float { return x }    

// picks first %% definition it can find
let y = (%%)(1)   
print(y.dynamicType) // "Double"

// ambiguity error as expected
//let z = %%(1) // error: ambiguous use of operator '%%'

[†]: : , , , , , , . , - "" : , , .


( Swift 3.0 IBM Swift Sandbox, Swift 2.2, XCode 7.3, )

+2

Source: https://habr.com/ru/post/1650925/