How to get the type of a field using reflection? - scala

Is there a way to get the Type of a field with scala reflection?
Let's see the standard reflection example:
scala> class C { val x = 2; var y = 3 }
defined class C
scala> val m = ru.runtimeMirror(getClass.getClassLoader)
m: scala.reflect.runtime.universe.Mirror = JavaMirror ...
scala> val im = m.reflect(new C)
im: scala.reflect.runtime.universe.InstanceMirror = instance mirror for C#5f0c8ac1
scala> val fieldX = ru.typeOf[C].declaration(ru.newTermName("x")).asTerm.accessed.asTerm
fieldX: scala.reflect.runtime.universe.TermSymbol = value x
scala> val fmX = im.reflectField(fieldX)
fmX: scala.reflect.runtime.universe.FieldMirror = field mirror for C.x (bound to C#5f0c8ac1)
scala> fmX.get
res0: Any = 2
Is there a way to do something like
val test: Int = fmX.get
That means can I "cast" the result of a reflection get to the actual type of the field? And otherwise: is it possible to do a reflection set from a string? In the example something like
fmx.set("10")
Thanks for hints!

Here's the deal... the type is not known at compile time, so, basically, you have to tell the compiler what the type it's supposed to be. You can do it safely or not, like this:
val test: Int = fmX.get.asInstanceOf[Int]
val test: Int = fmX.get match {
case n: Int => n
case _ => 0 // or however you want to handle the exception
}
Note that, since you declared test to be Int, you have to assign an Int to it. And even if you kept test as Any, at some point you have to pick a type for it, and it is always going to be something static -- as in, in the source code.
The second case just uses pattern matching to ensure you have the right type.
I'm not sure I understand what you mean by the second case.

Related

Eliminating identity wrapper types from Scala APIs

Suppose I am trying to "abstract over execution":
import scala.language.higherKinds
class Operator[W[_]]( f : Int => W[Int] ) {
def operate( i : Int ) : W[Int] = f(i)
}
Now I can define an Operator[Future] or Operator[Task] etc. For example...
import scala.concurrent.{ExecutionContext,Future}
def futureSquared( i : Int ) = Future( i * i )( ExecutionContext.global )
In REPL-style...
scala> val fop = new Operator( futureSquared )
fop: Operator[scala.concurrent.Future] = Operator#105c54cb
scala> fop.operate(4)
res0: scala.concurrent.Future[Int] = Future(<not completed>)
scala> res0
res1: scala.concurrent.Future[Int] = Future(Success(16))
Hooray!
But I also might want a straightforward synchronous version, so I define somewhere
type Identity[T] = T
And I can define a synchronous operator...
scala> def square( i : Int ) : Identity[Int] = i * i
square: (i: Int)Identity[Int]
scala> val sop = new Operator( square )
sop: Operator[Identity] = Operator#18f2960b
scala> sop.operate(9)
res2: Identity[Int] = 81
Sweet.
But, it's awkward that the inferred type of the result is Identity[Int], rather than the simpler, straightforward Int. Of course the two types are really the same, and so are identical in every way. But I'd like clients of my library who don't know anything about this abstracting-over-execution stuff not to be confused.
I could write a wrapper by hand...
class SimpleOperator( inner : Operator[Identity] ) extends Operator[Identity]( inner.operate ) {
override def operate( i : Int ) : Int = super.operate(i)
}
which does work...
scala> val simple = new SimpleOperator( sop )
simple: SimpleOperator = SimpleOperator#345c744e
scala> simple.operate(7)
res3: Int = 49
But this feels very boiler-platey, especially if my abstracted-over-execution class has lots of methods rather than just one. And I'd have to remember to keep the wrapper in sync as the generic class evolves.
Is there some more generic, maintainable way to get a version of Operator[Identity] that makes the containing type disappear from the type inference and API docs?
This more of long comment rather than an answer...
But, it's awkward that the inferred type of the result is Identity[Int], rather than the simpler, straightforward Int. Of course the two types apparent types are really the same, and so are identical in every way. But I'd like clients of my library who don't know anything about this abstracting-over-execution stuff not to be confused.
This sounds like you want to convert Indentity[T] back to T... Have you considered type ascription?
scala>def f[T](t: T): Identity[T] = t
scala>f(3)
// res11: Identity[Int] = 3
scala>f(3): Int
// res12: Int = 3
// So in your case
scala>sop.operate(9): Int
// res18: Int = 81
As Steve Waldman suggested in comments given type Identity[T] = T, the types T and Identity[T] really are identical without any ceremony, substitutable and transparent at call sites or anywhere else. For example, following works fine out-of-the-box
sop.operate(9) // res2: cats.Id[Int] = 81
def foo(i: Int) = i
foo(sop.operate(9)) // res3: Int = 81
extract from Cats is the dual of pure and extracts the value from its context, so perhaps we could provide similar methods for users not familiar with the above equivalence (like myself if you see my previous edit).
Can be done by providing types explicitly, but still looks magical for external users investigating method signature.
type Identity[T] = T
def square( i : Int ):Int = i * i
class Operator[W[_], T <: W[Int] ]( f : Int => T ) {
def operate(i : Int):T = f(i)
}
val op = new Operator[Identity,Int](square)
op.operate(5)
//res0: Int = 25
Works for new Operator[Future,Future[Int]] as well.

Scala: How to define an enum with extra attributes?

I have a use-case where I need to define a new enum type LongShort but I need it in a way to also carry the sign so it can be directly used in mathematical expressions e.g.
object LongShortType extends Enumeration {
type Type = Value
val Long = Value(+1)
val Short = Value(-1)
}
I'd then like to use it like this:
val longShort = LongShortType.Short
val numberOfContracts: Int = 10
val vanillaOptionNotional: Double = longShort*numberOfContracts
but this leads to compiler error cannot resolve symbol * ... is there a way to extract the value of the enum? Or am I not understanding how enum types work?
The type of LongShortType.Short isn't Int, it's Value. You can either extract the underlying id of the value:
val longShort = LongShortType.Short.id
Which is a little ugly. Or you could not use an enum type at all:
object LongShortType {
val Long = 1
val Short = -1
}
And then your equation would work as is.
OK I worked out a solution to accomplish what I wanted without any compromisse and by that I mean that this solution has all the advantages of using Scala enum e.g. the withName and still allows me to define extra features on it:
object LongShortType extends Enumeration {
type Type = LongShortVal
val Long = Value("Long", +1)
val Short = Value("Short", -1)
case class LongShortVal(name: String, sign: Int) extends Val(nextId, name)
protected final def Value(name: String, sign: Int) = new LongShortVal(name, sign)
}
and now can do:
val longShort = LongShortType.Short
val numberOfContracts: Int = 10
val vanillaOptionNotional: Double = longShort.sign*numberOfContracts
and can also do:
val longShort = LongShort.withName("Long") // returns LongShort.Long

Scala type for limiting an Int to a range

There is a program where I would like to limit the range on a set of ints from 5 to 15.
Is there a way to define a type which allows this?
An example of how would like to use this:
// Define type Good X as range from 5 to 15
class Foo(val x: GoodX)
{
//blah blah
}
I would also like to preserve the "Int-iness" of GoodX.
val base:GoodX=5
val f=Foo(base+4)
Take a look at https://github.com/fthomas/refined . It allows you to refine (constrain) existing types at type level. E.g. positive integers, which still have a subtype relationship with integers.
The syntax is a bit verbose, and it will box primitives (see below for details). But other than that it does exactly what you want.
Here is a short demo. Define a refinement and a method using a refined type:
import eu.timepit.refined._
import eu.timepit.refined.api.Refined
import eu.timepit.refined.auto._
import eu.timepit.refined.numeric._
type FiveToFifteen = GreaterEqual[W.`5`.T] And Less[W.`15`.T]
type IntFiveToFifteen = Int Refined FiveToFifteen
def sum(a: IntFiveToFifteen, b: IntFiveToFifteen): Int = a + b
Use it with constants (note the good compile error messages):
scala> sum(5,5)
res6: Int = 10
scala> sum(0,10)
<console>:60: error: Left predicate of (!(0 < 5) && (0 < 15)) failed: Predicate (0 < 5) did not fail.
sum(0,10)
^
scala> sum(5,20)
<console>:60: error: Right predicate of (!(20 < 5) && (20 < 15)) failed: Predicate failed: (20 < 15).
sum(5,20)
^
When you have variables, you do not know at compile time whether they are in range or not. So downcasting from Int to a refined int can fail. Throwing exceptions is not considered good style in functional libraries. So the refineV method returns an Either:
val x = 20
val y = 5
scala> refineV[FiveToFifteen](x)
res14: Either[String,eu.timepit.refined.api.Refined[Int,FiveToFifteen]] = Left(Right predicate of (!(20 < 5) && (20 < 15)) failed: Predicate failed: (20 < 15).)
scala> refineV[FiveToFifteen](y)
res16: Either[String,eu.timepit.refined.api.Refined[Int,FiveToFifteen]] = Right(5)
I think Partial Function would help.
case class GoodX(x: Int)
object GoodX {
def apply: PartialFunction[Int, GoodX] =
{ case i if i > 5 && i < 15 => new GoodX(i) }
}
// implicits to remain int-fulness
implicit def goodXToInt(goodX: GoodX): Int = goodX.x
GoodX(5) // throw Match Error
GoodX(10) // GoodX(10)
This solution requires no library.
Hope this help.
As shown in examples section of refined library we can define a custom refined type whose value is between 7 and 77
// Here we define a refined type "Int with the predicate (7 <= value < 77)".
scala> type Age = Int Refined Interval.ClosedOpen[W.`7`.T, W.`77`.T]
Furthermore, if on scala 2.13.x, one can also use literal based singleton types as shown below there by not needing Witness from shapeless ;)
import eu.timepit.refined.numeric.Interval.Closed
type AgeOfChild = Int Refined Closed[2, 12]
case class Child(name: NonEmptyString, age:AgeOfChild = 2)
Please refer to SIP and official documentation for more details.
Sure ...
object FiveToFifteen extends Enumeration {
val _5 = Value(5)
val _6,_7,_8,_9,_10,_11,_12,_13,_14,_15 = Value
}
Edit if you want to "preserve int-ness", you could also add conversions like this:
implicit def toInt(v: Value) = v.id
implicit def fromInt(i: Int) = apply(i)
But this, obviously, won't make your type much more "int-ful" then it already is (which is, pretty much none), because things like
val v: Value = _15 - _10 or val v: Value = _5 * 3 or even val v = _15 * _5 will work, but others, like val v: Value = _5 - 1 will crash

