This page is no longer maintained — Please continue to the home page at www.scala-lang.org

polymorphic self type specifier?

3 replies
Jeremy Cloud
Joined: 2009-02-02,
User offline. Last seen 42 years 45 weeks ago.

I have a set of classes that follow this pattern:

abstract class BaseThing {
def metadata: MetaData[???]
...
}

abstract class MetaData[T <: BaseThing] {
def dataClass: Class[T]
...
}

class ThingA extends BaseThing {
def metadata = MetaDataA
...
}

object MetaDataA extends MetaData[ThingA] {
def dataClass = classOf[ThingA]
...
}

Basically, for any class T <: BaseThing, I want its metadata method to have
the return type MetaData[T] (not MetaData[BaseThing]), but I am uncertain of
the best way to specify this. What I really want is some soft of type
specifier that is always equal to the current class (I thought "this.type"
would do it, but that seems to do something else). In the Sather language,
for instance, the type "Self" was always equal to the class on which a
method was invoked, rather than the class on which the method was defined.

I believe I could add a type parameter to BaseType such as the following,
but this seems silly:

abstract class BaseThing[T <: BaseThing] {
def metadata: MetaData[T]
}

class ThingA extends BaseThing[ThingA] ...

This annoys me because adding a type parameter to BaseThing effects the
public type signature of BaseThing and consequently every use of the
BaseThing class needs to be parameterized.

Any suggestions?

Colin Bullock
Joined: 2009-01-23,
User offline. Last seen 42 years 45 weeks ago.
Re: polymorphic self type specifier?
Perhaps abstract types are what you're looking for:


trait MetaData[T <: BaseThing] {
  def dataClass: Class[T]
}

abstract class BaseThing {
  type BaseType <: BaseThing
  def metadata: MetaData[BaseType]
}

object MetaDataA extends MetaData[ThingA] {
  def dataClass = classOf[ThingA]
}

class ThingA extends BaseThing {
  type BaseType = ThingA
  def metadata = MetaDataA
}

- Colin
Jeremy Cloud
Joined: 2009-02-02,
User offline. Last seen 42 years 45 weeks ago.
Re: polymorphic self type specifier?

I am experimenting with abstract types, and they seem to be getting me
farther, but not quite all the way. Because there is no way to declare a
constraint that BaseType must always be equal to the current type, certain
type inferences fail. For example, if I have the method doSomething in
MetaData:

trait MetaData[T <: BaseThing] {
def doSomething(thing: T) { ... }
}

and then elsewhere have:

object SomeUtilClass {
def doSomethingOn[T <: BaseThing](thing: T) = {
thing.metadata.doSomething(thing)
}
...
}

Then the compiler complains about a type mismatch (found T, expecting
thing.BaseType). I believe this is because, for any type T <: BaseThing,
the compiler doesn't know that T.BaseType will be T, so thing.metadata could
be returning a MetaData parameterized by a different type.

It appears that I can get the above code to compile by inserting
asInstanceOf:
thing.metadata.asInstanceOf[MetaData[T]].doSomething(thing)

However, I always have this feeling that every time I use asInstanceOf, it
is because I have done something wrong.

Jorge Ortiz
Joined: 2008-12-16,
User offline. Last seen 29 weeks 3 days ago.
Re: polymorphic self type specifier?
Try the following. Lift uses this pattern for it's ORM.

  object Things {
    abstract class BaseThing[T <: BaseThing[T]] {
      def metadata: MetaData[T]
    }

    abstract class MetaData[T <: BaseThing[T]] {
      def dataClass: Class[T]
      def doSomething(thing: T) {}
    }

    class ThingA extends BaseThing[ThingA] {
       def metadata = MetaDataA
    }

    object MetaDataA extends MetaData[ThingA] {
       def dataClass = classOf[ThingA]
    }
 
    def doSomethingOn[T <: BaseThing[T]](thing: T) =
      thing.metadata.doSomething(thing)
  }

--j
On Mon, Feb 2, 2009 at 8:05 AM, Jeremy Cloud <jeremy [at] synthesisstudios [dot] com> wrote:

I am experimenting with abstract types, and they seem to be getting me
farther, but not quite all the way.  Because there is no way to declare a
constraint that BaseType must always be equal to the current type, certain
type inferences fail.  For example, if I have the method doSomething in
MetaData:

trait MetaData[T <: BaseThing] {
 def doSomething(thing: T) { ... }
}

and then elsewhere have:

object SomeUtilClass {
 def doSomethingOn[T <: BaseThing](thing: T) = {
   thing.metadata.doSomething(thing)
 }
 ...
}

Then the compiler complains about a type mismatch (found T, expecting
thing.BaseType).  I believe this is because, for any type T <: BaseThing,
the compiler doesn't know that T.BaseType will be T, so thing.metadata could
be returning a MetaData parameterized by a different type.

It appears that I can get the above code to compile by inserting
asInstanceOf:
  thing.metadata.asInstanceOf[MetaData[T]].doSomething(thing)

However, I always have this feeling that every time I use asInstanceOf, it
is because I have done something wrong.
--
View this message in context: http://www.nabble.com/polymorphic-self-type-specifier--tp21791157p21792383.html
Sent from the Scala - User mailing list archive at Nabble.com.


Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland