Reputation: 26008
I wonder, what's the difference between these two:
class SomeClass(val a: Int)
//1
class Class1[T <: SomeClass] {
def method1(param1: T) = ....
}
//2
class Class2 {
def method1(param1: SomeClass) = ....
}
Upvotes: 1
Views: 125
Reputation: 9705
Functionally? Say why some 3rd-party code has the possibility to load those classes will do the following:
class ThirdPatyClass(val a: Int) extends SomeClass(a) with ThirdPartyTrait
An instance of Class1[ThirdPartyClass]
(and a reified corresponding method1
) could be used where there would be a type bound of the form
[S <: ThirdPartyTrait]
whereas Class2
couldn't.
And, of course, depending what you do within those methods, you could return an object of type T
(or anything that uses T
as a bound, e.g. Class[_ <: T]
) in Class1.method1
.
In general, with Class1
you're giving the compiler (and the developer) a possibility to preserve more information on the type of param1
, in contrast with Class2
where you can only preserve the compile-time information that param1
is an instance of SomeClass
.
EDIT: to answer the question from the comment - yes, whether to select one approach or the other depends on what you need. If you require more flexibility and more static type information, go with the the generic type bounds. If not, I'd say you should follow YAGNI and not clutter your API.
Upvotes: 3
Reputation: 4843
Class2
is both a class and a type, while Class1
is only a class. There can never be a value with type Class1
, although there can be any number of parameterised types (Class1[SomeClass]
, Class1[SomeSubClass1]
, Class1[SomeClassType2] etc.), all of which have the same class and will, at run time, only be identifieable as Class1[_]
due to type erasure. This has some practical effects:
Class1
than Class2
.Class1
requires more thought, as variance issues must be considered.On the other hand, because Class1
is parameterised, it is easy to mix in an arbitrary set of traits and know they all apply safely to the same type, without requiring any common inheritance or special equivalence methods. The compiler will catch incompatible type operations.
trait Trait1[T]
def method1: T // Method happens to do something safely compatible with SomeClass
}
trait Trait2[T <: SomeClass]
def method2: T
}
class NewClass[T <: SomeClass] extends Class1[T] with Trait1[T] with Trait2[T]
Upvotes: 1