18

Somewhat similar to Stack Overflow question Compose and andThen methods, I've been working through Twitter's Scala School tutorial and quickly ran into the same problem that a commenter had (which was great, because I went to bed thinking my problem was solved).

In the tutorial, it defines two methods as such:

def addUmm(x: String) = x + " umm"
def addAhem(x: String) = x + " ahem"

and while in newer versions of Scala, you can't call compose on them as such: addUmm(_).compose(addAhem(_)), the accepted answer (and some of the other answers seem to hinge upon the fact that addUmm and addAhem are methods, not functions, which creates an issue when trying to call compose. I went to bed satisfied, having successfully run:

scala> ((s: String) => s + " umm").compose((s: String) => s + " ahem")
res0: String => java.lang.String = <function1>

Cool. The issue is that while not being able to compose methods makes some sense, when I the same thing with values I know evaluate to Function1:

val a = (s: String) => s + " umm"
val b = (s: String) => s + " ahem"
val c = a(_).compose(b(_))

Well, that last line coughs up the same error that the original question did, even though they're partial applications of functions this time, not methods. One of the answers in the original question (highly-ranked, but not the accepted answer) seems to hint that it has to do with how the partial application is expanded, what is the explanation?

For a Scala newbie, the fact that the inferencer gets a(_).compose(b(_)) wrong no matter if you explicitly specify _: String both places, but a.compose(b) does is somewhat confusing.

Community
  • 1
  • 1
Marc Bollinger
  • 3,109
  • 2
  • 27
  • 32
  • If something doesn't work using the underscore shortcut for lambdas, then try it using the normal syntax first. The underscore often behaves unexpectedly. – ziggystar Oct 07 '11 at 08:10
  • You should read [my answer](http://stackoverflow.com/questions/7505304/compose-and-andthen-methods-problem/7506870#7506870) in that question. I explain precisely what the problem is with that line, which is _not_ related to method/function distinction. – Daniel C. Sobral Oct 07 '11 at 13:24
  • 1
    @DanielC.Sobral yours was actually the answer (the highly-ranked one) I was referencing (and upvoted your answer long ago :)). The line I'm complaining about seems to be at the kernel of that question, and so the accepted answer (as you point out) seemed like something of a red herring. I just wanted to factor that out here. – Marc Bollinger Oct 07 '11 at 14:17

2 Answers2

24

a(_).compose(b(_)) expands to x => { a(x).compose(y => b(y) }. Hence the error. What you want is (x => a(x)).compose(y => b(y)). Adding a pair of parentheses fixes this.

scala> (a(_)).compose(b(_: String))
res56: String => java.lang.String = <function1>

scala> res56("hello")
res57: java.lang.String = helloahemumm

But since a and b are functions, you can avoid all this cruft and simply do a compose b.

missingfaktor
  • 90,905
  • 62
  • 285
  • 365
  • Purely stylistically, is `a compose b` preferred to `a.compose(b)` in the community at large (haven't read any actual Scala projects yet)? – Marc Bollinger Oct 07 '11 at 14:13
  • 1
    @Marc: Yes. Personally I do not have any hard and fast rules, but I tend to use the former only with non-alphaneumeric method names, and latter for everything else. – missingfaktor Oct 07 '11 at 15:15
  • 2
    @Marc: Imagine you have this line of code: `xs filter { f } map { g }`. Suppose at some latter point in time you need to add a `toList` at end. You put it so: `xs filter { f } map { g } toList`. This may cause semicolon inference issues. To avoid these issues, you either put a semicolon at end, or put a newline. Both options are ugly IMO. To avoid all this nonsense, I always prefer to go with `xs.filter(f).map(g)`. It's always easier to refactor with this syntax. – missingfaktor Oct 07 '11 at 15:20
  • @Marc: One exception to the rule in my first comment: Internal DSLs. They look nicer with the space syntax, and are usually designed with care so as not to cause parsing issues when written in this manner. – missingfaktor Oct 07 '11 at 15:22
  • Thanks! Exactly the kind of insight I was looking for. – Marc Bollinger Oct 07 '11 at 18:15
  • @Marc: Glad to be of help. :-) – missingfaktor Oct 07 '11 at 18:26
4

You can use simply 'a compose b'.

scala> val c = a compose b
c: String => java.lang.String = <function1>
  • Right, so I'm aware I _can_, as that's equivalent to `a.compose(b)` as above. It's more about 'why not' vis-a-vis the other cases. I guess I'm more concerned with the inner workings of partial compositions (and, I guess, expansions thereof), and unlike is answered in the other question, the partial composition of methods and functions really yield the same type. And if that's meaningful. If that makes sense. – Marc Bollinger Oct 07 '11 at 06:01