Apologies in advance for my ignorance, but is there some reference(s) you could point me to where the notion of "open recursion" is defined? I am pretty sure I understand "dynamic dispatch." -- Best, Zhenya On Fri, Feb 10, 2017 at 4:38 AM, Leo White wrote: > I think it would be more correct to say that you want open recursion. > Classes are the easiest way to get that in OCaml, and they indeed use > dynamic dispatch and inheritance, but there are other mechanisms that > provide open recursion. For example, most proposals for "mixin modules" > support open recursion but I wouldn't say they use dynamic dispatch. > > Regards, > > Leo > > On Thu, 9 Feb 2017, at 10:16 PM, Steffen Smolka wrote: > > Right....but you have to explicitly make that choice when you implement > `f`. With objects on the other hand, somebody may write a base > implementation c: > > class c = object(this) > method foo = ... this#bar ... > method bar = ... this#foo ... (* original definition *) > end > > Later on, somebody else may refine this implementation by overwriting > c#bar: > > class c2 = object(this) > inherit c > method bar = ... (* new definition *) > end > > Now c2#foo will invoke the new definition of bar, even though the author > of `c` may have never anticipated this (and did not have to account for > this possibility when he defined foo). > > So, I would say "dynamic dispatch" plus inheritance give you the ability > to extend modules in ways that weren't necessarily anticipated by the > original author of the module. And yet all the code written by the original > author will work with your extended version of the module. > > -- Steffen > > > > On Thu, Feb 9, 2017 at 9:01 PM, Yaron Minsky > wrote: > > I've always been a bit confused about what the term "dynamic dispatch" > means, but don't first class modules provide what you want? After all, > when you write: > > let f (module M : S) x = > M.g x > > the specific function M.g is determined dynamically, depending on > which first class module is passed into f. > > y > > On Thu, Feb 9, 2017 at 6:54 PM, Steffen Smolka > wrote: > > Yeah, I have seen that there is support for first class modules, that's > > pretty cool stuff! > > I do need dynamic dispatch, though. > > > > -- Steffen > > > > On Thu, Feb 9, 2017 at 6:37 PM, Gerd Stolpmann > > wrote: > >> > >> Am Donnerstag, den 09.02.2017, 18:19 -0500 schrieb Steffen Smolka: > >> > >> Thanks for the detailed answer, Jeremy! > >> > >> If you're keen to stick with objects > >> > >> > >> Yes, I rely on inheritance and dynamic dispatch for what I have in mind. > >> (This is actually the first time I'm touching the dark object oriented > side > >> of OCaml :) ) > >> > >> To give some more context, I am refactoring some code that uses modules > >> and no objects. The reason I want to move to objects is that I want to > >> derive a slightly enhanced module from some base implementation. > Inheritance > >> + dynamic dispatch allow me to do so with very little trouble: I can > simply > >> overwrite a few methods from the base implementation. > >> > >> I suppose I could achieve the same by turning the base module into a > >> functor, and abstracting over the functions that my enhanced > implementation > >> needs to replace. I think it won't be quite as natural, but I'll give > that a > >> try. > >> > >> > >> First-class modules could also be an option: Let's assume both the base > >> module and the modified one can use the same module type: > >> > >> module T = sig ... end > >> > >> Now, define the base module like > >> > >> module Base : T = > >> ... > >> end > >> > >> then, define the modified one: > >> > >> module Mod : T = > >> include Base > >> ... now override what you need to change but note that there's no > >> dynamic dispatch ... > >> end > >> > >> Of course, you could also use functors for making these modules. > >> > >> Now turn this into first-class modules and pass them around: > >> > >> let base = (module Base : T) > >> let mod = (module Mod : T) > >> > >> The syntax for unpacking the module is quite cumbersome: > >> > >> let module M = (val base : T) in > >> M.function ... > >> > >> Unfortunately, there's nothing simple like base.function. > >> > >> Compared with objects you get: > >> > >> You can also put types and (to some degree) modules into these "code > >> containers" > >> However, there's no dynamic dispatch except you arrange explicitly for > >> that, e.g. with references to functions > >> Generally, a heavier syntax, but it might be ok > >> > >> > >> Gerd > >> > >> > >> > >> Or you could select the encoding using a variant type: > >> > >> > >> Good idea, and I'm happy with the syntax for the caller. But I'm more > >> concerned with the organization of the code; this would mix the Latin1 > and > >> Utf8 implementations. I would rather keep them separate. > >> > >> -- Steffen > >> > >> > >> On Thu, Feb 9, 2017 at 5:55 PM, Jeremy Yallop wrote: > >> > >> Dear Steffen, > >> > >> On 9 February 2017 at 20:36, Steffen Smolka > wrote: > >> > Is it possible to create namespaces inside an object? Concretely, I > >> > would > >> > like to write > >> > > >> > class buffer = object(self) > >> > ... > >> > method get = ... > >> > > >> > module Latin1 = struct > >> > method get = ... > >> > end > >> > > >> > module Utf8 = struct > >> > method get = ... > >> > end > >> > end > >> > > >> > so that given an object b : buffer, I can call methods > >> > b#get > >> > b#Latin1.get > >> > b#Utf8.get > >> > >> It's possible to achieve something like this using methods that return > >> objects. If your nested objects don't need to access the internal > >> state of the parent then you might write it like this: > >> > >> class buffer = > >> let latin1 = object > >> method get = ... > >> end > >> and utf8 = object > >> method get = ... > >> end in > >> object(self) > >> ... > >> method get = ... > >> method latin1 = latin1 > >> method utf8 = utf8 > >> end > >> > >> With this approach you can write > >> > >> b#get > >> b#latin1#get > >> b#utf8#get > >> > >> which, apart from some minor orthographic differences, looks like what > >> you were aiming for. > >> > >> Your intuition that this isn't really idiomatic OCaml is right, > >> though. In OCaml, unlike some other languages with classes and > >> objects, classes are not usually used as namespaces; method names are > >> globally (or, rather, "ambiently") scoped, and there's no real support > >> for the kind of nesting that you're interested in. Instead, people > >> typically build nested namespaces using modules: > >> > >> module Buffer = > >> struct > >> let get = ... > >> > >> module Latin1 = struct > >> let get = ... > >> end > >> > >> module Utf8 = struct > >> let get = ... > >> end > >> end > >> > >> With the module approach you write the 'receiver' after the 'method' > >> rather than before, but that doesn't seem like a huge hardship. (10% > >> of the world manages to get by with VSO languages.) > >> > >> Buffer.get b ... > >> Buffer.Latin1.get b ... > >> Buffer.Utf8.get b ... > >> > >> If you're keen to stick with objects there are slightly more idiomatic > >> ways to make it work. You could, of course, replace the '.' with a > >> '_' and define methods 'latin1_get', 'utf8_get' in place of > >> 'Latin1.get', 'Utf8.get'. Or you could select the encoding using a > >> variant type: > >> > >> type enc = Latin1 | Utf8 > >> > >> class buffer = > >> object (self) > >> method get = function > >> | Latin1 -> ... > >> | Utf8 -> ... > >> end > >> > >> Of course, the order of the words in an invocation changes again, but > >> there's no real increase in complexity for the caller: > >> > >> b#get Latin1 > >> b#get Utf8 > >> > >> This last approach can be taken quite far -- for example, you could > >> enrich the type 'enc' so that the return type of 'get' varies > >> according to the encoding. > >> > >> Kind regards, > >> > >> Jeremy > >> > >> > >> -- > >> ------------------------------------------------------------ > >> Gerd Stolpmann, Darmstadt, Germany gerd@gerd-stolpmann.de > >> My OCaml site: http://www.camlcity.org > >> Contact details: http://www.camlcity.org/contact.html > >> Company homepage: http://www.gerd-stolpmann.de > >> ------------------------------------------------------------ > >> > > > > >