Java Forum / General / March 2007
Some help wanted in class design -- Immutability
Hendrik Maryns - 28 Feb 2007 17:32 GMT Hi folks,
I’d appreciate some input on a design problem I’m having trouble with.
I have a class CompactFunction, which is basically an implementation of an MDD (Multi-Valued Decision Diagram), a generalisation of a BDD (http://en.wikipedia.org/wiki/Binary_decision_diagram). This is expanded to model non-determinism, with a whole bunch of methods that make it suitable for modelling the transition function of a tree automaton.
The class Automaton models, guess what, an automaton. It is immutable. (I like immutability, it helps keeping an overview.) Since it contains a function, which can be asked for, CompactFunction should be immutable too.
OTOH, I want to be able to create this function step-by-step, adding transitions one after the other. This is needed for some manipulations (determinisation, minimisation), and to offer a way to create initial functions in the first place. Until now, I had a CompactFunctionBuilder for this. It builds a decision tree from the transitions it gets, and reduces that tree when getFunction() is invoked.
However, my preliminary implementation of reduction has an error, which makes a reduction of the function that has been built necessary. The problem is the following: no function builder is used here, since transitions are not computed one by one, but based on the graph structure of MDD. However, reduction is implemented in the builder.
This leads me to think I should get rid of the builder class and put the reduction logic in the function itself. But then I would have to allow adding single transitions too, which would loose the immutability of the CompactFunction class.
And here’s my query, for anyone so kind to read this far: what would be the right way to go here? - - implement the reduction in CompactFunction too (sort of duplicating most of the work of the builder), and keeping the builder - - make CompactFunction mutable, providing some sort of protection if one asks for an automaton’s function (mind that an MDD is a graph, so copying is complicated and expensive), getting rid of the builder - - other suggestions?
I’d be happy to clarify if things are too vague.
Thanks, H. - -- Hendrik Maryns http://tcl.sfs.uni-tuebingen.de/~hendrik/ ================== http://aouw.org Ask smart questions, get good answers: http://www.catb.org/~esr/faqs/smart-questions.html
Hendrik Maryns - 01 Mar 2007 11:26 GMT Hendrik Maryns schreef:
> Hi folks, > [quoted text clipped - 38 lines] > > I’d be happy to clarify if things are too vague. Well, doesn’t really surprise me that I got no answer here (yet), but after thinking about it for a while, I decided to go the same way I do with Sets: declare an interface that allows some methods to throw an UnsupportedOperationException, and create a class ImmutableFunction, then let my compact function be mutable, implementing the interface, but wrap it in the immutable Automaton class.
Getting to work now...
Comments still welcome, though. H. - -- Hendrik Maryns http://tcl.sfs.uni-tuebingen.de/~hendrik/ ================== http://aouw.org Ask smart questions, get good answers: http://www.catb.org/~esr/faqs/smart-questions.html
Hendrik Maryns - 01 Mar 2007 15:20 GMT Hendrik Maryns schreef:
> Hendrik Maryns schreef: >> Hi folks, [quoted text clipped - 48 lines] > > Getting to work now... And in doing this, still another solution is emerging: have Automaton use an interface, which does not include the muting methods. Since it returns its function as an instance of this interface, the muting methods will still not be available. They will, if somebody casts it down to a specific implementation, but I think I will take that risk, in favour of cleaner design and one level less of nesting.
Comments still welcome, though. H. - -- Hendrik Maryns http://tcl.sfs.uni-tuebingen.de/~hendrik/ ================== http://aouw.org Ask smart questions, get good answers: http://www.catb.org/~esr/faqs/smart-questions.html
Lew - 01 Mar 2007 18:21 GMT > And in doing this, still another solution is emerging: have Automaton > use an interface, which does not include the muting methods. Since it > returns its function as an instance of this interface, the muting > methods will still not be available. They will, if somebody casts it > down to a specific implementation, ... Not if the immutable version is a subclass of the mutable version, and overrides the mutators. Also not if the immutable version is a copy of the mutable one or a wrapper for one that delegates to the mutable class's accessors.
- Lew
Hendrik Maryns - 02 Mar 2007 10:47 GMT Lew schreef:
>> And in doing this, still another solution is emerging: have Automaton >> use an interface, which does not include the muting methods. Since it [quoted text clipped - 6 lines] > the mutable one or a wrapper for one that delegates to the mutable > class's accessors. Hm, yes, I had a wrapper initially, but thought I could do without if I offer people only the interface, which does not have the mutators. That is not safe for casting. But I probably will change the design once more, after reading Chris’s post.
As for subclassing: I try to use that only where it is really necessary, in this case a decorator would do as well.
Thanks, H. - -- Hendrik Maryns http://tcl.sfs.uni-tuebingen.de/~hendrik/ ================== http://aouw.org Ask smart questions, get good answers: http://www.catb.org/~esr/faqs/smart-questions.html
Chris Uppal - 01 Mar 2007 17:31 GMT > However, my preliminary implementation of reduction has an error, which > makes a reduction of the function that has been built necessary. The > problem is the following: no function builder is used here, since > transitions are not computed one by one, but based on the graph > structure of MDD. However, reduction is implemented in the builder. I may be misunderstanding you, but if you are considering changing your architecture because of a bug in your own code, then I strongly urge you not to. Fix the bug !
You have (what sounds like) a nice, clean, understandable architecture; with well-defined roles for all the objects. The only good reason for changing that design is if this problem is showing you that the design isn't as good as it sounds (the roles are badly assigned, for instance).
I would say that the way each object has a clear role to perform is more important (quite a lot more important) than any consideratations of mutability. So make the design right, /then/ consider which objects, if any, can be made logically immutable. Only /then/ consider what implementation tricks and techniques you can use to implement that immutability (and make sure that whatever tricks you choose don't warp your initial design).
Still, if you are finding that your original design was wrong in that the Builder should never have had responsibility for reducing the tree, then you can change the design. Maybe the Builder's only responsibility is to know how to build the initial tree (before any reduction, etc). If so then its role is reduced, but still coherent. But maybe now it's name is a little misleading -- it could be seen as more of a /description/ of a tree (a specification for the tree in some logical space, distinct from the messy optimised version which will finally be used when the automaton executes).
(BTW, I'm currently facing similar kinds of design problems in a related space: runtime specifications of grammars, and derivations of parsers for those grammars. I'm having trouble working out which of the Grammar, the Parser, the GrammarBuilder (if I decide to add these), or the caller of the code, should be responsible for ensuring that whatever modifications to the Grammar (potentially of several sorts) are made in order to ensure that the Parser (also of several sorts) is able to implement the grammar....)
-- chris
Hendrik Maryns - 02 Mar 2007 10:45 GMT Chris Uppal schreef:
>> However, my preliminary implementation of reduction has an error, which >> makes a reduction of the function that has been built necessary. The [quoted text clipped - 5 lines] > architecture because of a bug in your own code, then I strongly urge you not > to. Fix the bug ! Hm, almost too late by now, I’ve been jamming into it already, and reverting would be as big a pain as going on, I’m afraid.
> You have (what sounds like) a nice, clean, understandable architecture; with > well-defined roles for all the objects. The only good reason for changing that > design is if this problem is showing you that the design isn't as good as it > sounds (the roles are badly assigned, for instance). Makes sense. Only: how to decide this last point? I think the bug (and new insights) suggest the design wasn’t that good (it was a temporary implementation for testing originally), but it is difficult to draw the line here.
> I would say that the way each object has a clear role to perform is more > important (quite a lot more important) than any consideratations of mutability. > So make the design right, /then/ consider which objects, if any, can be made > logically immutable. Only /then/ consider what implementation tricks and > techniques you can use to implement that immutability (and make sure that > whatever tricks you choose don't warp your initial design). Makes sense again. Maybe now I am confusing roles in that I make a function responsible for building itself.
> Still, if you are finding that your original design was wrong in that the > Builder should never have had responsibility for reducing the tree, then you [quoted text clipped - 4 lines] > tree in some logical space, distinct from the messy optimised version which > will finally be used when the automaton executes). Sounds good. Maybe I can move only the reduce() method into the function, but make it package accessible, such that the builder has access to it if it is finished, and the function can use it itself.
> (BTW, I'm currently facing similar kinds of design problems in a related space: > runtime specifications of grammars, and derivations of parsers for those [quoted text clipped - 3 lines] > (potentially of several sorts) are made in order to ensure that the Parser > (also of several sorts) is able to implement the grammar....) Yes, that sounds very similar.
Thank you very much, your comments are very useful to show me some more angles to look at the problem.
H. - -- Hendrik Maryns http://tcl.sfs.uni-tuebingen.de/~hendrik/ ================== http://aouw.org Ask smart questions, get good answers: http://www.catb.org/~esr/faqs/smart-questions.html
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|