Generics in Scala: implementing an interface/trait twice?

227 views
Skip to first unread message

Andrei Pozolotin

unread,
Oct 28, 2011, 9:52:03 PM10/28/11
to scala-user
Hello;

there seems to be a strong NO answer to the question:
http://stackoverflow.com/questions/7565673/generics-in-scala-implemen...

but I am curious, what is the underlying reason prevents scala from
doing this?

compiler has access to type information, why not generate overloaded
methods?

is it feasible this feature will become available soon?

thank you;

Andrei

Aleksey Nikiforov

unread,
Oct 29, 2011, 12:42:53 PM10/29/11
to Andrei Pozolotin, scala-user
Lets assume that you want is possible. Then you can have a class C that extends trats trait T[String] and T[Int]. Lets say we have the following method signatures:
foo(t: T[String]) and foo(t: T[Int]). Now we call foo(C). Which method should the overloading resolve to? The kind of typing you are looking for is clearly ambiguous in this case. I'm sure if you look into it you will find more problems with it.

Regardless of how unsound this is theoretically, JVM simply does not allow this kind of inheritance. So this is not possible in practice unless you want to throw away Java interop and roll some kind of a hack to bypass the Java type system.

Simon Ochsenreither

unread,
Oct 29, 2011, 7:08:16 PM10/29/11
to scala...@googlegroups.com, Andrei Pozolotin
I wonder how it is done in C#/CLR ... or if they just disallow the case of ambiguous calls completely, while allowing to implement types with different type parameters.

Andrei Pozolotin

unread,
Oct 29, 2011, 7:23:00 PM10/29/11
to scala-user
Aleksey:

1) thanks for getting back; I am sorry I was not clear in my question;
and after I get myself clear, I found a solution :-)

http://xeno-by.blogspot.com/2011/10/scala-macros-status-update-and-call-for.html

2) so my use case would look like this
(based on various "xeno-by" presentaions):

// trait definition
macro trait Binder [NAME : TYPE] {
protected var NAME : TYPE
protected def bind(service : TYPE) { NAME = service }
protected def unbind(service : TYPE) { NAME = null }
}

// trait consumer: look, ma, no boiler plate!
class Component extends Base
with Binder[runnable : Runnable]
with Binder[callable : Callable] {
}

3) this would produce the following scala class, expressed as java
decompile:

// this is java
public class Component implements $some$auto$generated$interface {

protected Runnable runnable;
protected void bind(Runnable service) { runnable = service }
protected void unbind(Runnable service) { runnable = null }

protected Callable callable;
protected void bind(Callable callable) { callable = service }
protected void unbind(Callable callable) { callable = null }

}

4) I could not find a way how to make this actually work;
can someone please share an example?

thank you;

Andrei.

Eugene Burmako

unread,
Oct 30, 2011, 3:32:36 PM10/30/11
to scala-user
@Andrei. Yep, that would be definitely possible to cover your use case
with macro types.

Actual syntax might be different, since we have to conform to scala
syntactic rules when writing macro invocations. Most likely, it
wouldn't be possible to write "with Binder[runnable : Runnable]",
since the "runnable: Runnable" part doesn't look like a valid type
arguments clause. Something like "with Binder("runnable",
classOf[Runnable])" would definitely work, but it looks awful. I'll
try to come up with something more palatable.

On Oct 30, 2:23 am, Andrei Pozolotin <andrei.pozolo...@gmail.com>
wrote:
> Aleksey:
>
> 1) thanks for getting back; I am sorry I was not clear in my question;
> and after I get myself clear, I found a solution :-)
>
> http://xeno-by.blogspot.com/2011/10/scala-macros-status-update-and-ca...

martin odersky

unread,
Oct 30, 2011, 3:59:17 PM10/30/11
to Eugene Burmako, scala-user
On Sun, Oct 30, 2011 at 8:32 PM, Eugene Burmako <xen...@gmail.com> wrote:
@Andrei. Yep, that would be definitely possible to cover your use case
with macro types.

Hi Eugene,
 
I doubt that. Or at least you have to explain what kind of code you intend to generate and how you change typechecking. The restriction to a single interface instance is burned into both the typechecker and the JVM bytecode model.

Cheers

 -- Martin



--
Martin Odersky
Prof., EPFL and Chairman, Typesafe
PSED, 1015 Lausanne, Switzerland
Tel. EPFL: +41 21 693 6863
Tel. Typesafe: +41 21 691 4967

Eugene Burmako

unread,
Oct 30, 2011, 4:26:22 PM10/30/11
to scala-user
Hi Martin,

From the most recent message of Andrei, I assumed that it's not the
actual inheritance scenario that is important, but rather the desire
to satisfy multiple similar contracts. This scenario can be achieved
with macro types as described by Andrei (btw, mixing in macro types is
one of the points that I wanted to discuss with you upon my return to
Lausanne).

