I would like to create a framework where users are able to subclass a base class, Node which is able to produce a message (here an integer) based on the current instance state, and the properties of another instance (the parameter n). The users should be able to specialize the method getMessage to produce different messages based on the class of the current instance and the class of the parameter n, as shown in the code below.
The function importantAlgorithm uses messages generated by these nodes to compute the final results.
// Classes defined by the framework //
abstract class Node {
def getMessage(n: Node) : Int
}
def importantAlgorithm(lstNodes1: List[_ <: Node], lstNodes2: List[_ <: Node]) = {
val results = lstNodes1.zip(lstNodes2).map({case (n1, n2) =>
// I would like to get the proper message *BASED ON
// THE TYPE OF N1 and N2*
val message = n1.getMessage(n2)
// Do some work with the message
//...
//...
})
//...
}
// Classes defined by framework users //
class ItemNode(val p: Int) extends Node {
override def getMessage(n: UserNode) = {
// Compute message based on this ItemNode member variables
// and n (instance of UserNode) member variables
}
override def getMessage(n: ItemNode) = {
// Compute message based on this ItemNode member variables
// and n (instance of UserNode) member variables
// The algorithm is different from the algorithm
// used in the previous method
}
}
class UserNode extends Node {
override def getMessage(n: OtherNode) = {
// Compute message. Same idea as above
}
}
class OtherNode extends Node {
override def getMessage(n: UserNode) = {
// Compute message. Same idea as above
}
}
// The user should be able to use the framework this way
importantAlgorithm(List(new UserNode(), new ItemNode(236), new OtherNode(),
List(new OtherNode(), new ItemNode(542), new UserNode()))
Of course, Scala does not allow to specialize a parameter of a method in a subclass and the above code does not compile. I could use isInstanceOf[] or RTTI but I have a feeling that I am not thinking properly and not designing my framework properly. How could I replace the mechanism described in the code sample above by a simpler and cleaner solution ?
Would this suffice? (It compiles...)
/* Classes defined by the framework */
abstract class Node {
def getMessage(n: Node): Int
}
def importantAlgorithm(lstNodes1: List[Node], lstNodes2: List[Node]) {
lstNodes1.zip(lstNodes2).map {
case (n1, n2) =>
// I would like to get the proper message *BASED ON
// THE TYPE OF N1 and N2*
val message = n1.getMessage(n2)
}
}
/* Classes defined by framework users */
class ItemNode(val p: Int)
extends Node
{
def getMessage(n: Node): Int =
n match {
// Compute message based on this ItemNode member variables
// and n (instance of UserNode) member variables
case un: UserNode => 0
case in: ItemNode => 1
case xn: Node => -1
}
}
class UserNode
extends Node
{
def getMessage(n: Node): Int =
n match {
case on: OtherNode => 23
case xn: Node => -1
}
}
class OtherNode
extends Node
{
def getMessage(n: Node): Int =
n match {
case xn: Node => 514
}
}
// The user should be able to use the framework this way
importantAlgorithm(List(new UserNode(),
new ItemNode(236),
new OtherNode()),
List(new OtherNode(),
new ItemNode(542),
new UserNode()))
I think you need is something like
trait Node {
type AppropriateSender <: Node
def getMessage(n: AppropriateSender): Int
}
class UserNode extends Node {
type AppropriateSender = OtherNode
def getMessage(n: OtherNode) = ???
}
...
However, there are some problems caused by type erasure so that you cannot check the compatibility of your n1 and n2 (maybe type tags?), but at least you can implement your staff in a clean way now. Another issue is how you deal with the fact that some node types have more than 1 appropriate sender type (which might be solved by an implementation of raw union type).
Related
i need your help with this Scala issue that i have.
I have a hierarchy of classes: Vehicle that has only common variables of every vehicle and then 3 subclasses: Car, Truck and MotorCycle, everyone with its own specific variables.
I am using pattern matching in an auxiliary object method to do some transformations depending of the type of vehicle:
object Transformation {
def someTransformation(vehicle:Vehicle):Vehicle = {
vehicle match {
case Car(<<<vars>>>) => Car(<<< transformed vars>>>)
case Truck(<<<vars>>>) => Truck(<<< transformed vars>>>)
case MotorCycle(<<<vars>>>) => MotorCycle(<<< transformed vars>>>)
}
}
}
my problem is when i have to test it, as i am returning a Vehicle (lets say a mixin), i have to cast every time it appears in order to access to the private vars of the vehicle involved.
I want a way to leave this code as it is and in tests access private members without casting, knowing that the vehicle i received as param is the same type as the vehicle i returned.
This can be addressed by generics?, how?
THANK YOU, i hope its understandable.
I think what you want to do is place a restriction on the return type of the function someTransformation. You want someTransformation to only return the type of vehicle that it is called on.
Here's how you can do this with context bounds:
trait Vehicle
case class Car(a: Int) extends Vehicle
case class Truck(b: Int) with Vehicle
case class MotorCycle(c: Int) with Vehicle
object Transformation {
trait Transformer[V <: Vehicle] {
def transform(v: V): V
}
implicit val carTransformer = new Transformer[Car] {
override def transform(c: Car): Car = Car(c.a + 1)
}
implicit val truckTransformer = new Transformer[Truck] {
override def transform(t: Truck): Truck = Truck(t.b + 10)
}
implicit val motorCycleTransformer = new Transformer[MotorCycle] {
override def transform(m: MotorCycle): MotorCycle = MotorCycle(m.c + 100)
}
def someTransformation[V <: Vehicle : Transformer](v: V): V = {
implicitly[Transformer[V]].transform(v)
}
}
Transformation.someTransformation(Car(1)) // results in Car(2)
Transformation.someTransformation(Truck(1)) // results in Truck(11)
Transformation.someTransformation(MotorCycle(1)) // results in MotorCycle(101)
Suppose I have the following:
class Deck[+T] {
class Card(value: T)
class Pile(val cards: List[Card]) {
val deck = Deck.this
def shuffle(shuffler: Shuffler): shuffler.shuffle(this)
}
}
trait Shuffler {
def shuffle[T](pile: Deck[T]#Pile): pile.type
}
object Shuffler {
def randomShuffler(r: Random): Shuffler = new Shuffler {
override def shuffle[T](pile: Deck[T]#Pile): pile.deck.Pile = {
new pile.deck.Pile(r.shuffle(pile.cards))
}
}
}
Is it possible to do the same thing without having the val deck declaration in Pile? Also, is it possible to do the same thing without the T declaration in shuffle()?
I had been playing around with things such as pile: x.Pile forSome {val x: Deck[_]}, but they don't seem to compile due to typing issues (read: me not fully understanding semantics therein), and I'm trying to avoid rewriting Shuffler to, say, work with raw lists instead (how do I express that, anyways? List[Deck[T]#Card] is not quite there, since I want lists of Cards from the same Deck).
Is it possible to do the same thing without having the val deck declaration in Pile?
Not if we want to enforce a value dependent type, which you seem to want (e.g. two Pile[Int] being only compatible if they refer to the same deck value).
Also, is it possible to do the same thing without the T declaration in shuffle()?
You can move type parameters to type members, this can sometimes save you from needing to specify them when they are only internally used.
Here is an idea:
object Pile {
def apply(deck0: Deck): Pile { type D = deck0.type } = new Pile {
val deck = deck0
type D = deck0.type
val cards = deck.cards.toList
}
}
trait Pile { self =>
type D <: Deck
type Self = Pile { type D = self.deck.type }
val deck : D
def cards: List[deck.Card]
def shuffle(shuffler: Shuffler): Self = shuffler.shuffle(this)
}
object Deck {
def apply[A1](values: Set[A1]): Deck { type A = A1 } = new Deck {
type A = A1
val cards = values.map(Card(_))
}
}
trait Deck {
type A
case class Card(value: A)
def cards: Set[Card]
}
trait Shuffler {
def shuffle(pile: Pile): pile.Self
}
object Shuffler {
def randomShuffler(r: util.Random): Shuffler = new Shuffler {
def shuffle(pile: Pile): pile.Self = new Pile {
type D = pile.deck.type
val deck = pile.deck
val cards = r.shuffle(pile.cards)
}
}
}
Test:
val deck = Deck(Set(1 to 10: _*))
val pile0 = Pile(deck)
pile0.cards
val sh = Shuffler.randomShuffler(util.Random)
val pile1 = pile0.shuffle(sh)
pile1.cards
As you can see, enforcing value dependent types is not trivial, so the question is if you really need them, or you are ok with a simple type parameter for A. For example, the above doesn't prevent you from accidentally putting the same card twice into a pile.
To exercise my OOP abilities on Scala-specific features, I have tried to design a game where I have a Player class. It has an abstract method play which decides, given a list of players (different from the player the method is called on), what action to take. I wanted to prevent the play method to alter the state of this other players. The right way to play is to cast a Spell and let the system reflect its effect on other players.
Yet, the play method needs read access to the other players to decide a strategy. I have thus created an inner singleton ReadOnlyPlayer. I made it a singleton to prevent copying over and over and simply returning this singleton everytime.
abstract class Player(private var _health: Int = 0) {
Check.isPositive(_health)
def health = _health
def play(players: List[/*?*/]) // how to denote inner type ReadOnlyPlayer ?
def hit(damage: Int) = { _health = max(0, _health - damage); this }
def safeCopy = ReadOnlyPlayer
final object ReadOnlyPlayer extends Player {
override def health = _health
// noop
override def hit (damage: Int ) = this
override def play(players: List[/*?*/]) = ()
}
}
I can't get it to compile because of the line I put a comment on. I am aware of a number of workarounds to this issue :
if it was a class instead of a singleton, I could use Player#ReadOnlyPlayer. I tried, it works fine. However, this requires to create a new copy everytime, so if I wanted to do this it would actually be better to create a separate immutable class.
I could manually implement a singleton pattern and always return the same instance of this class.
I could make the class private and only declare Player, but I want my clients to know they explicitly know they won't be able to modify the Player instance. I can do this using an sealed empty trait with a meaningful name.
I know how I can handle this in various ways, so my question is more out of curiosity : how can one denote an inner singleton type ?
Note that I'm answering without fully understanding what you're trying to do making a list of inner singletons.
Typically the type of a singleton is accessed by using SingletonName.type. So, in your case, it would look like this:
abstract class Player(private var _health: Int = 0) {
def health = _health
def play(players: List[ReadOnlyPlayer.type]) = ()// how to denote inner type ReadOnlyPlayer ?
def hit(damage: Int) = { _health = Math.max(0, _health - damage); this }
def safeCopy = ReadOnlyPlayer
final object ReadOnlyPlayer extends Player {
override def health = _health
// noop
override def hit (damage: Int ) = this
override def play(players: List[ReadOnlyPlayer.type]) = ()
}
}
As #lloydme pointed it, what I was trying to achieve didn't really make sense. Here is the solution I finally opted for :
sealed trait ReadOnlyPlayer extends Player
abstract class Player(private var _health: Int = 0) {
Check.isPositive(_health)
def health = _health
def play(players: List[ReadOnlyPlayer])
def hit(damage: Int) = { _health = max(0, _health - damage); this }
lazy val safeCopy: ReadOnlyPlayer = ReadOnlyCopy
private object ReadOnlyCopy extends ReadOnlyPlayer {
override def health = _health
// noop
override def hit (damage: Int) = this
override def play(players: List[ReadOnlyPlayer]) = ()
}
}
A list of nested objects:
$ scala
Welcome to Scala version 2.11.7 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_60).
Type in expressions to have them evaluated.
Type :help for more information.
scala> class X(id: Int) { object Y { def y = id } }
defined class X
scala> val xs = List.tabulate(10)(new X(_))
xs: List[X] = List(X#5f77d0f9, X#463fd068, X#895e367, X#1b266842, X#7a3793c7, X#42b3b079, X#651aed93, X#4dd6fd0a, X#bb9e6dc, X#5456afaa)
scala> val Ys = xs map (_.Y)
Ys: List[x$1.Y.type forSome { val x$1: X }] = List(X$Y$#43c67247, X$Y$#fac80, X$Y$#726386ed, X$Y$#649f2009, X$Y$#14bb2297, X$Y$#69adf72c, X$Y$#797501a, X$Y$#1a15b789, X$Y$#57f791c6, X$Y$#51650883)
scala> val ys = Ys map (_.y)
ys: List[Int] = List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
I try to define a parametric type alias :
case class A
case class B
case class C
// We need an Int to load instances of A and B, and a String to load C
object Service {
def loadA(i: Int) : A = ???
def loadB(i: Int) : B = ???
def loadC(s: String) : C = ???
}
trait Location[T] { def get : T}
class IntLocation(val i: Int)
class StringLocation(val s: String)
trait EntityLocation[E] extends Location[_]
// Aim : make the loader typesafe
// Problem : I need something like that : type EntityLocation[Composite] = IntLocation
object Family {
trait EntityLoader[EntityT] extends (EntityLocation[EntityT] => EntityT)
val ALoader = new EntityLoader[A] {def load[A](l: EntityLocation[A]) = Service.loadA(l.get)
}
I am not sure what you are trying to achieve here. Could you please explain how you want to use these types in your code?
Assuming just want to use the types IdLocation and FileLocation in your code, maybe you want to try
trait Location[T] { def get : T }
type IdLocation = Location[Id]
type FileLocation = Location[java.io.File]
Seems rather convoluted, so I'm not sure I follow exactly what your purpose here is. You seem to go into many layers of factories that create factories, that call factory methods, etc.
Seems to me that at the end of the day you need you want to have a val ALoader value that you can use to get instances of A from Location[Int] objects, so I'll go with that assumption:
// Not sure what you want this one, but let's assume that you need a wrapper class per your example.
trait Location[P] { def get: P }
class IntLocation(val i: Int) extends Location[Int]
{
override def get: Int = i
}
// P for parameter, O for output class.
def loader[O, P](creator: P => O)(param: Location[P]) = { creator(param.get) }
object Service
{
// A function somewhere, capable of taking your parameter and creating something else (in your example, an Int to an 'A')
// here Int to String to make something concrete.
// This could be any function, anywhere
def loadA(someParam: Int) = someParam.toString
}
def main(args: Array[String])
{
val myStringLoader: Location[Int] => String = loader(Service.loadA)
// Alternatively, you could have written `val myStringLoader = loader(Service.loadA)(_)`. Either the type or the underscore are needed to tell the compiler that you expect a function, not a value.
// Some definition for you wrapper class
val location3 = new Location[Int]{
override def get: Int = 3
}
// ... or just a plain old instance of it.
val otherLocation = new IntLocation(5)
// This would 'load' the kind of thing you want using the method you specified.
val myString = myStringLoader(location3)
val myOtherString = myStringLoader(otherLocation)
// This prints "3 - 5"
print(myString + " - " + myOtherString)
}
This might seem like a long answer, but in truth the line def loader[O, P](creator: P => O)(param: Location[P]) = { creator(param.get) } is the one that does it all, the rest is to make it as similar to your sample as possible and to provide a working main you can use to start from.
Of course, this would be even simpler if you don't really need the Location wrapper for your integer.
Let's say I've got two traits, one of them being a factory for another:
trait BaseT {
val name: String
def introduceYourself() = println("Hi, I am " +name)
// some other members ...
}
trait BaseTBuilder {
def build: BaseT
}
Now, I want to extend BaseT:
trait ExtendedT extends BaseT {
val someNewCoolField: Int
override def introduceYourself() = {
super.introduceYourself()
println(someNewCoolField)
}
// some other extra fields
Let's say I know how to initialize the new fields, but I'd like to use BaseTBuilder for initializing superclass members. Is there a possibility to create a trait that would be able to instantiate ExtendedT somehow? This approach obviously fails:
trait ExtendedTBuilder { self: TBuilder =>
def build: ExtendedT = {
val base = self.build()
val extended = base.asInstanceOf[ExtendedT] // this cannot work
extended.someNewCoolField = 4 // this cannot work either, assignment to val
extended
}
def buildDifferently: ExtendedT = {
new ExtendedT(4) // this fails, we don't know anything about constructors of ExtendedT
}
def build3: ExtendedT = {
self.build() with {someNewCoolField=5} //that would be cool, but it cannot work either
}
}
I'd like to have such a set of traits (or objects) that when someone supplies concrete implementation of BaseT and BaseTBuilder I could instantiantiate ExtendedT by writing:
val extendedBuilder = new ConcreteBaseTBuilder with ExtendedTBuilder
val e: ExtendedT = extendedBuilder.build
ExtendedT could contain a field of type BaseT, but then it would require manually proxying all the necessary methods and fields, which is in my opinion a violation of DRY principle. How to solve that?
How about create ExtendBaseT instance in your ExtendBaseTBuilder
trait ExtendBaseTBuilder { self : BaseTBuilder =>
def build: ExtendBaseT = {
new ExtendBaseT {
val someNewCoolField: Int = 3
}
}
}