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

Arity-1 name-based extractors should work like arity 2+ #9836

Closed
scabug opened this issue Jun 28, 2016 · 9 comments
Closed

Arity-1 name-based extractors should work like arity 2+ #9836

scabug opened this issue Jun 28, 2016 · 9 comments

Comments

@scabug
Copy link

scabug commented Jun 28, 2016

Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_102).
Type in expressions for evaluation. Or try :help.

scala> :pa
// Entering paste mode (ctrl-D to finish)

final class Foo1(a: Int) {
  def isEmpty = false
  def get     = this
  def _1      = a
}
object Foo1 { def unapply(x: Foo1) = x }

final class Foo2(a: Int, b: Int) {
  def isEmpty = false
  def get     = this
  def _1      = a
  def _2      = b
}
object Foo2 { def unapply(x: Foo2) = x }


// Exiting paste mode, now interpreting.

defined class Foo1
defined object Foo1
defined class Foo2
defined object Foo2

scala> new Foo1(1) match { case Foo1(a) => Array(a) }
res0: Array[Foo1] = Array(Foo1@6340e5f0)

scala> new Foo2(1, 2) match { case Foo2(a, b) => Array(a, b) }
res1: Array[Int] = Array(1, 2)

For clarity, I expected res0 to be Array[Int] not Array[Foo1].

I believe this is as specced, but I submit as counter-proof that @adriaanm expected it to work as well: "Looks like it doesn't work for Product1":

https://issues.scala-lang.org/browse/SI-8989?focusedCommentId=71182

@scabug
Copy link
Author

scabug commented Jun 28, 2016

Imported From: https://issues.scala-lang.org/browse/SI-9836?orig=1
Reporter: @dwijnand
Affected Versions: 2.11.8
See #6675, #6111

@scabug
Copy link
Author

scabug commented Jun 28, 2016

@som-snytt said:
Maybe res0 should be (1). If you want 1, define get appropriately.

@scabug
Copy link
Author

scabug commented Jun 28, 2016

@dwijnand said:
Why? res1 isn't ((1), (a))

@scabug
Copy link
Author

scabug commented Jun 28, 2016

@som-snytt said:
res1 is a tuple, so res0 should be a tuple, too. Probably I expect to iterate over the Product elements.

Uniformity was discussed in comments to #7897

It's inconvenient to special-case Product1 just because n == 1.

@scabug
Copy link
Author

scabug commented Jun 28, 2016

@dwijnand said:
I changed the examples to use array, so we don't get all hung-up on confusing the arity of the extractor with the arity of the return type.

It returns Array(Bippy(1)) when it should return Array(1).

@scabug
Copy link
Author

scabug commented Oct 12, 2016

@dwijnand said:
Simplified the test case to Foo1(a: Int) and Foo2(a: Int, b: Int).

res0 is an Array[Foo1] where I expected it to be an Array[Int].

@scabug scabug added this to the Backlog milestone Apr 7, 2017
@adriaanm adriaanm removed their assignment Sep 28, 2018
@dwijnand
Copy link
Member

Tested on Dotty and the same problem exists there: https://scastie.scala-lang.org/kVbcuVRFQ7ScUjx5VehItA.

@som-snytt
Copy link

I started looking at this and the linked tickets about so-called "auto-tupling in patterns".

I think the first example below is perfectly fine and should not warn (as it currently does). I almost had a fix last week, but ExtractorAlignment sees the tree in typer and the different tree in patmat. The test is simply that the subpattern consumes the required tuple.

The code is commented "don't unwrap Tuple1", but maybe there is a useful cue for whether to unwrap, for example, Product1, or detect get = this to avoid self-extraction. I encountered the asymmetry in a macro once, where it was inconvenient to generate the special case.

object X { def unapply(s: String): Option[(Int,Int)] = { val Array(a,b) = s.split("/") ; Some((a.toInt,b.toInt)) }}
object T { def unapply(t: (Int,Int)) = Option(t._1+t._2) }

trait Test {
  "1/2" match { case X(T(x)) => x }

  "1/3" match { case X(x @ (_, _)) => x }

  "1/4" match { case X(x) => x }
}

@dwijnand
Copy link
Member

dwijnand commented Jun 7, 2022

Studying scala/scala3#15230 I realised why it's important that you can bind the result of the get in the arity-1 case.

@dwijnand dwijnand closed this as completed Jun 7, 2022
@SethTisue SethTisue removed this from the Backlog milestone Jun 7, 2022
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

5 participants