Expression pattern cannot be a named tuple constant

(Resending — this didn’t get any responses when I sent it a month ago.)

Swift 2.2 in Xcode 7.3.1.

Apparently you cannot use a named tuple constant as an expression pattern in a case label.

func test(x: Int, y: Int) -> Int {
   let int_1 = 1
   switch x {
   case 0:
       return 0
   case int_1:
       return 1
   default:
       break
   }

   let int_1_1: (Int, Int) = (1, 1)
   switch (x, y) {
   case (0, 0):
       return 0
   case int_1_1: // <<<<
       return 1
   default:
       return -1
   }
}

error: expression pattern of type '(Int, Int)' cannot match values of type '(Int, Int)'
   case int_1_1:
        ^~~~~~~

The error message is particularly amusing.

  - Neil Faiman

I think switch treats (x,y) as two variables instead of a tuple. So it
prohibits int_1_1 as it looks like one value only at the first glance.
Below two expressions will work.

case (int_1_1.0,int_1_1.1): // <<<<

case let foo where foo == int_1_1: // <<<<

​That why you can use something like

case (_, 10)

​Zhaoxin ​

···

On Tue, Jul 5, 2016 at 5:56 AM, Neil Faiman via swift-users < swift-users@swift.org> wrote:

(Resending — this didn’t get any responses when I sent it a month ago.)

Swift 2.2 in Xcode 7.3.1.

Apparently you cannot use a named tuple constant as an expression pattern
in a case label.

func test(x: Int, y: Int) -> Int {
   let int_1 = 1
   switch x {
   case 0:
       return 0
   case int_1:
       return 1
   default:
       break
   }

   let int_1_1: (Int, Int) = (1, 1)
   switch (x, y) {
   case (0, 0):
       return 0
   case int_1_1: // <<<<
       return 1
   default:
       return -1
   }
}

error: expression pattern of type '(Int, Int)' cannot match values of type
'(Int, Int)'
   case int_1_1:
        ^~~~~~~

The error message is particularly amusing.

        - Neil Faiman
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

I'd definitely consider that a bug. Can you file it at bugs.swift.org?

Jordan

···

On Jul 4, 2016, at 14:56, Neil Faiman via swift-users <swift-users@swift.org> wrote:

(Resending — this didn’t get any responses when I sent it a month ago.)

Swift 2.2 in Xcode 7.3.1.

Apparently you cannot use a named tuple constant as an expression pattern in a case label.

func test(x: Int, y: Int) -> Int {
  let int_1 = 1
  switch x {
  case 0:
      return 0
  case int_1:
      return 1
  default:
      break
  }

  let int_1_1: (Int, Int) = (1, 1)
  switch (x, y) {
  case (0, 0):
      return 0
  case int_1_1: // <<<<
      return 1
  default:
      return -1
  }
}

error: expression pattern of type '(Int, Int)' cannot match values of type '(Int, Int)'
  case int_1_1:
       ^~~~~~~

The error message is particularly amusing.

  - Neil Faiman
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

SR-1993.

···

On Jul 5, 2016, at 4:15 PM, Jordan Rose <jordan_rose@apple.com> wrote:

I'd definitely consider that a bug. Can you file it at bugs.swift.org?

Jordan

On Jul 4, 2016, at 14:56, Neil Faiman via swift-users <swift-users@swift.org> wrote:

(Resending — this didn’t get any responses when I sent it a month ago.)

Swift 2.2 in Xcode 7.3.1.

Apparently you cannot use a named tuple constant as an expression pattern in a case label.

func test(x: Int, y: Int) -> Int {
let int_1 = 1
switch x {
case 0:
     return 0
case int_1:
     return 1
default:
     break
}

let int_1_1: (Int, Int) = (1, 1)
switch (x, y) {
case (0, 0):
     return 0
case int_1_1: // <<<<
     return 1
default:
     return -1
}
}

error: expression pattern of type '(Int, Int)' cannot match values of type '(Int, Int)'
case int_1_1:
      ^~~~~~~

The error message is particularly amusing.

  - Neil Faiman
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

I’m not convinced that I see this as a bug, maybe more of a feature request?

The test given seems to be conflating a tuple-type with tuple-pattern…

Shane

···

On Jul 5, 2016, at 6:16 PM, Neil Faiman via swift-users <swift-users@swift.org> wrote:

SR-1993.

On Jul 5, 2016, at 4:15 PM, Jordan Rose <jordan_rose@apple.com> wrote:

I'd definitely consider that a bug. Can you file it at bugs.swift.org?

Jordan

On Jul 4, 2016, at 14:56, Neil Faiman via swift-users <swift-users@swift.org> wrote:

(Resending — this didn’t get any responses when I sent it a month ago.)

