As odd as this may appear at first glance there are some good use cases for symbols.
- Save memory
- Extra semantics. Semantically they are the same object where "hi" is not necessarily the same as "hi" so 'hi has some extra semantics meaning this is the one an only 'hi object.
- Shorter syntax. This can be useful when designing DSLs
- Identifier syntax. When using the simpler syntax the symbol will be a valid Scala identifier so it can be good when intending to reference methods or variable, perhaps in a heavily reflection based framework
I hope that makes sense :)
- // This is the long way to create a symbol object
- scala> Symbol("hi")
- res10: Symbol = 'hi
- // This is the short way. The symbol must be a legal Scala symbol (like a method name or value/variable name)
- scala> 'hi
- res11: Symbol = 'hi
- // If you *need* characters in a symbol that are not legal in Scala identifiers the Symbol
- // object has a factory method for that purpose
- scala> Symbol("hi there")
- res12: Symbol = 'hi there
- // Not legal
- scala> 'hi there
- < console>:5: error: value there is not a member of Symbol
- 'hi there
- ^
- // quotes are not legal for identifiers
- scala> '"hi there"
- < console>:1: error: unclosed character literal
- '"hi there"
- ^
- < console>:1: error: unclosed string literal
- '"hi there"
- ^
- scala> 'hi\ there
- < console>:5: error: value \ is not a member of Symbol
- 'hi\ there
- ^
- // You can extract out the string from the symbol if desired quite easily
- scala> 'hi match { case Symbol(b) => b}
- res14: String = hi
- // A simpler way to get the string
- scala> 'hi.toString drop 1
- res0: String = hi
An even simpler way to get the string:
ReplyDelete'hi.name
Literal String instances are also cached by the compiler. The intern method allows to internalize strings created at runtime to get unique reference.
ReplyDeleteSo I think that on the JVM symbols are useless. Perhaps they were introduced for .Net sake?
One thing to have in mind: symbols in Scala pre-2.8 are implemented as weak references in a hashmap. This could pose some performance problems.
ReplyDeleteOne also ought to be careful with frameworks which use reflection to construct objects (like XStream) as this could possibly cause consistency issues when two different symbol objects with the same string exist:
val s = 'symbol
println(s == s.getClass.getConstructors().first.newInstance("symbol"))