Kotlin compiler is giving me error while running below :
fun main() {
val x = object {
val i = 1
val k = "s"
}
val y = x as Planet
if (y is Planet) {
println("Hello " + x.i)
}
}
data class Planet(
var i : Int,
var k : String
)
Error :
Exception in thread "main" java.lang.ClassCastException:
FileKt$main$x$1 cannot be cast to Planet at FileKt.main (File.kt:7)
at FileKt.main (File.kt:-1) at
sun.reflect.NativeMethodAccessorImpl.invoke0
(NativeMethodAccessorImpl.java:-2)
I am unable to understand why i am not able to cast Any object type to specific class object.
Isn't all Kotlin classes inherit from Any super class?
please let me know what i am doing wrong here.
Kotlin is a strongly statically typed language. Every variable and every expression has a type that is known at compile time.
In your example you are not specifying the type, but that does not mean it is unknown at compile time.
Kotlin uses type inference to determine its type. In your case Any.
val x: Any = object {
// ...
}
Any is the root of the Kotlin class hierarchy. Every Kotlin class has Any as a superclass.
This is the reason why you can not cast Any to Planet at runtime.
What you could do is using Kotlin safe-cast as? which returns null instead of an exception:
val planet: Planet? = x as? Planet
What you also can do, if you ever casted a Planet to Any, you can cast it back to Planet.
data class Planet(val name: String)
val pluto: Planet = Planet("Pluto")
val anyPlanet: Any = pluto
val planet: Planet = anyPlanet as Pluto
Thanks to Selvins comments for pointing me to right direction, the problem with my implementation is that i am trying to convert an object to type that is not Planet.
But the problem is that i needed to implement some way to screen the incoming object that is supposed to be of type Planet.
So below is the new implementation where i am checking for property of Planet against the anonymous object, if i get object with any fields other than what is present in Planet it will do nothing.
fun main() {
val x = object {
val i = 1
val k = "s"
}
val i = Planet::class.java.declaredFields.asIterable()
val j = x.javaClass.declaredFields.asIterable()
val b = i.zip(j).all { (f, a) -> f.name == a.name }
if (b){
x.let {
val p = Planet(i=it.i,k=it.k)
Log.d("TAG","$p")
}
}
}
data class Planet( val i: Int, val k: String)
May be not the best way, but feel free to comment.
Related
I want write method to clear this array, so I choose get every element in array and make this to be null, but compiler says this element must be T, In the document, null is a subtype of every type except of those of value class, and I have defined T extends AnyRef, but it does't work.Is there any way to make this work?
scala version: 2.11.12
class CuckooHashTable[T<: AnyRef: ClassTag](val hashFamily: HashFamily[T]) {
private var data:Array[T] = new Array[T](DEFAULT_TABLE_SIZE)
private val numHashFunctions = hashFamily.getNumberOfFunctions
private var currentSize: Int = _
def this(hashFamily: HashFamily[T], size: Int){
this(hashFamily)
data = new Array[T](size)
}
def doclear = {
for(i <- data.indices){
//error line
data(i) = null
}
}
}
object CuckooHashTable{
private val MAX_LOAD = 0.4
private val ALLOWED_REHASHS = 1
private val DEFAULT_TABLE_SIZE = 101
}
T extends AnyRef, but that does not mean that T is a supertype of Null for every T.
It is not type sound because there is one type in Scala that is not a supertype of Null, which is Nothing. For example, one could do this:
val cht = new CuckooHashTable[Nothing](new HashFamily[Nothing])
Since Nothing is the bottom type in Scala (the subtype of every other type), and Null is not a subtype of Nothing, this is not type sound.
A workaround would be to have Null as the lower bound of type T:
class CuckooHashTable[T >: Null <: AnyRef: ClassTag](val hashFamily: HashFamily[T])
Now Nothing is not allowed anymore, the code becomes type sound, and your code compiles.
I am fairly new to Scala and trying to do some code reuse. I have two enums AB and AC, both extend A which is a trait with some common methods.
object AB extends A[AB]{
val X = Value("x")
}
object AC extends A[AC]{
val Y = Value("y")
}
trait A[T] extends Enumeration{
def getProperty(prop: T.Value): String = {
//some code that uses prop.toString
}
I am trying to have a getProperty method that will restrict users to only Enums from the enumeration that it is being called upon.
if I call AB.getProperty() than i should be able to pass only X. if I call AC.getProperty than I should be able to pass only Y
If I have to redesign my classes that is fine. Please let me know how I can achieve this.
Thanks in advance
I am not sure what ConfigProperties is in your code, and why you need the type parameters, but the answer to your question is, declare the parameter type in geProperty as Value -> getProperty(prop: Value).
Value is a nested abstract class in Enumeration, so it will be expanded by the compiler respectively to AB.Value and XY.Value, depending on the instance. A simplified example which you can test in the REPL:
object AB extends A {
val A = Value('A')
val B = Value('B')
}
object XY extends A {
val X = Value('X')
val Y = Value('Y')
}
trait A extends Enumeration {
def getProperty(prop: Value): String = {
//some code that uses prop.toString
prop.toString()
}
}
AB.getProperty(AB.A) // OK
XY.getProperty(XY.Y) // Also OK
// AB.getProperty(XY.X) <- this won't compile
// Error:(21, 20) type mismatch;
// found : A$A238.this.XY.Value
// required: A$A238.this.AB.Value
// AB.getProperty(XY.X)
//
I am currently reading Scala in depth and I struggle with a point about existential types.
Using those sources : https://github.com/jsuereth/scala-in-depth-source/blob/master/chapter6/existential-types/existential.scala
with openjdk 7 and scala 2.10.3
The following instructions gives me a error :
val x = new VariableStore[Int](12)
val d = new Dependencies {}
val t = x.observe(println)
d.addHandle(t)
<console>:14: error: method addHandle in trait Dependencies cannot be accessed in types.Dependencies
Access to protected method addHandle not permitted because
enclosing object $iw is not a subclass of
trait Dependencies in package types where target is defined
d.addHandle(t)
^
And I can't find out why and how I arrive to this error.
Edit 1 :
I added the following code from Kihyo's answer :
class MyDependencies extends Dependencies {
override def addHandle(handle: Ref) = super.addHandle(handle)
}
val x = new VariableStore[Int](12)
val d = new MyDependencies
val t = x.observe(println)
d.addHandle(t) //compiles
It make addHandle public instead of protected.
Now I have the following error message :
type mismatch; found : x.Handle (which expands to) x.HandleClass required: d.Ref (which
expands to) x.Handle forSome { val x: sid.types.obs.Observable }
HandleClass is a Handle and Ref is a Handle of any Observer (if I get it right) so the value t should be accepted as a correct type for the exception.
In the trait Dependencies, addHandle is defined like that:
protected def addHandle(handle : Ref) : Unit
protected means, only subclasses can access this method and thats why you get the error. (which basically tells you exactly that)
Your code could work when you create a subclass that makes addHandle public:
class MyDependencies extends Dependencies {
override def addHandle(handle: Ref) = super.addHandle(handle)
}
val x = new VariableStore[Int](12)
val d = new MyDependencies
val t = x.observe(println)
d.addHandle(t) //compiles
But I have no idea about that example and what you want to do with it.
#Edit1:
I get the same error as you, but I can't explain why. It worked for me when I extend App instead of having a main-method:
object TestObs extends App {
val x = new VariableStore[Int](12)
val d = new MyDependencies
val t = x.observe(println)
d.addHandle(t)
}
Maybe someone else has some insight on this.
I have a feeling that the problem I am facing has something to do with Type Erasure of Scala, but as a newbie I can't put my fingers on it. Need some help here.
First, the code:
class C (val i: Int) {
def mkString() = { println("C.i =" + this.i) }
object C {
implicit val cOrdering = new Ordering [C]
{
def compare (a: C, b: C)=
{
a.i compare b.i;
}
}
Then, I create another class which holds a collection of class 'C' thus:
class ContainerOfC [C] (s:Int) (implicit ordering: cOrdering[C]) {
var internalCollection = new TreeSet[C]()
def + (c:C): ContainerOfC [C] = {
this.internalCollection += c
this
}
def mkStringOfElems () = {
val y = this.internalCollection.toList
println (y.head.i) // <--- Problem here
}
}
This is what REPL tells me:
error: value i is not a member of type parameter C
println(y.head.i)
^
I have checked the type of 'y' out there: it is a List[C]. If so, why am I not allowed to access the 'i'? It is a construction parameter alright, but it is a val and hence, can be treated as a member variable, can't it be?
I have gone through a few of the other related posts in the forum, and Manifests and Typetags are possible ways out here. But, I am not sure if I need to go to that level for this simple use-case.
This have a strange and familiar feeling of "been there, done that".
How about you try to change this:
class ContainerOfC [C] (s:Int) (implicit ordering: cOrdering[C]) { ... }
to this without the type parameter C in the declaration :
class ContainerOfC(s:Int) (implicit ordering: cOrdering[C]) { ... }
The code you showed created a class and specific type C. When you later write class ContainerOfC[C], that C is a type parameter that could be named by any other identifier. It is the same as defining class ContainerOfC[A] where A does not have any relation to the class/type C defined in the earlier code. In your example the type parameter C would shadow the name of the class defined earlier... The error message is indicating that C does not have a value i and that's because the compiler is not referring to the same C than you are thinking of.
Edit: just so you know quickly if we are on the same page without getting bogged down in other compilation errors, here are a few edits to make the code compile and using more commonly used indentation and brace style:
class C(val i: Int) {
def mkString() = println("C.i =" + this.i)
}
object C {
implicit val cOrdering = new Ordering[C] {
def compare(a: C, b: C) = a.i compare b.i
}
}
class ContainerOfC(s: Int)(implicit ordering: Ordering[C]) {
var internalCollection = new collection.mutable.TreeSet[C]()
def +(c: C): ContainerOfC = {
this.internalCollection += c
this
}
def mkStringOfElems() = {
val y = this.internalCollection.toList
println(y.head.i)
}
}
please see the below code. This line is marked as incorrect by Eclipse:
var map = Map[MyEnum,Point]()
I am trying to do the scala equivalent of Java:
private enum Letters{ A,B,C}
private Map<Letters,Integer> thing= new HashMap<Letters,Integer> ();
And this is the file/context in which it is written.
class Point(var x:Int = 0, var y:Int = 0, var hasBeenSet:Boolean = false){
}
object MyEnum extends Enumeration{
MyEnum = Value
val UL,U,UR,L,R,DL,D,DR = Value
}
object MyEnumHolder {
var map = Map[MyEnum,Point]()
MyEnum.values.foreach(x => (map + (x -> new Point()) )
}
I am trying to initialize an instance of the map with each value of the enum mapped to an empty point (that's what is going on in the for each loop).
EDIT: Had to edit because I messed some things up editing the pasted code, but it should be valid now
var map = Map[MyEnum.Value, Point]()
or I prefer
import MyEnum._
var map = Map[MyEnum,Point]()
edit: To give a little explanation of what this means, in the enumeration Value is the name of both a type and a method. type MyEnum = Value is basically just declaring an alias for the Value type, and the next line val UL, U... = Value is calling the method to generate the enums, each of which has type MyEnum.Value. So when declaring the map, you have to refer to this type in order for the key to store enums. You could also use MyEnum.MyEnum, but the reason you declare the type alias in the first place is so you can import it into scope and be able to refer to it just as MyEnum.
You are not putting MyEnums in the map, but values of MyEnum:
var map = Map[MyEnum.Value, Point]()
object MyEnum extends Enumeration {
type MyEnum = Value /* You were missing keyword "type" here */
val UL,U,UR,L,R,DL,D,DR = Value
}
object MyEnumHolder {
import MyEnum.MyEnum /* Import this, otherwise type MyEnum can't be found */
var map = Map[MyEnum, String]()
MyEnum.values.foreach(x => (map + (x -> x.toString)))
}
You might also want to have a look at Case classes vs Enumerations in Scala.
I got it to work with the following. The syntax is a bit wonky, I'll admit.
object MyEnum extends Enumeration {
type MyEnum = Value
val UL, U, UR, L, R, DL, D, DR = Value
}
object Main extends App {
Map[MyEnum.MyEnum, String]()
}
Although I guess it can help for pluralization
object Diaries extends Enumeration {
type Diary = Value
val Steven, Jessica, Bob = Value
}
import Diaries._
val currentDiary = Steven
val interestingDiaries = List[Diary](Steven, Jessica)
So here Diaries is the list of Diary, and Diary is a specific diary in the list.