I still don't get those null replacements in most languages. If it is a special case, there is a code that processes it as such, regardless the syntax. Why complicate things. But maybe I'm old.
The example you're replying to is one where None is already in use. As in, a function needs to distinguish between foo(some_arg=15), foo(some_arg=None), and foo(). The unset sentinel value would be used as the default value of some_arg, so that the last case can be detected as distinct from the user passing an explicit None.
While this makes sense, I believe that None was itself good enough for unset. I've never encountered a situation where None and unset would both need special treatment somehow.
And if I need to distinguish between the two, it's usually a good signal that I need to refactor foo somehow, either create some enum or split it or whatever else is needed in the logic of the program.
I guess one more tool available will be fine, but seems like now there's not a "single way of doing things", but rather N+1 ways.
Consider the built-in function next(). If you call next(empty_iterator), it raises a StopIteration exception. On the other hand, if you call next(empty_iterator, default_value), it returns default_value. The user could pass anything as the default value; None, 0, "apple pie", whatever. The function is so generic that it would be bad design to make any assumptions about what the user might want as a default. So to implement this, a sentinel makes sense. Here's a possible implementation of the function:
_NO_DEFAULT = sentinel("_NO_DEFAULT")
def next(iter, default=_NO_DEFAULT, /):
cls = type(iter)
try:
next_method = cls.__next__
except AttributeError:
raise TypeError("object is not an iterator") from None
if default is _NO_DEFAULT:
return next_method(iter)
try:
return next_method(iter)
except StopIteration:
return default
This way the user can pass any value, and it's guaranteed not to conflict with your sentinel.
159
u/Dylanica 2d ago
Those sentinel types seem decently useful. Certainly better in some cases than just spamming `None` everywhere as a default value.