I have a class called MAP :
class MAP [KEY,VAL]
inherit ITERABLE [KEY]
I implemented the new cursor inside the map cursor which returns and
MAP_ITERATOR_CURSOR [KEY]
and passes that iterable cursor an array of KEYS to iterate through
I implemented the MAP_ITERATOR_CURSOR [KEY] class
class MAP_ITERATOR_CURSOR [KEY]
inherit ITERATION_CURSOR [KEY]
for this class I implemented the feature item: VAL but because the class was defined with KEY it won't recognize VAL how do I get MAP_ITERATOR_CURSOR [KEY] item feature to return the VAL associated with the key that we are on at the moment ?
Knowing that MAP has a function called item which take key and returns VAL associated with that key
item (k: KEY): VAL
As soon as MAP [KEY, VAL] inherits ITERABLE [KEY], the generic parameter of ITERATION_CURSOR is bound to KEY. However {ITERATION_CURSOR}.item is just a normal feature, that is subject to redeclaration, renaming, etc. Therefore several approaches can fit your need:
Declare MAP_ITERATOR_CURSOR to have two formal generics and declare {MAP}.new_cursor as follows:
class MAP [KEY, VAL] inherit ITERABLE [KEY] feature
new_cursor: MAP_ITERATOR_CURSOR [KEY, VAL]
do
create Result.make (Current)
end
end
class MAP_ITERATOR_CURSOR [KEY, VAL] inherit ITERATION_CURSOR [KEY]
create make
feature
make (t: like target)
do
target := t
end
target: MAP [KEY, VAL]
item: KEY ...
value: VAL
do
Result := target.item (item)
end
end
Then the client code can look as
across map as c loop
-- Use `c.item` of type KEY.
-- Use `c.value` of type VAL.
end
If it is required that {MAP_ITERATOR_CURSOR}.item is of type VAL, the first way is to use exactly the same code as above but rename feature item that comes from ITERABLE:
class MAP_ITERATOR_CURSOR [KEY, VAL] inherit
ITERATION_CURSOR [KEY] rename item as key end
...
key: KEY ...
item: VAL
do
Result := target.item (key)
end
end
Then the client code can look as
across map as c loop
-- Use `c.item` of type VAL.
-- Use `c.key` of type KEY.
end
The iteration can be performed over items of type VAL from the very beginning. In that case the actual generic of ITERABLE should be VAL:
class MAP [KEY, VAL] inherit ITERABLE [VAL] feature
new_cursor: MAP_ITERATOR_CURSOR [KEY, VAL]
do
create Result.make (Current)
end
end
class MAP_ITERATOR_CURSOR [KEY, VAL] inherit ITERATION_CURSOR [VAL]
create make
feature
make (t: like target)
do
target := t
end
target: MAP [KEY, VAL]
item: VAL
do
Result := target.item (key)
end
key: KEY
-- This feature can be not exported, or even not present
-- as soon as `item` can be implemented.
end
The client code is similar to case 2, but key may be unavailable:
across map as c loop
-- Use `c.item` of type VAL.
end
In 3 the formal generic KEY in MAP_ITERATION_CURSOR is kept for convenience. It can be removed provided that there is some way to access items of MAP, but this may raise some other issues related to access to MAP, conformance and CAT-calls. Therefore though it's potentially feasible, I would not go for it.
Why not using TABLE_ITERABLE [G,K] ?
cf https://svn.eiffel.com/eiffelstudio/trunk/Src/library/base/elks/kernel/table_iterable.e
Related
I have the following class structure. The CarModel Class has a defects List which is of Type CarDefects. And I wanted to add the instance of the CarDefects class into this list of defects of carModel which is passed as a parameter for the CarDefects constructor.
However i cannot the use the add method and the error message says the following:
Unresolved reference: add
class CarModel(val brand: Brand, val modelName: String, val version: Int){
var defects: List<CarDefects>? = null
inner class Car(val model: CarModel, val manufactureYear: Int, val engineSerialNum: String){
}
inner class CarDefects(var carModel: CarModel, val affectedYears: Array<Int>, val defectCode: String ) {
init{
carModel.defects.add(//instance of this class)
}
}
}
You have a List as the type of defects. List is immutable, so you can't add more elements to it. You need to use a mutableList to be able to do this.
Here you have more info on this
A generic ordered collection of elements. Methods in this interface support only read-only access to the list; read/write access is supported through the MutableList interface.
Alternatively, you can try to create a new mutable List and add it each time, then convert to list. Something like this.
defects = defects?.toMutableList()?.add(//your car instance).toList()
I am using objects of type Question as the keys in a HashMap. I implemented the hashCode() and equals functions as shown below.
Question.kt
#Parcelize
#Entity(primaryKeys = ["id"])
data class Question(
val id: Int,
val question:String
) : Parcelable{
#Ignore
#IgnoredOnParcel
var isQuestionDimmed: Boolean = false
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Question
if (id != other.id) return false
if (isQuestionDimmed != other.isQuestionDimmed) return false
return true
}
override fun hashCode(): Int {
var result = id
result = 31 * result + isQuestionDimmed.hashCode()
return result
}[![enter image description here][1]][1]
}
fun Question.clone(): Question {
val question = Question(id,question)
question.isQuestionDimmed = isQuestionDimmed
return question
}
Now I create my HashMap as such:
val hm:LinkedHashMap<Question, QuestionAnswerDetails> = hashMapOf()
Now, I expect that when I try to fetch the value of a certain key, the HashMap would use the hashCode() and equals() functions under the hood to locate the pre-inserted value.
This always works, except if I modify a key's "isQuestionDimmed" property. Then, after that, fetching that key always returns null! Although the key exists and has the same hashCode as the key object I am searching with and the equals() function returns true.
Here's a screenshot of my debugging in action:
When using objects as keys in HashMaps, you have to make sure that you satisfy the below conditions:
Updated thanks to #cactustictacs
The key object implements hashCode() fun
The key object implements equals() fun
The key object properties used in hashCode() and equals() implementation are immutable (Not necessarily the whole key object to be immutable)
Why override equals() and hashCode()?
If a class does not override the equals() and hashCode() methods of the Object class and an object of such class is used as a key for map or set in Java, the default implementation of these methods is used which simply checks for reference equality. Reference Thus, you will only be able to access Map values using the exact same key object which you used to add the value originally.
Why should the key object properties used in hashCode() and equals() implementation be immutable?
Because, when first defining let’s say value v1 to k1, the place in memory assigned for (k1,v1) depends on the hashcode calculated the first time (k1,v1) is added to the hashMap according to the hashcode of k1. If you later modify a k1 property that is used in hashCode(), its hashcode will become different but the place in memory for (k1,v1) will remain the same according to the original hashcode of k1. Thus, if you try to fetch the hashmap using k1 after modifying it, the result will be null as it will point to a new location in memory with nothing assigned to it. Same thing for equals(), the properties used in it should be immutable to be able to maintain only unique keys in the HashMap.
How to fix the above code?
Luckily, since Kotlin's data classes give you default implementations of hashCode() and equals() that only use the properties in the primary constructor, we can simply rewrite the code as follows:
#Parcelize
#Entity(primaryKeys = ["id"])
data class Question(
val id: Int,
val question:String
) : Parcelable{
#Ignore
#IgnoredOnParcel
var isQuestionDimmed: Boolean = false
}
Now, you can change the value of isQuestionDimmed freely
Let's imagine that we have data class with two properties and we need secondary constructor for some reasons. Problem is that i need recalculate each argument in primary constructor call instead of using some cached value of raw.split("_"):
data class Id(
val arg1: String,
val arg2: String
) {
constructor(raw: String) : this(raw.split("_")[0], raw.split("_")[1])
}
I can do this in Java but how I can do this in Kotlin?
You can do it this way:
data class Id(
val arg1: String,
val arg2: String
) {
private constructor(splitted: List<String>) : this(splitted[0], splitted[1])
constructor(raw: String) : this(raw.split("_"))
}
It's a good and idiomatic way to solve your problem. Since all secondary constructors must delegate to primary constructor (data class always has it), you can't do what you want in constructor body. In Java it works because there are no primary constructors and no data classes at language level - in Kotlin you can do it like in Java too if you remove data modifier and move properties outside of constructor, but it's a really bad way.
I want to model the following Scala hierarchy in the Inox solver interface:
abstract class Element()
abstract class nonZero() extends Element
final case class Zero() extends Element
final case class One() extends nonZero()
final case class notOne() extends nonZero()
How can I model nonZero?
If I model it as an constructor
def mkConstructor(id: Identifier, flags: Flag*)
(tParamNames: String*)
(sort: Option[Identifier])
(fieldBuilder: Seq[TypeParameter] => Seq[ValDef]) = {
val tParams = tParamNames map TypeParameter.fresh
val tParamDefs = tParams map (TypeParameterDef(_))
val fields = fieldBuilder(tParams)
new ADTConstructor(id, tParamDefs, sort, fields, flags.toSet)
}
Then I'm not able to specify that it has other constructors extending it. Whereas if I model it as a sort:
def mkSort(id: Identifier, flags: Flag*)
(tParamNames: String*)
(cons: Seq[Identifier]) = {
val tParams = tParamNames map TypeParameter.fresh
val tParamDefs = tParams map (TypeParameterDef(_))
new ADTSort(id, tParamDefs, cons, flags.toSet)
}
Then I cannot specify that it is a subtype of Element.
Why do I need this for
I need this hierarchy because I need to state properties as this:
The set of non zero elements of the field with one, inverse and
multiplication by a non zero element forms a group.
I would need then some mechanism to generate a type to restrict the constructors of a sort, in this case, restrict the constructors of Element to One and notZeroOne(). In that case I would be modelling:
abstract class Element()
final case class Zero() extends Element
final case class One() extends Element()
final case class notZeroOne() extends Element()
What is the cleanest solution for this?
Unfortunately, the "class hierarchy" in Inox is limited to a single abstract parent with a sequence of concrete constructors (no subtyping between constructors is possible). This limitation reflects the limitation imposed on the theory of algebraic datatypes supported by the underlying SMT solvers.
If you want to state properties on non-zero elements, why don't you just use an implication of the form (elem !== Zero()) ==> someProperty? Note that in general, you can simulate the nonZero() type proposed above through a concrete predicate that exhaustively enumerates the allowed constructors. For example,
def nonZero(e: Expr): Expr = e.isInstOf(T(one)()) || e.isInstOf(T(notOne)())
Then you can state properties on non-zero elements by using nonZero(e) ==> property(e).
I have a type like this
sealed class Foo[A](val value: A)
object Foo {
def apply[A](v: A)(implicit num: Numeric[A]): Foo[A] =
/* highly complex stuff to make a Foo[A] */
implicit def toA[A](x: Foo[A]) = x.value
}
Foo as a class is only supposed to hold the value, so an implicit Numeric would not make much sense. But I need the type of A to be always a numeric.
So my idea is to just make it impossible to use Foos normal constructor outside of its companion. Is that possible in Scala?
Yeah, since the companion object can access private members of its companion class you can just make the primary (and auxiliary if any) constructor private.
Pseudo code here:
class ConcreteFoo private (n: Int) extends Foo(n)