dart-lang / dart-lang/language

Enums, value classes and beyond

Open
#183 2 comments 3 reactions 0 assignees View on GitHub
Dominant language
TeX
Stars
2.9k
Forks
239
Avg merge
2d 18h
Merged PRs (30d)
14

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:
```dart
// 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.
```dart
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:
```dart
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.
```dart
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?

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.