2

Instead of describing the problem in words, let me just show you a Scala Interpreter session that shows what I want to do.

    scala> class A extends Parent{
         | def name = "Alex"
         | }
    defined class A

    scala> class B extends Parent{
         | def name = "Bernardo"
         | }
    defined class B

    scala> def addFamilyName[T <: Parent](fn:String, c:T{def name():String}) = c.name + " " + fn
    addFamilyName: [T <: Parent](fn: String, c: T{def name(): String})java.lang.String

    scala> addFamilyName( "Martins", new A())
    <console>:11: error: type mismatch;
     found   : A
     required: ?{def name(): String}
           addFamilyName( "Martins", new A())
                             ^

So basically I want to define a type in a parameter that is both a subclass of a certain type and also contains a method with the signature def name():String.

NOTE: I'm trying to do it this way because my class hierarchy is already way to complicated. Given this, I prefer to not add a ParentWithName abstract class or trait if it can be avoided.

  • 2
    The methods `name` and `name()` are _not the same_. While calling the latter can be done with the syntax for the former, they are distinct and structural types, in particular, do not consider them the same. – Daniel C. Sobral Nov 16 '11 at 03:07

1 Answers1

6

Believe it or not, the issue is in the parentheses in the method signature. This works:

def addFamilyName[T <: Parent](fn:String, c:T{def name:String}) =
    c.name + " " + fn

Though I should add you don't actually need a type parameter. This is just as good:

def addFamilyName(fn:String, c:Parent{def name:String}) =
    c.name + " " + fn
Owen
  • 38,836
  • 14
  • 95
  • 125
  • Wow. That was ... unexpected!?! Do you know something I can read to understand why? Either way, next time I have a problem like this I will try adding and removing parenthesis before asking. Thanks. :) – Alexandre Martins Nov 16 '11 at 00:29
  • @Alexandre I'm afraid I do not know why. I suspect it is to prevent ambiguity in the case of methods that return functions, but I'm not sure. – Owen Nov 16 '11 at 00:40
  • Did some digging in the interpreter and came up with a possible explanation for it (I added it to the answer). Thanks a lot for the help once again Owen! – Alexandre Martins Nov 16 '11 at 00:50
  • 1
    @AlexandreMartins This would have worked fine if the types were as `def name() = "Bernardo"`, e.g. `def name` isn't the same as `def name()`, although I don't know the applicable SLS/reason off the top of my head. –  Nov 16 '11 at 00:51
  • @pst - it didn't work. That's why I asked this question. Or did I not understand what you are trying to say?? – Alexandre Martins Nov 16 '11 at 00:57
  • 1
    @AlexandreMartins pst is saying you need to define `name` in class A and B as `name()` (which does work: I tried it!). This question may provide some clues: http://stackoverflow.com/q/7409502/770361 – Luigi Plinge Nov 16 '11 at 01:40
  • 1
    These are different methods. Paulp tried once to get structural type to accept both, but Odersky flat out overruled it. – Daniel C. Sobral Nov 16 '11 at 03:08
  • Thanks for the pointers DanielC.Sobral and @LuigiPlinge. So, methods without parentheses, by conversion, don't have side effects. On the other hand, when using structural typing, you can use "var xxx" and "def xxx" interchangeably even dough "var xxx" clearly has side effects (the change of its own value). I can't quite see the forest here, only the trees. – Alexandre Martins Nov 16 '11 at 18:47
  • @pst I see what you meant now. Thanks! – Alexandre Martins Nov 16 '11 at 18:49