* [Caml-list] Type That's Concrete From Within A Library Abstract From Without @ 2018-04-26 14:18 Jun Inoue 2018-04-26 14:27 ` Malcolm Matalka ` (2 more replies) 0 siblings, 3 replies; 13+ messages in thread From: Jun Inoue @ 2018-04-26 14:18 UTC (permalink / raw) To: caml list Dear list, Is there a way to make a type concrete inside a library, yet opaque to library users, preferably in a way that works with -pack? This is a nagging issue in our sundials package (http://inria-parkas.github.io/sundialsml/). Basically, we have a type declared in one module of the library that is pattern-matched upon in other modules, like: (* private.ml *) type opaque_type = Foo | Bar (* public.ml *) let f : opaque_type -> int = function | Foo -> 0 | Bar -> 1 There are a few constraints: - We don't want users to be able to pattern-match on opaque_type. - We need multiple modules in the library to pattern-match on opaque-type (so moving opaque_typ e to public.ml is not an option). - To avoid namespace pollution, we want to pack the whole library (with ocamlc -pack) as a single Sundials module, so the user sees a Sundials.Public module instead of just Public. Is this possible? Right now, we just collect public.cmo and private.cmo into sundials.cma and throw away private.cmi. But this doesn't work with packing: $ ocamlc -pack -o sundials.cmo private.cmo public.cmo demands that there be a private.cmi. -- Jun Inoue ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Caml-list] Type That's Concrete From Within A Library Abstract From Without 2018-04-26 14:18 [Caml-list] Type That's Concrete From Within A Library Abstract From Without Jun Inoue @ 2018-04-26 14:27 ` Malcolm Matalka 2018-04-26 15:03 ` Nicolás Ojeda Bär 2018-04-26 15:06 ` Ivan Gotovchits 2 siblings, 0 replies; 13+ messages in thread From: Malcolm Matalka @ 2018-04-26 14:27 UTC (permalink / raw) To: Jun Inoue; +Cc: caml list Jun Inoue <jun.lambda@gmail.com> writes: > Dear list, > > Is there a way to make a type concrete inside a library, yet opaque to > library users, preferably in a way that works with -pack? This is a > nagging issue in our sundials package > (http://inria-parkas.github.io/sundialsml/). > > Basically, we have a type declared in one module of the library that > is pattern-matched upon in other modules, like: > > (* private.ml *) > type opaque_type = Foo | Bar > > (* public.ml *) > let f : opaque_type -> int = function > | Foo -> 0 > | Bar -> 1 > Doesn't using .mli files do exactly what you want? (* public.mli *) type opaque_type val f : opaque_type -> int (* public.ml *) type opaque_type = Foo | Bar let f t = .... > There are a few constraints: > - We don't want users to be able to pattern-match on opaque_type. > - We need multiple modules in the library to pattern-match on > opaque-type (so moving opaque_typ e to public.ml is not an option). > - To avoid namespace pollution, we want to pack the whole library > (with ocamlc -pack) as a single Sundials module, so the user sees a > Sundials.Public module instead of just Public. > > Is this possible? Right now, we just collect public.cmo and > private.cmo into sundials.cma and throw away private.cmi. But this > doesn't work with packing: > > $ ocamlc -pack -o sundials.cmo private.cmo public.cmo > > demands that there be a private.cmi. > > -- > Jun Inoue ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Caml-list] Type That's Concrete From Within A Library Abstract From Without 2018-04-26 14:18 [Caml-list] Type That's Concrete From Within A Library Abstract From Without Jun Inoue 2018-04-26 14:27 ` Malcolm Matalka @ 2018-04-26 15:03 ` Nicolás Ojeda Bär 2018-04-26 15:14 ` Nicolás Ojeda Bär 2018-07-06 8:05 ` Timothy Bourke 2018-04-26 15:06 ` Ivan Gotovchits 2 siblings, 2 replies; 13+ messages in thread From: Nicolás Ojeda Bär @ 2018-04-26 15:03 UTC (permalink / raw) To: Jun Inoue; +Cc: caml list Dear Jun, This is a limitation of module packs. However, there is a much better alternative to module packs in the form of module aliases which will allow you to do what you want. You can head to https://caml.inria.fr/pub/docs/manual-ocaml/extn.html#sec249 for a more lengthy explanation, but briefly, in your example: 1. rename private.ml to sundials__private.ml and public.ml to sundials__public.ml 2. create a file sundials.ml with contents: module Private = Sundials__private module Public = Sundials__public 3. compile sundials.ml with ocamlc -no-alias-deps -c sundials.ml (you may want to disable warning 49 when doing this) 4. compile the individual files in the library with ocamlc -no-alias-deps -open Sundials -c sundials__private.ml ocamlc -no-alias-deps -open Sundials -c sundials__public.ml 5. You can now delete (or not install) sundials__private.cmi and ship the other files sundials.cmo sundials.cmi sundials__public.cmo sundials__public.cmi sundials__private.cmo to hide the private module from "outside" library users. Note that if you use jbuilder/dune, then your library will be built like this (steps 1-4) by default. Hope it helps, Best wishes, Nicolás On Thu, Apr 26, 2018 at 4:18 PM, Jun Inoue <jun.lambda@gmail.com> wrote: > Dear list, > > Is there a way to make a type concrete inside a library, yet opaque to > library users, preferably in a way that works with -pack? This is a > nagging issue in our sundials package > (http://inria-parkas.github.io/sundialsml/). > > Basically, we have a type declared in one module of the library that > is pattern-matched upon in other modules, like: > > (* private.ml *) > type opaque_type = Foo | Bar > > (* public.ml *) > let f : opaque_type -> int = function > | Foo -> 0 > | Bar -> 1 > > There are a few constraints: > - We don't want users to be able to pattern-match on opaque_type. > - We need multiple modules in the library to pattern-match on > opaque-type (so moving opaque_typ e to public.ml is not an option). > - To avoid namespace pollution, we want to pack the whole library > (with ocamlc -pack) as a single Sundials module, so the user sees a > Sundials.Public module instead of just Public. > > Is this possible? Right now, we just collect public.cmo and > private.cmo into sundials.cma and throw away private.cmi. But this > doesn't work with packing: > > $ ocamlc -pack -o sundials.cmo private.cmo public.cmo > > demands that there be a private.cmi. > > -- > Jun Inoue > > -- > Caml-list mailing list. Subscription management and archives: > https://sympa.inria.fr/sympa/arc/caml-list > Beginner's list: http://groups.yahoo.com/group/ocaml_beginners > Bug reports: http://caml.inria.fr/bin/caml-bugs ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Caml-list] Type That's Concrete From Within A Library Abstract From Without 2018-04-26 15:03 ` Nicolás Ojeda Bär @ 2018-04-26 15:14 ` Nicolás Ojeda Bär 2018-07-06 8:05 ` Timothy Bourke 1 sibling, 0 replies; 13+ messages in thread From: Nicolás Ojeda Bär @ 2018-04-26 15:14 UTC (permalink / raw) To: Jun Inoue; +Cc: caml list Sorry, I forgot the last step in my email, which is to create a cma with all the compilation units: ocamlc -a sundials*.cmo -o sundials.cma and install sundials.cma and the public *.cmi's as needed. Best wishes, Nicolás On Thu, Apr 26, 2018 at 5:03 PM, Nicolás Ojeda Bär <nicolas.ojeda.bar@lexifi.com> wrote: > Dear Jun, > > This is a limitation of module packs. However, there is a much better > alternative to module packs in the form of module aliases which will > allow you to do what you want. > > You can head to > https://caml.inria.fr/pub/docs/manual-ocaml/extn.html#sec249 for a > more lengthy explanation, but briefly, in your example: > > 1. rename private.ml to sundials__private.ml and public.ml to > sundials__public.ml > 2. create a file sundials.ml with contents: > > module Private = Sundials__private > module Public = Sundials__public > > 3. compile sundials.ml with > > ocamlc -no-alias-deps -c sundials.ml > > (you may want to disable warning 49 when doing this) > > 4. compile the individual files in the library with > > ocamlc -no-alias-deps -open Sundials -c sundials__private.ml > ocamlc -no-alias-deps -open Sundials -c sundials__public.ml > > 5. You can now delete (or not install) sundials__private.cmi and ship > the other files > > sundials.cmo > sundials.cmi > sundials__public.cmo > sundials__public.cmi > sundials__private.cmo > > to hide the private module from "outside" library users. > > Note that if you use jbuilder/dune, then your library will be built > like this (steps 1-4) by default. > > Hope it helps, > > Best wishes, > Nicolás > > On Thu, Apr 26, 2018 at 4:18 PM, Jun Inoue <jun.lambda@gmail.com> wrote: >> Dear list, >> >> Is there a way to make a type concrete inside a library, yet opaque to >> library users, preferably in a way that works with -pack? This is a >> nagging issue in our sundials package >> (http://inria-parkas.github.io/sundialsml/). >> >> Basically, we have a type declared in one module of the library that >> is pattern-matched upon in other modules, like: >> >> (* private.ml *) >> type opaque_type = Foo | Bar >> >> (* public.ml *) >> let f : opaque_type -> int = function >> | Foo -> 0 >> | Bar -> 1 >> >> There are a few constraints: >> - We don't want users to be able to pattern-match on opaque_type. >> - We need multiple modules in the library to pattern-match on >> opaque-type (so moving opaque_typ e to public.ml is not an option). >> - To avoid namespace pollution, we want to pack the whole library >> (with ocamlc -pack) as a single Sundials module, so the user sees a >> Sundials.Public module instead of just Public. >> >> Is this possible? Right now, we just collect public.cmo and >> private.cmo into sundials.cma and throw away private.cmi. But this >> doesn't work with packing: >> >> $ ocamlc -pack -o sundials.cmo private.cmo public.cmo >> >> demands that there be a private.cmi. >> >> -- >> Jun Inoue >> >> -- >> Caml-list mailing list. Subscription management and archives: >> https://sympa.inria.fr/sympa/arc/caml-list >> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners >> Bug reports: http://caml.inria.fr/bin/caml-bugs ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Caml-list] Type That's Concrete From Within A Library Abstract From Without 2018-04-26 15:03 ` Nicolás Ojeda Bär 2018-04-26 15:14 ` Nicolás Ojeda Bär @ 2018-07-06 8:05 ` Timothy Bourke 2018-07-06 8:52 ` Gabriel Scherer 1 sibling, 1 reply; 13+ messages in thread From: Timothy Bourke @ 2018-07-06 8:05 UTC (permalink / raw) To: Nicolás Ojeda Bär; +Cc: Jun Inoue, caml list [-- Attachment #1: Type: text/plain, Size: 966 bytes --] * Nicolás Ojeda Bär [2018-04-26 17:03 +0200]: >This is a limitation of module packs. However, there is a much better >alternative to module packs in the form of module aliases which will >allow you to do what you want. Thank you for this suggestion. We have tried it on a development branch of the Sundials/ML library and it works quite well. >4. compile the individual files in the library with > > ocamlc -no-alias-deps -open Sundials -c sundials__private.ml > ocamlc -no-alias-deps -open Sundials -c sundials__public.ml For the record, two details are worth noting regarding the "-open Sundials". 1. It works well with Merlin if one adds the line FLG -open Sundials to the .merlin file. 2. It does not work well with ocamldoc, which has no -open option. Maybe there is another way around this problem? In any case, there currently seem to be some other limitations around ocamldoc and module aliases. Tim. [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 488 bytes --] ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Caml-list] Type That's Concrete From Within A Library Abstract From Without 2018-07-06 8:05 ` Timothy Bourke @ 2018-07-06 8:52 ` Gabriel Scherer 2018-07-06 9:03 ` Timothy Bourke 0 siblings, 1 reply; 13+ messages in thread From: Gabriel Scherer @ 2018-07-06 8:52 UTC (permalink / raw) To: tim, Nicolas Ojeda Bar, Jun Inoue, caml users According to the OCaml changelog, ocamldoc support for -open was contributed by Florian Angeletti for OCaml 4.04, so it should be supported. (But indeed there may be other limitations around module aliases.) On Fri, Jul 6, 2018 at 10:08 AM Timothy Bourke <tim@tbrk.org> wrote: > > * Nicolás Ojeda Bär [2018-04-26 17:03 +0200]: > >This is a limitation of module packs. However, there is a much better > >alternative to module packs in the form of module aliases which will > >allow you to do what you want. > > Thank you for this suggestion. We have tried it on a development > branch of the Sundials/ML library and it works quite well. > > >4. compile the individual files in the library with > > > > ocamlc -no-alias-deps -open Sundials -c sundials__private.ml > > ocamlc -no-alias-deps -open Sundials -c sundials__public.ml > > For the record, two details are worth noting regarding the "-open > Sundials". > > 1. It works well with Merlin if one adds the line > > FLG -open Sundials > > to the .merlin file. > > 2. It does not work well with ocamldoc, which has no -open option. > Maybe there is another way around this problem? > > In any case, there currently seem to be some other limitations around > ocamldoc and module aliases. > > Tim. > ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Caml-list] Type That's Concrete From Within A Library Abstract From Without 2018-07-06 8:52 ` Gabriel Scherer @ 2018-07-06 9:03 ` Timothy Bourke 0 siblings, 0 replies; 13+ messages in thread From: Timothy Bourke @ 2018-07-06 9:03 UTC (permalink / raw) To: Gabriel Scherer; +Cc: Nicolas Ojeda Bar, Jun Inoue, caml users [-- Attachment #1: Type: text/plain, Size: 583 bytes --] * Gabriel Scherer [2018-07-06 10:52 +0200]: >According to the OCaml changelog, ocamldoc support for -open was >contributed by Florian Angeletti for OCaml 4.04, so it should be >supported. Thanks Gabriel (and Florian!). Sorry for missing that: the option is indeed shown by ocamldoc -h, but I only checked the man page where it is missing (Fix: https://github.com/ocaml/ocaml/pull/1887). >(But indeed there may be other limitations around module aliases.) We will use URLs for the time being, e.g., {{!Sundials_config.version}Sundials.Config.version}. Tim. [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 488 bytes --] ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Caml-list] Type That's Concrete From Within A Library Abstract From Without 2018-04-26 14:18 [Caml-list] Type That's Concrete From Within A Library Abstract From Without Jun Inoue 2018-04-26 14:27 ` Malcolm Matalka 2018-04-26 15:03 ` Nicolás Ojeda Bär @ 2018-04-26 15:06 ` Ivan Gotovchits 2018-04-27 5:48 ` Jun Inoue 2 siblings, 1 reply; 13+ messages in thread From: Ivan Gotovchits @ 2018-04-26 15:06 UTC (permalink / raw) To: Jun Inoue; +Cc: caml list [-- Attachment #1: Type: text/plain, Size: 2457 bytes --] Hi Jun, You can achieve this by implying an extra layer of indirection, i.e., by having two levels of interfaces. For example, * A.ml - implementation of module A * A.mli - private interface of module A * B.ml - implementation of module B that may rely on anything in A.mli * Std.ml - a set of modules that you would like to import, e.g., `module A = A`, `module B = B` * Std.mli - public interface specification Next, you deploy `std.cmxa` and `std.cmi` but keep `a.cmi` and `b.cmi` to yourself. This will prevent users from accessing your private modules A and B directly. (In oasis you can use PrivateModules stanza for this) Now you will have `Std.A` and `Std.B` that exposes as much as you want. Not sure whether it will work with the `-pack`, but you can use this approach instead of it. This is how we address the same issue in [BAP][1] Cheers, Ivan [1]: https://github.com/BinaryAnalysisPlatform/bap On Thu, Apr 26, 2018 at 10:18 AM, Jun Inoue <jun.lambda@gmail.com> wrote: > Dear list, > > Is there a way to make a type concrete inside a library, yet opaque to > library users, preferably in a way that works with -pack? This is a > nagging issue in our sundials package > (http://inria-parkas.github.io/sundialsml/). > > Basically, we have a type declared in one module of the library that > is pattern-matched upon in other modules, like: > > (* private.ml *) > type opaque_type = Foo | Bar > > (* public.ml *) > let f : opaque_type -> int = function > | Foo -> 0 > | Bar -> 1 > > There are a few constraints: > - We don't want users to be able to pattern-match on opaque_type. > - We need multiple modules in the library to pattern-match on > opaque-type (so moving opaque_typ e to public.ml is not an option). > - To avoid namespace pollution, we want to pack the whole library > (with ocamlc -pack) as a single Sundials module, so the user sees a > Sundials.Public module instead of just Public. > > Is this possible? Right now, we just collect public.cmo and > private.cmo into sundials.cma and throw away private.cmi. But this > doesn't work with packing: > > $ ocamlc -pack -o sundials.cmo private.cmo public.cmo > > demands that there be a private.cmi. > > -- > Jun Inoue > > -- > Caml-list mailing list. Subscription management and archives: > https://sympa.inria.fr/sympa/arc/caml-list > Beginner's list: http://groups.yahoo.com/group/ocaml_beginners > Bug reports: http://caml.inria.fr/bin/caml-bugs > [-- Attachment #2: Type: text/html, Size: 3843 bytes --] ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Caml-list] Type That's Concrete From Within A Library Abstract From Without 2018-04-26 15:06 ` Ivan Gotovchits @ 2018-04-27 5:48 ` Jun Inoue 2018-04-27 6:05 ` Jacques Garrigue 0 siblings, 1 reply; 13+ messages in thread From: Jun Inoue @ 2018-04-27 5:48 UTC (permalink / raw) To: Ivan Gotovchits; +Cc: caml list Hi Ivan, That's basically our current approach, but it doesn't solve the namespace pollution problem. In your example, when someone installs a file named b.cmi (whose interface is unrelated to your b.ml), the name conflict prevents loading the std.cma file at all: $ ocaml OCaml version 4.04.0 # #show B;; module B : sig val foo : int end # #load "std.cma";; The files std.cma and b.cmi disagree over interface B So the technique makes B inaccessible but doesn't remove it from the namespace. This is why we want to -pack things, because our analogue of b.ml is named matrix.ml, and there's no other sensible name for it. This technique doesn't work with -pack because that option demands all .cmi's, including b.cmi. I guess we could rename matrix.ml to matrix_internal_dont_touch.ml, but we wanted to know if there's a cleaner approach. I wish we could supply a .mli file to the product of -pack, but that also doesn't work... On Fri, Apr 27, 2018 at 12:06 AM, Ivan Gotovchits <ivg@ieee.org> wrote: > Hi Jun, > > You can achieve this by implying an extra layer of indirection, i.e., by > having two levels of interfaces. For example, > > * A.ml - implementation of module A > * A.mli - private interface of module A > * B.ml - implementation of module B that may rely on anything in A.mli > * Std.ml - a set of modules that you would like to import, e.g., `module > A = A`, `module B = B` > * Std.mli - public interface specification > > > Next, you deploy `std.cmxa` and `std.cmi` but keep `a.cmi` and `b.cmi` to > yourself. This will prevent users from accessing your private modules A and > B directly. (In oasis you can use PrivateModules stanza for this) > > Now you will have `Std.A` and `Std.B` that exposes as much as you want. Not > sure whether it will work with the `-pack`, but you can use this approach > instead of it. This is how we address the same issue in [BAP][1] > > Cheers, > Ivan > > [1]: https://github.com/BinaryAnalysisPlatform/bap > > > On Thu, Apr 26, 2018 at 10:18 AM, Jun Inoue <jun.lambda@gmail.com> wrote: >> >> Dear list, >> >> Is there a way to make a type concrete inside a library, yet opaque to >> library users, preferably in a way that works with -pack? This is a >> nagging issue in our sundials package >> (http://inria-parkas.github.io/sundialsml/). >> >> Basically, we have a type declared in one module of the library that >> is pattern-matched upon in other modules, like: >> >> (* private.ml *) >> type opaque_type = Foo | Bar >> >> (* public.ml *) >> let f : opaque_type -> int = function >> | Foo -> 0 >> | Bar -> 1 >> >> There are a few constraints: >> - We don't want users to be able to pattern-match on opaque_type. >> - We need multiple modules in the library to pattern-match on >> opaque-type (so moving opaque_typ e to public.ml is not an option). >> - To avoid namespace pollution, we want to pack the whole library >> (with ocamlc -pack) as a single Sundials module, so the user sees a >> Sundials.Public module instead of just Public. >> >> Is this possible? Right now, we just collect public.cmo and >> private.cmo into sundials.cma and throw away private.cmi. But this >> doesn't work with packing: >> >> $ ocamlc -pack -o sundials.cmo private.cmo public.cmo >> >> demands that there be a private.cmi. >> >> -- >> Jun Inoue >> >> -- >> Caml-list mailing list. Subscription management and archives: >> https://sympa.inria.fr/sympa/arc/caml-list >> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners >> Bug reports: http://caml.inria.fr/bin/caml-bugs > > -- Jun Inoue ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Caml-list] Type That's Concrete From Within A Library Abstract From Without 2018-04-27 5:48 ` Jun Inoue @ 2018-04-27 6:05 ` Jacques Garrigue 2018-04-27 8:53 ` Jun Inoue 0 siblings, 1 reply; 13+ messages in thread From: Jacques Garrigue @ 2018-04-27 6:05 UTC (permalink / raw) To: Jun Inoue; +Cc: Mailing List OCaml You can provide a mli for the -pack. Just compile it before. $ cat > a.ml type t = int let x : int = 3 $ cat > b.ml let x2 = A.x * A.x $ ocamlc -for-pack P a.ml b.ml $ cat > p.mli module A : sig type t val x : t end module B : sig val x2 : int end $ ocamlc -c p.mli $ ocamlc -pack -o p.cmo a.cmo b.cmo Now, if you use your library with only p.cmo and p.cmi available, you will only be able to access it through the interface you provided. Also, the method using module aliases can work too: you just have to use longer file names for the internal modules, to reduce the risk of conflicts. But this is more involved than using -pack with a mli. Jacques Garrigue On 2018/04/27 14:48, Jun Inoue wrote: > > Hi Ivan, > > That's basically our current approach, but it doesn't solve the > namespace pollution problem. In your example, when someone installs a > file named b.cmi (whose interface is unrelated to your b.ml), the name > conflict prevents loading the std.cma file at all: > > $ ocaml > OCaml version 4.04.0 > > # #show B;; > module B : sig val foo : int end > # #load "std.cma";; > The files std.cma and b.cmi disagree over interface B > > So the technique makes B inaccessible but doesn't remove it from the > namespace. This is why we want to -pack things, because our analogue > of b.ml is named matrix.ml, and there's no other sensible name for it. > > This technique doesn't work with -pack because that option demands all > .cmi's, including b.cmi. I guess we could rename matrix.ml to > matrix_internal_dont_touch.ml, but we wanted to know if there's a > cleaner approach. I wish we could supply a .mli file to the product > of -pack, but that also doesn't work... > > On Fri, Apr 27, 2018 at 12:06 AM, Ivan Gotovchits <ivg@ieee.org> wrote: >> Hi Jun, >> >> You can achieve this by implying an extra layer of indirection, i.e., by >> having two levels of interfaces. For example, >> >> * A.ml - implementation of module A >> * A.mli - private interface of module A >> * B.ml - implementation of module B that may rely on anything in A.mli >> * Std.ml - a set of modules that you would like to import, e.g., `module >> A = A`, `module B = B` >> * Std.mli - public interface specification >> >> >> Next, you deploy `std.cmxa` and `std.cmi` but keep `a.cmi` and `b.cmi` to >> yourself. This will prevent users from accessing your private modules A and >> B directly. (In oasis you can use PrivateModules stanza for this) >> >> Now you will have `Std.A` and `Std.B` that exposes as much as you want. Not >> sure whether it will work with the `-pack`, but you can use this approach >> instead of it. This is how we address the same issue in [BAP][1] >> >> Cheers, >> Ivan >> >> [1]: https://github.com/BinaryAnalysisPlatform/bap >> >> >> On Thu, Apr 26, 2018 at 10:18 AM, Jun Inoue <jun.lambda@gmail.com> wrote: >>> >>> Dear list, >>> >>> Is there a way to make a type concrete inside a library, yet opaque to >>> library users, preferably in a way that works with -pack? This is a >>> nagging issue in our sundials package >>> (http://inria-parkas.github.io/sundialsml/). >>> >>> Basically, we have a type declared in one module of the library that >>> is pattern-matched upon in other modules, like: >>> >>> (* private.ml *) >>> type opaque_type = Foo | Bar >>> >>> (* public.ml *) >>> let f : opaque_type -> int = function >>> | Foo -> 0 >>> | Bar -> 1 >>> >>> There are a few constraints: >>> - We don't want users to be able to pattern-match on opaque_type. >>> - We need multiple modules in the library to pattern-match on >>> opaque-type (so moving opaque_typ e to public.ml is not an option). >>> - To avoid namespace pollution, we want to pack the whole library >>> (with ocamlc -pack) as a single Sundials module, so the user sees a >>> Sundials.Public module instead of just Public. >>> >>> Is this possible? Right now, we just collect public.cmo and >>> private.cmo into sundials.cma and throw away private.cmi. But this >>> doesn't work with packing: >>> >>> $ ocamlc -pack -o sundials.cmo private.cmo public.cmo >>> >>> demands that there be a private.cmi. >>> >>> -- >>> Jun Inoue >>> >>> -- >>> Caml-list mailing list. Subscription management and archives: >>> https://sympa.inria.fr/sympa/arc/caml-list >>> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners >>> Bug reports: http://caml.inria.fr/bin/caml-bugs ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Caml-list] Type That's Concrete From Within A Library Abstract From Without 2018-04-27 6:05 ` Jacques Garrigue @ 2018-04-27 8:53 ` Jun Inoue 2018-04-27 10:40 ` Mikhail Mandrykin 2018-04-27 11:21 ` Elie Canonici Merle 0 siblings, 2 replies; 13+ messages in thread From: Jun Inoue @ 2018-04-27 8:53 UTC (permalink / raw) To: Jacques Garrigue; +Cc: Mailing List OCaml Hi Jacques, OCaml gives a type error if a public type in b.ml references a non-trivial type in a.ml. Is there a way around this? $ cat > a.ml type t = Foo of int let x : t = Foo 3 $ cat > b.ml type t = A.t let x2 = A.x $ cat > p.mli module B : sig type t = A.t val x2 : t end $ ocamlc -for-pack P -c a.ml b.ml $ ocamlc -c p.mli $ ocamlc -pack -o p.cmo a.cmo b.cmo File "_none_", line 1: Error: The implementation (obtained by packing) does not match the interface p.mli: In module B: Modules do not match: sig type t = A.t val x2 : A.t end is not included in sig type t = A.t val x2 : t end In module B: Type declarations do not match: type t = A.t is not included in type t = A.t On Fri, Apr 27, 2018 at 3:05 PM, Jacques Garrigue <garrigue@math.nagoya-u.ac.jp> wrote: > You can provide a mli for the -pack. > Just compile it before. > > $ cat > a.ml > type t = int > let x : int = 3 > $ cat > b.ml > let x2 = A.x * A.x > $ ocamlc -for-pack P a.ml b.ml > $ cat > p.mli > module A : sig type t val x : t end > module B : sig val x2 : int end > $ ocamlc -c p.mli > $ ocamlc -pack -o p.cmo a.cmo b.cmo > > Now, if you use your library with only p.cmo and p.cmi available, you will > only be able to access it through the interface you provided. > > Also, the method using module aliases can work too: you just have > to use longer file names for the internal modules, to reduce the risk of > conflicts. But this is more involved than using -pack with a mli. > > Jacques Garrigue > > On 2018/04/27 14:48, Jun Inoue wrote: >> >> Hi Ivan, >> >> That's basically our current approach, but it doesn't solve the >> namespace pollution problem. In your example, when someone installs a >> file named b.cmi (whose interface is unrelated to your b.ml), the name >> conflict prevents loading the std.cma file at all: >> >> $ ocaml >> OCaml version 4.04.0 >> >> # #show B;; >> module B : sig val foo : int end >> # #load "std.cma";; >> The files std.cma and b.cmi disagree over interface B >> >> So the technique makes B inaccessible but doesn't remove it from the >> namespace. This is why we want to -pack things, because our analogue >> of b.ml is named matrix.ml, and there's no other sensible name for it. >> >> This technique doesn't work with -pack because that option demands all >> .cmi's, including b.cmi. I guess we could rename matrix.ml to >> matrix_internal_dont_touch.ml, but we wanted to know if there's a >> cleaner approach. I wish we could supply a .mli file to the product >> of -pack, but that also doesn't work... >> >> On Fri, Apr 27, 2018 at 12:06 AM, Ivan Gotovchits <ivg@ieee.org> wrote: >>> Hi Jun, >>> >>> You can achieve this by implying an extra layer of indirection, i.e., by >>> having two levels of interfaces. For example, >>> >>> * A.ml - implementation of module A >>> * A.mli - private interface of module A >>> * B.ml - implementation of module B that may rely on anything in A.mli >>> * Std.ml - a set of modules that you would like to import, e.g., `module >>> A = A`, `module B = B` >>> * Std.mli - public interface specification >>> >>> >>> Next, you deploy `std.cmxa` and `std.cmi` but keep `a.cmi` and `b.cmi` to >>> yourself. This will prevent users from accessing your private modules A and >>> B directly. (In oasis you can use PrivateModules stanza for this) >>> >>> Now you will have `Std.A` and `Std.B` that exposes as much as you want. Not >>> sure whether it will work with the `-pack`, but you can use this approach >>> instead of it. This is how we address the same issue in [BAP][1] >>> >>> Cheers, >>> Ivan >>> >>> [1]: https://github.com/BinaryAnalysisPlatform/bap >>> >>> >>> On Thu, Apr 26, 2018 at 10:18 AM, Jun Inoue <jun.lambda@gmail.com> wrote: >>>> >>>> Dear list, >>>> >>>> Is there a way to make a type concrete inside a library, yet opaque to >>>> library users, preferably in a way that works with -pack? This is a >>>> nagging issue in our sundials package >>>> (http://inria-parkas.github.io/sundialsml/). >>>> >>>> Basically, we have a type declared in one module of the library that >>>> is pattern-matched upon in other modules, like: >>>> >>>> (* private.ml *) >>>> type opaque_type = Foo | Bar >>>> >>>> (* public.ml *) >>>> let f : opaque_type -> int = function >>>> | Foo -> 0 >>>> | Bar -> 1 >>>> >>>> There are a few constraints: >>>> - We don't want users to be able to pattern-match on opaque_type. >>>> - We need multiple modules in the library to pattern-match on >>>> opaque-type (so moving opaque_typ e to public.ml is not an option). >>>> - To avoid namespace pollution, we want to pack the whole library >>>> (with ocamlc -pack) as a single Sundials module, so the user sees a >>>> Sundials.Public module instead of just Public. >>>> >>>> Is this possible? Right now, we just collect public.cmo and >>>> private.cmo into sundials.cma and throw away private.cmi. But this >>>> doesn't work with packing: >>>> >>>> $ ocamlc -pack -o sundials.cmo private.cmo public.cmo >>>> >>>> demands that there be a private.cmi. >>>> >>>> -- >>>> Jun Inoue >>>> >>>> -- >>>> Caml-list mailing list. Subscription management and archives: >>>> https://sympa.inria.fr/sympa/arc/caml-list >>>> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners >>>> Bug reports: http://caml.inria.fr/bin/caml-bugs > > > -- Jun Inoue ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Caml-list] Type That's Concrete From Within A Library Abstract From Without 2018-04-27 8:53 ` Jun Inoue @ 2018-04-27 10:40 ` Mikhail Mandrykin 2018-04-27 11:21 ` Elie Canonici Merle 1 sibling, 0 replies; 13+ messages in thread From: Mikhail Mandrykin @ 2018-04-27 10:40 UTC (permalink / raw) To: Jun Inoue; +Cc: Jacques Garrigue, Mailing List OCaml Hello, > $ cat > p.mli > module B : sig type t = A.t val x2 : t end It seems it's the ambiguity between the "outer" and "packed" module A. Shadowing the outer A in p.mli fixes it: $ cat > p.mli module A : sig type t end (* t is abstract *) module B : sig type t = A.t val x2 : t end $ ocamlc -c p.mli $ ocamlc -pack -o p.cmo a.cmo b.cmo On 27.04.2018 11:53, Jun Inoue wrote: > Hi Jacques, > > OCaml gives a type error if a public type in b.ml references a > non-trivial type in a.ml. Is there a way around this? > > $ cat > a.ml > type t = Foo of int > let x : t = Foo 3 > $ cat > b.ml > type t = A.t > let x2 = A.x > $ cat > p.mli > module B : sig type t = A.t val x2 : t end > $ ocamlc -for-pack P -c a.ml b.ml > $ ocamlc -c p.mli > $ ocamlc -pack -o p.cmo a.cmo b.cmo > File "_none_", line 1: > Error: The implementation (obtained by packing) > does not match the interface p.mli: > In module B: > Modules do not match: > sig type t = A.t val x2 : A.t end > is not included in > sig type t = A.t val x2 : t end > In module B: > Type declarations do not match: > type t = A.t > is not included in > type t = A.t > > > On Fri, Apr 27, 2018 at 3:05 PM, Jacques Garrigue > <garrigue@math.nagoya-u.ac.jp> wrote: >> You can provide a mli for the -pack. >> Just compile it before. >> >> $ cat > a.ml >> type t = int >> let x : int = 3 >> $ cat > b.ml >> let x2 = A.x * A.x >> $ ocamlc -for-pack P a.ml b.ml >> $ cat > p.mli >> module A : sig type t val x : t end >> module B : sig val x2 : int end >> $ ocamlc -c p.mli >> $ ocamlc -pack -o p.cmo a.cmo b.cmo >> >> Now, if you use your library with only p.cmo and p.cmi available, you will >> only be able to access it through the interface you provided. >> >> Also, the method using module aliases can work too: you just have >> to use longer file names for the internal modules, to reduce the risk of >> conflicts. But this is more involved than using -pack with a mli. >> >> Jacques Garrigue >> >> On 2018/04/27 14:48, Jun Inoue wrote: >>> Hi Ivan, >>> >>> That's basically our current approach, but it doesn't solve the >>> namespace pollution problem. In your example, when someone installs a >>> file named b.cmi (whose interface is unrelated to your b.ml), the name >>> conflict prevents loading the std.cma file at all: >>> >>> $ ocaml >>> OCaml version 4.04.0 >>> >>> # #show B;; >>> module B : sig val foo : int end >>> # #load "std.cma";; >>> The files std.cma and b.cmi disagree over interface B >>> >>> So the technique makes B inaccessible but doesn't remove it from the >>> namespace. This is why we want to -pack things, because our analogue >>> of b.ml is named matrix.ml, and there's no other sensible name for it. >>> >>> This technique doesn't work with -pack because that option demands all >>> .cmi's, including b.cmi. I guess we could rename matrix.ml to >>> matrix_internal_dont_touch.ml, but we wanted to know if there's a >>> cleaner approach. I wish we could supply a .mli file to the product >>> of -pack, but that also doesn't work... >>> >>> On Fri, Apr 27, 2018 at 12:06 AM, Ivan Gotovchits <ivg@ieee.org> wrote: >>>> Hi Jun, >>>> >>>> You can achieve this by implying an extra layer of indirection, i.e., by >>>> having two levels of interfaces. For example, >>>> >>>> * A.ml - implementation of module A >>>> * A.mli - private interface of module A >>>> * B.ml - implementation of module B that may rely on anything in A.mli >>>> * Std.ml - a set of modules that you would like to import, e.g., `module >>>> A = A`, `module B = B` >>>> * Std.mli - public interface specification >>>> >>>> >>>> Next, you deploy `std.cmxa` and `std.cmi` but keep `a.cmi` and `b.cmi` to >>>> yourself. This will prevent users from accessing your private modules A and >>>> B directly. (In oasis you can use PrivateModules stanza for this) >>>> >>>> Now you will have `Std.A` and `Std.B` that exposes as much as you want. Not >>>> sure whether it will work with the `-pack`, but you can use this approach >>>> instead of it. This is how we address the same issue in [BAP][1] >>>> >>>> Cheers, >>>> Ivan >>>> >>>> [1]: https://github.com/BinaryAnalysisPlatform/bap >>>> >>>> >>>> On Thu, Apr 26, 2018 at 10:18 AM, Jun Inoue <jun.lambda@gmail.com> wrote: >>>>> Dear list, >>>>> >>>>> Is there a way to make a type concrete inside a library, yet opaque to >>>>> library users, preferably in a way that works with -pack? This is a >>>>> nagging issue in our sundials package >>>>> (http://inria-parkas.github.io/sundialsml/). >>>>> >>>>> Basically, we have a type declared in one module of the library that >>>>> is pattern-matched upon in other modules, like: >>>>> >>>>> (* private.ml *) >>>>> type opaque_type = Foo | Bar >>>>> >>>>> (* public.ml *) >>>>> let f : opaque_type -> int = function >>>>> | Foo -> 0 >>>>> | Bar -> 1 >>>>> >>>>> There are a few constraints: >>>>> - We don't want users to be able to pattern-match on opaque_type. >>>>> - We need multiple modules in the library to pattern-match on >>>>> opaque-type (so moving opaque_typ e to public.ml is not an option). >>>>> - To avoid namespace pollution, we want to pack the whole library >>>>> (with ocamlc -pack) as a single Sundials module, so the user sees a >>>>> Sundials.Public module instead of just Public. >>>>> >>>>> Is this possible? Right now, we just collect public.cmo and >>>>> private.cmo into sundials.cma and throw away private.cmi. But this >>>>> doesn't work with packing: >>>>> >>>>> $ ocamlc -pack -o sundials.cmo private.cmo public.cmo >>>>> >>>>> demands that there be a private.cmi. >>>>> >>>>> -- >>>>> Jun Inoue >>>>> >>>>> -- >>>>> Caml-list mailing list. Subscription management and archives: >>>>> https://sympa.inria.fr/sympa/arc/caml-list >>>>> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners >>>>> Bug reports: http://caml.inria.fr/bin/caml-bugs >> >> > > -- Mikhail Mandrykin Linux Verification Center, ISPRAS web: http://linuxtesting.org e-mail: mandrykin@ispras.ru ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Caml-list] Type That's Concrete From Within A Library Abstract From Without 2018-04-27 8:53 ` Jun Inoue 2018-04-27 10:40 ` Mikhail Mandrykin @ 2018-04-27 11:21 ` Elie Canonici Merle 1 sibling, 0 replies; 13+ messages in thread From: Elie Canonici Merle @ 2018-04-27 11:21 UTC (permalink / raw) To: Jun Inoue; +Cc: Mailing List OCaml [-- Attachment #1: Type: text/plain, Size: 6819 bytes --] Hi, Do you need to expose that B.t and A.t are the same? Because if you don't it works. $ cat > a.ml type t = Foo of int let x : t = Foo 3 $ cat > b.ml type t = A.t let x2 = A.x $ cat > p.mli module B : sig type t val x2 : t end $ ocamlc -for-pack P -c a.ml b.ml $ ocamlc -c p.mli $ ocamlc -pack -o p.cmo a.cmo b.cmo If you need to expose the type equality you can make it work by adding the signature of the module A while still keeping A.t abstract in p.mli (or not, depending on your needs) $ cat > a.ml type t = Foo of int let x : t = Foo 3 $ cat > b.ml type t = A.t let x2 = A.x $ cat > p.mli module A : sig type t end module B : sig type t = A.t val x2 : t end $ ocamlc -for-pack P -c a.ml b.ml $ ocamlc -c p.mli $ ocamlc -pack -o p.cmo a.cmo b.cmo I hope it helps. 2018-04-27 10:53 GMT+02:00 Jun Inoue <jun.lambda@gmail.com>: > Hi Jacques, > > OCaml gives a type error if a public type in b.ml references a > non-trivial type in a.ml. Is there a way around this? > > $ cat > a.ml > type t = Foo of int > let x : t = Foo 3 > $ cat > b.ml > type t = A.t > let x2 = A.x > $ cat > p.mli > module B : sig type t = A.t val x2 : t end > $ ocamlc -for-pack P -c a.ml b.ml > $ ocamlc -c p.mli > $ ocamlc -pack -o p.cmo a.cmo b.cmo > File "_none_", line 1: > Error: The implementation (obtained by packing) > does not match the interface p.mli: > In module B: > Modules do not match: > sig type t = A.t val x2 : A.t end > is not included in > sig type t = A.t val x2 : t end > In module B: > Type declarations do not match: > type t = A.t > is not included in > type t = A.t > > > On Fri, Apr 27, 2018 at 3:05 PM, Jacques Garrigue > <garrigue@math.nagoya-u.ac.jp> wrote: > > You can provide a mli for the -pack. > > Just compile it before. > > > > $ cat > a.ml > > type t = int > > let x : int = 3 > > $ cat > b.ml > > let x2 = A.x * A.x > > $ ocamlc -for-pack P a.ml b.ml > > $ cat > p.mli > > module A : sig type t val x : t end > > module B : sig val x2 : int end > > $ ocamlc -c p.mli > > $ ocamlc -pack -o p.cmo a.cmo b.cmo > > > > Now, if you use your library with only p.cmo and p.cmi available, you > will > > only be able to access it through the interface you provided. > > > > Also, the method using module aliases can work too: you just have > > to use longer file names for the internal modules, to reduce the risk of > > conflicts. But this is more involved than using -pack with a mli. > > > > Jacques Garrigue > > > > On 2018/04/27 14:48, Jun Inoue wrote: > >> > >> Hi Ivan, > >> > >> That's basically our current approach, but it doesn't solve the > >> namespace pollution problem. In your example, when someone installs a > >> file named b.cmi (whose interface is unrelated to your b.ml), the name > >> conflict prevents loading the std.cma file at all: > >> > >> $ ocaml > >> OCaml version 4.04.0 > >> > >> # #show B;; > >> module B : sig val foo : int end > >> # #load "std.cma";; > >> The files std.cma and b.cmi disagree over interface B > >> > >> So the technique makes B inaccessible but doesn't remove it from the > >> namespace. This is why we want to -pack things, because our analogue > >> of b.ml is named matrix.ml, and there's no other sensible name for it. > >> > >> This technique doesn't work with -pack because that option demands all > >> .cmi's, including b.cmi. I guess we could rename matrix.ml to > >> matrix_internal_dont_touch.ml, but we wanted to know if there's a > >> cleaner approach. I wish we could supply a .mli file to the product > >> of -pack, but that also doesn't work... > >> > >> On Fri, Apr 27, 2018 at 12:06 AM, Ivan Gotovchits <ivg@ieee.org> wrote: > >>> Hi Jun, > >>> > >>> You can achieve this by implying an extra layer of indirection, i.e., > by > >>> having two levels of interfaces. For example, > >>> > >>> * A.ml - implementation of module A > >>> * A.mli - private interface of module A > >>> * B.ml - implementation of module B that may rely on anything in > A.mli > >>> * Std.ml - a set of modules that you would like to import, e.g., > `module > >>> A = A`, `module B = B` > >>> * Std.mli - public interface specification > >>> > >>> > >>> Next, you deploy `std.cmxa` and `std.cmi` but keep `a.cmi` and `b.cmi` > to > >>> yourself. This will prevent users from accessing your private modules > A and > >>> B directly. (In oasis you can use PrivateModules stanza for this) > >>> > >>> Now you will have `Std.A` and `Std.B` that exposes as much as you > want. Not > >>> sure whether it will work with the `-pack`, but you can use this > approach > >>> instead of it. This is how we address the same issue in [BAP][1] > >>> > >>> Cheers, > >>> Ivan > >>> > >>> [1]: https://github.com/BinaryAnalysisPlatform/bap > >>> > >>> > >>> On Thu, Apr 26, 2018 at 10:18 AM, Jun Inoue <jun.lambda@gmail.com> > wrote: > >>>> > >>>> Dear list, > >>>> > >>>> Is there a way to make a type concrete inside a library, yet opaque to > >>>> library users, preferably in a way that works with -pack? This is a > >>>> nagging issue in our sundials package > >>>> (http://inria-parkas.github.io/sundialsml/). > >>>> > >>>> Basically, we have a type declared in one module of the library that > >>>> is pattern-matched upon in other modules, like: > >>>> > >>>> (* private.ml *) > >>>> type opaque_type = Foo | Bar > >>>> > >>>> (* public.ml *) > >>>> let f : opaque_type -> int = function > >>>> | Foo -> 0 > >>>> | Bar -> 1 > >>>> > >>>> There are a few constraints: > >>>> - We don't want users to be able to pattern-match on opaque_type. > >>>> - We need multiple modules in the library to pattern-match on > >>>> opaque-type (so moving opaque_typ e to public.ml is not an option). > >>>> - To avoid namespace pollution, we want to pack the whole library > >>>> (with ocamlc -pack) as a single Sundials module, so the user sees a > >>>> Sundials.Public module instead of just Public. > >>>> > >>>> Is this possible? Right now, we just collect public.cmo and > >>>> private.cmo into sundials.cma and throw away private.cmi. But this > >>>> doesn't work with packing: > >>>> > >>>> $ ocamlc -pack -o sundials.cmo private.cmo public.cmo > >>>> > >>>> demands that there be a private.cmi. > >>>> > >>>> -- > >>>> Jun Inoue > >>>> > >>>> -- > >>>> Caml-list mailing list. Subscription management and archives: > >>>> https://sympa.inria.fr/sympa/arc/caml-list > >>>> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners > >>>> Bug reports: http://caml.inria.fr/bin/caml-bugs > > > > > > > > > > -- > Jun Inoue > > -- > Caml-list mailing list. Subscription management and archives: > https://sympa.inria.fr/sympa/arc/caml-list > Beginner's list: http://groups.yahoo.com/group/ocaml_beginners > Bug reports: http://caml.inria.fr/bin/caml-bugs > [-- Attachment #2: Type: text/html, Size: 12775 bytes --] ^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2018-07-06 9:04 UTC | newest] Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2018-04-26 14:18 [Caml-list] Type That's Concrete From Within A Library Abstract From Without Jun Inoue 2018-04-26 14:27 ` Malcolm Matalka 2018-04-26 15:03 ` Nicolás Ojeda Bär 2018-04-26 15:14 ` Nicolás Ojeda Bär 2018-07-06 8:05 ` Timothy Bourke 2018-07-06 8:52 ` Gabriel Scherer 2018-07-06 9:03 ` Timothy Bourke 2018-04-26 15:06 ` Ivan Gotovchits 2018-04-27 5:48 ` Jun Inoue 2018-04-27 6:05 ` Jacques Garrigue 2018-04-27 8:53 ` Jun Inoue 2018-04-27 10:40 ` Mikhail Mandrykin 2018-04-27 11:21 ` Elie Canonici Merle
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox