Reputation: 2149
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;
}
}
Upvotes: 1
Views: 311
Reputation: 2149
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;
}
Upvotes: 0
Reputation: 120489
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']);
}
Upvotes: 1