27

Beginner Scala question, but I couldn't find the answer on here.

Similar to overloading in C++, I would expect the compiler can tell the difference between a method called - which takes one parameter (with the same type as the class) and the unary version of - which takes no parameters, so why is unary_ needed?

jhabbott
  • 18,461
  • 9
  • 58
  • 95

2 Answers2

76

The unary_ prefix for unary prefix operators is a bit misleading: it's more about the prefix part than the unary part. You need some way to distinguish

!foo // unary prefix !

from

foo! // unary postfix !

Remember: Scala doesn't actually have operators. There are two ways to call a method, either with a . or with whitespace:

foo.bar(1, "two")
foo bar(1, "two")

And when you have a single argument, you can leave off the parentheses:

foo plus(1)
foo plus 1

Lastly, (almost) any character is legal in an identifier:

foo plus 1
foo + 1

Now it looks like Scala has a binary infix + operator, but it actually doesn't. It's just a normal method called with normal method calling syntax.

What I said above isn't fully true, however. If Scala didn't have support for operators and it all was just normal method calling, then

2 + 3 * 4

would evaluate to 20 (like it does in Smalltalk, Self and Newspeak for example) instead of 14. So, there is a little bit of support for operators in Scala (two little bits, actually). When a method is called with whitespace (so-called "operator syntax") instead of the ., and that method starts with an operator character, then Scala will respect operator precedence.

And the other little bit of operator support is that there are some operators that you would like to have, but that cannot be easily expressed as a method call. It works fine for binary infix operators and unary postfix operators:

foo op bar // same as:
foo.op(bar)

foo op     // same as:
foo.op

But not for prefix or "around-fix" operators:

!foo
foo(bar)

So, there are a couple of special syntactic sugar translation rules:

!foo
foo.unary_!
// same for +, - and ~

foo(bar)
foo.apply(bar)

foo(bar) = 1
foo.update(bar, 1)

foo += 1
foo.+=(1) // but if this doesn't compile, then the compiler will also try
foo = foo.+(1)

And the reason why there needs to be an underscore between the alphanumeric and the "operator" part in a method name is because you wouldn't know whether

foo!

means

foo.!

or

this.foo!

Thus, foo! as a method name is illegal, it needs to be called foo_!.

jhabbott
  • 18,461
  • 9
  • 58
  • 95
Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653
  • 5
    Thanks for the detailed explanation and additional insight :) – jhabbott May 20 '13 at 08:56
  • 1
    Since this answer seems to gather some attention: is there a a bit of method calling syntax sugar I am missing? – Jörg W Mittag May 20 '13 at 15:03
  • "When a method is called with whitespace (so-called "operator syntax") instead of the ., and that method starts with an operator character, then Scala will respect operator precedence." @jhabbott watch this: scala> 2.+3.*4 res10: Double = 14.0 – liango Dec 26 '15 at 08:52
  • @liango: You are using operator syntax in that case. It is being interpreted as `(2.) + (3.) * (4)`. You should get a deprecation warning, though; float literals without decimals are deprecated and will be removed in later versions. – Jörg W Mittag Dec 26 '15 at 10:28
9

Because in scala it is totally fine to create a method named -, that takes no arguments. How would you distinguish between a normal and a unary method? For example ! has a totally different meaning as unary, than as post fix operator.

drexin
  • 24,225
  • 4
  • 67
  • 81
  • So you can have `!x` and `x!` both called just `!` and taking no additional parameters and the compiler will know it's two different functions? Also it will know which one to call because it's before or after the object? – jhabbott May 20 '13 at 08:42
  • Jörg W Mittag explains in a little more detail, what I wanted to say with my answer ;-) – drexin May 20 '13 at 11:20
  • Yeah thanks - you both got upvotes :) I'm just learning and some things are tricky to understand when you don't know about all the other things yet. – jhabbott May 20 '13 at 12:44