Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extractors can't provide Tuples as a single parameter in a match #6111

Closed
scabug opened this issue Jul 20, 2012 · 5 comments
Closed

Extractors can't provide Tuples as a single parameter in a match #6111

scabug opened this issue Jul 20, 2012 · 5 comments
Assignees
Milestone

Comments

@scabug
Copy link

scabug commented Jul 20, 2012

There seems to be an issue when using a generic extractor and which could receive a tuple type. As soon as the generic type parameter in the result type is instantiated with a tuple type, the pattern matcher interprets it as multiple parameters in a match.

object Foo {
  def unapply[S, T](scrutinee: S)(implicit witness: FooHasType[S, T]): Option[T] = scrutinee match {
    case i: Int => Some((i, i).asInstanceOf[T])
  }
}

class FooHasType[S, T]
object FooHasType {
  implicit object int extends FooHasType[Int, (Int, Int)]
}

object Test {
  val x = 8
  x match {
    case Foo(p) => p // p should be a pair of Int
  }
}

This should compile. However, it instead results in the following error:

<console>:21: error: wrong number of arguments for object Foo
           case Foo(p) => p // p should be a pair of Int
                   ^
<console>:21: error: not found: value p
           case Foo(p) => p // p should be a pair of Int
                          ^

The work-around to use the FooHasType implicit to force T to be Any in the case where it would otherwise be a tuple does not completely solve the issue because then the type info for the components of the tuple gets lost.

So, the bottom line: it seems this bug makes it impossible to provide a representation-independent extractor for types such as Try.

@scabug
Copy link
Author

scabug commented Jul 20, 2012

Imported From: https://issues.scala-lang.org/browse/SI-6111?orig=1
Reporter: @heathermiller
Affected Versions: 2.10.0

@scabug
Copy link
Author

scabug commented Jul 20, 2012

@adriaanm said:
More generally, even though we can write a case class with one tuple-valued argument,
we can't express the corresponding extractor.

This finally gives us a use case for Product1:

scala> case class Holder[T](_1: T) extends Product1[T]
defined class Holder

scala> object Foo { def unapply(x: Any): Some[Holder[(Int, Int)]] = Some(Holder((1, 2))) }
defined module Foo

scala> 1 match { case Foo(t) => t }
res0: Holder[(Int, Int)] = Holder((1,2))
// expected (1, 2) as result type, by analogy to the Product2 extractor:

scala> object Foo { def unapply(x: Any): Some[((Int, Int), Any)] = Some(((1, 2), "foo")) }
defined module Foo

scala> 1 match { case Foo(t, _) => t }
res1: (Int, Int) = (1,2)

The spec has to be changed, since now it says (specialized to the case for n = 1)

An unapply method in an object x matches the pattern x(p1) if it takes exactly one argument and unapply’s result type is Option[T], for some type T.
In this case, the (only) argument pattern p1 is typed in turn with expected type T.
The extractor pattern matches then all values v for which x.unapply(v) yields a value of form Some(v1), and p1 matches v1.

@scabug
Copy link
Author

scabug commented Jul 20, 2012

@adriaanm said:
I'd propose the following spec change: allow Option[ProductN[...]] for any N >= 1, instead of N > 1
keep the N = 1 and Option[T] as a fallback if T is not a product type

@scabug
Copy link
Author

scabug commented Jul 23, 2012

@adriaanm said:
I was wrong: the spec already covers this case. Correcting implementation in doTypedUnapply

@scabug
Copy link
Author

scabug commented Jul 23, 2012

@adriaanm said:
scala/scala#979

@scabug scabug closed this as completed Jul 24, 2012
@scabug scabug added this to the 2.10.0-M5 milestone Apr 7, 2017
zimmermatt added a commit to zimmermatt/atlas that referenced this issue Sep 14, 2018
 `case extractor(extracted) => extracted`

yields

 ```
 Warning:(68, 16) class ValueExtractor expects 2 patterns to hold
 (String, String) but crushing into 2-tuple to fit single pattern
 (scala/bug#6675)
 ```

See
* scala/bug#6675
* scala/bug#6111
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants