Description
Hi. These topics have been brought up several times in the language and SDK repos, however I'd like to show a particular use case that may help with designing future language features.
While writing parsers or generators for binary file formats, the following code evolution usually happens. Out of simplicity, this is how it starts:
// type of data
const text = 7;
const image = 8;
final type = readByte();
switch (type) {
case text:
//readText();
case image:
//readImage();
default:
// throw
}
Then, either the number of consts grows, or another field emerges. So, to keep values organized, static consts within abstract classes could be used. This approach scopes values (thus preventing certain errors), but doesn't provide full type safety, since values are just integers.
abstract class DataType {
static const int text = 7;
static const int image = 8;
}
abstract class CompressionType {
static const int none = 0;
static const int deflate = 2;
}
final type = readByte();
final compression = readByte();
// ...
To achieve type safety, much more boilerplate is needed:
class DataType {
final int value;
const DataType._(this.value);
factory DataType(int value) {
switch(value) {
case _text:
return text;
case _image:
return image;
default:
return null; // or throw ArgumentError
}
}
static const int _text = 7;
static const int _image = 8;
static const DataType text = DataType._(_text);
static const DataType image = DataType._(_image);
}
final type = DataType(readByte()); // instance of DataType
// ...
The next step usually involves adding string names to these values and overriding toString
for a better debugging.
class DataType {
final int value;
final String name;
const DataType._(this.value, this.name);
factory DataType(int value) {
switch(value) {
case _text:
return text;
case _image:
return image;
default:
return null; // or throw ArgumentError
}
}
static const int _text = 7;
static const int _image = 8;
static const DataType text = DataType._(_text, 'text');
static const DataType image = DataType._(_image, 'image');
@override
String toString() => '$value ($name)';
}
Could future language development reduce the amount of boilerplate here or it would be more appropriate to go with codegen?