0

I'm trying to access variables of an object by using strings whose values are determined at run time.

Basically the object is used as a dictionary, and now I want to dynamically poll values from that dictionary

A simplified example:

object Something extends scala.AnyRef {
    final val zero = 0
    final val one = 1
    final val two = 2
}

I would then principally like to do the following

Somthing."zero"

and get 0 in return.

Ideally I would like to use scala reflection for this

5
  • 4
    If you want a dictionary, use a dictionary. Commented Sep 6, 2018 at 14:19
  • fair enough but that code is not mine to modify Commented Sep 6, 2018 at 14:25
  • Build a dictionary from someine else's object data. Commented Sep 6, 2018 at 14:35
  • 2
    Scala heavily prefers type-safe compile-time reflection. So, using reflection in this way is not the Scala way. The Scala way would probably be to use compile-time reflection to generate all those pattern match cases from Luis's answer. Commented Sep 6, 2018 at 14:52
  • 2
    You could certainly use Java reflection, but then your code would be tied to Java, and you would not be able to enjoy some of the cool new Scala implementations like Scala.JS or Scala-native. Commented Sep 6, 2018 at 14:53

2 Answers 2

2

WARNING: Please heed Jörg W Mittag's advice before following my answer:

Scala heavily prefers type-safe compile-time reflection. So, using reflection in this way is not the Scala way. The Scala way would probably be to use compile-time reflection to generate all those pattern match cases

Using reflection Something.getClass.getDeclaredMethods.foreach(println) gives:

public final int example.Something$.zero()
public final int example.Something$.one()
public final int example.Something$.two()

so to get the names we can do

Something.getClass.getDeclaredMethods.map(_.getName) // Array(zero,one,two)

and to get the value

Something.getClass.getMethod("zero").invoke(Something) // 0

Defining the following implicit class

implicit class AccessMembersByReflectionName(something: Something.type) {
  def get(name: String): AnyRef = {
    Something.getClass.getMethod(name).invoke(Something)
  }
}

cleans up the call site

Something.get("zero") // 0
Sign up to request clarification or add additional context in comments.

Comments

1

As @n.m. already pointed, if you only want to retrieve values of the same type given an string key, you should use a Dictionary.

However, if for some reason you still need an object, you could accomplish something similar of what you want with this method.

Object Something {
  val Zero: Int  = 0
  val One: Int   = 1
  val Three: Int = 3

  def getValueByString(valName: String): Int = valName.toLowerCase match {
    case "zero"  => Zero
    case "one"   => One
    case "three" => Three
  }
}  

EDIT I just read that you can modify the object, you still can make a function that will receive the object and the valName as a string.

5 Comments

Thanks for the input. Now, the thing is that there are > 5000 variables which makes this solution unsuitable. I was hoping for a solution using the scala reflection.
Well, as other already point out Scala don't encorage using runtime reflection, you can go for Mario's answer if you really need to, but I recomend you to lear about macros and scala-meta, for a more typesafe way for solving this problem.
+1 for not using reflection. It's a huge code smell to resort to that for your app code. I would suggest keeping that class around for legacy reasons but build a Map on the side a.s.a.p and start using that for all new code. If the code comes from a dependency, stop using it, it's crap. If the code comes from another in house team, ask them whether they could provide a better API for lookups.
@Luis thanks for the feed back. I'll search for a more typesafe way in the future, but am going with Mario's solution in the short term
Oh, there is a better API which I intend to use in the live version. This is a temporary solution during initial testing

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.