[GUI] Re: Know you backends

Peter Achten peter88@cs.kun.nl
Fri, 31 Jan 2003 16:13:36 +0100


--=====================_25259391==_.ALT
Content-Type: text/plain; charset="us-ascii"; format=flowed

At 14:32 30-1-03 +0100, Daan Leijen wrote:
>[..]
>However, it is not yet clear how that level should look like. We could take
>the ObjectIO interface as our layer but I would not recommend that.
>Note, this is not a critique on the ObjectIO library, I highly respect the 
>work
>of the Clean people, and Peter van Achten in particular. However, the Haskell
>ObjectIO interface should be heavily revised to fit better in the style of 
>Haskell.
>Right now, it is still influenced by the non-monadic uniqueness style of 
>Clean.
>For example, the generation of identifiers (openId) is quit unsafe. In the 
>Haskell
>tradition we would use a monadic bind to name widgets.  ie.
>
> >  w <- window []
>
>instead of
>
> >   w <- openId
> >   openWindow ... [ WindowId w, ...]
This issue has nothing to do with monads, but is rather a design decision 
how to identify GUI elements. One particular disadvantage of the
w <- window []

style is that GUI creation is an (opaque) action, rather than a first-class 
description of the GUI. Identification values become available only after 
creation of GUI elements, which is less convenient than knowing them 
beforehand. The only 'danger' is forgetting to associate the identification 
value with the window, but the same problem exists with the other style:
w <- window []          -- window identified by w
...
close w                 -- window identified by w destroyed
...
setTitle w "Hi there"   -- unbound

Also, if you do prefer the binding style, it is easily added to Object I/O:
window :: IO WindowID
window = do {
             w <- openId
             window [WindowId w]
             return w
          }

>Other things are the widget attributes that are specified using 
>constructors. A more Haskellish
>style
>would use function names instead of constructors (as to be able to 
>abstract from them) and use type
>classes for grouping them (as to prevent using illegal attributes on a 
>certain widget). i.e.
>
> >  w <- window [title =: "My window" ]
>
>instead of
>
> >   w <- openId
> >   openWindow ... [ WindowId w,  WindowTitle w...]

Window titles are mandatory in Object I/O, so the excerpt should read:
w <- openId
openWindow ... (Window "My window" [WindowId w])

The same argument applies here as above: data constructors are more 
'first-class' than functions because one can do pattern-matching on them. 
Also, it is more general, as the elegant TkGofer style is built easily on 
top of it. For Object I/O devotees, it could be done as follows (in Clean):
// The class that fixes the relation between widget and attribute:
class Atts gui att where
     addAtt :: (gui .ls .pst) (att *(.ls,.pst)) -> gui .ls .pst
     getAtt :: (gui .ls .pst)                   -> att *(.ls,.pst)

// 'Lift' current attribute data constructors to type constructors:
::  WindowViewSize st = WindowViewSize` Size
::  WindowHScroll  st = WindowHScroll`  ScrollFunction

/* Instantiate the proper relations (note that view size and scroll bar
    are proper Window attributes, but for Dialogs only view size is valid.
*/
instance Atts (Window c) WindowViewSize | Controls c where ...
instance Atts (Window c) WindowHScroll  | Controls c where ...
instance Atts (Dialog c) WindowViewSize | Controls c where ...

// Convenient shorthand for addAtt:
(<==) infixl :: (gui .ls .pst) (att *(.ls,.pst))
             -> gui .ls .pst | Atts gui att
(<==) w a = addAtt w a

// Now one can set size and scroll attribute for a window...
w  = Window "Hi there" NilLS []
      <== WindowViewSize` {w=100,h=200}
       <== WindowHScroll` (stdScrollFunction Horizontal 100)
// ...and *only* the size for a dialog...
d1 = Dialog "Hi there" NilLS [] <== WindowViewSize` {w=100,h=200}
// ...but setting scrollbar won't type check...
d2 = Dialog "Hi there" NilLS [] <== WindowHScroll`
                                       (stdScrollFunction Horizontal 100)

>This is basically what I am trying to do in the GIO library. However, even 
>than, there
>are still tons of other design decisions to make, I wonder whether 
>consensus can ever
>be reached.
>
>All the best,
>     Daan.

The above is not a critique on Port or GIO (honest!). I just wanted to 
explain part of the design reasons for Object I/O and show that it supports 
elegant ideas such as advocated by Daan.

Regards,
Peter

--=====================_25259391==_.ALT
Content-Type: text/html; charset="us-ascii"

<html>
At 14:32 30-1-03 +0100, Daan Leijen wrote:<br>
<blockquote type=cite cite>[..]<br>
However, it is not yet clear how that level should look like. We could
take<br>
the ObjectIO interface as our layer but I would not recommend that.<br>
Note, this is not a critique on the ObjectIO library, I highly respect
the work<br>
of the Clean people, and Peter van Achten in particular. However, the
Haskell<br>
ObjectIO interface should be heavily revised to fit better in the style
of Haskell.<br>
Right now, it is still influenced by the non-monadic uniqueness style of
Clean.<br>
For example, the generation of identifiers (openId) is quit unsafe. In
the Haskell<br>
tradition we would use a monadic bind to name widgets.&nbsp; ie.<br>
<br>
&gt;&nbsp; w &lt;- window []<br>
<br>
instead of<br>
<br>
&gt;&nbsp;&nbsp; w &lt;- openId<br>
&gt;&nbsp;&nbsp; openWindow ... [ WindowId w, ...]</blockquote>This issue
has nothing to do with monads, but is rather a design decision how to
identify GUI elements. One particular disadvantage of the <br>

