Common Lisp: How to import symbols of other packages inside a lexical scope only?

1.5k views Asked by At

I want to use some functions inside another package with a long name (e.g., "sb-bsd-sockets"), and I have to write this:

(defun myfun (...)
   (sb-bsd-sockets:socket-bind ...)
   (sb-bsd-sockets:socket-listen ...)
   ...)

Is there a way to import some of those symbols only available inside myfun (without any performance loss)?

4

There are 4 answers

0
Baggers On BEST ANSWER

The following is the first thing that popped into my head (a simple tree walk and replace of symbol names).

It should be noted that the question was about importing symbols and the following does not do that. It simply adds the ugly package-name:: part for you.

(defmacro with-symbols-from ((package-name &rest symbols) &body body)
  (let ((f-symbols (loop :for s :in symbols :collect 
                      (intern (symbol-name s) package-name))))
    `(progn
       ,@(loop :for symbol :in symbols :for f-symbol :in f-symbols 
            :with body = body
            :do (setf body (subst f-symbol symbol body :test #'eq))
            :finally (return body)))))

Usage example:

CL-USER> (with-symbols-from (:cffi foreign-alloc mem-aref)
           (let ((a (foreign-alloc :int)))
             (setf (mem-aref a :int) 1)
             (mem-aref a :int)))
1

The above expanded to:

(PROGN
 (LET ((A (CFFI:FOREIGN-ALLOC :INT)))
   (SETF (CFFI:MEM-AREF A :INT) 1)
   (CFFI:MEM-AREF A :INT)))
2
sds On

Inside a function, no: the defun form is read in the current *package*, and the symbols therein are resolved before anything else (inside it) is processed.

However, you can do something like this (untested and not recommended):

(defpackage #:tmp (:use cl sb-bsd-sockets))
(in-package #:tmp)

(defun old-pack::myfun ...)

(in-package old-pack) ; the package which was current before `tmp` was created
(delete-package #:tmp)

Generally speaking, it is not a good idea.

It would be much cleaner to move the socket code into a separate file with a separate package and then use that package in the other files.

2
Vatine On

The question that immediately comes to mind is "why would you want to do that?"

I would, normally, simply import the the package into the (project-specific) package that needed it and/or structure my project package tree such that if I absolutely cannot have package B imported into package A, have a package A-sub that imports it, exports a few functions, then call A-sub:function from other code within package A.

As a general rule, if you are trying to do something that seems awkward in Common Lisp, it's probably time to take a short step back and consider if what you're trying to do is the best way of accomplishing what you want (in this case, the question could be "does it matter if the symbol socket-bind is imported from sb-bsd-sockets?" and if the answer isn't a resounding YES, then simply import socket-bind into your package).

0
I.Omar On

There is import function as well.

(import 'sb-bsd-sockets:socket-bind)
(import 'sb-bsd-sockets:socket-listen)
(socket-listen) ;; error, but found