grscheller.untyped.nothing
A nothing is an attempt to give Python a "bottom" type.
- unlike a true bottom, it can be instantiated as a singleton
- types like ~T|None and ~T|() act like a poor man's Optional/Maybe Monads
- both None and () make for lousy bottom types
- both don't accept many methods, None has no length, at least () is iterable
- when returning or iterating values, both must constantly be checked for
- many developers use None and () as sentinel values
- therefore by design Null & () are store-able in this data structure
1# Copyright 2023-2024 Geoffrey R. Scheller 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15"""A nothing is an attempt to give Python a "bottom" type. 16 17* unlike a true bottom, it can be instantiated as a singleton 18* types like ~T|None and ~T|() act like a poor man's Optional/Maybe Monads 19* both None and () make for lousy bottom types 20* both don't accept many methods, None has no length, at least () is iterable 21* when returning or iterating values, both must constantly be checked for 22* many developers use None and () as sentinel values 23* therefore by design Null & () are store-able in this data structure 24 25""" 26 27from __future__ import annotations 28 29__all__ = [ 'Nothing', 'nothing' ] 30__author__ = "Geoffrey R. Scheller" 31__copyright__ = "Copyright (c) 2023-2024 Geoffrey R. Scheller" 32__license__ = "Apache License 2.0" 33 34from typing import Any, Callable, Iterator, Optional 35 36class Nothing(): 37 """Singleton semantically represents a missing value. 38 39 * nothing: Nothing = Nothing() is a singleton representing an absent value 40 * returns itself for arbitrary method calls 41 * returns itself if called as a Callable with arbitrary arguments 42 * interpreted as an empty container by standard Python functions 43 * makes for a better "bottom type" than either None or () 44 """ 45 __slots__ = () 46 47 def __new__(cls) -> Nothing: 48 if not hasattr(cls, 'instance'): 49 cls.instance = super(Nothing, cls).__new__(cls) 50 return cls.instance 51 52 def __iter__(self) -> Iterator[Any]: 53 return iter(()) 54 55 def __repr__(self) -> str: 56 return 'nothing' 57 58 def __bool__(self) -> bool: 59 return False 60 61 def __len__(self) -> int: 62 return 0 63 64 def __add__(self, right: Any) -> Any: 65 return Nothing() 66 67 def __radd__(self, left: Any) -> Any: 68 return Nothing() 69 70 def __mul__(self, right: Any) -> Any: 71 return Nothing() 72 73 def __rmul__(self, left: Any) -> Any: 74 return Nothing() 75 76 def __getitem__(self, index: int|slice) -> Any: 77 return Nothing() 78 79 def __setitem__(self, index: int|slice, item: Any) -> None: 80 return 81 82 # def __getattr__(self, name: str) -> Callable[[Any], Any]: 83 # """pdoc gags on this commented-out code when generating docs""" 84 # def method(*args: Any, **kwargs: Any) -> Any: 85 # return Nothing() 86 # return method 87 88 def __call__(*args: Any, **kwargs: Any) -> Any: 89 return Nothing() 90 91 def get(self, alt: Optional[Any]=(None, (13, 7), None, 42424242)) -> Any: 92 """Returns an alternate value, defaults Nothing().""" 93 if alt == (None, (13, 7), None, 42424242): # an unlikely sentinel value 94 return Nothing() 95 else: 96 return alt 97 98nothing = Nothing()
class
Nothing:
37class Nothing(): 38 """Singleton semantically represents a missing value. 39 40 * nothing: Nothing = Nothing() is a singleton representing an absent value 41 * returns itself for arbitrary method calls 42 * returns itself if called as a Callable with arbitrary arguments 43 * interpreted as an empty container by standard Python functions 44 * makes for a better "bottom type" than either None or () 45 """ 46 __slots__ = () 47 48 def __new__(cls) -> Nothing: 49 if not hasattr(cls, 'instance'): 50 cls.instance = super(Nothing, cls).__new__(cls) 51 return cls.instance 52 53 def __iter__(self) -> Iterator[Any]: 54 return iter(()) 55 56 def __repr__(self) -> str: 57 return 'nothing' 58 59 def __bool__(self) -> bool: 60 return False 61 62 def __len__(self) -> int: 63 return 0 64 65 def __add__(self, right: Any) -> Any: 66 return Nothing() 67 68 def __radd__(self, left: Any) -> Any: 69 return Nothing() 70 71 def __mul__(self, right: Any) -> Any: 72 return Nothing() 73 74 def __rmul__(self, left: Any) -> Any: 75 return Nothing() 76 77 def __getitem__(self, index: int|slice) -> Any: 78 return Nothing() 79 80 def __setitem__(self, index: int|slice, item: Any) -> None: 81 return 82 83 # def __getattr__(self, name: str) -> Callable[[Any], Any]: 84 # """pdoc gags on this commented-out code when generating docs""" 85 # def method(*args: Any, **kwargs: Any) -> Any: 86 # return Nothing() 87 # return method 88 89 def __call__(*args: Any, **kwargs: Any) -> Any: 90 return Nothing() 91 92 def get(self, alt: Optional[Any]=(None, (13, 7), None, 42424242)) -> Any: 93 """Returns an alternate value, defaults Nothing().""" 94 if alt == (None, (13, 7), None, 42424242): # an unlikely sentinel value 95 return Nothing() 96 else: 97 return alt
Singleton semantically represents a missing value.
- nothing: Nothing = Nothing() is a singleton representing an absent value
- returns itself for arbitrary method calls
- returns itself if called as a Callable with arbitrary arguments
- interpreted as an empty container by standard Python functions
- makes for a better "bottom type" than either None or ()
def
get(self, alt: Optional[Any] = (None, (13, 7), None, 42424242)) -> Any:
92 def get(self, alt: Optional[Any]=(None, (13, 7), None, 42424242)) -> Any: 93 """Returns an alternate value, defaults Nothing().""" 94 if alt == (None, (13, 7), None, 42424242): # an unlikely sentinel value 95 return Nothing() 96 else: 97 return alt
Returns an alternate value, defaults Nothing().
nothing =
nothing