By chance I came across weird compiling Scala syntax:
class Some extends {
def hi = println(\"hi\")
}
This is actually a strange quirk in Scala's syntax. An extraneous extends
is allowed before beginning the body of the class. Here are the relevant parts from the Scala Syntax Summary:
ClassDef ::= id [TypeParamClause] {ConstrAnnotation} [AccessModifier]
ClassParamClauses ClassTemplateOpt
ClassTemplateOpt ::= ‘extends’ ClassTemplate | [[‘extends’] TemplateBody]
ClassTemplate ::= [EarlyDefs] ClassParents [TemplateBody]
ClassTemplateOpt
is everything after the class's parameters, in this case everything from extends
onwards. The usual use of extends
is the first alternation of ClassTemplateOpt
, with extends
being followed either by a parent or an early initializer. However, an early initializer cannot contain a def
, and there is no way to interpret the contents of the braces as a parent. It cannot be a structural type because hi
has a concrete definition.
The second alternation allows the class parameters to be immediately followed by the class body, without using extends
. However, an optional extends
is allowed. The extends
in OP's code is an example of this, and is exactly equivalent to the same code without the optional extends:
class Some {
def hi = println("hi")
}
Yes this is Scala's structural typing or more commonly known as duck typing.
object LoudDuck {
def quack(): String = "QUACK"
}
object QuietDuck {
def quack(): String = "quack"
}
object CowDuck {
def quack(): String = "moo"
}
def quackMyDuck(duck: { def quack(): String }) {
println(duck.quack())
}
scala>quackMyDuck(LoudDuck)
QUACK
scala>
scala>quackMyDuck(QuietDuck)
quack
scala>
scala>quackMyDuck(CowDuck)
moo
You can also declare your stuctural types with the "type" keyword.
type Duck = { def quack(): String }
def quackMyDuck(duck: Duck) {
println(duck.quack())
}
This is actually just a syntactical accident (I think). Scala allows early definitions which look like
class Some extends {
...
} with ATrait
so the parser also accepts class Some extends { ... }
which is equivalent to class Some { ... }
(source).