Hi There, I'd like to discuss a design question. Some time ago Adrien Boussicault and myself started to write some experimental code for copy-on-write in Sage/Python. The idea is now more or less dropped because performance gain was not so good and the syntax was not very usable. It still remain that along the way we had a design idea that I would like to submit here for comment:
The idea is inspired from the "prototype" design pattern (see [Pro], [GOF]). I want to define subclasses of Element with the following behavior: Those classes are intended to be used to model *mathematical* objects, which are by essence immutable. However, in many occasions, one wants to construct the data-structure encoding of a new mathematical object by small modifications of the data structure encoding some already built object. This is a very common stuff for example in matrices: For example: given a matrix M we want to replace every non_zero position by 1 res = copy(M) for pos in res._nonzero_positions_by_row(): res[pos] = 1 res.set_immutable() However in many cases, for the resulting data-structure to correctly encode the mathematical object, some structural invariants must hold (say for example we want that the matrix is symmetric). One problem is that, in many cases, during the modification process, there is no possibility but to break the invariants. Here there is no way to keep the matrix symmetric during the replacement by 1... A typical example in combinatorics, in a list modeling a permutation of \{1,\dots,n\}, the integers must be distinct. A very common operation is to take a permutation to make a copy with some small modifications, like exchanging two consecutive values in the list or cycling some values. Though the result is clearly a permutations there's no way to avoid breaking the permutations invariants at some point during the modifications. So the idea is the following: to allows local breaking of invariant on a locally mutable copy and to check that things are restored in a proper state at the end. So I wrote a small class called ClonableElement and several derived subclasses (clone is the standard name for the copy method in the "prototype" design pattern): A class C inheriting from ClonableElement must implement the following two methods - obj.__copy__() -- returns a fresh copy of obj - obj.check() -- returns nothing, raise an exception if obj doesn't satisfies the data structure invariants Then, given an instance obj of C, the following sequences of instructions ensures that the invariants of new_obj are properly restored at the end with obj.clone() as new_obj: ... # lot of invariant breaking modifications on new_obj ... # invariants are ensured to be fulfilled The following equivalent sequence of instructions can be used if speed is needed, in particular in Cython code (unfortunately, the handling of the with instruction make some overhead)... new_obj = obj.__copy__() ... # lot of invariant breaking modifications on new_obj ... new_obj.set_immutable() new_obj.check() # invariants are ensured to be fulfilled I also took to chance to handle hashing... All the code is on #8702, together with some performance tests... Also this is my first real life Cython code so any help is welcome. Thanks for any comment or suggestion. Cheers, Florent [Pro] Prototype pattern http://en.wikipedia.org/wiki/Prototype_pattern [GOF] Design Patterns: Elements of Reusable Object-Oriented Software. E. Gamma; R. Helm; R. Johnson; J. Vlissides (1994). Addison-Wesley. ISBN 0-201-63361-2. -- To post to this group, send an email to sage-devel@googlegroups.com To unsubscribe from this group, send an email to sage-devel+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/sage-devel URL: http://www.sagemath.org