Reason: "open fields" feature

Created on 24 Nov 2016  路  5Comments  路  Source: reasonml/reason

Opening of modules brings in too much into scope. In addition to the other proposals to create a lighter weight "import" mechanism for specific values (there's another issue for that), it would also be nice to have an "import fields" feature which brings in only the variant and record field labels of a module. You can try to achieve this by creating nested modules just for the type definitions, but it doesn't quite do what you want:

/* MyModule.re */
module Types = {
  type layout = {
    left: unitOfM,
    top: unitOfM,
    right: unitOfM,
    bottom: unitOfM,
  };
};
open Types;
let myValue = "hi";

/* YourModule.re */
open MyModule.Types;
/* Nice, we can see the labels and not `myValue` */
let x = {left: 0, right: 0, bottom: 0, top: 0};
/* Hmm, this sucks, we can see the type name */
type x = layout;

Feature:

  • Allow importing only the labels/variant tags from a module without bringing in any values or type definitions.
  • Without requiring people to group their record/variant type definitions into a Types module.
  • Make this automatic.

One proposal:

/* MyModule.re */
type layout = {
  left: unitOfM,
  top: unitOfM,
  right: unitOfM,
  bottom: unitOfM,
};
let myValue = "hi";

/* YourModule.re */
import fields MyModule;
/* Nice, we can see the labels and not `myValue` */
let x = {left: 0, right: 0, bottom: 0, top: 0};
/* Awesome, not this will fail because we can't see the type definition either! */
/* type x = layout; */

Not yet answered: How this plays with .rei/.re files. Also, how does that change when we create a way for .re to pose as .rei.

RFC

Most helpful comment

@Schmavery That creates an alias for the type but it doesn't bring the constructors for the type into scope.

In OCaml:

module Foo = struct
  type t =
    | A
    | B
end

type foo = Foo.t
(* A and B are still not directly in scope, even though foo is an alias for Foo.t now *)

All 5 comments

In that proposal, you can in one shot bring in all the fields of all the records and variants defined in MyModule. But perhaps a better solution is more granular import of a single type's fields. It could be unified with a more general import syntax:

/* MyModule.re: */
type layout = {
  left: unitOfM,
  top: unitOfM,
  right: unitOfM,
  bottom: unitOfM,
};
let myValue = "hi";


/* YourModule.re: */
/* This would let you see the type name and its record fields */
import {type layout} from MyModule;
import {type layout, myValue} from MyModule;


/* Then you could import only the labels/fields if you wanted to,
 * by saying you want to *import* the *import* of a type.
 * This isn't quite that useful once we have full granularity of import */
import {import type layout} from MyModule;

/* Note: I'm using a destructing syntax for import */

https://github.com/whitequark/ppx_import is available for some inspiration if it helps.

Is this different than something like type layout = MyModule.layout? Just trying to understand, since I didn't see that called out here.

@Schmavery That creates an alias for the type but it doesn't bring the constructors for the type into scope.

In OCaml:

module Foo = struct
  type t =
    | A
    | B
end

type foo = Foo.t
(* A and B are still not directly in scope, even though foo is an alias for Foo.t now *)

see also #627

Was this page helpful?
0 / 5 - 0 ratings

Related issues

gustavopinto picture gustavopinto  路  3Comments

ostera picture ostera  路  3Comments

bobzhang picture bobzhang  路  3Comments

shaneosullivan picture shaneosullivan  路  3Comments

aaronshaf picture aaronshaf  路  3Comments