1
votes

My title is probably not really describing the problem real well. I do not need the answer to this question for what I am doing, I have things correct now, but while I was working with the Scala combinator parsers I had this issue that confused me. I would like to understand the language better (I'm a Scala newbie for the most part), so I thought I would see if anyone can explain this to me:

Here is the code:

package my.example

import scala.io.Source
import scala.util.parsing.input.StreamReader
import scala.util.parsing.combinator.lexical.StdLexical
import scala.util.parsing.combinator.syntactical.StandardTokenParsers

class DummyParser extends StandardTokenParsers
{
    def scan
    (
        filename : String
    ) : Unit =
    {
        // Read in file
        val input = StreamReader( Source.fromFile( filename ).bufferedReader )
        // I want a reference to lexical in StandardTokenParsers
        val mylexical = lexical
        // Even if I put a type above like these two below it does not help
        // val mylexical : StdLexical = lexical
        // val mylexical : Tokens = lexical
        val tokensGood : lexical.Scanner = new lexical.Scanner( input )
        /*
        Compile error in following line:
        error: type mismatch;
        found   : mylexical.Scanner
        required: DummyParser.this.lexical.Scanner
        */
        val tokensBad : lexical.Scanner = new mylexical.Scanner( input )
    }
}

The "val tokensBad" line gets the compile error shown in the comments. Isn't mylexical above referencing the exact same object as this.lexical (defined in StandardTokenParsers that the class above is deriving from). Reading "Programming in Scala" I think I sort of understand that the type of lexical.Scanner is path dependent (Section 20.7), but shouldn't lexical.Scanner and mylexical.Scanner be the same type? Isn't lexical and mylexical the same object? Heck, the dog food example in the book on page 426 seems to say the SuitableFood type from two different dogs is the same, and in my case above its the exact same object (I think). What's really going on here?

1

1 Answers

8
votes

You would like the compiler to consider lexical.Scanner and mylexical.Scanner as equal, based on the fact that at runtime, the value of mylexical and lexical is always the same. This is a run-time property, and the type checker doesn't do any data-flow analysis (that would be way too slow to be practical).

So you need to help the type checker by telling it that the two values are always the same. You can do that by using a singleton type. A singleton type is a type that has exactly one value, and is written as (in this case) lexical.type.

If you change the definition of mylexical to:

val mylexical: lexical.type = lexical

your program type-checks.

What we just did is tell the type checker that mylexical can only have one value at runtime, given by the singleton type.