Solution: nil. Problem: How do you tell the difference between "the array was empty" and "the item you popped was nil"?
Solution: have pop return a Maybe instead.
{ has_value: bool,
val: T|nil }
* well, this representation is a bit too permissive, since you could do {has_value: true, val: nil}
if you wanted to get the types water-tight, you'd need dependent types, typing it as dependent pair: Maybe<T> =
sigma (has_value: bool)
if has_value
then T
else ()
which can then only have values (false, ())
or (true, <actual value of type T>)or a whole value
or use an enumerator
or a collection decorator
All of which are simple solutions already available. No need to import every new paradigm hammer in the hope that everything is a nail.
It’s great in large scale projects, which I think is where a dynamic language starts to show its warts.
Never manually do the work that the compiler / runtime could do.
You can design "more thoughtfully designing your data/object model" (in other regards) AND have the compiler make sure you're not doing null referencing for you (so that that's not your concern anymore) -- instead of manually and in an ad-hoc way per project implementing another menial responsibility into the design of your model.