docs: def immutable(cls):
      '''
      The @immutable decorator makes an abstract type out of the decorated class that overloads
      __new__ to create interesting behavior consistent with immutable data types. The following
      decorators may be used inside of the decorated class to define immutable behavior:
        * @value indicates that the following function is really a value that should be calculated
          and stored as a value of its arguments. The arguments should not start with self and 
          should instead be named after other values from which it is calculated. If there are no
          arguments, then the returned value is a constant. Note that self is not an argument to this
          function.
        * @param indicates that the following function is really a variable that should be checked
          by the decorated function. Params are settable as long as the immutable object is transient.
          The check function decorated by @param() is actually a transformation function that is
          called every time the parameter gets changed; the actual value given to which the param is
          set is the value returned by this function. The function may raise exceptions to flag
          errors. Note that self is not an argument to this function. All parameters are required for
          an instantiated object; this means that all parameters must either be provided as values or
          options of implementing classes or must be assigned in the constructor.
        * @option(x) indicates that the following function is really an optional value; the syntax and
          behavior of @option is identical to @param except that @option(x) indicates that, if not
          provided, the parameter should take the value x, while @param indicates that an exception
          should be raised.
        * @require indicates that the following function is a requirement that should be run on the
          given arguments (which should name params/options/values of the class). Note that self is
          an argument to the function. If the function yields a truthy value, then the requirement is
          considered to be met; if it raises an exception or yields a non-trithy value (like None or
          []), then the requirement is not met and the object is considered invalid.
      In immutable objects, the functions defined by @require decorators are not instantiated; they
      may, however, be overloaded and called back to the parent class.
      '''
      # Annotate the class!
      cls = _annotate_imm(cls)
      # The attributes we want to make sure get set:
      auto_members = (('__getattribute__', _imm_getattribute),
                      ('__setattr__',      _imm_setattr),
                      ('__delattr__',      _imm_delattr),
                      ('__copy__',         _imm__copy__),
                      ('__deepcopy__',     _imm__copy__))
      for (name, fn) in auto_members: setattr(cls, name, _method_type(fn, cls))
      # __new__ is special...
      @staticmethod
      def _custom_new(c, *args, **kwargs): return _imm_new(c)
      setattr(cls, '__new__', _custom_new)
      # and the attributes we set only if they haven't been specified
      optl_members = (('is_persistent',    _imm_is_persist),
                      ('is_transient',     _imm_is_trans),
                      ('persist',          imm_persist),
                      ('transient',        imm_transient),
                      ('copy',             imm_copy),
                      ('params',           imm_params),
                      ('values',           imm_values),
                      ('todict',           imm_dict))
      for (name, fn) in optl_members:
          if not hasattr(cls, name):
              setattr(cls, name, _method_type(fn, cls))
      # and the attributes we set if they're not overloaded from object
      initfn = _imm_default_init if cls.__init__ is object.__init__ else cls.__init__
      # we set this up so that it can monitor entry and exit from this specific class's __init__()
      def _init_wrapper(imm, *args, **kwargs):
          # call the init normally...
          initfn(imm, *args, **kwargs)
          # If we're still initializing after running the constructor, we need to switch to
          # transient
          if type(imm) is cls and _imm_is_init(imm): _imm_init_to_trans(imm)
          # Okay, all checks passed!
      setattr(cls, '__init__', _method_type(_init_wrapper, cls))
      dflt_members = (('__dir__',          _imm_dir),
                      ('__repr__',         _imm_repr),
                      ('__hash__',         _imm_hash))
      for (name, fn) in dflt_members:
          if not hasattr(cls, name) or not hasattr(object, name) or \
             getattr(cls, name) is getattr(object, name):
              setattr(cls, name, _method_type(fn, cls))
      # Done!
      return cls