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

spec for == and ##

9 replies
extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.

Here is a kind of off the top of my head attempt to spec out equality
and hash codes. I don't really speak spec-ese but this is written in
the pidgin spec-ese within my grasp. Does this look approximately
correct? (Anyone else feel free to chime in on that point.) What if
anything would you like me to do with it?

Resolution of x == y
====================

1) Null values will not cause NPEs.

2) Nothing is == to null except null.

3) All objects must be == to themselves.

The first three conditions are summarized in this initial expansion of 'x == y', which the compiler may or may not inline. All user-defined equals methods are responsible for preserving invariants 2 and 3.

if (x eq y) true
else if (x eq null) false
else // remainder of algorithm

4) If the static type of the left hand side allows for the possibility that it is a boxed or unboxed primitive numeric type (any of Byte, Short, Int, Long, Float, Double, or Char) then: go to step 5.

If the static type definitively excludes those types, then: the result is x.equals(y).

5) If the static types of both operands are primitive types, then: the result is that of the primitive comparison, exactly as performed in java.

If the static types are identical final types (for instance, both are java.lang.Longs) then the result is x.equals(y).

In all other cases, both operands are boxed if necessary and a method in BoxesRunTime is called. (The method will be semantically equivalent to BoxesRunTime.equals, but a different method may be chosen to avoid repeating the above tests.)

BoxesRuntime.equals
===================

All of the preceding logic is preserved, and then it proceeds as follows, where 'x' remains the left hand side operand and 'y' the right.

1) Runtime instance checks will be done to determine the types of the operands, with the following resolutions. (Resolutions represent the semantics, not necessarily the implementation.)

1a) If both sides of the comparison are boxed primitives, then they are unboxed and the primitive comparison is performed as in java.

1b) If 'x' is a class implementing the scala.math.ScalaNumber trait, then the result is x.equals(y).

1c) If 'x' is a boxed primitive and 'y' is a class implementing the scala.math.ScalaNumber trait, then the result is y.equals(x).

1d) Otherwise, the result is x.equals(y).

hashCode and ##
===============

The unification of primitives and boxed types in scala necessitates measures to preserve the equality contract: equal objects must have equal hash codes. To accomplish this a new method is introduced on Any:

def ##: Int

This method should be called in preference to hashCode by all scala software which consumes hashCodes. (One need not use or even be aware of it unless implementing something which depends on hashCodes -- to define an object's hashCode, overridding hashCode remains the mechanism.)

The default implementation of ## is simply to call hashCode:

def ##: Int = this.hashCode()

In the case of numeric types however, it selectively alters hash codes to support the == algorithm given above. The guarantees provided by ## are as follows. "Numbers" are the aforementioned primitives (boxed or unboxed) and any standard scala library class implementing ScalaNumber.

1) If x and y are whole Numbers in the range Int.MinValue to Int.MaxValue, then (x == y) implies (x.## == y.##). The value of ## for all Numbers in that range is equal to the result of .toInt on that Number.

2) If x and y are Numbers and either or both is fractional, then the guarantee in 1) applies if both are in the range Short.MinValue to Short.MaxValue.

3) If x and y are Numbers and neither 1) nor 2) applies, the implication is preserved on a best-effort basis, but cannot be preserved generally given the fuzziness introduced in primitive equality at the borders. (For instance given a large Float, a java primitive Float/Double comparison may return true for 2^10 different Double values, and similar issues arise with Longs and Doubles.)

Archontophoenix
Joined: 2010-02-04,
User offline. Last seen 2 years 35 weeks ago.
RE: spec for == and ##

> Resolution of x == y
> ====================
>
> 1) Null values will not cause NPEs.
>
> hashCode and ##
> ===============
>
> The unification of primitives and boxed types in scala necessitates measures to preserve the equality contract: equal objects must have equal hash codes. To accomplish this a new method is introduced on Any:
>
> def ##: Int
>
> This method should be called in preference to hashCode by all scala software which consumes hashCodes.


So:

. What's the relationship between ## and ScalaRunTime.hash (if any)? Does the former obsolete the latter?

. I gather that, unlike for null == x, there's no compiler support to make null.## do anything other than throw NPE. This means that where null is a possible value, software that consumes hash codes must still check for it explicitly, and (if necessary) substitute an appropriate value (presumably zero). Right?

A


The New Busy think 9 to 5 is a cute idea. Combine multiple calendars with Hotmail. Get busy.
extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: spec for == and ##

On Tue, Apr 13, 2010 at 02:35:41PM -0700, adriaN kinG wrote:
> . What's the relationship between ## and ScalaRunTime.hash (if any)?
> Does the former obsolete the latter?

The former is the spec and the latter is an implementation detail.

> . I gather that, unlike for null == x, there's no compiler support to
> make null.## do anything other than throw NPE.

Hmm. You are right, and I can't see any reason there shouldn't be. In
fact there definitely should be. If martin has no objection I'll define
null.## to 0.

odersky
Joined: 2008-07-29,
User offline. Last seen 45 weeks 6 days ago.
Re: spec for == and ##


On Tue, Apr 13, 2010 at 11:45 PM, Paul Phillips <paulp@improving.org> wrote:
On Tue, Apr 13, 2010 at 02:35:41PM -0700, adriaN kinG wrote:
> . What's the relationship between ## and ScalaRunTime.hash (if any)?
> Does the former obsolete the latter?

The former is the spec and the latter is an implementation detail.

> . I gather that, unlike for null == x, there's no compiler support to
> make null.## do anything other than throw NPE.

