3

OK, so, I get that I can do things like:

trait MyTrait[T <: MyTrait[T]] { self: T =>
  val listOfT: List[T]
  def getFirst: T
  def getOne: T = if (listOfT.length > 0) getFirst else self
}

class MyClass extends MyTrait[MyClass] {
  override val listOfT: List[MyClass] = List[MyClass](this)
  override def getFirst: MyClass = listOfT.head
}

and that if I want MyTrait to have a companion object it looks like:

object MyTrait{
  def doSomething[T <: MyTrait[T]](aninstance:T)= { ... }
}

All that seems ugly and I'd like to see a nicer way, but, right now I'm just trying to figure out, how do I refer to the type from anywhere else? For example:

case class Foo( anInstanceOfMyTrait: MyTrait[what goes here???] )

Or is there a simpler way?

4
  • what about case class Foo[A](i: MyTrait[A])? Commented Sep 7, 2012 at 18:12
  • Well, then the case class compiles, but if I extract i from that in a matcher and try to pass the i to MyTrait.doSomething[T<:MyTrait[T]](aninstance:T), I get an error: "inferred type arguments [MyTrait[Any]] do not conform to method doSomething's type parameter bounds [T <: MyTrait[T]]" Commented Sep 7, 2012 at 18:18
  • and if I: case class Foo[A <: MyTrait[A]](i:MyTrait[A]) I still get the same inferred type arguments error when trying to pass the i to doSomething Commented Sep 7, 2012 at 18:23
  • added another similar question with more issues based on same sample code: stackoverflow.com/questions/12337846/… Commented Sep 9, 2012 at 9:07

2 Answers 2

3

Looking at your comment it seems the actual problem is that in your attempt to parameterize Foo, you referenced MyTrait twice:

case class Foo[A <: MyTrait[A]](i:MyTrait[A])

Try this instead:

case class Foo[A <: MyTrait[A]](i: A)

This mirrors the way MyTrait.doSomething is defined, so that you can pass i to doSomething:

case class Foo[A<:MyTrait[A]](i: A)
val foo = new Foo[MyClass]( new MyClass )
MyTrait.doSomething( foo.i ) // This compiled OK
Sign up to request clarification or add additional context in comments.

5 Comments

Doesn't work for me... Changing it to case class Foo[A<:MyTrait[A]](i:A) still gives me inferred type arguments [Any] do not conform to method doSomething's type parameter bounds [T <: MyTrait[T]]
I see what the issue is in your answer... you've specified new Foo[MyClass] (so your code compiles). I'm in the file defining traits, I don't know what the subclass will be here. I need a case class to hold instances of MyTrait generically to pass between a method in the companion object and another method in the companion object, so need to be able to create an instance of the case class without knowledge of the implementing class.
This should have been in the original question then. Can you post a more complete code snippet, that would fully represent what you are trying to achieve? For what it's worth, I don't think you need to change anything to "be able to create an instance of the case class without knowledge of the implementing class". Just have your 2 companion object methods be generic. But then again, please update your post so we don't have to assume things.
I'm not sure why I'm having trouble explaining this, but I'm just trying to find generally how I can refer to the type of the trait in a consistent way in a non-trivial program. I gave one example of another class (that happened to be a case class) that might want to have the trait be an attribute. Your answer only shows how to refer to the subclass, which a trivial problem. See the comments on the original question.
Maybe I just didn't understand your answer, it's pretty similar to the one I accepted on my other question... not quite sure why I couldn't get it to work before.
2

I got this to work:

trait MyTrait[T <: MyTrait[T]] {
  def getFirst = this
}

class MyClass extends MyTrait[MyClass]

case class Foo[A <: MyTrait[A]](i: MyTrait[A])

object MyTrait {
  def doSomething[T <: MyTrait[T], U[X <: MyTrait[X]] <: MyTrait[X]](t: U[T]) =
    t.getFirst
}

val mc = new MyClass
val foo = Foo(mc)
MyTrait.doSomething(foo.i)

4 Comments

Now if I try to call any method on t from within doSomething I get that that method is not a member of type parameter U[T]
more specific error, if I change t to t.getOne in the implementation of doSomething, I get: error: value getOne is not a member of type parameter U[T]. I need to a more universal way to refer to the type, I also need to be able to specify the return type since in my real application some of these methods are recursive. (I'm using the implementation of MyTrait from the original post that has a getOne)
@Brian: Yes, I see. I introduced an upper bound for U[X]. Looks quite ugly, but works. I do not understand what you mean with recursive methods. If this answer does not yet solve all your problems, please edit your question to explain all your needs.
All I meant about recursive methods is that I can't leave out return-type-annotations in my actual program. As I commented on the other answer, I'm trying to understand generally how I can refer to the type, the case class was just an example. Your answer does handle the specific example, so I'll 'accept'. In reality I'll re-write my program to not use recursive type parameters. One of the issues I have with your answer now is that if I pass a U[T] around, other classes don't see that type as being compatible with MyTrait[T]. I'll just add other questions on SO for specific other problems.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.