5
votes

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?

3
I'm not clear on the biff example. Is there a missing argument?Aaron Novstrup
@Aaron Novstrup no missing argument. I'm getting an error when I state it like that. Says I can't define "V" such that it depends on "T."wheaties

3 Answers

11
votes

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]
}
6
votes

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.

2
votes

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