Genie Vala Generics and Nullable Types - gtk3

Simple question: In the following generic class, how should the generic type and contained types be defined so that they are nullable? The following will not compile.
class Pair? of G1, G2: Object
_first:G1?
_second:G2?
construct()
_first = null
_second = null
def insert( first:G1, second:G2 )
_first = first
_second = second
def insert_first( value:G1 )
_first = value
def insert_second( value:G2 )
_second = value
def second():G2
return _second
Usage:
var pair = new Pair() of string, string
pair = null

Due to the way Vala Generics work, generic parameters are always nullable.
As long as you don't switch on --enable-experimental-non-null class variables are nullable as well, so your code simplifies to:
[indent=4]
class Pair of G1, G2: Object
_first:G1
_second:G2
construct()
_first = null
_second = null
def insert( first:G1, second:G2 )
_first = first
_second = second
def insert_first( value:G1 )
_first = value
def insert_second( value:G2 )
_second = value
def second():G2
return _second
init
var pair = new Pair of string, string
pair = null
When --enable-experimental-non-null is on, you have to be explicit in the type of the variable. I don't know how to write this in Genie, I tried this, but the compiler does not like it:
init
pair: Pair? of string, string = new Pair of string, string
pair = null
In Vala it's no problem:
class Pair<G1,G2>: Object {
private G1 first;
private G2 second;
public Pair () {
first = null;
second = null;
}
// ...
}
int main () {
Pair<string, string>? pair = new Pair<string, string> ();
pair = null;
return 0;
}

I can't wrap my head around the concept of a type parameter that has null as the type. I don't think that is a useful concept. So the definition of your class would be:
[indent = 4]
class Pair of G1, G2: Object
_first:G1?
_second:G2?
def insert( first:G1, second:G2 )
_first = first
_second = second
def insert_first( value:G1 )
_first = value
def insert_second( value:G2 )
_second = value
def second():G2
return _second
If you must re-assign the variable that has the object instance to null then it would be:
[indent = 4]
init
var pair = new Pair of string,string()
pair = null
The Vala compiler will, however, dereference pair when it goes out of scope. So I'm not sure why you would need to assign null.
The use of nulls would ideally only be used when interfacing with a C library in my view. Accessing a null can lead to a crash (segmentation fault) if it is not checked for properly. For example:
init
a:int? = 1
a = null
var b = a + 1
The Vala compiler does have an experimental non-null mode that does some checking for unsafe code. If you compile the following with the Vala switch --enable-experimental-non-null:
[indent = 4]
init
var pair = new Pair of string,string()
pair = null
you will get the error:
error: Assignment: Cannot convert fromnull' to Pair<string,string>'
If you understand the consequences then you can tell the compiler this is OK with:
[indent = 4]
init
pair:Pair? = new Pair of string,string()
pair = null

Related

Scala - Using 'this' keyword multiple times one after the other will fail

I've come across an issue where using the this keyword in Scala multiple times within the same method will actually fail.
I cannot replicate the problem here because the codebase is too large, but I will do my best to show the problem.
I have a class, Foo, with an override-able method fooMethod. Inside fooMethod, three property values are generated, and the current class instance is updated with these properties separately, using this. However, only the last this call actually sets any of the properties, the two preceding this calls have no effect on the object.
case class Foo(prop1: prop, prop2: prop2, prop3:prop3) extends FooParent {
override def fooMethod(){
val propA = gen()
val propB = gen()
val propC = gen()
this.withPropA(propA)
this.withPropB(propB)
this.withPropC(propC)
}
def withPropA(:propA): Foo = this.copy(prop1 = propA)
def withPropB(:propB): Foo = this.copy(prop2 = propB)
def withPropC(:propC): Foo = this.copy(prop3 = propC)
}
The above code will only apply the final this.withPropC call, and therefore only prop3 is updated.
However, if I do the following
case class Foo(prop1: prop, prop2: prop2, prop3:prop3) extends FooParent {
override def fooMethod(){
val propA = gen()
val propB = gen()
val propC = gen()
// here
val one = this.withPropA(propA)
val two = one.withPropB(propB)
two.withPropC(propC)
}
def withPropA(:propA): Foo = this.copy(prop1 = propA)
def withPropB(:propB): Foo = this.copy(prop2 = propB)
def withPropC(:propC): Foo = this.copy(prop3 = propC)
}
then all of the properties are updated. Why is this?
Case class are immutable, so copy based functions (like those withProp*) never mutate this.
Moreover, in case of sequential property changes, each update must be applied on the result of previous one (chain); Not on (orginal) this, what would create separate instances corresponding to each unrelated update.
If you really intend to use such functions, it should be
withPropA(propA). // chain update
withPropB(propB). // chain
withPropC(propC)
What can be written:
copy(prop1 = propA, prop2 = propB, prop3 = propC)

What scala expects as a value when it's method accepts '?0' as argument type?

I want to pass a String type argument in a setValue() of vaadin with scala.
Problem :
it shows like def setValue(x$1: ?0): Unit. it means it is expecting some ?0 type of arg.
i don't know how to handle this.
It will be nice if anyone can explain what is this type exactly, what kind of value it accepts and how can I pass String type arg to that method.
Note : setValue(Object newValue) works fine with java.
Here is the code snippet.
def getProcessTreeContainer(): HierarchicalContainer = {
var container = new HierarchicalContainer();
container.addContainerProperty("process", classOf[java.lang.String], null)
val tc = new TableCommon();
var process_menu_data_object_list = tc.getProcessTree();
val size = process_menu_data_object_list.size()
val obj = process_menu_data_object_list.iterator()
while (obj.hasNext()) {
val key = obj.next().id
val parent_key = obj.next().family_id
var name = ""
if (key == parent_key) {
val l = obj.next().name
//println(l.toString()+"...at step 1")
println(("okiiess".asInstanceOf[String]))
var child: Item = container.getItem(container.addItem(key))
child.getItemProperty("process").setValue(l.asInstanceOf)
// arg l.asInstanceOf(), what I am passing in setValue() method, throws NullPointerException.
} else {
container.setParent(key, parent_key)
}
//println("okay...")
}
return container;
}
?0 is not a datatype, it's Scala compiler telling you it doesn't know what the type is. The issue is that child.getItemProperty("process") returns a raw type Property for some reason, which aren't supported in Scala and shouldn't be used in Java either (it should return Property<?> instead). Cast it to Property[String], since you know what its type actually is.

Check if certain string exist in my enum values without NoSuchElement Exception

I have the following code:
object Order extends Enumeration("asc", "desc") {
type OrderType = Value
val asc, desc = Value
}
And i use it:
val someStr:String = "someStr"
val order = Order.withName(someStr)
This gives me the enum of the input string, but if i send string "asc1" i get Exception:
NoSuchElementException: None.get (ProductRequest.scala
My question is - Can i iterate the values and check if the strings exists? This way i can throw better detailed exception..
I was thinking i can iterate Order.values -> but could not find something useful
Thanks
Your could define your Enumeration as:
object Order extends Enumeration {
type OrderType = Value
val asc = Value("asc")
val desc = Value("desc")
def isOrderType(s: String) = values.exists(_.toString == s)
}
And use it:
Order.isOrderType("asc") //> res0: Boolean = true
Order.isOrderType("foo") //> res1: Boolean = false
This seems to do the trick:
object EnumerationTypes extends App {
object Order extends Enumeration {
type OrderType = Value
val asc = Value("asc")
val desc = Value("desc")
def valueOf(name: String) = this.values.find(_.toString == name)
}
println(Order.valueOf("asc")) // Some(asc)
println(Order.valueOf("ascending")) // None
}
It returns None when the string is not valid instead of throwing an exception.

How to mimic Scala's Map/Array assignment syntax in my own class

Following is a simple map entry assignment:
scala> var myl = mutable.Map[String,String]()
myl: scala.collection.mutable.Map[String,String] = Map()
myl("abc") = "123"
I would like to mimic that assignment structure in my own class that works with mutable Tuple's. Now, "getting" a value from a Map is achieved via the "apply" method:
e.g mutable.HashMap:
override def apply(key: A): B = {
val result = findEntry(key)
if (result eq null) default(key)
else result.value
}
I was not however able to find how the map entry is "set" via myMap("myKey") = "myval". A pointer to the Scala source code to do that would be appreciated. Thanks.
The method you want to implement is called update() and takes two parameters, one for the input value passed in parentheses and the other for the assigned value.
class QueryParams {
var params = ""
def update(name: String, value: String) { params += s"$name=$value&" }
}
For example:
val p = new QueryParams()
p("q") = "SFO"
p("start") = "10"
p("rows") = "10"
p.params

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.