grscheller.untyped.nothing
Singleton Representing a Non-existing Value
A version of grscheller.fp.nada geared for use in less strictly typed code.
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 17A version of grscheller.fp.nada geared for use in less strictly 18typed code. 19""" 20 21from __future__ import annotations 22from typing import Any, Callable, Iterator, NewType 23 24__all__ = [ 'Nothing', 'nothing' ] 25 26_S = NewType('_S', tuple[tuple[()], tuple[tuple[()], tuple[tuple[()], None]]]) 27_sentinel: _S = _S(((), ((), ((), None)))) 28 29class Nothing(): 30 """ 31 #### Singleton semantically represents a missing value. 32 33 * singleton nothing: nothing = Nothing() represents a non-existent value 34 * returns itself for arbitrary method calls 35 * returns itself if called as a Callable with arbitrary arguments 36 * interpreted as an empty container by standard Python functions 37 * comparison ops compare true only when 2 non-missing values compare true 38 * when compared to itself behaves somewhat like IEEE Float NAN's 39 * `nothing is nothing` is true 40 * `nothing == nothing` is false 41 * `nothing != nothing` is true 42 """ 43 __slots__ = () 44 45 def __new__(cls) -> Nothing: 46 if not hasattr(cls, 'instance'): 47 cls.instance = super(Nothing, cls).__new__(cls) 48 cls._hash = hash((_sentinel, (_sentinel,))) 49 return cls.instance 50 51 def __iter__(self) -> Iterator: 52 return iter(()) 53 54 def __hash__(self) -> int: 55 return self._hash 56 57 def __repr__(self) -> str: 58 return 'nothing' 59 60 def __bool__(self) -> bool: 61 return False 62 63 def __len__(self) -> int: 64 return 0 65 66 def __add__(self, right: Any) -> Nothing: 67 return Nothing() 68 69 def __radd__(self, left: Any) -> Nothing: 70 return Nothing() 71 72 def __mul__(self, right: Any) -> Nothing: 73 return Nothing() 74 75 def __rmul__(self, left: Any) -> Nothing: 76 return Nothing() 77 78 def __eq__(self, right: Any) -> bool: 79 """Never equals anything, even itself.""" 80 return False 81 82 def __ne__(self, right: Any) -> bool: 83 """Always does not equal anything, even itself.""" 84 return True 85 86 def __ge__(self, right: Any) -> bool: 87 return False 88 89 def __gt__(self, right: Any) -> bool: 90 return False 91 92 def __le__(self, right: Any) -> bool: 93 return False 94 95 def __lt__(self, right: Any) -> bool: 96 return False 97 98 def __getitem__(self, index: int|slice) -> Any: 99 return Nothing() 100 101 def __setitem__(self, index: int|slice, item: Any) -> None: 102 return 103 104 def __call__(*args: Any, **kwargs: Any) -> Any: 105 return Nothing() 106 107 # def __getattr__(self, name: str) -> Callable[[Any], Any]: 108 # """Comment out for doc generation, pdoc gags on this method.""" 109 # def method(*args: Any, **kwargs: Any) -> Any: 110 # return Nothing() 111 # return method 112 113 def get(self, alt: Any=_sentinel) -> Any: 114 """ 115 ##### Get an alternate value, defaults to Nada(). 116 """ 117 if alt == _sentinel: 118 return Nothing() 119 else: 120 return alt 121 122nothing = Nothing()
class
Nothing:
30class Nothing(): 31 """ 32 #### Singleton semantically represents a missing value. 33 34 * singleton nothing: nothing = Nothing() represents a non-existent value 35 * returns itself for arbitrary method calls 36 * returns itself if called as a Callable with arbitrary arguments 37 * interpreted as an empty container by standard Python functions 38 * comparison ops compare true only when 2 non-missing values compare true 39 * when compared to itself behaves somewhat like IEEE Float NAN's 40 * `nothing is nothing` is true 41 * `nothing == nothing` is false 42 * `nothing != nothing` is true 43 """ 44 __slots__ = () 45 46 def __new__(cls) -> Nothing: 47 if not hasattr(cls, 'instance'): 48 cls.instance = super(Nothing, cls).__new__(cls) 49 cls._hash = hash((_sentinel, (_sentinel,))) 50 return cls.instance 51 52 def __iter__(self) -> Iterator: 53 return iter(()) 54 55 def __hash__(self) -> int: 56 return self._hash 57 58 def __repr__(self) -> str: 59 return 'nothing' 60 61 def __bool__(self) -> bool: 62 return False 63 64 def __len__(self) -> int: 65 return 0 66 67 def __add__(self, right: Any) -> Nothing: 68 return Nothing() 69 70 def __radd__(self, left: Any) -> Nothing: 71 return Nothing() 72 73 def __mul__(self, right: Any) -> Nothing: 74 return Nothing() 75 76 def __rmul__(self, left: Any) -> Nothing: 77 return Nothing() 78 79 def __eq__(self, right: Any) -> bool: 80 """Never equals anything, even itself.""" 81 return False 82 83 def __ne__(self, right: Any) -> bool: 84 """Always does not equal anything, even itself.""" 85 return True 86 87 def __ge__(self, right: Any) -> bool: 88 return False 89 90 def __gt__(self, right: Any) -> bool: 91 return False 92 93 def __le__(self, right: Any) -> bool: 94 return False 95 96 def __lt__(self, right: Any) -> bool: 97 return False 98 99 def __getitem__(self, index: int|slice) -> Any: 100 return Nothing() 101 102 def __setitem__(self, index: int|slice, item: Any) -> None: 103 return 104 105 def __call__(*args: Any, **kwargs: Any) -> Any: 106 return Nothing() 107 108 # def __getattr__(self, name: str) -> Callable[[Any], Any]: 109 # """Comment out for doc generation, pdoc gags on this method.""" 110 # def method(*args: Any, **kwargs: Any) -> Any: 111 # return Nothing() 112 # return method 113 114 def get(self, alt: Any=_sentinel) -> Any: 115 """ 116 ##### Get an alternate value, defaults to Nada(). 117 """ 118 if alt == _sentinel: 119 return Nothing() 120 else: 121 return alt
Singleton semantically represents a missing value.
- singleton nothing: nothing = Nothing() 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
- comparison ops compare true only when 2 non-missing values compare true
- when compared to itself behaves somewhat like IEEE Float NAN's
nothing is nothingis truenothing == nothingis falsenothing != nothingis true
- when compared to itself behaves somewhat like IEEE Float NAN's
nothing =
nothing