74

Where can I find a list of Scala's "magic" functions, such as apply, unapply, update, +=, etc.?

By magic-functions I mean functions which are used by some syntactic sugar of the compiler, for example

o.update(x,y) <=> o(x) = y

I googled for some combination of scala magic and synonyms of functions, but I didn't find anything.

I'm not interested with the usage of magic functions in the standard library, but in which magic functions exists.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Elazar Leibovich
  • 32,750
  • 33
  • 122
  • 169

6 Answers6

81

As far as I know:

Getters/setters related:

apply
update
identifier_=

Pattern matching:

unapply
unapplySeq

For-comprehensions:

map
flatMap
filter
withFilter
foreach

Prefixed operators:

unary_+
unary_-
unary_!
unary_~

Beyond that, any implicit from A to B. Scala will also convert A <op>= B into A = A <op> B, if the former operator isn't defined, "op" is not alphanumeric, and <op>= isn't !=, ==, <= or >=.

And I don't believe there's any single place where all of Scala's syntactic sugars are listed.

Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681
17

In addition to update and apply, there are also a number of unary operators which (I believe) qualify as magical:

  • unary_+
  • unary_-
  • unary_!
  • unary_~

Add to that the regular infix/suffix operators (which can be almost anything) and you've got yourself the complete package.

You really should take a look at the Scala Language Specification. It is the only authoritative source on this stuff. It's not that hard to read (as long as you're comfortable with context-free grammars), and very easily searchable. The only thing it doesn't specify well is the XML support.

Daniel Spiewak
  • 54,515
  • 14
  • 108
  • 120
12

Sorry if it's not exactly answering your question, but my favorite WTF moment so far is @ as assignment operator inside pattern match. Thanks to soft copy of "Programming in Scala" I found out what it was pretty quickly.

Using @ we can bind any part of a pattern to a variable, and if the pattern match succeeds, the variable will capture the value of the sub-pattern. Here's the example from Programming in Scala (Section 15.2 - Variable Binding):

expr match {
  case UnOp("abs", e @ UnOp("abs", _)) => e
  case _ =>
}

If the entire pattern match succeeds, then the portion that matched the UnOp("abs", _) part is made available as variable e.

And here's what Programming Scala says about it.

That link no longer works. Here is one that does.

justinpitts
  • 721
  • 8
  • 11
Yardena
  • 2,837
  • 20
  • 17
4

I'll also add _* for pattern matching on an arbitrary number of parameters like

case x: A(_*)

And operator associativity rule, from Odersky-Spoon-Venners book:

The associativity of an operator in Scala is determined by its last character. As mentioned on <...>, any method that ends in a ‘:’ character is invoked on its right operand, passing in the left operand. Methods that end in any other character are the other way around. They are invoked on their left operand, passing in the right operand. So a * b yields a.*(b), but a ::: b yields b.:::(a).


Maybe we should also mention syntactic desugaring of for expressions which can be found here


And (of course!), alternative syntax for pairs

a -> b //converted to (a, b), where a and b are instances

(as correctly pointed out, this one is just an implicit conversion done through a library, so it's probably not eligible, but I find it's a common puzzler for newcomers)


Community
  • 1
  • 1
pagoda_5b
  • 7,333
  • 1
  • 27
  • 40
4

I'd like to add that there is also a "magic" trait - scala.Dynamic:

A marker trait that enables dynamic invocations. Instances x of this trait allow method invocations x.meth(args) for arbitrary method names meth and argument lists args as well as field accesses x.field for arbitrary field names field.

If a call is not natively supported by x (i.e. if type checking fails), it is rewritten according to the following rules:

foo.method("blah")      ~~> foo.applyDynamic("method")("blah")
foo.method(x = "blah")  ~~> foo.applyDynamicNamed("method")(("x", "blah"))
foo.method(x = 1, 2)    ~~> foo.applyDynamicNamed("method")(("x", 1), ("", 2))
foo.field           ~~> foo.selectDynamic("field")
foo.varia = 10      ~~> foo.updateDynamic("varia")(10)
foo.arr(10) = 13    ~~> foo.selectDynamic("arr").update(10, 13)
foo.arr(10)         ~~> foo.applyDynamic("arr")(10)

As of Scala 2.10, defining direct or indirect subclasses of this trait is only possible if the language feature dynamics is enabled.

So you can do stuff like

import scala.language.dynamics

object Dyn extends Dynamic {
  def applyDynamic(name: String)(a1: Int, a2: String) {
    println("Invoked " + name + " on (" + a1 + "," + a2 + ")");
  }
}

Dyn.foo(3, "x");
Dyn.bar(3, "y");
Daniel Carlsson
  • 103
  • 1
  • 4
Petr
  • 62,528
  • 13
  • 153
  • 317
3

They are defined in the Scala Language Specification. As far as I know, there are just three "magic" functions as you mentioned.

Scalas Getter and Setter may also relate to your "magic":

scala> class Magic {
 |     private var x :Int = _
 |     override def toString = "Magic(%d)".format(x)
 |     def member = x
 |     def member_=(m :Int){ x = m }
 | }

defined class Magic

scala> val m = new Magic

m: Magic = Magic(0)

scala> m.member

res14: Int = 0

scala> m.member = 100

scala> m

res15: Magic = Magic(100)

scala> m.member += 99

scala> m

res17: Magic = Magic(199)
kiritsuku
  • 52,967
  • 18
  • 114
  • 136
Eastsun
  • 18,526
  • 6
  • 57
  • 81
  • If you could dig for me an evidence for that claim, you'll be answering my question ;-) I assumed it'll be in the specs, but finding them in it is not a fun job. – Elazar Leibovich Sep 27 '09 at 12:55
  • 2
    Scala Language Specification: 6.15 Assignments ... If x is a parameterless function defined in some template, and the same template contains a setter function x_= as member, then the assignment x = e is interpreted as the invocation x_=(e ) of that setter function. Analogously, an assignment f .x = e to a parameterless function x is interpreted as the invocation f .x_=(e ). An assignment f (args) = e with a function application to the left of the “=’ operator is interpreted as f .update(args, e ), i.e. the invocation of an update function defined by f . – Eastsun Sep 27 '09 at 13:25
  • I ment, evidence that there're no more. – Elazar Leibovich Sep 28 '09 at 22:11