Hmm.  You are right, and I can't see any reason there shouldn't be.  In
fact there definitely should be.  If martin has no objection I'll define
null.## to 0.

At first reaction I'm against his. It's going to impose a (small) tax on every ## operation. Does it ever make sense to take the hashcode of null? I mean, we have no intention to let you use null as key of a hashtable, right?

Cheers

 -- martin

 
--
Paul Phillips      | Beware of bugs in the above code; I have only
Apatheist          | proved it correct, not tried it.
Empiricist         |     -- Knuth
pal, i pill push   |----------* http://www.improving.org/paulp/ *----------


extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: spec for == and ##

On Tue, Apr 13, 2010 at 11:49:14PM +0200, martin odersky wrote:
> At first reaction I'm against his. It's going to impose a (small) tax
> on every ## operation. Does it ever make sense to take the hashcode of
> null? I mean, we have no intention to let you use null as key of a
> hashtable, right?

Well, that's one of those other questions. But it's not so much about
null as a first class key as not making everyone perpetually rewrite
this logic (actual example from ScalaRunTime)

code = code * 41 + (if (elem == null) 0 else elem.hashCode())

I mean if we're folding a sequence into a hashcode we have to use ## on
all those too.

Parenthetically, I'd be all for choking off null keys (I'm always for
excluding null, it's a tense relationship we have) but when it has come
up before the nebulons have triumphed.

https://lampsvn.epfl.ch/trac/scala/ticket/2935

Changed 3 months ago by odersky:

This is one of these decisions where we can't give a clear guideline. I
would rather leave the spec of maps underspecified. Some maps will
accept nulls but you should not rely on it for all maps. Ragarding
Paul's patch, I think it's OK if there is no measureable slowdown. But
if we even get a 1% slowdown for lookup I would be in favor of reverting
and decalaring that null cannot be stored as a key in a flat hashtable.

