Delivered-To: lablgtk at yquem.inria.fr DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=beta; h=domainkey-signature:received:received:received:date:to:subject:message-id:mail-followup-to:references:mime-version:content-type:content-disposition:content-transfer-encoding:in-reply-to:user-agent:from; bh=Y4+Y2fpkaElOK3ERyzg4eY6j6wwWUH1BMWmF2RbjZSI=; b=GdGddAUdDY/RS9eAee5+rBGZG8GPh76dc4lJnnbCsTn6juFvIBI761bnpuYcknzikDn4jJ2HehW9bHevWLCnmdi1i1mLqaLxD0VxRMfNVlii1w7fz8khGUqQBXmiwiFWZyOCYDRESbx4EobsJq4h8w9tWnJGUd8tMWviOWDe394= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=beta; h=received:date:to:subject:message-id:mail-followup-to:references:mime-version:content-type:content-disposition:content-transfer-encoding:in-reply-to:user-agent:from; b=qhEtqRfl6FUHheGeyU6FG9ccNCYV47ySCZq5v5xSVZSZcRJymAAZYM2WMfnJtjd3ryTMTZgdRbicZXb6ntS2VhUB0k0/A2C/vqvNGd3flQo9VW0sKu0YHBNMiIgN9DGn4uDH7R6tpQdYtSiiiP88/yuU97g+JeT5NtANsFutt+Y= Date: Wed, 31 Oct 2007 07:25:14 +0100 To: lablgtk at yquem.inria.fr Subject: Re: [Lablgtk] Re: Signals - how to inherit GObj.gobject_signals properly? Message-ID: <20071031062514.GA26132 at localhost> Mail-Followup-To: Julien Moutinho , lablgtk@yquem.inria.fr References: <20071030044841.GB29836 at localhost> MIME-Version: 1.0 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable In-Reply-To: From: Julien Moutinho Content-Type: text/plain; charset=utf-8 Content-Length: 11057 On Wed, Oct 31, 2007 at 02:10:15AM +0100, Dawid Toton wrote: > Thank you for looking at my code! (further questions below) > >>> One thing more I don't understand worries me: why it is legal to write >>> inherit [[> GtkPrintOperation_types.print_operation]]=20 >>> GObj.gobject_signals >>> >>> when "[[> GtkPrintOperation_types.print_operation]] GObj.gobject_signal= s"=20 >>> is sort of Gobject.obj->object and needs to be feeded with some obj to= =20 >>> become an OCaml object (that surely can be inherited). >>> Now it looks as if it inherits "Gobject.obj->object" function. >>> =20 >> It is only authorized in signatures where the types of the class'=20 >> arguments >> (a.k.a. implicit instance variables) are abstracted by the class'=20 >> parameters >> (i.e. the types before the class' name, those between '[' ']')). >> So if arguments' types are already abstrated (understand bound or known), >> no need to write them right. >> >> =20 > For me the class type is a tree of arrows and types. When I inherit/inclu= de=20 > such a type does a copiler look for the righmost leaf to find methods and= =20 > values of interest? Sorry for being that indecipherable, here is an example illustrating what I tried to say: module M =3D struct class ['a] c0 (a: 'a) =3D object method a =3D a end class c1 =3D object inherit [int] c0 42 end end Then you may write this: module Ok : sig class ['a] c0 : 'a -> object method a : 'a end class c1 : object inherit [int] c0 end end =3D M not that: module Ko : sig class ['a] c0 : 'a -> object method a : 'a end class c1 : object inherit [int] c0 : int (* <-- fancy addition here *) end end =3D M Again I am sorry if this wasn't your question. > According to what you've written the following declaration is incorrect: > > class print_settings : 'obj Gobject.obj -> object > constraint 'obj =3D [>GtkPrintOperation_types.print_settings] > inherit print_settings_skel (* this shouldn't be allowed - type of class= =20 > argument is not known *) > end > > becouse print_settings_skel has arguments that need to be bound. and it _has been_ completely bound at the definition of print_settings_skel: class print_settings_skel : 'obj Gobject.obj -> object ('self) constraint 'obj =3D GtkPrintOperation_types.print_settings ... If we would have written: class ['obj] print_settings_skel : 'obj Gobject.obj -> object ('self) constraint 'obj =3D [> GtkPrintOperation_types.print_settings ] ... Then print_settings would be something like that: class ['obj] print_settings : 'obj Gobject.obj -> object constraint 'obj =3D [>GtkPrintOperation_types.print_settings] inherit ['obj] print_settings_skel end >> Also, see the attached files, I have modified the classes so they are no >> longer recursive, which is ugly.=20 > Is it only matter of aesthetics? If so, I'd rather stay with recursive=20 > definitions, becouse: > * if the code is handwritten: > 1. need to imagine/draw a tree of dependency and do topological sorting f= or=20 > each change in the interface (that involves just defined classes) > 2. eventually (after some enhancements made to the API), when a cycle=20 > appears, one needs to change all "class" to "and" to make the definition= =20 > recursive > * when the code will be generated: need additional code that does this=20 > topological sorting (and need to expect cyclic graph case as well) with n= o=20 > practical benefit > > So it's easier and cheaper to have recursive definition from the beginnin= g.=20 > (Initially I favoured this choice, becouse this way it resembles the=20 > behaviour of popular OO languages.) I said it is "ugly" because when I want to understand a new code with a big set of recursive definitions, I do a lot of matches with my Vim to see what requires what, and this is quite a pain. This is why I prefer to avoid recursivity whenever possible. However I've made this remark principally because of a more subtle and tech= nical problem I'll try to explain below. >> Note also that *_skel take now a [closed polymorphic variant type]=20 >> Gobject.obj, >> this is due to *.copy which closes the p.v.t.. >> =20 > In my code GtkPrintOprtaionProps.PrintSettings.copy doesn't close the=20 > p.v.t.: > external copy : [>`printsettings] obj -> print_settings Gobject.obj opti= on I meant *.copy close the p.v.t. they _return_. Let me be a little bit prolix in order to show you why this implies that "*_skel take now a [closed polymorphic variant type] Gobject.obj" and why if we want to keep the p.v.t. open in the inheriting classes, the recursive scheme cannot be used (to my mind): # (* what we need *) module Gobject =3D struct type -'a obj end let printsettings_copy : [>`X] Gobject.obj -> [`X] Gobject.obj option =3D fun _ -> None let mapsome f =3D function | Some x -> Some (f x) | _ -> None (* a succinct skeleton class *) class ['obj] print_settings_skel (obj: 'obj) =3D object val obj =3D obj constraint 'obj =3D [> `X ] Gobject.obj method copy =3D (mapsome (fun obj -> {< obj =3D obj >}) (printsettings_copy obj)) end (* an inheriting class for which we _want_ an open p.v.t. *) class ['obj] print_settings (obj: 'obj) =3D object inherit ['obj] print_settings_skel obj end;; module Gobject : sig type -'a obj end val printsettings_copy : [> `X ] Gobject.obj -> [ `X ] Gobject.obj option = =3D val mapsome : ('a -> 'b) -> 'a option -> 'b option =3D class ['a] print_settings_skel : 'a -> object ('b) constraint 'a =3D [ `X ] Gobject.obj val obj : 'a method copy : 'b option end class ['a] print_settings : 'a -> object ('b) constraint 'a =3D [ `X ] Gobject.obj val obj : 'a method copy : 'b option end See in the the skeleton class, the p.v.t. has been closed by the type syste= m, (hence the 'a parameter is now useless but is still present, which is norma= l). Besides the p.v.t. in print_settings has been closed because of the 'obj al= ias, which is normal. Now redo it with an open p.v.t.: let printsettings_copy : [>`X] Gobject.obj -> [>`X] Gobject.obj option =3D fun _ -> None The p.v.t. is kept open (and the 'a parameter of both classes is required to abstract 'c): class ['a] print_settings_skel : 'a -> object ('b) constraint 'a =3D ([> `X ] as 'c) Gobject.obj val obj : 'a method copy : 'b option end class ['a] print_settings : 'a -> object ('b) constraint 'a =3D ([> `X ] as 'c) Gobject.obj val obj : 'a method copy : 'b option end A shorter example of what is happening could be: # let x : [ `X ] =3D `X;; val x : [ `X ] =3D `X # class ['a] c o =3D object (self) constraint 'a =3D [> `X ] method m (x: 'a) =3D () end;; class ['a] c : 'b -> object constraint 'a =3D [> `X ] method m : 'a -> unit= end # class ['a] c o =3D object (self) constraint 'a =3D [> `X ] method m (x: 'a) =3D () initializer self#m x end;; class ['a] c : 'b -> object constraint 'a =3D [ `X ] method m : 'a -> unit = end Note that I do not understand why the type system _has to_ close the p.v.t. in such situation... but it does. Anyway, having the p.v.t. closed at the *_skel level shouldn't be harmful since *_skel are only meant to be used by their respective *. And in order to keep the p.v.t. open for *, we just have to coerce (obj :> [`X] Gobject.obj): # let printsettings_copy : [>`X] Gobject.obj -> [`X] Gobject.obj option =3D fun _ -> None;; val printsettings_copy : [> `X ] Gobject.obj -> [ `X ] Gobject.obj option = =3D # class print_settings_skel (obj: 'obj) =3D object val obj =3D obj constraint 'obj =3D [ `X ] Gobject.obj method copy =3D (mapsome (fun obj -> {< obj =3D obj >}) (printsettings_copy obj)) end class ['obj] print_settings (obj: 'obj) =3D object inherit print_settings_skel (obj :> [`X] Gobject.obj) end;; class print_settings_skel : [ `X ] Gobject.obj -> object ('a) val obj : [ `X ] Gobject.obj method copy : 'a option end class ['a] print_settings : 'a -> object ('b) constraint 'a =3D ([> `X ] as 'c) Gobject.obj val obj : [ `X ] Gobject.obj method copy : 'b option end This is the solution I sent you yesterday. Now if you keep the recursive scheme, you'll nat=C3=BCrlich hit the same pr= oblem: class ['obj] print_settings_skel (obj: 'obj) =3D object constraint 'obj =3D [> `X ] Gobject.obj method copy =3D (mapsome (new print_settings) (printsettings_copy obj)) end and ['obj] print_settings (obj: 'obj) =3D object inherit ['obj] print_settings_skel (obj :> [`X] Gobject.obj) end;; class ['a] print_settings_skel : 'a -> object constraint 'a =3D [ `X ] Gobject.obj method copy : 'a print_settings option end and ['a] print_settings : 'a -> object constraint 'a =3D [ `X ] Gobject.obj method copy : 'a print_settings option end But this time, the coercion inside print_settings does not change anything. The p.v.t. Gobject.obj argument of the inheriting class has already been cl= osed inside the skeleton class... class ['obj] print_settings_skel (obj: 'obj) =3D object method private obj =3D obj constraint 'obj =3D [> `X ] Gobject.obj method copy =3D (mapsome (new print_settings) (printsettings_copy obj)) end and ['obj] print_settings (obj: 'obj) =3D object inherit ['obj] print_settings_skel (obj :> [`X] Gobject.obj) end;; class ['a] print_settings_skel : 'a -> object constraint 'a =3D [ `X ] Gobject.obj method copy : 'a print_settings option method private obj : 'a end and ['a] print_settings : 'a -> object constraint 'a =3D [ `X ] Gobject.obj method copy : 'a print_settings option method private obj : 'a end What we would need is to apply (new print_settings) on an open p.v.t. but unless we use a little bit of Obj.magic... I see no way. Voil=C3=A0, I hope that I have given you the keys to understand why the recursive scheme is an impasse, to my mind. > I can imagine it could be wrong if gtk_*_copy functions are not aware of= =20 > the actual type of the whole object, i.e. if it could cut away a part of= =20 > the object that belongs to a subclass. After a quick look at GTK docs I= =20 > suppose that *_copy functions are defined for final (not subject to=20 > inheritance) classes. Thus I think that=20 > GtkPrintOprtaionProps.PrintSettings.copy and similar don't need to close= =20 > the type. > If it's really necessary to close the variant type then I'd need to=20 > maintain the functions as having exceptional translation from C code. I think like you that the types of *.copy are right. Regards, Julien. PS: By the way, be aware that: # class c =3D object end and d =3D object inherit c end;; class c : object end and d : object end # class d =3D object inherit c end and c =3D object end;; The class c is not yet completely defined _______________________________________________ Lablgtk mailing list Lablgtk@yquem.inria.fr http://yquem.inria.fr/cgi-bin/mailman/listinfo/lablgtk