Previous week Up Next week

Hello

Here is the latest OCaml Weekly News, for the week of February 21 to 28, 2017.

  1. List of structurally typed objects
  2. mirage 3.0.0
  3. Ocaml Github Pull Requests
  4. Other OCaml News

List of structurally typed objects

Archive: https://sympa.inria.fr/sympa/arc/caml-list/2017-02/msg00119.html

Richard W. M. Jones asked:
Is it possible to construct a list of structurally typed ("duck
typed") objects?

The code below seems as if superficially it should work, at least as
far as I understand the OCaml memory model and how objects work
internally.  However the implementation doesn't match the interface.

------ list_fns.mli ----------------------------
type 'a obj = < hello : string; .. > as 'a
val register_obj : string -> 'a obj -> unit
val get_obj : string -> 'a obj
------------------------------------------------

------ list_fns.ml -----------------------------
type 'a obj = < hello : string; .. > as 'a
let objs = ref []
let register_obj name obj = objs := (name, obj) :: !objs
let get_obj name = List.assoc name !objs
------------------------------------------------

$ ocamlc -c list_fns.mli
$ ocamlc -c list_fns.ml
File "list_fns.ml", line 1:
Error: The implementation list_fns.ml
       does not match the interface list_fns.cmi:
       Values do not match:
         val register_obj : string -> '_a -> unit
       is not included in
         val register_obj : string -> < hello : string; .. > obj -> unit
       File "list_fns.ml", line 3, characters 4-16: Actual declaration

I'm guessing that "constraint" should be used here, but how?
      
Gabriel Scherer then replied and Richard Jones said:
> The signature you demand is actually incorrect, because the return
> type of get_obj is to permissive: it claims that it can return *any*
> ('a obj), so you could register an object with just the hello method
> and get back an object with more methods.
> 
> On the other hand, if you use the monomorphic < hello : string > type
> in the interface, then it is type-correct and the implementation you
> provide is accepted. It is explicit in the fact that you can't recover
> the extra methods of the object once they have been stored in this
> lowest-common-denominator container.

Ah, I see.

Modifying the code to use the monomorphic type works, but I have to
downcast the objects to the right type.  For reference, the working
code is below.

Thanks,

Rich.

list_fns.mli --------------------------------------------------------
type obj = < hello : string >
val register_obj : string -> obj -> unit
val get_obj : string -> obj

list_fns.ml ---------------------------------------------------------
type obj = < hello : string >
let objs = ref []
let register_obj name obj = objs := (name, obj) :: !objs
let get_obj name = List.assoc name !objs

test.ml -------------------------------------------------------------
class foo = object
  method hello = "hello from foo"
  method goodbye () = print_endline "goodbye"
end

class bar = object
  method hello = "hello from bar"
end

let () =
  let o1 = new foo in
  let o2 = new bar in
  List_fns.register_obj "o1" (o1 :> List_fns.obj);
  List_fns.register_obj "o2" (o2 :> List_fns.obj);
  print_endline ("calling o1: " ^ (List_fns.get_obj "o1")#hello);
  print_endline ("calling o2: " ^ (List_fns.get_obj "o2")#hello)
--------------------------------------------------------------------
      
Nicolás Ojeda Bär then suggested and Richard Jones replied:
> Note that you can still write < hello: string; .. > in the signature of
> register_obj and do the cast before adding your object to the list:
> 
>   let register_obj name obj = objs := (name, (obj :> < hello: string >)) ::
> !objs
> 
> This way you do not need to downcast at each call-site of register_obj.

Indeed, that will make my code simpler too.
      
Damien Guichard suggested, Richard Jones asked, and Ivan Gotovchits said:
Damien:
>> Is this the code you want ?
>>
>> type 'a obj_list = 'a list
>> constraint 'a = < hello : string; .. > as 'a

Richard:
> Perhaps. Is it possible to write the list_fns.mli interface
> using this?

Ivan:

It is possible to generalize this approach using private row types. 

list_fns.mli:

 module Registry(Obj : sig
 type t = private < .. >
 end) : sig
 val register_obj : string -> Obj.t -> unit
 val get_obj : string -> Obj.t
 end

list_fns.ml:

 module Registry(Obj : sig
 type t = private < .. >
 end) = struct

 let objs = ref []
 let register_obj name obj = objs := (name, obj) :: !objs
 let get_obj name = List.assoc name !objs
 end

test.ml:

 class foo = object
 method hello = "hello from foo"
 method goodbye () = print_endline "goodbye"
 end

 class bar = object
 method hello = "hello from bar"
 end

 module Bars = List_fns.Registry(struct type t = bar end)

 let () =
 let o1 = new foo in
 let o2 = new bar in
 Bars.register_obj "o1" (o1 :> bar);
 Bars.register_obj "o2" (o2 );
 print_endline ("calling o1: " ^ (Bars.get_obj "o1")#hello);
 print_endline ("calling o2: " ^ (Bars.get_obj "o2")#hello)

The List_fns.Registry functor will create a monomorphic registry for the
specified base type.

Probably, this may help you :)
      
Mikhail Mandrykin then added:
> It is possible to generalize this approach using private row types.

If at least a limited support for dynamic object typing is needed, it's also
possible to construct a heterogeneous container of objects using several
advanced features like first-class modules and GADT, but even in this case the
exact type of the object should match precisely when extracted from the list or
at least a finite (and small) number of possibilities for that type should be
known. It's, however, still possible to upcast the object to some supertype upon
addition and later extract and use it as the object of that supertype. An
example:
https://github.com/schrodibear/ocaml_tricks/blob/master/object_hlist/obj_list.ml
      

mirage 3.0.0

Archive: https://sympa.inria.fr/sympa/arc/caml-list/2017-02/msg00141.html

Mindy Preston announced:
It is my great pleasure to announce that Mirage version 3 has been released into
opam-repository. Allowing for the time necessary to sync `opam.ocaml.org`, you
should soon be able to upgrade to Mirage 3. You'll need to be using OCaml
version 4.03.0 or later.

For more information on what's in Mirage 3, check out the blog post at
https://mirage.io/blog/announcing-mirage-30-release . (There's also a version
hosted on the new Solo5 backend at
http://solo5.mirage.io/blog/announcing-mirage-30-release !)

We've prepared a porting guide at https://mirage.io/wiki/mirage2-to-mirage3 for
those of you want quick help getting your unikernels up and running in the new
universe. The introductory content at https://mirage.io/wiki/hello-world (and
https://github.com/mirage/mirage-skeleton , to which it refers) has also been
updated, if you're looking to get started with Mirage for the first time.


If you choose to use a pre-existing opam switch when upgrading to Mirage 3 from
Mirage 2, you may need to remove some roots that were previously autoinstalled
by `mirage configure` in version 2 before `opam upgrade` is willing to upgrade
you to Mirage 3.

If you were using the `mirage-dev` or `mirageos-3-beta` opam remotes, those are
no longer necessary.  `mirageos-3-beta` will be removed shortly, and
`mirage-dev` will have its packages cleared to make way for whatever next set of
staging packages is about to dazzle us.

Please let us know if you have any difficulties or questions :)
      
Anil Madhavapeddy then added:
And to the more experienced OCaml'ers, one of the more exciting aspects of
switching to a baseline of OCaml 4.03 is that we can finally start taking
advantage of new features such as flambda now. The executable part of a typical
Mirage unikernel is a set of functor applications that link in the relevant
device drivers, and so we're hoping to see a real performance and efficiency
benefits from the compiler.

So if you are interested in this sort of topic, we'd love to help you get
involved and to contribute. Many of the libraries (see http://docs.mirage.io)
can run just fine in a normal Linux or macos laptop, without requiring a
hypervisor, and the vast amount of development is using a normal OCaml
development environment.
      

Ocaml Github Pull Requests

Gabriel Scherer and the editor compiled this list:
Here is a sneak peek at some potential future features of the Ocaml
compiler, discussed by their implementers in these Github Pull Requests.

- Bidirectional type checking for applications by let-def
  https://github.com/ocaml/ocaml/pull/285
- Add single-line comments by let-def
  https://github.com/ocaml/ocaml/pull/671
- Add caml_startup_exn
  https://github.com/ocaml/ocaml/pull/953
- Add Pervasives.pi
  https://github.com/ocaml/ocaml/pull/964
- Deprecate Bigarray.*.map_file and add Unix.map_file
  https://github.com/ocaml/ocaml/pull/997
- Fix for PR7447: incorrect code generation for nested recursive bindings
  https://github.com/ocaml/ocaml/pull/995
- ocamldep: add -plugin and use compilerlibs to build
  https://github.com/ocaml/ocaml/pull/1015
- Add runtime functions for integer arithmetic with checked overflow
  https://github.com/ocaml/ocaml/pull/1060
- Add ?follow option to Unix.link
  https://github.com/ocaml/ocaml/pull/1061
- Extended indexing operators
  https://github.com/ocaml/ocaml/pull/1064
- Integrate findlib into compiler toolchain
  https://github.com/ocaml/ocaml/pull/1065
- Quoted string
  https://github.com/ocaml/ocaml/pull/1066
- Per type warn 4
  https://github.com/ocaml/ocaml/pull/1071
      

Other OCaml News

From the ocamlcore planet blog:
Here are links from many OCaml blogs aggregated at OCaml Planet,
http://ocaml.org/community/planet/.

10
 http://erratique.ch/contact.en

Moving from ocaml.io to ocamllabs.io
 https://ocaml.io/w/Blog:News/Moving_from_ocaml.io_to_ocamllabs.io
      

Old cwn

If you happen to miss a CWN, you can send me a message and I'll mail it to you, or go take a look at the archive or the RSS feed of the archives.

If you also wish to receive it every week by mail, you may subscribe online.


Alan Schmitt