Scala comparing type:Ordering

I have a sorting function like this:
def sort[A:Ordering](vals: Array[A]):Array[A] = {
for (i <- 1 until vals.length) {
val temp = vals(i)
var j = i
while (j > 0 && temp < vals(j-1) ){
vals(j) = vals(j-1)
j -= 1
}
vals(j) = temp;
}
vals
}
And its supposed to get an array of type A(which is either Int or String, but the code doesn't know that) as a parameter and sort it and then return it.
Now eclipse tells me that:
"value < is not a member of type parameter A"
at line 5. I donĀ“t understand why can't it compare those values, I've tried A:Comparable, A:Ordered and A:every-word-that-could-possibly-work. Nothing works.
Any help is appreciated!
Thanks!
[A:Ordering] on a function sort means that there should exist such implicit value (to be completely honest it may not be implicit, but in this case you'll have to pass it by manually), that has type Ordering[A] at the point of sort call, and this implicit value will be added in separate argument list of the function.
This is how typeclasses supported in Scala.
This won't magically add < to A, as there is no type bound on A and compiller can know no more that A is a subtype of Any.
Anyway, to use ordering in body of your sort you can obtain it using:
implicitly[Ordering[A]]
... and then use it. This works because, again implicit value of type Ordering[A] were added behind the scenes in extra argument list of sort.
Here is a code snippet that should give you an idea on how to use it in your code:
scala> def lt[T : Ordering](a: T, b: T) = { implicitly[Ordering[T]].lt(a, b) }
lt: [T](a: T, b: T)(implicit evidence$1: Ordering[T])Boolean
scala> lt(1, 1)
res9: Boolean = false
scala> lt(1, 2)
res10: Boolean = true

How do I use Scala Hashmaps and Tuples together correctly?

My code is as follows
import scala.collection.mutable.HashMap
type CrossingInterval = (Date, Date)
val crossingMap = new HashMap[String, CrossingInterval]
val crossingData: String = ...
Firstly why does the following line compile?
val time = crossingMap.getOrElse(crossingData, -1)
I would have thought -1 would have been an invalid value
Secondly how do I do a basic check such as the following
if (value exists in map) {
}
else {
}
In Java I would just check for null values. I'm not sure about the proper way to do it in Scala
Typing your code in the interpreter shows why the first statement compiles:
type Date = String
scala> val time = crossingMap.getOrElse(crossingData, -1)
time: Any = -1
Basically, getOrElse on a Map[A, B] (here B = CrossingDate) accepts a parameter of any type B1 >: B: that means that B1 must be a supertype of B. Here B1 = Any, and -1 is of course a valid value of type Any. In this case you actually want to have a type declaration for time.
For testing whether a key belongs to the map, just call the contains method. An example is below - since Date was not available, I simply defined it as an alias to String.
scala> crossingMap.contains(crossingData)
res13: Boolean = false
scala> crossingMap += "" -> ("", "")
res14: crossingMap.type = Map("" -> ("",""))
//Now "" is a map of the key
scala> crossingMap.contains("")
res15: Boolean = true
If you want to check whether a value is part of the map, the simplest way is to write this code:
crossingMap.values.toSet.contains("")
However, this builds a Set containing all values. EDIT: You can find a better solution for this subproblem in Kipton Barros comment.