Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Self-referential duck-typing

Tags:

scala

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.

like image 432
Michael Lorton Avatar asked Dec 12 '22 17:12

Michael Lorton


1 Answers

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

like image 190
psp Avatar answered Jan 09 '23 11:01

psp