Jump to page: 1 2
Thread overview
Enumerated Unions (sum types)
Sep 12
Dukc
Sep 12
Dukc
Sep 12
Dukc
Sep 12
Dukc
Sep 12
Dukc
Sep 12
Dukc
Sep 12
Dukc
Sep 12
jmh530
September 12

https://gist.github.com/pbackus/28e7f5668219ce83467c83c347ec7202

This DIP proposes a conservative design for sum types that aims to be consistent with existing D syntax and semantics. It does not discuss pattern matching.

September 12

On Thursday, 12 September 2024 at 02:42:17 UTC, Paul Backus wrote:

>

https://gist.github.com/pbackus/28e7f5668219ce83467c83c347ec7202

This DIP proposes a conservative design for sum types that aims to be consistent with existing D syntax and semantics. It does not discuss pattern matching.

I'm pretty sure I know, but the active field is the one last set, correct?

>

Access to the tag field of an enum union, if it exists, is always @system.

Does this mean obj.__tag is @system? Surely, having this knowledge is not a safety violation.

I think your example with the @trusted attribute is not safe, because the type in question may not be @safe to return (i.e. copy constructor not @safe).

The proposal should address taking the address of any member, especially in @safe code. i.e. this is currently allowed:

@safe:
void foo(ref int x)
{
   x = 5;
}

union U
{
   ubyte[4] buf;
   int x;
}

void bar()
{
   U u = {buf: [ 1, 2, 3, 4] };
   foo(u.x);
}

Such an example would not update the __tag even though the last value set would be via .x.

Unless I misunderstand what the "active" field is supposed to be.

The proposal should address what happens when you switch types, in terms of lifetime management. Is the prior active field destroyed? Is the memory blitted with field.init before assigning? Is this a construction or an assignment? Is it runtime dependent?

None of the examples show an enum union switching types, so maybe I'm misunderstanding something.

-Steve

September 12
This proposal follows Walter's design in requiring names for elements.

This does not match D's library implementations.

It does not match how it is used in the literature.

It is an improvement, from 8 issues down to 1 that I was able to determine, but unlike Walter's this cannot be fixed. It is core to the design.

For the other languages listed, Rust supports names being optional and SML supports the type being optional.

September 12

On Thursday, 12 September 2024 at 02:42:17 UTC, Paul Backus wrote:

>

https://gist.github.com/pbackus/28e7f5668219ce83467c83c347ec7202

This DIP proposes a conservative design for sum types that aims to be consistent with existing D syntax and semantics. It does not discuss pattern matching.

Does the __tag property have to be prefixed with a double underscore? Properties for any existing types don't appear to use underscores. Even if different in semantics from other fields, I don't think it needs an exception.

September 12
Paul Backus kirjoitti 12.9.2024 klo 5.42:
> https://gist.github.com/pbackus/28e7f5668219ce83467c83c347ec7202
> 
> This DIP proposes a conservative design for sum types that aims to be consistent with existing D syntax and semantics. It does not discuss pattern matching.

You're leaving the implementation of tag field undefined. I think it's better to define it. That way sum types can be used in foreign language APIs, and `sizeof(ASumType)` stays predictable.

Also I propose that the tag type is enumerated type that is implicitly convertible to `int`. The base type is an unsigned integer type big enough to hold all the field types. Default value and the enumerated values (other than having one for each type) can remain unspecified though.

The user should not have to write that `get` function of the example themselves. Otherwise we can't use the sum type from fully `@safe` code if any of it's fields can have unsafe values. Likewise, we should have a generic setter function for all the sum types that type safely checks the tag, and runs the destructor of the old object if the assignment changes the type.

I propose the DIP explicitly allows `void` fields, that work the same way as `Void` fields of TaggedAlgebraic. The void field could be initialised with either `void.init` or `void`. The return reference from `get`ting a void field would point to null. Setting a sumtype to void would simply wouldn't take a value argument.

Overall I like this approach though. Way better than the sum type proposals of Walter and Rikki.
September 12

On Thursday, 12 September 2024 at 03:22:07 UTC, Steven Schveighoffer wrote:

>

I'm pretty sure I know, but the active field is the one last set, correct?

Yes.

> >

Access to the tag field of an enum union, if it exists, is always @system.

Does this mean obj.__tag is @system? Surely, having this knowledge is not a safety violation.

__tag is an rvalue property that returns an index. Accessing it is @safe.

The tag field is a hidden field whose content is unspecified. Accessing it is @system.

They are two different things.

>

I think your example with the @trusted attribute is not safe, because the type in question may not be @safe to return (i.e. copy constructor not @safe).

It returns by reference, so no copy constructor is called.

>

The proposal should address taking the address of any member, especially in @safe code. i.e. this is currently allowed:

@safe:
void foo(ref int x)
{
   x = 5;
}

union U
{
   ubyte[4] buf;
   int x;
}

void bar()
{
   U u = {buf: [ 1, 2, 3, 4] };
   foo(u.x);
}

Such an example would not update the __tag even though the last value set would be via .x.

Good catch.

>

The proposal should address what happens when you switch types, in terms of lifetime management. Is the prior active field destroyed? Is the memory blitted with field.init before assigning? Is this a construction or an assignment? Is it runtime dependent?

None of the examples show an enum union switching types, so maybe I'm misunderstanding something.

The intent is that the previous value is destroyed, but you're right that the proposal does not address this.

September 12

On Thursday, 12 September 2024 at 08:55:01 UTC, cookiewitch wrote:

>

On Thursday, 12 September 2024 at 02:42:17 UTC, Paul Backus wrote:

>

https://gist.github.com/pbackus/28e7f5668219ce83467c83c347ec7202

This DIP proposes a conservative design for sum types that aims to be consistent with existing D syntax and semantics. It does not discuss pattern matching.

Does the __tag property have to be prefixed with a double underscore? Properties for any existing types don't appear to use underscores. Even if different in semantics from other fields, I don't think it needs an exception.

The point of the double underscore is to avoid name collision with a user-defined field or method.

Ideally, most users would use pattern matching, and never have to check __tag directly.

September 12

On Thursday, 12 September 2024 at 09:40:14 UTC, Dukc wrote:

>

Likewise, we should have a generic setter function for all the sum types that type safely checks the tag, and runs the destructor of the old object if the assignment changes the type.

Correction: I think the destructor should run any time the tag changes, even if the new field has the same type as the old one.

September 12
On Thursday, 12 September 2024 at 09:40:14 UTC, Dukc wrote:
> Paul Backus kirjoitti 12.9.2024 klo 5.42:
>> https://gist.github.com/pbackus/28e7f5668219ce83467c83c347ec7202
>> 
>> This DIP proposes a conservative design for sum types that aims to be consistent with existing D syntax and semantics. It does not discuss pattern matching.
>
> You're leaving the implementation of tag field undefined. I think it's better to define it. That way sum types can be used in foreign language APIs, and `sizeof(ASumType)` stays predictable.

Leaving the tag implementation unspecified allows the compiler to optimize it out.

You can use them in foreign languages by defining an extern(C) API and treating the content as opaque.

> Also I propose that the tag type is enumerated type that is implicitly convertible to `int`. The base type is an unsigned integer type big enough to hold all the field types. Default value and the enumerated values (other than having one for each type) can remain unspecified though.

By "tag type" I assume you mean the type of the __tag property. Is there any practical difference between what you describe and just using size_t?

> The user should not have to write that `get` function of the example themselves. Otherwise we can't use the sum type from fully `@safe` code if any of it's fields can have unsafe values.

I agree. Ideally, you would use pattern matching to access the fields. But that's a whole separate DIP.

> Likewise, we should have a generic setter function for all the sum types that type safely checks the tag, and runs the destructor of the old object if the assignment changes the type.

I agree. I'll add to the DIP that the assignment operator should behave like this.

> I propose the DIP explicitly allows `void` fields, that work the same way as `Void` fields of TaggedAlgebraic. The void field could be initialised with either `void.init` or `void`. The return reference from `get`ting a void field would point to null. Setting a sumtype to void would simply wouldn't take a value argument.

I agree that void fields should be allowed, but that should be a separate DIP, not part of a sum type proposal. They should be allowed for structs and classes too.
September 12

On Thursday, 12 September 2024 at 09:56:44 UTC, Paul Backus wrote:

>

You can use them in foreign languages by defining an extern(C) API and treating the content as opaque.

Yes, if the foreign language will only handle it via a pointer. But if the ABI is nailed down, the foreign language can have the sum type on an array or at the stack, and pass them to D functions by value.

>

I agree. Ideally, you would use pattern matching to access the fields. But that's a whole separate DIP.

Pattern matching is complex enough that I agree it's best as it's own DIP. But I think this DIP still needs the simple getter function since a language-level sum type really doesn't carry it's weight if it is too low-level. We already have union for the low-level work.

If you insist, IMO the DIP doesn't necessarily have to specify what exactly the getter function must do, because in the end it's just an utility function. But at least it must be proposed that one should be added to the language or the standard library.

>

I agree. I'll add to the DIP that the assignment operator should behave like this.

I was initially thinking about assignment operator too, but there's a problem. You might have two or more fields with the same type, in which case assigning a value of that type to the sum type is ambiguous. If you instead/also mean an assignment to field of the sum type, then that avoids the problem.

>

I agree that void fields should be allowed, but that should be a separate DIP, not part of a sum type proposal. They should be allowed for structs and classes too.

...and if they are, we don't need the annoying special case that the setter wouldn't take a value argument for void fields. I think it's worth mentioning in the DIP though as a future development, once/if you submit it for real.

« First   ‹ Prev
1 2