Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overriding "defun" within a package

I would like to define a macro named "defun" from within a package i am creating and i would like to export it to be used in certain places. There is a library called parenscript that does this in it's package like so,

(export #:defun)

When i try to do this within my own package i get this SBCL error

Lock on package COMMON-LISP violated when defining DEFUN as a macro while in package COMMON-LISP-USER.

How is this done in the parenscript library? I know that you can type the form;

(ps (defun function-name (args) (body)))

I want to be able to do the same but cannot figure out how this is done?

like image 484
James Gunn Avatar asked Mar 03 '23 22:03

James Gunn


2 Answers

You want to shadow the original symbol from the CL package.

CL-USER 1 > (defpackage "MY-PACKAGE" (:use "CL"))
#<The MY-PACKAGE package, 0/16 internal, 0/16 external>

CL-USER 2 > (in-package "MY-PACKAGE")
#<The MY-PACKAGE package, 0/16 internal, 0/16 external>

MY-PACKAGE 3 > (shadow 'defun)
T

MY-PACKAGE 4 > (cl:defun defun () :my-defun-returns)
DEFUN

MY-PACKAGE 5 > (defun)
:MY-DEFUN-RETURNS

MY-PACKAGE 6 > (export 'defun)
T
like image 173
Rainer Joswig Avatar answered Mar 11 '23 21:03

Rainer Joswig


You need to read more about packages and symbols. Here I am going to qualify all symbols when needed so that there is no ambiguity about which one I am talking about.

  1. You cannot redefine CL:DEFUN, this invokes undefined behavior and you are likely to "break" your runtime by making it unusable. That's why SBCL has a concept of locks for packages, which are a way to avoid modifying a package and its bindings by mistake (you can still unlock a package, by you usually don't need to).

  2. Under the scope of your macro, you are free to interpret CL:DEFUN as you wish, which is what Parenscript does by translating a subset of actual Lisp code to Javascript.

  3. In any other package P, you can define P:DEFUN as a variable/function/macro/whatever that is entirely distinct from CL:DEFUN. You can export it and everything is fine, you can use both P:DEFUN and CL:DEFUN however you want.

  4. Conflicts can happen if you want to write an unqualified DEFUN symbol and have the reader find out which symbols is being referenced. Typically, users of a library might define a package like so:

    (defpackage :foo (:use :cl :p))
    

    This leads to a conflict, because both the "CL" and the "P" packages export "DEFUN". One way to solve that is to define a Common Lisp dialect that rebind DEFUN and re-exports all other symbols from "CL". Your users must then use only your package and not the CL one. Another way is to use CL and shadow-import only "DEFUN" from P, so that DEFUN is an alias for P:DEFUN (consequently, you need to write CL:DEFUN to explicitly reference the Common Lisp macro).

The link given above goes into more details.

like image 33
coredump Avatar answered Mar 11 '23 21:03

coredump