From: Jim Bushnell
Subject: Is this an appropriate use of globals?
Date: 
Message-ID: <CRHE8.90400$eV5.7136583@bin2.nnrp.aus1.giganews.com>
I am an avid contract bridge player and Common Lisp programmer. In some
bridge programming I am doing, I use the following kind of code in cases
where I may have to generate thousands of deals before finding one which
satisfies requirements, so I am concerned about efficiency and avoiding
consing. I am interested in comments and/or suggestions about my use of the
global I call *deal* in this and related situations.

(defconstant *deal* (make-array '(4 4) :initial-element 0)
  "a 4x4 array representing a bridge deal, where each element
is a 13-bit integer")

(defun deal ()
  (make-new-deal-destructively-modifying-*deal*)
  *deal*)

(defun copy-deal (&optional (deal *deal*))
  (let ((new-deal (make-array '(4 4))))
    (dotimes (hand 4)
      (dotimes (suit 4)
        (setf (aref new-deal hand suit) (aref deal hand suit))))
    new-deal))

(defun find-deal-satisfying-requirements (requirements)
  (loop for next-deal = (deal)
        until (satisfies-requirements next-deal requirements)
        finally return (copy-deal)))

I welcome your ideas. Thanks.

Jim Bushnell

From: Joe Marshall
Subject: Re: Is this an appropriate use of globals?
Date: 
Message-ID: <TDNE8.5891$Bn5.2390950@typhoon.ne.ipsvc.net>
"Jim Bushnell" <···········@comcast.net> wrote in message
····························@bin2.nnrp.aus1.giganews.com...
> I am an avid contract bridge player and Common Lisp programmer. In some
> bridge programming I am doing, I use the following kind of code in cases
> where I may have to generate thousands of deals before finding one which
> satisfies requirements, so I am concerned about efficiency and avoiding
> consing.

Why do you believe that consing is a problem?  With appropriate garbage
collector settings, the overhead for consing should be down in the noise.
From: Barry Margolin
Subject: Re: Is this an appropriate use of globals?
Date: 
Message-ID: <b2PE8.2$d91.119@paloalto-snr2.gtei.net>
In article <······················@typhoon.ne.ipsvc.net>,
Joe Marshall <·············@attbi.com> wrote:
>
>"Jim Bushnell" <···········@comcast.net> wrote in message
>····························@bin2.nnrp.aus1.giganews.com...
>> I am an avid contract bridge player and Common Lisp programmer. In some
>> bridge programming I am doing, I use the following kind of code in cases
>> where I may have to generate thousands of deals before finding one which
>> satisfies requirements, so I am concerned about efficiency and avoiding
>> consing.
>
>Why do you believe that consing is a problem?  With appropriate garbage
>collector settings, the overhead for consing should be down in the noise.

Agreed.  Most implementations have ephemeral (aka generational) garbage
collectors, which are optimized to clean up short-lived data.  Your program
matches that model quite well.

-- 
Barry Margolin, ······@genuity.net
Genuity, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: james anderson
Subject: Re: Is this an appropriate use of globals?
Date: 
Message-ID: <3CE3B88B.A3C029F2@setf.de>
an alternative is to permit the caller to determine the extent of the
datum and to default to a new instance with indefinite extent.

something like

(defconstant *deal* (make-array '(4 4) :initial-element 0)
  "a 4x4 array representing a bridge deal, where each element
is a 13-bit integer")

(defun deal (&optional (a-deal (copy-deal)))
  (make-new-deal-destructively-modifying-deal a-deal)
  a-deal)

(defun copy-deal (&optional (deal *deal*))
  (let ((new-deal (make-array '(4 4))))
    (dotimes (hand 4)
      (dotimes (suit 4)
        (setf (aref new-deal hand suit) (aref deal hand suit))))
    new-deal))

(defun find-deal-satisfying-requirements (requirements &optional (a-deal (copy-deal)))
  (if (satisfies-requirements (deal a-deal) requirements)
     a-deal
     (find-deal-satisfying-requirements requirements a-deal)))

...

Jim Bushnell wrote:
> 
> I am an avid contract bridge player and Common Lisp programmer. In some
> bridge programming I am doing, I use the following kind of code in cases
> where I may have to generate thousands of deals before finding one which
> satisfies requirements, so I am concerned about efficiency and avoiding
> consing. I am interested in comments and/or suggestions about my use of the
> global I call *deal* in this and related situations.
> 
> (defconstant *deal* (make-array '(4 4) :initial-element 0)
>   "a 4x4 array representing a bridge deal, where each element
> is a 13-bit integer")
> 
> (defun deal ()
>   (make-new-deal-destructively-modifying-*deal*)
>   *deal*)
> 
> (defun copy-deal (&optional (deal *deal*))
>   (let ((new-deal (make-array '(4 4))))
>     (dotimes (hand 4)
>       (dotimes (suit 4)
>         (setf (aref new-deal hand suit) (aref deal hand suit))))
>     new-deal))
> 
> (defun find-deal-satisfying-requirements (requirements)
>   (loop for next-deal = (deal)
>         until (satisfies-requirements next-deal requirements)
>         finally return (copy-deal)))
> 
> I welcome your ideas. Thanks.
> 
> Jim Bushnell
From: Coby Beck
Subject: Re: Is this an appropriate use of globals?
Date: 
Message-ID: <gBQE8.83470$xS2.6775902@news1.calgary.shaw.ca>
Jim Bushnell <···········@comcast.net> wrote in message
····························@bin2.nnrp.aus1.giganews.com...
> I am an avid contract bridge player and Common Lisp programmer. In some
> bridge programming I am doing, I use the following kind of code in cases
> where I may have to generate thousands of deals before finding one which
> satisfies requirements, so I am concerned about efficiency and avoiding
> consing. I am interested in comments and/or suggestions about my use of
the
> global I call *deal* in this and related situations.

I personally don't see any reason in the code below to have any global
variable.  If the rest of your code wants it, I would have callers of
find-deal-satisfying-requirements bind it themselves.

>
> (defconstant *deal* (make-array '(4 4) :initial-element 0)
>   "a 4x4 array representing a bridge deal, where each element
> is a 13-bit integer")

You are modifying something you have declared as a constant above.  You
meant defparameter I think.

>
> (defun deal ()
>   (make-new-deal-destructively-modifying-*deal*)
>   *deal*)
>
> (defun copy-deal (&optional (deal *deal*))
>   (let ((new-deal (make-array '(4 4))))
>     (dotimes (hand 4)
>       (dotimes (suit 4)
>         (setf (aref new-deal hand suit) (aref deal hand suit))))
>     new-deal))
>
> (defun find-deal-satisfying-requirements (requirements)
>   (loop for next-deal = (deal)
>         until (satisfies-requirements next-deal requirements)
>         finally return (copy-deal)))
>

How about:
(defun find-deal-satisfying-requirements (requirements)
   (loop for next-deal = (make-new-deal-that-destructively-modifies-nothing)
         until (satisfies-requirements next-deal requirements)
         finally (return next-deal)))

--
Coby Beck
(remove #\Space "coby 101 @ bigpond . com")
From: Drew McDermott
Subject: Re: Is this an appropriate use of globals?
Date: 
Message-ID: <3CE3F56F.8020309@yale.edu>
Coby Beck wrote:
> Jim Bushnell <···········@comcast.net> wrote in message
> ····························@bin2.nnrp.aus1.giganews.com...
> 
>>I am an avid contract bridge player and Common Lisp programmer. In some
>>bridge programming I am doing, I use the following kind of code in cases
>>where I may have to generate thousands of deals before finding one which
>>satisfies requirements, so I am concerned about efficiency and avoiding
>>consing. I am interested in comments and/or suggestions about my use of
>> the global I call *deal* in this and related situations.
> 
> 
> I personally don't see any reason in the code below to have any global
> variable.  If the rest of your code wants it, I would have callers of
> find-deal-satisfying-requirements bind it themselves.


I agree with Mr. Beck's comments.  Not taking any position on whether 
destructive modification saves anything non-neglible here, you could 
just as well write

(defun find-deal-satisfying-requirements (requirements)
    (let ((deal (make-new-deal)))
       (loop for next-deal =
          (make-new-deal-destructively-modifying deal)
        until (satisfies-requirements next-deal requirements)
        finally (return next-deal))))

In general, special variables, especially global variables, are a bad 
idea, and I almost always find myself having to get rid of them some 
time after I design them in.  The problem is that the use of a special 
variable assumes that just one sort of program is going to be looking at 
it, and sooner or later you find yourself wanting two.  For instance, 
you design an exensible parser, and create a special variable 
*syntax-table* to record its syntax.  It is inevitable (trust me) that 
you are eventually going to want to parse two languages simultaneously, 
and you are going to have to do away with the global variable and 
replace it with an argument passed down to the subroutines of the parser.

      -- Drew McDermott
From: Tim Moore
Subject: Re: Is this an appropriate use of globals?
Date: 
Message-ID: <ac0v6i$3t6$0@216.39.145.192>
On Thu, 16 May 2002 14:07:43 -0400, Drew McDermott <··············@yale.edu>
wrote:

>
>In general, special variables, especially global variables, are a bad 
>idea, and I almost always find myself having to get rid of them some 
>time after I design them in.  The problem is that the use of a special 
>variable assumes that just one sort of program is going to be looking at 
>it, and sooner or later you find yourself wanting two.  For instance, 
>you design an exensible parser, and create a special variable 
>*syntax-table* to record its syntax.  It is inevitable (trust me) that 
>you are eventually going to want to parse two languages simultaneously, 
>and you are going to have to do away with the global variable and 
>replace it with an argument passed down to the subroutines of the parser.

It seems that you're ignoring the "special" in "special variables" i.e.,
special binding.  What's wrong with:

(defvar *syntax-table* nil)

(defun parse-language (stream language)
  (let ((*syntax-table* (syntax-table language)))
    (parse stream)))

Tim
From: Drew McDermott
Subject: Re: Is this an appropriate use of globals?
Date: 
Message-ID: <3CE585F4.1010102@yale.edu>
Tim Moore wrote:
> On Thu, 16 May 2002 14:07:43 -0400, Drew McDermott <··············@yale.edu>
> wrote:
> 
> 
>>In general, special variables, especially global variables, are a bad 
>>idea, and I almost always find myself having to get rid of them some 
>>time after I design them in.  The problem is that the use of a special 
>>variable assumes that just one sort of program is going to be looking at 
>>it, and sooner or later you find yourself wanting two.  For instance, 
>>you design an exensible parser, and create a special variable 
>>*syntax-table* to record its syntax.  It is inevitable (trust me) that 
>>you are eventually going to want to parse two languages simultaneously, 
>>and you are going to have to do away with the global variable and 
>>replace it with an argument passed down to the subroutines of the parser.
> 
> 
> It seems that you're ignoring the "special" in "special variables" i.e.,
> special binding.  What's wrong with:
> 
> (defvar *syntax-table* nil)
> 
> (defun parse-language (stream language)
>   (let ((*syntax-table* (syntax-table language)))
>     (parse stream)))
> 
> Tim
> 

How about the following (nonhypothetical) case: You design a type system 
    suitable for underpinning both a typed version of Lisp (implemented 
with macros) and a typed KR system with Lisp syntax.  Now you want to 
write a typed KR system using your typed Lisp.  Are you *sure* you can 
keep the scopes of the specials straight?  Even if you're Kent P., and 
can understand the difference between all three environments in 
existence during compilation, isn't there some chance a macro in your 
typed Lisp will be expanded when *type-bindings* is bound to the value 
for the KR system?

In any case, why work so hard to use specials?  It's almost always 
pretty easy to get rid of them.  I have seen many an AI program that 
binds a global variable called, say, *knowledge-base*, with the 
intention that some axiom set is going to be loaded in.  Then they have 
files that look like

(define-piece-of-knowledge "roses are red")
(define-piece-of-knowledge "violets are vile")
...

In this primitive, exploratory phase, this is okay, but very quickly 
they find it a nuisance to have to restart Lisp when they want to 
refresh the KB.  At that point, if they find themselves defining a 
function (purge-KB) that erases everything so they can load it in again, 
they are making a mistake.  The correct tack is to define an abstraction 
called 'knowledge-base', and introduce a form

(define-knowledge-base test-1
    (define-piece-of-knowledge "roses are red")
    (define-piece-of-knowledge "violets are vile")
     ...)

Now they need just one global variable, *knowledge-base-table*, which 
implements a global namespace for names such as 'test-1'.  In all other 
contexts, they pass the current KB as an argument to whatever function 
wants to do something with a KB.

 From then on, they can have as many KBs in existence simultaneously as 
they want (and, as I said before, they will inevitably want more than 
one eventually).  To reload one, they just re-evaluate the 
'define-knowledge-base' form, and it knows how to purge test-1 and 
rebuild it.

This solution works fine until you realize that you want names to have 
Internet-wide scope, when you have to switch to using URIs, but that's a 
  different story ....

      -- Drew McDermott