1

I'm new to scala and I need a structure where I can easily add new indivdual accessable constants and also iterate over all of them. Something like this:

object Constants {
    val A = Something(...)
    val B = Something(...)
    val C = Something(...)
    // ...

    val listOfConstants = (A, B, C, ...)
}

But without the need to add the constant to the list manually. I considered a Map but this would make it harder to access the constants and I ended up writing this:

def getElements[T : ClassTag](c : Any) : Set[T] = {
    var result : Set[T] = Set()
    for (field <- c.getClass.getDeclaredFields) {
        field.setAccessible(true)
        field.get(c) match {
            case t: T => result += t
            case _ =>
        }
    }
    result
}

and then using the following line for structures like this

val listOfConstants = getElements[Something](Constants)

Is this a dirty solution? Are there better alternatives?

ChrisU
  • 11
  • 2

3 Answers3

3

You could use scala's default Enumeration, but it has it's own caveats. The best enumaration library I know is Enumeratum. It allows you to write something like this:

object MyEnum extends Enum[Something] {

  val values = findValues

  case object A extends Something
  case object B extends Something
  case object C extends Something
  case object D extends Something

}

findValues is a macros that automatically finds all sub-objects of Something (inside MyEnum) in compile-time.

To add this lib using SBT:

libraryDependencies += "com.beachape" %% "enumeratum" % "1.4.0"
dk14
  • 22,206
  • 4
  • 51
  • 88
2

Try enumerations, for instance http://www.scala-lang.org/api/current/scala/Enumeration.html, or How to model type-safe enum types?. You can also write your enum in Java and use it from Scala

For instance, here's an enum defined in Java that you can use from Scala - and comes with a map of all its possible values, so you can get by key, iterate on the values, etc. The map of values is constructed automatically, so it does not need to be maintained manually.

import java.util.Collections;
import java.util.Map;
import java.util.HashMap;

/**
 * Demonstrates parsing of an enum from the contained value
 */
public enum WithFrom implements Something {
    TWO("one plus 1"), SIX("two plus 4");

    WithFrom(String expr) {
        this.expr = expr;
    }

    private final String expr;

    public static final Map<String, WithFrom> fromValue = Collections
            .unmodifiableMap(new HashMap<String, WithFrom>() {
                private static final long serialVersionUID = 7205142682214758287L;

                {
                    for (WithFrom wf : WithFrom.values()) {
                        put(wf.expr, wf);
                    }
                }
            });
}
Community
  • 1
  • 1
radumanolescu
  • 4,059
  • 2
  • 31
  • 44
  • Thanks for the answer, but in my case `Something` is an abstract type from which A, B, C,... can be various subtypes. As far as I understand enums can't be extended. – ChrisU Nov 16 '16 at 22:45
  • A Java enum can implement an interface. Would that help? – radumanolescu Nov 16 '16 at 23:03
1

You could create an Enumeration and use its values: ValueSet method.

Anatoly
  • 456
  • 5
  • 13