Proposal: add non-exhaustive types #4170
Replies: 2 comments 5 replies
-
Hello! Thank you for the suggestion. I am myself against this proposal as it makes it possible for a type to change without the consumers of the type to be aware of that fact. I subscribe to the OCaml popular opinion that using a catch all pattern is a likely cause of bugs and to be avoided as much as possible, not something to be encouraged or forced. |
Beta Was this translation helpful? Give feedback.
-
I wish we had the exhaustiveness checker consindering guards (enventually) so that I do not have to use catch all pattern matches in cases. The more explicitness the better. This would allow me to specify ranges for say ints rather than having to catch "the rest" which would make my code more solid IMHO. This proposal goes into the opposite direction and for enums encourages catch all statements. In most situations I want to list all possible branches. |
Beta Was this translation helpful? Give feedback.
-
Prior art
In Rust, it is possible to tag an enum with the non-exhaustive attribute. This means that new variants of the enum may be added in the future, and forces users of said enum to add a catch-all arm when matching the enum.
This is useful because it lets library authors to have the freedom of adding new variants without causing breaking changes for the users, which in turn are free to decide whether to handle the new variant, if needed, or to leave their
match
expressions as they are, given that they already have a catch-all arm.Possible workarounds
In Gleam this is not possible, at the moment (as far as I'm aware: I searched on Google, issues and discussions, but I may have used the wrong terminology). A workaround is to simply add a constructor to a type to mimic the same concept:
If, for some reason, the type is meant to be manipulated by the user directly, and we don't want the user to ever be able to construct the
UnsupportedProtocol
variant, one can do this:This works fine, but users are not forced to add a catch-all arm, and they may write something like this:
This means that adding a new variant to
Protocol
is a breaking change for users, because they would need to update theircase
expression to match against the new variant, in case they didn't use a catch-all arm.Proposal
I don't know the internals of the Gleam compiler, so excuse me if my attempt in proposing a syntax to introduce non-exhaustive types is poorly thought out.
A way that Gleam could use to "tag" a type as non-exhaustive could be this:
Basically, an underscore in place of a constructor in a type definition means that new variants may be added in the future. Thus, this would fail to compile:
While this would work:
The advantage of this syntax is that it does not introduce any new keyword or weird ways to tag the enum, while using an already existing symbol (the underscore). It is also nice that the underscore is used in catch-all arms for
case
expressions, adding consistency. Finally, it would not be a breaking change for Gleam itself, I think.What I'm not a fan of is the fact that the underscore is a single symbol, and it's possibly a bit hard to quickly distinguish non-exhaustive types from "normal" types.
Beta Was this translation helpful? Give feedback.
All reactions