1

I am porting a library heavily based on Java enums and need to code my own enum until there are native support for them.

However I fail!

In the code below the ChessColor.values() method returns null and I can't see why.

However I am new to Dart ...

There must be something with static fields and initialization that I have missed ...

Enum base class

part of chessmodel;

/**
 * Emulation of Java Enum class.
 */
abstract class Enum {    

  final int code;
  final String name;

  Enum(this.code, this.name);    

  toString() => name;    

}

A simple usage try

part of chessmodel;

final ChessColor WHITE = ChessColor.WHITE;
final ChessColor BLACK = ChessColor.BLACK;

class ChessColor extends Enum {

  static List<ChessColor> _values;
  static Map<String, ChessColor> _valueByName;

  static ChessColor WHITE = new ChessColor._x(0, "WHITE");
  static ChessColor BLACK = new ChessColor._x(1, "BLACK");

  ChessColor._x(int code, String name) : super (code, name) {
    if (_values == null) {
      _values = new List<ChessColor>();
      _valueByName = new Map<String, ChessColor>();
    }
    _values.add(this);
    _valueByName[name] = this;
  }

  static List<ChessColor> values() {
    return _values;
  }

  static ChessColor valueOf(String name) {
    return _valueByName [name];
  }

    ChessColor opponent() {
        return this == WHITE ? BLACK : WHITE;
    }

    bool isWhite() {
        return this == WHITE;
    }

    bool isBlack() {
        return this == BLACK;
    }

}
Seth Ladd
  • 112,095
  • 66
  • 196
  • 279
Gunnar Eketrapp
  • 2,009
  • 1
  • 19
  • 33
  • Check out this question on how to build enums in dart: http://stackoverflow.com/q/15854549/1479964 – Matt B Apr 18 '13 at 13:06
  • Saw that but I need the values() and valuOf(String name) so I made this attempt. – Gunnar Eketrapp Apr 18 '13 at 14:04
  • And you have the right idea. But I haven't seen all the code you're using but I think this is the issue you're running into https://groups.google.com/a/dartlang.org/d/topic/misc/dKurFjODRXQ/discussion (Statics are lazy initialied) so if you call values before you've accessed one of the static values, then the constructor is not yet called. – Matt B Apr 18 '13 at 14:35
  • Yea I found that out. My currently ugly solution is to ensure that all enums are created upon init. – Gunnar Eketrapp Apr 18 '13 at 15:12

2 Answers2

1

If you absolutely need to emulate the old Java enum pattern, you can. However, Dart looks at enums as a much more simple construct.

To answer one of your questions, static fields are initialized "lazily", in that they are initialized on their first access.

That being said, here's one way you can implement what you are trying to do. Use const constructors to create const objects. Const objects are canonicalized by the compiler. This means that two const objects that are initialized in the same way are in fact the same exact object. Generally, you want enums to be const.

/**
 * Emulation of Java Enum class.
 */
abstract class Enum {    

  final int code;
  final String name;

  const Enum(this.code, this.name);    

  String toString() => name;
}

final ChessColor WHITE = ChessColor.WHITE;
final ChessColor BLACK = ChessColor.BLACK;

class ChessColor extends Enum {

  static const List<ChessColor> values =
      const [ChessColor.WHITE, ChessColor.BLACK];
  static Map<String, ChessColor> valueByName =
      const {"WHITE": ChessColor.WHITE, "BLACK": ChessColor.BLACK};

  static const ChessColor WHITE = const ChessColor._x(0, "WHITE");
  static const ChessColor BLACK = const ChessColor._x(1, "BLACK");

  const ChessColor._x(int code, String name) : super (code, name);
}

void main() {
  print(WHITE);
  print(ChessColor.values);
  print(ChessColor.WHITE.code);
  print(ChessColor.valueByName['BLACK']);
}
Seth Ladd
  • 112,095
  • 66
  • 196
  • 279
0

So my porting from java to dart goes on but I still have problems related to static init.

My Java enums where smart. I.e. ChessSquare A2 know its neighbours. ChessBoardDirection knows it's opposite direction. ChessColor knows its opponent colors etc etc.

I am sure that one can debate such a design but it leads to clean and nice code when it comes to writing chess code.

In the current porting attempt I have found myself forced to add static initiateModule() methods in such classes which becomes nasty real fast since they depend on each other.

In java this is easily done with static code blocks that are guaranteed to be executed when class is loaded.

In the minimal example below with ChessColor how is that best solved in dart? I.e. how is _opponent initiated.

Java

package chess.model;

public enum ChessColor {
  WHITE, BLACK;

  private ChessColor opponent;

  public ChessColor opponent() {
    return opponent;
  }

  public boolean isWhite() {
    return this == WHITE;
  }

  public boolean isBlack() {
    return this == BLACK;
  }

  static { // Initiate cross dependencies
    WHITE.opponent = BLACK;
    BLACK.opponent = WHITE;
  }
}

Dart

part of chessmodel;

final ChessColor WHITE = ChessColor.WHITE;
final ChessColor BLACK = ChessColor.BLACK;

class ChessColor extends Enum {

  static ChessColor WHITE = new ChessColor._x(0, "WHITE");
  static ChessColor BLACK = new ChessColor._x(1, "BLACK");

  static List<ChessColor> _values = [WHITE, BLACK];
  static Map<String, ChessColor> _valueByName = {"WHITE": WHITE, "BLACK": BLACK};

  ChessColor _opponent;

  ChessColor._x(int code, String name) : super (code, name);

  static List<ChessColor> values() {
    return _values;
  }

  static ChessColor valueOf(String name) {
    return _valueByName [name];
  }

  ChessColor get opponent => _opponent; 
  bool get isWhite => this == WHITE;
  bool isBlack => this == BLACK;

}
Gunnar Eketrapp
  • 2,009
  • 1
  • 19
  • 33