This page is no longer maintained — Please continue to the home page at www.scala-lang.org

abstract override and vals - a bug?

3 replies
Chris Marshall
Joined: 2009-06-17,
User offline. Last seen 44 weeks 3 days ago.
I was poking around using abstract override with vals (disclaimer: I haven't used stackable traits much), when I stumbled over what looks like unexpected behaviour (I won't go so far as to say it's a bug, as I'm far from sure I'm doing anything sensible):
Welcome to Scala version 2.9.1.final (Java HotSpot(TM) Server VM, Java 1.6.0_18).Type in expressions to have them evaluated.Type :help for more information.
scala> trait Fields { def fields: PartialFunction[Int, String] = Map.empty }defined trait Fields
scala> trait BasicFields extends Fields{ abstract override val fields = Map(3 -> "c") orElse super.fields }defined trait BasicFields
scala> trait EvenMoreFields extends Fields{ abstract override val fields = Map(2 -> "b") orElse super.fields }defined trait EvenMoreFields
scala> def test(f : Fields) = (1 to 5) map (f.fields isDefinedAt _)test: (f: Fields)scala.collection.immutable.IndexedSeq[Boolean]
scala> test(new BasicFields {})res0: scala.collection.immutable.IndexedSeq[Boolean] = Vector(false, false, true, false, false)

But...
scala> test(new BasicFields with EvenMoreFields {})java.lang.NullPointerException        at scala.PartialFunction$$anon$1.isDefinedAt(PartialFunction.scala:43)        at $anonfun$test$1.apply$mcZI$sp(<console>:8)        at $anonfun$test$1.apply(<console>:8)        at $anonfun$test$1.apply(<console>:8)        at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:194)        at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:194)        at scala.collection.immutable.Range.foreach(Range.scala:75)        at scala.collection.TraversableLike$class.map(TraversableLike.scala:194)        at scala.collection.immutable.Range.map(Range.scala:43)        at .test(<console>:8)        at .<init>(<console>:13)        at .<clinit>(<console>)        at .<init>(<console>:11)        at .<clinit>(<console>)        at $print(<console>)        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)        at java.lang.reflect.Method.invoke(Method.java:597)        at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:704)

If I change the definition of Basic and Extra fields such that they use "abstract override def" instead of "abstract override val" it works, but this means my program will cause an expensive map to be constructed on each call to fields.
is the NPE a bug? Should "abstract override val" work? if it shouldn't, why does it compile?
Chris
Arjan Blokzijl
Joined: 2009-10-31,
User offline. Last seen 46 weeks 5 days ago.
Re: abstract override and vals - a bug?
That one is explained on Paul's scala faq: https://github.com/paulp/scala-faq/wiki/Initialization-Order
Arjan

On 5 October 2011 17:52, Chris Marshall <oxbow_lakes [at] hotmail [dot] com> wrote:
I was poking around using abstract override with vals (disclaimer: I haven't used stackable traits much), when I stumbled over what looks like unexpected behaviour (I won't go so far as to say it's a bug, as I'm far from sure I'm doing anything sensible):
Welcome to Scala version 2.9.1.final (Java HotSpot(TM) Server VM, Java 1.6.0_18). Type in expressions to have them evaluated.Type :help for more information.
scala> trait Fields { def fields: PartialFunction[Int, String] = Map.empty }defined trait Fields
scala> trait BasicFields extends Fields{ abstract override val fields = Map(3 -> "c") orElse super.fields }defined trait BasicFields
scala> trait EvenMoreFields extends Fields{ abstract override val fields = Map(2 -> "b") orElse super.fields } defined trait EvenMoreFields
scala> def test(f : Fields) = (1 to 5) map (f.fields isDefinedAt _) test: (f: Fields)scala.collection.immutable.IndexedSeq[Boolean]
scala> test(new BasicFields {}) res0: scala.collection.immutable.IndexedSeq[Boolean] = Vector(false, false, true, false, false)

But...
scala> test(new BasicFields with EvenMoreFields {}) java.lang.NullPointerException        at scala.PartialFunction$$anon$1.isDefinedAt(PartialFunction.scala:43)         at $anonfun$test$1.apply$mcZI$sp(<console>:8)        at $anonfun$test$1.apply(<console>:8)         at $anonfun$test$1.apply(<console>:8)        at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:194)         at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:194)        at scala.collection.immutable.Range.foreach(Range.scala:75)         at scala.collection.TraversableLike$class.map(TraversableLike.scala:194)        at scala.collection.immutable.Range.map(Range.scala:43)         at .test(<console>:8)        at .<init>(<console>:13)        at .<clinit>(<console>)         at .<init>(<console>:11)        at .<clinit>(<console>)        at $print(<console>)         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)         at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)        at java.lang.reflect.Method.invoke(Method.java:597)         at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:704)

If I change the definition of Basic and Extra fields such that they use "abstract override def" instead of "abstract override val" it works, but this means my program will cause an expensive map to be constructed on each call to fields.
is the NPE a bug? Should "abstract override val" work? if it shouldn't, why does it compile?
Chris

Chris Marshall
Joined: 2009-06-17,
User offline. Last seen 44 weeks 3 days ago.
RE: abstract override and vals - a bug?
Looks like using "lazy val" instead of val (Paul's suggestion: it's not exactly the same issue) causes stack overflow. I say: why does it even compile if it doesn't actually work?
Chris

Date: Wed, 5 Oct 2011 19:25:28 +0200
Subject: Re: [scala-user] abstract override and vals - a bug?
From: arjanblokzijl [at] gmail [dot] com
To: oxbow_lakes [at] hotmail [dot] com
CC: scala-user [at] googlegroups [dot] com

That one is explained on Paul's scala faq: https://github.com/paulp/scala-faq/wiki/Initialization-Order
Arjan

On 5 October 2011 17:52, Chris Marshall <oxbow_lakes [at] hotmail [dot] com> wrote:
I was poking around using abstract override with vals (disclaimer: I haven't used stackable traits much), when I stumbled over what looks like unexpected behaviour (I won't go so far as to say it's a bug, as I'm far from sure I'm doing anything sensible):
Welcome to Scala version 2.9.1.final (Java HotSpot(TM) Server VM, Java 1.6.0_18). Type in expressions to have them evaluated.Type :help for more information.
scala> trait Fields { def fields: PartialFunction[Int, String] = Map.empty }defined trait Fields
scala> trait BasicFields extends Fields{ abstract override val fields = Map(3 -> "c") orElse super.fields }defined trait BasicFields
scala> trait EvenMoreFields extends Fields{ abstract override val fields = Map(2 -> "b") orElse super.fields } defined trait EvenMoreFields
scala> def test(f : Fields) = (1 to 5) map (f.fields isDefinedAt _) test: (f: Fields)scala.collection.immutable.IndexedSeq[Boolean]
scala> test(new BasicFields {}) res0: scala.collection.immutable.IndexedSeq[Boolean] = Vector(false, false, true, false, false)

But...
scala> test(new BasicFields with EvenMoreFields {}) java.lang.NullPointerException        at scala.PartialFunction$$anon$1.isDefinedAt(PartialFunction.scala:43)         at $anonfun$test$1.apply$mcZI$sp(<console>:8)        at $anonfun$test$1.apply(<console>:8)         at $anonfun$test$1.apply(<console>:8)        at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:194)         at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:194)        at scala.collection.immutable.Range.foreach(Range.scala:75)         at scala.collection.TraversableLike$class.map(TraversableLike.scala:194)        at scala.collection.immutable.Range.map(Range.scala:43)         at .test(<console>:8)        at .<init>(<console>:13)        at .<clinit>(<console>)         at .<init>(<console>:11)        at .<clinit>(<console>)        at $print(<console>)         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)         at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)        at java.lang.reflect.Method.invoke(Method.java:597)         at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:704)

