My workplace has been experimenting in moving from Java to Scala for some tasks, and it works well for what we're doing. However, some preexisting logging methods expect a java.lang.Enum
. The logging method is defined in the (Java) base class, and the subclasses can define their own enums, which the logger will track across all instances in multiple threads/machines.
It works like this in Java:
public class JavaSubClass extends JavaBaseClass {
enum Counters {
BAD_THING,
GOOD_THING
}
public void someDistributedTask() {
// some work here
if(terribleThing) {
loggingMethod(Counters.BAD_THING)
} else {
loggingMethod(Counters.GOOD_THING)
// more work here
}
}
}
Then, when the task has finished, we can see that
BAD_THING: 230
GOOD_THING: 10345
Is there any way to replicate this in Scala, either by creating Java Enum
s or converting from Enumeration
to Enum
? I have tried extending Enum
directly, but it seems to be sealed, as I get the error in the console:
error: constructor Enum in class Enum cannot be accessed in object $iw
Access to protected constructor Enum not permitted because
enclosing object $iw is not a subclass of
class Enum in package lang where target is defined
In Scala, there is no enum keyword unlike Java or C. Scala provides an Enumeration class which we can extend in order to create our enumerations. Every Enumeration constant represents an object of type Enumeration. Enumeration values are defined as val members of the evaluation.
Enumerated (enum) types are data types that comprise a static, ordered set of values. They are equivalent to the enum types supported in a number of programming languages. An example of an enum type might be the days of the week, or a set of status values for a piece of data.
valueOf. Returns the enum constant of the specified enum type with the specified name. The name must match exactly an identifier used to declare an enum constant in this type. (Extraneous whitespace characters are not permitted.)
Java Enums
For an enum class Counter
would be a better name than Counters
- each enum value represents a singular counter.
When javac compiles an enum
class, it:
Counter
) containing all of the constructors, methods, other members of the enum (if any)each enum
value (GOOD_THING
, BAD_THING
) is made a public static
field of (1) - with class equal to the class in (1) (Counter
):
// Java Code:
class Counter {
public static Counter GOOD_THING;
public static Counter BAD_THING;
// constructors, methods, fields as defined in the enum ...
}
initialization logic in the class automatically constructs each enum
value as a singleton object
Scala Options
A. Reference Java Enum From Scala
Import Counter, refer to GOOD_THING and BAD_THING just like in java, and (if you like) additionally call Enum class methods:
// Scala Code:
import JavaSubClass.Counter;
def someDistributedTask = {
// some work here
if (terribleThing) {
loggingMethod(Counter.BAD_THING)
} else {
loggingMethod(Counter.GOOD_THING)
// more work here
}
}
// Other things you can do:
val GoodThing = Counter.valueOf("GOOD_THING")
Counter.values() foreach { // do something }
counter match {
case Counter.GOOD_THING => "Hoorah"
case Counter.BAD_THING => "Pfft"
case _ => throw new RuntimeException("someone added a new value?")
}
Advantages: Can do everything that java enumerations do, plus supports pattern matching.
Disadvanges: Because the base trait is not sealed
, any code doing pattern matching is not typed-checked to ensure exhaustive cases are covered.
B. Use Scala Enumeration
Convert java enum
to equivalent scala Enumeration
:
// Scala Code:
object Counter extends Enumeration {
type Counter = Value
val GoodThing = Value("GoodThing")
val BadThing = Value("BadThing")
}
Use it:
// Scala Code:
import someScalaPackage.Counter;
def someDistributedTask = {
// some work here
if (terribleThing) {
loggingMethod(Counter.BadThing)
} else {
loggingMethod(Counter.GoodThing)
// more work here
}
}
// Other things you can do:
val GoodThing = Counter.withName("GoodThing")
val label = Counter.BadThing.toString
Counter.values foreach { // do something }
myCounter match {
case Counter.GOOD_THING => "Bully!"
case Counter.BAD_THING => "Meh"
case _ => throw new RuntimeException("someone added a new value?")
}
Advantages: Scala's Enumeration
methods are as rich as Java Enum
's, plus supports pattern matching.
Disadvanges: Can't do everything that java enum
s do - java enum's are defined as a class with arbitrary constructors, methods and other members allowable (i.e. full OO modelling on the enum basetype). Because the base trait is not sealed
, any code doing pattern matching is not typed-checked to ensure exhaustive cases are covered.
C. Use Scala Case Classes:
Can convert enum
s directly into Case Objects (i.e. singleton objects as opposed to Case Class, which is not singleton):
sealed trait Counter
object Counter {
case object GoodThing extends Counter;
case object BadThing extends Counter;
}
Use it:
// Scala Code:
import someScalaPackage.Counter;
def someDistributedTask = {
// some work here
if (terribleThing) {
loggingMethod(Counter.BadThing)
} else {
loggingMethod(Counter.GoodThing)
// more work here
}
}
// Other things you can do:
// NO!! val GoodThing = Counter.withName("GoodThing")
val label = Counter.BadThing.toString
// NO!! Counter.values foreach { // do something }
myCounter match {
case Counter.GOOD_THING => "Bully!"
case Counter.BAD_THING => "Meh"
case _ => throw new RuntimeException("someone added a new value?")
}
sealed
, any code doing pattern matching is typed-checked to ensure exhaustive cases are covered. (Not useful for your requirements).If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With