To: garrigue at kurims.kyoto-u.ac.jp Cc: lablgtk at kaba.or.jp Subject: Re: reusing button class In-Reply-To: <20010105115319P.garrigue at kurims.kyoto-u.ac.jp> References: <20010104162842A.wakita at is.titech.ac.jp> <20010105115319P.garrigue@kurims.kyoto-u.ac.jp> Mime-Version: 1.0 Content-Type: Text/Plain; charset=us-ascii Content-Transfer-Encoding: 7bit Message-Id: <20010105141009H.wakita at is.titech.ac.jp> Date: Fri, 05 Jan 2001 14:10:09 +0900 From: Ken Wakita Lines: 152 Thank you. I guess what you favor is object composition or delegation to inheritance. I agree that delegation is more flexible and sometimes better for design reuse of the source code. But your code can be polished by delegating [connect] and [event] message to the [button] object and remove somewhat misterious code fragments. class image_button ~file ?(label = "") ?border_width ?width ?height ?packing ?show () = let button = GButton.button ?border_width ?width ?height ?packing ?show () in let box = GPack.vbox ~packing: button#add () in let pm = GMisc.pixmap (GDraw.pixmap_from_xpm ~window: box ~file ()) ~packing: box#pack () in let label = GMisc.label ~text: label ~packing: box#pack () in object inherit GObj.widget button#as_widget method connect = button#connect method event = button#event method button = button method pm = pm method label = label end class image_button : file:string -> ?label:string -> ?border_width:int -> ?width:int -> ?height:int -> ?packing:(GObj.widget -> unit) -> ?show:bool -> unit -> object val obj : Gtk.widget Gtk.obj method as_widget : Gtk.widget Gtk.obj method button : GButton.button method coerce : GObj.widget method connect : GButton.button_signals method destroy : unit -> unit method drag : GObj.drag_ops method event : GObj.event_ops method get_id : int method label : GMisc.label method misc : GObj.misc_ops method pm : GMisc.pixmap end By the way, why do we have [connect] and [event] or why not clicked, grab_default, and others? The following is the list of methods [button] class inherits from its ancestors. gtkobj: destroy, get_id widget: as_widget, misc, drag, coerce container: add, remove, children, set_border_width, focus button_skel: clicked, grab_default button: connect, event Maybe it's not meaningful to reuse the methods from container as we have replaced the implementation of container but still we can wire and replace methods provided by the [container] class with the ones provided by vertical [box] object. By the way, one thing I miss for ocamlbrowser is ability to browse the class hierarcy. As the current implementation does not show the super class I am obliged to look into *.ml* files for investing class organization. Probably this is caused from ocaml not saving this information in the *.cmi. Ken In message (<20010105115319P.garrigue@kurims.kyoto-u.ac.jp>) from Jacques Garrigue , talking about "Re: reusing button class", on Fri, 05 Jan 2001 11:53:19 +0900 > From: Ken Wakita > > > I tried to define [image_button] class that contain an icon and an > > optional label. It was easy to implement a function that make a > > button with an icon. > > > > Then I tried to make a lablgtk style object-oriented class definition > > and I was in a trouble. Lablgtk style seems to require defining both > > the class and constructor function. However, initialization code by > > using low-level interface makes this difficult to do in a handy > > manner. So I pushed the iniitalization code in the initializer of the > > class definition and obtained attached below. > > > class button ?label ?border_width ?width ?height ?packing ?show () = > > let obj = GtkButton.Button.create ?label () in > > object (self) > > inherit GButton.button_skel (GtkButton.Button.coerce obj) > > method connect = new GButton.button_signals obj > > method event = new GObj.event_ops obj > > initializer > > GtkBase.Container.set obj ?border_width ?width ?height; > > ignore (GObj.pack_return self ?packing ?show) > > end > > Class and constructors are not distinguished so much for good style, > but rather for technical reasons. LablGTK classes are just wrappers to > raw GTK widgets, and they must have a constructor taking the raw widget > as argument, since you do not only wrap newly created widgets, but > also those returned by methods, or manually casted ones. > Then the problem is that ocaml objects have only one constructor. > So in the old beta1 version of lablGTK, there were actually two > classes for each widget: one acting just as a wrapper, called > [button_wrapper], and another one defined very much like you are doing > here, called [button]. However this meant a bit of gymnastic to hide > the [button_wrapper] type, and have [new button_wrapper w] return an > object of type [button]. Also this appeared to be a cause of code > bloat, which is not so nice when what you are doing is just > interfacing to the real library. > Still there was something nice about it: according to olabl optional > semantics, [new button] would return a button, without need to write > [new button ()] like with a function. But optional semantics changed > with ocaml 3, and I went back to a simpler approach, using a normal > function as constructor. > Another point was of course that you could inherit from the [button] > class more naturally, as you state here. However I have grown more and > more convinced than inheritance is generally not what you want. That > is, inheritance is not a way to organize a library (that should be > subtyping, at best), but just to throw around your code. > > So here is how I would write you image_button example in the new > lablgtk style. > class image_button ~file ?(label = "") > ?border_width ?width ?height ?packing ?show () = > let button = GButton.button ?border_width ?width ?height ?packing ?show () in > let box = GPack.vbox ~packing:button#add () in > let pm = GMisc.pixmap (GDraw.pixmap_from_xpm ~window: box ~file ()) > ~packing:box#add in > let label = GMisc.label ~text: label ~packing () in > object > inherit GButton.button (GtkButton.Button.cast button#as_widget) > method label = label > method pixmap = pm > end > > In this specific case, it is natural to inherit from button, but in > most cases I would even avoid it, and write > > class image_button ... = > ... > object > inherit GObj.widget button#coerce > method connect = new GButton.button_signals obj > method event = new GObj.event_ops obj > method button = button