Hi Brad,
Thanks for taking the time to write this all up to keep me in the loop on
the internal discussions.
Like you mentioned, the motivation here is to fix/improve "union", and to
introduce a possible way of dealing with error cases. I think we can
accomplish both by replacing the current "union" construct completely, with
something more elegant and useful than "C-style unions with a way to tell
which field is active", while maintaining the performance characteristics.
That said, the replacement I'm proposing makes the most sense (to me,
anyway) when thought of as an extension of C's enum. Extending enum, or
absorbing enum into this new concept, isn't actually the goal, it's just a
pleasant side-effect. We'll get back to the idea that this is a "union"
replacement after introducing it as an "enum" extension.
I'll call it "variant".
Consider:
enum Color { Red, Green, Blue }
(Ignore for now the idea of Red = 1, etc.)
Red, Green, and Blue can be thought of as subtypes of Color, like a very
simple class hierarchy. With enums, we're limited to unit types, so we
can't attach any additional information to any of the subtypes, and we're
obviously limited to a single level of subtypes in our hierarchy. But when
this is all we need, the enum is the perfect solution, with great
performance.
Now, if we want to add an "Other" color, with some information attached to
it, enum no longer suffices, so we could rewrite this as a class hierarchy:
class Color {}
class Red : Color {}
class Green : Color {}
class Blue : Color {}
class Other : Color {
var name: string;
}
Red, Green, and Blue are unit types, while Other is a composite type. All
are subtypes of Color. This works, but it's a bit verbose, and it's no
longer efficient (particularly if we have a large vector of Colors, for
example). (Let's just pretend for now that we have a way to check the
dynamic type of an object, so that we can use these types similarly to how
we might use our enum.)
With a "variant" construct, we could write this as:
variant Color {
Red,
Green,
Blue,
Other { var name: string; }
}
We should think of this as listing the subtypes of Color. Some or all of
these subtypes can be composite types, with one or more fields.
Equivalently, I suppose we could write: Color { Red{}, Green{}, Blue{},
Other{var name: string;}}. To be clear, Other doesn't have an anonymous
record attached to it; Other is a composite type itself, and values of type
Color.Other have a field called "name".
This is almost syntactic sugar for the class hierarchy above, except that
the "variant" would have value semantics, and would be implemented
efficiently (e.g. `struct Color { int tag; union { string Other_name; }}`).
The special case of "variant" where all the subtypes are unit types is
obviously the same as "enum". This special case could be implemented
exactly the same as today's enums, and an efficient implementation could be
guaranteed in the language spec. (Above, I said to ignore the idea of the
user assigning an integer value to each subtype, but we could certainly
allow `variant Color { Red = 1, Blue = 2, Green = 3 }`. I'm not sure if it
makes sense to assign 'Other' an integer value, or whether this would be
restricted to variants with only unit types, but I want to stick to the
bigger picture for now).
Now, back to "union". In my mind, the unifying theme between "enum" and
"union" is the "one of" concept. For example:
enum EResult { Success, Error }
union UResult { var Success: int; var Error: string; }
var v1: EResult = f1();
var v2: UResult = f2();
v1 is "one of" Success or Failure, but we *can't* attach other information
to either of the two possibilities.
v2 is "one of" Success or Failure, and we *have to* attach other
information to each of the two possibilities.
We can replace these two separate concepts with "variant", which allows us
to attach information to some possibilities and not others, as we wish:
variant VResult {
Success,
Error { var message: string; }
}
Because of how "variant" is implemented, we no longer need "union".
This:
record Error { var message: string; var position: int; }
union NumOrError {
var num: int;
var error: Error;
}
would instead be written:
variant NumOrError {
Num { var value: int; },
Error { var message: string; var position: int; }
}
and could be implemented exactly the same.
I think the latter is much nicer. There's no real indication in the "union"
syntax (or variations on that syntax) that the fields are mutually
exclusive, other than the word "union" (or whatever it would be called). It
looks too much like a record.
In "variant" it's (hopefully) clear that a value can only be one of the
subtypes at a time (like an enum), and there's a natural syntax for
matching and unpacking the subtypes in a 'select' statement:
select x {
when Num{value} do ...
when Error{msg, pos} do ...
}
To repeat the ideas on optional returns, and possible failures, that could
look something like:
(Using Kyle's generic syntax proposal.)
// Copying Haskell
variant Maybe(type T) {
Just { var value: T; },
Nothing
}
var c: Maybe(string) = getUserInputOrTimeout();
variant Expected(type T) {
Success { var value: T; },
Error { var message: string; }
}
var n: Expected(int) = parseInt(getUserInput())
// This is just a special case of Haskell's Either type:
variant Either(type A, type B) {
Left { var value: A; },
Right { var value: B; }
}
var x: Either(int, string) = f();
This doesn't address everything in your notes, but it's about time I called
it a night. Please note that I haven't tied my ego to these ideas, and I'm
certainly open to discussing other options.
- Sean
------------------------------------------------------------------------------
Dive into the World of Parallel Programming. The Go Parallel Website,
sponsored by Intel and developed in partnership with Slashdot Media, is your
hub for all things parallel software development, from weekly thought
leadership blogs to news, videos, case studies, tutorials and more. Take a
look and join the conversation now. http://goparallel.sourceforge.net/
_______________________________________________
Chapel-developers mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/chapel-developers