#14524: Decorator for methods requiring mutability or immutability
-----------------------------+----------------------------------------------
   Reporter:  SimonKing      |             Owner:  jason               
       Type:  PLEASE CHANGE  |            Status:  new                 
   Priority:  major          |         Milestone:  sage-5.10           
  Component:  misc           |          Keywords:  decorator mutability
Work issues:                 |   Report Upstream:  N/A                 
  Reviewers:                 |           Authors:  Simon King          
  Merged in:                 |      Dependencies:                      
   Stopgaps:                 |  
-----------------------------+----------------------------------------------
 Some methods (most notably `__hash__`) require that an object is
 immutable. Other methods (such as `add_vertex` of a graph) require that an
 object is mutable.

 I suggest to introduce a method decorator, such that (im)mutability is
 automatically verified before calling the method. Note that the patch just
 creates the decorator, but does not use it yet. In a second step, I plan
 to use it on graphs.

 The decorator tests immutability by the value of an attribute called
 `_is_immutable`, which is used by `sage.structure.mutability.Mutability`
 anyway (but I change this attribute into a public attribute).
 Unfortunately, `sage.graphs.generic_graph.GenericGraph.__hash__` uses
 another name, namely `_immutable`. But I think this can be changed in the
 second step.

 From the doctests:
 {{{
         sage: from sage.structure.mutability import require_mutable,
 require_immutable
         sage: class A:
         ...    def __init__(self, val):
         ...        self._m = val
         ...    @require_mutable
         ...    def change(self, new_val):
         ...        'change self'
         ...        self._m = new_val
         ...    @require_immutable
         ...    def __hash__(self):
         ...        'implement hash'
         ...        return hash(self._m)
         sage: a = A(5)
         sage: a.change(6)
         sage: hash(a)
         Traceback (most recent call last):
         ...
         AssertionError: <type 'instance'> instance is mutable, <function
 __hash__ at ...> must not be called
         sage: a._is_immutable = True
         sage: hash(a)
         6
         sage: a.change(7)   # indirect doctest
         Traceback (most recent call last):
         ...
         AssertionError: <type 'instance'> instance is immutable, <function
 change at ...> must not be called
         sage: from sage.misc.sageinspect import sage_getdoc
         sage: print sage_getdoc(a.change)
         change self
 }}}

 As one can see, by default an object is supposed to be mutable. This may
 be important during initialisation of the object. So, one would first
 initialise it and then declare that it is (from now on) immutable.

 __Questions__

 - Is `AssertionError` the right thing to raise here? Usually, when hashing
 does not work, a `TypeError` is raised.
 - One could be more intrusive. For example, when calling a method
 decorated by `require_immutable` on a mutable object, one could instead
 ''make'' it immutable (by assignment to `_is_immutable`. In that way,
 after the first call to `hash`, the object can not be accidentally changed
 (but of course, if the user wants so, `_is_immutable` can be deleted).
 Good idea, or not pythonic?

-- 
Ticket URL: <http://trac.sagemath.org/sage_trac/ticket/14524>
Sage <http://www.sagemath.org>
Sage: Creating a Viable Open Source Alternative to Magma, Maple, Mathematica, 
and MATLAB

-- 
You received this message because you are subscribed to the Google Groups 
"sage-trac" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sage-trac?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to