tags:

views:

245

answers:

3
package it.onof.scalaDemo

case class MyInt(val i : Int) {
    private def factorial(a : Int) : Int = a match {
        case 0 => 1
        case n => (n) * factorial(n-1)
    }
    def ! = factorial(i)
    override def toString = i.toString
}

object MyInt {
    implicit def intToMyInt(x : Int) = MyInt(x)
    implicit def myIntToInt(x : MyInt) = x.i
}
import MyInt._

object Factorial {  
    def main(args: Array[String]): Unit = {
        val a = 5
        val aFact = a!
        println("factorial of " + a + " is " + aFact)

  }
}

If i don't put a semicolon or a empty line before println it fails to compile:

recursive value aFact needs type

+7  A: 

Because otherwise the ! could be interpreted as a binary expression

a ! println("factorial of " + a + " is " + aFact)

The opposite could just be proven if the compiler evalated both types of the expressions involved, because there is the possibility of an implicit conversion for these types that allowed the call.

But since the right operand involves aFact itself, the value is recursive, Scala can't determine it's type and thus not the correct fixity of the operator.

You need to be explicit here!

Dario
but println is Unit, why could not it realize that ! is unary? And, why empty line is enough?
onof
Because he can't tell there is no binary version. It's ambiguous unless you know the types.
Dario
This decision is made by the parser, before the types are known. I added an Inspection recently to IntelliJ to highlight potential problems like this here's how your code would look: http://twitpic.com/2p99rl
retronym
There might be an implicit conversion from `Unit` to a type which defines binary `!`.
Alexey Romanov
+1  A: 

Below code compiles fine:

package it.onof.scalaDemo

case class MyInt(val i : Int) {
    private def factorial(a : Int) : Int = a match {
        case 0 => 1
        case n => (n) * factorial(n-1)
    }
    def ! = factorial(i)
    override def toString = i.toString
}

object MyInt {
    implicit def intToMyInt(x : Int) = MyInt(x)
    implicit def myIntToInt(x : MyInt) = x.i
}
import MyInt._

object Factorial {  
    def main(args: Array[String]): Unit = {
        val a = 5
        val aFact:Int = a.!
        println("factorial of " + a + " is " + aFact)
  }
}
Jaydeep
+4  A: 

All this talk about recursive function and type is a red-herring. Scala's grammar does not allow for postfix operators in any other place than the end of an expression. This is the grammar we are talking about: the syntax of things without any semantics. Here is the relevant grammar from the specs:

Expr        ::= (Bindings | [‘implicit’] id | ‘_’) ‘=>’ Expr
              | Expr1
Expr1       ::= ‘if’ ‘(’ Expr ‘)’ {nl} Expr [[semi] else Expr]
              | ‘while’ ‘(’ Expr ‘)’ {nl} Expr
              | ‘try’ ‘{’ Block ‘}’ [‘catch’ ‘{’ CaseClauses ‘}’]
                [‘finally’ Expr]
              | ‘do’ Expr [semi] ‘while’ ‘(’ Expr ’)’
              | ‘for’ (‘(’ Enumerators ‘)’ | ‘{’ Enumerators ‘}’)
              | {nl} [‘yield’] Expr
              | ‘throw’ Expr
              | ‘return’ [Expr]
              | [SimpleExpr ‘.’] id ‘=’ Expr
              | SimpleExpr1 ArgumentExprs ‘=’ Expr
              | PostfixExpr
              | PostfixExpr Ascription
              | PostfixExpr ‘match’ ‘{’ CaseClauses ‘}’
PostfixExpr ::= InfixExpr [id [nl]]

The only two places where PostfixExpr appears beside these are after the if on a case statement and before : _* on an argument list. So, looking at that, we see that the only things that can appear on the right side of a postfix expression's method name is a type ascription or a match.

So, what end expressions? Well, expressions appears in a lot of places in the grammar, so there's a lot of things that could end it. In this particular example, the expression is a BlockStat inside a Block, so it must end with a semi-colon, which may be inferred or not.

To infer this semi-colon, it is necessary that the next line must not be something that could be parsed as another kind of expression. In this particular case, we have this:

    val aFact = a!
    println("factorial of " + a + " is " + aFact)

Now, let's rewrite that from the point of view of the compiler:

    val id = id id
    id ( stringLit id id id stringLit id id )

These literals and identifiers are parsed like this:

    val id = id id id ( expr )
    val Pattern2 = SimpleExpr1 id SimpleExpr1 ArgumentExprs
    val Pattern2 = InfixExpr
    val Pattern2 = Expr
    val PatDef
    PatVarDef
    Def
    BlockStat

So that looks like a valid infix expression to the compiler as he parsed your program. Afterwards, it noticed the types didn't match, but it's too late to go back and see if a semi-colon could be inferred.

Daniel