Hacker News new | ask | show | jobs
by geonik 4083 days ago
I second that; Java has solutions for all problems described by this post.

- constructors, private fields, methods, addressing the "separations of concerns" - how about Enum.valueOf(enumClass, text.toUpperCase()) to avoid the "classic shadow array of string literals"?

Here is an example of what can be achieved by Java enums

  enum Type {
    ANIMAL(null),
    MAMMAL(ANIMAL),
    DOG(MAMMAL) {
      public void makeNoise() {
        System.out.println("Woof");
      }
    },
    CAT(MAMMAL) {
      public void makeNoise() {
        System.out.println("Meow");
      }
    };
    private Type parent;
    Type(Type parent) {
      this.parent = parent;
    }
    public boolean isA(Type type) {
      if(this == type) return true;
      if(parent != null) return parent.isA(type);
      return false;
    }
    public void makeNoise() { }
  }
  assert Type.DOG.isA(Type.MAMMAL) == true;
  assert Type.CAT.isA(Type.DOG) == false;
  Type.CAT.makeNoise(); // "Meow"
1 comments

This demonstrates a different problem - enums are closed. If I want to add an Owl, I can't do it without editing Type. This might break the API contract (if you own the library) or not be possible (if it's a third part library).

There is very little reason to use an enum over classes in this example. It's rare that I've seen a Java class style enum that wouldn't have been better served by classes (including some that I've written myself and regretted!)

The main point of an enumerated type is that it should be closed. You control all instances of the type, so that you and the compiler can benefit from the fact that it's closed.

If the fact that enums are closed ever presents a problem, then it's a good indication that you shouldn't be using enums. That's not a problem with enums, it's just a bad design decision that needs to be reversed.

Agreed that Vehicle is a poor choice for an enum, because it's something that isn't really closed. But if you're modelling something like states of a TCP connection, there's nothing dangerous about it being closed.

For this example, I agree that it makes very little sense. The question you really need to ask yourself whenever you are making an `enum` is: Does it make sense that this type is restricted to a predefined selection of instances? There are times when the legitimate answer to this question is "yes", and in those cases go ahead and make an `enum` and enjoy its benefits.
Historically, I've used rich enums in Java to be able to use switch statements to reason about a system state and as poor man's type pattern matching. Sometimes the switch is handy for making a state machine clearer, and sometimes it makes it easier to explain the relationships of these states as an ordered list. Another important use of enums is if you're trying to create a rich set of annotations that take parameters, which would force you into dropping a lot of the Java OOP typing available. I can't have a closure or even an anonymous class as an argument to parameterized annotations - and this is definitely by design.

I got bit pretty hard before trying to design an annotation-driven convention for a library I was writing (I had been writing a lot of Python for a while) and realized I'd have to squash a bunch of my carefully arranged classes into an enum. You run into similar problems when marshalling your objects to, say, a Thrift structure definition.