From: Pascal J. Bourguignon on
Peter Keller <psilord(a)cs.wisc.edu> writes:

> In my case, I've implemented a master/worker paradigm with distributed
> processes. The master process packs up the worker's task data along with the
> symbol associated with the function on the worker side and sends it to the
> worker process in an RPC-like model. I use cl-serializer, so I actually do send
> the target function's symbol to the client side, which arrives uninterned--it
> could just have easily been the string of the function's name though.

So you are reading symbol names. You have strings, not symbols to
start with, and this is a reading problem. Why didn't you tell first?


The easy solution, is to set *PRINT-READABLY* true when you serialize
your function names:

(in-package :cl-user)
(let ((*print-readably* t))
(print 'y::sz))

prints:

|Y|::|SZ|

So that there may be no ambiguity on the reading side.


If you don't want to do that (I'd wonder why?), then you would have to
make assumptions on the reading side, such as, in what package should
unqualified symbols be read, and with what readtable-case setting?

For example:

(with-standard-io-syntax
(let ((*package* (find-package "Y")))
(read-from-string "sz")))

--> Y::SZ



> My problem lies in that the master/worker library is package X, and the
> application built on it is package Y.

No, this is irrelevant.


> I suppose I could bind the value of *package* into the task structure from the
> master to the worker, and the worker could use that while interning the symbol
> same and using symbol-function on it, but I went down that road for a bit and
> couldn't get it working. Should I try again?

Yes. But my advice is to use *print-readably* = true.



> In C, I would just associate a function pointer with the string in a hash table
> and use that since there is no notion of namespaces (and don't forget the
> master and worker are the exact same executable). In Lisp (to which I'm new),
> it is confounded somewhat, so I'd like to know how to solve it.

Imagine you have several hash-tables!

Each package is one map from symbol names to symbols, often different symbols.



--
__Pascal Bourguignon__ http://www.informatimago.com/
From: Scott L. Burson on
On Jun 27, 4:06 pm, Peter Keller <psil...(a)cs.wisc.edu> wrote:
> In my case, I've implemented a master/worker paradigm with distributed
> processes. The master process packs up the worker's task data along with the
> symbol associated with the function on the worker side and sends it to the
> worker process in an RPC-like model. I use cl-serializer, so I actually do send
> the target function's symbol to the client side, which arrives uninterned--it
> could just have easily been the string of the function's name though.

I haven't used cl-serializer, but I would suggest it is standard
practice for a serializer to preserve the package of a serialized
symbol. Certainly the Lisp printer/reader can be made to do this
easily enough, and a high-speed binary serializer I once wrote did it
as well. It seems odd that cl-serializer does not. Perhaps there is
some option you can set to cause it to do so?

> I suppose I could bind the value of *package* into the task structure from the
> master to the worker, and the worker could use that while interning the symbol
> same and using symbol-function on it, but I went down that road for a bit and
> couldn't get it working. Should I try again?

My suggestion at this point would be first to try to get cl-serializer
to do the right thing, but if that proves difficult for some reason,
try to do this -- or maybe try a different serializer :)

(Really, the first thing to ask yourself is whether the Lisp printer/
reader is an adequate serializer for your purposes.)

-- Scott
From: Peter Keller on
Pascal J. Bourguignon <pjb(a)informatimago.com> wrote:
> Peter Keller <psilord(a)cs.wisc.edu> writes:
>
>> In my case, I've implemented a master/worker paradigm with distributed
>> processes. The master process packs up the worker's task data along with the
>> symbol associated with the function on the worker side and sends it to the
>> worker process in an RPC-like model. I use cl-serializer, so I actually do send
>> the target function's symbol to the client side, which arrives uninterned--it
>> could just have easily been the string of the function's name though.
>
> So you are reading symbol names. You have strings, not symbols to
> start with, and this is a reading problem. Why didn't you tell first?

Ah, you misunderstand, I really do have the symbol names for the functions. I
have an easy choice between the unqualified symbolic name of a function, or the
unqualified string representation of the funtion's name.

From your response, however, it looks like my problem is that they are
unqualified.

> The easy solution, is to set *PRINT-READABLY* true when you serialize
> your function names:
>
> (in-package :cl-user)
> (let ((*print-readably* t))
> (print 'y::sz))
>
> prints:
>
> |Y|::|SZ|
>
> So that there may be no ambiguity on the reading side.

> If you don't want to do that (I'd wonder why?), then you would have to
> make assumptions on the reading side, such as, in what package should
> unqualified symbols be read, and with what readtable-case setting?
>
> For example:
>
> (with-standard-io-syntax
> (let ((*package* (find-package "Y")))
> (read-from-string "sz")))
>
> --> Y::SZ

The common idea in both of these solutions you've provided is that the SZ
symbol is qualified with a package name.

So, basically, when I'm storing the symbol of the function I need to call, I
need to store the fully qualified name of the symbol. Then on the client
side, the invocation of it will pick it from the right package properly.

>> My problem lies in that the master/worker library is package X, and the
>> application built on it is package Y.
>
> No, this is irrelevant.

I think I might have a small understanding of why you said this. But I'll need
to experiment a bit more to really understand it.

Thank you for your help. I'll try out some of the above and see if I learn
something.

At least after a bit, if I continue not to understand, I'll probably be able to
state my question more precisely.

-pete
From: Peter Keller on
Scott L. Burson <gyro(a)zeta-soft.com> wrote:
> On Jun 27, 4:06?pm, Peter Keller <psil...(a)cs.wisc.edu> wrote:
> I haven't used cl-serializer, but I would suggest it is standard
> practice for a serializer to preserve the package of a serialized
> symbol. Certainly the Lisp printer/reader can be made to do this
> easily enough, and a high-speed binary serializer I once wrote did it
> as well. It seems odd that cl-serializer does not. Perhaps there is
> some option you can set to cause it to do so?

I have no idea. It seems likely not since there are exactly two functions
that it exports: serialize, and deserialize. :)

> My suggestion at this point would be first to try to get cl-serializer
> to do the right thing, but if that proves difficult for some reason,
> try to do this -- or maybe try a different serializer :)

