4

I wish to write a function that operates on any value that can be added to other members of its own type (whatever "added" means in context). The obvious (heh-heh) definition of such a type:

type Addable = { def +(a : Addable) : Addable }

That gives me an error I don't understand at all: recursive method + needs result type

Why isn't that last : Addable the result type? Why does it think + is recursive anyway?

But I found a more general problem, trying to refer to a type inside its own definition:

type T = { def f: T  }     

But then I had a brain-wave: solve it the way I would in Java!

type T[T] = { def f: T  } 

This compiled!

But now I have two more problems.

First, I have no idea how to use type T. In particular,

def n(a:T) = a.f

gives the wholly sensible yet frustrating "type T takes type parameters" error.

Second, attempting to apply this pattern to the original problem

type Addable[Addable] = { def +(a : Addable) : Addable }

leads to a completely incomprehensible "Parameter type in structural refinement may not refer to an abstract type defined outside that refinement". (The actual problem is not that it's "+" -- thank God and Martin, since that would complete mess up my head -- just that it takes an Addable as a parameter.)

So

  1. How do I define a duck-type meaning "has a particular function returning a value of the same type"?
  2. How do I define a duck-type meaning "has a particular function taking a expression of the same type as a parameter"?

I have a religious-like belief that this problem is solvable.

Michael Lorton
  • 43,060
  • 26
  • 103
  • 144
  • 2
    See http://stackoverflow.com/questions/3466100/are-recursive-structural-types-not-supported-in-scala-anymore and http://stackoverflow.com/questions/3201577/scala-how-to-define-a-structural-type-that-refers-to-itself – Michel Krämer Dec 02 '10 at 06:36

1 Answers1

13

Those are different Ts.

scala> type T[T] = { def f: T  } 
defined type alias T

scala> var x: T[Int] = null
x: T[Int] = null

scala> x = new AnyRef { def f = 5 }
x: T[Int] = $anon$1@44daa9f1

When you write:

type Addable[Addable] = { def +(a : Addable) : Addable }

You have a type Addable which takes a single type parameter, also called Addable. Here's a similar variation people often confuse themselves with.

scala> def f[Int](x: Int) = x * x
<console>:7: error: value * is not a member of type parameter Int
       def f[Int](x: Int) = x * x
                              ^

The actual answer to your question is "you can't" but I would hate to shatter your religious-like faith so instead I'll say "structural types work in mysterious ways." If you want to go on a religious mission you might visit here, which explains why you can't.

http://article.gmane.org/gmane.comp.lang.scala/7013

psp
  • 12,138
  • 1
  • 41
  • 51
  • Die, heretic! Actually, the article made it clear why you can't do this in a JVM. I had hoped the Scala would finally solve all my type problems. Ah, well. The Quest continues. – Michael Lorton Dec 02 '10 at 23:13
  • Referring to the linked article: getMethod doesn't require static types. It requires Class objects. Something like 'subject.getClass.getMethod("$plus", Array(subject.getClass))' should work. So I'm still baffeled. – IttayD Dec 04 '10 at 17:23