Possible to code generic return types in Scala similar to C++ templates?
Asked Answered
F

3

5

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?

Frodine answered 17/11, 2010 at 3:17 Comment(2)
I'm not clear on the biff example. Is there a missing argument?Gronseth
@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."Frodine
G
11

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]
}
Gronseth answered 17/11, 2010 at 3:55 Comment(0)
A
6

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.

Archidiaconal answered 17/11, 2010 at 10:58 Comment(1)
Thanks Daniel. You always provide a great "why."Frodine
P
2

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
Propend answered 17/11, 2010 at 8:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.