Pattern match as boolean value

156 views
Skip to first unread message

Johannes Rudolph

unread,
Oct 14, 2011, 7:06:35 AM10/14/11
to scala-debate, Mathias
Hi,

there's a common use case to check if some value matches a pattern.

E.g. to check if a value is a one-element list of a particular value.
This is a bit awkward to achieve right now:

val x: List[Option[String]] = List(None) // ...
x match { case List(Some("Test")) => true case _ => false }

This is inefficient syntax-wise because you have to make the boolean
result explicit as true/false and add the default case. We think that
this may warrant the addition of a new bit of syntax which is
equivalent to the above but more succinct. As ubiquitous as patterns
are in Scala this would be a consequent way to access what is
implemented as `PartialFunction.isDefined` right now. It would be an
additional plus if you could use the short syntax as a predicate
requiring a value of `T => Boolean` similar to "Pattern Matching
Anonymous Functions" (SLS 8.5).

Here's a first syntax proposal:

Expand `x match y` into `x match { case y => true case _ => false }`.
For an equivalent to SLS 8.5 this little change would already include
the short form "_ match y" to make an anonymous function out of it.
Creating even shorter forms may be difficult to achieve because of the
similarity between expressions and patterns and the resulting possible
ambiguity in the parser which is currently solved by allowing patterns
only after certain keywords or in certain positions.

Here are some examples of what would be possible with this syntax addition:

val x: List[Option[String]] = //...
x match List(Some("Test"))

or

x.count(_ match Some("Test"))

or even

x.count(_ match Some("Test" | "test2"))

Unused features from patterns (and therefore perhaps confusing if
allowed at those positions) would be binding and guards.

If you want to play around with this syntax I attached a short patch
against trunk which implements this addition directly in the parser.
What do you think?

--
Johannes

-----------------------------------------------
Johannes Rudolph
http://virtual-void.net

short-matches.patch

Jason Zaugg

unread,
Oct 14, 2011, 7:34:22 AM10/14/11
to Johannes Rudolph, scala-debate, Mathias
On Fri, Oct 14, 2011 at 1:06 PM, Johannes Rudolph <johannes...@googlemail.com> wrote:
Here's a first syntax proposal:

Expand `x match y` into `x match { case y => true case _ => false }`.
For an equivalent to SLS 8.5 this little change would already include
the short form "_ match y" to make an anonymous function out of it.
Creating even shorter forms may be difficult to achieve because of the
similarity between expressions and patterns and the resulting possible
ambiguity in the parser which is currently solved by allowing patterns
only after certain keywords or in certain positions.

Here are some examples of what would be possible with this syntax addition:

val x: List[Option[String]] = //...
x match List(Some("Test"))

or

x.count(_ match Some("Test"))

or even

x.count(_ match Some("Test" | "test2"))

Unused features from patterns (and therefore perhaps confusing if
allowed at those positions) would be binding and guards.

If you want to play around with this syntax I attached a short patch
against trunk which implements this addition directly in the parser.
What do you think?

You can cut down a bit of the noise today with PartialFunction.cond

  scala> import PartialFunction.cond
  import PartialFunction.cond

  scala> if (cond(1) { case 2 => true }) {}

Or

  scala> def cond1[T](t: T)(pf: PartialFunction[T, Any]) = pf.isDefinedAt(t)
  cond1: [T](t: T)(pf: PartialFunction[T,Any])Boolean

  scala> if (cond1(1) { case 2 => }) {}

That said, I quite like the proposed syntax.

-jason
 

Alex Repain

unread,
Oct 14, 2011, 8:00:33 AM10/14/11
to Jason Zaugg, Johannes Rudolph, scala-debate, Mathias
I guess this thread would be a good fit for inaugurating the new mailing list, scala-sips ( see http://permalink.gmane.org/gmane.comp.lang.scala/24768 ).

2011/10/14 Jason Zaugg <jza...@gmail.com>



--
Alex REPAIN
ENSEIRB-MATMECA - student
TECHNICOLOR R&D - intern
BORDEAUX I      - master's student

SCALA           - enthusiast


Adriaan Moors

unread,
Oct 14, 2011, 10:29:46 AM10/14/11
to scala-debate
FWIW:

class Matches[T](x: T) {
  def matches(pf: PartialFunction[T, Any]) = pf isDefinedAt x
}

implicit def anyToMatches[T](x: T) = new Matches[T](x)

scala> val x: List[Option[String]] = List(None)

scala> x matches { case List(Some("Test")) =>  }
res0: Boolean = false

scala> x matches { case List(None) =>  }
res1: Boolean = true

Razvan Cojocaru

unread,
Oct 14, 2011, 12:42:14 PM10/14/11
to adriaa...@epfl.ch, scala-debate

This works as well – might need a bit more syntax for cases like case 1|2|3 but…

 

Try it now: http://bit.ly/mXSXZj

 

implicit def toKaKu (x:Any) = new KaKu(x)

class KaKu (val x:Any) {

    def matches[T] (what:T) = what == x

}

 

List(1,2,3) matches List(1,2,3)

List(1,2,3) matches Seq (1,2,3)

 

System.currentTimeMillis matches "nada"

 

Also – you can take a look at the matchers of scalatest and expect()…

 

Having said that, I also like the syntax proposed – would simplify a bunch of code and less to remember/import.

Lars Hupel

unread,
Oct 14, 2011, 1:06:40 PM10/14/11
to scala-...@googlegroups.com
+1

This would also enable match-based assertions, as discussed on the list
not long ago.

Jeff Olson

unread,
Oct 14, 2011, 1:52:14 PM10/14/11
to scala-...@googlegroups.com
+1

I've wanted this many times. I would love to see language support for it. I second the suggestion to post over on the new scala-sips [at] googlegroups.com list.

@Adriaan: That's a awesome trick. Thanks.

-Jeff

Harrison Klaperman

unread,
Oct 14, 2011, 2:28:54 PM10/14/11
to scala-...@googlegroups.com, Mathias
+1
I third the suggestion to move to scala-sips.  Johannes, it's your suggestion, so you should be the one to post, if you wish.  :)

I would add that the danger in this proposal is that beginning Scala programmers might try to use the following Kotlinesque gibberish:

if (x match P1)
  r1
else if (x match P2)
  r2
[...]
else
  r0

in place of:

x match {
  case P1 => r1
  case P2 => r2
  [...]
  case _ => r0
}

which is why I think this feature isn't already in the language.  It's a simple matter to fix this issue, however.  Just have the compiler emit a warning when it sees an if-else expression (yes, specifically one with an else branch) whose conditional is a match-test expression.  (We need a name to distinguish this match from the existing match statement as well, and a disambiguating name for the existing match.  Perhaps we could use x case P1 instead of x match P1 as the syntax for the proposed match-test expression; though this would have the disadvantage of not sounding right when read aloud.)

Johannes Rudolph

unread,
Oct 31, 2012, 5:10:01 AM10/31/12
to scala-debate
On Fri, Oct 14, 2011 at 1:06 PM, Johannes Rudolph
<johannes...@googlemail.com> wrote:
> Here are some examples of what would be possible with this syntax addition:
>
> val x: List[Option[String]] = //...
> x match List(Some("Test"))
>
> or
>
> x.count(_ match Some("Test"))

We finally put together a proposal for this feature.

See it here:

https://docs.google.com/document/d/1onPrzSqyDpHScc9PS_hpxJwa3FlPtthxw-bAuuEe8uA/edit#

Discussion on the sip mailing list:

https://groups.google.com/d/topic/scala-sips/zWB86iGVQcA/discussion
Reply all
Reply to author
Forward
0 new messages