In C++ I can do the following:
template<typename T, typename V>
struct{
void operator()(T _1, V _2){
_2.foo( _1 );
}
};
which lets me arbitrarily decide to use any object which has some method called "foo" that takes some type "T" without specifying in advance either the argument type of the "foo" function nor the return type of said function.
When I look at Scala, see traits like Function1, and am playing around with function definitions like
def foo[T<:{def foo():Unit}]( arg:T ) = //something
def bar( x:{def foo():Unit} ) = //something
def baz[T,V<:Function1[T,_]]( x:T, y:V ) = y( x )
I look at myself and think why can't I do the same thing? Why does "baz" return an Any? Can't it deduce the actual return type at compile time? Why do I have to declare the return type of "foo" if I might not even use it?
I'd like to be able to do
def biff[T,V:{def foo( x:T ):Unit}] = //something
or
def boff[T<:{def foo( x:Double ):_}]( y:T ) = y.foo _
Can you do this and am I just missing something? Or if not, why not?
Comparing Templates and GenericsGenerics are generic until the types are substituted for them at runtime. Templates are specialized at compile time so they are not still parameterized types at runtime.
Templates are the foundation of generic programming, which involves writing code in a way that is independent of any particular type. A template is a blueprint or formula for creating a generic class or a function.
Generics are syntax components of a programming language that can be reused for different types of objects. Typically, generics take the form classes or functions, which take type(s) as a parameter.
C has no templates like C++, though you can achieve something similar with "clever" (or WTFey, depending on how you look at it) use of #define macros. However, take a look at how for example GLib does it for singly linked lists or doubly linked lists.
Update:
Actually, you can do much better, and the type inferencer will help you:
def boff[T,R](y: T)(implicit e: T <:< {def foo(x: Double): R}) = e(y).foo _
For baz
, the same technique will improve type inference:
def baz[T,R,V]( x:T, y:V )(implicit e: V <:< (T => R)) = e(y).apply( x )
scala> baz(1, (i: Int) => i+1)
res0: Int = 2
You can do better by currying:
def baz[T,R](x: T)(f: T => R) = f(x)
First solution:
The type inferencer won't supply the T
type for you, but you can do:
class Boff[T] {
def apply[R](y: T)(implicit e: T <:< {def foo(x: Double): R}) = e(y).foo _
}
object boff {
def apply[T] = new Boff[T]
}
The fundamental distinction between Scala and C++ is that each class in Scala is compiled once, and then becomes available as-is for use with anything that depends on it, whereas a templated class in C++ must be compiled for every new dependency.
So, in fact, a C++ template generates N compiled classes, while Scala generates just one.
Can't it deduce the actual return type at compile time?
Because it must be decided at the time the class is compiled, which may be different than the time its use is compiled.
For foo
:
def foo[R,T<:{def foo():R}]( arg:T ) = ...
In case of baz
, you say that V
must be a function from T
to some type. This type can't appear in result type: how could you write it? So the compiler can only infer that the result type is Any
. If you give it a name, however, you get
scala> def baz[T,R,V<:Function1[T,R]]( x:T, y:V ) = y( x )
baz: [T,R,V <: (T) => R](x: T,y: V)R
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With