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 an empty line before println
it fails to compile:
recursive value aFact needs type
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With