Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala Dependent type does not compile

This code should compile in Scala:

trait Pipe {
  type Input
  type Output
  def apply(input: Input): Output
}

object Pipe {
  trait Start extends Pipe {
    override type Input = Seq[String]
  }

  abstract class Connect(val prev: Pipe) extends Pipe {
    override type Input = prev.Output
  }
}

object Pipe1 extends Pipe.Start {
  override type Output = Int
  override def apply(input: Input): Output = 
   input.length
}

object Pipe2 extends Pipe.Connect(prev = Pipe1) {
  override type Output = Boolean
  override def apply(input: Input): Output = 
   input%2 == 0
}

Pipe1 compiles fine but Pipe2 fails to compile with:

value % is not a member of Pipe2.this.Input
     input%2 == 0
          ^

I know I can solve this with generics instead of dependent types but this should work as Pipe2.Input should typecheck to be Int from Pipe1.Output

like image 830
pathikrit Avatar asked Jan 26 '23 12:01

pathikrit


1 Answers

The prev = Pipe thing in the invocation of the constructor is not a proper path, the compiler cannot tie any type information to that, so you end up with a rather useless prev.Output =:= Input for some indeterminate prev: Pipe which has been set to something in the constructor.

With a minimal change, it works as expected:

trait Pipe {
  type Input
  type Output
  def apply(input: Input): Output
}

object Pipe {
  trait Start extends Pipe {
    override type Input = Seq[String]
  }

  abstract class Connect extends Pipe {
    val prev: Pipe
    override type Input = prev.Output
  }

}

object Pipe1 extends Pipe.Start {
  override type Output = Int
  override def apply(input: Input): Output = 
    input.length
}

object Pipe2 extends Pipe.Connect {
  val prev = Pipe1
  override type Output = Boolean
  override def apply(input: Input): Output = input % 2 == 0
}

That's why it's called path dependent (not member dependent, not value dependent etc.).

like image 165
Andrey Tyukin Avatar answered Jan 31 '23 11:01

Andrey Tyukin