strange behavior of the object typechecker
 Pierre Boulet
[
Home
]
[ Index:
by date

by threads
]
[ Message by date: previous  next ] [ Message in thread: previous  next ] [ Thread: previous  next ]
[ Message by date: previous  next ] [ Message in thread: previous  next ] [ Thread: previous  next ]
Date:   (:) 
From:  Pierre Boulet <Pierre.Boulet@l...> 
Subject:  strange behavior of the object typechecker 
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 1718: 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 01: 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.