[scala] Constructor parameters for traits

View: New views
16 Messages — Rating Filter:   Alert me  

[scala] Constructor parameters for traits

by Sebastien Braun :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hello, List.

I know that traits can not have constructor parameters, however I have not
been able to find out much about the rationale behind this restriction; my
google-fu fails me and the SLS is quiet on it (or, maybe, I just don't know
where to look for it).

For this scala code

> trait A {
>   System.out.println("Hello, World!")
> }
>
> class AImpl extends A

scalac will generate (something closely resembling) the following pseudo-Java:

> public interface A {}
>
> public class A$class {
> public static void $init$(A $this) {
> System.out.println("Hello, World!");
> }
> }
>
> public class AImpl implements A {
> public A() {
> A$class.$init$(this);
> }
> }
So, intuitively (and perhaps naïvely...), it seems to me that the compiler
should also be able to accept constructor parameters for traits:

> trait A(message: String) {
> System.out.println(message)
> }

and just tack on the arguments to the $init$ method of the trait's
implementation class:

> public interface A {}
>
> public class A$class {
> public static void $init$(A $this, String message) {
> System.out.println(message);
> }
> }

Is this a bad idea?

Cheers,

Sébastien


signature.asc (204 bytes) Download Attachment

Re: [scala] Constructor parameters for traits

by David MacIver :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I think there's been some discussion of lifting the restriction. I don't believe it has any particular reasoning for it except that it would look scarily like full blown multiple inheritance.

Re: [scala] Constructor parameters for traits

by Ingo Maier-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

The reason why Scala doesn't have them right know is that no one has
worked out reasonable semantics for them yet: order of evaluation, what
happens in the case of diamond inheritance and so on.

We are currently working on adding them though.

Ingo

Sebastien Braun wrote:

> Hello, List.
>
> I know that traits can not have constructor parameters, however I have not
> been able to find out much about the rationale behind this restriction; my
> google-fu fails me and the SLS is quiet on it (or, maybe, I just don't know
> where to look for it).
>
> For this scala code
>
>> trait A {
>>   System.out.println("Hello, World!")
>> }
>>
>> class AImpl extends A
>
> scalac will generate (something closely resembling) the following pseudo-Java:
>
>> public interface A {}
>>
>> public class A$class {
>> public static void $init$(A $this) {
>> System.out.println("Hello, World!");
>> }
>> }
>>
>> public class AImpl implements A {
>> public A() {
>> A$class.$init$(this);
>> }
>> }
>
> So, intuitively (and perhaps naïvely...), it seems to me that the compiler
> should also be able to accept constructor parameters for traits:
>
>> trait A(message: String) {
>> System.out.println(message)
>> }
>
> and just tack on the arguments to the $init$ method of the trait's
> implementation class:
>
>> public interface A {}
>>
>> public class A$class {
>> public static void $init$(A $this, String message) {
>> System.out.println(message);
>> }
>> }
>
> Is this a bad idea?
>
> Cheers,
>
> Sébastien


Re: [scala] Constructor parameters for traits

by James Iry-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Diamond inheritance creates extra complexity.  Here's one example

trait Base(val msg : String}
trait Sub1 extends Base("hello")
trait Sub2 extends Base("goodbye")
Object Test extends Sub1 with Sub2
println(Test.msg) // hello?  goodbye? error?

There are ways for a language to let you resolve diamond inheritance.  But it does complicate things.

On Tue, Dec 2, 2008 at 9:17 AM, Sebastien Braun <sebb@...> wrote:
Hello, List.

I know that traits can not have constructor parameters, however I have not
been able to find out much about the rationale behind this restriction; my
google-fu fails me and the SLS is quiet on it (or, maybe, I just don't know
where to look for it).

For this scala code

> trait A {
>   System.out.println("Hello, World!")
> }
>
> class AImpl extends A

scalac will generate (something closely resembling) the following pseudo-Java:

> public interface A {}
>
> public class A$class {
>       public static void $init$(A $this) {
>               System.out.println("Hello, World!");
>       }
> }
>
> public class AImpl implements A {
>       public A() {
>               A$class.$init$(this);
>       }
> }

So, intuitively (and perhaps naïvely...), it seems to me that the compiler
should also be able to accept constructor parameters for traits:

> trait A(message: String) {
>       System.out.println(message)
> }

and just tack on the arguments to the $init$ method of the trait's
implementation class:

> public interface A {}
>
> public class A$class {
>       public static void $init$(A $this, String message) {
>               System.out.println(message);
>       }
> }

Is this a bad idea?

Cheers,

Sébastien


Re: [scala] Constructor parameters for traits

by Andrés Testi :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

But what about this?:

trait Base{ val msg: String }
trait Sub1 extends Base{ override val msg = "hello" }
trait Sub2 extends Base{ override val msg = "goodbye" }
Object Test extends Sub1 with Sub2

The above code works fine. Why not apply the same rules to solve
diamond inheritance?

- Andrés

2008/12/2 James Iry <jamesiry@...>:

> Diamond inheritance creates extra complexity.  Here's one example
>
> trait Base(val msg : String}
> trait Sub1 extends Base("hello")
> trait Sub2 extends Base("goodbye")
> Object Test extends Sub1 with Sub2
> println(Test.msg) // hello?  goodbye? error?
>
> There are ways for a language to let you resolve diamond inheritance.  But
> it does complicate things.
>
> On Tue, Dec 2, 2008 at 9:17 AM, Sebastien Braun <sebb@...>
> wrote:
>>
>> Hello, List.
>>
>> I know that traits can not have constructor parameters, however I have not
>> been able to find out much about the rationale behind this restriction; my
>> google-fu fails me and the SLS is quiet on it (or, maybe, I just don't
>> know
>> where to look for it).
>>
>> For this scala code
>>
>> > trait A {
>> >   System.out.println("Hello, World!")
>> > }
>> >
>> > class AImpl extends A
>>
>> scalac will generate (something closely resembling) the following
>> pseudo-Java:
>>
>> > public interface A {}
>> >
>> > public class A$class {
>> >       public static void $init$(A $this) {
>> >               System.out.println("Hello, World!");
>> >       }
>> > }
>> >
>> > public class AImpl implements A {
>> >       public A() {
>> >               A$class.$init$(this);
>> >       }
>> > }
>>
>> So, intuitively (and perhaps naïvely...), it seems to me that the compiler
>> should also be able to accept constructor parameters for traits:
>>
>> > trait A(message: String) {
>> >       System.out.println(message)
>> > }
>>
>> and just tack on the arguments to the $init$ method of the trait's
>> implementation class:
>>
>> > public interface A {}
>> >
>> > public class A$class {
>> >       public static void $init$(A $this, String message) {
>> >               System.out.println(message);
>> >       }
>> > }
>>
>> Is this a bad idea?
>>
>> Cheers,
>>
>> Sébastien
>
>

Re: [scala] Constructor parameters for traits

by Andrés Testi :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Oh, sorry, my code doesn't really works :-(

2008/12/2 Andrés Testi <andres.a.testi@...>:

> But what about this?:
>
> trait Base{ val msg: String }
> trait Sub1 extends Base{ override val msg = "hello" }
> trait Sub2 extends Base{ override val msg = "goodbye" }
> Object Test extends Sub1 with Sub2
>
> The above code works fine. Why not apply the same rules to solve
> diamond inheritance?
>
> - Andrés
>
> 2008/12/2 James Iry <jamesiry@...>:
>> Diamond inheritance creates extra complexity.  Here's one example
>>
>> trait Base(val msg : String}
>> trait Sub1 extends Base("hello")
>> trait Sub2 extends Base("goodbye")
>> Object Test extends Sub1 with Sub2
>> println(Test.msg) // hello?  goodbye? error?
>>
>> There are ways for a language to let you resolve diamond inheritance.  But
>> it does complicate things.
>>
>> On Tue, Dec 2, 2008 at 9:17 AM, Sebastien Braun <sebb@...>
>> wrote:
>>>
>>> Hello, List.
>>>
>>> I know that traits can not have constructor parameters, however I have not
>>> been able to find out much about the rationale behind this restriction; my
>>> google-fu fails me and the SLS is quiet on it (or, maybe, I just don't
>>> know
>>> where to look for it).
>>>
>>> For this scala code
>>>
>>> > trait A {
>>> >   System.out.println("Hello, World!")
>>> > }
>>> >
>>> > class AImpl extends A
>>>
>>> scalac will generate (something closely resembling) the following
>>> pseudo-Java:
>>>
>>> > public interface A {}
>>> >
>>> > public class A$class {
>>> >       public static void $init$(A $this) {
>>> >               System.out.println("Hello, World!");
>>> >       }
>>> > }
>>> >
>>> > public class AImpl implements A {
>>> >       public A() {
>>> >               A$class.$init$(this);
>>> >       }
>>> > }
>>>
>>> So, intuitively (and perhaps naïvely...), it seems to me that the compiler
>>> should also be able to accept constructor parameters for traits:
>>>
>>> > trait A(message: String) {
>>> >       System.out.println(message)
>>> > }
>>>
>>> and just tack on the arguments to the $init$ method of the trait's
>>> implementation class:
>>>
>>> > public interface A {}
>>> >
>>> > public class A$class {
>>> >       public static void $init$(A $this, String message) {
>>> >               System.out.println(message);
>>> >       }
>>> > }
>>>
>>> Is this a bad idea?
>>>
>>> Cheers,
>>>
>>> Sébastien
>>
>>
>

Re: [scala] Constructor parameters for traits

by Andrés Testi :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

But my example is yet valid. The compiler refuses my code because msg
in Sub1 was overriding msg in Sub2. Why not apply the same compiler
restrictions on trait constructors?

- Andrés

2008/12/2 Andrés Testi <andres.a.testi@...>:

> Oh, sorry, my code doesn't really works :-(
>
> 2008/12/2 Andrés Testi <andres.a.testi@...>:
>> But what about this?:
>>
>> trait Base{ val msg: String }
>> trait Sub1 extends Base{ override val msg = "hello" }
>> trait Sub2 extends Base{ override val msg = "goodbye" }
>> Object Test extends Sub1 with Sub2
>>
>> The above code works fine. Why not apply the same rules to solve
>> diamond inheritance?
>>
>> - Andrés
>>
>> 2008/12/2 James Iry <jamesiry@...>:
>>> Diamond inheritance creates extra complexity.  Here's one example
>>>
>>> trait Base(val msg : String}
>>> trait Sub1 extends Base("hello")
>>> trait Sub2 extends Base("goodbye")
>>> Object Test extends Sub1 with Sub2
>>> println(Test.msg) // hello?  goodbye? error?
>>>
>>> There are ways for a language to let you resolve diamond inheritance.  But
>>> it does complicate things.
>>>
>>> On Tue, Dec 2, 2008 at 9:17 AM, Sebastien Braun <sebb@...>
>>> wrote:
>>>>
>>>> Hello, List.
>>>>
>>>> I know that traits can not have constructor parameters, however I have not
>>>> been able to find out much about the rationale behind this restriction; my
>>>> google-fu fails me and the SLS is quiet on it (or, maybe, I just don't
>>>> know
>>>> where to look for it).
>>>>
>>>> For this scala code
>>>>
>>>> > trait A {
>>>> >   System.out.println("Hello, World!")
>>>> > }
>>>> >
>>>> > class AImpl extends A
>>>>
>>>> scalac will generate (something closely resembling) the following
>>>> pseudo-Java:
>>>>
>>>> > public interface A {}
>>>> >
>>>> > public class A$class {
>>>> >       public static void $init$(A $this) {
>>>> >               System.out.println("Hello, World!");
>>>> >       }
>>>> > }
>>>> >
>>>> > public class AImpl implements A {
>>>> >       public A() {
>>>> >               A$class.$init$(this);
>>>> >       }
>>>> > }
>>>>
>>>> So, intuitively (and perhaps naïvely...), it seems to me that the compiler
>>>> should also be able to accept constructor parameters for traits:
>>>>
>>>> > trait A(message: String) {
>>>> >       System.out.println(message)
>>>> > }
>>>>
>>>> and just tack on the arguments to the $init$ method of the trait's
>>>> implementation class:
>>>>
>>>> > public interface A {}
>>>> >
>>>> > public class A$class {
>>>> >       public static void $init$(A $this, String message) {
>>>> >               System.out.println(message);
>>>> >       }
>>>> > }
>>>>
>>>> Is this a bad idea?
>>>>
>>>> Cheers,
>>>>
>>>> Sébastien
>>>
>>>
>>
>

Re: [scala] Constructor parameters for traits

by Andrew McCallum :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I'm desperate for trait constructor arguments only because I need a Manifest for my trait's type argument (in order to include code whose behavior depends on the type). Something like:

trait Farm[A <: Animal](implicit m:Manifest[A]) {
  def foo(a:Animal) = if (m.erasure == a.getClass) bar1 else bar2
}

Is there some other recommended work-around?  Of course my true use-case is a bit more complicated.  I'm stuck without a solution.

-Andrew


Andrés Testi wrote:
But my example is yet valid. The compiler refuses my code because msg
in Sub1 was overriding msg in Sub2. Why not apply the same compiler
restrictions on trait constructors?

- Andrés

2008/12/2 Andrés Testi <andres.a.testi@gmail.com>:
> Oh, sorry, my code doesn't really works :-(
>
> 2008/12/2 Andrés Testi <andres.a.testi@gmail.com>:
>> But what about this?:
>>
>> trait Base{ val msg: String }
>> trait Sub1 extends Base{ override val msg = "hello" }
>> trait Sub2 extends Base{ override val msg = "goodbye" }
>> Object Test extends Sub1 with Sub2
>>
>> The above code works fine. Why not apply the same rules to solve
>> diamond inheritance?
>>
>> - Andrés
>>
>> 2008/12/2 James Iry <jamesiry@gmail.com>:
>>> Diamond inheritance creates extra complexity.  Here's one example
>>>
>>> trait Base(val msg : String}
>>> trait Sub1 extends Base("hello")
>>> trait Sub2 extends Base("goodbye")
>>> Object Test extends Sub1 with Sub2
>>> println(Test.msg) // hello?  goodbye? error?
>>>
>>> There are ways for a language to let you resolve diamond inheritance.  But
>>> it does complicate things.
>>>
>>> On Tue, Dec 2, 2008 at 9:17 AM, Sebastien Braun <sebb@yellowhippy.org>
>>> wrote:
>>>>
>>>> Hello, List.
>>>>
>>>> I know that traits can not have constructor parameters, however I have not
>>>> been able to find out much about the rationale behind this restriction; my
>>>> google-fu fails me and the SLS is quiet on it (or, maybe, I just don't
>>>> know
>>>> where to look for it).
>>>>
>>>> For this scala code
>>>>
>>>> > trait A {
>>>> >   System.out.println("Hello, World!")
>>>> > }
>>>> >
>>>> > class AImpl extends A
>>>>
>>>> scalac will generate (something closely resembling) the following
>>>> pseudo-Java:
>>>>
>>>> > public interface A {}
>>>> >
>>>> > public class A$class {
>>>> >       public static void $init$(A $this) {
>>>> >               System.out.println("Hello, World!");
>>>> >       }
>>>> > }
>>>> >
>>>> > public class AImpl implements A {
>>>> >       public A() {
>>>> >               A$class.$init$(this);
>>>> >       }
>>>> > }
>>>>
>>>> So, intuitively (and perhaps naïvely...), it seems to me that the compiler
>>>> should also be able to accept constructor parameters for traits:
>>>>
>>>> > trait A(message: String) {
>>>> >       System.out.println(message)
>>>> > }
>>>>
>>>> and just tack on the arguments to the $init$ method of the trait's
>>>> implementation class:
>>>>
>>>> > public interface A {}
>>>> >
>>>> > public class A$class {
>>>> >       public static void $init$(A $this, String message) {
>>>> >               System.out.println(message);
>>>> >       }
>>>> > }
>>>>
>>>> Is this a bad idea?
>>>>
>>>> Cheers,
>>>>
>>>> Sébastien
>>>
>>>
>>
>

