On 1/16/07, Chris MacRaild <c.a.macraild@xxxxxxxxxxx> wrote:
On Mon, 2007-01-15 at 17:44 +1100, Edward d'Auvergne wrote:
[snip]
> > Some asides
> >
> > A. I believe the runs that are passed around in relax are strings
> > which are then used to lookup data in a map. Why not just have
> > (runs/pipes) as objects... Then for example the call
> >
> > self.relax.data[self.relax.run]
> >
> > above becomes
> >
> > self.relax.run.data a much more object orientated and encapsulated
> structure
>
> You still need a list (array) or dictionary (hash) type structure to
> store multiple run objects. 'self.relax.data' would be a dictionary
> type object with key-value pairs, the key being the run name and the
> value being a standard class instance object containing all the data
> associated with the run as objects. The dictionary would be more
> logical than an array in this case.
>
The issue here is whether the user and/or developer should be dealing
with a run name (a string) or the run object itself. Currently the user
creates a new run with:
run.create(run_name, run_type)
and then uses the string, run_name, to address the object. In this
idiom, a dictionary of runs is clearly an appropriate structure.
Alternatively, we could have the user create a run with:
my_run = run.create(run_type)
Then the user has the run as an object, which they can make current or
pass to relax commands as required. In this idiom, a dictionary of runs
is an unnecessary abstraction.
You have mentioned the run object idea before, although I can't find
your post on the subject.
Currently, the relax interface is entirely script orientated, not object
orientated, so the alternative above is a fairly fundamental change in
interface design.
I don't favour an object orientated user interface, because oo tends to
be fairly intimdating to non-programmers. On the other hand, the relax
code-base could benefit from being more object orientated. So I propose
the following arrangement:
I have thought of your idea quite a bit, but am of the same opinion as
that stated in your above paragraph. The idea of having the run
objects as things that the user has at their fingertips to manipulate,
pass to functions, etc is quite powerful. However it does add
significant complexity to the prompt/script UI. I can clearly see the
idea embedded in a GUI design though whereby the data pipe (previously
called a run) is represented as a physical object (either in 2D or 3D)
which can be manipulated and the user functions applied to.
all runs are stored in a dictionary, keyed by run name, but only the
run-selection machinery should access this dictionary. The current run
should be the object self.relax.data.run (or something simiar), and all
relax functions should operate on that object.
I agree, however I would extend this using the global variable ideas
Gary proposed (https://mail.gna.org/public/relax-devel/2007-01/msg00013.html,
Message-id: <f001463a0701071314i61276e67hde685fe3afb8fe42@xxxxxxxxxxxxxx>).
So instead of using 'self.relax.data.run' the data container of the
current run, which is located in the dictionary type object
'self.relax.data[]', could be aliased as say 'data_pipe' or
'current_pipe' and placed into '__builtin__'. Then any part of relax
can access the data of the current data pipe by referring directly to
'current_pipe'. Maybe a better variable name would be 'cdp' (current
data pipe)? Or maybe simply 'data'?
In addition, I don't believe the name 'run' encapsulates the concept
at all. This name is a relic which is not at all related to its
current use (https://mail.gna.org/public/relax-devel/2006-10/msg00056.html,
Message-id: <1160555137.9523.70.camel@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx>).
The current use of the name 'run' encapsulates the segregation of the
data. This is why I prefer the words 'data pipe' or 'pipe' over
'run'.
Thus we would have user functions:
run.create(run_name, run_type):
self.relax._runs[run_name] = new_run(run_type)
The 'new_run' would be an empty data container (a class instance) and
the data pipe type would be a simple string variable inside this
container. Hence:
pipe.create(pipe_name, pipe_type):
self.relax.data[pipe_name] = PipeContainer(pipe_type)
run.make_current(run_name):
self.relax.data.run = self.relax._runs[run_name]
I see the word 'switch' is a little more direct than 'make_current',
although there may be even better alternatives. What do you think
Chris?
pipe.switch(pipe_name):
__builtin__.current_pipe = self.relax.data[pipe_name]
run.current():
return self.relax.data.run.name
pipe.current():
return current_pipe.name
Having the name stored in the dictionary as a key and in the data pipe
container as the 'name' variable is a little redundant. Maybe the
current pipe name should be stored as say 'self.relax.current_pipe'?
run.run_names():
return self.relax._runs.keys()
pipe.display():
print "%20s%20s" % ('Data pipe name', 'Data pipe type')
for key in self.relax.data:
print "%20s%20s" % (key, self.relax.data[key].pipe_type)
run.delete(run_name):
if run.current() == run_name:
self.relax.data.run = None
del self.relax._runs[run_name]
pipe.delete(pipe_name):
if self.relax.current_pipe == pipe_name:
__builtin__.data = None
del self.relax.data[pipe_name]
run.delete_all():
self.relax.data.run = None
self.relax._runs = {}
pipe.delete_all():
__builtin__.current_pipe = None
self.relax.data = PipeDictionary()
The point of 'PipeDictionary()' rather than {} is because many of the
objects in 'self.relax.data' are special. They have their
'__repr__()' methods modified so that when you type the object name at
the prompt, you get a formatted printout rather than something like:
<__main__.Data instance at 0xb764732c>
This way the abstraction of the dictionary of runs is cleanly hidden
from the developer who chooses to work with objects, but the scripting
style of the user interface is maintained.
Don't forget that the dictionary type 'self.relax.data' is an object,
as are the values corresponding to its keys - the data pipe
containers. In Python, essentially everything is an object.
Edward