Author: Per Gustafsson Status: Draft Type: Standards Track Created: 10-Aug-2007 Erlang-Version: R12B-0 Post-History: **** EEP 5: More Versatile Encapsulation with `export_to` ---- Abstract ======== This EEP describes a new directive called `export_to` which allows a module to specify exactly which other modules that can call a function defined in the module. This provides a very fine grained primitive for encapsulation. Allowing the programmer to control more directly how his code should be used. This is an idea originally proposed by Richard O'Keefe. Specification ============= This is the syntax for the `export_to` directive: -export_to(m,[f/a]) where `f` is the name of a function of arity `a` and `m` is a module. (Perhaps we should allow a list of modules) This means that the function `f/a` can be called from the module `m`. Whether the call is a static call, dynamic call or an apply should not matter. In addition these functions should act as exported functions to the rest of the world i.e. calls to these functions should always be to the latest version of the function. Motivation ========== The module in Erlang have several roles. It is the unit of compilation and code reloading. It is also the unit of encapsulation, because the only way to hide a function from being called by any other function is to make it a local function in a module. The module also defines a separate namespace for functions. This wealth of roles for the module makes it difficult to structure erlang applications in a way that makes them well encapsulated while keeping modules small and focused. Most applications written in Erlang consists of several smaller modules, and though the application has a public API which is a subset of the exported functions of the modules, exactly which functions that are part of the public API can only be specified in comments or documentation since functions are either exported so that anyone can call them, or not exported meaning that they can only be called inside the module, but sometimes we want to have more control than this e.g. this function should only be called from other modules in this application, or this function should only be called from the shell. The `export_to` directive gives the programmer the possibility to express such restrictions that the runtime system then enforces. It should be noted that the `export_to` directive is not meant to replace the export directive, but to be an alternative in the case when the programmer knows all possible collaborators. Rationale ========= There are some choices in designing the `export_to` syntax for example should m be allowed to be a list of modules or should we have an `export_to` list where each entry is a module, function/arity pair. One reason to use the suggested syntax is that it reads pretty easily as: export to module `m` this list of functions `[f/a]` Another issue is whether we should have some syntactic sugar for specifying common export patterns e.g. exporting a set of functions to all the modules in an application or exporting a function in order to make it possible to apply the function or to make it possible to update the code of the function. Discussions about such changes is outside the scope of this EEP, we only note that the `export_to` directive makes a good building block for creating such extensions without having to change the Erlang runtime. Backwards Compatibility ======================= Adding an `export_to` directive should be totally backwards compatible. Since writing such a directive now causes a syntax error since it is not a legal attribute. Implementation ============== This feature has not been implemented yet, but here are some goals that we think the implementation should fulfill: * Ordinary static calls to an `export_to` function should cost the same as calls to other exported functions * The performance of other calls should not be affected by the introduction of `export_to` calls This can be archived by putting most of the machinery to handle this feature in to the loader and only use dynamic checks for dynamic calls. [EmacsVar]: <> "Local Variables:" [EmacsVar]: <> "mode: indented-text" [EmacsVar]: <> "indent-tabs-mode: nil" [EmacsVar]: <> "sentence-end-double-space: t" [EmacsVar]: <> "fill-column: 70" [EmacsVar]: <> "coding: utf-8" [EmacsVar]: <> "End:"