Module grscheller.fp.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 Null & () should be store-able in data structures

Functions

def nothing(*args: Any, **kwargs: Any) ‑> Callable[[Any], Any]

Classes

class Nothing

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 ()
Expand source code
class Nothing():
    """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 ()

    """
    __slots__ = ()

    def __new__(cls) -> Nothing:
        if not hasattr(cls, 'instance'):
            cls.instance = super(Nothing, cls).__new__(cls)
        return cls.instance

    def __iter__(self) -> Iterator[Any]:
        return iter(())

    def __repr__(self) -> str:
        return 'Nothing()'

    def __str__(self) -> str:
        return 'nothing'

    def __bool__(self) -> bool:
        return False

    def __len__(self) -> int:
        return 0

    def __add__(self, right: Any) -> Any:
        return Nothing()

    def __radd__(self, left: Any) -> Any:
        return Nothing()

    def __mul__(self, right: Any) -> Any:
        return Nothing()

    def __rmul__(self, left: Any) -> Any:
        return Nothing()

    def __getitem__(self, index: int|slice) -> Any:
        return Nothing()

    def __setitem__(self, index: int|slice, item: Any) -> None:
        return

    def __getattr__(self, name: str) -> Any:
        def method(*args: Any, **kwargs: Any) -> Callable[[Any], Any]:
            return Nothing()
        return method

    def __call__(*args: Any, **kwargs: Any) -> Any:
        return Nothing()

    def get(self, alt: Optional[_T]=None) -> _T|Nothing:
        """Return an alternate value of type _T or a Nothing."""
        if alt is None:
            return Nothing()
        else:
            return alt

Methods

def get(self, alt: Optional[_T] = None) ‑> Union[_T, Nothing]

Return an alternate value of type _T or a Nothing.

def instance(*args: Any, **kwargs: Any) ‑> Callable[[Any], Any]