1

I'm having difficulty crafting a solution to this class hierarchy I want to assemble. I have a abstract data packet "Vertex", and an abstract class "VertexShader" which operates on Vertex instances. In fact, derived classes from VertexShader operate on specific derived classes of Vertex. It is a lot like the classic example of the Animal class with def eat(f : Food), but whose child classes can eat only specific kinds of Food.

I guess the problem is that the derived Vertex classes are supposed to provide a function "+" that operates on vertices as well, and i need to pass the result of this operation into the VertexShader. The problem is that the system won't let me pass the result of the '+' operation into the VertexShader object, even though the types all resolve correctly by inference.

Any suggestions on how to redesign this to avoid the type issue are very welcome.

/// Abstract Interface Types

trait Vertex 
{ 
   type V <: Vertex
   def position : Float 
   def + (v : V) : V
}

/// Derived class of vertex shader will use a specific derived class of
/// vertex that it can shade
trait VertexShader
{
   type V <: Vertex
   def shade( v : V ) : Float
}

/// Concrete Implementation Example

class MyVertex(p : Float, c : Float) extends Vertex
{
   type V = MyVertex   
   val position : Float = p       // inherited 
   val color    : Float = p*2.0f  // custom  

   def + (v : MyVertex) : MyVertex = new MyVertex(position + v.position, color + v.color)
}

class MyVertexShader extends VertexShader
{
   type V = MyVertex
   def shade( v : MyVertex ) : Float = v.position + v.color
}


object Bootstrap
{
   def main ( args : Array[String] )
   {
      /// Vertex and vertex shader, pretend concrete class type is unknown
      /// as these objects will be pulled out of some other abstract object
      /// interface at runtime
      val mVShader : VertexShader = new MyVertexShader
      val mV0 : Vertex = new MyVertex(1.0f, 9.0f)

     /////////////////////////////////////////

      val shadeValue = mVShader.shade(mV0 + mV0)
   }
}
om-nom-nom
  • 62,329
  • 13
  • 183
  • 228
Fooberman
  • 626
  • 5
  • 14

1 Answers1

6

The problem is that your type annotations are discarding information:

val mVShader : VertexShader = new MyVertexShader

You've just said that it is a VertexShader -- but in order to pass along MyVertex to its shade method, you need to be more specific:

val mVShader : VertexShader {type V = MyVertex} = new MyVertexShader

The easiest and concisest fix is to remove the type annotations:

val mVShader = new MyVertexShader
val mV0 = new MyVertex(1.0f, 9.0f)

In response to your comment:

If you have

trait Mesh {
    trait T <: Vertex
    def getVertex: T
}

and

class AMash extends Mesh { ... }

You can get the specific T for AMesh as

AMesh#T

and for a particular AMash object as

val amesh: AMesh = ...
... amesh.T ...

though the latter is a tricky thing that will not always work, or require dependent method types.

Community
  • 1
  • 1
Owen
  • 38,836
  • 14
  • 95
  • 125
  • Yeah, that will fix the example, but in a real-world case, suppose I had a reference (val) of abstract type Mesh, which has a function like this: "def generateVertex : Vertex" and of course it returns a vertex of a specific type T < Vertex. Can I get this type information from this Mesh object? For example, if the class Mesh declared "type V < Vertex" could I say Mesh.V ? – Fooberman Feb 17 '12 at 07:53