If I change the definition of Basic and Extra fields such that they use "abstract override def" instead of "abstract override val" it works, but this means my program will cause an expensive map to be constructed on each call to fields.
is the NPE a bug? Should "abstract override val" work? if it shouldn't, why does it compile?
Chris

Arjan Blokzijl
Joined: 2009-10-31,
User offline. Last seen 46 weeks 5 days ago.
Re: abstract override and vals - a bug?
The initialization order follows the same principle as the order in Java (i.e. base-class first, and then further down the inheritance line). I guess the compiler doesn't complain here because is not so easy statically check all the cases. I was a bit surprised by the stackoverflow when you use lazy vals in your example, but I found one issue where this also happens for an even simpler case: https://issues.scala-lang.org/browse/SI-3253 Iulian's comment on this issue was that static checking of initialization is still being researched.
Arjan


On 5 October 2011 19:41, Chris Marshall <oxbow_lakes [at] hotmail [dot] com> wrote:
Looks like using "lazy val" instead of val (Paul's suggestion: it's not exactly the same issue) causes stack overflow. I say: why does it even compile if it doesn't actually work?
Chris

Date: Wed, 5 Oct 2011 19:25:28 +0200
Subject: Re: [scala-user] abstract override and vals - a bug?
From: arjanblokzijl [at] gmail [dot] com
To: oxbow_lakes [at] hotmail [dot] com
CC: scala-user [at] googlegroups [dot] com

That one is explained on Paul's scala faq: https://github.com/paulp/scala-faq/wiki/Initialization-Order
Arjan

On 5 October 2011 17:52, Chris Marshall <oxbow_lakes [at] hotmail [dot] com> wrote:
I was poking around using abstract override with vals (disclaimer: I haven't used stackable traits much), when I stumbled over what looks like unexpected behaviour (I won't go so far as to say it's a bug, as I'm far from sure I'm doing anything sensible):
Welcome to Scala version 2.9.1.final (Java HotSpot(TM) Server VM, Java 1.6.0_18). Type in expressions to have them evaluated.Type :help for more information.
scala> trait Fields { def fields: PartialFunction[Int, String] = Map.empty }defined trait Fields
scala> trait BasicFields extends Fields{ abstract override val fields = Map(3 -> "c") orElse super.fields }defined trait BasicFields
scala> trait EvenMoreFields extends Fields{ abstract override val fields = Map(2 -> "b") orElse super.fields } defined trait EvenMoreFields
scala> def test(f : Fields) = (1 to 5) map (f.fields isDefinedAt _) test: (f: Fields)scala.collection.immutable.IndexedSeq[Boolean]
scala> test(new BasicFields {}) res0: scala.collection.immutable.IndexedSeq[Boolean] = Vector(false, false, true, false, false)

But...
scala> test(new BasicFields with EvenMoreFields {}) java.lang.NullPointerException        at scala.PartialFunction$$anon$1.isDefinedAt(PartialFunction.scala:43)         at $anonfun$test$1.apply$mcZI$sp(<console>:8)        at $anonfun$test$1.apply(<console>:8)         at $anonfun$test$1.apply(<console>:8)        at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:194)         at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:194)        at scala.collection.immutable.Range.foreach(Range.scala:75)         at scala.collection.TraversableLike$class.map(TraversableLike.scala:194)        at scala.collection.immutable.Range.map(Range.scala:43)         at .test(<console>:8)        at .<init>(<console>:13)        at .<clinit>(<console>)         at .<init>(<console>:11)        at .<clinit>(<console>)        at $print(<console>)         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)         at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)        at java.lang.reflect.Method.invoke(Method.java:597)         at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:704)

If I change the definition of Basic and Extra fields such that they use "abstract override def" instead of "abstract override val" it works, but this means my program will cause an expensive map to be constructed on each call to fields.
is the NPE a bug? Should "abstract override val" work? if it shouldn't, why does it compile?
Chris


Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland