tags:

views:

127

answers:

3

I want to have classes that can mix only specified traits:

class Peter extends Human with Lawful with Evil
class Mag extends Elf with Chaotic with Neutral

Is in scala a way to do this?

UPD:

trait Law
trait Lawful extends Law
trait LNeutral extends Law
trait Chaotic extends Law

trait Moral
trait Good extends Moral
trait Neutral extends Moral
trait Evil extends Moral

class Hero .........
class Homer extends Hero with Chaotic with Good

I want to define Hero class in way to constrain client programmer to mix specific traits (Lawful/LNeutral/Chaotic and Good/Neutral/Evil) if he extends Hero class. And I want to find some another possibilities to restrictions/constrainments of client code like this.

+7  A: 

Perhaps you're looking for restricting self-type declarations. E.g.:

class Human
trait Lawful
trait Lawless

class NiceGuy
extends Human
{
  this: Lawful =>
}

class BadGuy
extends Human
{
  this: Lawless =>
}


scala> class SuperHero extends NiceGuy
<console>:7: error: illegal inheritance;
 self-type SuperHero does not conform to NiceGuy's selftype NiceGuy with Lawful
       class SuperHero extends NiceGuy
                               ^

scala> class SuperHero extends NiceGuy with Lawful
defined class SuperHero

scala> class SuperVillain extends BadGuy
<console>:7: error: illegal inheritance;
 self-type SuperVillain does not conform to BadGuy's selftype BadGuy with Lawless
       class SuperVillain extends BadGuy
                                  ^

scala> class SuperVillain extends BadGuy with Lawless
defined class SuperVillain
Randall Schulz
A: 

You can check in the constructor of Human and/or Elf if its an instance of the allowed traits:

class Human {
  if (this.instanceOf[Lawful] && this.instanceOf[Chaotic])
    throw new AlignmentException("A Human can only be either Lawful or Chaotic")
}
RoToRa
just for runtime
Jeriho
Well, the original post didn't specify :-)
RoToRa
And I didn't deducted :p
Jeriho
+9  A: 

Tough. Try this:

scala> trait Law[T]
defined trait Law

scala> trait Lawful extends Law[Lawful]
defined trait Lawful

scala> trait Chaotic extends Law[Chaotic]
defined trait Chaotic

scala> class Peter extends Lawful with Chaotic
<console>:8: error: illegal inheritance;
 class Peter inherits different type instances of trait Law:
Law[Chaotic] and Law[Lawful]
       class Peter extends Lawful with Chaotic
             ^

If you want to make it a requirement that a Law type must be extended, then you need to to use self types in some base class or trait:

scala> class Human {
     |   self: Law[_] =>
     | }
defined class Human

scala> class Peter extends Human
<console>:7: error: illegal inheritance;
 self-type Peter does not conform to Human's selftype Human with Law[_]
       class Peter extends Human
                           ^

And there are a few further tweaks to ensure further type safety. The final result might look like this:

sealed abstract trait Law[T <: Law[T]]
trait Lawful extends Law[Lawful]
trait LNeutral extends Law[LNeutral]
trait Chaotic extends Law[Chaotic]

sealed abstract trait Moral[T <: Moral[T]]
trait Good extends Moral[Good]
trait Neutral extends Moral[Neutral]
trait Evil extends Moral[Evil]

class Human {
  self: Law[_] with Moral[_] =>
}
Daniel
All I can say: I love Scala!
Jeriho
Oh, I can say one another thing: when u inherit from human u should write "object James_Raynor extends Human with Chaotic with Good";not object "James_Raynor extends Human with Law[Chaotic] with Moral[Good]"
Jeriho
@Jeriho Well, you can't do that in a file other than the one were `Law` and `Moral` were defined because the traits are `sealed`, meaning you can't subclass them outside that file.
Daniel