[GUI] Class/Object Hierarchy
Wolfgang Thaller
wolfgang.thaller@gmx.net
Sat, 3 May 2003 21:40:05 +0200
I'll try to summarize the discussion about how to arrange the
class/object hierarchy, admittedly with some bias towards my own
opinions. I'd just like to confirm if we really have agreed on what I
think we've agreed [like many people, I have a tendency to think that
everyone agrees with my opinions unless I hear a clear "no" :-) ].
So what have we already agreed on?
1) There will be a datatype Window
2) There will be a datatype Pane
3) ... along with a class IsPane (or PaneClass or ...)
class IsPane p where
toPane :: p -> Pane
4) There will be a class Container
class Container c where
-- member functions to be determined
And we'll have
4a) instance Container Window
4b) instance Container GridBox
Open Issue/Disadvantage of this solution:
What type would a "getContainer" function have? Can we have such a
function at all?
What are the alternatives to a class Container?
5) For a particular widget type Foo, we will have
5a) data Foo
5b) instance IsPane Foo
5c) newFoo :: Container c => c -> [Prop Foo] -> IO Foo
6) GridBox is a layout container that works like Gtk's Table, Java's
GridBagLayout and Tk's grid.
It should be implemented using Gtk's Table for Gtk, and implemented in
Haskell for other platforms.
We have
6a) instance IsPane GridBox
6b) instance Container GridBox
6c) Layout constraints can be set using attributes:
column :: IsPane p => Attr (GridBox, p) Int
(and more attributes as required for a grid layout algorithm)
Example:
box <- newGridBox container [columns =: 2, rows =: 2]
button <- newButton box [...]
set (box,button) [column =: 1, row =: 1]
7) Below the "Pane" type and class, we'll try to keep the hierarchy
flat (perhaps even absolutely flat), so that we don't have any problems
with mismatches between the interface and backend implementations.
===
Undecided issues:
8) Will there be a datatype for a general Widget (in addition to the
datatype for a general Pane (Point 2)) ?
data Widget
along with
class IsWidget w where
toWidget :: w -> Widget
Pros:
*] Common features of Windows and Panes can be implemented very
conveniently on platforms where both Windows and Panes are represented
by a "Widget" object.
*] Having both getWindowSize and getPaneSize seems unnatural; having
getSize in a type class sounds nice, but might require that all Pane
types explicitly instantiate that class, always with the same
implementation, for example:
instance HasSize Button where
getSize b = getSize (toPane b)
Cons:
*] Not all platforms have that common representations; implementations
on other platforms would have to use a discriminated union type and
lots of case expressions, for example:
getSize w = case toWidget w of
WindowWidget win -> getWindowSize win
PaneWidget pane -> getPaneSize pane
*] The only common feature of Windows and Panes that I can think of is
size and position on screen.
*] The Parent/Child relationship is not such a common feature, as there
are no cross-platform parent/child relationships between toplevel
windows. Also, one widget being contained in another widget is not the
same thing as one window being a child of another window (the latter
has nothing to do with containment, except with MDI).
*] There's no reason to need a general list of widgets, where Panes and
Windows can be freely mixed.
9) Do we prefer to use a) too many type classes, i.e. a
HasFoo class even when there's only one widget that supports foo,
or do we rather want to risk having b) too few type classes, i.e.
making foo a plain function when we may later add another widget that
supports the exact same foo?
I think the performance costs of type classes are absolutely
negligible, but what about namespace polution and readability of error
messages?
So that's all for now, feel free to add your own points. - I'd also
like to know what other people think I've agreed to, when in fact I
haven't :-).
Cheers,
Wolfgang