[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.lisp

Accidentally defining a recursive function using defpackage/:shadow?

Max Rottenkolber

10/6/2015 10:24:00 PM

Hi c.l.l,

I stumbled upon a behavior today that I am unable to explain. Given the
following definitions

(defpackage test
(:use :cl)
(:export :foo))

(defun test:foo () :bar)

(defpackage test2
(:use :cl :test)
(:export :foo))

if I re-define TEST2 and define TEST2:FOO as follows

(defpackage test2
(:use :cl :test)
(:shadow :foo)
(:export :foo))

(defun test2:foo () (test:foo))

then calling TEST2:FOO will â??hangâ? (if you try it, do it somewhere where
you can C-c it, e.g. a Slime REPL). My guess is that TEST2:FOO was
defined to be a recursive function calling itself. I tested this on
Clozure CL 1.10 and CMUCL 21a, both exhibit this behavior.

I do not immediately see why this happens. If anyone knows what is going
on here, I would appreciate if they shared their wisdom. :)

Regards,
max

2 Answers

Pascal J. Bourguignon

10/6/2015 11:08:00 PM

0

Max Rottenkolber <max@mr.gy> writes:

> Hi c.l.l,
>
> I stumbled upon a behavior today that I am unable to explain. Given the
> following definitions
>
> (defpackage test
> (:use :cl)
> (:export :foo))
>
> (defun test:foo () :bar)
>
> (defpackage test2
> (:use :cl :test)
> (:export :foo))
>
> if I re-define TEST2 and define TEST2:FOO as follows

Beeep!

Re-defining a package is not conforming. Anything can happen, including
nasal daemon. Most implementation will do something relatively sane,
often involving interactive restarts, but all bets are off as to what
they will do. You will have to read the documentation of your
implementation.


> (defpackage test2
> (:use :cl :test)
> (:shadow :foo)
> (:export :foo))
>
> (defun test2:foo () (test:foo))
>
> then calling TEST2:FOO will â??hangâ? (if you try it, do it somewhere where
> you can C-c it, e.g. a Slime REPL).

"hang", "nasal daemons", "drone launcing missiles toward your general
direction", it's all the same, once you've redefined the package with
CL:DEFPACKAGE.


> My guess is that TEST2:FOO was
> defined to be a recursive function calling itself. I tested this on
> Clozure CL 1.10 and CMUCL 21a, both exhibit this behavior.

Yes, that would explain it; try: (eq 'test2:foo 'test:foo)


> I do not immediately see why this happens. If anyone knows what is going
> on here, I would appreciate if they shared their wisdom. :)

You could mutate the package "manually", using functions such as SHADOW,
EXPORT, IMPORT, UNEXPORT, USE-PACKAGE, UNUSE-PACKAGE, UNINTERN, etc.

You can also obtain conforming behavior redefining the package, if you
use your own defpackage macro, or, eg.
COM.INFORMATIMAGO.COMMON-LISP.LISP-READER.PACKAGE:DEFPACKAGE
(but extract it with the required functions to your own package (and
release it under AGPL3), since
COM.INFORMATIMAGO.COMMON-LISP.LISP-READER.PACKAGE:DEFPACKAGE
actually doesn't work with CL:PACKAGE but with
COM.INFORMATIMAGO.COMMON-LISP.LISP-READER.PACKAGE:PACKAGE.

An alternative, is to delete the package before re-defining it.
But if other packages depend on it, via a use-package or :use clause,
then you will have to unuse-package it first, or delete those other
packages before.

You can use
COM.INFORMATIMAGO.COMMON-LISP.CESARUM.PACKAGE:DELETE-PACKAGES
to delete packages recursively.

--
__Pascal Bourguignon__ http://www.informat...
â??The factory of the future will have only two employees, a man and a
dog. The man will be there to feed the dog. The dog will be there to
keep the man from touching the equipment.� -- Carl Bass CEO Autodesk

Zach Beane

10/7/2015 1:39:00 PM

0

Max Rottenkolber <max@mr.gy> writes:

> Hi c.l.l,
>
> I stumbled upon a behavior today that I am unable to explain. Given the
> following definitions
>
> (defpackage test
> (:use :cl)
> (:export :foo))
>
> (defun test:foo () :bar)
>
> (defpackage test2
> (:use :cl :test)
> (:export :foo))
>
> if I re-define TEST2 and define TEST2:FOO as follows
>
> (defpackage test2
> (:use :cl :test)
> (:shadow :foo)
> (:export :foo))
>
> (defun test2:foo () (test:foo))
>
> then calling TEST2:FOO will â??hangâ? (if you try it, do it somewhere where
> you can C-c it, e.g. a Slime REPL). My guess is that TEST2:FOO was
> defined to be a recursive function calling itself. I tested this on
> Clozure CL 1.10 and CMUCL 21a, both exhibit this behavior.
>
> I do not immediately see why this happens. If anyone knows what is going
> on here, I would appreciate if they shared their wisdom. :)

Before exporting, a symbol is ensured to be present. See
http://l1sp.org...:

If the symbol is present in package as an internal symbol, it is
simply changed to external status. If it is accessible as an internal
symbol via use-package, it is first imported into package, then
exported. (The symbol is then present in the package whether or not
package continues to use the package through which the symbol was
originally inherited.)

So the defpackage form that inherits FOO and then exports it makes it so
that TEST2::FOO and TEST::FOO are the same, EQ symbol.

The later change to the defpackage form to use shadowing then has no
effect on this EQ-ness. See http://l1sp.org...:

shadow assures that symbols with names given by symbol-names are
present in the package.

You would get the effect you expect if you first unintern FOO from TEST2
before evaluating the second defpackage form. It would remain interned
in TEST, and TEST2::FOO would no longer be EQ to TEST::FOO.

Zach