digitalmars.D - std.sumtype?
- Oleg B (22/22) Mar 18 2021 Hello everyone.
- rm (4/8) Mar 18 2021 I agree. Being able to extract items by type is missing. If the
- Paul Backus (3/5) Mar 18 2021 Yes you can. There's even a unit test for this specific use-case:
- rm (4/12) Mar 18 2021 I stand corrected. Now I'm going to have to go back to figure what was
- Paul Backus (3/4) Mar 18 2021 If -preview=dip1008 is ever implemented properly you will get
- Paul Backus (8/19) Mar 18 2021 There was discussion on Github [1] and on the forums [2].
- Oleg B (29/32) Mar 18 2021 Thank for links, I don't saw these news in November.
- Paul Backus (6/15) Mar 18 2021 Something like this:
- Oleg B (2/7) Mar 18 2021 why it is not in library? or why tag is private?
- Paul Backus (6/14) Mar 18 2021 Because I personally haven't needed it for anything, and nobody
- Oleg B (10/16) Mar 18 2021 Adding read-only tag is simple and useful change. If I understand
- Steven Schveighoffer (8/17) Mar 18 2021 That requires sorting the types somehow, which isn't really easy or
- Oleg B (15/22) Mar 18 2021 As I know it solved in mir.algebraic [1] and code for solving
- Paul Backus (14/21) Mar 18 2021 union U1 { int n; float f; }
- Oleg B (5/19) Mar 18 2021 okey, I agree
- Paul Backus (3/6) Mar 18 2021 https://github.com/pbackus/sumtype/pull/57
- Oleg B (2/9) Mar 19 2021 Thank you very much!
- drug (2/7) Mar 19 2021 Totally agree, it is an important feature.
- Paul Backus (3/10) Mar 19 2021 https://github.com/pbackus/sumtype/pull/57
- Atila Neves (2/9) Mar 23 2021 Can anyone explain to me why?
- Steven Schveighoffer (31/42) Mar 23 2021 1. It costs nothing (returning tag is pretty much free).
- Paul Backus (23/29) Mar 23 2021 Well, first, we would never write a naked magic number like this
- Atila Neves (22/66) Mar 25 2021 I don't think this is enough of a reason.
- drug (37/37) Mar 25 2021 I think that `kind` vs `handler` is more like old-school vs modern
- Paul Backus (26/59) Mar 25 2021 Only if you don't know what you're doing. Check this out:
- drug (2/13) Mar 25 2021 Looks good
- Jon Degenhardt (22/47) Mar 29 2021 This comment is not intended as criticism. SumType looks like a
- Paul Backus (29/48) Mar 30 2021 I wouldn't expect users to jump straight to the fully-generalized
- Steven Schveighoffer (10/23) Mar 30 2021 What might be nice is to have some simplifiers for match to prevent
- Paul Backus (19/27) Mar 30 2021 sumtype has had tryMatch [1] since version 0.4.0 (released May
- Steven Schveighoffer (15/49) Mar 30 2021 Yeah, that actually looks pretty good. Forgive my ignorance, I have not
- Jon Degenhardt (11/15) Mar 31 2021 Yeah, I would say its not obvious :) But, there does seem to be a
- Paul Backus (13/20) Mar 31 2021 Well, it's not really a specific "ability"; it's just a natural
- Paul Backus (14/19) Mar 25 2021 I suspect the big reason is that a lot of D programmers aren't
- Atila Neves (5/15) Mar 25 2021 Completely plausible but in my opinion not nearly enough of a
- Paul Backus (17/19) Mar 26 2021 IMO typeIndex is not really an "escape hatch", because while you
- Steven Schveighoffer (56/128) Mar 29 2021 But it is a reason. If it costs nothing to return it, and doesn't HARM
- Nick Treleaven (5/11) Mar 31 2021 How about e.g.:
- Oleg B (9/19) Mar 31 2021 Simple general example is serialization and deserialization of
- Q. Schroll (7/20) Mar 18 2021 Even
- ryuukk_ (29/29) Mar 18 2021 I'm not a fan of the syntax.. why is it a library instead of a
- Paul Backus (10/13) Mar 18 2021 Because it's easier to write a library than to go through the
- ryuukk_ (7/20) Mar 18 2021 That's how i feel about it, people didn't care enough and easiest
- Paul Backus (7/13) Mar 18 2021 I cared enough to spend my free time for the last *three years*
- ryuukk_ (7/22) Mar 18 2021 I apologies if i sounded rude or disrespectful, that wasn't my
- ryuukk_ (8/17) Mar 18 2021 The syntax is a result of it not being a language feature (the
- Paul Backus (5/10) Mar 18 2021 There is no need to remove the library even if a built-in version
- Imperatorn (3/13) Mar 23 2021 Instead of spending three years on the DIP, start small and spend
- kumar0raja (3/3) Mar 29 2021 I agree that the process for adding new modules to Phobos could
- Steven Schveighoffer (6/22) Mar 18 2021 Wait, you can't access the tag for the tagged union?
- Oleg B (3/3) Aug 29 2021 Paul, have you any plans to update `std.sumtype` to actual
- Paul Backus (7/10) Aug 29 2021 I did. The change was reverted by Atila Neves:
- Oleg B (47/58) Aug 29 2021 I write `sbin` and here I try to rewriter for use `std.sumtype`
- Paul Backus (40/45) Aug 29 2021 `staticIndexOf` returns `-1` when the type is not found, and
- Oleg B (16/30) Aug 30 2021 No problem with `typeIndex`, but `std.sumtype` have no
- drug (5/12) Aug 30 2021 A little tip: you can use just `cast()` to remove qualifiers:
- Oleg B (4/9) Aug 30 2021 I'm not sure what with simple `cast()` not `opCast` nor ctors are
- Paul Backus (8/23) Aug 30 2021 `SumType` does not define any `opCast` overloads, so you don't
- Oleg B (2/27) Aug 30 2021 Thanks!
- Steven Schveighoffer (5/9) Aug 29 2021 It was [added](https://github.com/dlang/phobos/pull/7886), and then
- SealabJaster (5/6) Aug 29 2021 What a shame... I've been using std.sumtype recently and I was
- Paul Backus (17/23) Aug 29 2021 If you find the lack of `typeIndex` is leading to clunky code,
- SealabJaster (29/30) Aug 29 2021 It is also of course totally possible I'm not using sumtypes
- SealabJaster (11/12) Aug 29 2021 While I'm on a tiny rant, I'd like to just mention that compiler
- Paul Backus (11/18) Aug 29 2021 I agree, this is annoying. My current best solution to this is:
- Paul Backus (51/79) Aug 29 2021 For cases like this you can use `tryMatch`, which does not
- SealabJaster (10/39) Aug 29 2021 An interesting way to think about things, which I assume is from
- surlymoor (3/12) Aug 29 2021 Can't wait until DIP1034 is fully implemented so one needn't do
- JG (25/79) Aug 29 2021 I have used something like the following (although I am finding I
- jmh530 (3/8) Mar 18 2021 Regardless of the other comments, it looks like the next release
- ryuukk_ (10/19) Mar 18 2021 I agree 1000% things are confusing when you want to manage memory
- ryuukk_ (9/9) Mar 18 2021 Things would improve drastically if std wasn't designed with
- JN (6/10) Mar 22 2021 Does anyone know if it would be possible to make it support (it
- Imperatorn (5/16) Mar 22 2021 Not that it really makes sense, but if you wanted to do that you
- JN (3/21) Mar 22 2021 isFahrenheit(Temperature(Fahrenheit(98.6)))
- Paul Backus (12/17) Mar 22 2021 You can do this by adding an additional overload to isFahrenheit:
- jmh530 (4/23) Mar 22 2021 What about something like
- Paul Backus (9/36) Mar 22 2021 Not sure what `BaseTypeOf` is supposed to do here, but if you
- jmh530 (4/15) Mar 22 2021 I was BaseTypeofOf!Temperature would be returning Fahrenheit in
- Meta (5/16) Mar 22 2021 I would love this too, but Walter is very against implicit
Hello everyone. Went to see what is being prepared in the new compiler and saw this https://dlang.org/changelog/pending.html#std-sumtype Is this realy final variant for including to phobos, not std.experimental? No way for getting tag explicitly (it's private), no way for getting type by tag, sumtype depend on order of types... I don't see any discussion about including it to phobos... Why? Nobody cares? I think algebraic types must be in phobos, but it must be fully complited. Otherwise it not neccessary: side libs will fix some misses and we don't get unified algebraics. For example std.json have no [de]serialization and vibe.data.json is more useful and used in many projects. More general question: why phobos so bad structured? No way to determine what can be used without gc, that need it (other D features like betterC in the same situation). Some basic actions requires couple of std libs (std.file, std.path etc). Why something things placed in experimental will be in experimental during several years, other placed to std directly (sumtype)? May be it's time to restructure std, and determine algorithm for place new code to it (like DIPs)?
Mar 18 2021
Is this realy final variant for including to phobos, not std.experimental? No way for getting tag explicitly (it's private), no way for getting type by tag, sumtype depend on order of types... I don't see any discussion about including it to phobos... Why? Nobody cares?I agree. Being able to extract items by type is missing. If the incorrect type is used, it can just assert(0); This makes it really complicated to use in nogc, since you cannot even create delegates to change things in your scope.
Mar 18 2021
On Thursday, 18 March 2021 at 15:04:13 UTC, rm wrote:This makes it really complicated to use in nogc, since you cannot even create delegates to change things in your scope.Yes you can. There's even a unit test for this specific use-case: https://github.com/dlang/phobos/blob/8281af7310aa876f2bdeb30fd176d952141b4c96/std/sumtype.d#L2403-L2410
Mar 18 2021
On 18/03/2021 17:12, Paul Backus wrote:On Thursday, 18 March 2021 at 15:04:13 UTC, rm wrote:I stand corrected. Now I'm going to have to go back to figure what was wrong with my code back then. I would still like to have tryMatch in nogc.This makes it really complicated to use in nogc, since you cannot even create delegates to change things in your scope.Yes you can. There's even a unit test for this specific use-case: https://github.com/dlang/phobos/blob/8281af7310aa876f2bdeb30fd176d952141b4c96/std/s mtype.d#L2403-L2410
Mar 18 2021
On Thursday, 18 March 2021 at 15:37:52 UTC, rm wrote:I would still like to have tryMatch in nogc.If -preview=dip1008 is ever implemented properly you will get this for free.
Mar 18 2021
On Thursday, 18 March 2021 at 14:42:03 UTC, Oleg B wrote:Hello everyone. Went to see what is being prepared in the new compiler and saw this https://dlang.org/changelog/pending.html#std-sumtype Is this realy final variant for including to phobos, not std.experimental? No way for getting tag explicitly (it's private), no way for getting type by tag, sumtype depend on order of types... I don't see any discussion about including it to phobos... Why? Nobody cares?There was discussion on Github [1] and on the forums [2]. [1] https://github.com/dlang/phobos/pull/7702 [2] https://forum.dlang.org/thread/dkizmcporviutijhqlcs forum.dlang.orgMay be it's time to restructure std, and determine algorithm for place new code to it (like DIPs)?I agree that the process for adding new modules to Phobos could do with an overhaul, and that the community should be involved in some way, as it is for DIPs.
Mar 18 2021
On Thursday, 18 March 2021 at 15:08:19 UTC, Paul Backus wrote:[1] https://github.com/dlang/phobos/pull/7702 [2] https://forum.dlang.org/thread/dkizmcporviutijhqlcs forum.dlang.orgThank for links, I don't saw these news in November. Since sumtype will be in phobos, can you explane algorithm of [de]serialization of general Sumtype value? In other libs it will be simple for serialization: 1. get tag -> write tag 2. switch for all tags (final switch + static foreach by enum members) -> write value example [1] https://github.com/deviator/sbin/blob/master/source/sbin/serialize.d#L76 and deserialization: 1. read tag 2. final switch + static foreach check tag -> read typed value -> write it to algebraic variable example [2] https://github.com/deviator/sbin/blob/master/source/sbin/deserialize.d#L189 for sumtype I see what I need make own enum (or use number) what I get through match: auto tag = val.match!( (Type1 t1) => 0, // or MyOwnValTag.type1 (Type2 t2) => 1, // or MyOwnValTag.type2 ... etc ); next write tag, in next match write value how to generate this match without mixins? how to get (in general way) type from sumtype val by own tag or number for deserialization? I think these problems have a solutions, but it more complicated (and need write more code) than use enum tags directly.
Mar 18 2021
On Thursday, 18 March 2021 at 15:58:55 UTC, Oleg B wrote:auto tag = val.match!( (Type1 t1) => 0, // or MyOwnValTag.type1 (Type2 t2) => 1, // or MyOwnValTag.type2 ... etc ); next write tag, in next match write value how to generate this match without mixins? how to get (in general way) type from sumtype val by own tag or number for deserialization?Something like this: alias QualifiedTypes = CopyTypeQualifiers!(typeof(val), val.Types); auto tag = val.match!(v => staticIndexOf!(typeof(v), QualifiedTypes));
Mar 18 2021
On Thursday, 18 March 2021 at 16:11:06 UTC, Paul Backus wrote:Something like this: alias QualifiedTypes = CopyTypeQualifiers!(typeof(val), val.Types); auto tag = val.match!(v => staticIndexOf!(typeof(v), QualifiedTypes));why it is not in library? or why tag is private?
Mar 18 2021
On Thursday, 18 March 2021 at 16:34:15 UTC, Oleg B wrote:On Thursday, 18 March 2021 at 16:11:06 UTC, Paul Backus wrote:Because I personally haven't needed it for anything, and nobody else has presented me with a convincing use-case for it until now. In general, it is much, much easier to add new features than to remove existing ones, so I try to put off adding a feature until I am absolutely sure it is the right decision.Something like this: alias QualifiedTypes = CopyTypeQualifiers!(typeof(val), val.Types); auto tag = val.match!(v => staticIndexOf!(typeof(v), QualifiedTypes));why it is not in library? or why tag is private?
Mar 18 2021
On Thursday, 18 March 2021 at 16:48:01 UTC, Paul Backus wrote:Because I personally haven't needed it for anything, and nobody else has presented me with a convincing use-case for it until now. In general, it is much, much easier to add new features than to remove existing ones, so I try to put off adding a feature until I am absolutely sure it is the right decision.Adding read-only tag is simple and useful change. If I understand code correctly tag is direct index of val.Types, it's right? May be depending on order of types must be fixed too ``` alias S1 = Sumtype!(int, float); alias S2 = Sumtype!(float, int); static assert (is(S1 == S2)); // false by now ``` because no different between S1 and S2 in practice use
Mar 18 2021
On 3/18/21 1:24 PM, Oleg B wrote:May be depending on order of types must be fixed too ``` alias S1 = Sumtype!(int, float); alias S2 = Sumtype!(float, int); static assert (is(S1 == S2)); // false by now ``` because no different between S1 and S2 in practice useThat requires sorting the types somehow, which isn't really easy or cheap at compile-time. It's the same for std.variant.Algebraic (although it's a runtime error instead of a compile-time one). It's kind of a tradeoff that you have to live with -- nice type checking, but you have to keep the same order for sanity. -Steve
Mar 18 2021
On Thursday, 18 March 2021 at 17:39:04 UTC, Steven Schveighoffer wrote:That requires sorting the types somehow, which isn't really easy or cheap at compile-time. It's the same for std.variant.Algebraic (although it's a runtime error instead of a compile-time one). It's kind of a tradeoff that you have to live with -- nice type checking, but you have to keep the same order for sanity. -SteveAs I know it solved in mir.algebraic [1] and code for solving isn't complicated [2] but it will be good if it be in library. [1] http://mir-core.libmir.org/mir_algebraic.html [2] example for some kind of tuple ``` struct Bar(T...) { T val; } template Foo(T...) { enum CmpTypes(T1, T2) = fullyQualifiedName!T1 < fullyQualifiedName!T2; alias Foo = Bar!(staticSort!(CmpTypes, T)); } ```
Mar 18 2021
On Thursday, 18 March 2021 at 17:24:13 UTC, Oleg B wrote:May be depending on order of types must be fixed too ``` alias S1 = Sumtype!(int, float); alias S2 = Sumtype!(float, int); static assert (is(S1 == S2)); // false by now ``` because no different between S1 and S2 in practice useunion U1 { int n; float f; } union U2 { float f; int n; } static assert(is(U1 == U2)); // fails D is a nominally-typed language, not a structurally-typed one. That means types that are structurally identical (like the unions and SumTypes in the above examples) are still considered separate types if their names are spelled differently. IMO the behavior of SumType in this regard is perfectly consistent with the rest of the language. If you want to use structural typing instead of nominal typing in your own code, you can define template predicates to check for SumTypes with a particular structure, the same way Phobos defines predicates like `isInputRange` to check for types with a particular structure.
Mar 18 2021
On Thursday, 18 March 2021 at 18:09:38 UTC, Paul Backus wrote:union U1 { int n; float f; } union U2 { float f; int n; } static assert(is(U1 == U2)); // fails D is a nominally-typed language, not a structurally-typed one. That means types that are structurally identical (like the unions and SumTypes in the above examples) are still considered separate types if their names are spelled differently. IMO the behavior of SumType in this regard is perfectly consistent with the rest of the language. If you want to use structural typing instead of nominal typing in your own code, you can define template predicates to check for SumTypes with a particular structure, the same way Phobos defines predicates like `isInputRange` to check for types with a particular structure.okey, I agree but read-only tag (kind, type index) is key feature in chouse between sumtype and other for me, and I hope it will be added before next compiler release...
Mar 18 2021
On Thursday, 18 March 2021 at 18:42:32 UTC, Oleg B wrote:but read-only tag (kind, type index) is key feature in chouse between sumtype and other for me, and I hope it will be added before next compiler release...https://github.com/pbackus/sumtype/pull/57 https://github.com/dlang/phobos/pull/7886
Mar 18 2021
On Friday, 19 March 2021 at 01:31:59 UTC, Paul Backus wrote:On Thursday, 18 March 2021 at 18:42:32 UTC, Oleg B wrote:Thank you very much!but read-only tag (kind, type index) is key feature in chouse between sumtype and other for me, and I hope it will be added before next compiler release...https://github.com/pbackus/sumtype/pull/57 https://github.com/dlang/phobos/pull/7886
Mar 19 2021
On 3/18/21 9:42 PM, Oleg B wrote:but read-only tag (kind, type index) is key feature in chouse between sumtype and other for me, and I hope it will be added before next compiler release...Totally agree, it is an important feature.
Mar 19 2021
On Friday, 19 March 2021 at 07:28:19 UTC, drug wrote:On 3/18/21 9:42 PM, Oleg B wrote:https://github.com/pbackus/sumtype/pull/57 https://github.com/dlang/phobos/pull/7886but read-only tag (kind, type index) is key feature in chouse between sumtype and other for me, and I hope it will be added before next compiler release...Totally agree, it is an important feature.
Mar 19 2021
On Friday, 19 March 2021 at 07:28:19 UTC, drug wrote:On 3/18/21 9:42 PM, Oleg B wrote:Can anyone explain to me why?but read-only tag (kind, type index) is key feature in chouse between sumtype and other for me, and I hope it will be added before next compiler release...Totally agree, it is an important feature.
Mar 23 2021
On 3/23/21 10:45 AM, Atila Neves wrote:On Friday, 19 March 2021 at 07:28:19 UTC, drug wrote:1. It costs nothing (returning tag is pretty much free). 2. reasoning about things to do with a SumType without having to generate (possibly) an entire set of handler functions allows different designs or writing code in more efficient/straightforward ways. Consider an assert that validates a SumType is a certain type: SumType!(string, float, int) someType; ... someType.match!((T t) {assert(is(T == int)); }); vs. assert(someType.typeIndex == 2); Which looks better? Which performs better? For the first case, all the types have to be used to build the lambda, which means 4 more functions, and the match call has to basically do a switch on all possible tags, and call the right function, which then throws an assert error or not. Or, without asserts enabled, builds 4 functions empty functions which hopefully are inlined. The second implementation checks if an integer equals 2. Or if asserts are disabled, elides the whole statement. Only drawback I see is it's very dependent on the type not changing indexes. All that said, the taggedalgebraic project looks nicer to me: union Values { string String; float Float; int Integer; } TaggedAlgebraic!(Values) algType; ... assert(algType.kind == algType.Kind.Integer); -SteveOn 3/18/21 9:42 PM, Oleg B wrote:Can anyone explain to me why?but read-only tag (kind, type index) is key feature in chouse between sumtype and other for me, and I hope it will be added before next compiler release...Totally agree, it is an important feature.
Mar 23 2021
On Tuesday, 23 March 2021 at 16:29:52 UTC, Steven Schveighoffer wrote:Consider an assert that validates a SumType is a certain type: SumType!(string, float, int) someType; ... someType.match!((T t) {assert(is(T == int)); }); vs. assert(someType.typeIndex == 2);Well, first, we would never write a naked magic number like this in production code, so for the sake of a fair comparison, let's fix that issue: assert(someType.typeIndex == staticIndexOf!(int, someType.Types)); Moving on--if I were doing this often enough for it to matter, I would define a helper function: bool contains(T, ST)(ST st) if (isSumType!ST) { return st.match!(value => is(typeof(value) == T)); } Usage: assert(someType.contains!int); Personally I think this is far preferable to the typeIndex version in terms of readability. In terms of performance: I checked the generated assembly, and `ldc -O` inlines everything, but `dmd -O -inline` does not, so if you are using DMD you're leaving performance on the table here (but isn't that true in general?). There is also some additional compile-time overhead from instantiating the templates.
Mar 23 2021
On Tuesday, 23 March 2021 at 16:29:52 UTC, Steven Schveighoffer wrote:On 3/23/21 10:45 AM, Atila Neves wrote:I don't think this is enough of a reason.On Friday, 19 March 2021 at 07:28:19 UTC, drug wrote:1. It costs nothing (returning tag is pretty much free).On 3/18/21 9:42 PM, Oleg B wrote:Can anyone explain to me why?but read-only tag (kind, type index) is key feature in chouse between sumtype and other for me, and I hope it will be added before next compiler release...Totally agree, it is an important feature.2. reasoning about things to do with a SumType without having to generate (possibly) an entire set of handler functions allows different designs or writing code in more efficient/straightforward ways.This is the part I don't get. Why would one want to do that? To me this feels like checking for the dynamic type of an object in OOP, in the sense that if you're doing that you're probably doing something wrong.Consider an assert that validates a SumType is a certain type: SumType!(string, float, int) someType; ... someType.match!((T t) {assert(is(T == int)); }); vs. assert(someType.typeIndex == 2); Which looks better?The former.Which performs better?It shouldn't matter - performance considerations in the absence of running a profiler are futile. If nobody notices, it doesn't matter. If someone noticed, a profiler gets run and the code optimised where it's actually slow. Having said that, I think that if there are two alternatives to getting the job done, and the two are equally readable/maintainable, prefer the fastest one. Or as Sutter/Alexandrescu once wrote, "belated pessimization is the root of no good". For the first case,all the types have to be used to build the lambda, which means 4 more functions, and the match call has to basically do a switch on all possible tags, and call the right function, which then throws an assert error or not. Or, without asserts enabled, builds 4 functions empty functions which hopefully are inlined. The second implementation checks if an integer equals 2. Or if asserts are disabled, elides the whole statement. Only drawback I see is it's very dependent on the type not changing indexes. All that said, the taggedalgebraic project looks nicer to me: union Values { string String; float Float; int Integer; } TaggedAlgebraic!(Values) algType; ... assert(algType.kind == algType.Kind.Integer);If one wants to do that sort of thing, yes, this is nicer. I'm still at a loss as to why one would *want* to do such a thing. I think it's useful to remember that in languages where sum types and pattern matching are features there's no way to do this.
Mar 25 2021
I think that `kind` vs `handler` is more like old-school vs modern style. They are equal in general. Modern compilers are good in optimization. I chose TaggedAlgebraic for my projects about 7 years ago and don't remember the exact reason I was need for kind feature. In general I agree to Steven. I can add to his post that kind lets you do: ```D switch(kind) { case Kind.foo0..case Kind.foo5: doSomething1; break; case Kind.bar: case Kind.baz: case Kind.foobar: doSomething2; break; default: doDefaultThings; } ``` using handlers: ```D someType.match!( (Foo0 foo) => doSomething1, (Foo1 foo) => doSomething1, (Foo2 foo) => doSomething1, (Foo3 foo) => doSomething1, (Foo4 foo) => doSomething1, (Bar bar) => doSomething2, (Baz baz) => doSomething2, (FooBar fb) => doSomething2, (_) => doDefaultThings; ); ``` These examples are verbose equally but the first version contains less boilerplate. I believe both approaches are good. They complement each other.
Mar 25 2021
On Thursday, 25 March 2021 at 15:03:37 UTC, drug wrote:In general I agree to Steven. I can add to his post that kind lets you do: ```D switch(kind) { case Kind.foo0..case Kind.foo5: doSomething1; break; case Kind.bar: case Kind.baz: case Kind.foobar: doSomething2; break; default: doDefaultThings; } ``` using handlers: ```D someType.match!( (Foo0 foo) => doSomething1, (Foo1 foo) => doSomething1, (Foo2 foo) => doSomething1, (Foo3 foo) => doSomething1, (Foo4 foo) => doSomething1, (Bar bar) => doSomething2, (Baz baz) => doSomething2, (FooBar fb) => doSomething2, (_) => doDefaultThings; ); ``` These examples are verbose equally but the first version contains less boilerplate.Only if you don't know what you're doing. Check this out: template restrictTo(Args...) if (Args.length >= 1) { import std.meta : IndexOf = staticIndexOf; alias Types = Args[0 .. $-1]; alias fun = Args[$]; auto ref restrictTo(T)(auto ref T value) if (IndexOf!(T, Types) >= 0); { import core.lifetime: forward static assert(IndexOf!(T, Types) >= 0); return fun(forward!value); } } Usage: someType.match!( restrictTo!(Foo0, Foo1, Foo2, Foo3, Foo4, val => doSomething1 ), restrictTo!(Bar, Baz, FooBar, val => doSomething2 ), _ => doDefaultThings );
Mar 25 2021
On 3/25/21 6:17 PM, Paul Backus wrote:Usage: someType.match!( restrictTo!(Foo0, Foo1, Foo2, Foo3, Foo4, val => doSomething1 ), restrictTo!(Bar, Baz, FooBar, val => doSomething2 ), _ => doDefaultThings );Looks good
Mar 25 2021
On Thursday, 25 March 2021 at 15:17:31 UTC, Paul Backus wrote:Only if you don't know what you're doing. Check this out: template restrictTo(Args...) if (Args.length >= 1) { import std.meta : IndexOf = staticIndexOf; alias Types = Args[0 .. $-1]; alias fun = Args[$]; auto ref restrictTo(T)(auto ref T value) if (IndexOf!(T, Types) >= 0); { import core.lifetime: forward static assert(IndexOf!(T, Types) >= 0); return fun(forward!value); } } Usage: someType.match!( restrictTo!(Foo0, Foo1, Foo2, Foo3, Foo4, val => doSomething1 ), restrictTo!(Bar, Baz, FooBar, val => doSomething2 ), _ => doDefaultThings );This comment is not intended as criticism. SumType looks like a very good package. But, I am confused by this response. In particular, the expectation for when such a technique would be used. Use of D's case-range statement is not a particularly advanced technique. But writing the 'restrictTo' template requires a good bit more knowledge. I doubt the intent is that people will write the equivalent of 'restrictTo' whenever coming across a 'match' use like this. But I don't see 'restrictTo' included with SumType. Is the thought that this will be rare that it won't be needed? Or perhaps, that with additional experience, such a facility might be added to SumType later? Or something much more basic that I'm missing? Separate thing - I think the catch-all handler could be a bit better documented. Is the lack of a type that triggers it? Or is underscore ('_') special (ala Scala). If the latter, then are the '_1' and '_2' forms shown in the multiple dispatch examples special? (I'm guessing that there's nothing special about the underscore forms, but people familiar with Scala might assume some else.) I'm looking at the docs here: https://pbackus.github.io/sumtype/sumtype.SumType.html. --Jon
Mar 29 2021
On Tuesday, 30 March 2021 at 03:13:04 UTC, Jon Degenhardt wrote:In particular, the expectation for when such a technique would be used. Use of D's case-range statement is not a particularly advanced technique. But writing the 'restrictTo' template requires a good bit more knowledge. I doubt the intent is that people will write the equivalent of 'restrictTo' whenever coming across a 'match' use like this.I wouldn't expect users to jump straight to the fully-generalized version, but you don't need a lot of fancy template machinery to get the same result in a specific case. For example: (val) { alias T = typeof(val); static assert(is(T == Foo0) || is(T == Foo1) || is(T == Foo2) || is(T == Foo3) || is(T == Foo4)); doSomething1; } And once you have that, it's not a huge leap to notice that you can clean it up a bit with `staticIndexOf`. And once you do that a few times, maybe you start to think about how to generalize it. I will grant that it may not be obvious that you can use `static assert` with `match` in this way to begin with. That's something that can be addressed by improving SumType's documentation.But I don't see 'restrictTo' included with SumType. Is the thought that this will be rare that it won't be needed? Or perhaps, that with additional experience, such a facility might be added to SumType later? Or something much more basic that I'm missing?The thought is: I don't know in advance what will be common and what won't, so I think it's best to wait for feedback before adding facilities like this. In the long run, I expect we will see some utility templates like `restrictTo` added--either to the `sumtype` module, or to a more general module like `std.functional` if they stand on their own.Separate thing - I think the catch-all handler could be a bit better documented. Is the lack of a type that triggers it? Or is underscore ('_') special (ala Scala). If the latter, then are the '_1' and '_2' forms shown in the multiple dispatch examples special? (I'm guessing that there's nothing special about the underscore forms, but people familiar with Scala might assume some else.) I'm looking at the docs here: https://pbackus.github.io/sumtype/sumtype.SumType.html.Your guess that the underscore is not special is correct. This should be clear from reading the documentation for match [1], but I expect there are many users who read only the examples and skip the prose, so it would be best to add a note about this to the examples as well. [1] https://pbackus.github.io/sumtype/sumtype.match.html
Mar 30 2021
On 3/30/21 12:32 PM, Paul Backus wrote:What might be nice is to have some simplifiers for match to prevent having to jump through the hoops. For example, a match flavor that throws by default, or one that ignores unhandled types. This way, you don't have to write stuff like `(_) {}` at the end of your handlers. FWIW, taggedalgebraic has `visit` to enforce all items are handled, and `tryVisit` that throws if at runtime it determines no visitors match the current type. -SteveSeparate thing - I think the catch-all handler could be a bit better documented. Is the lack of a type that triggers it? Or is underscore ('_') special (ala Scala). If the latter, then are the '_1' and '_2' forms shown in the multiple dispatch examples special? (I'm guessing that there's nothing special about the underscore forms, but people familiar with Scala might assume some else.) I'm looking at the docs here: https://pbackus.github.io/sumtype/sumtype.SumType.html.Your guess that the underscore is not special is correct. This should be clear from reading the documentation for match [1], but I expect there are many users who read only the examples and skip the prose, so it would be best to add a note about this to the examples as well.
Mar 30 2021
On Tuesday, 30 March 2021 at 17:01:29 UTC, Steven Schveighoffer wrote:What might be nice is to have some simplifiers for match to prevent having to jump through the hoops. For example, a match flavor that throws by default, or one that ignores unhandled types. This way, you don't have to write stuff like `(_) {}` at the end of your handlers. FWIW, taggedalgebraic has `visit` to enforce all items are handled, and `tryVisit` that throws if at runtime it determines no visitors match the current type.sumtype has had tryMatch [1] since version 0.4.0 (released May 2018). For ignoring types, I have found the following utility function handy: void ignore(T)(auto ref T) {} You can instantiate it explicitly to ignore a specific type: obj.match!( ignore!A, (B b) { doSomething1; }, (C c) { doSomething2; } ); Or you can use it as a catch-all handler: obj.match!( (A a) { doSomethingWith(a); }, ignore ); [1] https://pbackus.github.io/sumtype/sumtype.tryMatch.html
Mar 30 2021
On 3/30/21 1:14 PM, Paul Backus wrote:On Tuesday, 30 March 2021 at 17:01:29 UTC, Steven Schveighoffer wrote:Yeah, that actually looks pretty good. Forgive my ignorance, I have not looked at any depth at SumType. I think `ignore` would be a great addition to the library, and makes the code much easier to read. I can't think of a `match` name that would look better than just specifying ignore in the list. One thing that is sticking out via this mechanism for pattern matching is that with lambdas, you have to name the parameter (for everything but keywords) or you will not get what you are looking for. So things like (B b) { doSomething2; } would look nicer as (B) { doSomething2; } but obviously will not do what you would expect. Hence the usage of `_` in the previous examples. Not sure if there might be a language improvement to help with this. It probably is not that common anyway. -SteveWhat might be nice is to have some simplifiers for match to prevent having to jump through the hoops. For example, a match flavor that throws by default, or one that ignores unhandled types. This way, you don't have to write stuff like `(_) {}` at the end of your handlers. FWIW, taggedalgebraic has `visit` to enforce all items are handled, and `tryVisit` that throws if at runtime it determines no visitors match the current type.sumtype has had tryMatch [1] since version 0.4.0 (released May 2018). For ignoring types, I have found the following utility function handy: void ignore(T)(auto ref T) {} You can instantiate it explicitly to ignore a specific type: obj.match!( ignore!A, (B b) { doSomething1; }, (C c) { doSomething2; } ); Or you can use it as a catch-all handler: obj.match!( (A a) { doSomethingWith(a); }, ignore ); [1] https://pbackus.github.io/sumtype/sumtype.tryMatch.html
Mar 30 2021
On Tuesday, 30 March 2021 at 16:32:21 UTC, Paul Backus wrote:I will grant that it may not be obvious that you can use `static assert` with `match` in this way to begin with. That's something that can be addressed by improving SumType's documentation.Yeah, I would say its not obvious :) But, there does seem to be a fairly good opportunity for improving usability via documentation. As another example, the ability to define a catch-all handler is not mentioned in the text (or at least I couldn't find it). It's in the examples. I don't know that I'll have time to propose doc updates via pull-request, but I might have time to make suggestions by some other mechanism, like issue reports something else. Is there a mechanism/venue that would work for you? --Jon
Mar 31 2021
On Wednesday, 31 March 2021 at 17:34:00 UTC, Jon Degenhardt wrote:As another example, the ability to define a catch-all handler is not mentioned in the text (or at least I couldn't find it). It's in the examples.Well, it's not really a specific "ability"; it's just a natural consequence of the fact that you're allowed to use templates as handlers. I think an example is the most appropriate place to illustrate something like that, but it is probably worth adding a link to the documentation to explicitly point out the connection.I don't know that I'll have time to propose doc updates via pull-request, but I might have time to make suggestions by some other mechanism, like issue reports something else. Is there a mechanism/venue that would work for you?If you want to make sure that it's seen by me specifically, the easiest way is probably to submit an issue to the `sumtype` repository on Github [1]. Another possibility is to submit a report to issues.dlang.org and add me to the CC list. I have not tried this myself, but I expect Bugzilla would notify me. [1] https://github.com/pbackus/sumtype/issues/
Mar 31 2021
On Thursday, 25 March 2021 at 14:28:06 UTC, Atila Neves wrote:If one wants to do that sort of thing, yes, this is nicer. I'm still at a loss as to why one would *want* to do such a thing. I think it's useful to remember that in languages where sum types and pattern matching are features there's no way to do this.I suspect the big reason is that a lot of D programmers aren't super familiar with these languages, or with functional programming in general, so they find SumType's match function less comfortable and approachable than switching on an enum (even though it's fundamentally the same thing). There's a great illustration of this in a forum thread from last year [1]. Once I showed how to convert the code to use SumType and match [2], the author could understand it, but they weren't able to come up with it on their own. [1] https://forum.dlang.org/post/kjozzeynentyrarssnzz forum.dlang.org [2] https://forum.dlang.org/post/bzueywubiazbkxvqnaid forum.dlang.org
Mar 25 2021
On Thursday, 25 March 2021 at 15:05:40 UTC, Paul Backus wrote:On Thursday, 25 March 2021 at 14:28:06 UTC, Atila Neves wrote:Completely plausible but in my opinion not nearly enough of a reason to offer an escape hatch.I think it's useful to remember that in languages where sum types and pattern matching are features there's no way to do this.I suspect the big reason is that a lot of D programmers aren't super familiar with these languages, or with functional programming in general, so they find SumType's match function less comfortable and approachablethan switching on an enum (even though it's fundamentally the same thing).Matching is like *final* switching on the enum, except that's that the only thing you can do so you can't screw up.
Mar 25 2021
On Friday, 26 March 2021 at 02:56:29 UTC, Atila Neves wrote:Completely plausible but in my opinion not nearly enough of a reason to offer an escape hatch.IMO typeIndex is not really an "escape hatch", because while you can write: if (sumTypeInstance.typeIndex == 2) { // ... } ...there is still nothing you can do inside the `if` body to access the value without going through `match`. To follow the OOP analogy, it would be like having access to `instanceof` but not downcasts--you can check what the runtime type is, but you still need to go through the normal runtime dispatch mechanism to do anything with the object. I think this principle--that you can't touch the SumType's value without using `match`--is a good place to draw the line on what we're willing to allow in SumType's public API and what we're not, but I am happy to hear arguments for other positions. Perhaps we can talk about this during the upcoming BeerConf.
Mar 26 2021
On 3/25/21 10:28 AM, Atila Neves wrote:On Tuesday, 23 March 2021 at 16:29:52 UTC, Steven Schveighoffer wrote:But it is a reason. If it costs nothing to return it, and doesn't HARM anything to return it, why not make it available? A tagged union is required to store the tag, so it's not like that piece of data will cease to be available.On 3/23/21 10:45 AM, Atila Neves wrote:I don't think this is enough of a reason.On Friday, 19 March 2021 at 07:28:19 UTC, drug wrote:1. It costs nothing (returning tag is pretty much free).On 3/18/21 9:42 PM, Oleg B wrote:Can anyone explain to me why?but read-only tag (kind, type index) is key feature in chouse between sumtype and other for me, and I hope it will be added before next compiler release...Totally agree, it is an important feature.I'm not sure if you have considered that `match` actually does exactly what you are saying not to do. In fact it has to. `SumType` has a dynamic type. It's just easier to write code sometimes if you have the primitives to do it.2. reasoning about things to do with a SumType without having to generate (possibly) an entire set of handler functions allows different designs or writing code in more efficient/straightforward ways.This is the part I don't get. Why would one want to do that? To me this feels like checking for the dynamic type of an object in OOP, in the sense that if you're doing that you're probably doing something wrong.We disagree on that.Consider an assert that validates a SumType is a certain type: SumType!(string, float, int) someType; ... someType.match!((T t) {assert(is(T == int)); }); vs. assert(someType.typeIndex == 2); Which looks better?The former.I'm not talking about runtime performance.Which performs better?It shouldn't matter - performance considerations in the absence of running a profiler are futile. If nobody notices, it doesn't matter. If someone noticed, a profiler gets run and the code optimised where it's actually slow.Having said that, I think that if there are two alternatives to getting the job done, and the two are equally readable/maintainable, prefer the fastest one. Or as Sutter/Alexandrescu once wrote, "belated pessimization is the root of no good".I don't need a profiler to tell me that checking an integer against 2 is easier for the compiler to deal with than: 1. static-foreaching over a list of templates 2. Seeing which templates match which types, which also have to be static-foreached over 3. Determining if the lambda functions can be inlined 4. Inlining said functions 5. Optimizing out the combination of all the instantiated functions into "check this integer against 2".I see code like this all the time: static if(is(T == int)) { ... } This directly maps to what one needs to do here. You are checking the type of a dynamic type against one of the possibilities (which necessarily is done at runtime). If for example, I want to only execute some code if the type is an int, then I still have to handle all the other types if I use `match`. The code "if it's an int then execute this code" reads so much better than "for all types in the sumtype, check if the type is an int, and if so, execute this code, and if not, execute code that does nothing." The only awkward part is using the literal `2`, which probably I would extract down to using a statcIndexOf (which I don't really like, because more meaningless work for the compiler).The second implementation checks if an integer equals 2. Or if asserts are disabled, elides the whole statement. Only drawback I see is it's very dependent on the type not changing indexes. All that said, the taggedalgebraic project looks nicer to me: union Values { string String; float Float; int Integer; } TaggedAlgebraic!(Values) algType; ... assert(algType.kind == algType.Kind.Integer);If one wants to do that sort of thing, yes, this is nicer. I'm still at a loss as to why one would *want* to do such a thing.I think it's useful to remember that in languages where sum types and pattern matching are features there's no way to do this.In swift, for instance, you can use switch on a type. Something like that built into D would allow this to be much more palatable, but would probably require first-class types. ``` switch(sumtype.type) { case int v: doMyCode(v); break; default: break; } ``` But I still don't love it. If SumType were a compiler builtin, it would be much more appealing (then you aren't involving all sorts of template machinery to figure out which code to run, and hope the compiler optimizes it out). The fact that the tag is there, but you can't access it is.... puzzling. It's OK, taggedalgebraic exists, so I can just use that instead of SumType. Hopefully std.sumtype doesn't become a rarely used module, but I'll stay away from it for now. -Steve
Mar 29 2021
On Tuesday, 23 March 2021 at 16:29:52 UTC, Steven Schveighoffer wrote:Consider an assert that validates a SumType is a certain type: SumType!(string, float, int) someType; ... someType.match!((T t) {assert(is(T == int)); }); vs. assert(someType.typeIndex == 2);How about e.g.: assert(someType.has!int); int i = someType.unwrap!int; // asserts has!int
Mar 31 2021
On Tuesday, 23 March 2021 at 14:45:18 UTC, Atila Neves wrote:On Friday, 19 March 2021 at 07:28:19 UTC, drug wrote:Simple general example is serialization and deserialization of algebraic value: without tag (kind, type index) it's not impossible but more complicated. For serialization you need write tag first (`match` is good for serialization exist value) and then deserialize you need to read tag and do deserialization for writed value type (how it must be with `match`?). If tag is private and/or it not direct point to types you need "jump through hoops" for this simple algo.On 3/18/21 9:42 PM, Oleg B wrote:Can anyone explain to me why?but read-only tag (kind, type index) is key feature in chouse between sumtype and other for me, and I hope it will be added before next compiler release...Totally agree, it is an important feature.
Mar 31 2021
On Thursday, 18 March 2021 at 18:09:38 UTC, Paul Backus wrote:On Thursday, 18 March 2021 at 17:24:13 UTC, Oleg B wrote:Even union U1 { int n; float f; } union U2 { int n; float f; } static assert(is(U1 == U2)); // also fails If types have different names, they're considered different. It's that simple. S1 and S2 shouldn't be considered equal IMO.May be depending on order of types must be fixed too ``` alias S1 = Sumtype!(int, float); alias S2 = Sumtype!(float, int); static assert (is(S1 == S2)); // false by now ``` because no different between S1 and S2 in practice useunion U1 { int n; float f; } union U2 { float f; int n; } static assert(is(U1 == U2)); // fails
Mar 18 2021
I'm not a fan of the syntax.. why is it a library instead of a language feature?.. ``` Fahrenheit toFahrenheit(Temperature t) { return Fahrenheit( t.match!( (Fahrenheit f) => f.degrees, (Celsius c) => c.degrees * 9.0/5 + 32, (Kelvin k) => k.degrees * 9.0/5 - 459.4 ) ); } ``` vs ``` Fahrenheit toFahrenheit(Temperature t) { return match(t) { (Fahrenheit f) => f.degrees, (Celsius c) => c.degrees * 9.0/5 + 32, (Kelvin k) => k.degrees * 9.0/5 - 459.4 }; } ``` I don't understand why make things confusing when it can be done simpler Discriminated union should be a language feature, not lib! Because now you depend on ``std``
Mar 18 2021
On Thursday, 18 March 2021 at 18:06:45 UTC, ryuukk_ wrote:I'm not a fan of the syntax.. why is it a library instead of a language feature?..Because it's easier to write a library than to go through the whole process of writing a DIP for a new language feature, getting it accepted, and implementing it in the compiler. If you or anyone else wants to write a DIP to add sum types to D as a language feature, I will happily support the effort, but I am not going to do it myself.Because now you depend on ``std```std.sumtype` has no non-optional dependencies on Phobos outside of compile time, so you can use it even if you do not want to depend on anything else in `std`.
Mar 18 2021
On Thursday, 18 March 2021 at 18:15:29 UTC, Paul Backus wrote:On Thursday, 18 March 2021 at 18:06:45 UTC, ryuukk_ wrote:That's how i feel about it, people didn't care enough and easiest solution picked (let's put this lib instead), now you have to use a feature, as a lib, calling functions that looks like template functions, in the end it is confusing i can switch(t), but i can't match(t), i need to use a different syntaxI'm not a fan of the syntax.. why is it a library instead of a language feature?..Because it's easier to write a library than to go through the whole process of writing a DIP for a new language feature, getting it accepted, and implementing it in the compiler. If you or anyone else wants to write a DIP to add sum types to D as a language feature, I will happily support the effort, but I am not going to do it myself.Because now you depend on ``std```std.sumtype` has no non-optional dependencies on Phobos outside of compile time, so you can use it even if you do not want to depend on anything else in `std`.
Mar 18 2021
On Thursday, 18 March 2021 at 18:29:34 UTC, ryuukk_ wrote:That's how i feel about it, people didn't care enough and easiest solution picked (let's put this lib instead), now you have to use a feature, as a lib, calling functions that looks like template functions, in the end it is confusing i can switch(t), but i can't match(t), i need to use a different syntaxI cared enough to spend my free time for the last *three years* working on the sumtype library and submitting it for inclusion in Phobos. That's more than you've done, I'll bet. I understand your frustration, but these kinds of disparaging comments are extremely disrespectful, and you should avoid making them if you want anyone to take your criticisms seriously.
Mar 18 2021
On Thursday, 18 March 2021 at 18:40:01 UTC, Paul Backus wrote:On Thursday, 18 March 2021 at 18:29:34 UTC, ryuukk_ wrote:I apologies if i sounded rude or disrespectful, that wasn't my intention As i said in the other reply, sumtype as a library is excellent, sumtype in the std on other than is where i disagree, if inclusion, that would be as a language feature, to be useful for everyone, and to enhance the syntax for everyoneThat's how i feel about it, people didn't care enough and easiest solution picked (let's put this lib instead), now you have to use a feature, as a lib, calling functions that looks like template functions, in the end it is confusing i can switch(t), but i can't match(t), i need to use a different syntaxI cared enough to spend my free time for the last *three years* working on the sumtype library and submitting it for inclusion in Phobos. That's more than you've done, I'll bet. I understand your frustration, but these kinds of disparaging comments are extremely disrespectful, and you should avoid making them if you want anyone to take your criticisms seriously.
Mar 18 2021
On Thursday, 18 March 2021 at 18:15:29 UTC, Paul Backus wrote:On Thursday, 18 March 2021 at 18:06:45 UTC, ryuukk_ wrote:The syntax is a result of it not being a language feature (the lib itself is perfectly fine, don't get me wrong! but the problem i have is it'd be better as a language feature) I'd love to help create a DIP for it, but making it as a lib now, and then removing it few months/year later will feel bad because that's gonna be code people will have to change, again, hence the importance of not taking shortcuts, we need think long termI'm not a fan of the syntax.. why is it a library instead of a language feature?..Because it's easier to write a library than to go through the whole process of writing a DIP for a new language feature, getting it accepted, and implementing it in the compiler. If you or anyone else wants to write a DIP to add sum types to D as a language feature, I will happily support the effort, but I am not going to do it myself.
Mar 18 2021
On Thursday, 18 March 2021 at 18:40:49 UTC, ryuukk_ wrote:I'd love to help create a DIP for it, but making it as a lib now, and then removing it few months/year later will feel bad because that's gonna be code people will have to change, again, hence the importance of not taking shortcuts, we need think long termThere is no need to remove the library even if a built-in version is added. The library version can simply be updated to alias itself to the built-in version, and its documentation can be hidden to discourage new code from using it.
Mar 18 2021
On Thursday, 18 March 2021 at 18:40:49 UTC, ryuukk_ wrote:On Thursday, 18 March 2021 at 18:15:29 UTC, Paul Backus wrote:Instead of spending three years on the DIP, start small and spend three days and see how far you come.[...]The syntax is a result of it not being a language feature (the lib itself is perfectly fine, don't get me wrong! but the problem i have is it'd be better as a language feature) I'd love to help create a DIP for it, but making it as a lib now, and then removing it few months/year later will feel bad because that's gonna be code people will have to change, again, hence the importance of not taking shortcuts, we need think long term
Mar 23 2021
I agree that the process for adding new modules to Phobos could do with an overhaul, and that the community should be involved in some way, as it is for DIPs.
Mar 29 2021
On 3/18/21 12:11 PM, Paul Backus wrote:On Thursday, 18 March 2021 at 15:58:55 UTC, Oleg B wrote:Wait, you can't access the tag for the tagged union? FYI, taggedalgebraic, it's simply val.kind. I'd suggest giving read-only access to the tag. The types are already accessible. -Steveauto tag = val.match!( (Type1 t1) => 0, // or MyOwnValTag.type1 (Type2 t2) => 1, // or MyOwnValTag.type2 ... etc ); next write tag, in next match write value how to generate this match without mixins? how to get (in general way) type from sumtype val by own tag or number for deserialization?Something like this: alias QualifiedTypes = CopyTypeQualifiers!(typeof(val), val.Types); auto tag = val.match!(v => staticIndexOf!(typeof(v), QualifiedTypes));
Mar 18 2021
Paul, have you any plans to update `std.sumtype` to actual version of `sumtype` (1.1.x)? `typeIndex` is needed
Aug 29 2021
On Sunday, 29 August 2021 at 14:00:30 UTC, Oleg B wrote:Paul, have you any plans to update `std.sumtype` to actual version of `sumtype` (1.1.x)? `typeIndex` is neededI did. The change was reverted by Atila Neves: https://github.com/dlang/phobos/pull/7922 He was not satisfied with the rationale given in this thread for adding `typeIndex`. Since you use it yourself, you can probably give a better example use-case than I did; feel free to add your own comment to the discussion.
Aug 29 2021
On Sunday, 29 August 2021 at 14:25:11 UTC, Paul Backus wrote:On Sunday, 29 August 2021 at 14:00:30 UTC, Oleg B wrote:I write `sbin` and here I try to rewriter for use `std.sumtype` https://github.com/deviator/sbin/blob/master/source/sbin/type.d#L147 like this ```d static if (isTagged!(T).isSumType) { version (Have_std_sumtype) { import std : staticIndexOf; // version from std doesn't have typeIndex return cast(TaggedTagType!T)( sumtype.match!(v => staticIndexOf!(Unqual!(typeof(v)), T.Types))(val)); } else return cast(TaggedTagType!(T))(val.typeIndex); } ``` but on this code I get problem: ```d alias UT3 = SumType!(typeof(null), byte, This[]); unittest { auto val1 = UT3([ UT3(42), UT3(null), UT3([ UT3(null), UT3(65) ]), UT3(12) ]); import std : stderr; auto data = sbinSerialize(val1); stderr.writeln(data); stderr.writeln([2, 4, 1, 42, 0, 2, 2, 0, 1, 65, 1, 12]); assert (data == [2, 4, 1, 42, 0, 2, 2, 0, 1, 65, 1, 12]); auto val2 = sbinDeserialize!UT3(data); assert (val1 == val2); } ``` output: ``` [255, 4, 1, 42, 0, 255, 2, 0, 1, 65, 1, 12] [2, 4, 1, 42, 0, 2, 2, 0, 1, 65, 1, 12] ... assertion ... ``` It means that `sumtype.match!(v => staticIndexOf!(Unqual!(typeof(v)), T.Types))(val));` doesn't return true value of type index (255 instead of 2). Can you suggest how to rewrite it? If it not possible, may be it can be strong argument for adding `typeIndex`? ps sumtype 1.1.4 with `typeIndex` works perfect with `UT3`.Paul, have you any plans to update `std.sumtype` to actual version of `sumtype` (1.1.x)? `typeIndex` is neededI did. The change was reverted by Atila Neves: https://github.com/dlang/phobos/pull/7922 He was not satisfied with the rationale given in this thread for adding `typeIndex`. Since you use it yourself, you can probably give a better example use-case than I did; feel free to add your own comment to the discussion.
Aug 29 2021
On Sunday, 29 August 2021 at 16:04:53 UTC, Oleg B wrote:It means that `sumtype.match!(v => staticIndexOf!(Unqual!(typeof(v)), T.Types))(val));` doesn't return true value of type index (255 instead of 2).`staticIndexOf` returns `-1` when the type is not found, and `255` is what you get when you cast `-1` to `ubyte`.Can you suggest how to rewrite it? If it not possible, may be it can be strong argument for adding `typeIndex`?Sure. Here's the implementation of `typeIndex` using `match`: ```d /** * Returns the index of the type of the `SumType`'s current value in the * `SumType`'s `Types`. * * If the `SumType` is qualified, returns the index of the type in `Types` * whose qualified version matches the `SumType`'s current value. */ size_t typeIndex(This)(auto ref This this_) { import std.traits : CopyTypeQualifiers; import std.meta : IndexOf = staticIndexOf; alias Qualify(T) = CopyTypeQualifiers!(This, T); alias QualifiedTypes = Map!(Qualify, This.Types); return this_.match!((ref value) => IndexOf!(typeof(value), QualifiedTypes) ); } ``` Note that this version has [the problem you complained about before][1] where it does not distinguish between the `int[]` and the `const(int[])` members of a `const(SumType!(int[], const(int[])))`. This is unavoidable--`match` itself is not capable of distinguishing between those members, so anything that uses `match` will also fail to do so. If this is still a problem for you, you can strip off the qualifier from the `SumType` before calling `typeIndex`: ```d return cast(TaggedTagType!(T))((cast(Unqual!T) val).typeIndex); ``` An unqualified `SumType` can never have duplicate member types, so this will always give consistent results. [1]: https://github.com/pbackus/sumtype/issues/58
Aug 29 2021
On Sunday, 29 August 2021 at 17:49:05 UTC, Paul Backus wrote:`staticIndexOf` returns `-1` when the type is not found, and `255` is what you get when you cast `-1` to `ubyte`.Yes, I understand, but it wasn't problem.Note that this version has [the problem you complained about before][1] where it does not distinguish between the `int[]` and the `const(int[])` members of a `const(SumType!(int[], const(int[])))`. This is unavoidable--`match` itself is not capable of distinguishing between those members, so anything that uses `match` will also fail to do so. If this is still a problem for you, you can strip off the qualifier from the `SumType` before calling `typeIndex`: ```d return cast(TaggedTagType!(T))((cast(Unqual!T) val).typeIndex); ```No problem with `typeIndex`, but `std.sumtype` have no `typeIndex`. If I understand correctly problem must resolve by removing `const` before `match`. Is this code will be correct? ```d auto typeIndex(T)(in T val) if (is(T == SumType!Args, Args...)) { return match!(v => staticIndexOf!(typeof(v), T.Types))(*(cast(T*)&val)); } ``` In what cases I get different result between your version with `CopyTypeQualifiers` and my?
Aug 30 2021
30.08.2021 13:20, Oleg B пишет:```d auto typeIndex(T)(in T val) if (is(T == SumType!Args, Args...)) { return match!(v => staticIndexOf!(typeof(v), T.Types))(*(cast(T*)&val)); } ```A little tip: you can use just `cast()` to remove qualifiers: ```D return match!(v => staticIndexOf!(typeof(v), T.Types))(cast()val)); ```
Aug 30 2021
On Monday, 30 August 2021 at 10:50:40 UTC, drug wrote:A little tip: you can use just `cast()` to remove qualifiers: ```D return match!(v => staticIndexOf!(typeof(v), T.Types))(cast()val)); ```I'm not sure what with simple `cast()` not `opCast` nor ctors are called, it depends on code of `SumType`, if it changed they can be called (not sure). Cast through pointer avoid it. Or I mistake?
Aug 30 2021
On Monday, 30 August 2021 at 11:19:46 UTC, Oleg B wrote:On Monday, 30 August 2021 at 10:50:40 UTC, drug wrote:`SumType` does not define any `opCast` overloads, so you don't have to worry about that. Re: ctors/copying, the [language spec for casts][1] says:A little tip: you can use just `cast()` to remove qualifiers: ```D return match!(v => staticIndexOf!(typeof(v), T.Types))(cast()val)); ```I'm not sure what with simple `cast()` not `opCast` nor ctors are called, it depends on code of `SumType`, if it changed they can be called (not sure). Cast through pointer avoid it. Or I mistake?10. Casting to a CastQual replaces the qualifiers to the type of the UnaryExpression. 11. Casting with no Type or CastQual removes any top level const, immutable, shared or inout type modifiers from the type of the UnaryExpression.In other words, casting to a different qualifier does not create a new value; it just causes the compiler to treat the existing value as though it had a different type. [1]: https://dlang.org/spec/expression.html#CastExpression
Aug 30 2021
On Monday, 30 August 2021 at 12:13:56 UTC, Paul Backus wrote:On Monday, 30 August 2021 at 11:19:46 UTC, Oleg B wrote:Thanks!On Monday, 30 August 2021 at 10:50:40 UTC, drug wrote:`SumType` does not define any `opCast` overloads, so you don't have to worry about that. Re: ctors/copying, the [language spec for casts][1] says:A little tip: you can use just `cast()` to remove qualifiers: ```D return match!(v => staticIndexOf!(typeof(v), T.Types))(cast()val)); ```I'm not sure what with simple `cast()` not `opCast` nor ctors are called, it depends on code of `SumType`, if it changed they can be called (not sure). Cast through pointer avoid it. Or I mistake?10. Casting to a CastQual replaces the qualifiers to the type of the UnaryExpression. 11. Casting with no Type or CastQual removes any top level const, immutable, shared or inout type modifiers from the type of the UnaryExpression.In other words, casting to a different qualifier does not create a new value; it just causes the compiler to treat the existing value as though it had a different type. [1]: https://dlang.org/spec/expression.html#CastExpression
Aug 30 2021
On 8/29/21 10:00 AM, Oleg B wrote:Paul, have you any plans to update `std.sumtype` to actual version of `sumtype` (1.1.x)? `typeIndex` is neededIt was [added](https://github.com/dlang/phobos/pull/7886), and then [removed](https://github.com/dlang/phobos/pull/7922) before release by Atila. I suspect it will never be re-added. -Steve
Aug 29 2021
On Sunday, 29 August 2021 at 14:29:09 UTC, Steven Schveighoffer wrote:...What a shame... I've been using std.sumtype recently and I was really hoping something like this would be added in. It feels really clunky otherwise.
Aug 29 2021
On Sunday, 29 August 2021 at 14:45:20 UTC, SealabJaster wrote:On Sunday, 29 August 2021 at 14:29:09 UTC, Steven Schveighoffer wrote:If you find the lack of `typeIndex` is leading to clunky code, you are probably not taking full advantage of `SumType`'s existing capabilities. In particular, `SumType` strongly rewards code written in a "functional" style, where different parts of a program are coupled together explicitly via function arguments and return values rather than implicitly via shared state and mutation. For a concrete example, have a look at * [Simen Kjærås's imperative-style code using a tagged union.][1] * [My functional-style version using `SumType`.][2] If you can give an example of the kind of code you have in mind, I would be happy to give more specific advice. [1]: https://forum.dlang.org/post/kjozzeynentyrarssnzz forum.dlang.org [2]: https://forum.dlang.org/post/bzueywubiazbkxvqnaid forum.dlang.org...What a shame... I've been using std.sumtype recently and I was really hoping something like this would be added in. It feels really clunky otherwise.
Aug 29 2021
On Sunday, 29 August 2021 at 15:05:57 UTC, Paul Backus wrote:...It is also of course totally possible I'm not using sumtypes right, but I'm frequently in situations such as this: ``` private string expectSingleIdentifier(Token tok, Expression[] exp) { string ret; exp[0].match!( (IdentifierExpression exp) { ret = exp.ident; }, (_) { throw new Exception(...); } ); return ret; } ``` While in this case I still have to go through `match` in order to access the value, sometimes I simply want to do a type check, and going through `match` seems a bit overkill. I guess it's just a niche case (wanting to 'abort' on a bad value rather than keep going) I keep running into, likely a sign I need to change my mindset rather than anything else. Or I'm just using it as a wrong abstraction >;3 In this specific case as well I don't believe I can use `return match!(...)` because I can't return anything in the "bad" case, since I'd then get an unreachable code error. Very minor yet annoying thing, but that's more a language issue rather than something inherent to SumType. And I keep forgetting to make the difference between a tagged union and a sum type, which is likely muddying my opinion since it's easy to extract and test values with the former case.
Aug 29 2021
On Sunday, 29 August 2021 at 19:19:54 UTC, SealabJaster wrote:...While I'm on a tiny rant, I'd like to just mention that compiler errors with SumType can be a bit obtuse. It's often annoying when you're using a generic case but due to a compiler error that the SumType eats up, all you get is "handler[x] is never matched" or "type X is unhandled", etc. Usually all you have to do is make a specific case for the type(s) causing the issue, but it's just a bit of extra work I'd rather not do. I appreciate that it's not really possible/easy to distinguish the case of "this handler *does* handle this type, it just doesn't compile due to an error in the body" though.
Aug 29 2021
On Sunday, 29 August 2021 at 19:29:29 UTC, SealabJaster wrote:On Sunday, 29 August 2021 at 19:19:54 UTC, SealabJaster wrote:I agree, this is annoying. My current best solution to this is: 1. Recompile with `-verrors=spec` and redirect the compiler's output to a file. 2. `grep` the file for error messages whose location is in one of my source files. 3. Search the results of that `grep` for the actual error that caused things to fail. By the way, this process works for anything that fails because of errors in a `__traits(compiles)` or `typeof(...)` check, not just `match`....While I'm on a tiny rant, I'd like to just mention that compiler errors with SumType can be a bit obtuse. It's often annoying when you're using a generic case but due to a compiler error that the SumType eats up, all you get is "handler[x] is never matched" or "type X is unhandled", etc.
Aug 29 2021
On Sunday, 29 August 2021 at 19:19:54 UTC, SealabJaster wrote:On Sunday, 29 August 2021 at 15:05:57 UTC, Paul Backus wrote:For cases like this you can use `tryMatch`, which does not require exhaustiveness and throws an exception at runtime if it encounters a type with no handler: ```d return exp[0].tryMatch!( (IdentifierExpression exp) => exp.ident ); ```...It is also of course totally possible I'm not using sumtypes right, but I'm frequently in situations such as this: ``` private string expectSingleIdentifier(Token tok, Expression[] exp) { string ret; exp[0].match!( (IdentifierExpression exp) { ret = exp.ident; }, (_) { throw new Exception(...); } ); return ret; } ```While in this case I still have to go through `match` in order to access the value, sometimes I simply want to do a type check, and going through `match` seems a bit overkill. I guess it's just a niche case (wanting to 'abort' on a bad value rather than keep going) I keep running into, likely a sign I need to change my mindset rather than anything else. Or I'm just using it as a wrong abstraction >;3If "abort unless this `SumType` contains a particular type" is a common pattern in your code I would suggest extracting it into a helper function: ```d void require(T, S)(S s) if (isSumType!S) { s.match!( (T t) {} (_) { assert(0); } ); } ``` But in general, I think this is the wrong approach. What I would do instead is create a helper function like the following: ```d Optional!T maybeGet(T, S)(S s) if (isSumType!S) { return s.match!( (T t) => some(t), _ => no!T; ); } ``` This narrows the set of cases you have to deal with from "anything that could be in the `SumType`" to "either `T` or not `T`", and from there you can handle the "not `T`" case however you want--abort, throw an exception, etc. The general principle here is ["Parse, don't validate."][1] [1]: https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/In this specific case as well I don't believe I can use `return match!(...)` because I can't return anything in the "bad" case, since I'd then get an unreachable code error. Very minor yet annoying thing, but that's more a language issue rather than something inherent to SumType.There is actually a workaround for this: ```d return exp[0].match!( (IdentifierExpression exp) => exp.ident, function string (_) { throw new Exception("..."); } ); ``` Note the explicit return type of `string` on the second lambda. The compiler will allow this, even though the lambda never returns a `string`, because it never returns normally at all.
Aug 29 2021
On Sunday, 29 August 2021 at 19:51:30 UTC, Paul Backus wrote:```d return exp[0].tryMatch!( (IdentifierExpression exp) => exp.ident ); ```That's pretty much perfect, thanks!But in general, I think this is the wrong approach. What I would do instead is create a helper function like the following: ```d Optional!T maybeGet(T, S)(S s) if (isSumType!S) { return s.match!( (T t) => some(t), _ => no!T; ); } ``` This narrows the set of cases you have to deal with from "anything that could be in the `SumType`" to "either `T` or not `T`", and from there you can handle the "not `T`" case however you want--abort, throw an exception, etc. The general principle here is ["Parse, don't validate."][1]An interesting way to think about things, which I assume is from your apparent experience with functional languages? There's definitely a lot to learn from them, even with my limited```d return exp[0].match!( (IdentifierExpression exp) => exp.ident, function string (_) { throw new Exception("..."); } ); ```I didn't even realise that syntax existed, TIL.I agree, this is annoying. My current best solution to this is:Glad it's not just me, another reason we need this: https://forum.dlang.org/post/rj5hok$c6q$1 digitalmars.com Thanks for your thorough answers.
Aug 29 2021
On Sunday, 29 August 2021 at 19:51:30 UTC, Paul Backus wrote:```d return exp[0].match!( (IdentifierExpression exp) => exp.ident, function string (_) { throw new Exception("..."); } ); ``` Note the explicit return type of `string` on the second lambda. The compiler will allow this, even though the lambda never returns a `string`, because it never returns normally at all.Can't wait until DIP1034 is fully implemented so one needn't do this.
Aug 29 2021
On Sunday, 29 August 2021 at 19:51:30 UTC, Paul Backus wrote:On Sunday, 29 August 2021 at 19:19:54 UTC, SealabJaster wrote:I have used something like the following (although I am finding I use this type of thing less the longer I use sumtype): import std; struct A {} struct B {} alias Sum = SumType!(A,B); T asserter(T)(string errMsg,string file =__FILE__,ulong line=__LINE__) { assert(0,format("%s(%s): %s",file,line,errMsg)); } T as(T,S)(S s, string file=__FILE__,ulong line=__LINE__) if(isSumType!S) { return s.match!((T t)=>t,_=>asserter!T("Sum contains unexpected type",file,line)); } void main() { Sum s = Sum(A.init); auto a = s.as!A; writeln(a); auto b = s.as!B; }[...]For cases like this you can use `tryMatch`, which does not require exhaustiveness and throws an exception at runtime if it encounters a type with no handler: ```d return exp[0].tryMatch!( (IdentifierExpression exp) => exp.ident ); ```[...]If "abort unless this `SumType` contains a particular type" is a common pattern in your code I would suggest extracting it into a helper function: ```d void require(T, S)(S s) if (isSumType!S) { s.match!( (T t) {} (_) { assert(0); } ); } ``` But in general, I think this is the wrong approach. What I would do instead is create a helper function like the following: ```d Optional!T maybeGet(T, S)(S s) if (isSumType!S) { return s.match!( (T t) => some(t), _ => no!T; ); } ``` This narrows the set of cases you have to deal with from "anything that could be in the `SumType`" to "either `T` or not `T`", and from there you can handle the "not `T`" case however you want--abort, throw an exception, etc. The general principle here is ["Parse, don't validate."][1] [1]: https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/[...]There is actually a workaround for this: ```d return exp[0].match!( (IdentifierExpression exp) => exp.ident, function string (_) { throw new Exception("..."); } ); ``` Note the explicit return type of `string` on the second lambda. The compiler will allow this, even though the lambda never returns a `string`, because it never returns normally at all.
Aug 29 2021
On Thursday, 18 March 2021 at 14:42:03 UTC, Oleg B wrote:Hello everyone. Went to see what is being prepared in the new compiler and saw this https://dlang.org/changelog/pending.html#std-sumtype [snip]Regardless of the other comments, it looks like the next release will be a big one.
Mar 18 2021
More general question: why phobos so bad structured? No way to determine what can be used without gc, that need it (other D features like betterC in the same situation). Some basic actions requires couple of std libs (std.file, std.path etc). Why something things placed in experimental will be in experimental during several years, other placed to std directly (sumtype)? May be it's time to restructure std, and determine algorithm for place new code to it (like DIPs)?I agree 1000% things are confusing when you want to manage memory yourself, you either have to check every functions and see if they allocate or no, or force yourself to add nogc everywhere OR use betterC and have access to no std at all I personally picked the betterC option and use D like i'd use C/C++, and it feels much better, i have my own Allocator struct, and whenever i need to allocate memory, i ask for an allocator If only the std was designed like this, whenever you want to allocate, you ask user to provide an allocator Want use GC? use gc allocator, everyone wins
Mar 18 2021
Things would improve drastically if std wasn't designed with assumptions on how user will use something STD should be here to serve as a base for people to design libraries, not to enforce how libraries should be designed, because it'll only serve one way to write software but it's not good if it's something like C++, now everyone complain and rewrite their own STL, for the better, i feel the same with D's STD (the language itself is perfect)
Mar 18 2021
On Thursday, 18 March 2021 at 14:42:03 UTC, Oleg B wrote:Hello everyone. Went to see what is being prepared in the new compiler and saw this https://dlang.org/changelog/pending.html#std-sumtypeDoes anyone know if it would be possible to make it support (it doesn't support it now) this kind of syntax: Temperature t1 = Fahrenheit(98.6); isFahrenheit(t1); // works isFahrenheit(Fahrenheit(98.6)); // doesn't work :(
Mar 22 2021
On Monday, 22 March 2021 at 19:24:54 UTC, JN wrote:On Thursday, 18 March 2021 at 14:42:03 UTC, Oleg B wrote:Not that it really makes sense, but if you wanted to do that you could cast: isFahrenheit(cast(Temperature)Fahrenheit(98.6)) //works Otherwize you would have to rewrite isFahrenheitHello everyone. Went to see what is being prepared in the new compiler and saw this https://dlang.org/changelog/pending.html#std-sumtypeDoes anyone know if it would be possible to make it support (it doesn't support it now) this kind of syntax: Temperature t1 = Fahrenheit(98.6); isFahrenheit(t1); // works isFahrenheit(Fahrenheit(98.6)); // doesn't work :(
Mar 22 2021
On Monday, 22 March 2021 at 20:43:12 UTC, Imperatorn wrote:On Monday, 22 March 2021 at 19:24:54 UTC, JN wrote:isFahrenheit(Temperature(Fahrenheit(98.6))) works too. but that's still extra typing.On Thursday, 18 March 2021 at 14:42:03 UTC, Oleg B wrote:Not that it really makes sense, but if you wanted to do that you could cast: isFahrenheit(cast(Temperature)Fahrenheit(98.6)) //works Otherwize you would have to rewrite isFahrenheitHello everyone. Went to see what is being prepared in the new compiler and saw this https://dlang.org/changelog/pending.html#std-sumtypeDoes anyone know if it would be possible to make it support (it doesn't support it now) this kind of syntax: Temperature t1 = Fahrenheit(98.6); isFahrenheit(t1); // works isFahrenheit(Fahrenheit(98.6)); // doesn't work :(
Mar 22 2021
On Monday, 22 March 2021 at 19:24:54 UTC, JN wrote:Does anyone know if it would be possible to make it support (it doesn't support it now) this kind of syntax: Temperature t1 = Fahrenheit(98.6); isFahrenheit(t1); // works isFahrenheit(Fahrenheit(98.6)); // doesn't work :(You can do this by adding an additional overload to isFahrenheit: bool isFahrenheit(T)(T t) if (staticIndexOf!(T, Temperature.Types) >= 0) { return is(T == Fahrenheit); } bool isFahrenheit(Temperature temp) { // Forward to template overload return temp.match!isFahrenheit; }
Mar 22 2021
On Monday, 22 March 2021 at 21:43:58 UTC, Paul Backus wrote:On Monday, 22 March 2021 at 19:24:54 UTC, JN wrote:What about something like Fahrenheit t2 = t1.to!(BaseTypeOf!(typeof(t1))); that could then be put into its own function.Does anyone know if it would be possible to make it support (it doesn't support it now) this kind of syntax: Temperature t1 = Fahrenheit(98.6); isFahrenheit(t1); // works isFahrenheit(Fahrenheit(98.6)); // doesn't work :(You can do this by adding an additional overload to isFahrenheit: bool isFahrenheit(T)(T t) if (staticIndexOf!(T, Temperature.Types) >= 0) { return is(T == Fahrenheit); } bool isFahrenheit(Temperature temp) { // Forward to template overload return temp.match!isFahrenheit; }
Mar 22 2021
On Monday, 22 March 2021 at 22:03:07 UTC, jmh530 wrote:On Monday, 22 March 2021 at 21:43:58 UTC, Paul Backus wrote:Not sure what `BaseTypeOf` is supposed to do here, but if you want to extract a particular type from a SumType it's pretty easy: Target to(Target, Source)(Source source) if (isSumType!Source && staticIndexOf!(Target, Source.Types)On Monday, 22 March 2021 at 19:24:54 UTC, JN wrote:What about something like Fahrenheit t2 = t1.to!(BaseTypeOf!(typeof(t1))); that could then be put into its own function.Does anyone know if it would be possible to make it support (it doesn't support it now) this kind of syntax: Temperature t1 = Fahrenheit(98.6); isFahrenheit(t1); // works isFahrenheit(Fahrenheit(98.6)); // doesn't work :(You can do this by adding an additional overload to isFahrenheit: bool isFahrenheit(T)(T t) if (staticIndexOf!(T, Temperature.Types) >= 0) { return is(T == Fahrenheit); } bool isFahrenheit(Temperature temp) { // Forward to template overload return temp.match!isFahrenheit; }= 0){ // Will throw MatchException if the wrong type is found return source.tryMatch!((Target target) => target)); }
Mar 22 2021
On Monday, 22 March 2021 at 23:25:07 UTC, Paul Backus wrote:[snip] Not sure what `BaseTypeOf` is supposed to do here, but if you want to extract a particular type from a SumType it's pretty easy: Target to(Target, Source)(Source source) if (isSumType!Source && staticIndexOf!(Target, Source.Types) >= 0) { // Will throw MatchException if the wrong type is found return source.tryMatch!((Target target) => target)); }I was BaseTypeofOf!Temperature would be returning Fahrenheit in that case. But yes, this looks like it would do what I was thinking.
Mar 22 2021
On Monday, 22 March 2021 at 19:24:54 UTC, JN wrote:On Thursday, 18 March 2021 at 14:42:03 UTC, Oleg B wrote:I would love this too, but Walter is very against implicit conversions. IMO this is one of the major reasons that algebraic types as a library are not adequate compared to a built-in language feature in D.Hello everyone. Went to see what is being prepared in the new compiler and saw this https://dlang.org/changelog/pending.html#std-sumtypeDoes anyone know if it would be possible to make it support (it doesn't support it now) this kind of syntax: Temperature t1 = Fahrenheit(98.6); isFahrenheit(t1); // works isFahrenheit(Fahrenheit(98.6)); // doesn't work :(
Mar 22 2021