Packages solve a lot of problems in Lisp. They not only allow you to modularize code, but also avoid problems like this: http://arclanguage.com/item?id=7701 and many more besides. I didn't like the idea of packages originally. As pg said in ANSI Common Lisp, people often get confused about packages, which suggests they aren't the right abstraction. It isn't easy to explain about maps from names to symbols, implicit interning, when two symbols are equal and so on. It's a very complex system, and everyone gets confused the first time (I know I did :) But they solve a lot of problems, especially tricky problems with macros, so I'm reconsidering them. I've come to realise that it's not packages that are the problem, but CL symbols. If you simplify symbols, then packages also become symbols. It's also possible to simplify packages a little bit, which also helps. To demonstrate, I'll explain how I'd like Arc packages to work. How Arc Packages Should Work ============================ A package should act like an implicit prefix for symbols. So if the current package is 'foo and you type in 'bar, Arc treats this as the symbol 'foo::bar. This is a full name of the symbol, while 'bar is the abbreviated name. A symbol can have multiple full names by importing it into different packages: (import 'foo::bar 'quux)
(is 'foo::bar 'quux::bar)
=> t
Every symbol has at least one full name (i.e. all symbols are interned somewhere). There is no #: syntax for accessing uninterned symbols, because they don't exist.Packages should be created when they're first used, just like symbols. For example 'quux::foo
creates a package called 'quux containing the symbol 'foo. There should also be an Arc equivalent of CL's 'in-package which can also create a package automatically, and can be used for modules.There should be no such thing as internal vs. external symbols. All symbols are accessed using :: (so that : can continue to be used for composition). There should also be no such thing as one package 'using' another. You just import the symbols you want, and hopefully the module creator will provide a nice list of symbols that you can pass to 'import to get all the symbols you need. There should be no such thing as 'make-symbol, as this would allow you to create uninterned symbols. To create a symbol from a string, use 'read, which already has the correct behaviour for creating interned symbols. Finally, instead of calling them packages, it would be better to call them prefixes, so that they don't sound like modules. As you can see, it's not difficult to understand or use packages this way. You don't have to worry about them being maps from names to symbols. You don't have to worry about what 'interning' is. You just treat them like prefixes. Gensyms ======= Gemsyms in Arc are always interned, so there is a possibility of them not being unique. Putting them in a different package would reduce the chance of this happening. Alternately, the 'gs package could be a special magic package where symbols always act like they are uninterned. (is 'foo::bar 'foo::bar)
=> t
(is 'gs::bar 'gs::bar)
=> nil
This could be explained by saying that gensyms aren't real symbols; they are special magic tokens that you can use instead of symbols, and are always unique. Note that you don't need to use #: to refer to these symbols, because the 'gs prefix tells you that they're uninterned.Obviously, implementing all this is very difficult, especially on Scheme, which is why I haven't even tried. But I think the benefits would be huge. What do you guys think? |