digitalmars.D.learn - Is std.variant useful for types only known at run time?
- Chris Piker (22/22) Sep 08 2021 Hi D
- jfondren (46/61) Sep 08 2021 a std.variant.Variant can contain *any* type, but this only four
- Chris Piker (27/28) Sep 08 2021 Wow, this forum is like a CS department with infinite office
- jfondren (19/43) Sep 08 2021 There's a lot to say about the precise differences. One practical
- Steven Schveighoffer (5/39) Sep 08 2021 Just as an aside,
Hi D I'm working on data streaming reading module where the encoding of each input array isn't known until runtime. For example date-time column values may be encoded as: * An ISO-8601 UTC time string (aka char[]) * A ASCII floating point value with an indicated unit size and epoch (aka char[]) * A IEEE double with an indicated endianness, unit size, and epoch. (aka double[]) * A 64-bit signed in with an indicated endianness, unit size, and epoch. (aka long[]) My job when encountering a date-time array in the stream is to just to properly convert the info into a broken down time structure, regardless of the encoding. Initially I've been reading chunks of the stream into a `ubyte[]` and then using `cast` and `to` as needed, but then I stumbled across std.variant which can hold any type. I'm wondering if std.variant is useful in cases where type information is only known at run-time, since many of the flexible data structures I've run across so far in D require compile-time information. Thanks,
Sep 08 2021
On Wednesday, 8 September 2021 at 07:10:21 UTC, Chris Piker wrote:Hi D I'm working on data streaming reading module where the encoding of each input array isn't known until runtime. For example date-time column values may be encoded as: * An ISO-8601 UTC time string (aka char[]) * A ASCII floating point value with an indicated unit size and epoch (aka char[]) * A IEEE double with an indicated endianness, unit size, and epoch. (aka double[]) * A 64-bit signed in with an indicated endianness, unit size, and epoch. (aka long[])a std.variant.Variant can contain *any* type, but this only four types, so I'd look at a std.sumtype of them first: ```d import std.sumtype; struct ISO8601 { } struct FloatEpoch { } struct DoubleEpoch { } struct LongEpoch { } alias Time = SumType!(ISO8601, FloatEpoch, DoubleEpoch, LongEpoch); void main() { import std.stdio : writeln; import std.format : format; Time e = ISO8601(); writeln(e.match!( (FloatEpoch _) => "doesn't happen", (DoubleEpoch _) => "doesn't happen", (LongEpoch _) => "an error to omit, unlike the next example", (ISO8601 time) => format!"%s"(time), )); } ``` ...I'm wondering if std.variant is useful in cases where type information is only known at run-time, since many of the flexible data structures I've run across so far in D require compile-time information.It is. It's used for message passing in std.concurrency for example, where an actor can receive any kind of type into its messagebox. If std.sumtype didn't exist then I might look at std.variant or a novel discriminated union of my own or OOP, where an option is to try casting to the different subtypes until the cast works: ```d class Encoding { } class ISO8601 : Encoding { } class FloatEpoch : Encoding { } class DoubleEpoch : Encoding { } class LongEpoch : Encoding { } void main() { import std.stdio : writeln; Encoding e = new ISO8601; if (!cast(FloatEpoch) e) writeln("it's null"); if (!cast(LongEpoch) e) writeln("it's null"); if (auto time = cast(ISO8601) e) writeln(time); } ```
Sep 08 2021
On Wednesday, 8 September 2021 at 08:39:53 UTC, jfondren wrote:so I'd look at a std.sumtype of them first:Wow, this forum is like a CS department with infinite office hours! Interesting. I presume that the big win for using std.sumtype over a class set is value semantics instead of reference semantics? So out of curiosity, say each structure implemented a function to provide the desired broken-down-time, would the following "virtual function" style call work? ```d import std.sumtype; struct BDTime { int y, int m, int d, int h, int m, double s }; struct ISO8601 { BDTime bdTime(){ ... } } struct FloatEpoch { BDTime bdTime(){ ... } } struct DoubleEpoch { BDTime bdTime(){ ... } } struct LongEpoch { BDTime bdTime(){ ... } } alias Time = SumType!(ISO8601, FloatEpoch, DoubleEpoch, LongEpoch); void main() { import std.stdio : writeln; import std.format : format; Time e = ISO8601(); BDTime = e.bdTime(); } ``` or would I need to use `match!` to get the right structure type and then generate the internal time representation?
Sep 08 2021
On Wednesday, 8 September 2021 at 09:55:20 UTC, Chris Piker wrote:Interesting. I presume that the big win for using std.sumtype over a class set is value semantics instead of reference semantics?There's a lot to say about the precise differences. One practical difference that I alluded to earlier is that an incomplete `match!` is a compile-time error, so if you later add a fifth kind of time encoding to your sumtype, the compiler will give you a laundry list of parts of your code to update to handle the new case.So out of curiosity, say each structure implemented a function to provide the desired broken-down-time, would the following "virtual function" style call work? ```d import std.sumtype; struct BDTime { int y, int m, int d, int h, int m, double s }; struct ISO8601 { BDTime bdTime(){ ... } } struct FloatEpoch { BDTime bdTime(){ ... } } struct DoubleEpoch { BDTime bdTime(){ ... } } struct LongEpoch { BDTime bdTime(){ ... } } alias Time = SumType!(ISO8601, FloatEpoch, DoubleEpoch, LongEpoch); void main() { import std.stdio : writeln; import std.format : format; Time e = ISO8601(); BDTime = e.bdTime(); } ``` or would I need to use `match!` to get the right structure type and then generate the internal time representation?You'd get an error like ``` Error: no property `bdTime` for type `std.sumtype.SumType!(ISO8601, ...)` ``` bdTime is defined for the individual times and not for the sumtype. You could have a match! that pulls out each member and calls its individual .bdTime(), but probably a more natural solution is to define bdTime only once, against the sumtype, where it has an internal `match!` that pulls out the different properties of the members that are necessary for each to construct a BDTime.
Sep 08 2021
On 9/8/21 5:55 AM, Chris Piker wrote:On Wednesday, 8 September 2021 at 08:39:53 UTC, jfondren wrote:Just as an aside, [taggedalgebraic](https://code.dlang.org/packages/taggedalgebraic) does this for you. -Steveso I'd look at a std.sumtype of them first:Wow, this forum is like a CS department with infinite office hours! Interesting. I presume that the big win for using std.sumtype over a class set is value semantics instead of reference semantics? So out of curiosity, say each structure implemented a function to provide the desired broken-down-time, would the following "virtual function" style call work? ```d import std.sumtype; struct BDTime { int y, int m, int d, int h, int m, double s }; struct ISO8601 { BDTime bdTime(){ ... } } struct FloatEpoch { BDTime bdTime(){ ... } } struct DoubleEpoch { BDTime bdTime(){ ... } } struct LongEpoch { BDTime bdTime(){ ... } } alias Time = SumType!(ISO8601, FloatEpoch, DoubleEpoch, LongEpoch); void main() { import std.stdio : writeln; import std.format : format; Time e = ISO8601(); BDTime = e.bdTime(); } ``` or would I need to use `match!` to get the right structure type and then generate the internal time representation?
Sep 08 2021