Why aren't my reflected setters changing my object's field values? - scala

My sample class:
class Thing() {
// Public vars
var one: Int = 1
var two: Int = 2
// Scala-style getter/setter
private var _age: Long = 3
def age: Long = _age
def age_=(a: Long) = _age = a
override def toString(): String = s"one: $one, two: $two, age: $age"
}
// A name -> setter holder class
case class Member(name:String, setter: MethodSymbol)
Now my reflection code and setter invoker:
def analyze[T](classSymbol: ClassSymbol)(implicit tt:TypeTag[T]): List[Member] = {
val tpe = tt.tpe
val classMirror = currentMirror.reflectClass(classSymbol)
tpe.members.filter(p => p.isPublic).collect {
// Ignore the non-methods and methods we don't care about
case (p) if (p.isMethod && tpe.member(TermName(p.name.toString + "_$eq")) != NoSymbol) =>
val setter =
// 1) Scala-stype getters/setters
tpe.members.filter(f => f.name.toString == p.name.toString + "_" && f.isMethod).headOption.map(_.asMethod)
// 2) Public var (no getter/setter)
.orElse(tpe.members.filter(f => f.name.toString == p.name.toString).headOption.map(_.asMethod))
Member(p.name.toString,setter.get)
}.toList
}
def setValue[T](t:T, members: List[Member], field: String, value: Any)(implicit tt:TypeTag[T]) = {
implicit val classTag = ClassTag[T](typeTag[T].mirror.runtimeClass(typeTag[T].tpe))
members.find(_.name == field).map{ m =>
println("--> Setting field "+m.name+" to "+value)
currentMirror.reflect(t).reflectMethod(m.setter)(value)
}
}
And finally my attempted usage:
val obj = new Thing()
println("Before: "+obj)
val members = analyze[Thing](currentMirror.classSymbol(obj.getClass()))
println(members.mkString("\n"))
// Now set some value on a public var
setValue[Thing](obj, members, "one", 99)
println("After: "+obj)
Output shows:
Before: one: 1, two: 2, age: 3
Member(age,method age)
Member(two,variable two)
Member(one,variable one)
--> Setting field one to 99
After: one: 1, two: 2, age: 3
As you can see, reflection correctly differentiated between a getter/setter field and a public var field. Upon attempting to set, it found the field and called the setter w/no exceptions thrown, but... no value actually changed in my object (this is true for either the getter/setter field or var fields). Why am I not seeing the value change?

Found it... posted in case this helps others.
I was filtering on the wrong thing. The setters in Scala have names formatted like "foo_$eq", so I have to look for that pattern. When those methods are called the values in the instance class change as expected. Revised reflection code below:
def analyze[T](classSymbol: ClassSymbol, isGetterSetter:Boolean = false)(implicit tt:TypeTag[T]): List[Member] = {
val tpe = tt.tpe
val Pattern = """(.*)_\$eq""".r
tpe.members.filter(p => p.isPublic).collect {
case p if (p.isMethod && p.name.toString.endsWith("_$eq")) =>
val Pattern(name) = p.name.toString
val setter =
// 1) Scala-stype getters/setters
tpe.members.filter(f => f.name.toString == p.name.toString + "_" && f.isMethod).headOption.map(_.asMethod)
// 2) Public var (no getter/setter)
.orElse(tpe.members.filter(f => f.name.toString == p.name.toString).headOption.map(_.asMethod))
Member(name,setter.get)
}.toList
}

Related

How to dynamically create an Enum type in Scala?

