* Polymorphic method question @ 2006-07-10 19:21 brogoff 2006-07-10 20:05 ` [Caml-list] " Richard Jones 2006-07-11 2:09 ` Jacques Garrigue 0 siblings, 2 replies; 13+ messages in thread From: brogoff @ 2006-07-10 19:21 UTC (permalink / raw) To: caml-list Hi, I'm sure I'll slap my forehead in disgust when someone lifts the scales from my eyes, but I'm once again perplexed by a type error from OCaml when using objects. Can someone tell me why I get the error from the second case (with the classes connected by "and") when the first case is OK? BTW, This example was distilled from one in which I could not cleanly remove the class recursion, one involving an "extensible visitor" in which there is a recursion between the visited and visitor classes. Assuming there's an obvious answer to my first question, is there a nice workaround in this case? brogoff@denali[tricks]$ ocaml Objective Caml version 3.09.2 # class virtual ['a] bar = object method virtual get : 'a end;; class virtual ['a] bar : object method virtual get : 'a end # class virtual foobar = object method virtual f : 'a . 'a bar -> 'a end;; class virtual foobar : object method virtual f : 'a bar -> 'a end # class virtual ['a] bar = object method virtual get : 'a end and foobar = object method virtual f : 'a . 'a bar -> 'a end;; Characters 115-132: method virtual f : 'a . 'a bar -> 'a ^^^^^^^^^^^^^^^^^ This type scheme cannot quantify 'a : it escapes this scope. -- -- Brian ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Caml-list] Polymorphic method question 2006-07-10 19:21 Polymorphic method question brogoff @ 2006-07-10 20:05 ` Richard Jones 2006-07-10 23:25 ` brogoff 2006-07-11 2:09 ` Jacques Garrigue 1 sibling, 1 reply; 13+ messages in thread From: Richard Jones @ 2006-07-10 20:05 UTC (permalink / raw) To: brogoff; +Cc: caml-list On Mon, Jul 10, 2006 at 12:21:26PM -0700, brogoff wrote: > This type scheme cannot quantify 'a : > it escapes this scope. Check out this thread: http://caml.inria.fr/pub/ml-archives/caml-list/2005/02/a67b1a509263be01705305f36d64c39c.en.html Rich. -- Richard Jones, CTO Merjis Ltd. Merjis - web marketing and technology - http://merjis.com Team Notepad - intranets and extranets for business - http://team-notepad.com ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Caml-list] Polymorphic method question 2006-07-10 20:05 ` [Caml-list] " Richard Jones @ 2006-07-10 23:25 ` brogoff 2006-07-11 2:24 ` skaller 0 siblings, 1 reply; 13+ messages in thread From: brogoff @ 2006-07-10 23:25 UTC (permalink / raw) To: Richard Jones; +Cc: caml-list On Mon, 10 Jul 2006, Richard Jones wrote: > On Mon, Jul 10, 2006 at 12:21:26PM -0700, brogoff wrote: > > This type scheme cannot quantify 'a : > > it escapes this scope. > > Check out this thread: > > http://caml.inria.fr/pub/ml-archives/caml-list/2005/02/a67b1a509263be01705305f36d64c39c.en.html > > Rich. Hi Rich, Thanks for the info, I guess I missed that one when it came out. Unfortunately, the solution proposed, breaking the recursion by introducing some polymorphic algebraic type to hold any kind of value in some class type to represent the visitor, breaks the whole thing. There are just too many recursive dependencies. Here's a more complete, but still small, example. The modules are only there to show how the classes would go into files, they're not essential. PS: Before anyone tells me that algebraic data types are favored for this over visitor classes, I'm well aware of all that, and in general agree with those who prefer their ML sans OOP. However, I was trying to encode a design pattern I read about somewhere (Felleisen?) which made good use of polymorphic methods, only to find that it just doesn't translate into the OCaml class system. The restriction on polymorphism in mutually recursive class definitions makes the idea unworkable. Any possibility that restriction will be lifted? (* The following code won't work, but hopefully gives the idea *) module Shape = struct class virtual ['a] shape_visitor = object method visit_square : square -> 'a method visit_rectangle : rectangle -> 'a method visit_polygon : polygon -> 'a method visit_translated : translated -> 'a (* and potentially many more! *) end and virtual shape = object method virtual visit : 'a . 'a shape_visitor -> 'a end and square pt width = object (self) inherit shape method visit visitor = visitor#visit_square self method as_tuple : ((int * int) * (int * int)) = let (ll_x, ll_y) = pt in (pt, (ll_x + width, ll_y + width)) method as_point_list : (int * int) list = failwith "Shape.square#as_point_list: unimplemented" end and rectangle ll ur = object (self) inherit shape method visit visitor = visitor#visit_rectangle self method as_tuple : ((int * int) * (int * int)) = (ll, ur) method as_point_list : (int * int) list = failwith "Shape.rectangle#as_point_list: unimplemented" end and polygon points = object (self) val points : (int * int) list = points inherit shape method visit visitor = visitor#visit_polygon self method as_point_list : (int * int) list = points end class translated pt s = object (self) inherit shape method visit visitor = visitor#visit_translated self method get_shape = s method get_translation = pt method as_point_list : (int * int) list = failwith "Shape.translated#as_point_list: unimplemented" end end (* module Shape *) module Contains_point = struct (* Writing code that works over shapes *) class contains_point point = object inherit bool Shape.shape_visitor method make_contains_point p = new contains_point p method visit_square : Shape.square node -> bool = fun s -> let ((ll_x, ll_y), (ur_x, ur_y)) = s#as_tuple in let (x, y) = point in ll_x <= x && x <= ur_x && ll_y <= y && y <= ur_y method visit_rectangle : Shape.rectangle node -> bool = fun r -> let ((ll_x, ll_y), (ur_x, ur_y)) = r#as_tuple in let (x, y) = point in ll_x <= x && x <= ur_x && ll_y <= y && y <= ur_y method visit_polygon : Shape.polygon node -> bool = fun p -> failwith "Contains_point.contains_point#visit_polygon: unimplemented" method visit_translated : Shape.translated node -> bool = fun t -> failwith "Contains_point.contains_point#visit_translated: unimplemented" end;; -- -- Brian ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Caml-list] Polymorphic method question 2006-07-10 23:25 ` brogoff @ 2006-07-11 2:24 ` skaller 2006-07-11 4:56 ` brogoff 0 siblings, 1 reply; 13+ messages in thread From: skaller @ 2006-07-11 2:24 UTC (permalink / raw) To: brogoff; +Cc: Richard Jones, caml-list On Mon, 2006-07-10 at 16:25 -0700, brogoff wrote: > The restriction on polymorphism in mutually recursive class > definitions makes the idea unworkable. Any possibility that restriction will be > lifted? I don't believe there is such a restriction: the problem is when you introduce other types such as variants which must recurse with class types, there's no support for type class t1 = .. and t2 = [`X ..] etc. The solution, using extra parameters and open recursion, followed by closure of the recursions, works but is vastly too messy to encode by hand if there are more than a couple of parameters needed. This really does need to be automated in the special case where you're only opening the types so you can later close them. In general, for incremental type building, you need to retain the open types.. and it isn't clear if there's any way to make it tractable (syntactically I mean). Unfortunately .. the easiest kind of solution is to write a code generator in Python or Perl .. this kind of polymorphism is not exactly desirable .. ;( Can MetaOcaml can handle this better? -- John Skaller <skaller at users dot sf dot net> Felix, successor to C++: http://felix.sf.net ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Caml-list] Polymorphic method question 2006-07-11 2:24 ` skaller @ 2006-07-11 4:56 ` brogoff 0 siblings, 0 replies; 13+ messages in thread From: brogoff @ 2006-07-11 4:56 UTC (permalink / raw) To: skaller; +Cc: caml-list, Richard Jones On Tue, 11 Jul 2006, skaller wrote: > On Mon, 2006-07-10 at 16:25 -0700, brogoff wrote: > > > The restriction on polymorphism in mutually recursive class > > definitions makes the idea unworkable. Any possibility that restriction will be > > lifted? > > I don't believe there is such a restriction: See the thread that Richard referenced, and go to Jacques Garrigue's final post. There he writes: "Inside mutually recursive definitions of classes, parameters cannot be used polymorphically" That's the problem, isn't it? > the problem is > when you introduce other types such as variants which must > recurse with class types, there's no support for > > type class t1 = .. > and t2 = [`X ..] That's surely annoying, but it's a different problem I think. > > etc. The solution, using extra parameters and open > recursion, followed by closure of the recursions, > works but is vastly too messy to encode by hand if there > are more than a couple of parameters needed. This really > does need to be automated in the special case where > you're only opening the types so you can later close them. If you look at the faux OCaml code I provided, I believe the intent is clear, forgiving OCaml's, ummm, suboptimal syntax. I could code it up in Java 1.5 (maybe I should, just to make sure it works!) and since Java doesn't do parameter inference it may all work fine. > In general, for incremental type building, you need to retain > the open types.. and it isn't clear if there's any way > to make it tractable (syntactically I mean). The code for this in Java 1.5 is quite clear, syntactically. It's a bit tricky to get it all right, of course, but someone smarter than me already figured it out, I just want to implement the trick in my language of choice, which is not Java. > Unfortunately .. the easiest kind of solution is to write > a code generator in Python or Perl .. this kind of polymorphism > is not exactly desirable .. ;( No, I think you're missing the point of the "exercise" here. I'm not looking for a code generator, but an OO approach to building extensible visitors with precise static type checking. -- Brian ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Caml-list] Polymorphic method question 2006-07-10 19:21 Polymorphic method question brogoff 2006-07-10 20:05 ` [Caml-list] " Richard Jones @ 2006-07-11 2:09 ` Jacques Garrigue 2006-07-11 5:22 ` brogoff 1 sibling, 1 reply; 13+ messages in thread From: Jacques Garrigue @ 2006-07-11 2:09 UTC (permalink / raw) To: brogoff; +Cc: caml-list From: brogoff <brogoff@speakeasy.net> Subject: [Caml-list] Polymorphic method question Date: Mon, 10 Jul 2006 12:21:26 -0700 (PDT) > Hi, > I'm sure I'll slap my forehead in disgust when someone lifts the > scales from my eyes, but I'm once again perplexed by a type error > from OCaml when using objects. Can someone tell me why I get the > error from the second case (with the classes connected by "and") when > the first case is OK? > # class virtual ['a] bar = > object > method virtual get : 'a > end > and foobar = > object > method virtual f : 'a . 'a bar -> 'a > end;; > Characters 115-132: > method virtual f : 'a . 'a bar -> 'a > ^^^^^^^^^^^^^^^^^ > This type scheme cannot quantify 'a : > it escapes this scope. Because bar is not yet completely defined when you use it in foobar. This is all related with parameter constraint inference: we don't know yet wether bar's parameter is really polymorphic or is constraint (e.g. 'a = 'b * 'c). Note that the problem does not occur with direct type definitions, as constraint inference is not done in that case (this is one of the reasons you cannot combine type and class definitions.) # type 'a bar = < get: 'a > and foobar = < f : 'a. 'a bar -> 'a >;; type 'a bar = < get : 'a > and foobar = < f : 'a. 'a bar -> 'a > The only way to solve this problem would be to remove parameter constraint inference from classes. It would certainly break some programs, so this seems difficult. By the way, if you're ready to define your types first, then you can do this properly. # class virtual ['a] bar = object method virtual get : 'a end and virtual foobar = object method virtual f : 'a . 'a bar_t -> 'a end;; class virtual ['a] bar : object method virtual get : 'a end and virtual foobar : object method virtual f : 'a bar_t -> 'a end > BTW, This example was distilled from one in which I could not cleanly > remove the class recursion, one involving an "extensible visitor" in > which there is a recursion between the visited and visitor classes. > Assuming there's an obvious answer to my first question, is there a > nice workaround in this case? Extensible visitor is more complex. You can already find the polymorphic variant solution at http://www.math.nagoya-u.ac.jp/~garrigue/papers/ There is a new solution using private rows and recursive modules inside "Private rows: abstracting the unnamed". With Keiko Nakata, we found another solution using objects in place of polymorhic variants. This is rather verbose, but here is the code. This is close to the Odersky&Zenger approach in Scala, but here our visitor is purely functional. Note how we are not able to use eval's self directly for recursion, as we need an abstract row. Jacques Garrigue (* OO decomposition in Objective Caml *) class type ['a,'exp] visit_add = object method visitNum : int -> 'a method visitAdd : 'exp -> 'exp -> 'a end module type AddTE = sig type ('a,'exp) t type exp = < accept : 'a. ('a, exp) t -> 'a > val num : int -> exp val add : exp -> exp -> exp end module type AddT = sig include AddTE val eval : (int, exp) t Lazy.t end module AddF(X : AddT with type ('a,'exp) t = private ('a,'exp) #visit_add) = struct type ('a, 'exp) t = ('a, 'exp) X.t class type exp = object ('e) method accept : 'a. ('a, 'e) t -> 'a end class num x = object (_ : #exp) method accept v = v#visitNum x end let num x = new num x class add a b = object (_ : #exp) method accept v = v#visitAdd a b end let add x = new add x class eval = object method visitNum (i : int) = i method visitAdd (r : exp) (l : exp) = r#accept (Lazy.force X.eval) + l#accept (Lazy.force X.eval) end let eval = lazy (new eval) end module rec Add : AddT with type('a,'exp) t = ('a,'exp) visit_add = AddF(Add) class type ['a,'exp] visit_add_neg = object inherit ['a,'exp] visit_add method visitNeg : 'exp -> 'a end module type AddNegT = sig include AddT val neg : exp -> exp end module AddNegF(X : AddNegT with type ('a,'exp) t = private ('a,'exp) #visit_add_neg) = struct module Add = AddF(X) include (Add : AddTE with type ('a,'e) t = ('a,'e) X.t) class neg x = object (_ : #Add.exp) method accept v = v#visitNeg x end let neg x = new neg x class eval = object inherit Add.eval method visitNeg (e : exp) = - e#accept (Lazy.force X.eval) end let eval = lazy (new eval) end module rec AddNeg : AddNegT with type ('a,'exp) t = ('a,'exp) visit_add_neg = AddNegF(AddNeg) # open Add;; # let e1 = (add (num 2) (num 3));; val e1 : Add.exp = <obj> # e1#accept (Lazy.force eval);; - : int = 5 # open AddNeg;; # let e2 = neg (e1 : Add.exp :> exp);; val e2 : AddNeg.exp = <obj> # e2#accept (Lazy.force eval);; - : int = -5 ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Caml-list] Polymorphic method question 2006-07-11 2:09 ` Jacques Garrigue @ 2006-07-11 5:22 ` brogoff 2006-07-11 7:32 ` Jacques Garrigue 0 siblings, 1 reply; 13+ messages in thread From: brogoff @ 2006-07-11 5:22 UTC (permalink / raw) To: Jacques Garrigue; +Cc: caml-list On Tue, 11 Jul 2006, Jacques Garrigue wrote: > From: brogoff <brogoff@speakeasy.net> > > Because bar is not yet completely defined when you use it in foobar. > This is all related with parameter constraint inference: we don't know > yet wether bar's parameter is really polymorphic or is constraint (e.g. > 'a = 'b * 'c). > Note that the problem does not occur with direct type definitions, as > constraint inference is not done in that case (this is one of the > reasons you cannot combine type and class definitions.) > > # type 'a bar = < get: 'a > and foobar = < f : 'a. 'a bar -> 'a >;; > type 'a bar = < get : 'a > > and foobar = < f : 'a. 'a bar -> 'a > > > The only way to solve this problem would be to remove parameter > constraint inference from classes. It would certainly break some > programs, so this seems difficult. That's too bad, as it seems the class based OO version of the extensible visitor is fairly straightforward in OCaml except for this counterintuitive gotcha. What would have to be done to fix the broken programs? It may be worth considering. > By the way, if you're ready to define your types first, then you > can do this properly. In the more realistic example I sent along after, you'll see that this solution is not really pleasing. You'd need to create a parallel type hierarchy to match your class hierarchy, which is too verbose. All this because we must have inference, which is supposed to make things less verbose. Ironic, isn't it? ;-) I have seen the new private rows stuff, which is very nice, but all of these solutions IMO are way too complex to be considered satisfactory. I'll see if the Java 1.5 approach actually works (I used some Pizza code to do the OCaml implementation) because that was quite straightforward. I'd prefer approaches that I can explain with a little hand waving. I think type theorists often forget that there are a few programmers still who don't have PhDs in type theory and will look at such solutions and conclude that OCaml is not for them ;-). -- Brian ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Caml-list] Polymorphic method question 2006-07-11 5:22 ` brogoff @ 2006-07-11 7:32 ` Jacques Garrigue 2006-07-11 18:20 ` brogoff 0 siblings, 1 reply; 13+ messages in thread From: Jacques Garrigue @ 2006-07-11 7:32 UTC (permalink / raw) To: brogoff; +Cc: caml-list From: brogoff <brogoff@speakeasy.net> > > The only way to solve this problem would be to remove parameter > > constraint inference from classes. It would certainly break some > > programs, so this seems difficult. > > That's too bad, as it seems the class based OO version of the extensible > visitor is fairly straightforward in OCaml except for this counterintuitive > gotcha. What would have to be done to fix the broken programs? It may be > worth considering. You just would have to write constraints explicitly when they are needed. This could be a pain for classes. See the tutorial on the subject-observer pattern in the reference manual for a non-trivial use of inference. But maybe we could rather have a way to tell the system that, for some specific class, type parameters are not constrained. Hacky though. > > By the way, if you're ready to define your types first, then you > > can do this properly. > > In the more realistic example I sent along after, you'll see that this > solution is not really pleasing. You'd need to create a parallel type > hierarchy to match your class hierarchy, which is too verbose. All this > because we must have inference, which is supposed to make things less > verbose. Ironic, isn't it? ;-) I'm not so sure about verbosity. Type syntax is pretty compact :-) > I have seen the new private rows stuff, which is very nice, but all of these > solutions IMO are way too complex to be considered satisfactory. I'll see if > the Java 1.5 approach actually works (I used some Pizza code to do the OCaml > implementation) because that was quite straightforward. I'd prefer approaches > that I can explain with a little hand waving. I think type theorists often > forget that there are a few programmers still who don't have PhDs in type > theory and will look at such solutions and conclude that OCaml is not for > them ;-). I'm sure you need some tricks to make it work in Java 1.5 too. I don't have the code in mind. I agree that the solution I posted is not too simple, but I don't think this is PhD level. Actually it's not much worse than the visitor pattern. What is hard is understanding why you have to do all this extra work, not using the pattern itself. Note that, if you are ready to use a slightly less functional approach, where the result is extracted from the visitor afterwards, then typing is no problem. This code is based on http://cristal.inria.fr/~remy/work/expr/ It is strictly equivalent to Odersky&Zenger's Scala version. (Actually this kind of code is one reason we reverted to sharing of instance variables in 3.10) Jacques Garrigue module Shape = struct class virtual shape_visitor = object method virtual visit_square : square -> unit method virtual visit_rectangle : rectangle -> unit method virtual visit_polygon : polygon -> unit method virtual visit_translated : translated -> unit (* and potentially many more! *) end and virtual shape = object method virtual visit : shape_visitor -> unit end and square pt width = object (self) inherit shape method visit visitor = visitor#visit_square (self :> square) method as_tuple : ((int * int) * (int * int)) = let (ll_x, ll_y) = pt in (pt, (ll_x + width, ll_y + width)) method as_point_list : (int * int) list = failwith "Shape.square#as_point_list: unimplemented" end and rectangle ll ur = object (self) inherit shape method visit visitor = visitor#visit_rectangle (self :> rectangle) method as_tuple : ((int * int) * (int * int)) = (ll, ur) method as_point_list : (int * int) list = failwith "Shape.rectangle#as_point_list: unimplemented" end and polygon points = object (self) val points : (int * int) list = points inherit shape method visit visitor = visitor#visit_polygon (self :> polygon) method as_point_list : (int * int) list = points end and translated (pt : int * int) (s : shape) = object (self) inherit shape method visit visitor = visitor#visit_translated (self :> translated) method get_shape = s method get_translation = pt method as_point_list : (int * int) list = failwith "Shape.translated#as_point_list: unimplemented" end end (* module Shape *) module Contains_point = struct (* Writing code that works over shapes *) class contains_point point = object inherit Shape.shape_visitor val mutable result = false method result = result method visit_square : Shape.square -> unit = fun s -> let ((ll_x, ll_y), (ur_x, ur_y)) = s#as_tuple in let (x, y) = point in result <- ll_x <= x && x <= ur_x && ll_y <= y && y <= ur_y method visit_rectangle : Shape.rectangle -> unit = fun r -> let ((ll_x, ll_y), (ur_x, ur_y)) = r#as_tuple in let (x, y) = point in result <- ll_x <= x && x <= ur_x && ll_y <= y && y <= ur_y method visit_polygon : Shape.polygon -> unit = fun p -> failwith "Contains_point.contains_point#visit_polygon: unimplemented" method visit_translated : Shape.translated -> unit = fun t -> let (x, y) = point in let (dx, dy) = t#get_translation in let visitor = new contains_point (x-dx, y-dy) in t#get_shape#visit (visitor :> Shape.shape_visitor); result <- visitor#result end let contains_point p (s : #Shape.shape) = let visitor = new contains_point p in s#visit (visitor :> Shape.shape_visitor); visitor#result end;; ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Caml-list] Polymorphic method question 2006-07-11 7:32 ` Jacques Garrigue @ 2006-07-11 18:20 ` brogoff 2006-07-12 0:37 ` Jacques Garrigue 0 siblings, 1 reply; 13+ messages in thread From: brogoff @ 2006-07-11 18:20 UTC (permalink / raw) To: Jacques Garrigue; +Cc: caml-list On Tue, 11 Jul 2006, Jacques Garrigue wrote: > From: brogoff <brogoff@speakeasy.net> > > > By the way, if you're ready to define your types first, then you > > > can do this properly. > > > > In the more realistic example I sent along after, you'll see that this > > solution is not really pleasing. You'd need to create a parallel type > > hierarchy to match your class hierarchy, which is too verbose. All this > > because we must have inference, which is supposed to make things less > > verbose. Ironic, isn't it? ;-) > > I'm not so sure about verbosity. Type syntax is pretty compact :-) But we have to repeat the information from the type in a later class, which seems redundant. Also, there's no way I know of to build object types from other object types, similar to the way I can combine polymorphic variant types. I haven't tried to encode it yet, maybe I'll try later, but I don't see how it can be made to work. > I'm sure you need some tricks to make it work in Java 1.5 too. The nastiest one for Caml is a downcast, when you want to extend the data the new class must call the extended visitor in its visit method. But Java supports this, so no big deal. Also, Java generics require that primitive types be wrapped, a mild annoyance. That's about it. Way easier than my attempts in OCaml, even though I don't use Java much at all. OK, to be fair, the original paper uses some Java variant (Pizza?) so maybe that's not too surprising. I wrote the code and it compiled, but I haven't tested it. > I don't have the code in mind. > I agree that the solution I posted is not too simple, but I don't > think this is PhD level. Actually it's not much worse than the visitor > pattern. What is hard is understanding why you have to do all this > extra work, not using the pattern itself. Sure, I exaggerated for affect, but I think the comparison with Java for this problem is telling. I'm reminded of something David MacQueen wrote in his paper "Should ML be Object Oriented" where he says in essence that the functional core of ML is lightweight and understandable but that OO (from the static typing POV) is surprisingly subtle and complex. > Note that, if you are ready to use a slightly less functional > approach, where the result is extracted from the visitor afterwards, > then typing is no problem. > This code is based on http://cristal.inria.fr/~remy/work/expr/ > It is strictly equivalent to Odersky&Zenger's Scala version. > (Actually this kind of code is one reason we reverted to sharing of > instance variables in 3.10) That's probably the right way to proceed, namely to eliminate the problem by eliminating the polymorphic methods. Too bad, the Java solution is both more functional, and more "typed". One of those rare cases for me where I feel that the Java solution is more elegant than the OCaml one. -- Brian ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Caml-list] Polymorphic method question 2006-07-11 18:20 ` brogoff @ 2006-07-12 0:37 ` Jacques Garrigue 2006-07-12 19:26 ` brogoff 0 siblings, 1 reply; 13+ messages in thread From: Jacques Garrigue @ 2006-07-12 0:37 UTC (permalink / raw) To: brogoff; +Cc: caml-list From: brogoff <brogoff@speakeasy.net> > > I'm sure you need some tricks to make it work in Java 1.5 too. > > The nastiest one for Caml is a downcast, when you want to extend the data > the new class must call the extended visitor in its visit method. But Java > supports this, so no big deal. Well, if you're ready to have downcasts in your code... But then, > > Note that, if you are ready to use a slightly less functional > > approach, where the result is extracted from the visitor afterwards, > > then typing is no problem. > > That's probably the right way to proceed, namely to eliminate the > problem by eliminating the polymorphic methods. Too bad, the Java > solution is both more functional, and more "typed". One of those > rare cases for me where I feel that the Java solution is more > elegant than the OCaml one. I would not say that your Java version is more "typed". It is less so if you have downcasts! By the way, the Scala version I mentioned uses no downcast, but cannot accomodate polymorphic methods (at least in the mentioned paper.) So there seems to be a tension between guaranteed type-safety and immutability. The point is that to solve it cleanly, one has to use type parameters in an abstract type. OCaml is able to do it, but I agree that this is rather verbose. [About having to write the type hierarchy by hand] > But we have to repeat the information from the type in a later class, > which seems redundant. Also, there's no way I know of to build object types > from other object types, similar to the way I can combine polymorphic variant > types. > > I haven't tried to encode it yet, maybe I'll try later, but I don't > see how it can be made to work. Indeed. At times I wonder whether it would not be better to have a syntax to do this with types. Or maybe not to infer parameter constraints for class types, as they are required for extensibility. Jacques Garrigue ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Caml-list] Polymorphic method question 2006-07-12 0:37 ` Jacques Garrigue @ 2006-07-12 19:26 ` brogoff 0 siblings, 0 replies; 13+ messages in thread From: brogoff @ 2006-07-12 19:26 UTC (permalink / raw) To: Jacques Garrigue; +Cc: caml-list On Wed, 12 Jul 2006, Jacques Garrigue wrote: > From: brogoff <brogoff@speakeasy.net> > > > I'm sure you need some tricks to make it work in Java 1.5 too. > > > > The nastiest one for Caml is a downcast, when you want to extend the data > > the new class must call the extended visitor in its visit method. But Java > > supports this, so no big deal. > > Well, if you're ready to have downcasts in your code... > But then, I'd hoped that there would be some trick I could figure out to remove the downcast, but it's essentially to overcome the lack of covariant method arguments (the visitor argument of the visited class) so yes it's a flaw in the approach. > I would not say that your Java version is more "typed". It is less so > if you have downcasts! Fair enough. However, the "typecase" that's being performed has only one branch, and is localized to the extending class, so as such crimes go, it's more like vandalism than arson. > [About having to write the type hierarchy by hand] > > But we have to repeat the information from the type in a later class, > > which seems redundant. Also, there's no way I know of to build object types > > from other object types, similar to the way I can combine polymorphic variant > > types. > > > > I haven't tried to encode it yet, maybe I'll try later, but I don't > > see how it can be made to work. > > Indeed. At times I wonder whether it would not be better to have a > syntax to do this with types. Or maybe not to infer parameter > constraints for class types, as they are required for extensibility. I think if we're going to do OO in an ML like language, I think it is probably more promising to consider a system like Dylan or CLOS. But that's a huge change, for a brand new language. I'd rather have a simpler language, with more powerful records, variants and module system. I usually use classes in OCaml as records anyways. -- Brian ^ permalink raw reply [flat|nested] 13+ messages in thread
* [Caml-list] polymorphic method question @ 2002-08-21 21:49 nadji 2002-08-21 22:57 ` Jacques Garrigue 0 siblings, 1 reply; 13+ messages in thread From: nadji @ 2002-08-21 21:49 UTC (permalink / raw) To: caml-list Hi, I am puzzled by this behaviour, can a guru explain me ? I have two classes class type ['a] basic = object method foo : 'a end;; class ['a] toto (a:'a) = object method foo = a method bar = () end;; I want to do a class gentoto : class gentoto = object method gen : 'a . 'a -> 'a basic = fun x -> (new toto x :> 'a basic ) end;; But the compiler complains that : Characters 64-98: fun x -> (new toto x :> 'a basic ) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This method has type 'a -> 'a basic which is less general than 'b. 'b -> 'b basic ... but if I do : let newtotoasbasic x = (new toto x :> 'a basic );; class gentoto = object method gen : 'a . 'a -> 'a basic = (* fun x -> (new toto x :> 'a basic ) *) newtotoasbasic end;; The compiler agrees with me ... What is wrong with the first declaration ? Thanks, Nadji ------------------- To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/ Beginner's list: http://groups.yahoo.com/group/ocaml_beginners ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Caml-list] polymorphic method question 2002-08-21 21:49 [Caml-list] polymorphic " nadji @ 2002-08-21 22:57 ` Jacques Garrigue 0 siblings, 0 replies; 13+ messages in thread From: Jacques Garrigue @ 2002-08-21 22:57 UTC (permalink / raw) To: nadji; +Cc: caml-list From: nadji@noos.fr > I am puzzled by this behaviour, can a guru explain me ? > I have two classes [...] > I want to do a class gentoto : > class gentoto = object > method gen : 'a . 'a -> 'a basic = > fun x -> (new toto x :> 'a basic ) > end;; > But the compiler complains that : > Characters 64-98: > fun x -> (new toto x :> 'a basic ) > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ > This method has type 'a -> 'a basic which is less general than > 'b. 'b -> 'b basic > > ... but if I do : > let newtotoasbasic x = (new toto x :> 'a basic );; [...] > The compiler agrees with me ... > What is wrong with the first declaration ? There is a problem with the scoping of named type variables in the language, which makes them incompatible with polymorphic methods. You can solve this by using anonymous variables: # class gentoto = object method gen : 'a . 'a -> 'a basic = fun x -> (new toto x :> _ basic) end;; class gentoto : object method gen : 'a -> 'a basic end Jacques Garrigue ------------------- To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/ Beginner's list: http://groups.yahoo.com/group/ocaml_beginners ^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2006-07-12 19:26 UTC | newest] Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2006-07-10 19:21 Polymorphic method question brogoff 2006-07-10 20:05 ` [Caml-list] " Richard Jones 2006-07-10 23:25 ` brogoff 2006-07-11 2:24 ` skaller 2006-07-11 4:56 ` brogoff 2006-07-11 2:09 ` Jacques Garrigue 2006-07-11 5:22 ` brogoff 2006-07-11 7:32 ` Jacques Garrigue 2006-07-11 18:20 ` brogoff 2006-07-12 0:37 ` Jacques Garrigue 2006-07-12 19:26 ` brogoff -- strict thread matches above, loose matches on Subject: below -- 2002-08-21 21:49 [Caml-list] polymorphic " nadji 2002-08-21 22:57 ` Jacques Garrigue
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox