[comp.windows.x] Multiple Inheritance

mitch@edsvcs.osf.org (Mitch Trachtenberg) (12/28/90)

        Here are some thoughts on how it might be possible to
mix in some kinda-sorta multiple inheritance capabilities to Xt
using the object class, making a minimum of changes to Xt.
It may be blue-sky, and it's probably late for R5, but I welcome
reactions in any case.

        The existing Xt implementation is oriented towards
single inheritance.  Each new capability of a widget class is
implemented as a wraparound to the capabilities of the class'
superclass.  Physically, each subclass adds a new "part" structure
to the part structures which make up its superclass.  A reasonable
image for this class arrangement is a set of concentric circles,
or perhaps a linear set of blocks.

        Label adds capabilities to core; pushbutton to label;
enhanced pushbutton to pushbutton.  In order to implement two
separate and nonconflicting capabilities beyond those of pushbutton,
and be able to create instances with either or both of these capabilities,
it would be necessary to write three (2**2)-1 subclasses:

        Pushbutton
                PushbuttonPlusA
                PushbuttonPlusB
                        PushbuttonPlusBAndA

For three such capabilities, you would need seven (2**3)-1  subclasses,
and so on.

        It would be desirable to be able to mix-in functionality
to widget classes in a more flexible way; using classes like
"PushbuttonhelperA" and "PushbuttonhelperB" which could be mixed-in
to instances of pushbutton.  You could then have a base pushbutton
class and three helper classes, and create instances of pushbuttons
with any one, any two, or all three helpers.  A reasonable image
for this class arrangement is a keyring, with each capability
implemented as a new key on the ring.

        Full-fledged multiple inheritance would require (I guess)
a pretty substantial rewrite of Xt.  However, some of the capabilities
of multiple inheritance can be worked in, I believe, with minimal effort.

        The object class allows for the creation of non-widget
objects which can be used as widget subparts.  In their Xt book,
Asente and Swick show how use of objects can simplify the creation
of a graph widget: they move the actual display handling of the graph
into an object subpart.  The graph widget (or the application) then
becomes responsible for creating an appropriate instance of GraphDisplay
as a child of the Graph widget.  One GraphDisplay gives Bar Charts,
another line graphs, and so on.  The Graph has the resources required
for all graphs, the GraphDisplays implement resources for their
particular type of graph display.  Asente and Swick point out that
"there is no standard way for applications to interact with widgets
that use objects as subparts," and then lay out some alternative methods
which might be used for interaction.

        Let's imagine for a moment that in addition to XtSetValues
and XtGetValues, there were the additional calls XtTree[S|G]etValues.
These new calls would visit a widget and all its descendants,
[s|g]etting resource values in each instance.  Now let's imagine --
this one's a bit nastier -- that all widgets, not just composites, could
support a list of object children.  (Don't scream just yet about the
changes this would inevitably require.)  If these hypotheticals were
true, we could create a variety of "helper" object classes and string
them onto a given widget by creating, as children of the widget,
instances of the helper classes.  Values for the helper could be set
and retrieved by calling XtTree[S|G]etValues on the parent.  The
SetValues routine in the helper would in general respond to new
settings by operating on the helper's parent.  [The parent-child
relationship here is *not* serving the same purpose as that between
a widget and its parent. It might help to think of the "helper" objects
as dynamic additions to the instance structures of their parents.
It just happens that the helper links up with the helpee using parent-
child pointers as the connection mechanism.]

        In all likelihood, we don't get the ability to use helpers
across different parent classes; we can't use a pushbutton helper on
a list, for example.  We do, though, gain the advantage of needing
only n helper classes instead of 2**n subclasses to get the functionality
we want.

        It would probably require substantial additional work
to arrange for helpers to handle events.  Nonetheless, even without
this additional capability, the helper concept seems worthwhile.

        Here's a concrete example.

        Starting with a label widget, we want the following additional
capabilities:

        1) Use the resource XtNlanguage -- not found in basic labels --
        to switch the label's XtNstring between XtNenglishString,
        XtNfrenchString, and XtNitalianString.  None of
        these language-specific resources are in a basic label.

        2) Use the resource XtNflash -- not found in basic labels --
        to invert the label's foreground and background every
        XtNsecondsPerFlash.

        3) We want the label to accept an XtNinteger resource and
        build its string from that integer when the integer is set:
        123 ==> "123".  We'd also like the label to signal negative
        numbers by any means available.

        We create a label widget and give it "LanguageHelper," "FlashHelper,"
and "IntegerHelper" child objects.  We hold the "TunaHelper." (Oops, sorry.)

        Now, using XtTreeSetValues on the *label*, we are able to set
the *LanguageHelper's* XtNlanguage resource to "english," XtNenglishString
to "stop", XtNfrenchString to "arrete" (?) and so on.  When the
LanguageHelper's SetValues routine is called with a new XtNlanguage,
the helper's SetValues routine calls XtSetValues on the helper's parent,
installing the appropriate XtNxxxString as the parent's XtNstring.

        Using XtTreeSetValues on the *label*, we are able to set the
*FlashHelper's* XtNflash to True.  The helper's SetValues routine
registers a timer routine which, on expiration, swaps the parent's
foreground and background resources and reinstalls itself.

        Using XtTreeSetValues on the *label*, we are able to set the
*IntegerHelper's* XtNinteger to 123.  The helper's SetValues routine
does the integer to string conversion and calls XtSetValues on the parent's
XtNstring.  If the IntegerHelper's XtNsignalWhenNegative resource is true,
the IntegerHelper's SetValues routine checks for new negative values of
XtNinteger and, when found, calls XtTreeSetValues to set the parent's
XtNflash resource true.  (If there is no flash helper child of the label,
nothing happens. If the flash helper exists, it starts the label flashing.
This might be made more generic so that if any helper able to provide
signalling was found, it would be used.)

        ***

Info Flow Between Helper and Parent

        This information flow is all from XtTreeSetValues to helper
to parent.  If XtTreeSetValues were somehow able to pass the helper
copies of the old and new widget instances of the helper's parent,
the helper could also take action when the parent's resources were
changed.  This seems very nice, but even without this capability
helpers could still be of service.  My guess is this would not
require much major work, but I'm not at all sure.

        It would also be lovely to be able to solicit events for
(and route them to) helpers.  My guess is this would mean major
redesign work.

        ***

Where to Put the Helper List

        The nice clean way to implement helpers would be, I guess,
to add a helpers pointer to the core class.  I know, it ain't gonna happen.
One sleazy way is to take advantage of the popup_list field.  Popups
have to be subclasses of WindowObj, so you could count on any non-window-obj
popup items being a helper.  I haven't investigated it, but this
might allow the introduction of helper's without introducing backward's
compatibility problems.  There might be other locations which could be
used, as well.

        ***

Helpers vs. Constraint Records

        It seems to me that constraints are most naturally handled
as a particular style of helper, rather than through the constraint
special-casing which currently exists.  Whenever a widget is created
as a child of a constraint widget (say, of class Xyz), the constraint
parent's insert_child procedure would create an "XyzConstraintHelper"
object as a child of the newly created child.  XtTreeGetValues
could then be used by the parent to retrieve constraint settings
from a given child.  XtTreeSetValues could be used to set the
constraints.  From a resource file, setting a constraint resource
would look like this

        *xyz_parent.button1*constraintAttachment: CLING_RIGHT

instead of this

        *xyz_parent.button1.constraintAttachment: CLING_RIGHT.

        Implementing constraints via this mechanism would free up
the constraints pointer in core.  This might be another place to
stuff a pointer to the array of helpers (rename the "constraints" member
to "helpers"; the impact, I think, would be restricted to recoding the
way existing constraint widgets manage constraints.)
--
Mitch Trachtenberg                      Lewis, Trachtenberg & Associates (LTA)
mitch@lta.com                           +1 617 225 0366

marbru@attc.UUCP (Martin Brunecky) (01/03/91)

In article <MITCH.90Dec28094606@edsvcs.osf.org> mitch@edsvcs.osf.org (Mitch Trachtenberg) writes:
>
>        Here are some thoughts on how it might be possible to
>mix in some kinda-sorta multiple inheritance capabilities to Xt
>using the object class, making a minimum of changes to Xt.
>It may be blue-sky, and it's probably late for R5, but I welcome
>reactions in any case.
>

    Just some ideas/issues to contribute to the brainstorm.

    On the Set|GetTreeValues.
    =========================
    In my Text widgets, my SetValues(Hook inR3) propagates the arguments
    down to the "supporting objects" - in this case source and sink.
    So the SetValues on the "big guy" can (and does) SetValues on those
    "little guys". It can be even improved by filtering out arguments
    applicable to the "big guy" only....
    No additional Xt support needed.

    The only thing that's BAD about it is:
    - interaction with X resource database. The user must KNOW that the
      support object "xyz" will be created under the "bug guy" and that
      he must specify resources for "xyz" properly qualified.
    - XtGetResourceLists does not know anything about "supporting object",
      and thus can NOT retrieve any such resources.

    However. Is it relly so important to *hide* supporting objects ?
    One of the Motif's controversies is exacly around those "confusion
    functions" intended to *hide* objects (such as shells) from the
    user. Why not make the user AWARE of the fact that the PushButton
    is in fact a composite of A,B and C where B and C are automatically
    created by A (unless provided by the user as non-default resources).

    An example. Every Motif widget that (currently) has all those 3D outline
    resources could be substantially reduced (instance size) using *reference*
    to a (shared) "3DOutlineObject". Many applications will need a single one,
    some may need more. The application writer would have to know about
    such an object, even if it was automatically created by the Motif toolkit
    as a default one.



    Inheriting multiple geometry management.
    ========================================
    Composite widgets have lots of functionality, ONE of them being geometry
    management. I have found that it beneficial to SEPARATE the
    geometry management into a "support object". I.e. my composite widgets
    know about "GMbaseClass" and re-vector all the geometry related class
    methods to the instance-specific GM object's methods. (Note that the
    SetValues on the supporting object may have to inform the parent about
    some changes, so I use callbacks installed by the parent - but that's
    the case in any "support object").
    
    Similarly to the case above, the resources are the problem. And again,
    by knowing about my "GM support object", the application writer can
    adress this one directly.
 
-- 
=*= Opinions presented here are solely of my own and not those of Auto-trol =*=
Martin Brunecky                           {...}sunpeaks!auto-trol!marbru
(303) 252-2499                        (sometimes also:  marbru@auto-trol.COM )
Auto-trol Technology Corp. 12500 North Washington St., Denver, CO 80241-2404