Practical examples of using symbols in Scala?

13,808

Solution 1

Do symbols really fit into Scala?

In the wonderful land of Lisp, code is represented as nested lists of literal objects that denote themselves (strings, numbers, and so on), and symbols, which are used as identifiers for things like classes, functions, and variables. As Lisp code has a very simple structure, Lisp allows the programmer to manipulate it (both at compile-time and run-time). Clearly, when doing this, the programmer will inevitably encounter symbols as data objects.

So symbols are (and need to be) objects in Lisp in any case, so why not use them as hash table keys or as enums as well? It's the natural way of doing things, and it keeps the language simple, as you don't have to define a special enumeration type.

To summarise, symbols are naturally used for code manipulation, enumeration, and keying. But Java people don't use identity as the equivalence relation between hash keys by default (which your traditional Lisp does), so they can just use strings as their keys. Enum types are defined separately in Scala. And finally, code as data isn't supported by the language at all.

So no, my impression is that symbols don't belong in the Scala language. That said, I'm going to keep an eye on the replies to this question. They might still demonstrate a genuine use of symbols in Scala that I can't think of right now.

(Addendum: Depending on the Lisp dialect, Lisp symbols may also be namespace-qualified, which is, of course, an immensely useful feature when manipulating code, and a feature that strings don't have.)

Solution 2

Searching a bit around the web it seems that the sense of symbols (symbol literals) in (a language like) Scala in comparision with Strings is a matter of semantics, and thus possibly even compiler awareness.

'String' is a datatype, consisting of a sequence of characters. You can operate on strings and so manipulate them. Strings can semantically be any text data, from a filename to a message to be printed on screen, a line in a CSV file, or whatever.

For the compiler -and thus the IDE- strings are values of a data type String, like numbers (sequences of digits) are values of a data type say: Integer . There is on the program level no difference between "foo" and "bar".

OTOH Symbols are identifiers, i.e. semantically identifying an item in the program. In this matter they are like class names, method names or attribute names. But while a class name identifies the class -i.e. the set of properties declaring the class' structure and behaviour- and a method name identifies the method -i.e. the parameters and statements- , a symbol name identifies the symbol -i.e. itsself, nothing more- .

So the compiler can explicitly distinguish between the symbols 'foo and 'bar, like he distinguishes between the classes Foo and Bar. As part of the compiler's symbol table, you can apply the same mechanisms in an IDE e.g. to search for the usage of 'foo (i.e. the references to this symbol) like you search for the usage of class Foo.

In comparision, searching for a string "foo" would require different approaches, like a full text scan. It follows the same semantics as searching for all occurrences of 4711 in the program code.

That's how I understand it, someone may correct me if I'm wrong.

Solution 3

According to the Scala book, Symbols are interned: "If you write the same symbol twice, both expressions will refer to the exact same Symbol object."

In contrast, Strings are only interned if they appear in literal form (at least in Java they are, not entirely sure about Scala). So I guess if you do a lot of serialization of Strings that are then put into collections, you might use symbols instead and save yourself some memory.

But I agree with skaffman, I'm not totally convinced of their use.

(In Ruby, Symbols are, apart from the meta-programming example you give, often used as keys in Hashes. In Ruby this is useful because there, Strings are never interned: every String allocates new memory. In Scala it might be useful, as I mentioned, if you combine it with a lot of (de)serialization so the Java Strings don't get interned as well.)

Solution 4

I guess Scala added them because functional languages use them.

They forgot, though, to add the ability of referencing an identifier through a symbol, which is kind of the central point of their existence. There's an experimental feature in Scala 2.8 that gives some of that. I'll quote the relevant part of the API documentation in full:


@experimental

object Invocation 
extends AnyRef

A more convenient syntax for reflective invocation. Example usage:

    class Obj { private def foo(x: Int, y: String): Long = x + y.length }

You can call it reflectively one of two ways:

    import scala.reflect.Invocation._
    (new Obj) o 'foo(5, "abc")                 // The 'o' method returns Any
    val x: Long = (new Obj) oo 'foo(5, "abc")  // The 'oo' method casts to expected type.

If you call the oo method and do not give the type inferencer enough help, it will most likely infer Nothing, which will result in a ClassCastException.

Author Paul Phillips

Solution 5

I believe comparisons between symbols is faster. If you've used Erlang, symbols are used a tonne when passing around messages and you want something cheap, and fast, that works well ACROSS machine boundaries. I'm not sure in what state remote actors are in Scala, IIRC, they were rather dodgy, but in the future when them in place, symbols could well be very useful in much the same way as they are in Erlang. Also case classes, some of the benefits aren't as apparent, then again, symbols are still cheaper.

Share:
13,808
Jesper
Author by

Jesper

Independent software developer. Pluralsight course author. Moderator at CodeRanch. Have a look at my blog.

Updated on June 10, 2022

Comments

  • Jesper
    Jesper about 2 years

    Scala has symbols - names that start with a single quote ' and which are a kind of string constants.

    I know symbols from Ruby (where they start with a colon). In Ruby they are used for some meta-programming tasks, like generating getters and setters for member variables (for example attr_reader :name to generate a getter for name).

    I haven't seen a lot of use of symbols in Scala code yet. What are practical uses for symbols in Scala?

  • skaffman
    skaffman almost 15 years
    But if you use String literals instead of symbol literals, which is the thrust of the question, then both get interned.
  • jqno
    jqno almost 15 years
    Exactly, so that's why the serialization is important. It'll give you different objects for the same strings, which the Symbols (supposedly) won't. Also, the question didn't explicitly specify Symbol literals. If it's literals you want, my answer indeed doesn't really apply. Which, I guess, would make Symbols even more tenuous :).
  • Saem
    Saem almost 15 years
    You'd still want to key hashes with symbols over strings, or what not, as they're cheaper and allow for easier refactoring, emphasis on the latter. Symbols if anything promote the separation of code and data, which is sought after in Scala, as you're clearly saying, this isn't some magic string that happens to be named the same across the code base, but it's actually code.
  • Daniel C. Sobral
    Daniel C. Sobral almost 15 years
    @Saem you are correct about code and data, but, alas, case objects will beat symbols almost every time in this regard. See my answer to a question about type-safe Enumeration in Scala.
  • heavi5ide
    heavi5ide over 13 years
    The automatic interning of Symbols also means that equals() for Symbols can be implemented as a reference equality check, so comparisons can be super fast (as opposed to comparing every character of two Strings). That would imply that they would be more efficient than Strings for many uses, e.g. when used as keys in a Map?
  • Carlos Verdes
    Carlos Verdes over 8 years
    Note: You can get the intern from a String like in Java with "asdf".intern() .
  • Little Alien
    Little Alien about 8 years
    Deserialization was really crucial to mention. What about Symbol deserialization? It seems to be important that identity is preserved but how do you achieve that? Nothing discusses the Symbold serialization, despite of its crucial importance, IMO.