Everything good about Python except GUI IDE?

Chris Angelico rosuav at gmail.com
Sun Feb 28 12:53:35 EST 2016


On Sun, Feb 28, 2016 at 11:50 PM, Steven D'Aprano <steve at pearwood.info> wrote:
> On Sun, 28 Feb 2016 07:44 pm, Chris Angelico wrote:
>
>> On Sun, Feb 28, 2016 at 5:34 PM, Steven D'Aprano <steve at pearwood.info>
>> wrote:
> [...]
>>> Drag-and-drop GUI builders have the same advantages over code as Python
>>> has over languages with distinct compile/execute steps: rapid
>>> development, prototyping, exploration and discovery. Of course, any
>>> decent modern builder won't limit you to literally drag-and-drop, but
>>> will offer functionality like duplicating elements, aligning them,
>>> magnetic guides, etc.
>>
>> Alright, but how do you go about doing, with a drag-and-drop builder,
>> all those things we're used to with code - composing new named actions
>> out of primitives, observing the changes to a program through source
>> control, unit testing (maybe), and code review?
>
> These are all good questions. Let's see if I can give good answers:
>
> (1) "composing new named actions" -- I'm not entirely sure what you mean. Do
> you mean new named *widgets*? A good builder app should give you the
> ability to Group widgets into a single element, this is functionality which
> has existed in vector-drawing programs since at least MacDraw in 1984 so it
> shouldn't be hard. This is composition, a fundamental, powerful and rich
> design pattern for making new widgets (classes) out of simpler parts. If
> objects have a name, now you can refer to CompositeMenuDateColourPicker by
> name. You can copy it, paste it, replicate it 30 times, whatever you like.

A good number of GUI builders do offer this functionality -
composition. (Even some of what we would call primitives are actually
composed of multiple widgets; a drop-down combo box is an entry field,
a button, and a possibly-hidden list box.) But there are other actions
than "put this widget here". For example, you could go and adjust some
widget's size or style, or reposition it according to some new rules
(hopefully most of your positioning rules can be codified, eg "use a
grid layout, put this in this cell", but a lot of the people who ask
for drag-and-drop GUI building are thinking in terms of "place this
right here", rather than using layout managers; and sometimes there
are rules that don't really fit the layout manager per se, or are
layered on top of the layout manager's rules). These kinds of actions
can be represented as functions and then applied everywhere, such that
you can change the precise appearance by editing that one function.
For example, I have a Dungeons & Dragons character sheet display, in
which there are large numbers of entry fields (editable), labels
(non-editable display, usually calculated from other fields), and less
commonly, drop-down lists and multi-line text fields. Call that four
primitives. Now, some of the fields need to be highlighted for the
human's attention ("this is the actual value you want to be reading,
most of the time"). Currently, I do this with a blue border around it
and its label. Okay, so I can no doubt create a "readme display"
widget that has the border (a GTK2 Frame) and two labels; and then a
"readme editable" with the border, one label, and one entry field.
That's already split it out into two options, where a parameterized
function could simply generate a border, a label, and *whatever object
it was given*. And what if I want to change the look of those readme
objects? What if, instead of surrounding them with a Frame, I want to
put a little icon to the right of them? With code, all I have to do is
change the definition of the function; it still takes a widget and
returns a widget, but now it returns (say) a horizontal box containing
a label, the provided widget, and the icon. With a GUI builder, how do
you redefine a function that isn't just simple composition?

This additional meta-level is one that is absent from a *lot* of
modern graphical environments. Look at spreadsheets - the classic
Lotus 1-2-3 model has stayed with us all through, with MS Excel, OO/LO
Calc, etc, etc generally following it. And that's fine; spreadsheets
do a lot of very good work for a lot of people. Now, suppose in cell
C2 you have this formula: "=A2+B2*.05". You can copy that down the
rest of the column, and C9 will say "=A9+B9*.05", and so on; that's
what spreadsheets do well. But once you've done that copy operation,
those cells lose all track of the fact that they got their formula
from C2. If you edit C2, you have to re-copy-down. That's not too hard
for a lot of people to remember, but what happens when that's
forgotten? In a spreadsheet with huge numbers of calculated cells, how
are you going to debug the "oops I forgot to re-copy that" problem?
There is nothing in the document itself that helps you; if you see
that C2 has "=A2+B2*.051" and that this pattern continues down as far
as C10 but no further, do you assume that someone was tinkering and
didn't edit all down the column (which is tedious), or do you assume
that it's intentional? (Of course, the tendency for spreadsheets to
lack comments is a separate issue.) There is one spreadsheet (that I
know of) that gives this extra meta-level: Mesa for OS/2. If you copy
down like that, the cells will say "SAME(C2)" instead of actually
copying anything. Then, if you change C2, it'll use that formula for
all the others.

