From: Duncan C. <dun...@wo...> - 2005-01-27 23:56:00
|
All, I've been talking to Einar Karttunen (author of hs-fltk) recently about our medium level API stuff. He uses a very similar style of attributes / properties to those used in wxHaskell. We've been discussing what set of setter/updater operators there should be and how to name them appropriately; particularly in relation to maintaining compatibility between libraries and minimising confusion for programmers moving between GUI libraries. For the unfamiliar, The basic idea is that an attribute is a getter and setter function for a value associated with an object. data Attr w a = Attr (w -> IO a) (w -> a -> IO ()) So for example we would have: -- the text attribute of a Label widget has type String labelText :: Attr Label String labelText = Attr labelGetText labelSetText Then the higher level interface is a pair of functions: get :: w -> Attr w a -> IO a set :: w -> [Prop w] -> IO () The get function is quite straight forward: get obj (Attr getter setter) = getter obj The set function is more complicated. It takes this list of properties. It's usage looks like: set myLabel2 [lineWrap := False ,justify := LeftJustify ,mnemonicWidget := button3 ,label :~ (\l -> l++ " blah")] So really it doesn't take a list of properties but a list of instructions for how to set or update attributes. In wxHaskell and hs-fltk there are two basic set/update operators: := -- ^ Assign a value to an attribute. :~ -- ^ Update the value of an attribute. So the first takes a new value for the attribute while the second takes a function which accept the existing value of the attribute and returns the new value it should be set to. Now, both wxHaskell and hs-fltk have extensions beyond these simple operators. wxHaskell has an extension: ::= -- ^ Assign a value to an attribute with the widget as argument. ::~ -- ^ Apply an update function to an attribute with the widget as an argument. Now Einar points out that this extension doesn't buy you much since the widget is always available in the context where you use the set function, the following are equivalent: foo widget value = ... set w [myAttr ::~ foo] vs set w [myAttr :~ foo w] He has another extension that he's put into hs-fltk which is to have IO variants of the two basic operators: :=> -- ^ Assign a value to an attribute, allowing IO. :~> -- ^ Update the value of an attribute, allowing IO. Now as I've presented them these operators all look ok however this glosses over the fact that these operators have actually been given different and incompatible names in wxHaskell and hs-fltk. This was the issue I particularly wanted to talk to Einar about. Since hs-fltk is still in the early stages of development I'm hopeful that he will change the operator names slightly so that his extension is not incompatible with the wxHaskell extension. My suggestion for gtk2hs would be to implement both extensions (as hs-fltk is also likely to do) since I am convinced that the IO extension is useful and the wxHaskell extension would help to attain a minimum level of compatibility. Since we cannot re-use the wxHaskell operator names for other purposes without horribly confusing users we lose nothing by implementing them with the same semantics as wxHaskell uses. So my suggestion is that we pick: data Prop w = forall a. Attr w a := a -- ^ Assign a value to an attribute. | forall a. Attr w a :=> (IO a) -- ^ Assign a value to an attribute, allowing IO. | forall a. Attr w a :~ (a -> a) -- ^ Update the value of an attribute. | forall a. Attr w a :~> (a -> IO a) -- ^ Update the value of an attribute, allowing IO. | forall a. Attr w a ::= (w -> a) -- ^ (for wxHaskell compatibility) Assign a value to an attribute with the widget as argument. | forall a. Attr w a ::~ (w -> a -> a) -- ^ (for wxHaskell compatibility) Apply an update function to an attribute with the widget as an argument. Note that there is no need to take things to their logical conclusion and add the operators (::=>) and (::~>). We only need the two :: variants for wxHaskell compatibility anyway. It reduces the number of somewhat confusing operators that we expose people too. Also as Einar points out the :: variants are non really necessary. As for library organisation, I suggest we add: System.Glib.Attribute System.Glib.Property The Attribute module would contain the (trivial) definition of the Attr data type and would be imported by just about every other module to allow them to define their object attributes. The Property module defines the get/set functions and the operators above. It does not need to be imported by any Gtk binding module. It can just be re-exported by Graphics.UI.Gtk. I have extended the code generator to gather the property definitions and documentation and it now produces stubs for each property. This email is already long enough so we can defer the discussion of how the code generator should implement these properties for later. BTW the tools/apiGen stuff is now much easier to use. It turns out that configuring and building gtk+ etc is not required and the Makefile automates the rest of it. I encourage people to try it out. Duncan |