caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* Polymorphic class types?
@ 2005-10-21 20:44 Matt Gushee
  2005-10-22  1:51 ` [Caml-list] " skaller
  2005-10-22  1:59 ` Jacques Garrigue
  0 siblings, 2 replies; 5+ messages in thread
From: Matt Gushee @ 2005-10-21 20:44 UTC (permalink / raw)
  To: caml-list

Hello, all--

I am trying to design a high-level GUI library in object-oriented OCaml.
 It will be based on LablTk, but that's not really relevant--right now
I'm just trying to work out skeleton classes; the current code doesn't
even import LablTk yet.

Anyway, the concept I'm trying to implement is a notecard metaphor,
where the user will interact with information through a number of cards,
which can be iconified, deiconified, moved around, etc[*]. Cards should
also be able to display arbitrary data types--in practice I think the
data will mostly be key-value structures where the values are mostly
strings, but I don't want to limit it to that.

So you are probably starting to get a sense of the problem: I need a
basic framework of display logic that is independent of the application
data, for positioning cards on the canvas, handling events, etc. But I
also need to be able to get and set the content of cards in response to
GUI events--the content being some arbitrary data structure, as
mentioned above.

So I have been trying to work with parameterized class type like this:

  class type ['a] card = object
    method id : string
    method place : int -> int -> unit
    method show : ?expanded:bool -> unit -> unit
    method hide : unit -> unit
    method expand : unit -> unit
    method collapse : int -> int -> unit
    method content : (string * 'a) list
    method title : string
  end

  class type ['a] cp_canvas = object
    method base : Widget.canvas Widget.widget
    method cards : 'a card list
    method get_card : string -> 'a card
    method add_card : 'a card -> unit
    method show : selection -> unit
    method hide : selection -> unit
    method expand : selection -> unit
    method collapse : selection -> unit
  end

But I don't think it's going to work. The sticking point is that there
need to be various subtypes of cards, each with appropriate display
logic for its content type, yet the canvas needs to be able to manage
cards in a generic manner--i.e. it needs to work with the 'card'
type--but of course that type doesn't exist, because 'card' takes a
parameter, right?

I won't go into detail here about the problems I've been having--I
suspect the design is wrong, but I have no clear idea of how to do it
right. I know my library could use an abstract 'data' type, which could
then be implemented in an application as, for example,

  type data =
    | I of int
    | F of float
    | S of string
    ...

... but I'd rather not if it can be helped. And I don't care very much
if it's object-oriented ... I started this several months ago and put it
aside for a while, so I don't remember what exactly I was thinking, but
probably the main point of using objects was to make it easy to add new
card types.

So, I would appreciate suggestions.


[*] Am I reinventing HyperCard? Could be ...

--
Matt Gushee
Englewood, CO, USA



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Caml-list] Polymorphic class types?
  2005-10-21 20:44 Polymorphic class types? Matt Gushee
@ 2005-10-22  1:51 ` skaller
  2005-10-22  5:53   ` Matt Gushee
  2005-10-22  1:59 ` Jacques Garrigue
  1 sibling, 1 reply; 5+ messages in thread
From: skaller @ 2005-10-22  1:51 UTC (permalink / raw)
  To: Matt Gushee; +Cc: caml-list

On Fri, 2005-10-21 at 14:44 -0600, Matt Gushee wrote:

> So you are probably starting to get a sense of the problem: I need a
> basic framework of display logic that is independent of the application
> data, for positioning cards on the canvas, handling events, etc. But I
> also need to be able to get and set the content of cards in response to
> GUI events--the content being some arbitrary data structure, as
> mentioned above.

Basic abstraction. The cards are abstractions, they have no content.
Make that work first for placement, iconisation, etc. 

Display the content as 'whiteness' or something.

Derive a new class which has content. The algorithms for
display management will not know about it. That is right.

The best way to derive a new class is to make one which
just delegates to another object, to allow you to 
move content around easily, and also avoid confusion
about what parts of the object type really do need
to be coupled with the subclass (and try to minimise that).

I recommend you consider organising the 'cards' in a tree.
So you can iconify whole groups of them. Etc. I have a design
for that called Hierarchical Window Manager, allows you to
manipluate sets of things easily -- eg move a set of top
level window contents into a tabbed notebook (with a single
drag and drop operation). I've implemented it twice (once in
Itcl and once in Python).

You statement: 

"need to be various subtypes of cards, 
each with appropriate display
logic for its content type"

is wrong. on the contrary! The display manager MUST NOT
know anything about the content. All you really need is
a single 'render' method with a 'surface' argument,
so the display manager can tell the underlying object
when to render itself and where. [ok, you may need size
and 'skin' and a couple of other things too]

BTW: the idea of using a 'polymorphic' class where the
data type is a type parameter is wrong (in Ocaml).
You need to use OO style subtyping here.

The reason is -- you cannot generalise your display
manager to work over a heterogenous collection which is
what you would get with many distinct instances of
the polymorphic class.

-- 
John Skaller <skaller at users dot sf dot net>
Felix, successor to C++: http://felix.sf.net


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Caml-list] Polymorphic class types?
  2005-10-21 20:44 Polymorphic class types? Matt Gushee
  2005-10-22  1:51 ` [Caml-list] " skaller
@ 2005-10-22  1:59 ` Jacques Garrigue
  1 sibling, 0 replies; 5+ messages in thread
From: Jacques Garrigue @ 2005-10-22  1:59 UTC (permalink / raw)
  To: matt; +Cc: caml-list

From: Matt Gushee <matt@gushee.net>

> So you are probably starting to get a sense of the problem: I need a
> basic framework of display logic that is independent of the application
> data, for positioning cards on the canvas, handling events, etc. But I
> also need to be able to get and set the content of cards in response to
> GUI events--the content being some arbitrary data structure, as
> mentioned above.

The trouble with your approach (that I leave below) is that you do not
distinguish between the programmer's view of the card and the canvas
view of the card. Clearly the canvas does not need to know what is in
the card, just how to show it.

So you have a type

class type card = object
  method id : string
  method place : int -> int -> unit
  method show : ?expanded:bool -> unit -> unit
  method hide : unit -> unit
  method expand : unit -> unit
  method collapse : int -> int -> unit
  method title : string
end

(everything but contents)

and another type

class type ['a] data_card = object
  inherit card
  method content : (string * 'a) list
end

which real cards will implement.

Then you canvas does not need a type parameter:

class type cp_canvas = object
  ...
  method cards : card list
  method get_card : string -> card
  method add_card : card -> unit
  ...
end

Now you will say: but when I use get_card I won't be able to get to
the real card anymore.
Sure, but that's not really a problem. Actually, in my experience I
would never use get_card anyway. If I have a way to connect events to
card, then I will define one handler for each card (or card family),
that will internally know the type of the exact card, so everything
works ok.

Lablgtk basically works that way: you add widgets to the GUI
structure, but you never try to extract information about them
afterwards.
One exception if for widgets the toolkit created for you internally,
for which you don't have enough information. But if you're designing
the toolkit this should not happen...

A smaller technical point: you are going to have to coerce your cards
to the type card. This can be done through (mycard :> card), but in
practice type inference is slow for that, and you don't want to see
the error message when it fails.
The approach in Lablgtk is to define a concrete class card, which
would include a coercing method
class virtual card = object (self)
   ...
   method as_card = (self :> card)
end
This way you just have to call the method to coerce any subclass to
the required type.

Jacques Garrigue

> So I have been trying to work with parameterized class type like this:
> 
>   class type ['a] card = object
>     method id : string
>     method place : int -> int -> unit
>     method show : ?expanded:bool -> unit -> unit
>     method hide : unit -> unit
>     method expand : unit -> unit
>     method collapse : int -> int -> unit
>     method content : (string * 'a) list
>     method title : string
>   end
> 
>   class type ['a] cp_canvas = object
>     method base : Widget.canvas Widget.widget
>     method cards : 'a card list
>     method get_card : string -> 'a card
>     method add_card : 'a card -> unit
>     method show : selection -> unit
>     method hide : selection -> unit
>     method expand : selection -> unit
>     method collapse : selection -> unit
>   end
> 
> But I don't think it's going to work. The sticking point is that there
> need to be various subtypes of cards, each with appropriate display
> logic for its content type, yet the canvas needs to be able to manage
> cards in a generic manner--i.e. it needs to work with the 'card'
> type--but of course that type doesn't exist, because 'card' takes a
> parameter, right?


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Caml-list] Polymorphic class types?
  2005-10-22  1:51 ` [Caml-list] " skaller
@ 2005-10-22  5:53   ` Matt Gushee
  2005-10-22  8:52     ` skaller
  0 siblings, 1 reply; 5+ messages in thread
From: Matt Gushee @ 2005-10-22  5:53 UTC (permalink / raw)
  To: caml-list

Thanks to John and Jacques for the thoughtful responses.

skaller wrote:

> I recommend you consider organising the 'cards' in a tree.
> So you can iconify whole groups of them. Etc. I have a design
> for that called Hierarchical Window Manager, allows you to
> manipluate sets of things easily -- eg move a set of top
> level window contents into a tabbed notebook (with a single
> drag and drop operation). I've implemented it twice (once in
> Itcl and once in Python).

Interesting. I'm not sure a hierarchical model would apply here--the
basic data model I'm trying to support is a graph rather than a tree.
Think "visual RDF editor" ... though I'm not trying to tie this thing
directly to RDF per se, it's conceptually pretty close. But I'd still be
interested in how you did that. Is your Python code available somewhere?

> You statement: 
> 
> "need to be various subtypes of cards, 
> each with appropriate display
> logic for its content type"
> 
> is wrong. on the contrary! The display manager MUST NOT
> know anything about the content. All you really need is
> a single 'render' method with a 'surface' argument,

Maybe I didn't make myself clear. To rephrase myself more explicitly,
"there need to be various subtypes of cards, each with appropriate
display logic for its content type *embedded within itself*." Or if you
understood that was what I meant, I don't see why you think it's wrong.
Isn't this a textbook case of encapsulation?

> BTW: the idea of using a 'polymorphic' class where the
> data type is a type parameter is wrong (in Ocaml).
> You need to use OO style subtyping here.

I thought that's what I was doing. Not well, obviously, hence my inquiry
to the list. If you have time, I'd like to hear more about this ... what
exactly do you mean by OO style subtyping? I've heard "subtyping is not
inheritance" about a thousand times ... but there's not much
documentation on how to do it right in OCaml, and unfortunately I don't
have enough theoretical background to figure it out on my own.


Jacques Garrigue wrote:

> The trouble with your approach (that I leave below) is that you do not
> distinguish between the programmer's view of the card and the canvas
> view of the card. Clearly the canvas does not need to know what is in
> the card, just how to show it.

Yes, actually I understood that. I didn't intend to create an ['a]
canvas type, but since the canvas needed to know about cards and I had
created the ['a] card type ...

> class type card = object
> [ .... ]

> and another type
>
> class type ['a] data_card = object
>   inherit card

Aha! Inheritance in class types ... I wasn't aware that you could do
that (actually I think I may have done it once a couple of years ago,
but if I did I must have forgotten about it).

> Now you will say: but when I use get_card I won't be able to get to
> the real card anymore.

No, I won't say that ;-) Actually I think I was pretty close to that
solution, just couldn't quite see it.

> A smaller technical point: you are going to have to coerce your cards
> to the type card. This can be done through (mycard :> card), but in
> practice type inference is slow for that, and you don't want to see
> the error message when it fails.

Oh, yeah. I've seen quite a few of those error messages, and would be
happy never to see another.

> class virtual card = object (self)
>    ...
>    method as_card = (self :> card)

Yes, I've done this before. Wow, I actually had the right idea about how
to do something with OCaml objects?

--
Matt Gushee
Englewood, CO, USA


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Caml-list] Polymorphic class types?
  2005-10-22  5:53   ` Matt Gushee
@ 2005-10-22  8:52     ` skaller
  0 siblings, 0 replies; 5+ messages in thread
From: skaller @ 2005-10-22  8:52 UTC (permalink / raw)
  To: Matt Gushee; +Cc: caml-list

On Fri, 2005-10-21 at 23:53 -0600, Matt Gushee wrote:

> Interesting. I'm not sure a hierarchical model would apply here--the
> basic data model I'm trying to support is a graph rather than a tree.
> Think "visual RDF editor" ... though I'm not trying to tie this thing
> directly to RDF per se, it's conceptually pretty close. But I'd still be
> interested in how you did that. Is your Python code available somewhere?

No sorry. The reason for a tree is that this is the model
of containment. Notebooks contain windows .. vertically paned
windows contain windows .. the Screen contains top level windows..
a network has many screens (I used to have two monitors, I could move
things from one to the other with drag-n-drop).

The containment relation uses a Tree widget instead of a linear
'toolbar'. Allows the user to group and regroup the 'card'
content in interesting ways.

> > is wrong. on the contrary! The display manager MUST NOT
> > know anything about the content. All you really need is
> > a single 'render' method with a 'surface' argument,
> 
> Maybe I didn't make myself clear. 

I think you did -- in any case Jacques Garrigue actually factored
your model by removing the contents, I think what he did is
correct.

[oo subtypes]

> I thought that's what I was doing.

In some language of Barry Jay, you can actually do that:
the parameter to a class is how you extend it, using
open recursion. It's very nice -- if you instantiate the parameter
to 'ground' the class becomes closed like with Java 'final'.

>  Not well, obviously, hence my inquiry
> to the list. If you have time, I'd like to hear more about this ... what
> exactly do you mean by OO style subtyping? I've heard "subtyping is not
> inheritance" about a thousand times ... but there's not much
> documentation on how to do it right in OCaml, and unfortunately I don't
> have enough theoretical background to figure it out on my own.

In Ocaml a class D is a subtype of B if D has 'at least all
the methods of B'.  Inheritance may be convenient way to make
this happen but it isn't essential.

It's clear why this works: the interfaces are the same for B and
D if you 'ignore some of the methods of D'. So any algorithm
that works for a B will work for a D.

[This isn't quite right as I'm sure someone will point out,
but it is a good first approximation :]

> > class type card = object
> > [ .... ]
> 
> > and another type
> >
> > class type ['a] data_card = object
> >   inherit card
> 
> Aha! Inheritance in class types ... I wasn't aware that you could do
> that (actually I think I may have done it once a couple of years ago,
> but if I did I must have forgotten about it).

It isn't inheritance.. its just a macro that pastes in
the inherited signature (more or less :) Saves writing,
nothing more.

-- 
John Skaller <skaller at users dot sf dot net>
Felix, successor to C++: http://felix.sf.net


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2005-10-22  8:53 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-10-21 20:44 Polymorphic class types? Matt Gushee
2005-10-22  1:51 ` [Caml-list] " skaller
2005-10-22  5:53   ` Matt Gushee
2005-10-22  8:52     ` skaller
2005-10-22  1:59 ` Jacques Garrigue

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).