grscheller.untyped.nada
Singleton Representing a Non-existing Value
An attempt to give Python a "bottom" type.
- nada is an attempt to give Python a "bottom" type
While a true bottom type has no instances, nada is a singleton. Python's
evolving typing system seems to reject the concept of a true bottom type.
- types like
Noneand()make for lousy bottoms- they take few methods (much less EVERY method)
Nonehas no length and not indexable,()is at least iterable- returned values must be constantly checked for
- preventing one from blissfully go down the "happy path"
Noneand()are commonly used as sentinel values- hindering both as being interpreted as "nothingness"
The nada object makes for a better bottom like singleton object than
either None and () do.
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"""### Singleton Representing a Non-existing Value 16 17An attempt to give Python a "bottom" type. 18 19* **nada** is an attempt to give Python a "bottom" type 20 21While a true bottom type has no instances, `nada` is a singleton. Python's 22evolving typing system seems to reject the concept of a true bottom type. 23 24* types like `None` and `()` make for lousy bottoms 25 * they take few methods (much less EVERY method) 26 * `None` has no length and not indexable, `()` is at least iterable 27 * returned values must be constantly checked for 28 * preventing one from blissfully go down the "happy path" 29 * `None` and `()` are commonly used as sentinel values 30 * hindering both as being interpreted as "nothingness" 31 32The `nada` object makes for a better bottom like singleton object than 33either `None` and `()` do. 34""" 35 36from __future__ import annotations 37from typing import Any, Callable, Final, Iterator 38 39__all__ = [ 'Nada', 'nada' ] 40 41class _Sentinel(): 42 def __repr__(self) -> str: 43 return '_Sentinel()' 44 45_sentinel: Final[_Sentinel] = _Sentinel() 46 47class Nada(): 48 """#### Singleton representing a missing value. 49 50 WARNING: OBSOLETED - use grscheller.experimental.nada instead 51 52 * singleton nada: nada = Nada() represents a non-existent value 53 * returns itself for arbitrary method calls 54 * returns itself if called as a Callable with arbitrary arguments 55 * interpreted as an empty container by standard Python functions 56 * warning: non-standard equality semantics 57 * comparison compares true only when 2 non-missing values compare true 58 * when compared to itself behaves somewhat like IEEE Float NAN's 59 * `nada is nada` is true 60 * `nada == nada` is false 61 * `nada != nada` is true 62 * thus a == b means two non-missing values compare as equal 63 * warning: does not handle named arguments 64 65 """ 66 __slots__ = () 67 68 def __new__(cls) -> Nada: 69 if not hasattr(cls, 'instance'): 70 cls.instance = super(Nada, cls).__new__(cls) 71 cls._hash = hash((_sentinel, (_sentinel,))) 72 return cls.instance 73 74 def __iter__(self) -> Iterator[Any]: 75 return iter(()) 76 77 def __hash__(self) -> int: 78 return self._hash 79 80 def __repr__(self) -> str: 81 return 'nada' 82 83 def __bool__(self) -> bool: 84 return False 85 86 def __len__(self) -> int: 87 return 0 88 89 def __add__(self, right: Any) -> Nada: 90 return Nada() 91 92 def __radd__(self, left: Any) -> Nada: 93 return Nada() 94 95 def __mul__(self, right: Any) -> Nada: 96 return Nada() 97 98 def __rmul__(self, left: Any) -> Nada: 99 return Nada() 100 101 def __eq__(self, right: Any) -> bool: 102 return False 103 104 def __ne__(self, right: Any) -> bool: 105 return True 106 107 def __ge__(self, right: Any) -> bool: 108 return False 109 110 def __gt__(self, right: Any) -> bool: 111 return False 112 113 def __le__(self, right: Any) -> bool: 114 return False 115 116 def __lt__(self, right: Any) -> bool: 117 return False 118 119 def __getitem__(self, index: int|slice) -> Any: 120 return Nada() 121 122 def __setitem__(self, index: int|slice, item: Any) -> None: 123 return 124 125 def __call__(*args: Any, **kwargs: Any) -> Any: 126 return Nada() 127 128 # def __getattr__(self, name: str) -> Callable[[Any], Any]: 129 # """Comment out for doc generation, pdoc gags on this method.""" 130 # def method(*args: Any, **kwargs: Any) -> Any: 131 # return Nada() 132 # return method 133 134 def nada_get(self, alt: Any=_sentinel) -> Any: 135 """ 136 Get an alternate value, defaults to Nada(). 137 138 """ 139 if alt == _sentinel: 140 return Nada() 141 else: 142 return alt 143 144nada = Nada()
class
Nada:
48class Nada(): 49 """#### Singleton representing a missing value. 50 51 WARNING: OBSOLETED - use grscheller.experimental.nada instead 52 53 * singleton nada: nada = Nada() represents a non-existent value 54 * returns itself for arbitrary method calls 55 * returns itself if called as a Callable with arbitrary arguments 56 * interpreted as an empty container by standard Python functions 57 * warning: non-standard equality semantics 58 * comparison compares true only when 2 non-missing values compare true 59 * when compared to itself behaves somewhat like IEEE Float NAN's 60 * `nada is nada` is true 61 * `nada == nada` is false 62 * `nada != nada` is true 63 * thus a == b means two non-missing values compare as equal 64 * warning: does not handle named arguments 65 66 """ 67 __slots__ = () 68 69 def __new__(cls) -> Nada: 70 if not hasattr(cls, 'instance'): 71 cls.instance = super(Nada, cls).__new__(cls) 72 cls._hash = hash((_sentinel, (_sentinel,))) 73 return cls.instance 74 75 def __iter__(self) -> Iterator[Any]: 76 return iter(()) 77 78 def __hash__(self) -> int: 79 return self._hash 80 81 def __repr__(self) -> str: 82 return 'nada' 83 84 def __bool__(self) -> bool: 85 return False 86 87 def __len__(self) -> int: 88 return 0 89 90 def __add__(self, right: Any) -> Nada: 91 return Nada() 92 93 def __radd__(self, left: Any) -> Nada: 94 return Nada() 95 96 def __mul__(self, right: Any) -> Nada: 97 return Nada() 98 99 def __rmul__(self, left: Any) -> Nada: 100 return Nada() 101 102 def __eq__(self, right: Any) -> bool: 103 return False 104 105 def __ne__(self, right: Any) -> bool: 106 return True 107 108 def __ge__(self, right: Any) -> bool: 109 return False 110 111 def __gt__(self, right: Any) -> bool: 112 return False 113 114 def __le__(self, right: Any) -> bool: 115 return False 116 117 def __lt__(self, right: Any) -> bool: 118 return False 119 120 def __getitem__(self, index: int|slice) -> Any: 121 return Nada() 122 123 def __setitem__(self, index: int|slice, item: Any) -> None: 124 return 125 126 def __call__(*args: Any, **kwargs: Any) -> Any: 127 return Nada() 128 129 # def __getattr__(self, name: str) -> Callable[[Any], Any]: 130 # """Comment out for doc generation, pdoc gags on this method.""" 131 # def method(*args: Any, **kwargs: Any) -> Any: 132 # return Nada() 133 # return method 134 135 def nada_get(self, alt: Any=_sentinel) -> Any: 136 """ 137 Get an alternate value, defaults to Nada(). 138 139 """ 140 if alt == _sentinel: 141 return Nada() 142 else: 143 return alt
Singleton representing a missing value.
WARNING: OBSOLETED - use grscheller.experimental.nada instead
- singleton nada: nada = Nada() represents a non-existent 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
- warning: non-standard equality semantics
- comparison compares true only when 2 non-missing values compare true
- when compared to itself behaves somewhat like IEEE Float NAN's
nada is nadais truenada == nadais falsenada != nadais true
- thus a == b means two non-missing values compare as equal
- comparison compares true only when 2 non-missing values compare true
- warning: does not handle named arguments
nada =
nada