Re: [scala] Constructor parameters for traits

by Miles Sabin :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Tue, Jun 30, 2009 at 2:57 PM, Andrew McCallum<mccallum@...> wrote:

> I'm desperate for trait constructor arguments only because I need a Manifest
> for my trait's type argument (in order to include code whose behavior
> depends on the type). Something like:
>
> trait Farm[A <: Animal](implicit m:Manifest[A]) {
>  def foo(a:Animal) = if (m.erasure == a.getClass) bar1 else bar2
> }
>
> Is there some other recommended work-around?  Of course my true use-case is
> a bit more complicated.  I'm stuck without a solution.

Couldn't you move the implicit parameter to the method?

trait Farm[A <: Animal] {
 def foo(a:Animal)(implicit m:Manifest[A]) = if (m.erasure ==
a.getClass) bar1 else bar2
}

Cheers,


Miles

--
Miles Sabin
tel: +44 (0)7813 944 528
skype:  milessabin
http://www.chuusai.com/
http://twitter.com/milessabin

Re: [scala] Constructor parameters for traits

by Marius Danciu-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Doesn't linearization help here ?

On Tue, Dec 2, 2008 at 8:58 PM, James Iry <jamesiry@...> wrote:
Diamond inheritance creates extra complexity.  Here's one example

trait Base(val msg : String}
trait Sub1 extends Base("hello")
trait Sub2 extends Base("goodbye")
Object Test extends Sub1 with Sub2
println(Test.msg) // hello?  goodbye? error?

There are ways for a language to let you resolve diamond inheritance.  But it does complicate things.


On Tue, Dec 2, 2008 at 9:17 AM, Sebastien Braun <sebb@...> wrote:
Hello, List.

I know that traits can not have constructor parameters, however I have not
been able to find out much about the rationale behind this restriction; my
google-fu fails me and the SLS is quiet on it (or, maybe, I just don't know
where to look for it).

For this scala code

> trait A {
>   System.out.println("Hello, World!")
> }
>
> class AImpl extends A

scalac will generate (something closely resembling) the following pseudo-Java:

> public interface A {}
>
> public class A$class {
>       public static void $init$(A $this) {
>               System.out.println("Hello, World!");
>       }
> }
>
> public class AImpl implements A {
>       public A() {
>               A$class.$init$(this);
>       }
> }

So, intuitively (and perhaps naïvely...), it seems to me that the compiler
should also be able to accept constructor parameters for traits:

> trait A(message: String) {
>       System.out.println(message)
> }

and just tack on the arguments to the $init$ method of the trait's
implementation class:

> public interface A {}
>
> public class A$class {
>       public static void $init$(A $this, String message) {
>               System.out.println(message);
>       }
> }

Is this a bad idea?

Cheers,

Sébastien



Re: [scala] Constructor parameters for traits

by Paul Phillips-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Tue, Jun 30, 2009 at 06:57:30AM -0700, Andrew McCallum wrote:
> I'm desperate for trait constructor arguments only because I need a
> Manifest for my trait's type argument (in order to include code whose
> behavior depends on the type). Something like:
>
> trait Farm[A <: Animal](implicit m:Manifest[A]) {
>   def foo(a:Animal) = if (m.erasure == a.getClass) bar1 else bar2
> }