Danielk
Joined: 2009-06-08,
User offline. Last seen 3 years 21 weeks ago.
Re: spec for == and ##
But this tax would be on the order of a nanosecond per invocation - it's difficult to imagine use cases where it would matter. I also think it is safe to assume that the vast majority of programmers and code use collection libraries rather than implement them, meaning they'll almost exclusively use .hashCode (or ## in this case) when implementing hashCode for a class in terms of the hashCodes of its fields, like in Paul's example. In this case it is definitely convenient not to have to check each field for null.


<side note>
It is also convenient not to have to come up with a suitable prime and add, multiply, add, multiply... In java I usually do something like:

@Override public int hashCode () {
        return hc (foo, hc (bar, hc (baz, 1)));
 }

where hc is a statically imported method:

public static int hc (Object o, int old) {
        return old * 31 + o != null ? o.hashCode () : 0;
}

Of course it's also easy to write such a helper method for performing null-friendly equality checks, but it is really nice that this is not necessary in Scala, so you don't have to reinvent the wheel in each project.
</side note>



Best regards,
Daniel






On Tue, Apr 13, 2010 at 11:49 PM, martin odersky <martin.odersky@epfl.ch> wrote:

At first reaction I'm against his. It's going to impose a (small) tax on every ## operation. Does it ever make sense to take the hashcode of null? I mean, we have no intention to let you use null as key of a hashtable, right?

Cheers

 -- martin

 
--
Paul Phillips      | Beware of bugs in the above code; I have only
Apatheist          | proved it correct, not tried it.
Empiricist         |     -- Knuth
pal, i pill push   |----------* http://www.improving.org/paulp/ *----------



extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: spec for == and ##

On Wed, Apr 14, 2010 at 01:26:50AM +0200, Daniel Kristensen wrote:
> But this tax would be on the order of a nanosecond per invocation -
> it's difficult to imagine use cases where it would matter.

It occurs to me that there's a performance argument in its favor.
What's the hashCode of a Seq[Any] ? If writing general usage code you
have to do a null check on every member even if it turns out to be a
million Ints. If we define ## on Any not to NPE, you can call it
directly and the anyvals can have final constant implementations.

Performance isn't my main game but I'd hate to see this opportunity
missed unless we have some pretty good evidence it matters. If anyone
out there wants to pitch in and take some measurements you might give us
better ammo (or conversely prove martin's concerns well founded - in
which case keep it quiet, ha ha.)

Archontophoenix
Joined: 2010-02-04,
User offline. Last seen 2 years 35 weeks ago.
RE: spec for == and ##

> On Wed, Apr 14, 2010 at 01:26:50AM +0200, Daniel Kristensen wrote:
> > But this tax would be on the order of a nanosecond per invocation -
> > it's difficult to imagine use cases where it would matter.
>
> It occurs to me that there's a performance argument in its favor.
> What's the hashCode of a Seq[Any] ? If writing general usage code you
> have to do a null check on every member even if it turns out to be a
> million Ints. If we define ## on Any not to NPE, you can call it
> directly and the anyvals can have final constant implementations.
>
> Performance isn't my main game but I'd hate to see this opportunity
> missed unless we have some pretty good evidence it matters. If anyone
> out there wants to pitch in and take some measurements you might give us
> better ammo (or conversely prove martin's concerns well founded - in
> which case keep it quiet, ha ha.)

On my configuration (2.66 GHz Core Duo, Java 1.6.0_19, Scala 2.8.0 Beta1), for a
class that looks like:

    case class C (a: Int, b: Int) {

      override def equals (o: Any): Boolean =
        o match {
          case C(oa,ob) => a == oa && b == ob
          case _ => false
        }

      override def hashCode: Int = 41 * a + b

    }

hashCode with an explicit null check takes about 60% longer (13.8 ns vs 8.6 ns).

(A better distributed hash function would take slightly longer and thereby
presumably reduce the relative cost of the check, but not by much; really good
hash functions are surprisingly cheap.)

By comparison, == (which checks implicitly for null) takes only 14% longer than
equals (15.0 ns vs 13.2).

I'm not sure this constitutes a compelling argument for not treating ## parallel
to ==, however. When you have to check for null, you have to check. (Sort of;
you can use a try-catch instead when you know there will be very few nulls, but
that trick is not applicable to general-purpose code.) And as Paul says, if you
know you have unboxed primitive types, you skip the check anyway.

If you want to avoid the check and you're in a situation where you know you have
a non-null reference type (other than boxed numerics that need special
treatment), you can still invoke equals and hashCode explicitly instead of ==
and ##.

A


The New Busy think 9 to 5 is a cute idea. Combine multiple calendars with Hotmail. Get busy.
Bill Venners
Joined: 2008-12-18,
User offline. Last seen 31 weeks 5 days ago.
Re: spec for == and ##

Hi Martin,

I'm getting a compiler stack trace compiling ScalaTest under RC1. I'm
going to try checking out everything fresh to make sure it isn't a
fluke, but in the meantime I'll include the info below.

svn checkout https://scalatest.dev.java.net/svn/scalatest/branches/app/trunk-for-scal...
st
cd st
source ./addmem.sh
ant doc

Buildfile: build.xml

init:

compile-main:
[scalac] Compiling 139 source files to
/Users/bv/nobkp/delus/st/target/jar_contents
[scalac] Exception in thread "main"
scala.tools.nsc.symtab.Types$TypeError: value
org$scalatest$DispatchReporter$$anonfun$Counter$$testsSucceededCount
is not a member of Counter
[scalac] at
scala.tools.nsc.typechecker.Contexts$Context.error(Contexts.scala:272)
[scalac] at
scala.tools.nsc.typechecker.Infer$Inferencer.error(Infer.scala:269)
[scalac] at
scala.tools.nsc.typechecker.Typers$Typer.typedSelect$1(Typers.scala:3563)
[scalac] at
scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:4058)
[scalac] at
scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:4151)
[scalac] at
scala.tools.nsc.typechecker.Duplicators$BodyDuplicator.typed(Duplicators.scala:276)
[scalac] at
scala.tools.nsc.typechecker.Typers$Typer.transformedOrTyped(Typers.scala:4295)
[scalac] at
scala.tools.nsc.typechecker.Typers$Typer.typedDefDef(Typers.scala:1848)
[scalac] at
scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:3815)
[scalac] at
scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:4151)
[scalac] at
scala.tools.nsc.typechecker.Duplicators$BodyDuplicator.typed(Duplicators.scala:213)
[scalac] at
scala.tools.nsc.typechecker.Typers$Typer.typedStat$1(Typers.scala:2141)
[scalac] at
scala.tools.nsc.typechecker.Typers$Typer$$anonfun$20.apply(Typers.scala:2209)
[scalac] at
scala.tools.nsc.typechecker.Typers$Typer$$anonfun$20.apply(Typers.scala:2209)
[scalac] at scala.collection.immutable.List.loop$1(List.scala:116)
[scalac] at scala.collection.immutable.List.mapConserve(List.scala:133)
[scalac] at
scala.tools.nsc.typechecker.Typers$Typer.typedStats(Typers.scala:2209)
[scalac] at
scala.tools.nsc.typechecker.Typers$Typer.typedTemplate(Typers.scala:1528)
[scalac] at
scala.tools.nsc.typechecker.Typers$Typer.typedClassDef(Typers.scala:1309)
[scalac] at
scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:3806)
[scalac] at
scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:4151)
[scalac] at
scala.tools.nsc.typechecker.Duplicators$BodyDuplicator.typed(Duplicators.scala:208)
[scalac] at
scala.tools.nsc.typechecker.Typers$Typer.typedStat$1(Typers.scala:2141)
[scalac] at
scala.tools.nsc.typechecker.Typers$Typer$$anonfun$20.apply(Typers.scala:2209)
[scalac] at
scala.tools.nsc.typechecker.Typers$Typer$$anonfun$20.apply(Typers.scala:2209)
[scalac] at scala.collection.immutable.List.loop$1(List.scala:116)
[scalac] at scala.collection.immutable.List.mapConserve(List.scala:133)
[scalac] at
scala.tools.nsc.typechecker.Typers$Typer.typedStats(Typers.scala:2209)
[scalac] at
scala.tools.nsc.typechecker.Typers$Typer.typedBlock(Typers.scala:1966)
[scalac] at
scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:3842)
[scalac] at
scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:4151)
[scalac] at
scala.tools.nsc.typechecker.Duplicators$BodyDuplicator.typed(Duplicators.scala:201)
[scalac] at
scala.tools.nsc.typechecker.Typers$Typer.transformedOrTyped(Typers.scala:4295)
[scalac] at
scala.tools.nsc.typechecker.Typers$Typer.typedDefDef(Typers.scala:1848)
[scalac] at
scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:3815)
[scalac] at
scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:4151)
[scalac] at
scala.tools.nsc.typechecker.Duplicators$BodyDuplicator.typed(Duplicators.scala:213)
[scalac] at
scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:4199)
[scalac] at
scala.tools.nsc.typechecker.Duplicators.retyped(Duplicators.scala:32)
[scalac] at
scala.tools.nsc.transform.SpecializeTypes$$anon$6.duplicateBody(SpecializeTypes.scala:1176)
[scalac] at
scala.tools.nsc.transform.SpecializeTypes$$anon$6.transform(SpecializeTypes.scala:1056)
[scalac] at
scala.tools.nsc.ast.Trees$Transformer$$anonfun$transformTrees$1.apply(Trees.scala:832)
[scalac] at
scala.tools.nsc.ast.Trees$Transformer$$anonfun$transformTrees$1.apply(Trees.scala:832)
[scalac] at scala.collection.immutable.List.loop$1(List.scala:116)
[scalac] at scala.collection.immutable.List.mapConserve(List.scala:133)
[scalac] at scala.collection.immutable.List.loop$1(List.scala:120)
[scalac] at scala.collection.immutable.List.mapConserve(List.scala:133)
[scalac] at scala.collection.immutable.List.loop$1(List.scala:120)
[scalac] at scala.collection.immutable.List.mapConserve(List.scala:133)
[scalac] at
scala.tools.nsc.ast.Trees$Transformer.transformTrees(Trees.scala:832)
[scalac] at
scala.tools.nsc.transform.SpecializeTypes$$anon$6$$anonfun$transform$3.apply(SpecializeTypes.scala:1041)
[scalac] at
scala.tools.nsc.transform.SpecializeTypes$$anon$6$$anonfun$transform$3.apply(SpecializeTypes.scala:1041)
[scalac] at scala.tools.nsc.ast.Trees$Transformer.atOwner(Trees.scala:858)
[scalac] at
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:36)
[scalac] at
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:29)
[scalac] at
scala.tools.nsc.transform.SpecializeTypes$$anon$6.transform(SpecializeTypes.scala:1041)
[scalac] at
scala.tools.nsc.ast.Trees$Transformer.transformTemplate(Trees.scala:834)
[scalac] at
scala.tools.nsc.ast.Trees$Transformer$$anonfun$transform$2.apply(Trees.scala:728)
[scalac] at
scala.tools.nsc.ast.Trees$Transformer$$anonfun$transform$2.apply(Trees.scala:727)
[scalac] at scala.tools.nsc.ast.Trees$Transformer.atOwner(Trees.scala:858)
[scalac] at
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:36)
[scalac] at
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:29)
[scalac] at scala.tools.nsc.ast.Trees$Transformer.transform(Trees.scala:726)
[scalac] at
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:51)
[scalac] at
scala.tools.nsc.transform.SpecializeTypes$$anon$6.transform(SpecializeTypes.scala:1139)
[scalac] at
scala.tools.nsc.ast.Trees$Transformer$$anonfun$transformStats$1.apply(Trees.scala:850)
[scalac] at
scala.tools.nsc.ast.Trees$Transformer$$anonfun$transformStats$1.apply(Trees.scala:848)
[scalac] at scala.collection.immutable.List.loop$1(List.scala:116)
[scalac] at scala.collection.immutable.List.mapConserve(List.scala:133)
[scalac] at
scala.tools.nsc.ast.Trees$Transformer.transformStats(Trees.scala:848)
[scalac] at scala.tools.nsc.ast.Trees$Transformer.transform(Trees.scala:760)
[scalac] at
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:51)
[scalac] at
scala.tools.nsc.transform.SpecializeTypes$$anon$6.transform(SpecializeTypes.scala:1139)
[scalac] at
scala.tools.nsc.ast.Trees$Transformer$$anonfun$transformTrees$1.apply(Trees.scala:832)
[scalac] at
scala.tools.nsc.ast.Trees$Transformer$$anonfun$transformTrees$1.apply(Trees.scala:832)
[scalac] at scala.collection.immutable.List.loop$1(List.scala:116)
[scalac] at scala.collection.immutable.List.mapConserve(List.scala:133)
[scalac] at
scala.tools.nsc.ast.Trees$Transformer.transformTrees(Trees.scala:832)
[scalac] at scala.tools.nsc.ast.Trees$Transformer.transform(Trees.scala:798)
[scalac] at
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:51)
[scalac] at
scala.tools.nsc.transform.SpecializeTypes$$anon$6.transform(SpecializeTypes.scala:1139)
[scalac] at
scala.tools.nsc.ast.Trees$Transformer$$anonfun$transform$4.apply(Trees.scala:738)
[scalac] at
scala.tools.nsc.ast.Trees$Transformer$$anonfun$transform$4.apply(Trees.scala:737)
[scalac] at scala.tools.nsc.ast.Trees$Transformer.atOwner(Trees.scala:858)
[scalac] at
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:36)
[scalac] at
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:29)
[scalac] at scala.tools.nsc.ast.Trees$Transformer.transform(Trees.scala:736)
[scalac] at
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:51)
[scalac] at
scala.tools.nsc.transform.SpecializeTypes$$anon$6.transform(SpecializeTypes.scala:1139)
[scalac] at
scala.tools.nsc.ast.Trees$Transformer$$anonfun$transformTrees$1.apply(Trees.scala:832)
[scalac] at
scala.tools.nsc.ast.Trees$Transformer$$anonfun$transformTrees$1.apply(Trees.scala:832)
[scalac] at scala.collection.immutable.List.loop$1(List.scala:116)
[scalac] at scala.collection.immutable.List.mapConserve(List.scala:133)
[scalac] at scala.collection.immutable.List.loop$1(List.scala:120)
[scalac] at scala.collection.immutable.List.mapConserve(List.scala:133)
[scalac] at scala.collection.immutable.List.loop$1(List.scala:120)
[scalac] at scala.collection.immutable.List.mapConserve(List.scala:133)
[scalac] at
scala.tools.nsc.ast.Trees$Transformer.transformTrees(Trees.scala:832)
[scalac] at
scala.tools.nsc.transform.SpecializeTypes$$anon$6$$anonfun$transform$3.apply(SpecializeTypes.scala:1041)
[scalac] at
scala.tools.nsc.transform.SpecializeTypes$$anon$6$$anonfun$transform$3.apply(SpecializeTypes.scala:1041)
[scalac] at scala.tools.nsc.ast.Trees$Transformer.atOwner(Trees.scala:858)
[scalac] at
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:36)
[scalac] at
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:29)
[scalac] at
scala.tools.nsc.transform.SpecializeTypes$$anon$6.transform(SpecializeTypes.scala:1041)
[scalac] at
scala.tools.nsc.ast.Trees$Transformer.transformTemplate(Trees.scala:834)
[scalac] at
scala.tools.nsc.ast.Trees$Transformer$$anonfun$transform$2.apply(Trees.scala:728)
[scalac] at
scala.tools.nsc.ast.Trees$Transformer$$anonfun$transform$2.apply(Trees.scala:727)
[scalac] at scala.tools.nsc.ast.Trees$Transformer.atOwner(Trees.scala:858)
[scalac] at
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:36)
[scalac] at
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:29)
[scalac] at scala.tools.nsc.ast.Trees$Transformer.transform(Trees.scala:726)
[scalac] at
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:51)
[scalac] at
scala.tools.nsc.transform.SpecializeTypes$$anon$6.transform(SpecializeTypes.scala:1139)
[scalac] at
scala.tools.nsc.ast.Trees$Transformer$$anonfun$transformStats$1.apply(Trees.scala:850)
[scalac] at
scala.tools.nsc.ast.Trees$Transformer$$anonfun$transformStats$1.apply(Trees.scala:848)
[scalac] at scala.collection.immutable.List.loop$1(List.scala:116)
[scalac] at scala.collection.immutable.List.mapConserve(List.scala:133)
[scalac] at
scala.tools.nsc.ast.Trees$Transformer.transformStats(Trees.scala:848)
[scalac] at
scala.tools.nsc.transform.SpecializeTypes$$anon$6$$anonfun$transform$2.apply(SpecializeTypes.scala:1028)
[scalac] at
scala.tools.nsc.transform.SpecializeTypes$$anon$6$$anonfun$transform$2.apply(SpecializeTypes.scala:1026)
[scalac] at scala.tools.nsc.ast.Trees$Transformer.atOwner(Trees.scala:858)
[scalac] at
scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:36)
[scalac] at
scala.tools.nsc.transform.SpecializeTypes$$anon$6.transform(SpecializeTypes.scala:1026)
[scalac] at
scala.tools.nsc.transform.SpecializeTypes$SpecializationTransformer$$anonfun$transform$5.apply(SpecializeTypes.scala:1377)
[scalac] at
scala.tools.nsc.transform.SpecializeTypes$SpecializationTransformer$$anonfun$transform$5.apply(SpecializeTypes.scala:1376)
[scalac] at
scala.tools.nsc.symtab.SymbolTable.atPhase(SymbolTable.scala:104)
[scalac] at
scala.tools.nsc.transform.SpecializeTypes$SpecializationTransformer.transform(SpecializeTypes.scala:1376)
[scalac] at
scala.tools.nsc.ast.Trees$Transformer.transformUnit(Trees.scala:851)
[scalac] at
scala.tools.nsc.transform.Transform$Phase.apply(Transform.scala:31)
[scalac] at
scala.tools.nsc.Global$GlobalPhase$$anonfun$applyPhase$1.apply(Global.scala:272)
[scalac] at
scala.tools.nsc.Global$GlobalPhase$$anonfun$applyPhase$1.apply(Global.scala:272)
[scalac] at scala.tools.nsc.reporters.Reporter.withSource(Reporter.scala:49)
[scalac] at scala.tools.nsc.Global$GlobalPhase.applyPhase(Global.scala:272)
[scalac] at
scala.tools.nsc.Global$GlobalPhase$$anonfun$run$1.apply(Global.scala:248)
[scalac] at
scala.tools.nsc.Global$GlobalPhase$$anonfun$run$1.apply(Global.scala:248)
[scalac] at scala.collection.Iterator$class.foreach(Iterator.scala:627)
[scalac] at
scala.collection.mutable.ListBuffer$$anon$1.foreach(ListBuffer.scala:305)
[scalac] at scala.tools.nsc.Global$GlobalPhase.run(Global.scala:248)
[scalac] at scala.tools.nsc.Global$Run.compileSources(Global.scala:729)
[scalac] at scala.tools.nsc.Global$Run.compile(Global.scala:815)
[scalac] at scala.tools.nsc.Main$.process(Main.scala:109)
[scalac] at scala.tools.nsc.Main$.main(Main.scala:123)
[scalac] at scala.tools.nsc.Main.main(Main.scala)

