NullPointerException on pattern matching

1,309 views
Skip to first unread message

Stefano Di Martino

unread,
Aug 8, 2014, 6:33:18 AM8/8/14
to scala-l...@googlegroups.com
Hi,
I thought that pattern matching with null should work, but it doesn't. The following code ist copied from a book:

  val sdLst = List("10.12.95", null, "", "01.04.97", "1.4.97")

  for (sd <- sdLst; DMY(optYear) = sd; y <- optYear)
    yield y 

object DMY {
  val df = """(\d\d)\.(\d\d)\.(\d\d)""".r

  def unapply(s: String) = s match {
    case df(d, m, y) => Some(Some(d.toInt, m.toInt, y.toInt))
    case _ => Some(None)
  }
}


I get following error:

> java.lang.NullPointerException
//| at java.util.regex.Matcher.getTextLength(Matcher.java:1234)
//| at java.util.regex.Matcher.reset(Matcher.java:308)
//| at java.util.regex.Matcher.<init>(Matcher.java:228)
//| at java.util.regex.Pattern.matcher(Pattern.java:1088)
//| at scala.util.matching.Regex.unapplySeq(Regex.scala:206)
//| at DMY$.unapply(TupelAssingingPatternMatching.scala:42)
//| at TupelAssingingPatternMatching$$anonfun$main$1$$anonfun$1.apply(TupelA
//| ssingingPatternMatching.scala:28)
//| at TupelAssingingPatternMatching$$anonfun$main$1$$anonfun$1.apply(TupelA
//| ssingingPatternMatching.scala:28)
//| at scala.collection.immutable.List.map(List.scala:276)
//| at TupelAssingingPatternMatching$$anonfun$main$1.apply$mcV$sp(TupelAssin
//| gingPatternMatching.scala:28)
//| at org.scalaide.worksheet.runtime.library.WorksheetSupport$$anonfun$$exe
//| cute$1.apply$mcV$sp(WorksheetSupport.scala:76)
//| at org.scalaide.worksheet.runtime.library.WorksheetSupport$.redirec
//| Output exceeds cutoff limit.

Any ideas?

Best regards,
Stefano

Oliver Ruebenacker

unread,
Aug 8, 2014, 9:32:40 AM8/8/14
to scala-l...@googlegroups.com

     Hello,

  For calls flatMap on each element, and you can't call methods on null.

     Best,
     Oliver


--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-languag...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Oliver Ruebenacker
Be always grateful, but never satisfied.

√iktor Ҡlang

unread,
Aug 8, 2014, 9:39:53 AM8/8/14
to scala-l...@googlegroups.com
Like this?

object DMY {
  val df = """(\d\d)\.(\d\d)\.(\d\d)""".r

  def unapply(s: String) = s match {
    case null => Some(None)
    case df(d, m, y) => Some(Some(d.toInt, m.toInt, y.toInt))
    case _ => Some(None)
  }
}

  val sdLst = List("10.12.95", null, "", "01.04.97", "1.4.97")
  for (sd <- sdLst; DMY(optYear) = sd; y <- optYear)
    yield y 

res0: List[(Int, Int, Int)] = List((10,12,95), (1,4,97))

Cheers,

Oliver Ruebenacker

unread,
Aug 8, 2014, 9:40:09 AM8/8/14
to scala-l...@googlegroups.com

     Hello,

  I wait, no, I'm wrong, flatMap is called on the collections, not the elements.

     Best,
     Oliver

Peter Salanki

unread,
Aug 8, 2014, 9:43:47 AM8/8/14
to scala-l...@googlegroups.com



On Aug 8, 2014, at 09:32, Oliver Ruebenacker <cur...@gmail.com> wrote:


     Hello,

  For calls flatMap on each element, and you can't call methods on null.
That is not what causes the NPE here however.

DMY(optYear) = sd
Will run DMY.unapply with null as a value, just as it should. And then the regex matcher will barf.

