List items change monitoring when items are instances of class - enthought

With the following code:
from traits.api import HasTraits, List, Int, Instance, on_trait_change
class A(HasTraits):
value = Int(0)
class B(HasTraits):
lst = List(Instance(A,()))
#on_trait_change('lst[]')
def _update(self):
print('changed')
'changed' is printed when the items are changed, as in:
b = B(lst = [A()])
How to make the event fired when the internals of the list items are changed, as in:
b.lst[0].value=1

You can listen to attributes of instances contained in an object using the syntax container:attribute_name. See below the decorator on the _item_update method:
from traits.api import HasTraits, List, Int, Instance, on_trait_change
class A(HasTraits):
value = Int(0)
class B(HasTraits):
lst = List(Instance(A,()))
#on_trait_change('lst[]')
def _update(self):
print('changed')
#on_trait_change('lst:value')
def _item_update(self, name, new):
print(name, new)
b = B(lst = [A()])
b.lst[0].value=1
This will print:
changed
('value', 1)
The "Semantics" section of the documentation shows all the possible patterns. The following section, on Notification Handler Signatures, lists out the possible listener method signatures.

Related

Scala collection whose elements can construct sibling instances using named parameters and default values?

I want to have a collection of objects, each object a companion of a different class, which classes all share a common method defined in a superclass that can be invoked when looping through the collection with a foreach(). I want the constructors of these sibling-classes to have the same named parameters and default parameter values as each other. Finally, I want to minimize repeated code.
Thus far, I am trying to do this with case classes, since--if it worked--it would eliminate all the duplicated code of the companion-objects for each type. The problem is that if I put all these companion objects into a Set, when I take them out again I lose the default parameters and parameter names.
Here is some example code of what I am describing:
trait MyType {
val param: String
def label = param // all instances of all subclasses have this method
}
case class caseOne(override val param: String = "default") extends MyType
case class caseTwo(override val param: String = "default") extends MyType
object Main extends App {
// I can construct instances using the companion objects' `apply()` method:
val works1 = caseOne(param = "I have been explicitly set").label
// I can construct instances that have the default parameter value
val works2 = caseOne().label
// But what I want to do is something like this:
val set = Set(caseOne, caseTwo)
for {
companion <- set
} {
val fail1 = companion() // Fails to compile--not enough arguments
val fail2 = companion(param = "not default") // Fails also as param has lost its name
val succeeds = companion("nameless param") // this works but not what I want
println(fail1.label + fail2.label) // this line is my goal
}
}
Notably if the Set has only one element, then it compiles, suggesting the inferred type of the multi-element Set lacks the parameter name--even though they are the same--and the default values. Also suggesting that if I gave the Set the right type parameter this could work. But what would that type be? Not MyType since that is the type of the companion classes rather that the objects in the Set.
I could define the companion objects explicitly, but that is the repeated code I want to avoid.
How can I loop through my collection, constructing instances of MyType subclasses on each iteration, with constructors that have my desired parameter names and default values? All while minimizing repeated code?
Update: Originally the example code showed caseOne and caseTwo as having different default values for param. That was incorrect; they are now the same.
You're not going to be able to get exactly what you want since you don't really have much control over the auto-generated companion objects. In particular for this to work they would all need to extend a common trait. This is why it fails to compile when the set has more than one companion object; even though they all have a method with the same signature, they don't extend a common trait for the compiler to utilize.
You can use a nested case class and get something very similar though:
trait MyType {
val param: String
def label = param // all instances of all subclasses have this method
}
abstract class MyTypeHelper(default: String) {
case class Case(param: String) extends MyType
def apply(param: String) : Case = Case(param)
def apply(): Case = apply(default)
}
object One extends MyTypeHelper("default one")
object Two extends MyTypeHelper("default two")
object Example {
val works1 = One(param = "I have been explicitly set").label
val works2 = One().label
val set = Set(One, Two)
for {
companion <- set
} {
val a = companion()
val b = companion(param = "not default")
val c = companion("nameless param")
println(a.label + b.label)
}
}
Instead of having a caseOne type, you have One.Case, but it still implements MyType so you shouldn't have any issue anywhere else in the code that uses that trait.

