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

Allow pattern matching on type in for comprehensions #900

Open
scabug opened this issue May 13, 2008 · 17 comments
Open

Allow pattern matching on type in for comprehensions #900

scabug opened this issue May 13, 2008 · 17 comments
Labels
enhancement fixed in Scala 3 This issue does not exist in the Scala 3 compiler (https://github.com/lampepfl/dotty/) patmat typelevel
Milestone

Comments

@scabug
Copy link

scabug commented May 13, 2008

It would be nice if pattern matches on type worked inside for comprehensions:

scala> for (Some(x) <- List(None, Some(1))) yield x
res4: List[Int] = List(1)

scala> for (x : Some[_] <- List(None, Some(1))) yield x
<console>:5: error: type mismatch;
 found   : (Some[_]) => Some[Any]
 required: (Option[Int]) => ?
       for (x : Some[_] <- List(None, Some(1))) yield x
            ^
scala> Some(1) match { case x : Some[_] => x }
res7: Some[Any] = Some(1)

I'd like the middle one to be a pattern match on type, so instead of a type error it would give List(Some(1)).

@scabug
Copy link
Author

scabug commented May 13, 2008

Imported From: https://issues.scala-lang.org/browse/SI-900?orig=1
Reporter: @DRMacIver

@scabug
Copy link
Author

scabug commented Feb 14, 2009

@paulp said:
See also #1089 and #1673, which are basically duplicates of this ticket but might add a little flavor.

@scabug
Copy link
Author

scabug commented Nov 9, 2009

@odersky said:
Note that this is in a sense the opposite of #140.

@scabug
Copy link
Author

scabug commented Jan 13, 2010

@dcsobral said:
To me, this is an exception to the rule, which is something that really doesn't fit Scala. However it works implementation-wise, I'm guided by a simple rule:

Pattern match works on val assignments, for-comprehensions and case statements.

Only there's an exception on for-comprehensions. Worse still, not an exception of an edge case no one is likely to use, or which would be hard to read, but an exception preventing an useful behavior. Right now, one can't express something like "for all ints in this list" in a direct way.

@scabug
Copy link
Author

scabug commented Aug 10, 2010

@retronym said:
I've been using this workaround:

scala> val xs = Seq(Some(1), None)             
xs: Seq[Option[Int]] = List(Some(1), None)

scala> for { x @ (_x : Some[_]) <- xs } yield x
res0: Seq[Some[Any]] = List(Some(1))

Unfortunately _ can't be used in place of x or _x.

@scabug
Copy link
Author

scabug commented Dec 8, 2010

@milessabin said:
@retronym's workaround is good for the match forms in #1089 and #1673 too, ie. the following compiles and evaluates as expected,

scala> val l = List(1, "foo", null)
l: List[Any] = List(1, foo, null)

scala> for (s @ (_x : String) <- l) yield s
res0: List[String] = List(foo)

@scabug
Copy link
Author

scabug commented Feb 10, 2011

Erik Bruchez (ebruchez) said:
I just asked a question related to this on StackOverflow and Daniel pointed to this ticket. See: http://stackoverflow.com/questions/4952124/why-is-there-a-difference-in-behavior-between-these-two-pattern-matches-in-a-for

The current behavior is really confusing and it would be great if it could be fixed.

@scabug
Copy link
Author

scabug commented Aug 6, 2011

@SethTisue said:
man. it would be super great if this somehow got addressed in 2.10.

I'm not saying I know what the right thing to do is, because I don't.

does anyone understand why, in Jason's workaround, _ can't be used in place of x or _x? if that weren't true, Jason's thing would be, like, allllllllmost something I could put up with. but if I am forced to supply a variable name I don't use, well, for me that pushes it over the line from "ok maybe" to "sad".

@scabug
Copy link
Author

scabug commented Jun 24, 2012

@retronym said:
A perhaps more intention revealing version of the workaround:

scala> object Typed { def unapply[A](a: A) = Some(a) }
defined module Typed

scala> for { Typed(a: Int) <- List(1, "2") } yield a
res1: List[Int] = List(1)

@scabug
Copy link
Author

scabug commented Jul 9, 2012

Piotr Czapla (pczapla) said:
I"ve just got bitten by this. Your book does not seems to mention about this problem either. And there is almost no info on the net about this. Fortunately folks at SO helped me: http://stackoverflow.com/questions/11394034/why-scalas-pattern-maching-does-not-work-in-for-loops-for-type-matching

Anyway +1 to fix this.

@scabug
Copy link
Author

scabug commented Jun 1, 2013

Ben Challenor (bchallenor) said:
Another +1 for this fix. Thanks.

@scabug
Copy link
Author

scabug commented Jun 13, 2013

Max Bolingbroke (batterseapower) said:
This is rather surprising behavior and seems to contradict the spec. It would be great if this could be fixed.

@scabug
Copy link
Author

scabug commented Jan 29, 2014

@densh said (edited on Jan 30, 2014 10:35:04 AM UTC):
Fix densh/scala@afd03a1

@scabug
Copy link
Author

scabug commented Feb 6, 2014

@densh said:
After discussion today the conclusion was that this behavior will not change in 2.11 but should be discussed again in 2.12 cycle.

@scabug
Copy link
Author

scabug commented Jul 22, 2016

@milessabin said:
It'd be great if we could revive this one for 2.12.x.

@scala scala deleted a comment from scabug Feb 17, 2018
@som-snytt
Copy link

An improvement that allows underscores in the workaround, the gist of which is to change the pattern from simple name or typed name such as in an ordinary val def.

The workaround also gibes with case x @ _ => to escape unused patvar warning.

scala> for (x @ (_: Some[_]) <- List(Some(42))) yield x
res0: List[Some[Any]] = List(Some(42))

scala> for (_ @ (_: Some[_]) <- List(Some(42))) yield 17
res1: List[Int] = List(17)

scala/scala#7525

@SethTisue SethTisue added the fixed in Scala 3 This issue does not exist in the Scala 3 compiler (https://github.com/lampepfl/dotty/) label Oct 31, 2020
@SethTisue
Copy link
Member

SethTisue commented Oct 31, 2020

in Dotty you just throw in case, and Bob's your uncle:

scala> for (case x : Some[_] <- List(None, Some(1))) yield x                                                        
val res1: List[Some[_]] = List(Some(1))

a simpler example:

scala> for (x: String <- List(1, "foo")) yield x
1 |for (x: String <- List(1, "foo")) yield x
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |     Found:    String => String
  |     Required: Any => String

scala> for (case x: String <- List(1, "foo")) yield x                                                               
val res2: List[String] = List(foo)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement fixed in Scala 3 This issue does not exist in the Scala 3 compiler (https://github.com/lampepfl/dotty/) patmat typelevel
Projects
None yet
Development

No branches or pull requests

5 participants