Two ways to get rid of the null values are:

  for (sd <- sdLst if sd != null; DMY(optYear) = sd; y <- optYear)
    yield y 

Or

 val sdLst = List(Option("10.12.95"), Option(null), Option(""), Option("01.04.97)", Option("1.4.97"))

  for (sdO <- sdLst; sd <- sdO; DMY(optYear) = sd; y <- optYear)
    yield y 

Simon Schäfer

unread,
Aug 8, 2014, 9:51:41 AM8/8/14
to scala-l...@googlegroups.com

On 08/08/2014 12:33 PM, Stefano Di Martino wrote:
> Hi,
> I thought that pattern matching with null should work, but it doesn't.
> The following code ist copied from a book:
That is a bug in Regex.unapplySeq. It calls a Java API which doesn't
handle null correctly. Therefore, the unapplySeq should handle the null
case. Please open a ticket.

Som Snytt

unread,
Aug 8, 2014, 11:49:38 AM8/8/14
to scala-l...@googlegroups.com
What do you know, there's actually a related ticket.

https://issues.scala-lang.org/browse/SI-4364

I was curious if unapplies everywhere are required to do this.

scala> null match { case util.control.NonFatal(x) => true }
res1: Boolean = true



--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-language+unsubscribe@googlegroups.com.

Stefano Di Martino

unread,
Aug 8, 2014, 12:12:34 PM8/8/14
to scala-l...@googlegroups.com

Som Snytt

unread,
Aug 8, 2014, 1:25:46 PM8/8/14
to scala-l...@googlegroups.com
I think you have more tickets to make.  (Besides null not being a NonFatal exception.)

scala> 'apm match { case Symbol(x) => x }
res0: String = apm

scala> null match { case Symbol(x) => x }
java.lang.NullPointerException
  at scala.Symbol$.keyFromValue(Symbol.scala:37)
  at scala.Symbol$.keyFromValue(Symbol.scala:34)
  at scala.UniquenessCache.unapply(Symbol.scala:89)
  ... 33 elided

That is, if this is the desired behavior, for extractors to be null-friendly.

Stefano Di Martino

unread,
Aug 8, 2014, 1:33:19 PM8/8/14
to scala-l...@googlegroups.com
Please report yourself. You found this bug. :-)
To unsubscribe from this group and stop receiving emails from it, send an email to scala-languag...@googlegroups.com.

Simon Schäfer

unread,
Aug 8, 2014, 4:22:46 PM8/8/14
to scala-l...@googlegroups.com

On 08/08/2014 07:25 PM, Som Snytt wrote:
I think you have more tickets to make.  (Besides null not being a NonFatal exception.)

scala> 'apm match { case Symbol(x) => x }
res0: String = apm

scala> null match { case Symbol(x) => x }
java.lang.NullPointerException
  at scala.Symbol$.keyFromValue(Symbol.scala:37)
  at scala.Symbol$.keyFromValue(Symbol.scala:34)
  at scala.UniquenessCache.unapply(Symbol.scala:89)
  ... 33 elided

That is, if this is the desired behavior, for extractors to be null-friendly.
Yes, making an extractor safe for null is not an easy task. One could change the spec insofar that it says that extractors are not called when the input is null, then it would be the part of the compiler to ensure that the NPE don't occur.

On the other side it is a lot of work. Just not using null and wrapping all calls to Java methods in Option is easier to achieve in general.



On Fri, Aug 8, 2014 at 8:49 AM, Som Snytt <som....@gmail.com> wrote:
What do you know, there's actually a related ticket.

https://issues.scala-lang.org/browse/SI-4364

I was curious if unapplies everywhere are required to do this.

scala> null match { case util.control.NonFatal(x) => true }
res1: Boolean = true

On Fri, Aug 8, 2014 at 6:51 AM, Simon Schäfer <ma...@antoras.de> wrote:

