version 0.3.1
[PyX/mjg.git] / design / arg.tex
blob9d2027339d369cd3519d8fb6fd00f76e6403846c
1 % $Header$
3 \documentclass{article}
4 \usepackage{pyx}
5 \begin{document}
6 \section*{Design rules for variable argument lists and dictionaries
7 of functions in \PyX}
9 In order to get an easy user interface, we should restrict ourselfs to
10 some well defined ways of handling function calls with variable
11 argument lists and dictionaries. This file tries to consider the
12 typical occurrences within \PyX{} and provides standard solutions for
13 them.
15 We describe two different kind of function calls with variable
16 argument lists and dictionaries. They are called
17 ``\verb|arglist|-functions and arguments'' and
18 ``\verb|argdict|-functions and arguments''. The distinction between
19 these two cases is given by the way the arguments are passed to the
20 function. In the following we will try to make out the difference in
21 the subject of the functions and arguments already.
23 Combinations of \verb|arglist|- and \verb|argdict|-type of arguments
24 should be avoided (although they are possible). The discussion here is
25 not restricted to standard function calls, but applies to class
26 methods and constructors as well.
28 \subsection*{\texttt{arglist}-type functions and arguments}
30 Somehow, this first case is the more specific to \PyX{} necessities than
31 the second one. Let's first consider an example:
32 \begin{verbatim}
33 class A:
34 def __str__(self):
35 return "<a>"
37 class B:
38 def __str__(self):
39 return "<b>"
41 def show(self, *args):
42 for arg in args:
43 print arg
45 show(A(), B())
46 \end{verbatim}
48 Although this is a rather trivial example, you can see, that the
49 arguments are collected in a list. This list is used to perform the
50 action ``show'' on its entries. The entries supply the needed
51 techniques to get showed -- thus \verb|show| itself doesn't need to
52 know any details about it.
54 A main feature is, that the classes \verb|A| and \verb|B| could have
55 some properties. Consider the following:
56 \begin{verbatim}
57 class A:
58 def __init__(self, color):
59 self.color = color
60 def __str__(self):
61 return "<a color=\"%s\">" % self.color
62 \end{verbatim}
64 Instead of the previous call \verb|show(A(), B())| we now have
65 to specify the color, e.g.
66 \verb|show(A("red"), B())|.\footnote{The constructor of class
67 \texttt{A} could have a default value for \texttt{color} (like
68 \texttt{color = "black"}), so that this default value could just be
69 omitted. You may keep this in mind, because it is a rather typical
70 construction. However, it is not used here, because it might raise
71 some confusion, because such default values belong to the
72 \texttt{argdict}-type of functions and arguments.}
74 To go further, we do modify the print routine in order to print some
75 text within the \verb|<...>|-tags. Suppose, the \verb|<...>|-tags can
76 be closed by \verb|</>| uniformly, then we could do:
77 \begin{verbatim}
78 def show(self, text, *args):
79 for arg in args:
80 print arg
81 print text
82 for arg in args:
83 print "</>"
84 \end{verbatim}
86 Here we have introduced a standard parameter \verb|text|, which leads
87 to an example call like \verb|show("text", A("red"), B())|. The
88 instances of class \verb|A| and \verb|B| become a property of
89 \verb|text|.
91 By this construction you can do even more, actually.
92 Consider the following:
93 \begin{verbatim}
94 show(A("red"))
95 show("text1")
96 show("text2")
97 \end{verbatim}
99 Here, the same class previously used as an property for a single
100 call of \verb|show| becomes now an automatically chosen attribute for
101 all following calls of \verb|show|.\footnote{We should ensure, that
102 calls like \textbf{show(A("red"), B())} don't work at all. In the case
103 of PostScript it need to be considered anyway, because the first
104 parameter usually provides PostScript as well as a bounding box
105 information unless we do a property change as first and only
106 parameter.} When this flavor of the property arguments is undesirable
107 its use should just be prohibited.\footnote{like for the \TeX/\LaTeX{}
108 interface ???}
110 You may miss the correct handling of the closing tags \verb|</>| in
111 the last example, but that's a question about the output needed.
112 Indeed, for PostScript, this is not an issue.
114 To summarize the description above, typical design features of
115 \verb|arglist|-type functions and arguments are:
116 \begin{itemize}
117 \item[$+$]
118 properties can just implement what they want --- the evaluation by
119 function calls makes it most flexible
120 \item[$+$]
121 property implementations are small and well separated
122 \item[$+$]
123 properties can have additional functionality --- they may are
124 comparable, incrementable, etc.
125 \item[$+$]
126 organization of properties can be done within a class tree
127 \item[$-$]
128 classes are needed construct all the different properties which leads
129 to a bloat up in the namespaces
130 \end{itemize}
132 \subsection*{\texttt{argdict}-type functions and arguments}
134 Consider a class \verb|axis| used to handle axes of a graphs. Its
135 constructor might be defined as:
136 \begin{verbatim}
137 class axis:
138 def __init__(self, min = None, max = None):
139 self.min = min
140 self.max = max
141 \end{verbatim}
143 There are two predefined arguments, \verb|min| and \verb|max|. The
144 user could just create an axis without passing values to these
145 parameters, which would lead to the usage of the predefined
146 values.\footnote{In this example the value \texttt{None} could mean,
147 that minimal and maximal values are unknown and should be
148 automatically estimated.}
150 We now derive this class in order to implement a new feature, namely
151 an axis title. This would look like:
152 \begin{verbatim}
153 class titleaxis(axis):
154 def __init__(self, min = None, max = None, title = ""):
155 axis.__init__(self, min = min, max = max)
156 self.title = title
157 \end{verbatim}
159 That would do, but its ugly. Of course, we can easily change the
160 default values for min and max -- but hence we have always to recode
161 the default values. What happens, if somebody enhances the class
162 \verb|axis| later? Yes, we wouldn't be able to access those additional
163 parameters without modifying titleaxis too.
165 The solution would look like the following:
166 \begin{verbatim}
167 class axis:
168 def __init__(self, min = None, max = None):
169 self.min = min
170 self.max = max
172 class titleaxis(axis):
173 def __init__(self, title = "", **args):
174 axis.__init__(self, **args)
175 self.title = title
176 \end{verbatim}
178 It is intrinsic, that we do not see all parameters we can handle to
179 the constructor of \verb|titleaxis| at its definition. As far as
180 discussed up to this point, this seems to be the perfect solution. And
181 for \PyX we shouldn't go along the line discussed in the following.
182 Anyhow, I want to describe it here to make the clear statement of
183 avoiding sophisticated excesses, although they may look fascinating.
184 I will point out the problems arising by them.
186 A first idea you could think about is multiple inheritance. Lets
187 assume, there is the same class \verb|axis| like before. Additionally,
188 there might be a class \verb|title| handling titles for arbitrary
189 objects:
191 \begin{verbatim}
192 class title:
193 def __init__(self, title = ""):
194 self.title = title
195 \end{verbatim}
197 A combination of those classes is a bad idea, because again you have
198 to know about the parameters and it's defaults, if you do:
199 \begin{verbatim}
200 class titleaxis(axis, title):
201 def __init__(self, min = None, max = None, title = ""):
202 axis.__init__(self, min = min, max = max)
203 title.__init__(self, title)
204 \end{verbatim}
206 There is another way, which is exactly a solution, I claim we should
207 avoid. The idea is to append a dictionary for additional parameters at
208 the base classes. The code would then look like:
210 \begin{verbatim}
211 class axis:
212 def __init__(self, min = None, max = None, **args):
213 self.min = min
214 self.max = max
216 class title:
217 def __init__(self, title = "", **args):
218 self.title = title
220 class titleaxis(axis, title):
221 def __init__(self, **args):
222 axis.__init__(self, **args)
223 title.__init__(self, **args)
224 \end{verbatim}
226 There are two things causing trouble here. First, we have to be sure
227 to have dictionaries for additional parameters at all base classes.
228 Secondly, and that's much more crucial, we do not get errors any more,
229 if we pass parameters which are not handled by any of the base
230 constructors we call. While we wanted to avoid knowing all parameters,
231 we're in troubles here. We could inspect the constructors we call
232 (using the inspect module) and find out if a parameter is never used,
233 but we shouldn't do that.
235 Another application is a parameter, which provides some solution for a
236 special task. Consider the non-trivial task of an automatic axis
237 partitioning, where there are different algorithms to provide it.
238 While it is wanted to keep this algorithm apart from other axis stuff,
239 the question arises, how to insert such an algorithm into an axis
240 class. Using a special routine, the user has to call in order to
241 insert an automatic axis partitioning is bad, because it would mean, the
242 user always has to call it (although some automatic default could be
243 implemented). Another option, multiple inheritance, leads to some
244 constrains as discussed before. It would also mean, the user can't
245 modify the default by just implementing another automatic axis
246 partitioning class, but additionally a new axis class derivation would
247 be needed. Naturally, an automatic axis partitioning would be just an
248 parameter of the constructor of the axis. It would look like:
249 \begin{verbatim}
250 class genpart:
251 def __init__(self, opt = 5):
252 self.opt = opt
254 class axis:
255 def __init__(self, min = None, max = None, part = genpart(opt = 10)):
256 self.min = min
257 self.max = max
258 self.part = part
259 \end{verbatim}
261 And actually, this should be the solution of choice. Similar to the
262 idea already discussed above, we could thought of a mechanism of
263 making the parameter \verb|opt| of the constructor of \verb|genpart|
264 directly available as a parameter of the constructor of \verb|axis|.
265 Instead of writing something like \verb|axis(part = genpart(opt = 15))|
266 we could desire a syntax \verb|axis(opt = 15)|. While it is
267 again a charming idea, it finally would generate a lot of trouble.
269 To summarize the description above, typical design features of
270 \verb|argdict|-type functions and arguments are:
271 \begin{itemize}
272 \item[$+$]straight forward implementation of ``to be set'' parameters
273 with default values
274 \item[$-$]should not be combined with an tailing dictionary parameter
275 (e.g. \verb|**args| at the end of the argument list)
276 \item[$-$]multiple inheritance should allow only one parent with an
277 \verb|argdict|-type constructor
278 \item[$-$]modification of parameters of default values (e.g. class
279 instances) are a little bulky
280 \end{itemize}
282 \section*{Comments}
284 \begin{itemize}
285 \item In my opinion, it is still not entirely clear, how we
286 distinguish the use of \verb|arglist| and \verb|argdict| type
287 parameters. Specifically, I think that a combination of both may in
288 some cases be desirable. Consider for instance in the \verb|axis|
289 example the case, where one wants to specify additionally the font
290 size of the title. Would this not justify the use of an
291 \verb|arglist| type argument?
292 \item Probably the distinction is already clear, if one draws the line
293 between graphical properties (color, line/text style/width, etc.)
294 and other things. But where exactly then do fit in transformations,
295 clipping, arrows, \dots?
296 \item Maybe we should make \verb|arglist| type arguments the special
297 case of \verb|argdict| arguments, namely \'a la
298 \begin{verbatim}
299 class main:
300 def show(self, style=(), *args):
301 for arg in args + tuple(style):
302 print arg
304 \end{verbatim}
305 We could even think of something like the following:
306 \begin{verbatim}
307 class main:
308 def show(self, style=(), trafo=(), *args):
309 for arg in args + tuple(style) + tuple(trafo):
310 print arg
312 \end{verbatim}
313 or maybe better
314 \begin{verbatim}
315 class main:
316 def show(self, style=(), trafo=(), *args):
317 for t in select_args(args, trafo, trafo.trafo):
318 print t
320 \end{verbatim}
321 where \verb|select_arg(args, inst, _class)| is a helper routine, which
322 selects all instances of the class \verb|_class| out of the lists
323 \verb|args| and \verb|inst|, where in the latter one only instances of
324 \verb|_class| are allowed. Maybe, we could also convert \verb|args| in
325 advance to a list which can the modified in place by
326 \verb|select_args|, and all found instances of \verb|_class| can be deleted.
328 \end{itemize}
330 \end{document}