November 29, 2022 Re: sumtypes for D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | On 11/29/22 08:26, Walter Bright wrote:
> On 11/28/2022 6:53 PM, Adam D Ruppe wrote:
>> Curious, what did you find lacking in std.sumtype?
>>
>> Same question to Walter.
>
> It's addressed in the draft DIP I just posted.
>
> https://github.com/WalterBright/DIPs/blob/sumtypes/DIPs/1NNN-(wgb).md
>
> I did email std.sumtype's author, Paul Backus, for his observations but have not heard back yet.
Nice! I think this general design, where it behaves just like a tagged union but @safe, makes some sense for D. I _really_ wish bad element access resulted in a compile-time error instead of a runtime error though.
Basically, you could treat
if(?s.member){
}
and
assert(?s.member);
specially, and only allow accesses to s.member if they are guarded by one of them. By default, accessing members is disallowed. The user can then choose between:
if(?s.member){
writeln(s.member);
}
and
assert(?s.member);
writeln(s.member);
To either check the tag manually or opt into the runtime error very explicitly.
I think catching errors early during type checking is one of the most compelling things about sum types in other languages, and it would be great if D could get that in some way. The analysis does not have to be particularly sophisticated. In particular, no control flow analysis is required.
|
November 29, 2022 Re: sumtypes for D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | On 11/29/22 08:26, Walter Bright wrote:
> On 11/28/2022 6:53 PM, Adam D Ruppe wrote:
>> Curious, what did you find lacking in std.sumtype?
>>
>> Same question to Walter.
>
> It's addressed in the draft DIP I just posted.
>
> https://github.com/WalterBright/DIPs/blob/sumtypes/DIPs/1NNN-(wgb).md
>
> I did email std.sumtype's author, Paul Backus, for his observations but have not heard back yet.
Some things that are missing:
- non-default construction, e.g.:
sumtype Result{
error,
int value;
}
auto result1 = Result.error;
auto result2 = Result.value(2);
The above is a bit unergonomic, maybe there is a better way to expose those constructors. They should exist though, otherwise it is e.g., impossible to initialize an immutable sumtype.
- introspection, e.g. is(T==sumtype) and __traits(allMembers, ...)
- in particular, it would be nice to provide access to the associated enumeration and the tag, e.g. for Result above, there could be an automatically generated enum like this:
enum Result{
error,
value,
}
Then you could do something like:
final switch(tag(result)) {
case Tag!Result.error: ...
case Tag!Result.value: ...
}
This way, sumtype can be a drop-in replacement for existing unsafe tagged unions. I guess with __traits(allMembers, ...) this can be done in the library, but nothing beats direct access to the tag.
- how does it interact with type qualifiers? In particular, I guess you can have a sumtype with only immutable members and reassign them anyway?
- pattern matching (though that's acknowledged in the DIP and can probably be designed later)
|
November 29, 2022 Re: sumtypes for D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | On 11/29/22 08:26, Walter Bright wrote:
> On 11/28/2022 6:53 PM, Adam D Ruppe wrote:
>> Curious, what did you find lacking in std.sumtype?
>>
>> Same question to Walter.
>
> It's addressed in the draft DIP I just posted.
>
> https://github.com/WalterBright/DIPs/blob/sumtypes/DIPs/1NNN-(wgb).md
>
> I did email std.sumtype's author, Paul Backus, for his observations but have not heard back yet.
BTW: I understand extraordinarily well where the desire for supporting an explicitly nullable pointer comes from, but I worry that integrating it into the more general syntax implicitly is a bit too cute. It will lead to bad interactions in generic code.
E.g.:
sumtype WithDefault(T){
Default;
T;
}
A user does not expect this to behave specially if `T` is a pointer. Generic code would have to explicitly check for that case and manually undo the rewrite in the library. I don't want to read the resulting unwieldy Phobos code.
Explicitly nullable pointers are too good of a feature to just give up though, so instead, you could introduce explicit syntax for the null check.
E.g.:
sumtype Nullable{
Null,
int* Ptr;
invariant(Ptr !is null);
}
The semantics of this would be to check the invariant on assignment and if it fails, then default-initialize the type instead. There could be multiple invariants that each can only refer to one of the members.
Then this would be distinct from:
sumtype DoublyNullable{
Null,
int* Ptr;
}
It would also be more general because it allows enforcing more general invariants. (But it could also be limited to the special case with null, at least in the beginning; what's important is that the different behavior is documented explicitly in a difference in syntax.)
Note that with the semantics where a bad member access is a runtime error, you don't gain much over just using a raw pointer. Therefore, I really think D should statically enforce that the user checks the tag.
|
November 29, 2022 Re: sumtypes for D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timon Gehr | On 11/29/22 15:01, Timon Gehr wrote:
> no control flow analysis is required.
Meant to write "data flow analysis" here.
|
November 29, 2022 Re: sumtypes for D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timon Gehr | On 11/29/22 15:18, Timon Gehr wrote:
>
> sumtype WithDefault(T){
> Default;
> T;
> }
Should have been:
sumtype WithDefault(T){
Default,
T value,
}
|
November 29, 2022 Re: sumtypes for D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | On 11/29/22 08:26, Walter Bright wrote:
> On 11/28/2022 6:53 PM, Adam D Ruppe wrote:
>> Curious, what did you find lacking in std.sumtype?
>>
>> Same question to Walter.
>
> It's addressed in the draft DIP I just posted.
>
> https://github.com/WalterBright/DIPs/blob/sumtypes/DIPs/1NNN-(wgb).md
>
> ...
Maybe consider changing the syntax to something like:
sumtype ST{
a;
int* b;
}
The reason is that with comma-separated values, metaprogramming is hobbled.
I think we really want to be able to do things like:
sumtype ST(bool hasC){
a;
int* b;
static if(hasC){
float c;
}
}
Similar for `static foreach`. The fact that this does not work for `enum`s is among the most annoying limitations of `enum`s.
|
November 30, 2022 Re: sumtypes for D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timon Gehr | On 30/11/2022 3:24 AM, Timon Gehr wrote:
> Maybe consider changing the syntax to something like:
>
> sumtype ST{
> a;
> int* b;
> }
>
> The reason is that with comma-separated values, metaprogramming is hobbled.
>
> I think we really want to be able to do things like:
>
> sumtype ST(bool hasC){
> a;
> int* b;
> static if(hasC){
> float c;
> }
> }
>
> Similar for `static foreach`. The fact that this does not work for `enum`s is among the most annoying limitations of `enum`s.
Could you please post this on the new thread where the draft is linked?
It is a good feedback and in this thread it'll get lost.
|
November 29, 2022 Re: sumtypes for D | ||||
---|---|---|---|---|
| ||||
Posted in reply to deadalnix | On 11/29/22 14:30, deadalnix wrote: > > Yes, and what I'm telling you is that the problems who'd deserve to be solved here are not specific to sum types, at least, not the worse offenders. I am also in favor of making solutions that are needed for sum types available to user-defined types to a good extent. But I do think some new solutions are needed, also on the front of the grammar. > Therefore, baking a special case solution for sum type would: > 1/ Not solve the core issue to begin with. Together with tuples, it solves the issue that there are no algebraic data types. I think this is significant and no pure library solution can match the ergonomics of a well-designed built-in solution. > 2/ Make the core issue harder to solve, because it now has to be compatible with whatever is done for sum types. Ideally that's not a constraint because it will be done right for sum types first and can then inform a more general solution. > 3/ Increase language complexity, which means more bugs and other problem in practice. > 4/ Tooling problems. Fair points. |
November 29, 2022 Re: sumtypes for D | ||||
---|---|---|---|---|
| ||||
Posted in reply to rikki cattermole | On 11/29/22 15:31, rikki cattermole wrote:
> On 30/11/2022 3:24 AM, Timon Gehr wrote:
>> Maybe consider changing the syntax to something like:
>>
>> sumtype ST{
>> a;
>> int* b;
>> }
>>
>> The reason is that with comma-separated values, metaprogramming is hobbled.
>>
>> I think we really want to be able to do things like:
>>
>> sumtype ST(bool hasC){
>> a;
>> int* b;
>> static if(hasC){
>> float c;
>> }
>> }
>>
>> Similar for `static foreach`. The fact that this does not work for `enum`s is among the most annoying limitations of `enum`s.
>
> Could you please post this on the new thread where the draft is linked?
>
> It is a good feedback and in this thread it'll get lost.
Oops. Moved it all over. I guess the corresponding messages in this thread can be deleted.
|
November 29, 2022 Re: sumtypes for D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D Ruppe | On Tuesday, 29 November 2022 at 02:53:27 UTC, Adam D Ruppe wrote:
> On Tuesday, 29 November 2022 at 02:33:21 UTC, deadalnix wrote:
>> I'm literally building a sum type
>
> Curious, what did you find lacking in std.sumtype?
>
> Same question to Walter.
>
> (btw I've never used it myself but this seems an obvious question that needs to be answered by anyone doing their own implementation, in or out of the language)
I haven't used it yet. But you can't implicitly convert an element type instance into a sum type struct instance. E.g. passing an int to a sum type struct function parameter.
|
Copyright © 1999-2021 by the D Language Foundation