Question

I'm confused over when a select is appropriate and when an apply is. I thought apply was a function or method application, thus

scala> val expr = u reify { Random.nextInt }
expr: reflect.runtime.universe.Expr[Int] = Expr[Int](Random.nextInt())

scala> u showRaw expr.tree
res0: String = Apply(Select(Ident(scala.util.Random), newTermName("nextInt")), List())

Is what I expect; an application of nextInt with an empty parameter list.

Also,

scala> val expr = u reify { Random.shuffle(List("sammy", "snake")) }
expr: reflect.runtime.universe.Expr[List[String]] = Expr[List[String]](Random.shuffle(List.apply("sammy", "snake"))(List.canBuildFrom))

scala> u showRaw expr.tree
res2: String = Apply(Apply(Select(Ident(scala.util.Random), newTermName("shuffle")), List(Apply(Select(Ident(scala.collection.immutable.List), newTermName("apply")), List(Literal(Constant("sammy")), Literal(Constant("snake")))))), List(Select(Ident(scala.collection.immutable.List), newTermName("canBuildFrom"))))

Is again what I expected - an application of the shuffle method, with a list of strings.

However,

scala> val expr = u reify { Random.shuffle(List("sammy", "snake")).head }
expr: reflect.runtime.universe.Expr[String] = Expr[String](Random.shuffle(List.apply("sammy", "snake"))(List.canBuildFrom).head)

scala> u showRaw expr.tree
res1: String = Select(Apply(Apply(Select(Ident(scala.util.Random), newTermName("shuffle")), List(Apply(Select(Ident(scala.collection.immutable.List), newTermName("apply")), List(Literal(Constant("sammy")), Literal(Constant("snake")))))), List(Select(Ident(scala.collection.immutable.List), newTermName("canBuildFrom")))), newTermName("head"))

Is a Select on head. I'm confused because I would have thought that that outer node would be an application of head. Why is it a select when head is a method?

Is there a web page that details the difference between Select and Apply because I cannot find one.

Was it helpful?

Solution

The meaning of Select and Apply is purely syntactical.

Select(prefix, newTermName("member")) means prefix.member

Apply(prefix, List(arg1, arg2, ...)) means prefix(arg1, arg2, ...)

So techically, Random.nextInt is a Select, but the Scala typechecker wrapped it in an additional Apply because Random.nextInt is defined as a function that takes single, empty parameter list. In other words, this is a desugaring performed by the typechecker.

This isn't the case with List's head method. If you look at its definition, it takes no parameter lists:

def head: A

And that's why the typechecker does not wrap it in an Apply tree.

Summarizing - there is difference between methods that take single, empty parameter list and methods that take no parameter lists. As a syntactic sugar, Scala allows to call methods with single, empty parameter list as if they take no parameter lists (without any parens), but the typechecker will still add the Apply in such cases.

OTHER TIPS

In this case, trees precisely reproduce syntactic structure of Scala programs. Select corresponds to member selection, e.g. to foo.bar, whereas Apply stands for an application of an argument list, e.g. baz(1, 2, 3).

If we have an empty arglist method in Scala, e.g. def x() = ??? (or Random.nextInt()), then its invocation can be written both as a Select (corresponding to something.x) and an Apply(Select(...), Nil) (corresponding to something.x()), because both are valid Scala expressions.

If we have a nullary method in Scala, e.g. def y = ??? (or List.head), then its invocation can only be written as a Select (which corresponds to somethingElse.y). If we write Apply(Select(...), Nil), that would mean somethingElse.y(), which would stand for applying an empty argument list to the result of calling method y on somethingElse.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top