On Feb 17, 2014, at 12:36 PM, Ian Ward <[email protected]> wrote:

>> I find AttrMap to be a very useful design concept. But I think it falls
>> short of its intended purpose because I find myself constantly needing to
>> insert .base_widget in various places -- AttrMap is not as transparent as the
>> docs suggest. A piece of urwid code will work but later break when you add
>> an extra AttrMap layer somewhere. Note that using AttrWrap instead makes the
>> example above work -- even though AttrWrap is deprecated in favor of AttrMap.
>> Several stock urwid examples also break if AttrWrap is replaced with
>> AttrMap, and it originally took me a few hours to figure out why.
> 
> I agree that it should be easier to work with decoration widgets. The
> best idea I have at the moment is to add a 'decorations' property or
> 'get_decorations()' method to widgets that will be called whenever
> that widget is added to a container or assigned to loop.widget. This
> way a widget class can define all its own decorations but still
> present just its methods and attributes to the programmer.
> 
> How does that approach sound to you?

I think it is necessary to make a design choice: are decorations Widgets in 
their own right or not (i.e. some properties of Widgets instead). The frame of 
mind I had been in when developing my app (which is where I think the docs lead 
you) was something like “AttrMap is a Widget that extends the Widget that it 
wraps, but it ‘overrides’ that Widget’s attribute mapping).  An "abbreviated" 
Composite pattern where AttrMap is a Widget and contains (just one, hence 
“abbreviated") another Widget. From this point of view, AttrMappingWidget or 
DecoratedWidget may be better names and it feels natural for it to “extend" the 
widget that it also wraps — then passing all methods and properties through 
makes sense and “.base_widget” is like “.super”.

An alternative design could be: don’t attempt to use a Composite pattern for 
decorations at all, because it would be a parallel Composite to the one that 
many are already used to: container Widgets. I.e. Columns is 
WidgetContainerMixin and it totally makes sense given how events like key 
strokes and mouse clicks are propagated. So, in this design choice we have a 
Decoration that is not a Widget and a Widget can contain multiple Decorations. 
But that raises more questions: if a Widget aggregates one or many Decorations, 
in which order are they applied? I am pretty sure that all possible answers 
here will only lead to a more confusing framework.

So, FWIW, I think it is best for a Decoration to accept a Widget as a 
constructor argument (i.e. to “wrap” it) but at the same time to be a Widget 
itself (which implies forwarding all methods/properties to the Widget being 
decorated by default). I.e. make the former choice above. I am not sure if this 
is the most pythonic choice, but it has been done with success before, see 
http://www.onjava.com/pub/a/onjava/2003/02/05/decorator.html The end users have 
two choices for extending and tweaking Widgets: by subclassing them or by 
wrapping them into Decorations (or Decorators). The former is a choice that 
affects all instances of the derived class and the latter decorates a single 
instance, so they are complementary.

As you can guess by now, I prefer the first choice. When you ask "If we pass 
through attribute access for just one decoration, why not do it for all 
decorations? If we do it for all decorations then users will be able to mostly 
pretend the decorations aren't there, but that could lead to some really hard 
to understand code” I answer “Yes” and “It’s a good thing that decorations can 
be transparent — it is compatible with them being Widgets”. When I write 
ChangeBackgroundColorDecorator(w) I find it natural not to know whether ‘w’ is 
a “primal” Widget or has already been decorated — it shouldn’t matter. The 
order of wrapping defines the order of decoration, so that’s all very natural, 
too. And this “pretending that the decorations aren’t there” is actually a good 
thing, as it will cause less coupling between various classes and more concern 
separation. Right now, every ‘.base_widget’ feels like a speedbump...

HTH,
Vlad     
_______________________________________________
Urwid mailing list
[email protected]
http://lists.excess.org/mailman/listinfo/urwid

Reply via email to