I have a basic enum type Currency that will include all major currencies traded e.g. EUR, USD, JPY, etc. This code I can write or generate one time. However, I'd also like to have strong enum type for all currency pair combinations e.g. EURCHF, USDCHF, etc. Is there any provision in Scala that would allow me to build such a derived enum type dynamically? I could also do it with some script generator from outside ... but I wonder whether it would be possible.
object Ccy extends Enumeration {
type Type = Value
val USD = Value("USD")
val CHF = Value("CHF")
val EUR = Value("EUR")
val GBP = Value("GBP")
val JPY = Value("JPY")
}
object CcyPair extends Enumeration {
type Type = Value
// ??? Ccy.values.toSeq.combinations(2) ...
}
UPDATE using the accepted answer as reference this was my solution implementation:
import scala.language.dynamics
object CcyPair extends Enumeration with Dynamic {
type Type = Value
/*
* contains all currency combinations including the symmetric AB and BA
*/
private val byCcy: Map[(Ccy.Value, Ccy.Value), Value] =
Ccy.values.toSeq.combinations(2).map { case Seq(c1, c2) =>
Seq(
(c1, c2) -> Value(c1.toString + c2.toString),
(c2, c1) -> Value(c2.toString + c1.toString)
)
}.flatten.toMap
/**
* reverse lookup to find currencies by currency pair, needed to find
* the base and risk components.
*/
private val revByCcy = byCcy.toSeq.map { case (((ccyRisk, ccyBase), ccyPair)) =>
ccyPair -> (ccyRisk, ccyBase)
}.toMap
def apply(ccy1: Ccy.Value, ccy2: Ccy.Value): Value = {
assert(ccy1 != ccy2, "currencies should be different")
byCcy((ccy1, ccy2))
}
implicit class DecoratedCcyPair(ccyPair: CcyPair.Type) {
def base: Ccy.Type = {
revByCcy(ccyPair)._1
}
def risk: Ccy.Type = {
revByCcy(ccyPair)._2
}
def name: String = ccyPair.toString()
}
def selectDynamic(ccyPair: String): Value = withName(ccyPair)
}
and then I can do things like:
val ccyPair = CcyPair.EURUSD
// or
val ccyPair = CcyPair(Ccy.EUR, Ccy.USD)
// and then do
println(ccyPair.name)
// and extract their parts like:
// print the base currency of the pair i.e. EUR
println(CcyPair.EURUSD.base)
// print the risk currency of the pair i.e. USD
println(CcyPair.EURUSD.risk)
There is no magic in Scala's Enumeration. The call to the Value function inside simply does some modifications to Enumeration's internal mutable structures. So you just have to call Value for each pair of currencies. The following code will work:
object CcyPair1 extends Enumeration {
Ccy.values.toSeq.combinations(2).foreach {
case Seq(c1, c2) =>
Value(c1.toString + c2.toString)
}
}
It's not very comfortable to work with though. You can access the values only through withName or values functions.
scala> CcyPair1.withName("USDEUR")
res20: CcyPair1.Value = USDEUR
But it's possible to extend this definition, for example, to allow retrieving CcyPair.Value by a pair of Ccy.Values, or to allow access by object fields with Dynamic, or to provide other facilities you may need:
import scala.language.dynamics
object CcyPair2 extends Enumeration with Dynamic {
val byCcy: Map[(Ccy.Value, Ccy.Value), Value] =
Ccy.values.toSeq.combinations(2).map {
case Seq(c1, c2) =>
(c1, c2) -> Value(c1.toString + c2.toString)
}.toMap
def forCcy(ccy1: Ccy.Value, ccy2: Ccy.Value): Value = {
assert(ccy1 != ccy2, "currencies should be different")
if (ccy1 < ccy2) byCcy((ccy1, ccy2))
else byCcy((ccy2, ccy1))
}
def selectDynamic(pairName: String): Value =
withName(pairName)
}
This definition is a bit more useful:
scala> CcyPair2.forCcy(Ccy.USD, Ccy.EUR)
res2: CcyPair2.Value = USDEUR
scala> CcyPair2.forCcy(Ccy.EUR, Ccy.USD)
res3: CcyPair2.Value = USDEUR
scala> CcyPair2.USDCHF
res4: CcyPair2.Value = USDCHF

Getting previous and next element of a value in a Scala enumeration

