C#-like records for D
Records are classes and provide boilerplate implementations for properties, equality, hashing and toString. Get only fields can be set at construction, or when duplicate
is called.
Classes, interfaces and pointers are checked by reference (they point to the same thing). Basic types and structs are checked by value.
The hashing algorithm is very basic. It is result = (31 * result) + currentField
for each field (in same order of declaration).
Only fields are printed. The format is { fieldName = fieldValue, fieldName2 = fieldValue2, ...}
.
Provides a field and accessor property. It can be default initialised or set during construction or duplication.
Provides a field, accessor and mutator properties. It can be default initialised, set during construction or duplication, or freely at any other time.
This provides a lambda function that is invoked after all other fields have been initialised. This means you can run an expensive algorithm that is dependent on other record fields, and it only runs once during construction (or duplication).
Provides a lambda method that can run a custom operation on the record fields.
General usage:
import drecord;
alias MyRecord = record!(
get!(int, "x"), /// x is an int, can only be set during construction
get_set!(float, "y"), /// y is a float, can be get or set whenever
property!("getDoubleOfX", (r) => r.x * 2), /// a property that returns the double of x
property!("getMultipleOfX", (r, m) => r.x * m, int), /// that takes an argument and multiples x by that value
property!("printY", (r) => writeln(r.y)), /// prints y
property!("resetY", (r) => r.y = 0) /// resets y to 0f
);
auto r = new MyRecord(12, 4.5f); /// sets x, y
writeln(r); // {x = 12, y = 4.5}
writeln(r.toHash); // 376
writeln(r.x); // 12
writeln(r.getDoubleOfX); // 24
writeln(r.getMultipleOfX(4)); // 48
r.printY; // 4.5
r.resetY;
writeln(r.y); // 0
r.y = 13f;
r.printY; // 13
/// Duplicate r, and set x to 17 (we can only do this in ctor, or during duplication)
/// This is equivalent to C#'s "with" syntax for records [0]
auto q = r.duplicate!("x")(17);
writeln(q); // {x = 17, y = 13}
writeln(q == r); // false
writeln(q is r); // false
auto b = r.duplicate; // duplicate, don't change any fields
writeln(b == r); // true
writeln(b is r); // false
Default initialisation:
import drecord;
alias DefaultRecord = record!(
// The third parameter is a lambda which provides default initialisation
get!(int, "x", () => 4), // x is set to 4 by default
get_set!(Object, "o", () => new Object) // o is set to a new Object by default
);
auto r = new DefaultRecord; // run the default initialisers
writeln(r); // {x = 4, o = object.Object}
auto q = DefaultRecord.create!"x"(9); // run default initialisers, then set x to 9
writeln(q); // {x = 9, o = object.Object}
Property computation:
alias MyRecord = record!(
get!(int, "x", () => 20),
// get_compute lets you compute a field after the rest have been initialised
get_compute!(float, "y", (rec) => rec.x * 2f)
);
auto r = new MyRecord;
writeln(r); // {x = 20, y = 40}
r = new MyRecord(10);
writeln(r); // {x = 10, y = 20}
r = MyRecord.create!"x"(5);
writeln(r); // {x = 5, y = 10}
auto q = r.duplicate!"x"(2);
writeln(q); // {x = 2, y = 4}
[0]: Records in C#