However, macro types are, of course, not real types, so they won't be
available, say, as type constructors. That is, it won't be possible to
write Binder[_] or to pass Binder to some place that wants a type
constructor. The best one can do is to write "type RunnableBinder =
Binder("runnable", classOf[Runnable]); type CallableBinder =
Binder("callable", classOf[Callable])" and then use the generated
types, but nothing more.

@Andrei Long story short, macros provide a workaround for your
scenario. It will be possible to write code that is similar to what
you've written, and it will work, but that won't give you full
integration with the type system. Sorry if I misunderstood your intent
in my previous answer.

All the best,
Eugene

On Oct 30, 10:59 pm, martin odersky <martin.oder...@epfl.ch> wrote:
> Prof., EPFL <http://www.epfl.ch> and Chairman, Typesafe<http://www.typesafe.com>

Eugene Burmako

unread,
Oct 30, 2011, 4:36:22 PM10/30/11
to scala-user
@Simon Yep, thanks to reification, it is possible to inherit from
multiple generic interfaces that differ only in type arguments.
Overloads are resolved using an algorithm that is similar to Scala's.
If there are multiple candidates for an invocation, the algorithm
tries to pick the most specific one. If that is impossible, the call
is considered to be ambiguous, and a compilation error is raised.

On Oct 30, 2:08 am, Simon Ochsenreither

Andrei Pozolotin

unread,
Oct 31, 2011, 8:16:59 PM10/31/11
to scala-user
@Eugene:

On Oct 30, 3:26 pm, Eugene Burmako <xeno...@gmail.com> wrote:
> Hi Martin,
>
> From the most recent message of Andrei, I assumed that it's not the
> actual inheritance scenario that is important, but rather the desire
> to satisfy multiple similar contracts.

correct.

> @Andrei Long story short, macros provide a workaround for your
> scenario. It will be possible to write code that is similar to what
> you've written, and it will work,

great!

do you by chance have an example somewhere on github?

thanks;

Andrei.

Andrei Pozolotin

unread,
Oct 31, 2011, 8:23:26 PM10/31/11
to scala-user
@Martin:

On Oct 30, 2:59 pm, martin odersky <martin.oder...@epfl.ch> wrote:
>
> I doubt that. Or at least you have to explain what kind of code you intend
> to generate and how you change typechecking. The restriction to a single
> interface instance is burned into both the typechecker and the JVM bytecode
> model.
>

in my example above I assumed that scala would generate
bunch of synthetic interfaces on the fly, to merge macros:

// this is java
interface $some$auto$generated$interface extends $binder$Runnable,
$binder$Callable {
@Override
protected void bind(Runnable service) {}
@Override
protected void bind(Callable service) {}
// ...
}

so it is still a single interface instance;

cheers,

Andrei.

Andrei Pozolotin

unread,
Oct 31, 2011, 8:33:00 PM10/31/11
to scala-user
@Eugene:

On Oct 30, 3:36 pm, Eugene Burmako <xeno...@gmail.com> wrote:
> @Simon Yep, thanks to reification, it is possible to inherit from
> multiple generic interfaces that differ only in type arguments.
> Overloads are resolved using an algorithm that is similar to Scala's.
> If there are multiple candidates for an invocation, the algorithm
> tries to pick the most specific one.

this is not my use case, :-)

but : why not apply the same approach with help of scala manifests?
(behind the scene, w/o exposing programmer to manifests themselves)

Andrei.

Andrei Pozolotin

unread,
May 25, 2012, 4:07:12 PM5/25/12
to scala...@googlegroups.com
Eugene: 

now that macros are part of scala, 
how would you express a macro for my use case?

thanks

Andrei.

Eugene Burmako

unread,
May 26, 2012, 1:57:38 PM5/26/12
to scala-user
Unfortunately, macro types won't be a part of Scala 2.10 (not even
under a flag - we simply don't have anything right now, not even a
design). Hence it's hard to answer your question without speculating
(which is something I'm not very good at).

On May 25, 10:07 pm, Andrei Pozolotin <andrei.pozolo...@gmail.com>
wrote:

Andrei Pozolotin

unread,
May 27, 2012, 1:04:44 PM5/27/12
to scala...@googlegroups.com
is it part of your plans? next 12 month?

Eugene Burmako

unread,
May 28, 2012, 1:05:38 PM5/28/12
to scala-user
Yes, macro types are indeed a part of SLICK:
https://www.assembla.com/spaces/typesafe-slick/milestones.

On May 27, 7:04 pm, Andrei Pozolotin <andrei.pozolo...@gmail.com>
Reply all
Reply to author
Forward
0 new messages