I would like to do dynamic casting for a scala variable, the casting type is stored in a different variable or in the database or provided by the user.
I am new to Scala and have mainly done coding on python. Here we are trying to take Any type input and query the type of the variable as per the type saved in DB eg.: "String/Int" and user-defined classes and cast them before any future processing.
in python:
eval("str('123')")
in scala I have tried
var a = 123.05
a.asInstanceOf['Int']
gives me error
error: identifier expected but string literal found.
And I want the code to be something as follows:
var a = 123.05
var b = "Int"
a.asInstanceOf[b]
gives me error
error: not found: type b
Ok so I have to be fairly exhaustive here because the stuff you're trying to do is tricky due to the static vs dynamic typing difference of scala and python.
First what you're doing in Python is not type casting but rather a conversion.
str(12)
in python takes the integer value 12 and converts it to a (UTF-8 ? dunno in python) string. The same thing in scala would be
12.toString
typecasting in the meantime is basically a pinky promise to the compilers typechecker that you know more than it and it should just believe you. It also should be avoided like the pest because you basically drop all the safety that static typechecking gives you. However there are certain cases where it is unavoidable
in a bit more fundamental terms. lets say you have the following scala snippet
sealed trait Foo
final case class Bar(i:Int) extends Foo
final case class Baz(s:String) extends Foo
val f:Foo = Bar(2)
//won't work because the compiler thinks f is of type Foo due to the type ascription bove
println(f.i)
//will work
println(f.asInstanceOf[Bar].i)
the Type Foo can be either Bar or Baz (because of the sealed and final, this is called an ADT) but we specifically told the compiler to treat f as a Foo which means we forgot which specific type it was. this is the case where you could use typecasting, note that we don't convert but rather tell the compiler that it is actually a Bar
Now this all happens during compile time which means you can't cast according to a runtime value like this
var a = 123.05
var b = "Int"
a.asInstanceOf[b]
Now as I understand you have some sort of stringly typed input and need to convert it according to some schema. The scalafiddle below has an example how you could do this: https://scalafiddle.io/sf/i97WZlA/0
However note that this makes use of some fairly advanced concepts in scala to ensure the types line up.
This will also work https://scalafiddle.io/sf/i97WZlA/1 but note that we lose all the type information requiring us to do a typecast if we want to do anything meaningful with out
EDIT/ADDENDUM: I thought I should also do an example on how to consume such values and make the schema dynamic.
https://scalafiddle.io/sf/i97WZlA/2
As a final note be warned that this is getting close to the limits what the compiler can do and necessitates a lot of boxing and unboxing to carry along the type information (in SchemaValue) also it's not stacksafe and has lackluster errorhandling. this solution would require some serious engineering to make viable but it should get the idea across
If you have a String value, then you can use toInt or toDouble to parse that string:
val s = "123.05"
val i = s.toInt
val d = s.toDouble
If you have an Any value then it is best to use match to convert it:
val a: Any = ...
a match {
case i: Int => // It is an Int
case d: Double => // It is a Double
case _ => // It is a different type
}
If all else fails you can explicitly pick a type, but this is not good practice:
val i = a.asInstanceOf[Int]
Any decent database framework will give you the ability to read and write values of specific types, so this should not be a problem with the right library.
I'm just beginning Scala, coming from Java.
So I know that in Scala, all things are objects, and Scala matches the longest token (source: http://www.scala-lang.org/docu/files/ScalaTutorial.pdf), so if i understand correctly:
var b = 1.+(2)
then b is a Double, plus and Int, which in Java would be a Double.
But when I check its type via println(b.isInstanceOf[Int]) I see that it is an Int. Why is it not a Double like in Java?
According to the specification:
1. is not a valid floating point literal because the mandatory digit after the . is missing.
I believe it's done like that, exactly because expressions like 1.+(2) should be parsed as an integer 1, method call ., method name + and method argument (2).
The compiler would treat 1 and 2 as Ints by default. You could force either one of these to be a Double using 1.toDouble And the result (b) would be a double.
Btw - did you mean to write 1.0+2 - in which case b would be a double?
We know that scala does not support more than 22 params, but if i write this
def echo(args: String*) = for (arg <- args) println(arg)
we can use more than 22 params to call this function like this.
echo("1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1")
But I think this is an array. So, it can do that and i tried this
val a = Array[String]("1","2","3");echo(a)
This code must be wrong, so here's my first question, why is this happening?
and, if i try to write this
echo(a : _*)
It's right,the second question is, what does this sign means '_*'? I can't use this code in other ways like in for(). So, is echo(a : _ *) is a right code?
The echo function is defined to take a variable number of string arguments. This is really only syntactic sugar; the compiler will insert the necessary instructions to wrap the arguments in an array and then pass the array. So the function will actually only receive a single argument at runtime.
The reason you can't pass the array directly is that there is no additional compiler logic to automagically figure out that the string arguments are already wrapped. The function declaration indicates that zero or more strings are expected, the parameter is actually an array, and a compiler error results.
The : _* notation is additional syntactic sugar to account for this problem; by using this syntax you indicate to the compiler that you are intentionally passing an array instead of the variable number of string parameters.
For example in the following article
http://www.artima.com/weblogs/viewpost.jsp?thread=179766
Two separate examples are given:
Automatic string conversion
Addition of append method
Suppose I want to have automatic string conversion AND a new append method. Is this possible? I have been trying to do both at the same time but I get compile errors. Does that mean the two implicits are conflicting?
You can have any number of implicit conversions from a class provided that each one can be unambiguously determined depending on usage. So the array to string and array to rich-array-class-containing-append is fine since String doesn't have an append method. But you can't convert to StringBuffer which has append methods which would interfere with your rich array append.
I need to print a formatted string containing scala.Long.
java.lang.String.format() is incompatible with scala.Long (compile time) and RichLong (java.util.IllegalFormatConversionException)
Compiler warns about deprecation of Integer on the following working code:
val number:Long = 3243
String.format("%d", new java.lang.Long(number))
Should I change fomatter, data type or something else?
You can try something like:
val number: Long = 3243
"%d".format(number)
The format method in Scala exists directly on instances of String, so you don't need/want the static class method. You also don't need to manually box the long primitive, let the compiler take care of all that for you!
String.format("%d", new java.lang.Integer(number))
is therefore better written as
"%d".format(number)
#Bruno's answer is what you should use in most cases.
If you must use a Java method to do the formatting, use
String.format("%d",number.asInstanceOf[AnyRef])
which will box the Long nicely for Java.