-
Notifications
You must be signed in to change notification settings - Fork 8
Add support for ADT enums #11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
cc: @rwaldron, @Jack-Works |
"string name", | ||
[expr] | ||
// A special `Enum.ADT` mapper exists that can be used to define algebraic data types: | ||
enum Message of Enum.ADT { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder how this dynamic dispatch approach (delegate to Enum.ADT[@@toEnum]) works with TypeScript.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may not matter too much for native enum
due to differences in how we handle enum
vs. const enum
. For something like enum Color of Number { red, green, blue }
, default members would be TypeFlags.EnumLiteral | TypeFlags.Number
.
I'm currently iterating on the ADT enum approach. I'm considering the possibility of having the of
mapper only apply to Scalar members that don't use ADT enum syntax, and having ADT enum members (that use {}
or ()
) always produce an ADT enum member factory. Essentially, that would mean that of
would only apply to uninitialized scalar values.
let x = Color.red; | ||
let y = Named["string name"]; | ||
// ADT enum construction | ||
const m1 = Message.Move{x: 10, y: 20}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
little skeptical about {}
syntax but ()
syntax is good to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd really like to be able to leverage this for the following scenario:
enum Node of Enum.ADT {
Identifier{ escapedText, pos, end },
StringLiteral{ text, pos, end },
NumericLiteral{ text, pos, end },
BigIntLiteral{ text, pos, end },
...
BinaryExpression{ left, operator, right, pos, end },
PropertyAccessExpression{ expression, name, pos, end },
ElementAccessExpression{ expression, argumentExpression, pos, end },
...
}
| @@toEnum | `"Symbol.toEnum"` | A method that is used to derive the value for an enum member during _EnumMember_ evaluation. | | ||
| @@formatEnum | `"Symbol.formatEnum"` | A method of an _enum object_ that is used to convert a value into a string representation based on the member names of the enum. Called by `Enum.format`. | | ||
| @@parseEnum | `"Symbol.parseEnum"` | A method of an _enum object_ that is used to convert a member name String into the value represented by that member of the enum. Called by `Enum.parse`. | | ||
| @@propertyConstruct | `"Symbol.propertyConstruct"` | A method of an ADT _enum member_ that is used to construct an ADT record-like enum value using object literal-like syntax. | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to reduce the number of new well-known symbols. Is it possible to merge them into one?
@@enum: { format?, parse?, construct?, from? }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe parse and format, but not the others:
@@toEnum
goes on the mapper passed toof
such asNumber
,String
, etc.@@formatEnum
and@@parseEnum
go on the constructor produced by the enum declaration_.@@propertyConstruct
goes on an ADT enum tagged record member.
Those are three wholly different placements. @@formatEnum
and @@parseEnum
provide a way to access the underlying enum data used to relate a key to a value and vice versa, and are symbols rather than internal slots so that existing enum-like constructs can be adapted to work with Enum
and can be produced by a transpiler.
README.md
Outdated
1. Set `value` to be the result of evaluating _Initializer_. | ||
1. If the _enum member_ has an _AgebraicDataTypeParameterList_ (i.e., `(a, b, c)`), then: | ||
1. Let `options` be a new Object. | ||
1. Set `options.kind` to `"tuple"`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not pass them as array/object directly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the declaration, not instance construction. There's no "object" to pass, only the property names or parameter list.
is transposed the following representation: | ||
|
||
```js | ||
const msg = Message.Move[Symbol.propertyConstruct](#{ x, y }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need R&T here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think so, yes. I'm of the opinion that ADT enum should have the same requirements as records and tuples as to the kinds of values they can hold. One reason is data portability between realms, along with the potential for a future shared enum
that could tie into shared struct
and multi-threaded JS. I'd also like to have Option.Some(1) === Option.Some(1)
hold.
What I don't see here is a clear explainer for what an ADT enum is (beyond just the initialism expansion), and why it's important to have that feature in the language. |
That is forthcoming, this is still fairly early. |
|
||
// `of` clause: | ||
|
||
// Each auto-initialized member value is a `Number`, auto-increments values by 1 starting at 0. | ||
enum Colors of Number { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If only derived from Number, how might these strictly compare to other number types, or would they only explicitly compare to themselves? I suppose the latter makes more sense anyway.
Automatic initialization is supported by way of an _Enum Mapper Object_ provided via an `of` clause: | ||
|
||
```js | ||
// Number-based enum with auto-increment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is mixing of auto-incremented values and explicit allowed as in some languages e.g., C#? In that case, should this proposal be explicit in how that will work e.g., auto-increments from the previous auto or explicit value?
This adds a rough description of ADT enum support.