reason
reason copied to clipboard
ppx_export mark 2
taking over from https://github.com/facebook/reason/pull/1206
The purpose of this is to allow you to "export" values from your .re (or .ml) file directly, instead of going through a separate .mli file. I personally think this will be more usable, and in any case it will be more familiar to people coming from javascript.
We first implement it as a ppx, and then we can put some syntactic sugar (like an export keyword) in our reason parser to make it even more ergonomic.
work remaining
- [x] basic things
- [x] classes
- [x] nested modules
- [x] recursive modules
- [x] good error reporting
- [x] various cleanups
- [x] export as & abstract type export
for example, you can do
let[@export] something: int = 5
let[@export] somefun (arg: int): string = "hello"
type[@export abstract] t = int
let[@export: t list] m = [2;3]
(* you can put an aribtrary signature in here too if you want more power*)
let[@export: val mm: int] mm = something
helpful documents for putting this together
- https://github.com/ocaml/ocaml/blob/trunk/parsing/ast_helper.mli
- https://github.com/ocaml/ocaml/blob/trunk/parsing/parsetree.mli
- https://caml.inria.fr/pub/docs/manual-ocaml/extn.html#attr-payload
One can export the whole type, or a more abstract version. Is this supported already? It's not crucial that this is supported in the first iteration, but to know that it's possible to extend it in future.
For example, here I'm just using modules directly for illustration, but imagine there are .re and .rei files, and a user of the .rei:
module M : { type t; let create : int => t; } = { type t = int; let create n => n };
then this shows that the type is hidden:
# M.create 34 == 34;
Error: This expression has type int but an expression was expected of type M.t
exporting a more abstracted version is not yet supported. I could imagine using an attribute w/ an "export type" to do that kind of thing, but yeah I think that should come as a separate diff. I'm thinking
module%export M = {
[@export `abstract]
type t = int;
[@export () => t]
let create () => 23
}
or something
Specifying an export level sounds like a promising direction.
In general, there can be many possible levels.
Consider for example the concrete type type mylist = list int, then possible exports include
1. list int
2. list t
3. t
4. no export at all
Would it be too hard to add "export as" in this diff? I'd be concerned that people are all too satisfied without the exporting as "abstract" feature because they are't used to having that capability, and then it never gets added - and then using the "exports" feature is inferior to using interface files. I think we should make it every bit just as good out of the gate. I'm finding that developers don't ask for abstract types, but they desperately need them.
Good idea
hmmm don't merge yet, I have a different idea
Ok, "export as" working across the board! You can now do, for example
type[@export abstract] t = int
let[@export: t] myvar = 10
Looks like some failures on 4.02.3 and 4.04. The 4.02.3 failures might be related to the ppx form we just discussed. Maybe you can use the equivalent syntactic form that would work on all versions. I'm not sure about the 4.04 failures though - looks more like slight differences in printing output.
Also, @let-def can you take a look at the changes too?
yeah, I'm not quite sure how I ought to fix the "ocaml 4.04 prints this a little differently"
could you not just do export let ... that seems simpler, and would also be more familiar to newcommers.
The proposal https://www.cl.cam.ac.uk/~jdy22/papers/extending-ocamls-open.pdf by @objmagic makes it possible to implement this feature with proper support from the compiler.
In particular, it makes it possible to use the compiler infrastructure for finding names that are valid from the outside (e.g. assuming private type t = int -> int and exported let f : t = fun x -> x + 1, the compiler will rewrite the binding from val f : t to val f : int -> int)
Thanks @let-def. The actual patch still needs some polish. And assuming if people are in favor of merging this feature into compiler, you probably will see it in >4.06 since I imagine the PR will go through a pretty long debate... ("looks ok to me" from Xavier, seems ok from Alain Frisch, neutral from Jacques and Leo)
That said, if people are in serious need of this ppx_export, continue working on this feature instead of waiting support from OCaml language is a better idea.
open extension pull request was just opened at https://github.com/ocaml/ocaml/pull/1506
That change ended up in 4.08, so as soon as the 4.08 PR gets merged this might be relevant again?