From: Carlos P.
Subject: Avoiding name clashes
Date: 
Message-ID: <453d10b2.0203241019.a1602c7@posting.google.com>
Hi!

I'm working in a medium-sized project using Common Lisp (particularly CLisp).
The code is relatively low-level with heavy use of structs and functions
to manipulate them but almost no use of classes. There are about 15/20 files
and, except for a few of them, the dependencies between the other are strong
enough to justify giving every one full access to the "public" symbols of the
rest in a simple way (I mean, not listing a lot of exported symbols or,
similarly, a lot of imported ones). But, as there is also a lot of auxiliary
machinery (functions, macros, structs, variables, etc) that is logically
local to each module/file I wouldn't like to make everything visible from
outside in order to avoid name clashes. One of the solutions that came
to my mind was using anonymous packages (automatically generated by a macro)
which import everything in the main package (the package where every module
is and from which global definitions can be accesed) without exporting
anything. Something like a "namespace { .... }" in C++ that uses another
namespace. Although this is factible, another solution seems more elegant
(at least to me): using lexical scopes. So I write a simple macro similar
to this one:

(defmacro lex (&rest forms)

  (let ((label-list '())
	(let-list '())
	(macrolet-list '())
	(body '()))
      
    (dolist (form forms)
      (case (car form)
	(ldefun (back-push (cdr form) label-list))
	(ldefmacro (back-push (cdr form) macrolet-list))
	(ldefvar (back-push (cdr form) let-list))
	(otherwise (back-push form body))))
      
    `(macrolet ,macrolet-list
       (let* ,let-list
	 (labels ,label-list
	   ,@body)))))


The use of this macro gives me some freedom to reorder the definitions at the
top level (I mean what is seen as being at the file top level, not the
top-level as defined by the Hyperspec) instead of putting every local
macro first, then every local var, then every local function and at the
end the global definitions. But this is only a matter of taste and also
has its limitations (the order is fixed, the symbols created by defstruct can�t
be made local, etc). Using this (and a few other) macros, a module would look
like:


(provide-module "module-1")


(require-module "module-2")
....
(require-module "module-n")


(in-package main-package)


(lex


(ldefvar local-var-1 ...)

(defun global-function-1 (...)
  ....)

(defmacro global-macro-1 (...)
  ....)

(ldefun local-function-1 (...)
  ....)

(defvar global-var-1 ...)

(ldefun local-function-2 (...)
  ....)

)


(The provide-module/require-module macros eval when
(:compile-toplevel :load-toplevel :execute), so they work fine with the
compiler. Their semantics are similar to those of provide/require.)

But the code above has a subtle problem when compiled: global-var-1 and
global-macro-1 are not top-level (I mean top-level as defined in the Hyperspec):
they are wrapped into (macrolet (let* (labels ....))).
According to the Hyperspec (3.2.3.1.1 Processing of Defining Macros):

   Defining  macros  (such as defmacro or defvar) appearing within a file
   being  processed  by  compile-file  normally  have  compile-time  side
   effects  which  affect  how  subsequent  forms  in  the  same file are
   compiled.  A  convenient  model  for explaining how these side effects
   happen  is  that the defining macro expands into one or more eval-when
   forms, and that the calls which cause the compile-time side effects to
   happen  appear  in  the body of an (eval-when (:compile-toplevel) ...)
   form.

   The   compile-time  side  effects  may  cause  information  about  the
   definition  to  be  stored  differently than if the defining macro had
   been  processed  in  the  `normal'  way  (either  interpretively or by
   loading the compiled file).

   ....

As they aren't top-level the compiler will never execute the 
(eval-when (:compile-toplevel) ...) part of (defmacro global-macro-1 ...)
and (defvar global-var-1 ...). This can't be fixed rewriting lexenv
to be evaluated when (:compile-toplevel) cause this would execute the
(eval-when (:execute) ...) part of (defmacro global-macro-1 ...)
and (defvar global-var-1 ...)   (I'm only following the "covenient model"
and the rules in "3.2.3.1 Processing of Top Level Forms" here).

What do you think? Is there a solution for this compilation problem? Or
am I facing the problem the wrong way and should I try another approach (for
example, the anonymous package one)?



Thank you very much,
Carlos

From: Joe Marshall
Subject: Re: Avoiding name clashes
Date: 
Message-ID: <rZpn8.38485$44.12970815@typhoon.ne.ipsvc.net>
"Carlos P." <·······@yahoo.com.ar> wrote in message
································@posting.google.com...
> Hi!
>
> I'm working in a medium-sized project using Common Lisp (particularly
CLisp).
> The code is relatively low-level with heavy use of structs and functions
> to manipulate them but almost no use of classes. There are about 15/20
files
> and, except for a few of them, the dependencies between the other are
strong
> enough to justify giving every one full access to the "public" symbols of
the
> rest in a simple way (I mean, not listing a lot of exported symbols or,
> similarly, a lot of imported ones). But, as there is also a lot of
auxiliary
> machinery (functions, macros, structs, variables, etc) that is logically
> local to each module/file I wouldn't like to make everything visible from
> outside in order to avoid name clashes. One of the solutions that came
> to my mind was using anonymous packages (automatically generated by a
macro)
> which import everything in the main package (the package where every
module
> is and from which global definitions can be accesed) without exporting
> anything. Something like a "namespace { .... }" in C++ that uses another
> namespace.

This sounds like it would work.

> Although this is factible, another solution seems more elegant
> (at least to me): using lexical scopes. So I write a simple macro similar
> to this one:
> [code and problems elided]

> What do you think? Is there a solution for this compilation problem? Or
> am I facing the problem the wrong way and should I try another approach
(for
> example, the anonymous package one)?

Ugh.  This seems like a very complex `solution' that doesn't solve
the problem.

By the way, why do the packages have to be anonymous?
From: Carlos P.
Subject: Re: Avoiding name clashes
Date: 
Message-ID: <453d10b2.0203251855.3ded6d8a@posting.google.com>
> 
> Ugh.  This seems like a very complex `solution' that doesn't solve
> the problem.
> 

It does solve the problem but it introduces that subtle compilation
complication. And I think it is very simple and it feels like the
natural way to do it for me: I will use these auxiliar functions,
macros and variables only to support code in this file so I bind them
in a lexical scope. Also, as I'm working at the top level of the file
I would like to have some freedom to reorder them in order to make the
code easier to follow (anyway, this is a matter of taste and is
irrelevant to the question). Of course, the same thing could be
achieved using the packages mechanism (and more because the names
generated by the definition of some entities can't be lexically bound
-for example, structs-.....am I wrong here?).

> By the way, why do the packages have to be anonymous?

They don't need to be anonymous. But as I'm using the local functions,
macros and variables only from inside the file where they are defined
I don't want to bother about thinking a name for a package that will
never be use'd and whose symbols will never be import'ed/export'ed.
Also, if there is a significant number of files in the project I would
be taking the unnecessary risk of package name clashes or the
unnecessary effort of some kind of name administration. So it's better
if the packages are anonymous (that is, with an automatically
generated unique name). So, these are the reasons that makes me feel
that the package solution sounds more as a trick than the other. I
would use it anyway but first I want to be sure that the compilation
problem is unavoidable and that the implications of wrapping the
result of the lex macro in an (eval-when (:compile-toplevel
:load-toplevel :execute) ....) form could be prejudicial to the
performance of the compiled code (as the :compile-toplevel part of
some of the defining forms -defmacro and defvar- will not be eval'ed).
(Also, I'm trying to understand the motivations for some of the
restrictions in the use of eval-when and if these restrictions can be
safely ignored in some specific situations. In part because I'm
writing a Common Lisp compiler/interpreter and I would like to make
some compatible extensions in this area.)
From: Pierre R. Mai
Subject: Re: Avoiding name clashes
Date: 
Message-ID: <87ofhbhxue.fsf@orion.bln.pmsf.de>
·······@yahoo.com.ar (Carlos P.) writes:

> I'm working in a medium-sized project using Common Lisp (particularly CLisp).
> The code is relatively low-level with heavy use of structs and functions
> to manipulate them but almost no use of classes. There are about 15/20 files
> and, except for a few of them, the dependencies between the other are strong
> enough to justify giving every one full access to the "public" symbols of the
> rest in a simple way (I mean, not listing a lot of exported symbols or,
> similarly, a lot of imported ones). But, as there is also a lot of auxiliary
> machinery (functions, macros, structs, variables, etc) that is logically
> local to each module/file I wouldn't like to make everything visible from
> outside in order to avoid name clashes. One of the solutions that came

After having read your later posts, I still don't see why using the
package system in a straigt forward way doesn't solve your problems
in a fairly efficient way.

Just make one (or more, if it's possible to segregate functionality)
package, let's call it MYAPP-SYS, that exports all shared symbols.
Then, for each functional sub-unit (which might or might not align
with files in your case), create a separate package, which uses
MYAPP-SYS, and work in that package.

Finally, if your application also exports certain of your shared
symbols to the public, make a package MYAPP, using MYAPP-SYS, which
re-exports the public subset of the shared symbols.

I didn't understand your problem about naming the sub-unit packages.
You already have that problem today, because in some way presumably
you are naming your files.  In the worst case, using a combination of
machine id and pathname provides uniquie package names, too.  Though
of course, I'd rather guess that there is a saner way of naming your
packages, while still avoiding collisions.

> to my mind was using anonymous packages (automatically generated by a macro)
> which import everything in the main package (the package where every module
> is and from which global definitions can be accesed) without exporting
> anything. Something like a "namespace { .... }" in C++ that uses another
> namespace. Although this is factible, another solution seems more elegant
> (at least to me): using lexical scopes. So I write a simple macro similar
> to this one:

You have already pointed out that many things (like e.g. type and
structure defintions, special proclamations, etc.) are not lexically
scoped in CL, so this approach seems inappropriate.

If you don't want to explicitly export symbols from the MYAPP-SYS
package, you can of course programmatically export all symbols whose
home-package is MYAPP-SYS from MYAPP-SYS and/or explicitly import
those into your sub-unit packages.

I'd be interested in hearing your objections to the approach outlined
above, with some more details about your application, that are
relevant to the objections...

Regs, Pierre.

-- 
Pierre R. Mai <····@acm.org>                    http://www.pmsf.de/pmai/
 The most likely way for the world to be destroyed, most experts agree,
 is by accident. That's where we come in; we're computer professionals.
 We cause accidents.                           -- Nathaniel Borenstein