Mike Hanafey
Mike Hanafey

Reputation: 5643

Is is reasonable, and is there a benefit to a Scala Symbol class that extends AnyVal?

It seems that one issue with scala.Symbol is it two objects, the Symbol and the String it is based on.

Why can this extra object not be eliminated by defining Sym something like:

class Sym private(val name:String) extends AnyVal {
    override def toString = "'" + name
}

object Sym {
    def apply(name:String) = new Sym(name.intern)
}

Admittedly the performance implications of object allocation are likely tiny, but comments with those with a deeper understanding of Scala would be illuminating. In particular, does the above provide efficient maps via equality by reference?

Another advantage of the simple 'Sym' above is in a map centric application where there are lots of string keys, but where the strings are naming many entirely different kinds of things, type safe Sym classes can be defined so that Maps will definitively show to the programmer, the compiler and refactoring tools what the key really is.

(Neither Symbol nor Sym can be extened, the former apparently by choice, and the latter because it extends AnyVal, but Sym is trivial enough to just duplicate with an appropriate name)

Upvotes: 1

Views: 363

Answers (3)

Rüdiger Klaehn
Rüdiger Klaehn

Reputation: 12565

It is not possible to do Symbol as an AnyVal. The main benefit of Symbols over simple Strings is that Symbols are guaranteed to be interned, so you can test equality of symbols using a simple reference comparison instead of an expensive string comparison.

See the source code of Symbol. Equals is overridden and redefined to do a reference comparison using the eq method.

But unfortunately an AnyVal does not allow you to redefine equality. From the SIP-15 for user-defined value classes:

C may not define concrete equals or hashCode methods.

So while it would be extremely useful to have a way to redefine equality without incurring runtime overhead, it is unfortunately not possible.

Edit: never use string.intern in any program where performance is important. The performance of string.intern is horrible compared to even a trivial intern table. See this SO question and answer. See the source code of Symbol above for a simple intern table.

Upvotes: 4

Arseniy Zhizhelev
Arseniy Zhizhelev

Reputation: 2401

For AnyVal the class is actually the String. The magically added methods and type-safety are just compiler tricks. It's the String that gets transfered all around.

For pattern matching (Symbol's purpose as I suppose) Scala needs the class of an object. Thus — Symbol extends AnyRef.

Upvotes: 0

wingedsubmariner
wingedsubmariner

Reputation: 13667

Unfortunately, object allocation for an AnyVal is forced whenever it is put into a collection, like the Map in your example. This is because the value class has to be cast to the type parameter of the collection, and casting to a new type always forces allocation. This eliminates almost any advantage of declaring Sym as a value class. See Allocation Details in the Scala documentation page for value classes.

Upvotes: 0

Related Questions