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.

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