FW: Packages must go

# Jeff Dyer (17 years ago)

For the purposes of the current ES4-WG discussion, here is a proposal to drop packages


At the last f2f Waldemar raised pertinent questions about whether the desugaring of packages (in their current form) into namespaces would work.

The answer appears to be, for the time being, no. One important problem, for example, is that packages appear to be scoped entities but are not. This fragment of code:

package P { public var x }

means exactly the same thing as this fragment:

package Q { } public var x

and that leads you into trouble when you start using import. Consider a third package R:

package R { external var x }

Now import R into P and Q and reference x:

package P { import R.*; public var x; ... x ... }

package Q { import R.*; ... x ... } public var x

Now the intent of the reference in Q is clearly meant to be to R.x, and the (outer) public::x should not be allowed to change that intent (consider that public::x is introduced in some later file, at a later time) while the most reasonable behavior for P is that x references public::x (it's in the same block as the reference, therefore "closer" or more obvious -- take your pick). The desired behavior is not the same in the two cases, yet the two fragments mean the same thing.

It's possible to construct even more fun examples with lexically nested import statements.

It may be possible to fix this by introducing arcane restrictions (consider flagging the reference to x in P as ambiguous) but not, probably, as a pure desugaring to namespaces, and even then it's not clear how useful the package abstraction would be.

As a consequence Jeff and I think we should remove packages from ES4 for the time being, instead of embarking on a design exercise without the benefit of practice. Concretely, we propose the following:

  • the 'package', 'import', and 'external' keywords and forms are removed from the language along with the dotted-name syntax for packages

  • the notion of top-level blocks (which was only required to model the desugaring) is removed from the language

  • "use default namespace" is allowed anywhere at the top level of the program and at the top level of class blocks (and its effect extends to the end of the program or class or until a new "use default namespace" pragma is seen)

  • "use namespace" is allowed anywhere at the top level of any block (including program and class blocks) and its effect extends to the end of the program or block

  • the keyword 'internal' persists, but its value is now an unforgeable namespace that is private to the compilation unit (script, file, etc).

The net effect is simplification and actually better integrity, since the file-private unforgeable namespace allows programs truly to hide definitions in a file. (Our "local package" mechanism provided something similar but that proposal appears to have fallen by the wayside.)

The mechanisms proposed above are sufficient to emulate simple packages a la Java. Consider an evaluator package that has a statement evaluator in one file and an expression evaluator in another:

// file 1 internal namespace PRIVATE = "eval private" internal namespace PUBLIC = "eval public" use namespace PRIVATE, namespace PUBLIC

PUBLIC function evaluate(t) evalStmt(t)

PRIVATE function evalStmt(t) ... evalExpr(t) ...

// file 2

internal namespace PRIVATE = "eval private" internal namespace PUBLIC = "eval public" use namespace PRIVATE, namespace PUBLIC

PRIVATE function evalExpr(t) ... evalStmt(t) ...

// file 3 (client)

namespace EVAL = "eval public" use namespace EVAL // import EVAL.*

print(evaluate(read()))

Perhaps, with some experience, a lightweight syntax could be added to ES4 to make that kind of evaluation simpler, but that's not what we're proposing at this time.

--lars

------ End of Forwarded Message