scala> trait Farm[A <: AnyRef] { def m(implicit man: reflect.Manifest[A]) = man }

scala> (new Farm[String] {}).m
res3: scala.reflect.Manifest[String] = java.lang.String

scala> (new Farm[List[String]] {}).m
res4: scala.reflect.Manifest[List[String]] = scala.collection.immutable.List[java.lang.String]

(Not sure what those Strings are doing on the Farm, but anyway.)

--
Paul Phillips      | If this is raisin, make toast with it.
Future Perfect     |
Empiricist         |
up hill, pi pals!  |----------* http://www.improving.org/paulp/ *----------

Re: [scala] Constructor parameters for traits

by nuttycom :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

The one situation where I've wanted trait constructor arguments is for
a very similar use to the one he describes - I really wish I could do:

trait Interval[T <% Ordered[T]] { ... }

But, of course, view bounds are desugared to add implicit conversion
function parameters to the methods that they annotate, and thus don't
work in this kind of position.

Is there a good way to provide such a trait?

Kris

On Tue, Jun 30, 2009 at 8:16 AM, Paul Phillips<paulp@...> wrote:

> On Tue, Jun 30, 2009 at 06:57:30AM -0700, Andrew McCallum wrote:
>> I'm desperate for trait constructor arguments only because I need a
>> Manifest for my trait's type argument (in order to include code whose
>> behavior depends on the type). Something like:
>>
>> trait Farm[A <: Animal](implicit m:Manifest[A]) {
>>   def foo(a:Animal) = if (m.erasure == a.getClass) bar1 else bar2
>> }
>
> scala> trait Farm[A <: AnyRef] { def m(implicit man: reflect.Manifest[A]) = man }
>
> scala> (new Farm[String] {}).m
> res3: scala.reflect.Manifest[String] = java.lang.String
>
> scala> (new Farm[List[String]] {}).m
> res4: scala.reflect.Manifest[List[String]] = scala.collection.immutable.List[java.lang.String]
>
> (Not sure what those Strings are doing on the Farm, but anyway.)
>
> --
> Paul Phillips      | If this is raisin, make toast with it.
> Future Perfect     |
> Empiricist         |
> up hill, pi pals!  |----------* http://www.improving.org/paulp/ *----------
>

Re: [scala] Constructor parameters for traits

by Andrew McCallum :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Paul,  Thank you for your input.  This solution works if we know the type of the object when method "m" is being called, but unfortunately this isn't true in my use case.  At its heart, I need a Manifest for a type argument inside the implementation of the trait... in a way that will allow me to place the objects conforming to the trait in a collection (among others that do not share precisely the same type arguments).  

Perhaps the thread title "constructor parameters for traits" is the wrong one for me---I don't necessarily need a solution depending on a constructor.  I just need a way to remember the non-erased type of the trait's type argument.

A simple example demonstrating my needs is the following. Below "Restaurant1" and "Restaurant2" must be traits (not classes), because in my actual case it is getting mixed into another set of objects that vary in a different way.

trait Nationality
trait Italian extends Nationality
trait Chinese extends Nationality
trait Japanese extends Nationality
trait Korean extends Nationality

trait Restaurant {
 def feed(customer:Nationality) : String
}
trait Resaurant1[N1<:Nationality] extends Restaurant {
 def m1(implicit man: reflect.Manifest[N1]) = man
 def feed(customer:Nationality) = if (m.erasure == customer.getClass)
"dish" else "sorry"
}
trait Resaurant2[N1<:Nationality,N2<:Nationality] extends Restaurant {
 def m1(implicit man: reflect.Manifest[N1]) = man
 def m2(implicit man: reflect.Manifest[N2]) = man
 def feed(customer:Nationality) = {
   if (m1.erasure == customer.getClass) "somedish" else "sorry"
   if (m2.erasure == customer.getClass) "anotherdish" else "sorry"
 }
}

