I'm having trouble using, in one trait, a Parser returned from a method in another trait. The compiler complains of a type mismatch and it appears to me that the problem is due to the path-dependent class. I'm not sure how to get what I want.
trait Outerparser extends RegexParsers {
def inner: Innerparser
def quoted[T](something: Parser[T]) = "\"" ~> something <~ "\""
def quotedNumber = quoted(inner.number) // Compile error
def quotedLocalNumber = quoted(number) // Compiles just fine
def number: Parser[Int] = ("""[1-9][0-9]*"""r) ^^ {str => str.toInt}
}
trait Innerparser extends RegexParsers {
def number: Parser[Int] = ("""[1-9][0-9]*"""r) ^^ {str => str.toInt}
}
And the error:
[error] /Path/to/MyParser.scala:6: type mismatch
[error] found : minerals.Innerparser#Parser[Int]
[error] required: Outerparser.this.Parser[?]
[error] def quotedNumber = quoted(inner.number)
I sort-of get the idea: each "something" method is defining a Parser type whose path is specific to the enclosing class (Outerparser or Innerparser). The "quoted" method of Outerparser expects an an instance of type Outerparser.this.Parser but is getting Innerparser#Parser.
I like to be able to use quoted with a parser obtained from this class or some other class. How can I do that?
You can use a self-type annotation to make it compile while still preserving the modularity:
trait OuterParser extends RegexParsers { this: InnerParser =>
def quoted[T](something: Parser[T]) = "\"" ~> something <~ "\""
def quotedNumber = quoted(number) // Compile error
}
trait InnerParser extends RegexParsers {
def number: Parser[Int] = ("""[1-9][0-9]*"""r) ^^ {str => str.toInt}
}
object MyCompleteParser extends OuterParser with InnerParser
The self-type annotation basically says that OuterParser depends InnerParser (they must be mixed together to create a proper instantiatable class). The compiler thus knows for sure that in OuterParser and InnerParser, Parser
refers to the same type.