I can ask around in #iolib, I think one of the people there might have had a
hand in writing it.

> (Really, the first thing to ask yourself is whether the Lisp printer/
> reader is an adequate serializer for your purposes.)

I need something to serialize almost arbitrary lisp forms down to an unsigned
byte array since it makes my network communications infintely easier to
perform.

-pete
From: Pascal J. Bourguignon on
Peter Keller <psilord(a)cs.wisc.edu> writes:

> Pascal J. Bourguignon <pjb(a)informatimago.com> wrote:
>> Peter Keller <psilord(a)cs.wisc.edu> writes:
>>
>>> In my case, I've implemented a master/worker paradigm with distributed
>>> processes. The master process packs up the worker's task data along with the
>>> symbol associated with the function on the worker side and sends it to the
>>> worker process in an RPC-like model. I use cl-serializer, so I actually do send
>>> the target function's symbol to the client side, which arrives uninterned--it
>>> could just have easily been the string of the function's name though.
>>
>> So you are reading symbol names. You have strings, not symbols to
>> start with, and this is a reading problem. Why didn't you tell first?
>
> Ah, you misunderstand, I really do have the symbol names for the functions.

Symbol names are strings:

(typep (symbol-name 'toto) 'string) --> T

When you serialize, using PRINT and deserializing using READ, you are
converting lisp objects to sequences of characters and back. And
STRINGs are sequences of characters. Don't let you be misled by the
fact that some sequences of character are "dynamic", transmitted on
sockets, ttys, or files, in time, while the others are stored
statically in memory.



> I have an easy choice between the unqualified symbolic name of a
> function, or the unqualified string representation of the funtion's
> name.
>
> From your response, however, it looks like my problem is that they are
> unqualified.
>
>> The easy solution, is to set *PRINT-READABLY* true when you serialize
>> your function names:
>>
>> (in-package :cl-user)
>> (let ((*print-readably* t))
>> (print 'y::sz))
>>
>> prints:
>>
>> |Y|::|SZ|
>>
>> So that there may be no ambiguity on the reading side.
>
>> If you don't want to do that (I'd wonder why?), then you would have to
>> make assumptions on the reading side, such as, in what package should
>> unqualified symbols be read, and with what readtable-case setting?
>>
>> For example:
>>
>> (with-standard-io-syntax
>> (let ((*package* (find-package "Y")))
>> (read-from-string "sz")))
>>
>> --> Y::SZ
>
> The common idea in both of these solutions you've provided is that the SZ
> symbol is qualified with a package name.
>
> So, basically, when I'm storing the symbol of the function I need to call, I
> need to store the fully qualified name of the symbol. Then on the client
> side, the invocation of it will pick it from the right package properly.


If you are "storing" a symbol, you don't need anything else than the
symbol A symbol can even have no package!

(defun g (fname)
(format t "I will call the function named ~A (~:*~S)~%" fname)
(funcall fname))

(let ((fname (gensym)))
(setf (symbol-function fname) (lambda () (print 'hi)))
(g fname))

prints:

| I will call the function named G11357 (#:G11357)
|
| HI

(defun y::f () (print '(hi from y)))

(g 'y::f)

prints:

| I will call the function named F (Y::F)
|
| (HI FROM Y)


Again, qualification only matters when you are READing a symbol, that
is, when you are deserializing it. And when you are PRINTing a
symbol, you can do so READABLY, so that qualification is produced, and
ambiguity removed.


>>> My problem lies in that the master/worker library is package X, and the
>>> application built on it is package Y.
>>
>> No, this is irrelevant.
>
> I think I might have a small understanding of why you said this. But I'll need
> to experiment a bit more to really understand it.

What could matter, is that PRINTing and READing occurs with two
different setting of the current package, *PACKAGE*.

If you bound *PACKAGE* to the same one at both ends, you could get
more consistent results. For example, using WITH-STANDARD-IO-SYNTAX,
which binds *PACKAGE* to the CL-USER package and *PRINT-READABLY* to
true.


> Thank you for your help. I'll try out some of the above and see if I learn
> something.
>
> At least after a bit, if I continue not to understand, I'll probably be able to
> state my question more precisely.
>
> -pete

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