BUILD FAILED
/Users/bv/nobkp/delus/stForScala2.8h/build.xml:158: Compilation failed
because of an internal compiler error; see the error output for
details.

Bill
----
Bill Venners
Artima, Inc.
http://www.artima.com

Bill Venners
Joined: 2008-12-18,
User offline. Last seen 31 weeks 5 days ago.
Re: spec for == and ##

Hi Martin,

Forgot to mention you'd need to add "--username guest" to the end of
the svn checkout command. And that this compiled fine under
2.8.0.Beta1.

Bill

On Wed, Apr 14, 2010 at 6:09 PM, Bill Venners wrote:
> Hi Martin,
>
> I'm getting a compiler stack trace compiling ScalaTest under RC1. I'm
> going to try checking out everything fresh to make sure it isn't a
> fluke, but in the meantime I'll include the info below.
>
> svn checkout https://scalatest.dev.java.net/svn/scalatest/branches/app/trunk-for-scal...
> st
> cd st
> source ./addmem.sh
> ant doc
>
> Buildfile: build.xml
>
> init:
>
> compile-main:
>   [scalac] Compiling 139 source files to
> /Users/bv/nobkp/delus/st/target/jar_contents
>   [scalac] Exception in thread "main"
> scala.tools.nsc.symtab.Types$TypeError: value
> org$scalatest$DispatchReporter$$anonfun$Counter$$testsSucceededCount
> is not a member of Counter
>   [scalac]     at
> scala.tools.nsc.typechecker.Contexts$Context.error(Contexts.scala:272)
>   [scalac]     at
> scala.tools.nsc.typechecker.Infer$Inferencer.error(Infer.scala:269)
>   [scalac]     at
> scala.tools.nsc.typechecker.Typers$Typer.typedSelect$1(Typers.scala:3563)
>   [scalac]     at
> scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:4058)
>   [scalac]     at
> scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:4151)
>   [scalac]     at
> scala.tools.nsc.typechecker.Duplicators$BodyDuplicator.typed(Duplicators.scala:276)
>   [scalac]     at
> scala.tools.nsc.typechecker.Typers$Typer.transformedOrTyped(Typers.scala:4295)
>   [scalac]     at
> scala.tools.nsc.typechecker.Typers$Typer.typedDefDef(Typers.scala:1848)
>   [scalac]     at
> scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:3815)
>   [scalac]     at
> scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:4151)
>   [scalac]     at
> scala.tools.nsc.typechecker.Duplicators$BodyDuplicator.typed(Duplicators.scala:213)
>   [scalac]     at
> scala.tools.nsc.typechecker.Typers$Typer.typedStat$1(Typers.scala:2141)
>   [scalac]     at
> scala.tools.nsc.typechecker.Typers$Typer$$anonfun$20.apply(Typers.scala:2209)
>   [scalac]     at
> scala.tools.nsc.typechecker.Typers$Typer$$anonfun$20.apply(Typers.scala:2209)
>   [scalac]     at scala.collection.immutable.List.loop$1(List.scala:116)
>   [scalac]     at scala.collection.immutable.List.mapConserve(List.scala:133)
>   [scalac]     at
> scala.tools.nsc.typechecker.Typers$Typer.typedStats(Typers.scala:2209)
>   [scalac]     at
> scala.tools.nsc.typechecker.Typers$Typer.typedTemplate(Typers.scala:1528)
>   [scalac]     at
> scala.tools.nsc.typechecker.Typers$Typer.typedClassDef(Typers.scala:1309)
>   [scalac]     at
> scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:3806)
>   [scalac]     at
> scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:4151)
>   [scalac]     at
> scala.tools.nsc.typechecker.Duplicators$BodyDuplicator.typed(Duplicators.scala:208)
>   [scalac]     at
> scala.tools.nsc.typechecker.Typers$Typer.typedStat$1(Typers.scala:2141)
>   [scalac]     at
> scala.tools.nsc.typechecker.Typers$Typer$$anonfun$20.apply(Typers.scala:2209)
>   [scalac]     at
> scala.tools.nsc.typechecker.Typers$Typer$$anonfun$20.apply(Typers.scala:2209)
>   [scalac]     at scala.collection.immutable.List.loop$1(List.scala:116)
>   [scalac]     at scala.collection.immutable.List.mapConserve(List.scala:133)
>   [scalac]     at
> scala.tools.nsc.typechecker.Typers$Typer.typedStats(Typers.scala:2209)
>   [scalac]     at
> scala.tools.nsc.typechecker.Typers$Typer.typedBlock(Typers.scala:1966)
>   [scalac]     at
> scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:3842)
>   [scalac]     at
> scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:4151)
>   [scalac]     at
> scala.tools.nsc.typechecker.Duplicators$BodyDuplicator.typed(Duplicators.scala:201)
>   [scalac]     at
> scala.tools.nsc.typechecker.Typers$Typer.transformedOrTyped(Typers.scala:4295)
>   [scalac]     at
> scala.tools.nsc.typechecker.Typers$Typer.typedDefDef(Typers.scala:1848)
>   [scalac]     at
> scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:3815)
>   [scalac]     at
> scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:4151)
>   [scalac]     at
> scala.tools.nsc.typechecker.Duplicators$BodyDuplicator.typed(Duplicators.scala:213)
>   [scalac]     at
> scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:4199)
>   [scalac]     at
> scala.tools.nsc.typechecker.Duplicators.retyped(Duplicators.scala:32)
>   [scalac]     at
> scala.tools.nsc.transform.SpecializeTypes$$anon$6.duplicateBody(SpecializeTypes.scala:1176)
>   [scalac]     at
> scala.tools.nsc.transform.SpecializeTypes$$anon$6.transform(SpecializeTypes.scala:1056)
>   [scalac]     at
> scala.tools.nsc.ast.Trees$Transformer$$anonfun$transformTrees$1.apply(Trees.scala:832)
>   [scalac]     at
> scala.tools.nsc.ast.Trees$Transformer$$anonfun$transformTrees$1.apply(Trees.scala:832)
>   [scalac]     at scala.collection.immutable.List.loop$1(List.scala:116)
>   [scalac]     at scala.collection.immutable.List.mapConserve(List.scala:133)
>   [scalac]     at scala.collection.immutable.List.loop$1(List.scala:120)
>   [scalac]     at scala.collection.immutable.List.mapConserve(List.scala:133)
>   [scalac]     at scala.collection.immutable.List.loop$1(List.scala:120)
>   [scalac]     at scala.collection.immutable.List.mapConserve(List.scala:133)
>   [scalac]     at
> scala.tools.nsc.ast.Trees$Transformer.transformTrees(Trees.scala:832)
>   [scalac]     at
> scala.tools.nsc.transform.SpecializeTypes$$anon$6$$anonfun$transform$3.apply(SpecializeTypes.scala:1041)
>   [scalac]     at
> scala.tools.nsc.transform.SpecializeTypes$$anon$6$$anonfun$transform$3.apply(SpecializeTypes.scala:1041)
>   [scalac]     at scala.tools.nsc.ast.Trees$Transformer.atOwner(Trees.scala:858)
>   [scalac]     at
> scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:36)
>   [scalac]     at
> scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:29)
>   [scalac]     at
> scala.tools.nsc.transform.SpecializeTypes$$anon$6.transform(SpecializeTypes.scala:1041)
>   [scalac]     at
> scala.tools.nsc.ast.Trees$Transformer.transformTemplate(Trees.scala:834)
>   [scalac]     at
> scala.tools.nsc.ast.Trees$Transformer$$anonfun$transform$2.apply(Trees.scala:728)
>   [scalac]     at
> scala.tools.nsc.ast.Trees$Transformer$$anonfun$transform$2.apply(Trees.scala:727)
>   [scalac]     at scala.tools.nsc.ast.Trees$Transformer.atOwner(Trees.scala:858)
>   [scalac]     at
> scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:36)
>   [scalac]     at
> scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:29)
>   [scalac]     at scala.tools.nsc.ast.Trees$Transformer.transform(Trees.scala:726)
>   [scalac]     at
> scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:51)
>   [scalac]     at
> scala.tools.nsc.transform.SpecializeTypes$$anon$6.transform(SpecializeTypes.scala:1139)
>   [scalac]     at
> scala.tools.nsc.ast.Trees$Transformer$$anonfun$transformStats$1.apply(Trees.scala:850)
>   [scalac]     at
> scala.tools.nsc.ast.Trees$Transformer$$anonfun$transformStats$1.apply(Trees.scala:848)
>   [scalac]     at scala.collection.immutable.List.loop$1(List.scala:116)
>   [scalac]     at scala.collection.immutable.List.mapConserve(List.scala:133)
>   [scalac]     at
> scala.tools.nsc.ast.Trees$Transformer.transformStats(Trees.scala:848)
>   [scalac]     at scala.tools.nsc.ast.Trees$Transformer.transform(Trees.scala:760)
>   [scalac]     at
> scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:51)
>   [scalac]     at
> scala.tools.nsc.transform.SpecializeTypes$$anon$6.transform(SpecializeTypes.scala:1139)
>   [scalac]     at
> scala.tools.nsc.ast.Trees$Transformer$$anonfun$transformTrees$1.apply(Trees.scala:832)
>   [scalac]     at
> scala.tools.nsc.ast.Trees$Transformer$$anonfun$transformTrees$1.apply(Trees.scala:832)
>   [scalac]     at scala.collection.immutable.List.loop$1(List.scala:116)
>   [scalac]     at scala.collection.immutable.List.mapConserve(List.scala:133)
>   [scalac]     at
> scala.tools.nsc.ast.Trees$Transformer.transformTrees(Trees.scala:832)
>   [scalac]     at scala.tools.nsc.ast.Trees$Transformer.transform(Trees.scala:798)
>   [scalac]     at
> scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:51)
>   [scalac]     at
> scala.tools.nsc.transform.SpecializeTypes$$anon$6.transform(SpecializeTypes.scala:1139)
>   [scalac]     at
> scala.tools.nsc.ast.Trees$Transformer$$anonfun$transform$4.apply(Trees.scala:738)
>   [scalac]     at
> scala.tools.nsc.ast.Trees$Transformer$$anonfun$transform$4.apply(Trees.scala:737)
>   [scalac]     at scala.tools.nsc.ast.Trees$Transformer.atOwner(Trees.scala:858)
>   [scalac]     at
> scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:36)
>   [scalac]     at
> scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:29)
>   [scalac]     at scala.tools.nsc.ast.Trees$Transformer.transform(Trees.scala:736)
>   [scalac]     at
> scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:51)
>   [scalac]     at
> scala.tools.nsc.transform.SpecializeTypes$$anon$6.transform(SpecializeTypes.scala:1139)
>   [scalac]     at
> scala.tools.nsc.ast.Trees$Transformer$$anonfun$transformTrees$1.apply(Trees.scala:832)
>   [scalac]     at
> scala.tools.nsc.ast.Trees$Transformer$$anonfun$transformTrees$1.apply(Trees.scala:832)
>   [scalac]     at scala.collection.immutable.List.loop$1(List.scala:116)
>   [scalac]     at scala.collection.immutable.List.mapConserve(List.scala:133)
>   [scalac]     at scala.collection.immutable.List.loop$1(List.scala:120)
>   [scalac]     at scala.collection.immutable.List.mapConserve(List.scala:133)
>   [scalac]     at scala.collection.immutable.List.loop$1(List.scala:120)
>   [scalac]     at scala.collection.immutable.List.mapConserve(List.scala:133)
>   [scalac]     at
> scala.tools.nsc.ast.Trees$Transformer.transformTrees(Trees.scala:832)
>   [scalac]     at
> scala.tools.nsc.transform.SpecializeTypes$$anon$6$$anonfun$transform$3.apply(SpecializeTypes.scala:1041)
>   [scalac]     at
> scala.tools.nsc.transform.SpecializeTypes$$anon$6$$anonfun$transform$3.apply(SpecializeTypes.scala:1041)
>   [scalac]     at scala.tools.nsc.ast.Trees$Transformer.atOwner(Trees.scala:858)
>   [scalac]     at
> scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:36)
>   [scalac]     at
> scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:29)
>   [scalac]     at
> scala.tools.nsc.transform.SpecializeTypes$$anon$6.transform(SpecializeTypes.scala:1041)
>   [scalac]     at
> scala.tools.nsc.ast.Trees$Transformer.transformTemplate(Trees.scala:834)
>   [scalac]     at
> scala.tools.nsc.ast.Trees$Transformer$$anonfun$transform$2.apply(Trees.scala:728)
>   [scalac]     at
> scala.tools.nsc.ast.Trees$Transformer$$anonfun$transform$2.apply(Trees.scala:727)
>   [scalac]     at scala.tools.nsc.ast.Trees$Transformer.atOwner(Trees.scala:858)
>   [scalac]     at
> scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:36)
>   [scalac]     at
> scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:29)
>   [scalac]     at scala.tools.nsc.ast.Trees$Transformer.transform(Trees.scala:726)
>   [scalac]     at
> scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:51)
>   [scalac]     at
> scala.tools.nsc.transform.SpecializeTypes$$anon$6.transform(SpecializeTypes.scala:1139)
>   [scalac]     at
> scala.tools.nsc.ast.Trees$Transformer$$anonfun$transformStats$1.apply(Trees.scala:850)
>   [scalac]     at
> scala.tools.nsc.ast.Trees$Transformer$$anonfun$transformStats$1.apply(Trees.scala:848)
>   [scalac]     at scala.collection.immutable.List.loop$1(List.scala:116)
>   [scalac]     at scala.collection.immutable.List.mapConserve(List.scala:133)
>   [scalac]     at
> scala.tools.nsc.ast.Trees$Transformer.transformStats(Trees.scala:848)
>   [scalac]     at
> scala.tools.nsc.transform.SpecializeTypes$$anon$6$$anonfun$transform$2.apply(SpecializeTypes.scala:1028)
>   [scalac]     at
> scala.tools.nsc.transform.SpecializeTypes$$anon$6$$anonfun$transform$2.apply(SpecializeTypes.scala:1026)
>   [scalac]     at scala.tools.nsc.ast.Trees$Transformer.atOwner(Trees.scala:858)
>   [scalac]     at
> scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:36)
>   [scalac]     at
> scala.tools.nsc.transform.SpecializeTypes$$anon$6.transform(SpecializeTypes.scala:1026)
>   [scalac]     at
> scala.tools.nsc.transform.SpecializeTypes$SpecializationTransformer$$anonfun$transform$5.apply(SpecializeTypes.scala:1377)
>   [scalac]     at
> scala.tools.nsc.transform.SpecializeTypes$SpecializationTransformer$$anonfun$transform$5.apply(SpecializeTypes.scala:1376)
>   [scalac]     at
> scala.tools.nsc.symtab.SymbolTable.atPhase(SymbolTable.scala:104)
>   [scalac]     at
> scala.tools.nsc.transform.SpecializeTypes$SpecializationTransformer.transform(SpecializeTypes.scala:1376)
>   [scalac]     at
> scala.tools.nsc.ast.Trees$Transformer.transformUnit(Trees.scala:851)
>   [scalac]     at
> scala.tools.nsc.transform.Transform$Phase.apply(Transform.scala:31)
>   [scalac]     at
> scala.tools.nsc.Global$GlobalPhase$$anonfun$applyPhase$1.apply(Global.scala:272)
>   [scalac]     at
> scala.tools.nsc.Global$GlobalPhase$$anonfun$applyPhase$1.apply(Global.scala:272)
>   [scalac]     at scala.tools.nsc.reporters.Reporter.withSource(Reporter.scala:49)
>   [scalac]     at scala.tools.nsc.Global$GlobalPhase.applyPhase(Global.scala:272)
>   [scalac]     at
> scala.tools.nsc.Global$GlobalPhase$$anonfun$run$1.apply(Global.scala:248)
>   [scalac]     at
> scala.tools.nsc.Global$GlobalPhase$$anonfun$run$1.apply(Global.scala:248)
>   [scalac]     at scala.collection.Iterator$class.foreach(Iterator.scala:627)
>   [scalac]     at
> scala.collection.mutable.ListBuffer$$anon$1.foreach(ListBuffer.scala:305)
>   [scalac]     at scala.tools.nsc.Global$GlobalPhase.run(Global.scala:248)
>   [scalac]     at scala.tools.nsc.Global$Run.compileSources(Global.scala:729)
>   [scalac]     at scala.tools.nsc.Global$Run.compile(Global.scala:815)
>   [scalac]     at scala.tools.nsc.Main$.process(Main.scala:109)
>   [scalac]     at scala.tools.nsc.Main$.main(Main.scala:123)
>   [scalac]     at scala.tools.nsc.Main.main(Main.scala)
>
> BUILD FAILED
> /Users/bv/nobkp/delus/stForScala2.8h/build.xml:158: Compilation failed
> because of an internal compiler error; see the error output for
> details.
>
> Bill
> ----
> Bill Venners
> Artima, Inc.
> http://www.artima.com
>

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