How to initialize transient fields during deserialization?

Following code shows serialization and deserialization of simple classes using Jackson. Trouble is during deserialization normal constructor of Root is not called, and therefore the transient fields name of Leaf classes do not have values they had when constructed originally. Is there some way how to provide the transient fields with desired values, without having to make them vars? Some custom serializer or some clever annotations?
I do not want to serialize name values to keep the serialized format as compact as possible - after all the value is given by the data structure and it should be possible to recreate it from the structure again.
import com.fasterxml.jackson.annotation._
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper
class Leaf(val value:Int, #transient val name:String) {
def this(#JsonProperty value:Int) = this(value,"")
}
class Root(val a: Leaf, val b:Leaf)
object Main extends App {
val om = new ObjectMapper() with ScalaObjectMapper {
registerModule(new DefaultScalaModule)
}
val root = new Root(new Leaf(1,"a"), new Leaf(2, "b"))
val out = om.writeValueAsString(root)
println(out)
val test = om.readValue(out, classOf[Root])
}
You could always use a method to name the Leaf instances in the alternate constructor. This method could even retain state if necessary. For example, the following will alternate calling each leaf a or b:
class Leaf(val value: Int, #transient val name: String) {
def this(#JsonProperty value:Int) = {
this(value, Leaf.namer.next)
}
}
object Leaf {
private val namer = Iterator.continually(Seq("a", "b")).flatten
}
Handling subobjects as part of the owning object
Even if Leaf objects are separate JVM objects, from serialization point of view they can be handled as part of the Root object and all the naming can be done by its constructor. For this constructor params need to be annotated and getters created and annotated accessing inner Leaf values, while the Leaf values itself are marked #transient:
class Leaf(val value:Int, val name:String)
class Root(
#(JsonProperty #param)("a") aVal: Int,
#(JsonProperty #param)("b") bVal:Int
) {
#transient val a = new Leaf(aVal,"a")
#transient val b = new Leaf(bVal,"b")
#(JsonProperty #getter) def getA = a.value
#(JsonProperty #getter) def getB = b.value
}
Using #JsonDeserialier(as)
Another option is to use #JsonDeserialier(as=xxx) annotation, then you need to create subclasses for each transient value needed:
class LeafA(value:Int) extends Leaf(value,"a")
class LeafB(value:Int) extends Leaf(value,"b")
case class Root(
#JsonDeserialize(as=classOf[LeafA]) a: Leaf,
#JsonDeserialize(as=classOf[LeafB]) b: Leaf
)
I would have one question: what needs to know the leaf name?
1) From you example alone, no one. Or maybe Root, but it already knows which leaf is a or b, because it is the name of the variable. In this case, just remove the name from Leaf, and what ever method needs to get a name should get it from the Root object. Eg:
case class Leaf(value: Int)
class Root(val a: Leaf, val b: Leaf){
def getLeavesWithName(): ((Leaf, String), (Leaf, String)) =
((a, "a"), (b,"b"))
This can be generalized, for example to a seq of leaves, by implementing the suitable naming rules in Root.
2) For some reason, Leaf can be of one of two types, which is related to its containing Root but can be treated independently from it.
In this case, use simple trait/(case)class hierarchy:
trait Leaf{
val value: Int
def name: String
}
case class LeafA(value: Int){ def name = "a" }
case class LeafB(value: Int){ def name = "b" }
case class Root(a: LeafA, b: LeafB)
3) Leaf needs to have a name independent of Root, but there is no specific rules about naming: You simply use "a" and "b" in some cases, but that could be anything.
In this case, simply keep name in the Leaf serialization (no #transient)
Now, which ever choice you make about the above, if your question is about optimizing the serialization of Root without leaves name, or type, because Root implies it, then simply don't serialize Leaf object within Root serialization.
I'm not familiar with the serialization API you're using, so I cannot tell how to do it. But what you need is
- a Serializer[Root](w: Root) = Serializer[(Int, Int)].write(w.a, w.b) that stores the values of a and b, and
- a Deserializer[Root](obj) = Deserializer[(Int, Int)].map((a,b) => new Root(a,b)) that takes those an make a Root instance.
You get what I mean

Enum.Value vs Enum#Value

I'm learning Scala coming from a Java background, and the first thing I've found that works significantly differently than Java are the Enums. I've managed to accomplish everything I've wanted to just by trial and error, but I'd love to better understand what I'm doing along the way.
From the Scala documentation, I'm told to create an enum by extending the class Enumeration, and add values by setting them equal to a constant Value, eg:
object Label extends Enumeration{
val NONE = Value
}
This works about as expected. My trouble comes in using not only enums but extensions of custom written enum extensions. I wrote a chunk of code as part of a Machine Learning class (now over) to separate data by their labels (for use in TDIDT, for example). At the bottom is a small piece of it to get at where I'm confused. The Data object is runnable, just to try it out.
First, on the print statement, I thought it would be true, but it is not
println(Label.NONE.equals(MessageLabel.NONE))//Thought this would be true, is false
Why is this the case? Is that even though the NONE that MessageLabel has inherited is directly from Label, the type system insists that they are different enum values?
Secondly and more importantly I've been going back and forth between Label.Value and Label#Value basically willy-nilly. The version that I posted with:
def splitByLabel[T <: Label#Value]
trait Labelable[T <: Label#Value]
abstract class Data[T <: Label#Value]
class Message( ... val label : MessageLabel.Value)
Compiles and runs correctly. When I change all the #s to ., I get a compile time error on the line splitByLabel(messages).foreach(a => println(a)), stating:
Inferred type arguments [MessageLabel.Value] do not conform to method splitByLabel's type parameter bounds[T <: Label.Value]
But when I change all the .s to #s, I get a compile time error on the line class Message(val index : Int, val s : Map[Double, Int], override val label : MessageLabel#Value) extends Data[MessageLabel#Value](label), stating:
Not Found: Type MessageLabel
So clearly there is a difference between the two and they each fill a specific role. Can someone help me understand what the difference is? Thank you!
/** Enum type all labels should extend. Guarantees access of universal NONE label */
class Label extends Enumeration{
val NONE = Value
}
/** Singleton instance for accessing NONE */
object Label extends Label{}
/** Companion object to all data classes. Hosts helper methods and a runnable main method */
object Data{
/** Returns a map of lists, each list is similarly labeled data. Map is label -> list of data */
def splitByLabel[T <: Label#Value](elms : List[Labelable[T]]) : Map[T, List[Labelable[T]]] = {
def f(acc : Map[T, List[Labelable[T]]], e : Labelable[T]) : Map[T, List[Labelable[T]]] = {
if(acc.contains(e.label)){
val l = acc(e.label)
acc - e.label + ((e.label, (e :: l)))
} else{
acc + ((e.label, List(e)))
}
}
elms.foldLeft(Map[T, List[Labelable[T]]]())(f)
}
def main(args : Array[String]){
println(Label.NONE.equals(MessageLabel.NONE))
val messages : List[Message] = (0 to 10).toList.map(a =>
new Message(a, Map(), if(a % 3 == 0) MessageLabel.HAM else MessageLabel.SPAM))
splitByLabel(messages).foreach(a => println(a))
}
}
/** Implementing classes can be labeled */
trait Labelable[T <: Label#Value]{
/** Returns the label of this thing */
val label : T
/** The possible labelings for this thing */
val labels : List[T]
}
abstract class Data[T <: Label#Value](override val label : T) extends Labelable[T]{
override def toString(): String = {
if (label != null)
label.toString
else
"NO_LABEL"
}
}
object MessageLabel extends Label{
val HAM, SPAM = Value
}
/** An instance represents a sentence. */
class Message(val index : Int, val s : Map[Int, Double], override val label : MessageLabel.Value)
extends Data[MessageLabel.Value](label){
/** Returns the possible labelings for a message */
override val labels = MessageLabel.values.toList
/** Adds index to tostring at front */
override def toString() : String = {
index + "-" + super.toString
}
}
Label#Value is the type Value in the type Label. Label.Value is the type Value in the value Label. (It's a bit confusing because you have both class Label and object Label (i.e. a value)). So a MessageLabel.Value is a Label#Value, because MessageLabel is an instance of the type (class) Label. But it isn't a Label.Value, because MessageLabel isn't the value (object) Label. And there is no MessageLabel#Value because there is no class MessageLabel (or trait).
(FWIW I find scala Enumeration very confusing and prefer to use Java enums in my Scala code)
This is not particular to Enumeration.
scala> class A { class B ; val None = new B }
defined class A
scala> class C extends A ; class D extends A
defined class C
defined class D
scala> val c = new C ; val d = new D
c: C = C#45fe3ee3
d: D = D#4cdf35a9
scala> c.None == d.None
res0: Boolean = false
No one would ever expect that to be true. One value is initialized in one (super-) constructor, another in the other.
Also, Value is not a constant; it's a function that says, "Give me another Value." So you're generating a value for each instance.
In Java, you can't extend enums in this sense. To "extend" is to add members or increase the extension, but subclassing means a subset or restricted domain.
This is a case where one prefers composition over inheritance. Given a set of weekdays and of weekend days, I get alldays by adding them, not by extending weekdays with the weekend.
Here is an example of using an Enumeration in a path-dependent way.
Another issue with the code as it stands:
scala> MessageLabel.NONE
res4: MessageLabel.Value = <Invalid enum: no field for #0>
https://issues.scala-lang.org/browse/SI-5147

How to add reusable field to Scala Enumeration?

I would like to extend Scala's implementation of Enumeration with a custom field, say label. That new field should be accessible via the values of that enumeration. Furthermore, that custom field should be part of various implementations of Enumeration.
I am aware of the following questions at Stackoverflow:
How to add a method to Enumeration in Scala?
How do I create an enum in scala that has an extra field
Overriding Scala Enumeration Value
Scala doesn't have enums - what to use instead of an enum
However, none of them solves my issues:
The first issue is that I am able to add a custom field. However, I cannot access that additional field via the Values returned by Enumeration.values. The following code works and prints 2nd enumeration value:
object MyEnum extends Enumeration {
type MyEnum = MyVal
val VALUE_ONE = MyVal()
val VALUE_TWO = MyVal(Some("2nd enumeration value"))
val VALUE_THREE = MyVal(Some("3rd value"))
case class MyVal(label: Option[String] = None) extends Val(nextId)
}
import MyEnum._
println(VALUE_TWO.label.get)
Note that I access the label via one of the values. The following code does not work:
for (value <- MyEnum.values) println(value.label)
The error message is as follows: error: value label is not a member of MyEnum.Value
Obviously, instead of MyEnum.MyVal, MyEnum.Val is used. The latter does not define label, while my custom value would provide field label.
The second issue is that it seems to be possible to introduce a custom Value and Val, respectively, in the context of an Enumeration only. Thus, as far as I know, it is not possible to use such a field across different enums. At least, the following code does not compile:
case class MyVal(label: Option[String] = None) extends Enumeration.Val(nextId)
object MyEnum extends Enumeration {
type MyEnum = MyVal
val VALUE_ONE = MyVal()
val VALUE_TWO = MyVal(Some("2nd enumeration value"))
}
object MySecondEnum extends Enumeration {
type MySecondEnum = MyVal
val VALUE_ONE = MyVal()
val VALUE_TWO = MyVal(Some("2nd enumeration value"))
}
Due to the fact that class Val is protected, case class MyVal cannot access Val -- MyVal is not defined in the context of an enumeration.
Any idea how to solve the above issues?
The first issue is addressed by a recent question, my answer to which got no love.
For that use case, I would write a custom widgets method with the useful type, but my linked answer, which just introduces an implicit conversion, seems pretty handy. I don't know why it's not the canonical solution.
For the second issue, your derived MyVal should just implement a trait.
Sample:
scala> trait Labelled { def label: Option[String] }
defined trait Labelled
scala> object A extends Enumeration { case class AA(label: Option[String]) extends Val with Labelled ; val X = AA(Some("one")) }
defined object A
scala> object B extends Enumeration { case class BB(label: Option[String]) extends Val with Labelled ; val Y = BB(None) }
defined object B
scala> val labels = List(A.X, B.Y)
labels: List[Enumeration#Val with Product with Labelled] = List(X, Y)
scala> labels map (_.label)
res0: List[Option[String]] = List(Some(one), None)

"Stable identifer required" error during companion object import

I'm really new to Scala, and I've come across an error I am unable to solve by myself or through internet searches.
I have a Scala class called "GUI" that represents a JFrame along with a companion class. When I try to import the companion class using import GUI._ I get the error "stable identifier required, but GUI.this.GUI() found".
I made an empty class and companion object and the import worked fine, so I assume that the error is related to something specific to my code. Below is the code in question:
object GUI {
def test:Integer = 1
}
class GUI extends JFrame{
import GUI._
val ICON_LOCATION:File = new File("Images/iMovies.ico");
val ICON:BufferedImage = Ootil.createImage("iMovies.png");
val TITLE:String = "iVideos";
val LICENSE_NAME:String = "OpenBSD";
def GUI(){
setLayout(new BorderLayout());
createGUI();
pack();
setSize(100,100);
setLocationRelativeTo(null);
setVisible(true);
}
def versionMajor: Integer = 1
def versionMinor: Integer = 0
def versionRevision: Integer = 0
def versionPreReleaseID: String = "alpha"
def versionBuildNumber: String = "1b"
private def createGUI():Unit = {
val panel = new JPanel();
panel.setLayout(new BorderLayout());
add(panel, BorderLayout.CENTER);
}
def getIcon():BufferedImage = ICON
def getProgramTitle():String = TITLE
def getConfigOptions():LookAndFeelConfigurationOptions = GUIConfigOptions.CONFIG_OPTIONS;
}
To add to Kipton's answer, there's nothing wrong with doing:
class GUI{
def GUI() {
println("something")
}
}
But the result won't be a constructor -- it will be an ordinary method.
val a = new GUI() won't print anything, but calling a.GUI() will.
This is why you didn't get an error message about defining your constructor incorrectly.
When you run the command import GUI._, Scala needs GUI to always evaluate to the same object. This is only the case when GUI is an object, a package, or a val.
In your code, import GUI._ referred to the method GUI that you defined, because the GUI method is defined in a closer scope than object GUI (the fact that the compiler hasn't encountered the definition of def GUI yet doesn't make a difference).
Since import GUI._ referred to the method GUI, which is not a val, object, or package, you got the error message about GUI not being a stable identifier.
Welcome to the Scala community.
Scala constructors work differently than they do in Java. To fix the error, you should put the body of your previously defined GUI() method directly into the class definition, like so,
class GUI extends JFrame{
import GUI._
val ICON_LOCATION:File = new File("Images/iMovies.ico");
val ICON:BufferedImage = Ootil.createImage("iMovies.png");
val TITLE:String = "iVideos";
val LICENSE_NAME:String = "OpenBSD";
// ** stuff that used to be in method GUI() goes below **
setLayout(new BorderLayout());
createGUI();
pack();
setSize(100,100);
setLocationRelativeTo(null);
setVisible(true);
...
}
It takes a little getting used to, but I think you'll find that Scala's way is a lot nicer.
If you want to define an auxiliary constructor, declare a method def this(...) { ... } whose first expression is a call to the primary constructor (in this case just this(), since it doesn't take parameters).
If you want to add parameters to your primary constructor, you would define the class as
class GUI( << some parameters >> ) extends JFrame { ... }
and then you can use the parameters anywhere in this class body.