On 08/08/2014 12:33 PM, Stefano Di Martino wrote:
Hi,
I thought that pattern matching with null should work, but it doesn't. The following code ist copied from a book:
That is a bug in Regex.unapplySeq. It calls a Java API which doesn't handle null correctly. Therefore, the unapplySeq should handle the null case. Please open a ticket.


--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-languag...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-languag...@googlegroups.com.

Ryan Hendrickson

unread,
Aug 8, 2014, 4:40:11 PM8/8/14
to scala-l...@googlegroups.com
> I think you have more tickets to make. (Besides null not being
> a NonFatal exception.)
>
> scala> 'apm match { case Symbol(x) => x }
> res0: String = apm
>
> scala> null match { case Symbol(x) => x }
> java.lang.NullPointerException
> at scala.Symbol$.keyFromValue(Symbol.scala:37)
> at scala.Symbol$.keyFromValue(Symbol.scala:34)
> at scala.UniquenessCache.unapply(Symbol.scala:89)
> ... 33 elided
>
>
> That is, if this is the desired behavior, for extractors to be
> null-friendly.
>
>
> Yes, making an extractor safe for null is not an easy task. One could
> change the spec insofar that it says that extractors are not called when
> the input is null, then it would be the part of the compiler to ensure
> that the NPE don't occur.
>
> On the other side it is a lot of work. Just not using null and wrapping
> all calls to Java methods in Option is easier to achieve in general.

Oh, but the situation is even more delightful than it at first appears:

scala> (null: Any) match { case Symbol(x) => x }
scala.MatchError: null
... 32 elided

So it would appear that the compiler is doing some work to this effect already; it's just inconsistent about it. MatchError or NullPointerException, whichever is ‘desired’; please tell me that a type ascription ought not to change the Throwable thrown.






(please forgive me my corporate legal disclaimer)

----------------------------------------

This message is intended exclusively for the individual(s) or entity to
which it is addressed. It may contain information that is proprietary,
privileged or confidential or otherwise legally exempt from disclosure.
If you are not the named addressee, you are not authorized to read,
print, retain, copy or disseminate this message or any part of it.
If you have received this message in error, please notify the sender
immediately by e-mail and delete all copies of the message.

Som Snytt

unread,
Aug 8, 2014, 6:19:14 PM8/8/14
to scala-l...@googlegroups.com
The behavior of matching on (null: Any) changes depending on the signature of the unapply method.

I'm embarrassed to point this out:

scala> val r = """\d+""".r
r: scala.util.matching.Regex = \d+

scala> (null: Any) match { case r(_*) => true }
warning: there was one deprecation warning; re-run with -deprecation for details
scala.MatchError: null
  ... 33 elided


That's using the deprecated unapply.  Hey, it's a workaround!  If you want nulls, you have give up type safety on the match.

I'm not entirely persuaded yet either way; it seems easy to put a null case first if you care about it.

OTOH, you don't want NPEs putting off people who are dipping their toe in the water because they heard how much fun regexes are in Scala.



Andrew Phillips

unread,
Aug 8, 2014, 6:29:19 PM8/8/14
to scala-l...@googlegroups.com, ryan.hen...@bwater.com
> So it would appear that the compiler is doing some work to this effect already; it's just inconsistent about it. MatchError or
> NullPointerException, whichever is ‘desired’; please tell me that a type ascription ought not to change the Throwable thrown. 

At the risk of stating the obvious, this works without a type ascription, too (2.11.1 REPL):

scala> val n: Object = null
n: Object = null

scala> n match { case Symbol(x) => x }
scala.MatchError: null
  ... 32 elided

It seems as though the compiler is inserting an n.isInstanceOf[Symbol]() check whenever the types don't allow either a direct assignment or a compile-time "error: scrutinee is incompatible with pattern type" rejection.

ap

Reply all
Reply to author
Forward
0 new messages