Extending a class with many implementation that each have main methods in Scala
imagine that I have a Tokenizer class with a single abstract method.
trait Tokenizer {
def tokenize(sentence: String): List[String]
}
I will implement a number of tokenizers that provide an implementation. I would like for each of these Tokenizer to have a main method. My first thought was to write code like this:
abstract class TokenizerMain(tokenizer: Tokenizer) {
def main(args: Array[String]) = println(tokenizer.tokenize(args(0)).mkString(" "))
}
class TokenizerOne(val model: String = "foo") extends Tokenizer {
def tokenize(sentence: String) = List("asdf")
}
object TokenizerOne extends TokenizerMain(new TokenizerOne) {
}
However, I get the error "super constructor cannot be passed a self reference unless parameter is declared by-name". I can rename object TokenizerOne
to object TokenizerOneMain
but I would like to keep it the same as开发者_C百科 the class
. Is there a better way to do this?
UPDATE: this problem seems to be caused by the implicit constructor parameter model
of TokenizerOne.
Here's a reduced code sample that gives the same error,
class Foo(t: Any)
class Bar(x: String = "bar")
object Bar extends Foo(new Bar())
// ^
// Error, super constructor cannot be passed a self reference unless
// parameter is declared by-name
The bytecode helps explain what's going on. From the REPL,
scala> class Foo(t: Any)
scala> class Bar(x: String = "bar")
scala> :javap -v Bar
Compiled from "<console>"
public class Bar extends java.lang.Object implements scala.ScalaObject
...
{
public Bar(java.lang.String);
...
We see that the class Bar
has only a single constructor, which takes a String
parameter. But we know that Bar
also has a constructor that uses the default value x = "bar"
, where does that come from?
scala> :javap -v Bar$
...
public java.lang.String init$default$1();
Code:
Stack=1, Locals=1, Args_size=1
0: ldc #16; //String bar
2: areturn
LineNumberTable:
line 7: 0
Ahh, that's defined in the companion object, which belongs to class Bar$
(only the Scala compiler is supposed to know about that).
So what seems to be happening is that in extends Foo(new Bar())
you're trying to access a method in object Bar
during the initialization of Bar
's super-class (which is before the object Bar
is actually constructed).
If this is not a bug in the Scala compiler, then it's a confusing error message! I can't say which. I filed issue SI-5000 in the bug tracker.
As a workaround, you can avoid the default value: object Bar extends Foo(new Bar("bar"))
.
精彩评论