The first one is called abstract type member
and the second one is a close analog to Java generics, but there are not complete the same. This is two different ways to achieve the same goal. As Martin Odersky explained is his interview, one reason for having both abstract type members and generic type parameters is orthogonality:
There have always been two notions of abstraction: parameterization
and abstract members. In Java you also have both, but it depends on
what you are abstracting over. In Java you have abstract methods, but
you can't pass a method as a parameter. You don't have abstract
fields, but you can pass a value as a parameter. And similarly you
don't have abstract type members, but you can specify a type as a
parameter. So in Java you also have all three of these, but there's a
distinction about what abstraction principle you can use for what
kinds of things. And you could argue that this distinction is fairly
arbitrary.
What we did in Scala was try to be more complete and orthogonal. We
decided to have the same construction principles for all three sorts
of members. So you can have abstract fields as well as value
parameters. You can pass methods (or "functions") as parameters, or
you can abstract over them. You can specify types as parameters, or
you can abstract over them. And what we get conceptually is that we
can model one in terms of the other. At least in principle, we can
express every sort of parameterization as a form of object-oriented
abstraction. So in a sense you could say Scala is a more orthogonal
and complete language.
He also described a difference between abstract type members and generic type parameters that can show up in practice:
But in practice, when you use type parameterization with many
different things, it leads to an explosion of parameters, and usually,
what's more, in bounds of parameters. At the 1998 ECOOP, Kim Bruce,
Phil Wadler, and I had a paper where we showed that as you increase
the number of things you don't know, the typical program will grow
quadratically. So there are very good reasons not to do parameters,
but to have these abstract members, because they don't give you this
quadratic blow up.
I think that a great and easy example was given by Bill Veners (the creator of ScalaTest):
// Type parameter version
trait FixtureSuite[F] {
// ...
}
and
// Type member version
trait FixtureSuite {
type F
// ...
}
In either case, F would be the type of the fixture parameter to pass into the tests, which suite subclasses would make concrete. Here's an example of a concrete suite of tests that needs a StringBuilder passed into each test, using the type parameter approach:
// Type parameter version
class MySuite extends FixtureSuite[StringBuilder] {
// ...
}
And here's an example of a concrete suite of tests that needs a StringBuilder passed into each test using the abstract type member approach:
// Type member version
class MySuite extends FixtureSuite {
type F = StringBuilder
// ...
}
For example, if you want to pass three different fixture objects into tests, you'll be able to do so, but you'll need to specify three types, one for each parameter. Thus the type parameter approach was choosen, your suite classes could have ended up looking like this:
// Type parameter version
class MySuite extends FixtureSuite3[StringBuilder, ListBuffer, Stack] with MyHandyFixture {
// ...
}
Whereas with the type member approach it will look like this:
// Type member version
class MySuite extends FixtureSuite3 with MyHandyFixture {
// ...
}
So that shows two approaches to the goal in achieving great modular abstraction. More on this topic can be read in this legendary paper on Scalable Components