Why is this a rare feature in spreadsheets? It's pretty obvious that
you can do this in code - you simply call that function. In anything
drag-and-drop, it has to be an explicitly provided feature.

> (2) "source control" -- the world is full of document types that aren't
> plain text source code, and people have found ways to manage collaborative
> editing and change management for them. Why don't we ask game developers
> how they manage changes to the non-code elements in their applications?
> Textures, icons, player avatars, sound effects, maps, etc. Surely you don't
> suggest that game developers edit their background images in a hex editor?

Yes, and while you're at it, ask the critical question: What happens
when two people make edits to the same object? Non-text source code is
fine as long as only one person at a time is ever editing. Source
control will happily track them. But merging is virtually impossible;
taking one base case and two modified files and producing a unified
result is hard for either a human or a machine, when the files are
non-text blobs.

My suspicion is that such game devs would have strict rules about
simultaneous editing of files. While that quite probably works fairly
well, it's a limitation that most of us would not accept in any code
project. Imagine if the Python bug tracker required you to send, not a
patch file, but the entire source file that has the edit you want. How
would you manage those sorts of edits?

> (3) "unit testing" -- I'm not sure that unit testing is what is needed for
> the GUI elements of your application. It's more like integration testing,
> to ensure that the entire application works together as a seamless whole.
> I'm not sure what the state of the art in GUI application integration
> testing is like. I suspect crap, judging by the state of the art in GUI
> applications.
>
> But whatever it is, it will surely operate the same regardless of whether
> you have built the application using code or a graphical builder.
>
> (The GUI framework itself may have some analogue to unit testing for the
> individual widgets, but that's not your responsibility as the user of the
> framework. It's not up to you to test that menus drop down when clicked,
> but it is your responsibility to check that the right menus exist and that
> they do what they are supposed to.)

Right. Testing the widgets isn't your responsibility, although testing
a composite widget might (imagine building a drop-down combo box out
of the three parts - you should be able to test that in isolation).
But I was stretching a bit here. Feel free to drop this one.

> (4) "code review" -- the usual way to review the graphical elements of a GUI
> app is to call somebody over, sit them down at the running application, and
> say "What do you think of this?". They will usually answer "that icon needs
> to be a bit more to the left, and can you make that button blue instead of
> green?".

That's if you review the entire app. I'm talking more about the
equivalent of sharing patches; "here, I changed this window, do you
accept my change or not?" is a hard question to ask if you can't see
exactly what changed. Closely related to the source control issue - if
you can make patches/diffs for one, you can do it for the other.

>> The only way I know of
>> to build a "function" in a DnD builder is to create a composite widget
>> (eg "horizontal box containing label and entry field"), which is
>> extremely useful, but limited - it's like saying that the only way to
>> reuse code is single-inheritance.
>
> A poor analogy. Composition is equivalent to multiple inheritance, except
> without any of the weaknesses of MI.

The analogy is of having a grossly-restricted form of code reuse as
your only form. Composition is one specific option, but that's not the
only thing you can do with code.

>> How would you create a higher-order
>> operation in a DnD builder? How would you write something that does
>> some sort of sweep over a set of widgets and does the same thing to
>> them?
>
> In Hypercard, if it was a once-off processing task, I would create a button,
> edit the button's script:
>
> on mouseUp:
>   -- my memory of HC syntax and functions is a bit rusty
>   -- this may not be correct
>   for btnNum in 1 to the number of buttons:
>     if btnNum is the number of me:
>       continue
>     end if
>     set the textsize of button btnNum to 9
>     set the textstyle of button btnNum to bold,italic
>     if the name of button btnNum starts with "Spam":
>       set the icon of button btnNum to SpamIcon
>     end if
>   end for
> end mouseUp
>
> then I would click on that button and run the script. Then, once I have
> satisfied myself that it has done what was needed, I'd delete the button.

This is like running a sed script over your code. That's still not the
same thing as higher-order code.

> If this was something that needed to run each time the application ran, I
> would put the script in some other layer of the application, say, in the
> card layer, in a named handler:
>
> on setBtnStyle:
>   for btnNum in 1 to the number of buttons:
>     set the textsize of button btnNum to 9
>     set the textstyle of button btnNum to bold,italic
>     if the name of button btnNum starts with "Spam":
>       set the icon of button btnNum to SpamIcon
>     end if
>   end for
> end setBtnStyle
>
>
> then call that handler on some event:
>
> on openCard:
>   setBtnStyle
> end openCard

I suppose that's a reasonable simulation of higher-order code. If it's
stuff you're happy to do at run time (ie it won't hurt that you can't
see it in the editor), this will work. It's still not as good IMO
though.

>> This doesn't have to be a dichotomy.
>
> I didn't say it did :-)

Good :)

ChrisA


More information about the Python-list mailing list