开发者

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")).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