id,summary,reporter,owner,description,type,status,priority,milestone,component,resolution,keywords,cc,merged,author,reviewer,upstream,work_issues,branch,commit,dependencies,stopgaps
14524,Decorator for methods requiring mutability or immutability,SimonKing,jason,"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: instance is mutable, 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: instance is immutable, 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?
",enhancement,closed,major,sage-5.11,misc,fixed,decorator mutability,,sage-5.11.beta0,Simon King,Volker Braun,N/A,,,,,