From: Dmitry V. Gorbatovsky
Subject: make-package on the fly
Date: 
Message-ID: <ejamtm$ugo$1@aioe.server.aioe.org>
Hello, I new to lisp ,writing specialized
server , kind of multiuser lisp enviroment.

I am trying to separate namespaces by creating 
user-package for every user-name/connection.
(instead of more conventional approach of forking
environment). That maybe wrong approach by themself (???).

After 2 days of coding (run-trepl "something") still not
working:

(defmacro trepl (user-name)
`(progn
  (make-package ',user-name
         :use '(:cl :server))
  (in-package ,user-name)
  (format t "~%~s " *package*)
  (loop
     until (equal (setf sform (read t)) :exit)
      do (progn
          (print (if (equal sform :exit)
                     (loop-finish)
                     (eval sform)) t)
          (format t "~%~a " *package*))
   finally (print "finish"))
  (in-package :server)
  (delete-package ',user-name)
  ))

(defun run-trepl (user-name)
  (trepl user-name)
  )

Please I need a help to find mistake in this code.
Any architectural suggestions would be also highly appreciated.  

Thanks, Dmitry

From: Thomas A. Russ
Subject: Re: make-package on the fly
Date: 
Message-ID: <ymir6w6q14u.fsf@sevak.isi.edu>
"Dmitry V. Gorbatovsky" <·········@midasitech.com> writes:


> After 2 days of coding (run-trepl "something") still not
> working:
> 
> (defmacro trepl (user-name)
> `(progn
>   (make-package ',user-name
>          :use '(:cl :server))
>   (in-package ,user-name)
>   (format t "~%~s " *package*)
>   (loop
>      until (equal (setf sform (read t)) :exit)
>       do (progn
>           (print (if (equal sform :exit)
>                      (loop-finish)
>                      (eval sform)) t)
>           (format t "~%~a " *package*))
>    finally (print "finish"))
>   (in-package :server)
>   (delete-package ',user-name)
>   ))
> 
> (defun run-trepl (user-name)
>   (trepl user-name)
>   )
> 
> Please I need a help to find mistake in this code.

One of the first steps to take in figuring out why a macro you are
working on is not working is to take advantage of the ability to expand
the macros in lisp itself.  In this case, see what happens when you do

  (macroexpand-1 '(trepl user-name))

and compare that to what you expect that you want to have.  (Remember
that macros generate code that will be replace the text of the macro
call itself.  In other words, imagine the output of the macroexpand-1
call inside

  (defun run-trepl (user-name)
    ...
   )

and then figure out if you think that code would do what you want it to
do.

(Of course, I also left out step 0 of all of this, which is to figure
 out if you need a macro or function for what you are doing....)

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Pascal Bourguignon
Subject: Re: make-package on the fly
Date: 
Message-ID: <87lkmfgddo.fsf@thalassa.informatimago.com>
"Dmitry V. Gorbatovsky" <·········@midasitech.com> writes:

> Hello, I new to lisp ,writing specialized
> server , kind of multiuser lisp enviroment.
>
> I am trying to separate namespaces by creating 
> user-package for every user-name/connection.
> (instead of more conventional approach of forking
> environment). That maybe wrong approach by themself (???).
>
> After 2 days of coding (run-trepl "something") still not
> working:
>
> (defmacro trepl (user-name)
> `(progn
>   (make-package ',user-name
>          :use '(:cl :server))
>   (in-package ,user-name)
>   (format t "~%~s " *package*)
>   (loop
>      until (equal (setf sform (read t)) :exit)
>       do (progn
>           (print (if (equal sform :exit)
>                      (loop-finish)
>                      (eval sform)) t)
>           (format t "~%~a " *package*))
>    finally (print "finish"))
>   (in-package :server)
>   (delete-package ',user-name)
>   ))
>
> (defun run-trepl (user-name)
>   (trepl user-name)
>   )
>
> Please I need a help to find mistake in this code.
> Any architectural suggestions would be also highly appreciated.  

Have a loook at my response in the "CLOS and Macros" thread.


Obviously, since you want to create the package at _run-time_, you
cannot use a macro!

Compilation-time ⊃ Macroexpansion-time   <->  macro

                         Run-time        <->  function


You can also assume:              Newbie ==>  NOT macro


(defun trepl (user-name)
  (make-package user-name :use '(:cl :server))
  (let ((*package* (find-package user-name)))
    (format t "~%~s " *package*)
    (loop
      until (equal (setf sform (read t)) :exit)
      do (progn
           (print (if (equal sform :exit)
                      (loop-finish)
                      (eval sform)) t)
          (format t "~%~a " *package*))
      finally (print "finish")))
  (delete-package user-name))


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

Nobody can fix the economy.  Nobody can be trusted with their finger
on the button.  Nobody's perfect.  VOTE FOR NOBODY.
From: Dmitry V. Gorbatovsky
Subject: Re: make-package on the fly
Date: 
Message-ID: <ejaugt$2h4$1@aioe.server.aioe.org>
Pascal Bourguignon wrote:


> Obviously, since you want to create the package at _run-time_, you
> cannot use a macro!
Thank you.
Sorry I just make a bit of fuss ...
Now it works:
(defun run-trepl ()
    (print "please print user-name")
    (let ((name (read t)))
    (make-package name :use '(:cl))
    (eval (list 'in-package name))
    (format t "~%~s " *package*)
                 (loop
                  do (let ((sform (read t)))
                       (print (if (equal sform :exit)
                                  (loop-finish)
                                  (eval sform)) t)
                       (format t "~%~a " *package*))
                  finally (print "finish" t))
                 (in-package :cl-user)
                 (delete-package name)
  ))

But still in doubt about design not to posix:fork but
create user-package for every user-name/connection.
Any suggestions are welcome.
Thanks, Dmitry
From: Pascal Bourguignon
Subject: Re: make-package on the fly
Date: 
Message-ID: <878xiehq7o.fsf@thalassa.informatimago.com>
"Dmitry V. Gorbatovsky" <·········@midasitech.com> writes:
> But still in doubt about design not to posix:fork but
> create user-package for every user-name/connection.
> Any suggestions are welcome.

Well, with a user package, you still share a lot of state.  

The users still have read/write access to the whole lisp image, and to
the whole posix environment accessible with the access rights of the
server user.



This might be useful, since several users may work collaboratively on
the same program, a kind of groupware development environment.  But of
course, if a user do something like:

(ext:without-package-lock ("COMMON-LISP")
   (setf (symbol-function 'load) (symbol-function 'delete-file))) ;-)

all the other users of the same server image may be surprized...



With a fork, a user can break the lisp image without impacting the
other users or the root image in the server.  The user can still
modify the files of the server, so when they're loaded, or the server
restarted, it may be broken.



In both cases, if you need more security, you might want to enforce
more restrictions on the operations allowed.  With a fork, you might
also change the uid to a powerless user account.  Or in both cases,
you might overwrite in the user package all the "dangerous" functions,
the difficulty being in proving that you didn't miss any.

In
http://www.informatimago.com/develop/lisp/small-cl-pgms/ibcl/ibcl.lisp
whose purpose is different, you may find a DEFPACKAGE macro showing
how you could provide a different "COMMON-LISP" package.  You'd have
to do something similar to a lot of other macros and functions
(including LIST-ALL-PACKAGES)...  You could also provide a different
set of I/O function to avoid accessing the file system, or accessing
it in a controled way.

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
Until real software engineering is developed, the next best practice
is to develop with a dynamic system that has extreme late binding in
all aspects. The first system to really do this in an important way
is Lisp. -- Alan Kay
From: Dmitry V. Gorbatovsky
Subject: Re: make-package on the fly
Date: 
Message-ID: <ejb1c5$cd1$1@aioe.server.aioe.org>
Pascal Bourguignon wrote:

> With a fork, a user can break the lisp image without impacting the
> other users or the root image in the server. �The user can still
> modify the files of the server, so when they're loaded, or the server
> restarted, it may be broken.

System programming definitely not my field
I try something like:
(defun trepl-server (stream)
  (let ((pid (sb-posix:fork))
        (line nil))
    (format stream "~%~s " *package*)
    (loop
     do (let ((sform (read stream)))
          (print (if (equal sform :exit)
                     (loop-finish)
                     (eval sform)) stream)
          (format stream "~%~a " *package*))
     finally (print "finish" stream))
    ;; (sb-ext:quit)
    (sb-unix:unix-kill pid sb-unix:sigkill))))

But I can't get rid of died processes.
Thanks, Dmitry
From: Dmitry V. Gorbatovsky
Subject: Re: make-package on the fly
Date: 
Message-ID: <ejb0b8$9ad$1@aioe.server.aioe.org>
Pascal Bourguignon wrote:


> (defun trepl (user-name)
>   (make-package user-name :use '(:cl :server))
>   (let ((*package* (find-package user-name)))
>     (format t "~%~s " *package*)
>     (loop
>       until (equal (setf sform (read t)) :exit)
>       do (progn
>            (print (if (equal sform :exit)
>                       (loop-finish)
>                       (eval sform)) t)
>           (format t "~%~a " *package*))
>       finally (print "finish")))
>   (delete-package user-name))
> 
> 
Get it now, the whole approach is wrong
since there *package* global any way.
And it will change after any connection.
So it seems there is no way to separate multiple
namespaces (for multiple users) within one lisp process ?

Thanks, Dmitry
From: Thomas A. Russ
Subject: Re: make-package on the fly
Date: 
Message-ID: <ymimz6uq0xu.fsf@sevak.isi.edu>
"Dmitry V. Gorbatovsky" <·········@midasitech.com> writes:

> Get it now, the whole approach is wrong
> since there *package* global any way.
> And it will change after any connection.
> So it seems there is no way to separate multiple
> namespaces (for multiple users) within one lisp process ?

You can separate the NAMESPACES within one lisp process.  What you can't
separate is the global state, and certain shared state.  By being
careful about what is accessed, you can achieve some separation of state
by various indexing methods and setting of special variables in a
thread-local manner, but that doesn't help a lot if you have to support
multiple connections from a single user.  You would also have to
restrict (via your own evaluator) what the users were allowed to do in
order to achieve this.

The Lisp execution model has shared memory, so the only way to avoid
this would be to implement your own virtual machine running inside
lisp.  Fortunately this is easier in lisp than other languages....


-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Barry Margolin
Subject: Re: make-package on the fly
Date: 
Message-ID: <barmar-6B3BCF.20042113112006@comcast.dca.giganews.com>
In article <············@aioe.server.aioe.org>,
 "Dmitry V. Gorbatovsky" <·········@midasitech.com> wrote:

> Pascal Bourguignon wrote:
> 
> 
> > (defun trepl (user-name)
> >   (make-package user-name :use '(:cl :server))
> >   (let ((*package* (find-package user-name)))
> >     (format t "~%~s " *package*)
> >     (loop
> >       until (equal (setf sform (read t)) :exit)
> >       do (progn
> >            (print (if (equal sform :exit)
> >                       (loop-finish)
> >                       (eval sform)) t)
> >           (format t "~%~a " *package*))
> >       finally (print "finish")))
> >   (delete-package user-name))
> > 
> > 
> Get it now, the whole approach is wrong
> since there *package* global any way.
> And it will change after any connection.
> So it seems there is no way to separate multiple
> namespaces (for multiple users) within one lisp process ?

But the dynamic binding above ensures that it will only be changed 
during the execution of the trepl function, which just handles a single 
connection.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
From: Dmitry V. Gorbatovsky
Subject: Re: make-package on the fly
Date: 
Message-ID: <ejb8sv$259$1@aioe.server.aioe.org>
Barry Margolin wrote:

> But the dynamic binding above ensures that it will only be changed
> during the execution of the trepl function, which just handles a single
> connection.
> 
Of course you right sir, my disregard has no excuse.
Thanks a lot, you just save me good amount of work.
Dmitry
From: Dmitry V. Gorbatovsky
Subject: Re: make-package on the fly
Date: 
Message-ID: <ejb9og$4dc$1@aioe.server.aioe.org>
Pascal Bourguignon wrote:

>   (make-package user-name :use '(:cl :server))
>   (let ((*package* (find-package user-name)))

Thank you Pascal.
Finally :) I understand it , o... my ignorance.
Dmitry
From: Dmitry V. Gorbatovsky
Subject: Re: make-package on the fly
Date: 
Message-ID: <ejc8vs$qfg$1@aioe.server.aioe.org>
Thank you all,

From the beginning I just wrestle to
send expandable argument to (in-package ...) form
with macro...(make-package ',user-name)
�            (in-package ,user-name)...

Pascal Bourguignon shows me how to do it in "another way"
with function ... (make-package user-name)
�                       (let ((*package* (find-package user-name)))

I "get it" ,send that argument 
by doing ...(make-package user-name)
� �             (eval (list 'in-package user-name)).

And finally after hint from Barry Margolin I realize 
how really different that Pascal's solution was.

Thanks again Dmitry.
From: Ivan Boldyrev
Subject: Re: make-package on the fly
Date: 
Message-ID: <jpgo24-gv7.ln1@ibhome.cgitftp.uiggm.nsc.ru>
On 9658 day of my life Dmitry V. Gorbatovsky wrote:
> After 2 days of coding (run-trepl "something") still not
> working:
>
> (defmacro trepl (user-name)
> `(progn
>   (make-package ',user-name
>          :use '(:cl :server))
>   (in-package ,user-name)
>   (format t "~%~s " *package*)
>   (loop
>      until (equal (setf sform (read t)) :exit)
>       do (progn
>           (print (if (equal sform :exit)
>                      (loop-finish)
>                      (eval sform)) t)
>           (format t "~%~a " *package*))
>    finally (print "finish"))
>   (in-package :server)
>   (delete-package ',user-name)
>   ))
>
> (defun run-trepl (user-name)
>   (trepl user-name)
>   )
>
> Please I need a help to find mistake in this code.

Look at macroexpansion of (trepl user-name):

* (macroexpand '(trepl user-name))
(PROGN
 (MAKE-PACKAGE 'USER-NAME
    :USE '(:CL :SERVER)) (IN-PACKAGE USER-NAME)
 (FORMAT T "~%~s " *PACKAGE*)
 (LOOP UNTIL (EQUAL (SETF SFORM (READ T)) :EXIT) DO
  (PROGN (PRINT (IF (EQUAL SFORM :EXIT) (LOOP-FINISH) (EVAL SFORM)) T)
   (FORMAT T "~%~a " *PACKAGE*))
  FINALLY (PRINT "finish"))
 (IN-PACKAGE :SERVER)
 (DELETE-PACKAGE 'USER-NAME))


So, when you use (trepl user-name) in a run-trepl, user-name symbol
gets hard-coded as constant, not variable.

There are several possibilities:

1.  Do not quote argument of trepl in expansion, i.e. write ,trepl
    instead of ',trepl

2.  (Better) Rewrite trepl as a function.  It is easy.

3.  Learn how macros work and re-write code in a way you really need.
    Hint: macros are expanded during compilation!  So, they are not
    re-expanded each time you call run-trepl.

Yet another hint: use (let ((*package* (make-package user-name ...))) ...)
instead of double (in-package ...).

And last hint for today: you haven't defined sform.  It must be
defined somewhere (locally with LET may be best, but it depends on
your goals).

-- 
Ivan Boldyrev

Violets are red, Roses are blue. //
I'm schizophrenic, And so am I.
From: Michael Bohn
Subject: Re: make-package on the fly
Date: 
Message-ID: <456d6e52$0$27612$9b4e6d93@newsspool2.arcor-online.net>
I have a questing about changing the package during runtime (LispWorks)

I'm doing:
  (let ((*package* (find-package package))) ;package = cl-user
        (eval '(defun my-function () "bla")))

Why do I not see my-function afterward in the Listener, although I'm in 
the package cl-user?

Running the code above again with (eval '(my-function)) return the 
expected string.

Greeting
Michael Bohn


Dmitry V. Gorbatovsky wrote:
> Hello, I new to lisp ,writing specialized
> server , kind of multiuser lisp enviroment.
> 
> I am trying to separate namespaces by creating 
> user-package for every user-name/connection.
> (instead of more conventional approach of forking
> environment). That maybe wrong approach by themself (???).
> 
> After 2 days of coding (run-trepl "something") still not
> working:
> 
> (defmacro trepl (user-name)
> `(progn
>   (make-package ',user-name
>          :use '(:cl :server))
>   (in-package ,user-name)
>   (format t "~%~s " *package*)
>   (loop
>      until (equal (setf sform (read t)) :exit)
>       do (progn
>           (print (if (equal sform :exit)
>                      (loop-finish)
>                      (eval sform)) t)
>           (format t "~%~a " *package*))
>    finally (print "finish"))
>   (in-package :server)
>   (delete-package ',user-name)
>   ))
> 
> (defun run-trepl (user-name)
>   (trepl user-name)
>   )
> 
> Please I need a help to find mistake in this code.
> Any architectural suggestions would be also highly appreciated.  
> 
> Thanks, Dmitry
> 
From: Rob Warnock
Subject: Re: make-package on the fly
Date: 
Message-ID: <Ru6dnf_cv4Hd7vDYnZ2dnUVZ_qudnZ2d@speakeasy.net>
Michael Bohn  <············@gmx.de> wrote:
+---------------
| I have a questing about changing the package during runtime (LispWorks)
| I'm doing:
|   (let ((*package* (find-package package))) ;package = cl-user
|         (eval '(defun my-function () "bla")))
| 
| Why do I not see my-function afterward in the Listener, although I'm in 
| the package cl-user?
+---------------

Hint: What package were you in when you typed
[or when Lisp read] the LET form?


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Pascal Costanza
Subject: Re: make-package on the fly
Date: 
Message-ID: <4t5bt0F128qctU1@mid.individual.net>
Michael Bohn wrote:
> I have a questing about changing the package during runtime (LispWorks)
> 
> I'm doing:
>  (let ((*package* (find-package package))) ;package = cl-user
>        (eval '(defun my-function () "bla")))
> 
> Why do I not see my-function afterward in the Listener, although I'm in 
> the package cl-user?
> 
> Running the code above again with (eval '(my-function)) return the 
> expected string.

Changing *package* has an effect on the reader, i.e., the program that 
reads strings and turns them into s-expressions. You are not reading 
anything here.

The following would make a difference:

(let ((*package* ...))
   (read-from-string "(defun my-function () 'bla)"))


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Michael Bohn
Subject: Re: make-package on the fly
Date: 
Message-ID: <456d817b$0$27612$9b4e6d93@newsspool2.arcor-online.net>
Pascal Costanza wrote:
> Michael Bohn wrote:
>> I have a questing about changing the package during runtime (LispWorks)
>>
>> I'm doing:
>>  (let ((*package* (find-package package))) ;package = cl-user
>>        (eval '(defun my-function () "bla")))
>>
>> Why do I not see my-function afterward in the Listener, although I'm 
>> in the package cl-user?
>>
>> Running the code above again with (eval '(my-function)) return the 
>> expected string.
> 
> Changing *package* has an effect on the reader, i.e., the program that 
> reads strings and turns them into s-expressions. You are not reading 
> anything here.
> 
> The following would make a difference:
> 
> (let ((*package* ...))
>   (read-from-string "(defun my-function () 'bla)"))
> 
> 
> Pascal
> 

Ok, I understand that now. Thank you very much for your answer.