I am new to Scala and have read threads related to String Interpolation.
My requirement is that , I want to find the type of an expression, before actually evaluating the expression.
To make it clear:
val tesType = s"${{10 * Math.cos(0)+ 3}.getClass}"
This gives me the return type of the entire expression.
Is it possible to generalise this by replacing the actual expression by a variable containing the expression?
Something like:
val expression="10 * Math.cos(0)+ 3"
val tesType = s"${{expression}.getClass}"
Would something like this be possible or I am totally wrong in thinking in this direction?
Thanks
It's not possible to do with string interpolation. What you actually want to do is to compile scala code in runtime from string (file etc).
For ex twitter Eval library can be used for this purposes:
https://eknet.org/main/dev/runtimecompilescala.html
If you want the expression to be in a string, then see mst's answer (you can also use scala-compiler itself as a library, but its API is harder to use).
If you have an expression as an expression, you can do
import scala.reflect.runtime.universe._
def typeOfExpr[T: TypeTag](t: => T) = typeOf[T]
typeOfExpr(10 * Math.cos(0)+ 3) // returns Double
Related
I am trying to convert string to scala type by using asInstanceof method, while executing this am getting below exception
java.lang.ClassCastException: java.lang.String cannot be cast to scala.Tuple2
my code as below
import org.apache.spark.sql.Column
import org.apache.spark.sql.functions.col
val cond : String = "(null, col(field).isNotNull)" // Will get this condition from properties file.
type mutliColumnType = (Column, Column)
def condition( value : String , field : String = "somefield") : mutliColumnType = {
value match {
case "a" => (null, col(field).isNull)
case _ => convertStringToMutliColumnType(cond) //cond.asInstanceOf[mutliColumnType]
}
}
condition("a") // returns data
condition("ab") // Exception
How can we convert string to multiColumnType here ?
UPDATE:
Currently I written below code snippet to parse string to mutliColumnType :
def convertStringToMutliColumnType(cond : String) : mutliColumnType = {
val colArray=cond.trim.substring(1, cond.length-1).split(",")
(col(colArray(0)), col(colArray(1)))
}
You seem to be wanting asInstanceOf to evaluate a string as Scala code. This isn't really the same thing as "casting", it's not what asInstanceOf does, and in fact evaluating strings as code is not something Scala supports at all (apart from some internal APIs and ill-advised libraries like the now-defunct twitter-util-eval).
It's quite unclear what you're trying to do here, but your options are basically either to write a parser that takes strings and returns mutliColumnType values (which is a lot of work and almost certainly a bad idea), or just not to do this—i.e. to use Scala code where you need Scala code and strings where you need strings.
As a footnote: asInstanceOf is only really useful for downcasting (when you've lost type information and have something typed as Any that you as the programmer "know" is actually a String or whatever), and even then it should be considered an advanced technique that's unsafe and not generally idiomatic. Any time you write asInstanceOf you're telling the compiler to get out of the way because you know better, and in my experience you'll generally be wrong.
I'm thinking if its possible to create some sort of data structure that would take a string as a parameter and if that string does not contains .txt or something like that it would give me a compile error?
I can be specific on my problem - I am trying to take a file as a parameter(Source) to a function but I am told that currently I am passing any kind of file and it only should take text files so it is not done correctly. How do i approach this?
-Thanks!! ^^
Yes, this is not a problem. The big question is should you do it though. If your code is a library of sorts then under certain circumstances this might make sense. Check out Uri.uri from the http4s project
In your case the implementation could look something like this:
import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context
class Macros(val c: Context) {
import c.universe._
def txtFile(fileName: c.Expr[String]): Tree =
fileName.tree match {
case Literal(Constant(s: String)) if s.endsWith(".txt") =>
fileName.tree
case _ =>
c.abort(
c.enclosingPosition,
s"Supplied parameter is not a text file"
)
}
}
object MyObject {
def txtFile(fileName: String): String = macro Macros.txtFile
}
You'd use this like:
val x: String = txtFile("abc.tx") // Fails to compile
val y: String = txtFile("abc.txt") // Compiles
Again, it can be done, but you probably want to go with Option :-)
Assuming that String is coming from somewhere other than the code base (web request, cmd line), you'll need to pass that String to something that accepts Strings. Thus you'll have a point at which you're converting a String to your special filename datatype. So I can't see any way you'll be able to protect against some kind of runtime check.
If you want a runtime check that will avoid an error, you could return an Option, returning None if the String isn't a valid filename
You could use the refined library:
type TxtSuffix = EndsWith[W.`".txt"`.T]
type TxtFile = String Refined TxtSuffix
In order to construct a TxtFile, you need to give it a string that ends with ".txt":
val file: TxtFile = refineMV[TxtSuffix]("some.pdf") // compiler error
error: Predicate failed: "some.pdf".endsWith(".txt")
I'm trying to create a class with an attribute named _1d_matrix, which is a 1D matrix. I would want to fill it with 0.
Thus, I tried to call the method empty of the Seq object (of course not the trait), as mentionned in the documentation : http://www.scala-lang.org/api/2.12.3/scala/collection/Seq$.html#empty[A]:CC[A]
For the moment my code is :
class Calc(val width : Int) {
private val _1d_matrix : Seq.empty[Int]()
}
But there are three errors :
empty is undefined
() can't be written (2 errors : "; or newline is expected" + "definition or declaration is expected")
I think it's because it's not allowed to directly make use of Seq instead of List (e.g.). But : why ? After all, Seq is an object (and a trait but not in my code).
Right way to initialize field looks like this:
private val _1d_matrix = Seq.empty[Int]
or
private val _1d_matrix: Seq[Int] = Seq()
There are two ways to define a 0-arity (no arguments) method in scala - with a pair of parenthesis after the name def exit(), and without one: def empty.
When it is defined in the former way, you can call it with or without parenthesis: exit() or exit - both work. But when parenthesis are not included into the method definition, you can not have them at the call site either: Seq.empty[Int] works, but Seq.empty[Int]() does not.
The convention is to use parenthesis for functions that have side effects, and not use them for purely functional calls.
The other problem with your code is that you have a : where it needs to be an assignment.
So, something like this should work:
val _1d_matrix = Seq.empty[Int]
Your thinking is correct but you have a couple syntax errors.
private val _1d_matrix : Seq.empty[Int]()
: here is used to define a type annotation, so it's trying to find the type Seq.empty rather than the method. That fails because there is no such type.
Use = instead to assign a value. Adding the type here is optional since Scala is able to infer the correct type.
The other is that the empty method is defined without parens, so you must use Seq.empty[Int] instead of Seq.empty[Int]()
I am using a macro annotation from Spotify's Scio library. I would like to define a variable of String type and annotate like this:
val schemaString = """schema here"""
#BigQueryType.fromSchema(outputString) class BigQuery
This does not compile, however, if I annotate the String directly, it works:
#BigQueryType.fromSchema("""schema here""") class BigQuery
Looking at the code, this matching is done here, essentially the code is as follows:
def str(tree: c.Tree) = tree match {
// "string literal"
case Literal(Constant(s: String)) => s
// "string literal".stripMargin
case Select(Literal(Constant(s: String)), TermName("stripMargin")) => s.stripMargin
case _ => c.abort(c.enclosingPosition, errorMessage)
}
The question is why this does not match the variable, but does the string? And if there is any way to make the first example work?
The problem is that the value of string variables might not be available at compile-time, when macros are executed. What if it was:
val schemaString = doSomeComplexFunction()
#BigQueryType.fromSchema(schemaString) class BigQuery
In theory, maybe the macro could search for where the val is defined and allow it to work if it's just assigned a literal value, but even that can get complex if you start to think about scope.
So no, there's probably no way to get the first example to work.
I'm writing a DSL where the "+" operator is strictly numeric, like some other popular languages. It's close, but the String "+" operator is messing up my implicit conversions. What's the syntax for unimporting an operator of the String class?
Just to be clearer, instead of this:
scala> var x = "2" + 3;
x: java.lang.String = 23
I'd like to get x: Int = 5
I imagine I just need 2 things to make that happen:
Remove (unimport within my scope) the definition of "+" from Strings
Define an implicit conversion of String to Int
I'm stuck on the first step.
Thanks
According to section 12.3.1 of the Scala spec, the + method for String has special treatment by the compiler. I don't know for sure, but I think this means you can't "unimport" it, which is a shame because it really breaks the type system (much like the related toString method).
Could you use a different name for the operator in your DSL, eg, ++ or &?
The + method for a string is a method on of the String class (and therefore on each string object), and as such it cannot be unimported.
You can't unimport it, but you could use +: and define it on the int class. What would be best is if you write it like this: "2".toInt + 3.