NullPointerException for AbstractPartialFunction.orElse in 20110108 trunk (2.10)

33 views
Skip to first unread message

Trond Olsen

unread,
Jan 8, 2012, 10:57:11 AM1/8/12
to scala...@googlegroups.com
I'm trying out the latest trunk but had some problems running my code. The code segment react(messageMatcher orElse nomatchMatcher) generates NullPointerException:

trait Resumable {
  this: scala.actors.Actor =>

  protected val monitor: scala.actors.Actor with Monitoring
  protected val messageMatcher: PartialFunction[Any, Unit]

  private final val nomatchMatcher: PartialFunction[Any, Unit] = {
    case Resumable.Exit => exit()
    case msg            => monitor.nomatchHandlers.foreach(f => f(this, msg))
  }

  final def act() {
    link(monitor)
    loop {
      react(messageMatcher orElse nomatchMatcher)
    }
  }
}

with the following stack trace:

Caused by: java.lang.NullPointerException

    at scala.runtime.AbstractPartialFunction.orElse(AbstractPartialFunction.scala:41)
    at project.ActorUtil$Resumable$$anonfun$act$1.apply(ActorUtil.scala:34)
    at project.ActorUtil$Resumable$$anonfun$act$1.apply(ActorUtil.scala:34)

Anyone able to spot the problem?

The AbstractPartialFunction is a new optimization for 2.10:

override def orElse[A1 <: T1, B1 >: R](that: PartialFunction[A1, B1]) : PartialFunction[A1, B1] = {
  val result = this.clone.asInstanceOf[AbstractPartialFunction[A1, B1]]
  result.synchronized {
    result.fallBackField = this.fallBackField orElse that
    result
  }
}

√iktor Ҡlang

unread,
Jan 8, 2012, 11:12:01 AM1/8/12
to Trond Olsen, scala...@googlegroups.com
Where are you assinging:

protected val messageMatcher: PartialFunction[Any, Unit]

?
--
Viktor Klang

Akka Tech Lead
Typesafe - Enterprise-Grade Scala from the Experts

Twitter: @viktorklang

Trond Olsen

unread,
Jan 8, 2012, 12:00:03 PM1/8/12
to √iktor Ҡlang, scala...@googlegroups.com
In the classes that mixin the Resumable trait ala:

class A
  extends Some
  with Actor with Resumable {
    protected val messageMatcher: PartialFunction[Any, Unit] = {
        case msg =>
    }
}


2012/1/8 √iktor Ҡlang <viktor...@gmail.com>

Trond Olsen

unread,
Jan 8, 2012, 7:33:53 PM1/8/12
to √iktor Ҡlang, scala...@googlegroups.com
Changed nomatchMatcher and messageMatcher to defs but still same exception.

The highlighted line in AbstractPartialFunction is where the exception is thrown. I read the error as this.fallBackField somehow has not been set (null is its initial value). It is set in fallback, which in turn is only called from missingCase and isDefinedAt (conditionally).

abstract class AbstractPartialFunction[-T1, +R]
    extends AbstractFunction1[T1, R]
    with PartialFunction[T1, R]
    with Cloneable {

  private var fallBackField: PartialFunction[T1 @uncheckedVariance, R @uncheckedVariance] = _

  def fallBack: PartialFunction[T1, R] = synchronized {
    if (fallBackField == null) fallBackField = PartialFunction.empty
    fallBackField
  }

  override protected def missingCase(x: T1): R = fallBack(x)

  // Question: Need to ensure that fallBack is overwritten before any access
  // Is the `synchronized` here the right thing to achieve this?
  // Is there a cheaper way?

  override def orElse[A1 <: T1, B1 >: R](that: PartialFunction[A1, B1]) : PartialFunction[A1, B1] = {
    val result = this.clone.asInstanceOf[AbstractPartialFunction[A1, B1]]
    result.synchronized {
      result.fallBackField = this.fallBackField orElse that
      result
    }
  }

  def isDefinedAt(x: T1): scala.Boolean = _isDefinedAt(x) || fallBack.isDefinedAt(x)
  def _isDefinedAt(x: T1): scala.Boolean

}

2012/1/8 √iktor Ҡlang <viktor...@gmail.com>

Avoid using abstract vals unless you're very comfortable with initialization order. Either use abstract def or lazy val.

Cheers,
V

Tobias Stenzel

unread,
Jan 8, 2012, 8:01:38 PM1/8/12
to scala-user
I noticed the same problem some weeks ago and filed an issue here:

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


On Jan 9, 1:33 am, Trond Olsen <tr...@steinbit.org> wrote:
> Changed nomatchMatcher and messageMatcher to defs but still same exception.
>
> The highlighted line in AbstractPartialFunction is where the exception is
> thrown. I read the error as this.fallBackField somehow has not been set
> (null is its initial value). It is set in fallback, which in turn is only
> called from missingCase and isDefinedAt (conditionally).
>
> abstract class AbstractPartialFunction[-T1, +R]
>     extends AbstractFunction1[T1, R]
>     with PartialFunction[T1, R]
>     with Cloneable {
>
>   private var fallBackField: PartialFunction[T1 @uncheckedVariance, R
> @uncheckedVariance] = _
>
>   def fallBack: PartialFunction[T1, R] = synchronized {
>     if (fallBackField == null) fallBackField = PartialFunction.empty
>     fallBackField
>   }
>
>   override protected def missingCase(x: T1): R = fallBack(x)
>
>   // Question: Need to ensure that fallBack is overwritten before any access
>   // Is the `synchronized` here the right thing to achieve this?
>   // Is there a cheaper way?
>   override def orElse[A1 <: T1, B1 >: R](that: PartialFunction[A1, B1]) :
> PartialFunction[A1, B1] = {
>     val result = this.clone.asInstanceOf[AbstractPartialFunction[A1, B1]]
>     result.synchronized {
> *      result.fallBackField = this.fallBackField orElse that*
>       result
>     }
>   }
>
>   def isDefinedAt(x: T1): scala.Boolean = _isDefinedAt(x) ||
> fallBack.isDefinedAt(x)
>   def _isDefinedAt(x: T1): scala.Boolean
>
> }
>
> 2012/1/8 √iktor Ҡlang <viktor.kl...@gmail.com>
>
>
>
>
>
>
>
> > Avoid using abstract vals unless you're very comfortable with
> > initialization order. Either use abstract def or lazy val.
>
> > Cheers,
> > V
> > On Jan 8, 2012 6:00 PM, "Trond Olsen" <tr...@steinbit.org> wrote:
>
> >> In the classes that mixin the Resumable trait ala:
>
> >> class A
> >>   extends Some
> >>   with Actor with Resumable {
> >>     protected val messageMatcher: PartialFunction[Any, Unit] = {
> >>         case msg =>
> >>     }
> >> }
>
> >> 2012/1/8 √iktor Ҡlang <viktor.kl...@gmail.com>
> >>> Typesafe <http://www.typesafe.com/> - Enterprise-Grade Scala from the
> >>> Experts
>
> >>> Twitter: @viktorklang

Trond Olsen

unread,
Jan 9, 2012, 11:49:04 AM1/9/12
to Tobias Stenzel, scala-user
After extempore's quick patch my project now unfortunately has no more bugs to report. ;)
Reply all
Reply to author
Forward
0 new messages