* strange behavior of the object type-checker @ 1999-09-09 16:34 Pierre Boulet 1999-09-09 19:43 ` Jerome Vouillon 0 siblings, 1 reply; 12+ messages in thread From: Pierre Boulet @ 1999-09-09 16:34 UTC (permalink / raw) To: caml-list dear ocamllers, I have finally decided to give a try to the object subsystem of ocaml and I have stumbled on something very strange (for me, at least). In the code I present below, after some parametric class creation, I try to execute some method of an object. Three *successive* tries give three *different* results: two different typing error messages and finally success. This code has been tested with ocaml 2.02 and the cvs version of yesterday (8 sept.), ocaml 2.02+3. They give the same result. My aim is to define a graph class which implements simple graph algorithms such as depth first scanning. Anyway, here is the code. class ['e] node g n0 = object (self) val mutable mark = true (* a boolean to handle cycles *) method mark = mark method set_mark = mark <- true method unset_mark = mark <- false val mutable edges = ([] : 'e list) (* outgoing edges *) method edges = edges method add_edge e = edges <- e::edges initializer g#add_node self (* registration into the graph *) val n = n0 (* dummy printing *) method n = n method draw = Printf.printf "node: %i\n" n method iter fn fe = (* depth first iteration *) if self#mark then begin fn self; self#unset_mark; List.iter (fun e -> e#iter fn fe) edges end end;; class ['n] edge g from_init towards_init = object (self) val mutable mark = true (* a boolean to handle cycles *) method mark = mark method set_mark = mark <- true method unset_mark = mark <- false val from = (from_init : 'n) val towards = (towards_init : 'n) method from = from method towards = towards initializer g#add_edge self (* registration into the graph *) initializer from#add_edge self (* registration into the from node *) method draw = (* dummy printing *) Printf.printf "edge: %i->%i\n" from#n towards#n method iter fn fe = (* depth first iteration *) if self#mark then begin fe self; self#unset_mark; towards#iter fn fe end end;; class ['n,'e] graph = object (self) val mutable nodes = ([] : 'n list) (* list of nodes *) method nodes = nodes val mutable start_node = (None : 'n option) method start_node = start_node method set_start_node n = start_node <- Some n method add_node n = nodes <- n::nodes; match nodes with | [n] -> self#set_start_node n | _ -> () val mutable edges = ([] : 'e list) (* list of edges *) method edges = edges method add_edge e = edges <- e::edges method set_marks = List.iter (fun n -> n#set_mark) nodes; List.iter (fun e -> e#set_mark) edges method iter (fn : 'n -> unit) (fe : 'e -> unit) = (* depth first iteration *) match start_node with | None -> failwith "set start node first" | Some n -> self#set_marks; (n#iter fn fe : unit) end;; let g = new graph;; g#iter (fun n -> n#draw) (fun e -> e#draw);; let n1 = new node g 1;; g#iter (fun n -> n#draw) (fun e -> e#draw);; (* until now, everything goes fine *) let e11 = new edge g n1 n1;; g#iter (fun n -> n#draw) (fun e -> e#draw);; (* returns: Characters 17-18: This expression has type 'a edge node as 'a It has no method draw *) g#iter (fun n -> n#draw) (fun e -> e#draw);; (* returns: Characters 0-1: This expression has type (('a edge as 'b) node as 'a, ('c node as 'd) edge as 'c) graph It has no method iter *) g#iter (fun n -> n#draw) (fun e -> e#draw);; (* returns as expected: node: 1 edge: 1->1 - : unit = () *) So what happens? It seems that adding an edge to the graph unsettles the type checker... any thought? -- Pierre. ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: strange behavior of the object type-checker 1999-09-09 16:34 strange behavior of the object type-checker Pierre Boulet @ 1999-09-09 19:43 ` Jerome Vouillon 1999-09-28 18:56 ` Can someone explain? skaller 0 siblings, 1 reply; 12+ messages in thread From: Jerome Vouillon @ 1999-09-09 19:43 UTC (permalink / raw) To: Pierre Boulet, caml-list On Thu, Sep 09, 1999 at 06:34:19PM +0200, Pierre Boulet wrote: > dear ocamllers, > > I have finally decided to give a try to the object subsystem of ocaml > and I have stumbled on something very strange (for me, at least). > > In the code I present below, after some parametric class creation, I > try to execute some method of an object. Three *successive* tries give > three *different* results: two different typing error messages and > finally success. This is due to a type checker bug. Here is a patch (the bug should also soon be corrected in cvs). -- Jérôme Index: typing/ctype.ml =================================================================== RCS file: /net/pauillac/caml/repository/csl/typing/ctype.ml,v retrieving revision 1.65 diff -u -u -r1.65 ctype.ml --- ctype.ml 1999/02/24 15:21:49 1.65 +++ ctype.ml 1999/09/09 19:35:33 @@ -1068,7 +1068,8 @@ let t1' = expand_head env t1 in let t2' = expand_head env t2 in (* Expansion may have changed the representative of the types... *) - let t1' = repr t1' and t2' = repr t2' in + let t1' = expand_head env t1' in + let t2' = expand_head env t2' in if t1' == t2' then () else let t1 = repr t1 and t2 = repr t2 in ^ permalink raw reply [flat|nested] 12+ messages in thread
* Can someone explain? 1999-09-09 19:43 ` Jerome Vouillon @ 1999-09-28 18:56 ` skaller 1999-10-04 8:23 ` Pierre Weis 0 siblings, 1 reply; 12+ messages in thread From: skaller @ 1999-09-28 18:56 UTC (permalink / raw) To: caml-list Is there a way to access a value of a class instance? If so, what is the syntax? If not, what is the purpose of allowing 'val' bindings in class declarations in module signatures? Similarly, what is the purpose of allowing 'virtual' methods in class types and class declarations in module signatures? I have a doubly linked list class, and concatenating two lists takes 100 times longer in ocaml using my code than pythons list concatenation function, which is written in C. My code isn't optimal (given the particular data structure I've chosen) because the concat function cannot get at values of the class. Excerpt given below. Any advice appreciated. (A high speed mutable list in the standard library would be even better :-) module DoublyLinkedList : BiDirectional = struct (* doubly linked list type *) type 't d_node = { mutable nxt: 't iterator; mutable prv: 't iterator; mutable data: 't } and 't iterator = Empty | Node of 't d_node let next x = match x with Empty -> Empty | Node n -> n.nxt let deref x = match x with Empty -> None | Node n -> Some n.data class ['t] dlist = object(self) val mutable first': 't iterator = Empty val mutable last': 't iterator = Empty val mutable size: int = 0 method private init node = last' <- node; first' <- node; size <- 1 method length = size (* STL style mutators *) method push_back (data':'t): unit = match last' with | Empty -> self#init (Node {nxt=Empty; prv=Empty; data=data'}) | Node fin -> let tmp = Node {nxt=Empty; prv=last'; data=data'} in fin.nxt <- tmp; last' <- tmp; size <- size + 1 method first = first' end let concat (x:'a dlist) (y:'a dlist) :'a dlist = let z = new dlist in let i = ref x#first in while deref !i <> None do match deref !i with | Some v -> z#push_back v; i := next !i | None -> assert false done; let j = ref y#first in while deref !j <> None do match deref !j with | Some v -> z#push_back v; j := next !j | None -> assert false done; z end -- John Skaller, mailto:skaller@maxtal.com.au 1/10 Toxteth Rd Glebe NSW 2037 Australia homepage: http://www.maxtal.com.au/~skaller downloads: http://www.triode.net.au/~skaller ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Can someone explain? 1999-09-28 18:56 ` Can someone explain? skaller @ 1999-10-04 8:23 ` Pierre Weis 1999-10-04 22:57 ` skaller 0 siblings, 1 reply; 12+ messages in thread From: Pierre Weis @ 1999-10-04 8:23 UTC (permalink / raw) To: skaller; +Cc: caml-list > Is there a way to access a value of a class instance? > If so, what is the syntax? If not, what is the purpose > of allowing 'val' bindings in class declarations in module > signatures? The only way to access a value of a class instance is via method invocation: you have to define a method that returns the value. > Similarly, what is the purpose of allowing 'virtual' > methods in class types and class declarations in > module signatures? Virtual methods are methods that are declared but not implemented: sub-classes must define them. > I have a doubly linked list class, and concatenating > two lists takes 100 times longer in ocaml using my > code than pythons list concatenation function, > which is written in C. Wao! I would like to be able to run your benchmark, since I will be glad to try to use the Python's way of handling lists to speed up the Caml list package by a factor of 100! We worked hard on this point, and Caml lists (and more generally similar data structure manipulations) are supposed to be among the fastest known implementations available. So, could you please send a complete reproducible benchmark ? > My code isn't optimal (given the particular data structure > I've chosen) because the concat function cannot > get at values of the class. Excerpt given below. > Any advice appreciated. (A high speed mutable list > in the standard library would be even better :-) As you suggested, we may add extra list manipulation modules in the standard library, such as mutable lists or doubly linked lists. Mutable lists are easy to implement and there is no doubt that many Caml programmers have already written such kind of packages and can contribute. About your own program, I cannot comment on efficiency, since I do not catch the general idea of the design: I am a bit surprised by the melting of object oriented features and regular algebraic data type manipulation to implement lists. Could you please explain a bit the logic of your code (in particular the only comment (* STL style mutators *) is a kind of puzzle for me) ? Best regards, Pierre Weis INRIA, Projet Cristal, Pierre.Weis@inria.fr, http://cristal.inria.fr/~weis/ > module DoublyLinkedList : BiDirectional = > struct (* doubly linked list type *) > type 't d_node = > { > mutable nxt: 't iterator; > mutable prv: 't iterator; > mutable data: 't > } > > and 't iterator = > Empty > | Node of 't d_node > > let next x = match x with Empty -> Empty | Node n -> n.nxt > let deref x = match x with Empty -> None | Node n -> Some n.data > > class ['t] dlist = > object(self) > val mutable first': 't iterator = Empty > val mutable last': 't iterator = Empty > val mutable size: int = 0 > > method private init node = > last' <- node; > first' <- node; > size <- 1 > > method length = size > > (* STL style mutators *) > method push_back (data':'t): unit = > match last' with > | Empty -> self#init (Node {nxt=Empty; prv=Empty; data=data'}) > | Node fin -> > let tmp = Node {nxt=Empty; prv=last'; data=data'} in > fin.nxt <- tmp; > last' <- tmp; > size <- size + 1 > > method first = first' > end > > let concat (x:'a dlist) (y:'a dlist) :'a dlist = > let z = new dlist in > let i = ref x#first in > while deref !i <> None do > match deref !i with > | Some v -> z#push_back v; i := next !i > | None -> assert false > done; > let j = ref y#first in > while deref !j <> None do > match deref !j with > | Some v -> z#push_back v; j := next !j > | None -> assert false > done; > z > end > > -- > John Skaller, mailto:skaller@maxtal.com.au > 1/10 Toxteth Rd Glebe NSW 2037 Australia > homepage: http://www.maxtal.com.au/~skaller > downloads: http://www.triode.net.au/~skaller ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Can someone explain? 1999-10-04 8:23 ` Pierre Weis @ 1999-10-04 22:57 ` skaller 1999-10-05 9:43 ` Jerome Vouillon ` (2 more replies) 0 siblings, 3 replies; 12+ messages in thread From: skaller @ 1999-10-04 22:57 UTC (permalink / raw) To: Pierre Weis; +Cc: caml-list Pierre Weis wrote: > > > Is there a way to access a value of a class instance? > > If so, what is the syntax? If not, what is the purpose > > of allowing 'val' bindings in class declarations in module > > signatures? > > The only way to access a value of a class instance is via method > invocation: you have to define a method that returns the value. Thanks, but you have not answered the real question here: WHY are the values present in the interface when they are not accessible via the interface? > > Similarly, what is the purpose of allowing 'virtual' > > methods in class types and class declarations in > > module signatures? > > Virtual methods are methods that are declared but not implemented: > sub-classes must define them. Again, I knew that, the real question is WHY this information is in the _interface_?? > > I have a doubly linked list class, and concatenating > > two lists takes 100 times longer in ocaml using my > > code than pythons list concatenation function, > > which is written in C. > > Wao! I would like to be able to run your benchmark, since I will be > glad to try to use the Python's way of handling lists to speed up the > Caml list package by a factor of 100! Sigh. I have just examined the Python implementation and the reason is that Python uses arrays for lists. This makes insertion, deletion, and concatenation O(n), but it uses fast machine primatives (memcpy) and does only one allocation. My doubly linked list is the same order for appending, but it laboriously copies each node one by one, and has to do an allocation for each one, and has to search for the i'th location as well. So it is much slower than the Python equivalent. I will change the representation to match Python, using an array (or perhaps a doubly linked list of arrays), and report back. > We worked hard on this point, > and Caml lists (and more generally similar data structure > manipulations) are supposed to be among the fastest known > implementations available. So, could you please send a complete > reproducible benchmark ? You would need the WHOLE interpreter :-) I will make that available in the near future, asking for help to speed up the implementation. I think it would be VERY useful to have an ocaml written Python interpreter/compiler as fast as, or faster than, CPython. There are a lot of Python users out there who could be introduced to ocaml this way, and gain immediate benefits from a faster implementation (particularly the compiler). > As you suggested, we may add extra list manipulation modules in the > standard library, such as mutable lists or doubly linked > lists. Mutable lists are easy to implement and there is no doubt that > many Caml programmers have already written such kind of packages and > can contribute. Excellent! This would be an ideal situation. The other thing I would beg for is to fix the parser and lexer to be re-entrant [purely functional]. At present, state information must be kept in global store :-( It would also be useful if the parser could support nested parser calls as the lexer can: this is possible with the lexer, because the lexbuf is always in a state to read the next lexeme, however it is not possible with the parser because it may have read a token ahead of the production being reduced. > About your own program, I cannot comment on efficiency, since I do not > catch the general idea of the design: I am a bit surprised by the > melting of object oriented features and regular algebraic data type > manipulation to implement lists. Could you please explain a bit the > logic of your code (in particular the only comment > (* STL style mutators *) is a kind of puzzle for me) ? Sorry for brevity. STL is the C++ Standard Template Library, it contains efficient codes for manipulating data structures with generic algorithms, using iterators (i.e. pointer like things). > > module DoublyLinkedList : BiDirectional = > > struct (* doubly linked list type *) > > type 't d_node = > > { > > mutable nxt: 't iterator; > > mutable prv: 't iterator; > > mutable data: 't > > } A doubly linked list has a node containing two pointers, nxt -- a pointer to the next node object prv -- a pointer to the previous node object data -- the data > > and 't iterator = > > Empty > > | Node of 't d_node This is the type of a pointer to a node. In ocaml, references are used for pointers, so the type of a pointer is just that of a node, except that the pointer can advance 'off the end of the list' and so can refer to no node, and thus the two cases 'Empty' for off the end, and Node for pointing to an actual node. > > let next x = match x with Empty -> Empty | Node n -> n.nxt > > let deref x = match x with Empty -> None | Node n -> Some n.data next gets a pointer to the next node, given a pointer to some node x. deref gets the data, given an iterator. in C++: x = ++x // next *x // deref is the notation used, however the implementation is x->nxt x->data > > class ['t] dlist = > > object(self) > > val mutable first': 't iterator = Empty A class is used here to represent the whole list. It is an object simply because that is the intended use: as a mutable object with various mutators. In retrospect, this is probably a mistake. -- John Skaller, mailto:skaller@maxtal.com.au 1/10 Toxteth Rd Glebe NSW 2037 Australia homepage: http://www.maxtal.com.au/~skaller downloads: http://www.triode.net.au/~skaller ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Can someone explain? 1999-10-04 22:57 ` skaller @ 1999-10-05 9:43 ` Jerome Vouillon 1999-10-05 19:35 ` Gerd Stolpmann 1999-10-05 21:42 ` Can someone explain? Lyn A Headley 2 siblings, 0 replies; 12+ messages in thread From: Jerome Vouillon @ 1999-10-05 9:43 UTC (permalink / raw) To: skaller On Tue, Oct 05, 1999 at 08:57:20AM +1000, skaller wrote: > Pierre Weis wrote: > > > > > Is there a way to access a value of a class instance? > > > If so, what is the syntax? If not, what is the purpose > > > of allowing 'val' bindings in class declarations in module > > > signatures? > > > > The only way to access a value of a class instance is via method > > invocation: you have to define a method that returns the value. > > Thanks, but you have not answered the real question here: > WHY are the values present in the interface when they are not accessible > via the interface? > > > > Similarly, what is the purpose of allowing 'virtual' > > > methods in class types and class declarations in > > > module signatures? > > > > Virtual methods are methods that are declared but not implemented: > > sub-classes must define them. > > Again, I knew that, the real question is WHY this information > is in the _interface_?? This information is in the interface because a class declaration can also be used for inheritance, and a subclass can access the instance variables of its parent and provide an implementation for the virtual methods. -- Jérôme ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Can someone explain? 1999-10-04 22:57 ` skaller 1999-10-05 9:43 ` Jerome Vouillon @ 1999-10-05 19:35 ` Gerd Stolpmann 1999-10-06 9:42 ` skaller 1999-10-08 0:17 ` Problem of coercion in recursive class definitions Peter Schrammel 1999-10-05 21:42 ` Can someone explain? Lyn A Headley 2 siblings, 2 replies; 12+ messages in thread From: Gerd Stolpmann @ 1999-10-05 19:35 UTC (permalink / raw) To: skaller; +Cc: caml-list On Tue, 05 Oct 1999, John Skaller wrote: > The other thing I would beg for is to fix the parser >and lexer to be re-entrant [purely functional]. At present, state >information >must be kept in global store :-( > > It would also be useful if the parser could support nested >parser calls as the lexer can: this is possible with the lexer, >because the lexbuf is always in a state to read the next lexeme, >however it is not possible with the parser because it may have read >a token ahead of the production being reduced. I have recently posted a solution for this problem by turning the generated parser into a class; side-effects still exist but are limited to the object representing the parser. You can simply create several instances of the same parser, and nested parser calls are possible if the sub-parser resides in a different object than the calling parser. The solution requires a complicated Makefile, and I again suggest to support an object-oriented parser generator in one of the next caml releases. You find a description of the idea here: http://pauillac.inria.fr/caml/caml-list/1575.html A working application is my XML parser, look at the files markup_yacc.mly and Makefile.code in http://people.darmstadt.netsurf.de/Gerd.Stolpmann/ocaml/markup-0.2.tar.gz As any real application, this parser is much more complicated than necessary to demonstrate the principle... Gerd -- ---------------------------------------------------------------------------- Gerd Stolpmann Telefon: +49 6151 997705 (privat) Viktoriastr. 100 64293 Darmstadt EMail: Gerd.Stolpmann@darmstadt.netsurf.de (privat) Germany ---------------------------------------------------------------------------- ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Can someone explain? 1999-10-05 19:35 ` Gerd Stolpmann @ 1999-10-06 9:42 ` skaller 1999-10-08 0:17 ` Problem of coercion in recursive class definitions Peter Schrammel 1 sibling, 0 replies; 12+ messages in thread From: skaller @ 1999-10-06 9:42 UTC (permalink / raw) To: Gerd.Stolpmann; +Cc: caml-list Gerd Stolpmann wrote: > > On Tue, 05 Oct 1999, John Skaller wrote: > > The other thing I would beg for is to fix the parser > >and lexer to be re-entrant [purely functional]. At present, state > >information > >must be kept in global store :-( > > > I have recently posted a solution for this problem > The solution requires a complicated Makefile I have seen your solution, but I'd prefer not to rely on this kind of thing in code which may be distributed: it's fragile, depending on implementation dependent knowledge about the form of the files ocamlyacc generates. However, it seems like a good proof of principle, and I'm sure we're agreeing a _standard_ solution in the next version of ocaml would be ideal. -- John Skaller, mailto:skaller@maxtal.com.au 1/10 Toxteth Rd Glebe NSW 2037 Australia homepage: http://www.maxtal.com.au/~skaller downloads: http://www.triode.net.au/~skaller ^ permalink raw reply [flat|nested] 12+ messages in thread
* Problem of coercion in recursive class definitions 1999-10-05 19:35 ` Gerd Stolpmann 1999-10-06 9:42 ` skaller @ 1999-10-08 0:17 ` Peter Schrammel 1 sibling, 0 replies; 12+ messages in thread From: Peter Schrammel @ 1999-10-08 0:17 UTC (permalink / raw) Cc: caml-list Sorry if this might be a RTFM problem but I tried to solve it for the last week but didn't make it. I attached two modules I wrote, The xmlParser.ml module is an instantiation of the xmlState.ml*. But it gives me the error: The method set_xml_cache has type cache:my_cache -> my_state0 but is expected to have type cache:(my_content_handler #XmlState.xml_state as 'b, my_content_handler) XmlState.xml_cache -> (< debug : unit -> unit; get_ch_factory : (my_content_handler Grove.small_obj_factory, Unicode.ustring) Grove.factory; get_xml_cache : ('b, my_content_handler) XmlState.xml_cache; get_xml_zipper : ('b, my_content_handler) XmlState.xml_zipper; set_ch_factory : factory:(my_content_handler Grove.small_obj_factory, Unicode.ustring) Grove.factory -> 'b; set_xml_cache : 'a; set_xml_zipper : zipper:('b, my_content_handler) XmlState.xml_zipper -> 'c; .. > as 'c) as 'a Type my_state0 = < .. > is not compatible with type 'c Self type cannot escape its class Although I tried the coercion trick from page 40 of the manual. Thanks for any help, Peter -- Peter Schrammel UniBw-Muenchen 106/2/116 85579 Neubiberg ICQ: 5469131 name="xmlState.mli" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="xmlState.mli" open Unicode;; type 'a content = START of 'a | TAG of 'a * 'a | EMPTY of 'a | PCDATA of 'a type cachetype = PERef of Unicode.ustring | ERef of Unicode.ustring type context = Unicode.ustring Grove.big_pattern type rOD_content = XmlTypes.refOrData content (*state and contenthandler are parameter*) class virtual ['state] content_handler : object constraint 'state = 'chandler #xml_state (*parse: get's some relevant information out of the content. for example the name of the element or the name of an id*) method virtual parse : state:'state -> 'state (*cache: bring this information into the cache *) method virtual cache : state:'state -> 'state (*uncache: remove it from there*) method virtual uncache : state:'state -> 'state method virtual deref : state:'state -> dtd:bool -> peref:bool -> eref:bool -> chref:bool -> XmlTypes.refOrData list * 'state end and virtual ['chandler] xml_state : object ('self) constraint 'chandler = 'state #content_handler method virtual get_xml_zipper : ('state,'chandler) xml_zipper method virtual set_xml_zipper : zipper:('state,'chandler) xml_zipper -> 'self method virtual get_xml_cache : ('state,'chandler) xml_cache method virtual set_xml_cache : cache:('state,'chandler) xml_cache -> 'self method virtual get_ch_factory : ('chandler Grove.small_obj_factory,ustring) Grove.factory method virtual set_ch_factory : factory:('chandler Grove.small_obj_factory,ustring) Grove.factory -> 'state end and virtual ['state,'chandler] xml_node : content:rOD_content -> chandler:'chandler -> object constraint 'state = 'chandler #xml_state constraint 'chandler = 'state #content_handler inherit Zipper.zip_obj inherit ['state] content_handler method virtual get_content : rOD_content method virtual set_content : content:rOD_content -> unit method virtual set_chandler : chandler:'chandler -> unit end and virtual ['state,'chandler] xml_zipper : root:('state,'chandler) xml_node -> object constraint 'state = 'chandler #xml_state constraint 'chandler = 'state #content_handler inherit [('state,'chandler) xml_node] Zipper.zipper method virtual build : preparsed:PreParser.tagOrPCData list -> state:'state -> 'state end and virtual ['state,'chandler] xml_cache : object ('cache) constraint 'state = 'chandler #xml_state constraint 'chandler = 'state #content_handler method virtual set : key:cachetype -> data:('state,'chandler) xml_node -> 'cache method virtual get : key:cachetype -> ('state,'chandler) xml_node method virtual remove : key:cachetype -> 'cache end name="xmlParser.ml" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="xmlParser.ml" open Unicode;; let us = Unicode.ustring_of_string;; let uc = Unicode.uchar_of_char;; let su = string_of_ustring;; open XmlState;; exception Parser_Error;; exception Cache_Error;; (* let debug_cachetype = function PERef u -> print_string (su u) | ERef u -> print_string (su u) *) class virtual my_state0 option:(opt : Eoption.eoption) xzipper:(z : my_zipper) ch_factory:(cf : (my_content_handler Grove.small_obj_factory,ustring) Grove.factory) = (*I have to declare this class to be able to coerce my_state*) object inherit [my_content_handler] xml_state inherit Debug.debug method virtual get_xml_cache : my_cache method virtual set_xml_cache : cache:my_cache -> my_state0 method virtual get_xml_zipper : my_zipper method virtual set_xml_zipper : zipper:my_zipper -> my_state0 method virtual get_ch_factory : (my_content_handler Grove.small_obj_factory,ustring) Grove.factory method virtual set_ch_factory : factory:(my_content_handler Grove.small_obj_factory,ustring) Grove.factory -> my_state0 method virtual get_entity_proxy : Catalog.entity_proxy method virtual get_option : Eoption.eoption end and my_content_handler = object inherit [my_state] content_handler method parse state:(s : my_state) = s method cache state:(s : my_state) = s method uncache state:(s : my_state) = s method deref state:(s : my_state) dtd:(dtd : bool) peref:(per : bool) eref:(er : bool) chref:(chr : bool) = (([] : XmlTypes.refOrData list),(s : my_state)) method debug () = () end and my_node content:(cnt : rOD_content) chandler:(ch : my_content_handler) = object inherit [my_state,my_content_handler] xml_node content:cnt chandler:ch val mutable content = cnt val mutable chandler = ch method get_content = content method set_content content:c = content <-cnt method set_chandler chandler:ch = chandler<-ch method parse = chandler#parse method cache = chandler#cache method uncache = chandler#uncache method deref = chandler#deref method debug () = () end and my_zipper root:(root : my_node) = object inherit [my_state,my_content_handler] xml_zipper root:root method build preparsed:(pre : PreParser.tagOrPCData list) state:(state : my_state) = state end and my_cache = object (self) inherit [my_state,my_content_handler] xml_cache val mutable cache = Hashtbl.create size:191 method set key:(k : cachetype) data:(d : my_node) = try let _ = Hashtbl.find cache key:k in raise Cache_Error with Not_found -> Hashtbl.add cache key:k data:d;self method remove key:k = Hashtbl.remove cache key:k;self method get key:k = Hashtbl.find cache key:k (* method debug () = let print k (d : my_node)= debug_cachetype k; print_string " -> "; d#debug (); print_newline (); in Hashtbl.iter fun:(fun key:k data:d -> print k d) cache;*) end and my_state option:(opt :Eoption.eoption) xzipper:(xzipper : my_zipper) ch_factory:( chfac : (my_content_handler Grove.small_obj_factory,ustring) Grove.factory) = object(self) inherit my_state0 val mutable xc = new my_cache val mutable ep = new Catalog.entity_proxy option:opt val mutable xz = xzipper val mutable op = opt val mutable chf = chfac method get_xml_zipper = xz method set_xml_zipper zipper:z = xz <- z;(self : #my_state0 :> my_state0) method get_xml_cache = xc method set_xml_cache cache:c = xc <- c;(self : #my_state0 :> my_state0) method get_ch_factory = chfac method set_ch_factory factory:c = chf <- c;(self : #my_state0 :> my_state0) method get_entity_proxy = ep method get_option = op method debug () = () end ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Can someone explain? 1999-10-04 22:57 ` skaller 1999-10-05 9:43 ` Jerome Vouillon 1999-10-05 19:35 ` Gerd Stolpmann @ 1999-10-05 21:42 ` Lyn A Headley 1999-10-06 10:17 ` skaller 2 siblings, 1 reply; 12+ messages in thread From: Lyn A Headley @ 1999-10-05 21:42 UTC (permalink / raw) To: skaller; +Cc: caml-list >>>>> "skaller" == skaller <skaller@maxtal.com.au> writes: >> The only way to access a value of a class instance is via >> method invocation: you have to define a method that returns the >> value. skaller> Thanks, but you have not answered the real question skaller> here: WHY are the values present in the interface when skaller> they are not accessible via the interface? good question. >> > Similarly, what is the purpose of allowing 'virtual' > >> methods in class types and class declarations in > module >> signatures? >> >> Virtual methods are methods that are declared but not >> implemented: sub-classes must define them. skaller> Again, I knew that, the real question is WHY this skaller> information is in the _interface_?? [I know] skaller> I will change the representation to match Python, skaller> using an array (or perhaps a doubly linked list of skaller> arrays), and report back. Here's an idea: just hijack the Python implementation and provide an ocaml interface. This has the advantages that (1) it has been hand-tuned for efficiency for years and (2) that it will export a similar interface to the ocaml code as has existed for the C code for years, thus allowing a smoother transition to ocaml for python extension writers. Come to think of it, why not do that for /all/ the builtin types? These will also be useful for use by code generated by viperc. skaller> You would need the WHOLE interpreter :-) I will make skaller> that available in the near future, asking for help to skaller> speed up the implementation. yum. <smacks his chops noisily> skaller> I think it would be VERY useful to have an ocaml skaller> written Python interpreter/compiler as fast as, or faster skaller> than, CPython. There are a lot of Python users out there skaller> who could be introduced to ocaml this way, and gain skaller> immediate benefits from a faster implementation skaller> (particularly the compiler). Me too! This could be a big thing for ocaml. Darn it, now you've got me all psyched about ocaml again. Too bad I already committed to Eiffel for my latest project. [snip] skaller> A doubly linked list has a node containing two pointers, [snip] >> > and 't iterator = > Empty > | Node of 't d_node skaller> This is the type of a pointer to a node. In ocaml, An ocaml "port" of STL would kick ass. especially, think how well iterators would combine with closures! The C++ notion of "function objects" and "adaptors" looks clumsy in comparison (e.g. you cannot create a localized class object) skaller> A class is used here to represent the whole list. It is skaller> an object simply because that is the intended use: as a skaller> mutable object with various mutators. In retrospect, this skaller> is probably a mistake. why? -Lyn ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Can someone explain? 1999-10-05 21:42 ` Can someone explain? Lyn A Headley @ 1999-10-06 10:17 ` skaller 0 siblings, 0 replies; 12+ messages in thread From: skaller @ 1999-10-06 10:17 UTC (permalink / raw) To: Lyn A Headley; +Cc: caml-list Lyn A Headley wrote: > Here's an idea: just hijack the Python implementation and provide an > ocaml interface. This has the advantages that (1) it has been > hand-tuned for efficiency for years and (2) that it will export a > similar interface to the ocaml code as has existed for the C code for > years, thus allowing a smoother transition to ocaml for python > extension writers. I thought of that, and I was tempted! However, I decided against it for several reasons. First, while it leverages the Python code, it creates a headache for memory management, since Python does it's own, which doesn't sit well with ocaml garbage collector. Second, it means any extensions I wish to write will have to be written in C. This defeats the advantages of using ocaml. For example, I have already added a Rational type using the num module: I did it in only a few hours, and added long integers at the same time: the num long integers are already faster than the python ones. Third, it becomes sensitive to the C implementation of Python which changes with versions, and depends on the whims of developers who may have different goals than I do. > Come to think of it, why not do that for /all/ the builtin types? > These will also be useful for use by code generated by viperc. So will the ocaml based run time, if the compiler back end generates ocaml :-) There are two versions of Python: CPython (C) and JPython (Java). Both suffer from portability problems, due to the base language, compared with ocaml (IMHO). Both suffer from inferior technology, compared with ocaml (IMHO). My plan is to suport _pure_ python, not C based extensions: just the same as JPython cannot use C based extensions. I suspect that the C -> ocaml -> python wrapper chain for extensions representing external interfaces (operating system services and access to C libraries) is probably easier than the C -> CPython extension -> Python. However, a lot of C modules in python are only for efficiency, and it is better to rewrite these in Python and use the compiler, or, in ocaml if really necessary. > Darn it, now you've got > me all psyched about ocaml again. Too bad I already committed to > Eiffel for my latest project. Oh well :-) > An ocaml "port" of STL would kick ass. The code I showed is part of a set of modules I'm developing that (attempt to) provide ocaml representations of the same ideas. However, this has a lower priority than the python compiler. >especially, think how well > iterators would combine with closures! The C++ notion of "function > objects" and "adaptors" looks clumsy in comparison (e.g. you cannot > create a localized class object) Yes. In fact, I have a contract to write a book on STL, but I gave up precisely because of this. I tried to tell the committee, but they just didn't understand. STL isn't that useful in C++, because the core language fails to support nested functions, when it could. Furthermore, the committee broke the way unions work, so that they cannot be used to implement variants easily. I prefer to work with a language whose developers actually know some mathematics. > skaller> A class is used here to represent the whole list. It is > skaller> an object simply because that is the intended use: as a > skaller> mutable object with various mutators. In retrospect, this > skaller> is probably a mistake. > > why? Because, the functional operations, such as concatenation, require access to the private data, and cannot get it. There are no friends in ocaml: the correct solution is to abandon the class and use an algebraic data structure, and restrict the interface of the module so it becomes abstract. There is another reason: class methods cannot be polymorphic, wheres plain functions of modules can be (independently of instantiation of type parameters of the module). -- John Skaller, mailto:skaller@maxtal.com.au 1/10 Toxteth Rd Glebe NSW 2037 Australia homepage: http://www.maxtal.com.au/~skaller downloads: http://www.triode.net.au/~skaller ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Can someone explain?
@ 1999-10-13 19:16 Juergen Pfitzenmaier
0 siblings, 0 replies; 12+ messages in thread
From: Juergen Pfitzenmaier @ 1999-10-13 19:16 UTC (permalink / raw)
To: caml-list
Lyn A Headley wrote:
> An ocaml "port" of STL would kick ass. especially, think how well
> iterators would combine with closures! The C++ notion of "function
> objects" and "adaptors" looks clumsy in comparison (e.g. you cannot
> create a localized class object)
Hmm, don't know if it would be the same nice thing as in C++. A year ago
I added a GC to the STL containers so there's some experience of what
can happen if you try this in ocaml.
Some algorithms using the STL are built around the fact that certain iterators
and the value they refer to don't change if you treat the container ``nicely''.
To keep these algos working was quite some pain.
Haven't really thought about what happens if the GC is a real member of the
language and not just an add-on. May be things are easier then but I wouldn't
bet on it.
ciao pfitzen
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~1999-10-14 13:01 UTC | newest] Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 1999-09-09 16:34 strange behavior of the object type-checker Pierre Boulet 1999-09-09 19:43 ` Jerome Vouillon 1999-09-28 18:56 ` Can someone explain? skaller 1999-10-04 8:23 ` Pierre Weis 1999-10-04 22:57 ` skaller 1999-10-05 9:43 ` Jerome Vouillon 1999-10-05 19:35 ` Gerd Stolpmann 1999-10-06 9:42 ` skaller 1999-10-08 0:17 ` Problem of coercion in recursive class definitions Peter Schrammel 1999-10-05 21:42 ` Can someone explain? Lyn A Headley 1999-10-06 10:17 ` skaller 1999-10-13 19:16 Juergen Pfitzenmaier
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox