This site is a static rendering of the Trac instance that was used by R7RS-WG1 for its work on R7RS-small (PDF), which was ratified in 2013. For more information, see Home.

Ticket 520: A library with no export declarations should export everything

2013-07-07 03:20:44
WG1 - Core
alexshinn
major
cowan
wontfix
source
closed
2013-05-13 15:59:37
defect

Mikael More writes:

There is no description in the spec of what a library exports if it has no export library declaration, and this could very well be interpreted as something else than that in this case, all of the library's identifiers should be exported.

Rationale: For (library) exports, an export-all by default approach is of value in many incremental development situations.

To give an example, a Tetris game, with rendering, keyboard input, and other libraries. The basic idea is that, as the programmer adds modules to the code project and imports them incrementally into the Scheme environment, it is implicit that every new identifier the programmer defines in a module should be exported to all of its dependencies; The library abstraction is used as a means for subdivision/modularization/separation of code only and the code project is so small that there cannot possibly be any unexpectable identifier/export collision to talk about.

A requirement to explicitly export symbols though, would require the programmer to add this as an extra consideration which is strictly speaking unnecessary, and would provide a clear incentive for the programmer to replace the spec-provided library functionality with a custom one; this would be an involvement of unnecessary complexity, and would also decrease the generality of the spec-provided library functionality so much that a less general name for its |import| form, such as |import-library|, would be really relevant to consider.

I would suggest that the R7RS Library syntax should be intended to deliver for incremental development also, as this appears like the most holistic approach - the Library syntax describe a mechanism for subdivision/modularization of code as it is already, so it would make sense for it to be intended also for this use. Therefore:

Suggestion: I'd suggest that a clarification is added to the spec that all identifiers are exported by default, so that that is the effect absence of an export library declaration has. A library that wants not to export any identifiers specify an export library declaration that lists no libraries, i.e. (export) .

The intention is that if nothing is mentioned in an export library declaration, nothing is exported. Such libraries can be imported solely for their side effects.

Ticket #402 proposed (export-all), though not the interpretation of no export declarations. In WG1Ballot6Results, the WG narrowly decided not to have (export-all) in the small language, on the grounds that it was an additional unnecessary complication, and that it was good discipline to export only what is explicitly mentioned. One member did bring up the idea of exporting all when no declarations are present, and rejected it as violating the Law of Least Astonishment.

In addition, the question was raised whether (export-all) should export what is imported as well as what is defined. There is a use case for both interpretations, analogous to public vs. private inheritance in C++. It's not clear which version this proposal intends, though I'd guess that it's meant to export only what is defined.

_comment0I agree that magically exporting all violates the Law of Least Astonishment, and so I rejecdt this option. I have, however, proposed `export-all` and `reexport` library declarations as a mandatory WG2 extension: see LibraryDeclarationsCowan for details. In my (still very limited) experience at writing R7RS libraries, however, I find that I almost never do want to export ''everything'', other than in the situation of extending a library (which is what `reexport` is for). For one thing, there is generally at least one new record type in each of my libraries, and I usually want to wrap the raw setters and the raw constructor in procedures that check their arguments for type and/or other things; similarly, I often want procedures that don't verify their invariants because I know they will only be called from other procedures that do verify them. In both cases, hiding the raw versions is crucial to safety. Given that in some libraries exporting may be more frequent than hiding, an alternative to `export-all` would be an `export-all-except` declaration. Such a declaration would be brittle: one would have to be careful, when adding new private procedures, to add them to the `export-all-except` list as well, and the compiler would provide no support for doing so. By contrast, if you forget to export something, you find out as soon as you run a proper set of tests that imports the library.1369075080517197

I agree that magically exporting all violates the Law of Least Astonishment, and so I reject this option. I have, however, proposed export-all and reexport library declarations as a mandatory WG2 extension: see LibraryDeclarationsCowan for details.

In my (still very limited) experience at writing R7RS libraries, however, I find that I almost never do want to export everything, other than in the situation of extending a library (which is what reexport is intended for). For one thing, there is generally at least one new record type in each of my libraries, and I usually want to wrap the raw setters and the raw constructor in procedures that check their arguments for type and/or other things; similarly, I often want procedures that don't verify their invariants because I know they will only be called from other procedures that do verify them. In both cases, hiding the raw versions is crucial to safety.

Given that in some libraries exporting may be more frequent than hiding, an alternative to export-all would be an export-all-except declaration. Such a declaration would be brittle: one would have to be careful, when adding new private procedures, to add them to the export-all-except list as well, and the compiler would provide no support for doing so. By contrast, if you forget to export something, you find out as soon as you run a proper set of tests that imports the library.

resolutionwontfix
statusnewclosed

The WG decided by unanimous consent to take no action on this ticket.