Closed FroMage closed 11 years ago
What about Anything/Nothing? (Scala has Any/Nothing.) I also like Top/Bottom.
This is subjective by nature, so:
To me (i.e. with some C(++) background) void mainly means "comes with no assumptions about the actual type". Of course, the concept's beatuy dies with the pointers you don't have in Java/Ceylon. So I concur that Void is a bit misplaced, even though it is to me because void*
is pretty much what Void
means in references but not return types.
Top/Bottom is nice for thinking in trees. Less so if you include interfaces in your topology ;(
Anything/Everything comes to mind, but is probably a bit off for c eyes.
Why Bottom could be SubType or NonValue or Undefined is beyone me. I guess I hate it.
I could think of Void
/Unspecified
, though that only works if you have in idea of void
, i.e. it's not too clear which is what.
Unknown/Impossible sounds good to me. Unknown invokes memories of COM's IUnknown, the superinterface of IDispatch (which was mapped to Object in Visual Basic).
@durban Nothing
works as the name of the bottom type in Scala because null
is an instance of the bottom type. But Ceylon's null
is typesafe, so Nothing
is a completely different type, not the bottom type.
But I suppose we could potentially use Anything
/Nothing
as the names of the top / bottom types if we renamed our current Nothing
class to Null
. That might work out pretty nicely.
I vote for!
@gavinking Well, if I understand correctly this: http://www.scala-lang.org/api/current/index.html, then Scala actually has a type called "Null" (null is an instance of this), and has a type called "Nothing", which is indeed Bottom (the empty type, i.e., it has no instances, and it is a subtype of every type). So yes, I think it would be good to rename the current "Nothing" to "Null", and use Anything / Nothing as top/bottom as you said.
I mostly like this version, because then if I have something which has the type "Nothing", then I know, that "it can be nothing" (because Nothing has no instances). Similarly with Anything: "it can be anything" (because everything is an instance of Anything). (I'm not a native speaker though, so I may be mistaken.)
Definitely seems the best option so far. Nicely symmetric names and null
being an instance of Null
also seems more intuitive than Nothing
. +1
Scala actually has a type called "Null" (null is an instance of this), and has a type called "Nothing", which is indeed Bottom (the empty type, i.e., it has no instances, and it is a subtype of every type).
Ah, OK, well, yeah, Scala's Null
is the bottom of the reference types, whereas Nothing
is the bottom of all types. There's two differences here:
IdentifiableObject
.null
isn't an instance of any kind of bottom type - it's not even an instance of Object
. So just be a little bit careful about mapping concepts back and forth between Ceylon and Scala, because they are not precisely the same.
I like Anything/Nothing and using Null as the type of null. It makes the type system look more regular.
This change would be acceptable to me.
+1
-1 on the Anything/Nothing.
I prefer Anything/Everything, or Anything/All, or Any/All.
An instance of SomeType<All> is assignable to SomeType<out T> for any T.
SomeType<Nothing> does not make the correct implication in the above case. Without deeper reasoning by the user, it seems to imply that it can't instantiated.
An example use case is if an empty collection is modeled with a Nil satisfies Collection<All>. This specific use example may not apply to the eventual standard collection library, since Ceylon has first class treatment of null with an intersection type. Nevertheless, there may be other use cases.
Also in my mind, Nothing is not the symmetric meaning to Anything. For me, it is intuitive that All or Everything can't be instantiated, because the set of types of a program is open due to subtyping.
"Without deeper reasoning by the user, it seems to imply that it can't instantiated" well as far as I understand things that's exactly what it means. That's why one of the alternative suggestions was Impossible
.
But my point is that SomeType<Impossible> can be instantiated.
The user has to reason out that while Impossible can't be instantiated, given the covariant parameter of SomeType, the former can be instantiated (the type parameter will never be allowed in the method input position).
Whereas, in my mind, it is obvious that type All or Everything, can't be instantiated, because there is no value that is all types of the program. And then there is not the implication that SomeType<All> can't be instantiated.
But the more I think about it, I don't like All and Everything, because the bottom type is not the supertype of all types. And it is not just Nothing or Impossible either. It is the subtype of all types. It is something and it is possible to use it for the type of a value, as per the example above.
The most accurate I can think of which is perhaps more intuitive than Top/Bottom is AnySub/AllSuper or AnySubtype/AllSupertypes. Since Ceylon favors verbosity for clarity, perhaps my suggestion is AnySubtype/AllSupertypes.
It cannot be instantiated, no value will ever exist of the type SomeType<Nothing>
that's exactly why Impossible
was one of the suggestions. No value will ever exist with a type that is a subtype of all possible types. It's a completely "virtual" type but still useful in some cases.
Please correct me, but I think it can be instantiated.
http://en.wikipedia.org/wiki/Bottom_type#Computer_science_applications
"3. List[Bot] is a natural type for the "null pointer" value (a pointer which does not point to any object) of languages like Java: in Java, the null type is the universal subtype of reference types. null is the only value of the null type; and it can be cast to any reference type.[3] However, the null type does not satisfy all the properties of a bottom type as described above, because bottom types cannot have any possible values, and the null type has the value null."
You can work it out by studying the Scala use cases.
Scala instantiates "object Nil extends List[Nothing]" and "object None extends Option[Nothing]":
http://www.codecommit.com/blog/ruby/monads-are-not-metaphors
Tangentially, that Wikipedia link says that Void is not the top type, and instead the unit type. I am not sure what corner cases that might introduce since Ceylon is conflating the top and void types. I saw that Ceylon wants to be able to assign any function that returns any type, to a type that is a function that returns Void.
I'd say this says it all: "However, the null type does not satisfy all the properties of a bottom type as described above, because bottom types cannot have any possible values, and the null type has the value null". Our bottom type is a "real" bottom type and has no possible values.
Apparently you are equating the instantiation of the bottom type with the instantiation of a type where the bottom type is a covariant parameter (which is exactly the misunderstanding I am trying to avoid, by suggesting using AllSupertypes instead of Nothing or Impossible). The latter is instantiable, the former is not.
The Scala type Nothing is not instantiable, and is the "real" bottom type too. The Scala type Option[Nothing] is instantiable (and is not a bottom type, so agrees with your Wikipedia quote). The Null type is distinct from Nothing in Scala too.
The requirements of a covariant type parameter enable that. What you are forgetting is that the bottom type is populated with every supertype in the program (which is why Nothing and Impossible are not truthful names). This means it can be instantiated where it is used as covariant type parameter.
P.S. In Ceylon, currently Nothing corresponds to Scala's Null type and Bottom to Scala's Nothing type. What I said for Scala, applies the same to Ceylon.
I don't see how List<AllSuperTypes>
would be more understandable than List<Nothing>
?
And you're right that List<Nothing>
is instantiable but it conveys the correct meaning that you won't be able to do anything with it. In case of the List it will always be empty, which is just what you want. For soomebody not well-versed in type theory it seems like a very intuitive thing.
It can do something, e.g. the instance of Nil
is an empty list, and it assignable to any type List<T>
, which is exactly what List<AllSuperTypes>
conveys in my mind since T represents all types and assignment is covariant subsumption. For example, a list data structure has two fields, T head
and List<T> tail
, so the tail
is set to Nil
to mark the end of the list.
Note that in Ceylon, one could mark the end of the list with null
and use type List<T>? tail
instead. But perhaps this is only an example of a more generally applicable type construction (I need to think about other use cases).
Whereas, assigning a List<Nothing>
to a List<T>
connotes that we are setting an unpopulated item to a populated one.
If I am not mistaken, there is a key type theory insight. In the domain of values, the bottom type is an empty set, but in the domain of types, it is definitely not an empty set, because it is populated by every supertype (every type other than bottom) in the program. That is fundamental reason that Nothing
or Impossible
is semantically untruthful. And the Ceylon spec makes the error of stating that the bottom type is the empty set, without stating which domain.
Any way, in the end perhaps it is just a matter of user taste on the name choice (although in any case, I am thinking the spec needs to corrected on the empty set domain point). I dunno.
Well the matter of taste is an important one in this case, because the current name is maybe to most semantically correct but we're looking at alternative names exactly because of the reason that we think it will be hard to explain to "The Average Java Enterprise Developer" what things like Void
and Bottom
mean. Se we're basically looking for intuitive, almost "catchy" names that are not too incorrect.
Yeah I leave the interpretation of user pyschology to the major stake holders in Ceylon. ;)
Thanks for taking the time to help me explain my point on the issue deeply.
Also hope someone looks at the point I made about Void should be distinct from the top type.
If I am correct that the bottom type is populated as the subtype of all types other than itself (i.e. not the empty set in the type domain), then another suggestion is:
AnyValue
/ AllTypes
Maybe that makes it more clear that the bottom type is not populated with values, but is populated with all types. So if user thinks about instantiating an AllTypes, they will realize there is no single type that will suffice.
When I first saw Nothing
in Scala, I thought it was the type of the null
value, since I didn't yet know there was a distinct Null
type, which confused me because List<Nothing>
(List[Nothing]
notation in Scala) was implying to me an empty list could contain null
values. But a list of null
values is not the same as an empty list.
The List<AllTypes>
implies to me a list of values each of which has the type of all types, which is thus a list which is impossible to populate, so I know it is empty.
But I see that if not confused to be List<Null>
, then List<Nothing>
could be interpreted as a list of values that are nothing, thus impossible to populate.
More descriptive:
AnyTypeOfValue
/ AllTypesNoValues
Probably it is completely nuts, but have you considered promoting void
to a keyword which stands for Void
or Bottom
in each case where it cannot sensibly be the other one?
E.g. Sequence<void>
would become Sequence<Void>
, not Sequence<Bottom>
. At the least, it would matter less which actual type names there are. I presume there are enough cases in favour of Bottom
.
Hey, let's call the bottom type either Error
or Problem
. Meaning that if the called function terminates it results in a thrown exception. I like Problem
, personally. To me this is more meaningful than Nothing
for the bottom type.
So, if the bottom type is Problem
(or Error
) here's a few idea for the renaming of Void
. Note that upon reflecting I think the name Object
is also in play, since the truth is that Ceylon's null
is an object according to ... so it's kind of lying to pretend it is not. Hell, it's even declared object null
, even though it is not an instance of the class Object
according to the naming scheme in use today. So here's some less-lying options:
class Object() of Nothing | Something {}
class Value() of Nothing | Something {}
class Anything() of Nothing | Something {}
Aren't you conflating unit (i.e. Void
) and bottom (i.e. Nothing
) types?
http://en.wikipedia.org/wiki/Unit_type
I also made an argument for equating unit and bottom, and was not well received:
http://stackoverflow.com/questions/19132/expression-versus-statement/8450398#8450398
You've given me an idea. Perhaps I like the name Exception
or Exceptional
for bottom, since bottom is not always a problem or error. It is an exceptional case. For example, to represent the empty list, e.g. List<Exception>
. Then it also works as a name for the unit type too, if conflating the names does not cause a problem?
The bottom type has no values, but is populated as the subtype of all types. The unit type has only one value, thus contains no compile-time information. Runtime exceptions can't be checked at compile-time, as that defeats the point of having them (as Java painfully discovered).
Even functions that return a value and have exceptions, really return the union containing the unit type. I read that unit is necessary to express some generic relationships, where bottom won't work.
Bottom type can only be used where it doesn't instantiate a value, so afaik this is some exceptional case, because it can be populated by all types in the contravariant direction.
So if you really don't want the user to think hard about what bottom really means, perhaps Exception
works. But if you do want deeper understanding, that is far from meaning "subtype of all types" and the "type of no value". But that concept is so deep, that I don't think most people get it even after it is explained.
Aren't you conflating unit (i.e. Void) and bottom (i.e. Nothing) types?
I don't think so, no. Ceylon doesn't use a unit type to represent the type of a void
function. We specifically wanted to make the return type of a void
function analyze to the top type. Even if that's slightly "wrong", it's much more convenient for working with higher-order functions.
I remember that void
is the top type in Celyon to be able to assign a function with any return type, to a function that returns void. I assume this so we can throw away the return type.
Afaics, this is a type hole because one can assume they are calling a function that has side-effects (void
functions always do), but which does not, thus wasting the CPU. Perhaps there are other more complex negative ramifications?
Afaics, the underlying dilemma is due to mixing pure functions with impure functions. Pure functions can never be void
. But this gets into a totally different way of looking at how for example a GUI should be programmed, and it reaches into the design of all the libraries. And pure functional reactive it is an area of research that has not provided conclusive results. If it were possible, I would prefer to not mix side-effect spaghetti with pure functions, and to make as much of the program as possible pure. But this is a really deep research issue and I know you don't want recreate Haskell, and thus I understand what Ceylon is working with and trying to improve. Just not sure if I agree with the compromise (I am researching solutions).
The bottom type is the type of any function that does not return, e.g. exit
or die
. This is different from the void
(unit) type, which does return but without any variable value. My point was that every function that can throw an exception returns a union including the bottom type. I wasn't thinking clearly when I asked if you were conflating void
with bottom. You never even implied that.
Exception
, NoValue
, or Nothing
seems to work for the return type of a function that never returns (and/or throws exceptions), as well as for the contravariant type parameter of a class. The user wouldn't be burdened with knowing it is also the subtype of all types, but they will need to know this if to understand why the bottom type works in the contravariant position. Are there any other practical uses of the bottom type?
I can't think of a name other than Bottom
that could imply "subtype of all types" intuitively. Even AllSuperTypes
or All
is confused with the top type. I argued that All
can't mean one type, so it must be a subtype, but I admit it is not intuitive.
So I guess I would choose Any
/NoValue
, because I assume you are not going to support unions of bottom for functions that optionally return exceptions. But I wish I could find a better solution.
Afaics, this is a type hole because one can assume they are calling a function that has side-effects (void functions always do), but which does not, thus wasting the CPU.
Wasting CPU is not something which our type system does or even theoretically could concern itself with.
Perhaps there are other more complex negative ramifications?
I don't think so, no.
Afaics, the underlying dilemma is due to mixing pure functions with impure functions.
I mean, some languages (Haskell) do have type systems which differentiate pure from impure (and other kinds of typed side-effects) but ours doesn't. It's a perfectly legitimate goal for a type system, but it's a non-goal for our type system.
Are there any other practical uses of the bottom type?
It's mainly useful for:
List<Integer>&List<String>
is a List<Integer&String>
), andConsumer<Bottom>
).Wasting CPU is not something which our type system does or even theoretically could concern itself with.
A function that returns void
always has side-effects (else a noop, which could be flagged by a smart compiler). A function which returns a value other than void
and does not have a bottom return type, may be pure and thus not have side-effects, i.e. it might only return a value. Thus, by allowing the assignment of the latter to the former automatically without a cast, i.e. by conflating the unit and top types, thus the type system allows the calling of functions which do nothing (because the return value is thrown away).
I understand it is not a goal for Ceylon's type system to identify pure functions. As a result, other Ceylon code can discard the return value of a pure function at the call site. The difference is automatic cast to void
can discard it far away from the call site (perhaps unseen to the programmer). So I see that as a type hole or violation of the single-point-of-truth[1], albeit agreeably a very small one in the context of not typing pure functions-- which was my point also.
[1] One objective of a type system is to declare invariants and have the compiler check all the cases we can't see.
I don't think so, no.
http://en.wikipedia.org/wiki/Unit_type
I am reading that null
should be the single value of the unit type, otherwise we loose some genericity.
Equating top as the type of null
(if unit and top are equated) would probably introduce problems.
In summary, these decisions to equate things which are not the same, are throwing away information. And as such there are scenarios where the lost information is needed. Nevertheless, we always throw away some information in life[2], so there is no perfect system. One of the design goals for Ceylon may be some compatibility with Java, and Java does not make null
the value of the unit type.
[2] It is impossible to sample the universe, http://en.wikipedia.org/wiki/Nyquist%E2%80%93Shannon_sampling_theorem http://relativisticobserver.blogspot.com/2012/03/thinking-backwards.html?showComment=1335811898940#c5244835704736353226
(3) it's also occasionally convenient to have a well-defined supertype of all instantiations of a covariant type. (eg.
Consumer<Bottom>
).
I think you meant a covariant type, Consumer<T>
that is contravariant in its type parameter, T
.
(1) representing degenerate cases (the element type of an empty collection)
Agreed, and note the type of the empty collection is the subtype of all collections (because the type parameter is covariant), i.e. it can be assigned to any collection type. I mention this to contrast it to the example in (3) above, which is the supertype of all, and to show it is a subtype, for the point I will make below about the consistency of the name for bottom so it is meaningful in both covariant and contravariant cases.
(2) assigning a principal instantiation to certain intersections and unions (eg. List
&List is a List<Integer&String>), and
I read a blog post of yours that I think was about that discovery. Will the programmer ever write the bottom type in these cases, or just for internal use of the compiler?
The reason I ask is because our purpose here is thinking about scenarios where the programmer will see and use the name of the bottom type.
Thus, (1) makes intuitive sense with names such as NoValue
, Nothing
, or Exception
. Or if thinking more deeply that the empty collection is the subtype of all collections with a covariant type parameter, then All
or SubTypeOfAll
.
Yet (3) makes intuitive sense with All
or Any
. Or if thinking more deeply that is the supertype of all with a contravariant type parameter, then All
or SubTypeOfAll
.
So my point is that trying to think of an intuitive name for bottom where the user doesn't have to think about the convariance of the type parameter is going to throw away information and thus will be an inconsistent name in some scenarios.
Lets not forget the 4th use of bottom, which is as the return type of a function which never returns. In that case, the names NoValue
, Nothing
, or Exception
are most intuitive.
Thus after all of this, I prefer the most descriptive and accurate name, i.e. SubTypeOfAll
. I prefer users recognize when they don't understand something, than create inconsistent names. That implies it can't have a value. Or we could be explicit and perhaps too verbose, SubTypeOfAllNoValues
, but at least the user will get a hint what they need to learn about.
When I recall my experience of learning Scala, Nothing
confused me. SubTypeOfAll
or SubTypeOfAllNoValues
would have given me enough hints to know what I was dealing with.
Another possible solution is to allow two names for bottom, Nothing
and All
(types). The top type could be Any
(type).
The best name for bottom can be chosen by the context in the code, i.e. Nothing
where the context is no (return) value and All
where the context is the subtype of all types.
You might prefer NoValue
instead of Nothing
and/or Every
(type) instead of All
(types).
The desire to simplify concepts using Error
, Problem
, or using Consumer<Nothing>
instead of Consumer<All>
, directs the user's mind away from the typing relationships to some other semantics elsewhere in the code. I suggest that is aliasing error and will give rise to insoluble situations. I am thinking that it is best to stick with type correctness, and for user's to learn how the type is being used, e.g. the contravariant type parameter of Consumer
requires a subtype of All
types.
My other idea is AllOrNothing
.
All
could be confused with Any
because the user could assume all types can be assigned to it, instead of it can be assigned to all types. Ditto Any
vice versa.
Thus I think I prefer the unambiguous SuperOfAll
for top, and for bottom the user choice of Nothing
or SubOfAll
. Or the shorter Supermost
and Submost
. I prefer them over the generic words Top
and Bottom
because programmers might want to use for types, and they provide no hints of meaning or of being builtin types to those who are unfamiliar with the concept of top and bottom types.
Both Nothing
and NoValue
have semantic holes. As a return type, this implies the function can return with no return value. Users might conflate this with void, which is returning with the single value of void (remember void is not the same as bottom). Thus perhaps I prefer Never
, which I like more than Error
or Exception
, since it is more general, i.e. the type of a value that never occurs.
I understand that since the return type is an intersection with possible return type(s), the bottom type must be used in that intersection to represent functions that may not return, because we want the return value to be assignable to those possible return types. Thus we can't separate this type from the bottom type.
Top is SuperOfAll
Bottom is Never
or SubOfAll
Wow, somehow I'm only just seeing this discussion now. I don't have time to read over the whole thing, but I've skimmed over it.
My proposal, Thing
for top and Nothing
for bottom.
As for void
functions, returning top is different from returning unit or not returning anything. In particular, not returning anything has different stack behavior than returning something. I don't know what the performance consequences of that are, though. As for returning unit versus returning top, unit has well defined operations on it such as equality, whereas top does not. If top did, it'd be something like .string
, in which case the values for top are distinguishable, so reasoning about correctness would be very different for top and unit functions.
In light of this, what should we do? Well, it seems important for non-returning functions to be usable as functions returning top when using higher-order functions. We'd also like to not have to distinguish between ReturningCallable
and NonReturningCallable
. So how about, whenever we make a first-class reference to a non-returning function, we box it into a function returning unit? Also, if a returning function is missing a return statement and its return type is a subtype of unit, we automatically insert a return unit;
. This would even let people specify the return type as top without inconvenience in order to let subclasses narrow the return type should they find that useful. Lastly, Callable
can have an attribute, say .unit
, which wraps it with a function that throws away the original's returned value and simply returns unit.
How does all that sound?
Sounds like unit
and top
are used in your proposal without being defined ;)
Also, Nothing
currently is the type of null
.
Also, I actually agreed to @gavinking's proposal:
But I suppose we could potentially use Anything/Nothing as the names of the top / bottom types if we renamed our current Nothing class to Null. That might work out pretty nicely.
Whatever happened to it?
unit and top are already well defined type-theoretic concepts, so I referred to them as concepts rather than as named types in Ceylon to keep things unambiguous (a lot of names are being thrown around, heheh).
As for Nothing
, I got the impression people were alright with changing the type of null
to Null
. Anything
, on the other hand, along with Any
and All
are not the best names in my opinion since a List<Anything>
is not a list of anything the user wants. The reason for lots of the confusion expressed above is that it's not clear whether it's the producer's choice or the consumer's choice of what "any" stands for. Hence I say just Thing
: List<Thing>
and Property<Thing>
both have clear meanings even in light of covariance and contravariance.
Short: +1 Long: That's actually how I felt as well, Anything/Nothing and Null seem pretty intuitive to me, and seems to fit with @RossTate 's suggestion too (preferring "Anything" over "Thing" though).
Also, I actually agreed to @gavinking's proposal:
But I suppose we could potentially use Anything/Nothing as the names of the top / bottom types if we renamed our current Nothing class to Null. That might work out pretty nicely.
Whatever happened to it?
I also prefer that.
@RossTate wdym that it's not a list of anything the user wants? If I look at List<Anything>
I could read it as "a list that could contain anything". Which I would then translate to: I can put anything in there I want but I must also expect that anything can be in there (so I can make no assumptions).
At the same time "Thing" and "Object" seem completely synonymous to me, so I could imagine people getting confused. (Although probably semantically speaking you could say that an "Object" seems more "physical" and therefore "feels" more like a subclass of "Thing", but that's probably taking it very far, most people wouldn't readily distinguish between the two I think)
The problem is "list of anything" is incomplete. As you say, you could read it the way you describe (i.e. "list of anything the producer wants"), but you could also read it the opposite way (i.e. "list of anything the consumer wants").
Object
is any instance of a class, and has long precedent for meaning that. In Ceylon, Thing
is different because not everything is an instance of a class (e.g. null
). If there's something odd in the two having different meanings, that's oddity is caused by Ceylon's separation of objects and other values.
"list of anything the consumer wants"
I don't understand this, do you have an example where this would make sense?
Here's another take: List<Anything>
is a list of anything I want. The problem is, who is "I"? Is "I" the person making the list (i.e. the producer), or is "I" the person using the list (i.e. the consumer)? Depending on your answer, you get top or bottom. The word "anything" is inherently ambiguous even in English. So let's not use it in a formal setting like programming.
I'm not a native speaker, but to me "Anything" in both producer or consumer cases mean "could be everything", so I can put everything I want (Top) and I can find anything in there so I have to check (Top again). So to me it's not really ambiguous. But I'm not biased by any language that already use the "Anything" term.
Depending on your answer, you get top or bottom
I don't know how it could be "bottom" if we already decided that that's basically equivalent to "nothing"? So probably I still don't see how "anything" could be "nothing" depending on your POV...
Same here: Anything
sounds correct to me, from the point of view of both producer and consumer.
So, if I were told I were given a list of anything I want, I would think that meant I could get integers, strings, floats, or whatever I choose from it. Mathematically, that would be a list of bottoms. Note that in this case I am the consumer.
On the other hand, if I were told I could make a list of anything I want, I would think that meant I could put integers, strings, floats, or whatever I choose into it. Mathematically, that would be a list of tops. Note that in this case I am the producer.
Does that make the difference clearer?
So, if I were told I were given a list of anything I want, I would think that meant I could get integers, strings, floats, or whatever I choose from it. Mathematically, that would be a list of bottoms. Note that in this case I am the consumer.
Sorry, but that doesn't make much sense to me. If someone gives me a list of anything and I take something from it, then that thing could obviously be anything, right? I mean, there's a difference between someone giving you a "list of anything" and someone giving you a "list of anything you want". Nobody said you have a choice, Ross ;-)
Exactly, to me it's simply the difference between the two following code snippets:
List<Anything> list1 = List<Anything>("foo");
Anything x = list1.first;
if (is String x) { print(x) }
and
List<Nothing> list2 = List<Nothing>( /* can only be empty */ )
Google "I'll give you anything" and (assuming google shows you the same thing as me) all the hits will use the bottom interpretation of "anything" not the top interpretation.
We find that
Void
(the top of the hierarchy) is not adequatly named, since it conveys the idea that it can only point to nothing.Similarly we find that
Bottom
(the subclass of every type) is confusing for those unfamiliar with the notion (everyone except ML guys).We proposed the following alternatives:
Note that
undefined
is a valid value in many languages and would therefore be confusing.