I would like to add two new operations to a Scala Enumeration to get the previous and the next value given a certain value if it exists. For example, I would like to write something like:
object Nums extends MyNewEnumerationType {
type Nums = Value
val One,Two,Three = Value
}
Nums.nextOf(One) // Some(Two)
Nums.prevOf(One) // None
My idea was to create a new class and add the methods in this way:
class PrevNextEnum extends Enumeration {
val prevOf = values.zip(None +: values.map{_.some}.toSeq).toMap
val nextOf = {
if (values.isEmpty) Map.empty
else values.zip(values.tail.map{_.some}.toSeq :+ None).toMap
}
}
The problem is that this doesn't work because when prevOf and nextOf are initialized, values is empty.
First question: why values is empty and when it is filled with the values?
Second question: how can I implement prevOf and nextOf?
Third question: is it possible to add the methods prevOf and nextOf to the value type instead of the enumeration? Writing One.next feels more natural than writing Num.nextOf(One)
try the following codes:
class PrevNextEnum extends Enumeration {
lazy val prevOf = {
val list = values.toList
val map = list.tail.zip(list.map(Some(_))).toMap + (list.head -> None)
map
}
lazy val nextOf = {
val list = values.toList
val map = (list.zip(list.tail.map(Some(_)) :+ None).toMap)
map
}
}
object Nums extends PrevNextEnum {
type Nums = Value
val One, Two, Three = Value
}
object App extends App {
println(Nums.prevOf(Nums.Two))
println(Nums.nextOf(Nums.One))
println(Nums.nextOf(Nums.Three))
println(Nums.prevOf(Nums.One))
}
Building on the answer of user1484819 :
class PrevNextEnum extends Enumeration {
lazy val prevOf = {
val list = values.toList
val map = list.tail.zip(list).toMap
v:Value => map.get(v)
}
lazy val nextOf = {
val list = values.toList
val map = list.zip(list.tail).toMap
v:Value => map.get(v)
}
}
object Nums extends PrevNextEnum {
type Nums = Value
val One, Two, Three = Value
}
This has basically the same structure, but uses the fact that Map can return Options itself when using get instead of apply.

Overriding toString method in Scala Enumeration

How can I override "toString" to make this Scala code acts like the following Java code.
Code in Scala
object BIT extends Enumeration {
type BIT = Value
val ZERO, ONE, ANY = Value
override def toString() =
this match {
case ANY => "x "
case ZERO=> "0 "
case ONE => "1 "
}
}
val b = ONE
println(ONE) // returns ONE
Wanted toString behaviour should produce same output as the following Java code.
public enum BIT {
ZERO, ONE, ANY;
/** print BIT as 0,1, and X */
public String toString() {
switch (this) {
case ZERO:
return "0 ";
case ONE:
return "1 ";
default://ANY
return "X ";
}
}
}
BIT b = ONE;
System.out.println(b); // returns 1
I think I am overriding the wrong "toString" method.
First, yes you are overriding the wrong toString method. You're overriding the method on the BIT object itself, which is not very useful.
Second, you do this much easier by simply doing
object BIT extends Enumeration {
type BIT = Value
val ZERO = Value("0")
val ONE = Value("1")
val ANY = Value("x")
}
Then you can do
println(BIT.ONE) //prints "1"
If you want to set the value and the string you can do it like this:
scala> object BIT extends Enumeration {
| type BIT = Value
| val ZERO = Value(0, "0")
| val ONE = Value(1, "1")
| val ANY = Value("x")
| }
defined module BIT
scala> BIT.ZERO.toString
res2: String = 0
scala> BIT.ZERO.id
res3: Int = 0
scala> BIT.ANY.id
res4: Int = 2
scala> BIT.ANY.toString
res5: String = x

An example of functional programming in scala

I'm studying scala. It's very promising, thanks to Odersky and all the other authors for their great work.
I took a euler problem (http://projecteuler.net/) to have a more-then-minimal example. And I'm trying to go the functional way. So this is not a "please answer me immediatly or my boss will kill me" but a "please if you've got time, can you help a imperative language programmer to take a journey in the functional world?"
Problem: I want a class for poker hands. A poker Hand is composed by a number of Card, from 0 to 5. I'd like to build the list of Cards one and for all, that is: my Hand class will be immutable, if I want to add a card, then I create a new Hand object.
So I need a collection of Card that can be created as "val", not as var.
First step: constructors, one for each number of cards. But Card's collection is handled in each constructor, so I must have it as var!
Here's the code, Card class is simply a Suit and a Value, passed to constructor as a string ("5S" is the 5 of spades):
class Hand(mycards : List[Card]) {
// this should be val, I guess
private var cards : List[Card] = {
if (mycards.length>5)
throw new IllegalArgumentException(
"Illegal number of cards: " + mycards.length);
sortCards(mycards)
}
// full hand constructor
def this(a : String, b : String, c : String, d : String, e : String) = {
this(Nil)
// assign cards
val cardBuffer = new ListBuffer[Card]()
if ( a!=null ) cardBuffer += new Card(a)
if ( b!=null ) cardBuffer += new Card(b)
if ( c!=null ) cardBuffer += new Card(c)
if ( d!=null ) cardBuffer += new Card(d)
if ( e!=null ) cardBuffer += new Card(e)
cards = sortCards(cardBuffer.toList)
}
// hand with less then 5 cards
def this(a : String, b : String, c : String, d : String) = this(a,b,c,d,null)
def this(a : String, b : String, c : String) = this(a, b, c, null)
def this(a : String, b : String) = this(a, b, null)
def this(a : String) = this(a, null)
def this() = this(Nil)
/* removed */
}
Do you know how to make it the true functional way?
Thanks.
PS: if you really want to know, it's problem 54.
My answer is not about functional aspect of scala, but your code is possible to write shortly using scala sugar:
class Hand(val mycards: List[Card]) {
require (mycards.size <= 5,"can't be more than five cards")
def this(input: String*) = {
this(input.map(c => new Card(c)).toList)
}
}
input: String* in auxiliary constructor says that you can have variable number of arguments (even thousand of strings).
I'm getting input and invoke creation for each new Card with map function, and then pass result to parent constructor which has it's own requirement.
(BTW, mapping from string to Card can be done anonymously, in that manner: this(input.map(new Card(_)).toList))
class Hand(val mycards: List[Card]) {...
Is equable to
class Hand(cards: List[Card]) {
val mycards = cards
...
From now on, if you will try to create more than five cards in hand you'll get java.lang.IllegalArgumentException:
scala> class Card(s: String) {println("Im a :"+s)}
defined class Card
scala> new Hand("one","two","three","four","five","six")
Im a :one
Im a :two
Im a :three
Im a :four
Im a :five
Im a :six
java.lang.IllegalArgumentException: requirement failed: can't be more than five card
at scala.Predef$.require(Predef.scala:157)
at Hand.<init>(<console>:9)
Well, the the var in the code below comes from you not initializing cards from the main constructor:
// this should be val, I guess
private var cards : List[Card] = {
if (mycards.length>5)
throw new IllegalArgumentException(
"Illegal number of cards: " + mycards.length);
sortCards(mycards)
}
So what you need to do is fix the secondary constructor:
// full hand constructor
def this(a : String, b : String, c : String, d : String, e : String) = {
this(Nil)
// assign cards
val cardBuffer = new ListBuffer[Card]()
if ( a!=null ) cardBuffer += new Card(a)
if ( b!=null ) cardBuffer += new Card(b)
if ( c!=null ) cardBuffer += new Card(c)
if ( d!=null ) cardBuffer += new Card(d)
if ( e!=null ) cardBuffer += new Card(e)
cards = sortCards(cardBuffer.toList)
}
THe problemn is simple: you want a list of cards formed by non-null Strings. If I were you, I'd just avoid passing nulls, but... Anyway, the best way to handle that is to convert this into options. The conversion is simple: Option(a) will return Some(a) is a is not null, and None if it is. If you compose a list of that, you can then flatten it to remove the None and convert Some(a) back into a. In other words:
def this(a : String, b : String, c : String, d : String, e : String) =
this(List(a, b, c, d, e).map(Option(_)).flatten.map(Card(_)))
Because in this example you are only allowed to use five cards I would check this at compile time with the use of a Tuple5:
type HandType = (ACard, ACard, ACard, ACard, ACard)
case class Hand(h: HandType)
abstract class ACard {
def exists: Boolean
}
case class Card(value: Int, color: Color) extends ACard {
def exists = true
}
case object NoCard extends ACard {
def exists = false
}
abstract class Color(val c: Int)
case object H extends Color(1)
case object C extends Color(2)
case object S extends Color(3)
case object D extends Color(4)
case object NoColor extends Color(0)
implicit def tuple2Card(t: (Int, Color)) = Card(t._1, t._2)
val h1 = Hand((Card(4, H), Card(6, S), Card(2, S), Card(8, D), NoCard))
val h2 = Hand((4 -> H, 6 -> S, 2 -> S, 8 -> D, NoCard))
println(h1)
println(h2)
h1.h.productIterator foreach { c => println(c.asInstanceOf[ACard].exists) }
Of course in another example when there can be an unspecific number of elements you need to check them at runtime. productIterator only returns a Iterator[Any] but when you use your cards directly by the field-identifiers (_1 .. _5) you will get an ACard.
Firstly, null is evil, use Option instead. Secondly, Scala supports default parameters. So instead of creating all the constructors, you might just wanna use one of them like this:
def this(a: String = null, ..., e: String = null) = ...
or with Option, which is safer.
def this(a: Option[String] = None, ..., e: Option[String] = None) = {
this(Nil)
val cardBuffer = new ListBuffer[Card]()
a foreach { cardBuffer += new Card(_) }
b foreach { cardBuffer += new Card(_) }
c foreach { cardBuffer += new Card(_) }
d foreach { cardBuffer += new Card(_) }
e foreach { cardBuffer += new Card(_) }
cards = sortCards(cardBuffer.toList)
}
So the cards are only added to the buffer if they "exist".
First, we need to fix a compile error in your cards field definition.
Note that in Scala you usually don't have to declare fields. Main constructor parameters already are fields! So, this can be written simpler:
class Hand(cards : List[Card]) {
if (cards.length>5)
throw new IllegalArgumentException(
"Illegal number of cards: " + mycards.length);
Now we have mutability problem. If you want to program in functional style, everything should be immutable, so the "full hand constructor" is not functional at all: it has 6 side-effecting operations, last of which does not compile.
In functional setting, an object can't be modified after its constructor has terminated, so all the code after this(Nil) is useless. You already said that cards is Nil, what else do you want?! So, all the computations have to happen before the main constructor call. We'd like to remove this(Nil) from the top and add this(sortCards(cardBuffer.toList)) to the bottom. Unfortunately, Scala does not allow that. Fortunately, it allows more options to achieve the same than java: first, you can use a nested block like this:
this({
val cardBuffer = ... /* terrible imperativeness */
sortCards(cardBuffer.toList)
})
second, you can use apply method instead of a constructor:
object Hand {
def apply(a : String, b : String, c : String, d : String, e : String) = {
val cardBuffer = ... /* terrible imperativeness */
new Hand(sortCards(cardBuffer.toList))
}
}
Now, let's start getting rid of imperative ListBuffer. First improvement would be to use var of type List[Card]. Making mutability more local will help to remove it later:
// assign cards
var cards = Nil
if ( e!=null ) cards = new Card(e) :: cards
if ( d!=null ) cards = new Card(d) :: cards
if ( c!=null ) cards = new Card(c) :: cards
if ( b!=null ) cards = new Card(b) :: cards
if ( a!=null ) cards = new Card(a) :: cards
sortCards(cards)
Okay, now we can see what exactly we are mutating and can easily remove that mutability:
val fromE = if ( e!=null ) new Card(e) :: Nil else Nil
val fromD = if ( d!=null ) new Card(d) :: fromE else fromE
val fromC = if ( c!=null ) new Card(c) :: fromD else fromD
val fromB = if ( b!=null ) new Card(b) :: fromC else fromC
val fromA = if ( a!=null ) new Card(a) :: fromB else fromB
sortCards(fromA)
Now we have a fair amount of code duplication. Let's remove that in a brute-force way (find a long duplicating piece of code and extract function)!
def prependCard(x : String, cards : List[Card]) =
if ( x!=null ) new Card(x) :: cards else cards
val cards = prependCard(a, prependCard(b,
prependCard(c, prependCard(d,
prependCard(e, Nil)
))
))
sortCards(cards)
Next, very important, transformation would be to replace nullable references with the values of Option type, or remove the empty card concept altogether.
Update:
As requested, I am adding an example of usage of the apply method. Notice that it is declared in object Hand, not class Hand, so it doesn't need an instance of the class (it's similar to static method in java). We just apply the object to parameters: val hand = Hand("5S", "5S", "5S", "5S", "5S").
Attempt using varargs, overloaded + operator, repeated addition in constructor, and Set to eliminate duplicate cards.
package poker
class Hand(private val cards:Set[Card] = Set.empty[Card]) {
def + (card:Card) = {
val hand = new Hand(cards + card)
require(hand.length > length, "Card %s duplicated".format(card))
require(hand.length <= Hand.maxLength, "Hand length > %d".format(Hand.maxLength))
hand
}
def length = cards.size
override def toString = cards.mkString("(", ",", ")")
}
object Hand {
val maxLength = 5
def apply(cards:Card*):Hand = cards.foldLeft(Hand())(_ + _)
private def apply() = new Hand()
}
//-----------------------------------------------------------------------------------------------//
class Card private (override val toString:String)
object Card {
def apply(card:String) = {
require(cardMap.contains(card), "Card %s does not exist".format(card))
cardMap(card)
}
def cards = cardMap.values.toList
private val cardMap = {
val ranks = Range(2,9).inclusive.map { _.toString } ++ List("T", "J", "Q", "K", "A")
val suits = List("c","d","h","s")
(for(r <- ranks; s <- suits) yield (r + s -> new Card(r + s))).toMap
}
}
//-----------------------------------------------------------------------------------------------//
object Test extends App {
Array("1f", "Ac").foreach { s =>
try {
printf("Created card %s successfully\n",Card(s))
} catch {
case e:Exception => printf("Input string %s - %s \n", s, e.getMessage)
}
}
println
for(i <- 0 to 6) {
val cards = Card.cards.slice(0, i)
makeHand(cards)
}
println
val cards1 = List("Ac","Ad","Ac").map { Card(_) }
makeHand(cards1)
println
val hand1 = Hand(List("Ac","Ad").map { Card(_) }:_* )
val card = Card("Ah")
val hand2 = hand1 + card
printf("%s + %s = %s\n", hand1, card, hand2)
def makeHand(cards:List[Card]) =
try {
val hand = Hand(cards: _*)
printf("Created hand %s successfully\n",hand)
} catch {
case e:Exception => printf("Input %s - %s \n", cards, e.getMessage)
}
}

Problem with Scala's getter/setters

I'm currently learning Scala, and just discovered the way to create custom field getters/setters. I have a simple example working:
class Thing(private val a:Int){
override def toString = "Thing[" + a + "]"
private var _value = a
def value = _value
def value_= (newVal:Int) = _value = newVal
}
On the console I can do:
scala> var t = new Thing(2)
t: dylan.code.Thing = Thing[2]
scala> t.value
res1: Int = 2
scala> t.value = 3
scala> t.value
res2: Int = 3
Now I'm trying to bring this concept to a slightly more complicated example; I'll try to whittle the code down to what's relevant:
abstract class CellExpression[Type] extends Publisher[CellUpdateEvent[Type]] with Subscriber[CellUpdateEvent[Type], CellExpression[Type]]{
protected var cachedValue: Type = recalculateValue()
protected def recalculateValue(): Type
protected def changeValue(newValue: Type):Unit = {
val oldValue = value()
if(newValue != oldValue){
cachedValue = newValue
publish(new CellUpdateEvent(this, oldValue, newValue))
}
}
def value() = cachedValue
def notify(pub: CellExpression[Type], event: CellUpdateEvent[Type]) = changeValue(recalculateValue())
}
//....
class CellVariable[Type](private val initialValue:Type) extends CellExpression[Type]{
cachedValue = initialValue
protected def recalculateValue() = { cachedValue }
override def toString = "CellVariable[" + value + "]"
def value_= (newValue:Type) = {changeValue(newValue)}
}
As far as I can tell, I've done what I need to in order to be able to treate value as a field via its getter and setter. But when I try it out in the console, I get:
scala> var i = new CellVariable(2)
i: dylan.code.CellVariable[Int] = CellVariable[2]
scala> i.value = 3
<console>:11: error: reassignment to val
i.value = 3
^
What have I done wrong, and how can I fix it?
I actually stumbled onto the solution.
The line where I declare my value function: def value() = cachedValue is the culprit.
If I remove the parentheses to make the line def value = cachedValue everything seems to work as I expected.
You cannot change values in Scala. A value is assigned once and only once. If you want to do this then you need to use variables instead of values. In other words, change the declaration from val to var.
The problem is inside one of your class definitions and may be on a line without val because I believe that if you neglect to declare a name, then Scala assumes that it is a value and therefore immutable.
Not sure what you want getters and setters for though. Scala enables you to ignore all of that Java overhead.
It is probably the line that says cachedValue = initialValue because it is not declared with var anywhere in that class. The definition in the other class is a different name because it is in a different scope. You would have to say something like class.varname to change a variable defined in another class.