[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.lisp

Packages and private/public members

Jeremy Smith

7/28/2015 4:35:00 PM

Hi,

I want to make a package, with some functions accessible from outside the
package, and some from within.

Outside is like 'public' in C++.

Inside is like 'private' in C++.

Say the package is called TEST.

(defpackage "COM.TEST"
(:shadow :hello-world)
(:use "COMMON-LISP"))

(in-package :COM.TEST)

(defun hello-world () (format t "hello public from EMAIL-DB package~%"))

(defun hello-world-internal () (format t "hello private from EMAIL-DB
package~%"))

(hello-world)

(in-package :cl-user)

;(hello-world)

hello-world is shadowed and thus is private, but hello-world-internal is
still public.

How can I make hello-world-internal private, and hello-world public?

By the way, I Googled this problem but couldn't find a decent answer.

All the best,

Jeremy.
5 Answers

Matthew Carter

7/28/2015 5:08:00 PM

0

Jeremy Smith <jeremy@decompiler.org> writes:

> Hi,
>
> I want to make a package, with some functions accessible from outside the
> package, and some from within.
>
> Outside is like 'public' in C++.
>
> Inside is like 'private' in C++.
>
> Say the package is called TEST.
>
> (defpackage "COM.TEST"
> (:shadow :hello-world)
> (:use "COMMON-LISP"))
>
> (in-package :COM.TEST)
>
> (defun hello-world () (format t "hello public from EMAIL-DB package~%"))
>
> (defun hello-world-internal () (format t "hello private from EMAIL-DB
> package~%"))
>
> (hello-world)
>
> (in-package :cl-user)
>
> ;(hello-world)
>
> hello-world is shadowed and thus is private, but hello-world-internal is
> still public.
>
> How can I make hello-world-internal private, and hello-world public?
>
> By the way, I Googled this problem but couldn't find a decent answer.
>
> All the best,
>
> Jeremy.

Unless you :export in your defpackage, the function is private and using
it via (com.test:hello-world) for instance, will signal an error.

This doesn't stop someone from explicitly calling it via
(com.test::hello-world) however.

I'm not sure it's possible to completely block an explicit call like
that.

If someone uses your package (use-package :com.test), it will only
import the :export'ed items into the namespace.

(defpackage "COM.TEST"
(:export :hello-world-public)
(:use "COMMON-LISP"))

You may want to read:
http://www.lispworks.com/documentation/HyperSpec/Body/m_...

I don't think :shadow is used for what you think it is.

--
Matthew Carter (m@ahungry.com)
http://a...

Pascal J. Bourguignon

7/28/2015 5:30:00 PM

0

Jeremy Smith <jeremy@decompiler.org> writes:

> Hi,
>
> I want to make a package, with some functions accessible from outside the
> package, and some from within.
>
> Outside is like 'public' in C++.

We say :export in lisp.

> Inside is like 'private' in C++.

We say :intern in lisp.


> Say the package is called TEST.
>
> (defpackage "COM.TEST"
> (:shadow :hello-world)
> (:use "COMMON-LISP"))

(defpackage "COM.TEST"
(:use "COMMON-LISP")
(:export "HELLO-WORLD")
(:intern "HELLO-WORLD-INTERNAL"))


> hello-world is shadowed and thus is private

Are you crazy? Can't you read?

http://www.lispworks.com/documentation/HyperSpec/Body/f_shadow....
http://www.lispworks.com/documentation/HyperSpec/Body/f_shdw_i.htm#shadow...
http://www.lispworks.com/documentation/HyperSpec/Body/m_...

Shadowing is for when you want to use a package, but shadow one more
more symbols from its export list.



Now, since by default defpackage doesn't export symbols, and symbols are
automatically interned when they're first read, you don't really need to
use :intern in defpackage, in general.

(defpackage "COM.TEST"
(:use "COMMON-LISP")
(:export "HELLO-WORLD"))

would be as good.



You may use :intern to introduce a private symbol for a friend package
that would import it:

(defpackage "COM.TEST"
(:use "COMMON-LISP")
(:export "HELLO-WORLD")
(:intern "HELLO-WORLD-FOR-FRIEND"))

(defpackage "COM.TEST.FRIEND"
(:use "COMMON-LISP")
(:import-from "COM.TEST" "HELLO-WORLD-FOR-FRIEND"))

and later, in some other file:

(in-package "COM.TEST")
(defun hello-world-internal () 'hello)
(defun hello-world-for-friend () (list (hello-world-internal) 'friend))
(defun hello-world () (list (hello-world-internal) 'world))

--
__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

Kaz Kylheku

7/28/2015 7:19:00 PM

0

On 2015-07-28, Pascal J. Bourguignon <pjb@informatimago.com> wrote:
> Jeremy Smith <jeremy@decompiler.org> writes:
>
>> Hi,
>>
>> I want to make a package, with some functions accessible from outside the
>> package, and some from within.
>>
>> Outside is like 'public' in C++.
>
> We say :export in lisp.
>
>> Inside is like 'private' in C++.
>
> We say :intern in lisp.

What? Interning doesn't have anything to do with privacy.
Please don't encourage newbies to make false associations.

taruss

7/28/2015 11:58:00 PM

0

On Tuesday, July 28, 2015 at 12:18:49 PM UTC-7, Kaz Kylheku wrote:
> On 2015-07-28, Pascal J. Bourguignon <pjb@informatimago.com> wrote:
> > Jeremy Smith <jeremy@decompiler.org> writes:
> >
> >> Hi,
> >>
> >> I want to make a package, with some functions accessible from outside the
> >> package, and some from within.
> >>
> >> Outside is like 'public' in C++.
> >
> > We say :export in lisp.
> >
> >> Inside is like 'private' in C++.
> >
> > We say :intern in lisp.
>
> What? Interning doesn't have anything to do with privacy.
> Please don't encourage newbies to make false associations.

I agree.

The main lesson is that Common Lisp doesn't have enforced public/private
distinctions, but instead relies on conventions and trusts programmers to
not do the wrong things. This makes the system flexible, but can be a shock
to programmers coming from other more rigid and controlling languages.

Symbols can be internal or external to a package.
By convention, programmers are supposed to only use the external symbols of a
package, since implementers are free to change or remove any of the external
symbols.

Now, in its flexibility, Common Lisp allows you to access the internal symbols,
but the understanding is that one does that at one's own peril.

There are a few tools that can be used to make functions or variable state
inaccessible to the outside, but they rely on somewhat cumbersome scoping, and
at least for functions tend not to be used for that purpose. Shared private
variables created by (top level) closures are more common:

(let ((shared-invisible-variable 0))
(defun get-var () shared-invisible-variable)
(defun inc-var () (incf shared-invisible-variable))
(defun dec-var ()
(when (> shared-invisible-variable 0)
(decf shared-invisible-variable)))
)

For functions all you really have is FLET and LABELS, which could be used, but
tend not to. It also doesn't help that the behavior of FLET or LABELS isn't
defined as a top level form. For that matter, neither is LET, but it tends to
be used more often like that.

So you could do that, but it would be rather cumbersome for any large system,
so nobody really does this in practice. Even the LET form is mainly used more
for illustrative or didactic purposes than for production code.


Pascal J. Bourguignon

7/29/2015 4:31:00 AM

0

taruss@google.com writes:

> There are a few tools that can be used to make functions or variable state
> inaccessible to the outside, but they rely on somewhat cumbersome scoping, and
> at least for functions tend not to be used for that purpose. Shared private
> variables created by (top level) closures are more common:
>
> (let ((shared-invisible-variable 0))
> (defun get-var () shared-invisible-variable)
> (defun inc-var () (incf shared-invisible-variable))
> (defun dec-var ()
> (when (> shared-invisible-variable 0)
> (decf shared-invisible-variable)))
> )

If you do that, since the defun are not toplevel anymore, the
compilation-time side effects of defun are not obtained. Therefore I
would advise to add in this case, at least a declaration:
(declaim (function get-var inc-var dec-var)) on the toplevel before the
let, to let the compiler know that you will have such functions and
avoid warnings about them being undefined.


> So you could do that, but it would be rather cumbersome for any large system,
> so nobody really does this in practice. Even the LET form is mainly used more
> for illustrative or didactic purposes than for production code.

Foremost because it's inconvenient to debug. You want to be able to see
the shared-invisible-variable to check whether the functions in the
closure work correctly. So you use a global variable instead.


--
__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