val restaurants = List(new Restaurant1[Chinese], new
Restaurant2[Chinese,Japanese])
val customer = new Nationality[Japanese]
println(restaurants.map(r => r.feed(customer)))

I could accomplish this by asking my library users to set an instance variable in the trait, but I'm designing a DSL, and a very much want it to be succinct and pretty.

I'd be very appreciative of any help or pointers.

Best wishes,
Andrew



Paul Phillips wrote:
On Tue, Jun 30, 2009 at 06:57:30AM -0700, Andrew McCallum wrote:
> I'm desperate for trait constructor arguments only because I need a
> Manifest for my trait's type argument (in order to include code whose
> behavior depends on the type). Something like:
>
> trait Farm[A <: Animal](implicit m:Manifest[A]) {
>   def foo(a:Animal) = if (m.erasure == a.getClass) bar1 else bar2
> }

scala> trait Farm[A <: AnyRef] { def m(implicit man: reflect.Manifest[A]) = man }

scala> (new Farm[String] {}).m
res3: scala.reflect.Manifest[String] = java.lang.String

scala> (new Farm[List[String]] {}).m
res4: scala.reflect.Manifest[List[String]] = scala.collection.immutable.List[java.lang.String]

(Not sure what those Strings are doing on the Farm, but anyway.)

--
Paul Phillips      | If this is raisin, make toast with it.
Future Perfect     |
Empiricist         |
up hill, pi pals!  |----------* http://www.improving.org/paulp/ *----------

Re: [scala] Constructor parameters for traits

by Paul Phillips-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I believe this does what you want:

% scala andrew
Trying to feed a Japanese at a restaurant serving Chinese
Trying to feed a Japanese at a restaurant serving Chinese, Japanese

// begin code

trait Nationality
trait Italian extends Nationality { override def toString() = "Italian" }
trait Chinese extends Nationality { override def toString() = "Chinese" }
trait Japanese extends Nationality { override def toString() = "Japanese" }
trait Korean extends Nationality { override def toString() = "Korean" }

trait Restaurant {
  def feed(customer: Nationality): String
  def status(customer: String, dishes: String) =
    "Trying to feed a %s at a restaurant serving %s".format(customer, dishes)
}

class Restaurant1Class[N1 <: Nationality](implicit m1: reflect.Manifest[N1]) extends Restaurant {
  def feed(customer: Nationality) = {
    status(customer.toString, m1.toString)
  }
}
trait Restaurant1[N1 <: Nationality] extends Restaurant1Class[N1]

class Restaurant2Class[N1 <: Nationality, N2 <: Nationality](
  implicit m1: reflect.Manifest[N1], m2: reflect.Manifest[N2]) extends Restaurant
{
  def feed(customer: Nationality) = {
    status(customer.toString, List(m1, m2).mkString(", "))
  }
}
trait Restaurant2[N1 <: Nationality, N2 <: Nationality] extends Restaurant2Class[N1, N2]

object andrew
{
  def main(args: Array[String]): Unit = {
    val restaurants = List(new Restaurant1[Chinese] {}, new Restaurant2[Chinese, Japanese] {})
    val customer = new Japanese {}
    restaurants map (_ feed customer) foreach println
  }
}

--
Paul Phillips      | It's not enough to bash in heads - you've got to
Everyman           | bash in minds.
Empiricist         |     -- Capt Hammer
i'll ship a pulp   |----------* http://www.improving.org/paulp/ *----------

Re: [scala] Constructor parameters for traits

by Adriaan Moors-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Being a sucker for questions about typing and implicits, here's my shot:

trait Nationality
class Italian extends Nationality
class Chinese extends Nationality
class Japanese extends Nationality
class Korean extends Nationality

trait Restaurant {
 def feed(customer:Nationality) : String
}

object Restaurant1 {
  def apply[N1<:Nationality](implicit man1: reflect.Manifest[N1]) = new Restaurant1[N1]{val m1 = man1}
}
trait Restaurant1[N1<:Nationality] extends Restaurant {
 implicit val m1: reflect.Manifest[N1]
 