<dl><tt>
<dd>w &lt;- window []<br>
<br>
</tt>
</dl>style is that GUI creation is an (opaque) action, rather than a
first-class description of the GUI. Identification values become
available only after creation of GUI elements, which is less convenient
than knowing them beforehand. The only 'danger' is forgetting to
associate the identification value with the window, but the same problem
exists with the other style:<br>

<dl><tt>
<dd>w &lt;- window []&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --
window identified by w
<dd>...
<dd>close
w&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-- window identified by w destroyed
<dd>...
<dd>setTitle w &quot;Hi there&quot;&nbsp;&nbsp; -- unbound<br>
<br>
</tt>
</dl>Also, if you do prefer the binding style, it is easily added to
Object I/O:<br>

<dl><tt>
<dd>window :: IO WindowID
<dd>window = do {
<dd>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; w
&lt;- openId
<dd>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
window [WindowId w]
<dd>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return w
<dd>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
<br>
</tt><blockquote type=cite cite>
</dl>Other things are the widget attributes that are specified using
constructors. A more Haskellish<br>
style<br>
would use function names instead of constructors (as to be able to
abstract from them) and use type<br>
classes for grouping them (as to prevent using illegal attributes on a
certain widget). i.e.<br>
<br>
&gt;&nbsp; w &lt;- window [title =: &quot;My window&quot; ]<br>
<br>
instead of<br>
<br>
&gt;&nbsp;&nbsp; w &lt;- openId<br>
&gt;&nbsp;&nbsp; openWindow ... [ WindowId w,&nbsp; WindowTitle
w...]</blockquote><br>
Window titles are mandatory in Object I/O, so the excerpt should
read:<br>

<dl><tt>
<dd>w &lt;- openId
<dd>openWindow ... (Window &quot;My window&quot; [WindowId w])<br>
<br>
</tt>
</dl>The same argument applies here as above: data constructors are more
'first-class' than functions because one can do pattern-matching on them.
Also, it is more general, as the elegant TkGofer style is built easily on
top of it. For Object I/O devotees, it could be done as follows (in
Clean):<br>

<dl><tt>
<dd>// The class that fixes the relation between widget and attribute:
<dd>class Atts gui att where
<dd>&nbsp;&nbsp;&nbsp; addAtt :: (gui .ls .pst) (att *(.ls,.pst)) -&gt;
gui .ls .pst
<dd>&nbsp;&nbsp;&nbsp; getAtt :: (gui .ls
.pst)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-&gt; att *(.ls,.pst)<br>
<br>

<dd>// 'Lift' current attribute data constructors to type constructors:
<dd>::&nbsp; WindowViewSize st = WindowViewSize` Size
<dd>::&nbsp; WindowHScroll&nbsp; st = WindowHScroll`&nbsp;
ScrollFunction<br>
<br>

<dd>/* Instantiate the proper relations (note that view size and scroll
bar
<dd>&nbsp;&nbsp; are proper Window attributes, but for Dialogs only view
size is valid.
<dd>*/
<dd>instance Atts (Window c) WindowViewSize | Controls c where ...
<dd>instance Atts (Window c) WindowHScroll&nbsp; | Controls c where ...
<dd>instance Atts (Dialog c) WindowViewSize | Controls c where ...<br>
<br>

<dd>// Convenient shorthand for addAtt:
<dd>(&lt;==) infixl :: (gui .ls .pst) (att *(.ls,.pst))
<dd>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
-&gt; gui .ls .pst | Atts gui att
<dd>(&lt;==) w a = addAtt w a<br>
<br>

<dd>// Now one can set size and scroll attribute for a window...
<dd>w&nbsp; = Window &quot;Hi there&quot; NilLS []
<dd>&nbsp;&nbsp;&nbsp;&nbsp;  &lt;== WindowViewSize` {w=100,h=200} 
<dd>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;== WindowHScroll`
(stdScrollFunction Horizontal 100)
<dd>// ...and *only* the size for a dialog...
<dd>d1 = Dialog &quot;Hi there&quot; NilLS [] &lt;== WindowViewSize`
{w=100,h=200}
<dd>// ...but setting scrollbar won't type check...
<dd>d2 = Dialog &quot;Hi there&quot; NilLS [] &lt;== WindowHScroll` 
<dd>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
(stdScrollFunction Horizontal 100)<br>
<br>
</tt><blockquote type=cite cite>
</dl>This is basically what I am trying to do in the GIO library.
However, even than, there<br>
are still tons of other design decisions to make, I wonder whether
consensus can ever<br>
be reached.<br>
<br>
All the best,<br>
&nbsp;&nbsp;&nbsp; Daan.</blockquote><br>
The above is not a critique on Port or GIO (honest!). I just wanted to
explain part of the design reasons for Object I/O and show that it
supports elegant ideas such as advocated by Daan.<br>
<br>
Regards,<br>
Peter<br>
</html>

--=====================_25259391==_.ALT--