[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