At a REPL, the definition:
trait Foo1{def testFoo[T](l1 : List[T] ) : List[T] }
is replacing the class definition
case class Foo1(i: Int)
If you try to do the same thing using the paste command you will see that both cannot be defined together:
scala> :paste
// Entering paste mode (ctrl-D to finish)
case class Foo1(i: Int)
trait Foo1{def testFoo[T](l1 : List[T] ) : List[T] }
// Exiting paste mode, now interpreting.
<console>:36: error: Foo1 is already defined as case class Foo1
trait Foo1{def testFoo[T](l1 : List[T] ) : List[T] }
^
As such you need to use a different name for your trait than your case class, which is sensible, as they refer to different things.
Once renamed, there are a couple of ways to achieve your goals. One is outlined by Sascha (use a type member), or you can promote type T to parameterize your trait instead of parameterizing the method on the trait.
case class Foo1(i: Int)
trait Bar[T] {
def testFoo(l1 : List[T] ) : List[T]
}
implicit val foodVal: Bar[Foo1] = new Bar[Foo1] {
override def testFoo(l: List[Foo1]): List[Foo1] = {
for { a <- l if a.i == 1 } yield a
}
}
To answer the Update question, the answer is the difference between declaration and implementation.
When I write an implementation of a parameterized trait in the form below, I am saying "replace the abstract type T with the concrete type Foo".
trait Bar[T] {...}
val instance = new Foo[Bar] { ... }
But when I override a method that is parameterized by type and change the name of the type, all I am doing is specifying a different name for that abstract type. I'm not specifying the specific concrete class to use, I'm specifying a new symbol by which to identify the abstract type that I am operating on.
trait Bar {
def something[T](t: T) : T
}
val instance = new Bar {
def something[Foo](t: Foo) : Foo = { ... }
}
So, in the example above, Foo is not a concrete type Foo, rather Foo is just a symbol that means an arbitrary type which will be made concrete based on the type of parameter passed to the method.
As such, even if there is a concrete type called Foo in the same scope, it is shadowed by the type parameter Foo that has been introduced and any reference to Foo, or an instance of Foo, within the context of that method, is a reference to the abstract type parameter Foo, not the concrete type Foo.