Swift 2.2 in Xcode 7.3.1.

Apparently you cannot use a named tuple constant as an expression pattern in a case label.

func test(x: Int, y: Int) -> Int {
let int_1 = 1
switch x {
case 0:
    return 0
case int_1:
    return 1
default:
    break
}

let int_1_1: (Int, Int) = (1, 1)
switch (x, y) {
case (0, 0):
    return 0
case int_1_1: // <<<<
    return 1
default:
    return -1
}
}

error: expression pattern of type '(Int, Int)' cannot match values of type '(Int, Int)'
case int_1_1:
     ^~~~~~~

The error message is particularly amusing.

  - Neil Faiman
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

It's somewhere in between the two. More formally, "by default, ~= compares two values of the same type using a conformance to Equatable". Since tuples aren't named types, they don't conform to Equatable, and so we don't use their == operator.

We could fix this by adding overloads of ~= for tuples, by having the compiler fall back to == in switches, or by eventually allowing tuples to conform to Equatable if their elements do (somehow). Maybe there are other answers I haven't thought of, too.

Jordan

···

On Jul 6, 2016, at 8:55, Neil Faiman <neil.swift@faiman.org> wrote:

It’s actually more complicated than that.

case (0, 0): is a tuple-pattern, so its interpretation is well defined. case int_1_1: must be an expression-pattern, since it does’t match any of the other pattern kinds. So it should compare the value of the pattern expression case_1_1 against the value of the switch expression (x, y).

Now, the Swift Reference, in the Expression Patterns section, says

The expression represented by the expression pattern is compared with the value of an input expression using the Swift standard library ~= operator. The match succeeds if the ~= operator returns true. By default, the ~= operator compares two values of the same type using the == operator. …

If this were true, then my code would compile and work as I expected.

But in fact, I observe that the expression int_1_1 == (x, y) compiles, but the expression int_1_1 ~= (x, y) gets the error “Binary operator ‘~=‘ cannot be applied to two ‘(int, int)’ operands.”

This strongly suggests that the emphasized line in the Swift Reference quote does not correctly describe the language behavior — there is a bug either in the documentation (~= was not intended to be defined for tuple types) or in the standard library (~= was intended to be defined for tuple types, but never got implemented).

It’s actually more complicated than that.

case (0, 0): is a tuple-pattern, so its interpretation is well defined. case int_1_1: must be an expression-pattern, since it does’t match any of the other pattern kinds. So it should compare the value of the pattern expression case_1_1 against the value of the switch expression (x, y).

Now, the Swift Reference, in the Expression Patterns section, says

The expression represented by the expression pattern is compared with the value of an input expression using the Swift standard library ~= operator. The match succeeds if the ~= operator returns true. By default, the ~= operator compares two values of the same type using the == operator. …

If this were true, then my code would compile and work as I expected.

But in fact, I observe that the expression int_1_1 == (x, y) compiles, but the expression int_1_1 ~= (x, y) gets the error “Binary operator ‘~=‘ cannot be applied to two ‘(int, int)’ operands.”

This strongly suggests that the emphasized line in the Swift Reference quote does not correctly describe the language behavior — there is a bug either in the documentation (~= was not intended to be defined for tuple types) or in the standard library (~= was intended to be defined for tuple types, but never got implemented).

Regards,

  Neil

···

On Jul 6, 2016, at 10:00 AM, Shane S <electro_alchemy@hotmail.com> wrote:

I’m not convinced that I see this as a bug, maybe more of a feature request?

The test given seems to be conflating a tuple-type with tuple-pattern…

Shane

On Jul 5, 2016, at 6:16 PM, Neil Faiman via swift-users <swift-users@swift.org> wrote:

SR-1993.

On Jul 5, 2016, at 4:15 PM, Jordan Rose <jordan_rose@apple.com> wrote:

I'd definitely consider that a bug. Can you file it at bugs.swift.org?

Jordan

On Jul 4, 2016, at 14:56, Neil Faiman via swift-users <swift-users@swift.org> wrote:

(Resending — this didn’t get any responses when I sent it a month ago.)

Swift 2.2 in Xcode 7.3.1.

Apparently you cannot use a named tuple constant as an expression pattern in a case label.

func test(x: Int, y: Int) -> Int {
let int_1 = 1
switch x {
case 0:
   return 0
case int_1:
   return 1
default:
   break
}

let int_1_1: (Int, Int) = (1, 1)
switch (x, y) {
case (0, 0):
   return 0
case int_1_1: // <<<<
   return 1
default:
   return -1
}
}

error: expression pattern of type '(Int, Int)' cannot match values of type '(Int, Int)'
case int_1_1:
    ^~~~~~~

The error message is particularly amusing.

  - Neil Faiman
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users