-
Notifications
You must be signed in to change notification settings - Fork 26
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
RFC: Enriching ADTs #870
Labels
Comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This RFC can be thought of as the "Future work" #869, i.e. features that we might add to our abstract data types. They are divided into two categories, depending on the amount of work needed to implement it.
Minor features
These are minor issues that should be fairly simple to fix. Some of them could probably be converted to issues of their own, but I include them here to encourage discussion.
Parentheses for field-less ADTs should be optional
Since ADTs are implemented as syntactic sugar, for each
case
of a data type, there is a corresponding class and function of the same name. When a programmer writesSome(42)
it is an actual call to a functionSome
of typeint -> Option
(assuming the existence of a data typeOption
). However, this means that constructing an ADT value with no arguments is written asNone()
; justNone
is a function of type() -> Option
!This is especially annoying for pattern matching, the case declaration and corresponding case in the
match
do not look the same:Even more annoying is the fact that writing
case None
in amatch
is currently interpreted as a (catch-all) variable!It would be more ergonomic to automatically translate
None
toNone()
, wherever it appears. This however raises the question of how capitalised variable names should be interpreted when there is no corresponding ADT constructor. There are two obvious options:While 2. is more permissive, it also opens up for errors like misspelled patterns:
Therefore I am leaning more towards 1. The sad thing about this is that all-caps variables, which a programmer may want to use to denote a constant, can no longer be used. This could in turn be fixed by applying option 1 from above, but only to patterns. I am not convinced that all-caps variables are important enough to motivate this discrepancy.
Type inference should be improved
The type inference machinery currently does not handle the following case:
Instead, the programmer has to write
Cons(1, Cons(2, Nil[int]()))
. My feeling is that this would be fixed if someone could just implement proper type inference for Encore in general (a thesis project perhaps?).Allow abstract methods in
data
declarationsThe desugaring process turns
data
declarations into traits andcase
s into classes. Adata
declaration can have methods, which will be inherited by thecase
s of this data type. Because of the close connection between traits anddata
declarations, it should be straightforward to support abstract methods by allowing adata
declaration torequire
methods, which eachcase
must then provide. I believe this is as simple as extending the parser to recognise requirements, and the desugarer to move them over to the resulting trait.Major features
These are features that require more thought (and effort) to implement than the features in the previous section. They also have more open ends and less clear use cases.
Allow
match
expressions to specialise types in casesThe correspondence between
data
/case
and trait/class gives us that all values of a data type are actually instances of classes typed using the same trait type. Due to the nature of our desugaring, when we usematch
we learn something about which class type the value being matched on actually has. This would allow us to do downcasts in a safe way:Since matching on ADTs already gives access to all the fields of that value, the reason for doing this would be to access
case
specific methods. It would be like allowinginstanceof
for a limited set of types.Allow cases belonging to several data types
Since a
case
is actually a class implementing a (data
) trait, it should be straightforward to have acase
which is part of several data types:This could be useful if
Binary
contains methods that need to be reused for multiple (but not all) instances ofExpr
. One could imagine using this for concurrency as well, but since ADTs are immutable, there's not a lot to be gained as far as I can see.The text was updated successfully, but these errors were encountered: