Is providing a function inside of an enum considered "clean"?

martijn p :

I found some code in a source that basically uses a switch case to go through every possible value of an enum and call the appropriate function that returns a Number object based on the data type.

Here is a snippet:

case TYPE_16BIT_SIGNED_BE:
    measurement = response.getRegisters().getShort(0);
    break;
case TYPE_16BIT_UNSIGNED_BE:
    measurement = response.getRegisters().getUnsignedShort(0);
    break;
case TYPE_16BIT_SIGNED_LE:
    measurement = response.getRegisters().getShortLE(0);
    break;

Now my question is, is adding this to the enumeration itself considered to be a good or a bad practice?

Here is an example of what I mean:

public enum SomethingType {
    INT((b) -> {
        return b.getInt(0);
    }),
    DOUBLE((b) -> {
        return b.getDouble(0);
    }),
    LONG((b) -> {
        return b.getLong(0);
    });

    private Function<ByteBuf, Number> getNumber;

    SomethingType(Function<ByteBuf, Number> getNumber) {
        this.getNumber = getNumber;
    }
}
güriösä :

One can find this approach promoted on all kind of places, a likely defensible example are state machines. Enum members were also adopted much later in the Scala language. So it clearly was no freak feature of Java but a desired one which proved to be useful. I personally used it in production code time and again, especially when some static mapping was needed, from enum to value or from enum to function. It allows for tightly structured, concise code.

Furthermore IMO it has been convincingly shown that the usage of lambdas the way presented in the initial question is preferable over the use of overridden methods, if I may scavenge a bit from the link provided by @johannes-kuhn.

Therefore I do argue that it is considered good practice ("clean" in the sense of M.Fowler and R.Martin) rather than bad one. And if it's not explicitly considered so, it should be.

That said, there are persistent comments out there which consider enums as such not to be clean, due to the fact that they lure you into using switch-statements, which are not clean (precisely: a code smell, perhaps the opposite of clean), referring to M.Fowlers first edition of "Refactoring: Improving the Design of Existing Code". And, you know, it was him who coinded the term "clean" (and "code smell"). But in the 2005 edition he retracted this judgement.

As for the switches: one has to consider what happens when you extend the Enums and forget to extend all switches too. Me and my collegues found it useful to introduce unit tests, that looped through all items of the enum and tested, what was needed to be ensured. That issue yields another argument for Enums enhanced by lambdas: you can spare the switches in some cases (switch someValue ... case Enum.x: dosmthg()) in favor of calling the mapped function (someValue.dosmthg()).

As for the suggestion to subsume this question under the Expression Problem:

Under close examination it doesn't look like the Expression Problem is related to the question at all. From the link: "The Expression Problem is a new name for an old problem. The goal is to define a datatype by cases, where one can add new cases to the datatype and new functions over the datatype, without recompiling existing code, and while retaining static type safety (e.g., no casts)."

Therefore one can not have the Expression Problem with approach A and approach B like suggested, the same way one can not have the Hadwiger–Nelson problem with them. The Expression Problem is a problem in its own right and a puzzler for functional and object oriented languages, with distinct solutions in each of them, independent from a context like given here. Here's a java solution shown that claims to be both complete and valid, alongside a Haskell solution. Quite a complex thing acutally.

Kill me if I'm wrong.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=306650&siteId=1
Recommended