
Axel Simon wrote:
Yes, I expected that. But perhaps we can create a (rather flat) object hierarchy which maps onto all backends.
If you say "object hierarchy", do you mean a set of types with upcast and downcast functions? Or are you referring to type classes? As to "rather flat", I'd say yes, I think that's what we have to do.
This was my proposal: http://haskell.org/pipermail/gui/2003-April/000459.html
OK so you're talking about upcast & downcast functions (as class members). At least that's how I would try to describe your approach. The question where to put the actual functions remains open. I think upcast and downcast functions become ugly as soon as the hierarchy doesn't match the underlying backend. What "upcasted" generic types do we need anyway? As I said, we need a data Pane = .... class PaneClass p where toPane :: p -> Pane fromPane :: Pane -> Maybe p ... at least in order to be able to implement dynamic layout in Haskell (for platforms that don't have it). I'm using the term Pane to mean any widget that can be placed inside a window; that is widgets minus windows and menu items. Do we need any other upcast/downcast functionality? Does anyone want to have a list of _any kind_ of widget, mixing windows and buttons and layout containers etc? Does anyone want to have a list of any kind of buttons, that may contain both push buttons and toggle buttons, but no edit text fields and labels? If the answer is no, then let's not include any more upcast/downcast functions, at least not in CGA 1.0, because they will never be conveniently implementable on all platforms at the same time. We could then just have classes that contain some functionality, and some plain functions where a certain functionality is only available at one widget. The next question we need to ask is, which widget type supports what functionality? I'd say we should only use single-function HasFoo classes where necessary; I prefer having logical groups of functionality, like "Container"; but I don't have a strong opinion on this issue. On the other hand, one-function-per-class-style is harder to screw up --- it will probably take a few tries until we have figured out what functionality we can group together in classes. Perhaps we should do a rough design first (which would have classes like HasOnActivate along with classes like Container), and then, when everything is basically there, go over it again and reorganize some classes. Below I've attached what I'm currently thinking of... could we have another quick "yes"/"no, because" vote and/or some counter-proposals? Cheers, Wolfgang ================== cut here ================== import Attributes -- from the CGA example (indirectly from HToolkit) data Pane = .... class PaneClass p where toPane :: p -> Pane fromPane :: Pane -> Maybe p -- plus any functions and attributes that are supported by all kinds of panes -- and not supported by any window or other object instance PaneClass Pane where toPane = id fromPane = Just -- ... class Container c where -- ... class HasOnActivate a where doOnActivate :: a -> IO () -> IO( IO() ) data Button = ... instance PaneClass Button where -- ... mkButton :: Container c => c -> [Prop Button] -> IO Button instance HasOnActivate Button where doOnActivate = ... data TextEntry = ... instance PaneClass TextEntry where -- ... mkTextEntry :: Container c => c -> [Prop TextEntry] -> IO TextEntry data GridBox = ... instance PaneClass GridBox where -- ... instance Container GridBox where -- ... column :: PaneClass c => Attr (GridBox,c) Int row :: PaneClass c => Attr (GridBox,c) Int columnspan :: PaneClass c => Attr (GridBox,c) Int rowspan :: PaneClass c => Attr (GridBox,c) Int -- plus some more data Window = ... -- no PaneClass instance for Window instance Container Window