From: gary
Subject: Special variables, style and packages
Date: 
Message-ID: <3632d8bf.0207010441.62350e63@posting.google.com>
How's it going?

I have something that's bothering me, I'd like to tell you the
specific problem I'm faced with and then ask a general question.

I'm using Lispwork's CAPI (it's a graphic library) to prepare some
dialog boxes for data entry.  I have over 90 data screens.  So, as an
example I have

(defvar *example-pane* 
   (make-instance 
      'capi:column-layout
      <.... about 40 lines of layout instructions ....> ))

I feel queasy having so many special variables around.  Usually, when
you are faced with so many special variables, is it normal practice to
set up a package and place each special variable within the package
(and export the symbol)?  Do you find that this solution scales up
well - like, does it seem strange to use 90 packages?

Thanks.



(If you're familiar with CAPI - I'm not sure, but I think that the
define-interface macro is convenient only if you have a few panes)

From: Andreas Hinze
Subject: Re: Special variables, style and packages
Date: 
Message-ID: <3D20561D.5A6645E5@smi.de>
gary wrote:
> 
> I'm using Lispwork's CAPI (it's a graphic library) to prepare some
> dialog boxes for data entry.  I have over 90 data screens.  So, as an
> example I have
> 
> (defvar *example-pane*
>    (make-instance
>       'capi:column-layout
>       <.... about 40 lines of layout instructions ....> ))
> 
> I feel queasy having so many special variables around.  Usually, when
> you are faced with so many special variables, is it normal practice to
> set up a package and place each special variable within the package
> (and export the symbol)?  Do you find that this solution scales up
> well - like, does it seem strange to use 90 packages?
> 
Why are you using special vars at all ? I would assume that functions will
make a better job here. At least you would be able to give parameters to it
and can handle callbacks local to the function if needed.

Best
AHz
From: Rob Warnock
Subject: Re: Special variables, style and packages
Date: 
Message-ID: <afr8od$5ho4b$1@fido.engr.sgi.com>
gary <··············@yahoo.com> wrote:
+---------------
| ...dialog boxes for data entry.  I have over 90 data screens...
| (defvar *example-pane* 
|    (make-instance 
|       'capi:column-layout
|       <.... about 40 lines of layout instructions ....> ))
| I feel queasy having so many special variables around.
+---------------

You should feel queasy.  What about defining a single alist or
hash table that contains all your examples?  E.g. [untested]:

	(defvar *capi-examples* (make-hash-table))

	; then lots of these:
	(setf (gethash 'example-pane *capi-examples*)
	  (make-instance
	    'capi:column-layout
	    <...layout instructions...> ))

	...additional SETFs as needed...

	; abstract the lookup (and error check)
	(defun get-capi-example (name)
	  (let ((example (gethash 'example-pane *capi-examples*)))
	    (unless example
	      (error "get-capi-example: example screen not found:" name))
	    example))

Then when you need the "example-pane" again, it's easily found:

	(let ((pane (get-capi-example 'example-pane)))
	  ...do something with pane...)


-Rob

p.s. Note: I originally wrote the above with keywords (":example-pane")
instead of symbols in the current package, but there have been comments
here on the list about not polluting the KEYWORD packages with such stuff.
You can do it either way. Or even make a single separate "CAPI-EXAMPLES"
package with the global hash table name and the hash keys in it, whatever.
Just be warned that I'm not an experienced enough CL programmer to be
giving advice on matters of style at that level...  ;-}

-----
Rob Warnock, 30-3-510		<····@sgi.com>
SGI Network Engineering		<http://www.rpw3.org/>
1600 Amphitheatre Pkwy.		Phone: 650-933-1673
Mountain View, CA  94043	PP-ASEL-IA

[Note: ·········@sgi.com and ········@sgi.com aren't for humans ]  
From: Will Hartung
Subject: Re: Special variables, style and packages
Date: 
Message-ID: <3d21e9ab$1_1@news5.nntpserver.com>
"Rob Warnock" <····@rigden.engr.sgi.com> wrote in message
···················@fido.engr.sgi.com...
> gary <··············@yahoo.com> wrote:
> +---------------
> | ...dialog boxes for data entry.  I have over 90 data screens...
> | (defvar *example-pane*
> |    (make-instance
> |       'capi:column-layout
> |       <.... about 40 lines of layout instructions ....> ))
> | I feel queasy having so many special variables around.
> +---------------
>
> You should feel queasy.  What about defining a single alist or
> hash table that contains all your examples?  E.g. [untested]:
>
> (defvar *capi-examples* (make-hash-table))
>
> ; then lots of these:
> (setf (gethash 'example-pane *capi-examples*)
>   (make-instance
>     'capi:column-layout
>     <...layout instructions...> ))
>
> ...additional SETFs as needed...
>
> ; abstract the lookup (and error check)
> (defun get-capi-example (name)
>   (let ((example (gethash 'example-pane *capi-examples*)))
>     (unless example
>       (error "get-capi-example: example screen not found:" name))
>     example))
>
> Then when you need the "example-pane" again, it's easily found:
>
> (let ((pane (get-capi-example 'example-pane)))
>   ...do something with pane...)

Now, I'm curious.

This is purely a stylistic issue at this point, correct?

Is there any real technical advantage to it?

Is there really any difference between using a hash table versus a dedicated
package containing the special variables? Will the compiler view them that
much differently and make worse code because of it?

Basically, what is the difference between (get-capi-example 'example-pane)
and pane-package::*example-pane*?

I'm just curious is all. They seem essentially identical to me.

Best Regards,

Will Hartung
(·····@msoft.com)
From: Tim Bradshaw
Subject: Re: Special variables, style and packages
Date: 
Message-ID: <ey3ofdqoudh.fsf@cley.com>
* Will Hartung wrote:

> Basically, what is the difference between (get-capi-example
> 'example-pane) and pane-package::*example-pane*?

I can see a couple of differences: using a function leaves more scope
for implementation to vary - the function could compute the pane on
the fly, compute it once and cache it, and so forth.  Internally, the
likely implementation of such a function makes things like `recompute
all panes' or `decache all cached panes' simpler.  If there was some
need to bind panes during a dynamic extent, then the special variable
approach is possibly better (however, if you want to bind *all* panes
during such an extent, then a function which accesses a secret special
variable and a binding macro might be better, and also allows special
actions to take place when the extent is exited).

--tim

(disregarding symbol macros)
From: james anderson
Subject: Re: Special variables, style and packages
Date: 
Message-ID: <3D22C53F.E6A3A8E4@setf.de>
Tim Bradshaw wrote:
> 
> * Will Hartung wrote:
> 
> > Basically, what is the difference between (get-capi-example
> > 'example-pane) and pane-package::*example-pane*?
> 
> I can see a couple of differences: using a function leaves more scope
> for implementation to vary - the function could compute the pane on
> the fly, compute it once and cache it, and so forth.

another option would be to implement the caching behaviour as an aspect of MAKE-INSTANCE for singleton pane classes. this would
afford the chance to differentiate by class declaration and/or initialization arguments.

...
From: Tim Bradshaw
Subject: Re: Special variables, style and packages
Date: 
Message-ID: <ey3d6u5otdm.fsf@cley.com>
* james anderson wrote:

> another option would be to implement the caching behaviour as an
> aspect of MAKE-INSTANCE for singleton pane classes. this would
> afford the chance to differentiate by class declaration and/or
> initialization arguments.

I've done this kind of thing, but I think it's bad.  I'd like to be
able to assume that (eq (make-instance ...) (make-instance ...)) is
NIL, the same way you can assume that for CONS, say.  Obviously (I
think) this is a style issue rather than a language one, but when I
want to do this now I typically have a wrapper (generic) function
called something like ENSURE-INSTANCE, which only may create an
instance.

--tim