 def feed(customer:Nationality) = 
  if (m1.erasure == customer.getClass) "dish" else "sorry"
}

object Restaurant2 {
  def apply[N1<:Nationality,N2<:Nationality](implicit man1: reflect.Manifest[N1], man2: reflect.Manifest[N2]) = new Restaurant2[N1, N2]{val m1 = man1; val m2 = man2}
}

trait Restaurant2[N1<:Nationality,N2<:Nationality] extends Restaurant {
 implicit val m1: reflect.Manifest[N1]
 implicit val m2: reflect.Manifest[N2]
  
 def feed(customer:Nationality) = 
  if (m1.erasure == customer.getClass) "somedish"
  else if (m2.erasure == customer.getClass) "anotherdish" 
  else "sorry"

}

object Test extends Application {
  val restaurants = List(Restaurant1[Chinese], Restaurant2[Chinese,Japanese])
  val customer = new Japanese
  println(restaurants.map(r => r.feed(customer)))
}

BTW: I would model nationalities differently -- Japanese should be an object, not a trait

On Mon, Aug 31, 2009 at 2:32 PM, Paul Phillips <paulp@...> wrote:
I believe this does what you want:

% scala andrew
Trying to feed a Japanese at a restaurant serving Chinese
Trying to feed a Japanese at a restaurant serving Chinese, Japanese

// begin code

trait Nationality
trait Italian extends Nationality { override def toString() = "Italian" }
trait Chinese extends Nationality { override def toString() = "Chinese" }
trait Japanese extends Nationality { override def toString() = "Japanese" }
trait Korean extends Nationality { override def toString() = "Korean" }

trait Restaurant {
 def feed(customer: Nationality): String
 def status(customer: String, dishes: String) =
   "Trying to feed a %s at a restaurant serving %s".format(customer, dishes)
}

class Restaurant1Class[N1 <: Nationality](implicit m1: reflect.Manifest[N1]) extends Restaurant {
 def feed(customer: Nationality) = {
   status(customer.toString, m1.toString)
 }
}
trait Restaurant1[N1 <: Nationality] extends Restaurant1Class[N1]

class Restaurant2Class[N1 <: Nationality, N2 <: Nationality](
 implicit m1: reflect.Manifest[N1], m2: reflect.Manifest[N2]) extends Restaurant
{
 def feed(customer: Nationality) = {
   status(customer.toString, List(m1, m2).mkString(", "))
 }
}
trait Restaurant2[N1 <: Nationality, N2 <: Nationality] extends Restaurant2Class[N1, N2]

object andrew
{
 def main(args: Array[String]): Unit = {
   val restaurants = List(new Restaurant1[Chinese] {}, new Restaurant2[Chinese, Japanese] {})
   val customer = new Japanese {}
   restaurants map (_ feed customer) foreach println
 }
}

--
Paul Phillips      | It's not enough to bash in heads - you've got to
Everyman           | bash in minds.
Empiricist         |     -- Capt Hammer
i'll ship a pulp   |----------* http://www.improving.org/paulp/ *----------


Parent Message unknown Re: [scala] Constructor parameters for traits

by Paul Phillips-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Wed, Sep 02, 2009 at 10:24:11AM +0200, Andrew McCallum wrote:
> Thank you so much for your fast response.  I was very hopeful about
> this solution.  Then I ran into the following show-stopper.  The
> reason that I need the Restaurants to be traits instead of classes is
> that they must be mixed in with another class hierarchy.  But when I
> try to do the mixin I get an "illegal inheritance" error.

Did you try adriaan's approach? It looks like he was able to model it
without restricting the traits like I did.  I would like to look at it
further but I have a billion things I should really be doing.

--
Paul Phillips      | A Sunday school is a prison in which children do
Everyman           | penance for the evil conscience of their parents.
Empiricist         |     -- H. L. Mencken
ha! spill, pupil   |----------* http://www.improving.org/paulp/ *----------