What is the proper way to write out expressions which are prepended with "#.", so they will be evaluated upon being read?
For example, I have a list of "point" objects, which have to be created with the function (macro, actually) "make-point" (that is, their printed representation is not sufficient to read them back in, so one has to re-create them by evaluating an expression). So I want to write this list out as a list of expressions, similar to this:
(#.(make-point 1 2 3) #.(make-point 4 5 6) ...)
such that when read in, each expression will automatically be converted into the result of the call to make-point.
I can make a list of the make-point expressions with something like the following:
(mapcar #'point-expression point-list)
which will produce
((make-point 1 2 3) (make-point 4 5 6) ...)
But, how do I produce a list in which each element ends up prepended by the "#." in the printed representation?
(I know i could kludge something together with strings containing the "#.", but I am hoping to be able to pretty-print an actual list)
In article <3AE9EEC3.13F4B...@genworks.com>, <dcoo...@genworks.com> wrote:
>Sorry if i'm missing something obvious, but:...
>What is the proper way to write out expressions which >are prepended with "#.", so they will be evaluated >upon being read?
>For example, I have a list of "point" objects, which >have to be created with the function (macro, actually) >"make-point" (that is, their printed representation is >not sufficient to read them back in, so one has to >re-create them by evaluating an expression). So I want >to write this list out as a list of expressions, similar >to this:
>such that when read in, each expression will automatically >be converted into the result of the call to make-point.
>I can make a list of the make-point expressions with >something like the following:
>(mapcar #'point-expression point-list)
>which will produce
> ((make-point 1 2 3) > (make-point 4 5 6) > ...)
>But, how do I produce a list in which each element ends >up prepended by the "#." in the printed representation?
>(I know i could kludge something together with strings >containing the "#.", but I am hoping to be able to >pretty-print an actual list)
There's nothing that automatically prints objects using #. syntax. If you've defined the POINT type using DEFCLASS or DEFSTRUCT, you can arrange for a user-defined function to be used to print them:
-- Barry Margolin, bar...@genuity.net Genuity, Burlington, MA *** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups. Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
It sounds like you're looking for some magic value that gets printed out as "#.". There's no portable way to do that, though some implementations might have some magic that enables that. To do what you want I'd try this:
> What is the proper way to write out expressions which > are prepended with "#.", so they will be evaluated > upon being read?
> For example, I have a list of "point" objects, which > have to be created with the function (macro, actually) > "make-point" (that is, their printed representation is > not sufficient to read them back in, so one has to > re-create them by evaluating an expression). So I want > to write this list out as a list of expressions, similar > to this:
Barry Margolin <bar...@genuity.net> writes: > There's nothing that automatically prints objects using #. syntax. If > you've defined the POINT type using DEFCLASS or DEFSTRUCT, you can arrange > for a user-defined function to be used to print them:
Doing it without the class defaults to class T, which is something users shouldn't be redefining.
I assume this was just a typo on Barry's part, but wanted to make sure anyone experimenting does this right.
- - - - -
Of course, the other way to do this is to define the point with defstruct and then it will be re-readable with #S with no special work.
The only disadvantage of #.(...) is that a lot of people bind *read-eval* when reading forms, and in that case you'll lose on the re-read. To counteract that, you might be better off to take some other dispatch on # and make something similar to #S but with user-definable characteristics. e.g., define a #_ or #U or some other undefined thing to read a (POINT :X 3 :Y 4 :Z 5) and turn it into (apply #'make-instance the-expression-seen-by-read) to obtain the object to return. It's a darned shame that #S is not thusly defined. I seem to recall I tried to get the committee to generalize its effect but for some reason it didn't go through--maybe it was after the feature freeze...
> The only disadvantage of #.(...) is that a lot of people bind *read-eval* > when reading forms, and in that case you'll lose on the re-read. To > counteract that, you might be better off to take some other dispatch on # > and make something similar to #S but with user-definable characteristics. : > I seem to recall I tried to get the committee to generalize its effect > but for some reason it didn't go through--maybe it was after the feature > freeze...
I have taken to define #/ as a reader-macro akin to the format control, to read _registered_ types with associated functions, as I ran out of convenient ways to specify classes and such.
In this particular case, #/point/(1 2 3), would require a registered type named point with an associated reader function that that would read as many arguments as it needs using whatever printer controls and reader functions it pleased, but it would of course be the question of more or less reasoanble usages, as with every other powerful mechanism. E.g., #/ip/192.168.150.155/26 could mean the address and a 26-bit mask for routing or matching purposes, whild #/ip/192.168.150.155:5555 could mean an address and a port number. And #/md5/0123456789abcdeffedcba9876543210 could mean the hexadecimal representation of an MD5 sum.
Given this framework, would be a very simple task to supply macros that defined and registered reader functions and corresponding print-object methods for new classes.
#:Erik -- I found no peace in solitude. I found no chaos in catastrophe. -- :wumpscut:
kmp> It's a darned shame that #S is not thusly defined.
never thought about that, but yeah, since it's not asking to much to make an implementation allow make-instance to work with structs as well (I know most commercial ones do), this is an obvious extension.
So here's a question I probably should have asked ages ago:
What would it take to have this change occur in ANSI Common Lisp? i.e. when will Common Lisp change, if ever?
I wouldn't mind things like this changing, though I also do realize that such a change would modify the behaviour of some of the code that's out there. But in a case like this, it seems worthwhile.
Erik Naggum <e...@naggum.net> writes: > * Kent M Pitman > > The only disadvantage of #.(...) is that a lot of people bind *read-eval* > > when reading forms, and in that case you'll lose on the re-read. To > > counteract that, you might be better off to take some other dispatch on # > > and make something similar to #S but with user-definable characteristics. > : > > I seem to recall I tried to get the committee to generalize its effect > > but for some reason it didn't go through--maybe it was after the feature > > freeze...
> I have taken to define #/ as a reader-macro akin to the format control, > to read _registered_ types with associated functions, as I ran out of > convenient ways to specify classes and such.
> In this particular case, #/point/(1 2 3), would require a registered type > named point with an associated reader function that that would read as > many arguments as it needs using whatever printer controls and reader > functions it pleased, but it would of course be the question of more or > less reasoanble usages, as with every other powerful mechanism. E.g., > #/ip/192.168.150.155/26 could mean the address and a 26-bit mask for > routing or matching purposes, whild #/ip/192.168.150.155:5555 could mean > an address and a port number. And #/md5/0123456789abcdeffedcba9876543210 > could mean the hexadecimal representation of an MD5 sum.
The only problem with this is that there is a convention (not sure if it's documented or not) that #<char> should be followed by exactly one readable token, for the case of making #- skip the right number of tokesn in a place where the object is not implemented.
> Given this framework, would be a very simple task to supply macros that > defined and registered reader functions and corresponding print-object > methods for new classes.
I agree with your intent, and another notation I've periodically wished for is like this: #_point(1 2 3)
But because of other practicalities would rather #S(MD5 :CODE "0123456789abcdeffedcba9876543210") and #S(IP :ADDRESS "192.168.150.155" :PORT "5555"). Absent support for extensible #S, #_ or whatever. The other advantage of the #S approach is that if the parser is proprietary for things like an IP address or a URL, it's easier to conjure a "parser" for #S-style structures (since it's just an application of GETF) than for the other notations you suggest, even if they are more compact.
David Bakhash <ca...@alum.mit.edu> writes: > >>>>> "kmp" == Kent M Pitman <Kent> writes:
> kmp> It's a darned shame that #S is not thusly defined.
> never thought about that, but yeah, since it's not asking to much to > make an implementation allow make-instance to work with structs as > well (I know most commercial ones do), this is an obvious extension.
> So here's a question I probably should have asked ages ago:
> What would it take to have this change occur in ANSI Common Lisp?
A miracle.
> i.e. when will Common Lisp change, if ever?
Hopefully never. The cost of it changing is very high.
> I wouldn't mind things like this changing, though I also do realize > that such a change would modify the behaviour of some of the code > that's out there. But in a case like this, it seems worthwhile.
I think the change could be made enough compatibly that individual vendors might be convinced to make this change as an extension, and we might be able to have it be a de facto standard.
Send a bug report to your vendors. Let's see if we can rally enough individual vendors to make the extension that it gets in.
I *think* this is what I would ask for. Someone correct me if this doesn't sound right:
If the <NAME> in #S(<NAME> . <OPTIONS>) is not defined as a structure, the effect of (APPLY #'MAKE-INSTANCE '<NAME> '<OPTIONS>) is done.
Frankly, I've never understood why we didn't just make it so that
(MAKE-INSTANCE '<structure-class-name> ...)
was a synonym for
(MAKE-<structure-class-name> ...)
[well, or vice versa]
Then it would be really obvious how to implement #S and the extension would fall out naturally instead of requiring dealing with structures and non-structures as special cases.
One reason I advocated this #S notation, btw, is that it can be used for built-in-classes as well, especially when *PRINT-READABLY* is true and the standard syntax isn't enough to allow proper re-reading of the structure. For example, hash tables, displaced arrays, etc. It requires some detailing to make sure the names of the "slots" of these objects, such as they are, are named. e.g., to decide that an array's contents is its :contents or :storage or whatever, and whether the length is explicit or implicit, and whether the contents beyond the fill pointer is shown, and all that. But still, these are things that could have been worked out, and would have been useful to the community.
Thank you for your replies. The defmethod of print-object is what the doctor ordered. I couldn't define a new print-object method for this point type itself, as doing so would have affected the printing of points everywhere else in the application (e.g. in object inspectors etc.)
So what I ended up doing was (the point type I am dealing with supports accessors get-x, get-y, and get-z):
(I had to specify the "cl" package with defmethod because by default any package using the "icad-supported" package sees the Flavors defmethod rather than the CLOS one).
Thank you for your replies. The defmethod of print-object is what the doctor ordered. I couldn't define a new print-object method for this point type itself, as doing so would have affected the printing of points everywhere else in the application (e.g. in object inspectors etc.)
So what I ended up doing was (the point type I am dealing with supports accessors get-x, get-y, and get-z):
(I had to specify the "cl" package with defmethod because by default any package using the "icad-supported" package sees the Flavors defmethod rather than the CLOS one).
> The only problem with this is that there is a convention (not sure if > it's documented or not) that #<char> should be followed by exactly one > readable token, for the case of making #- skip the right number of tokesn > in a place where the object is not implemented.
I do not agree with this. Input to the reader that use these notations either have an in-syntax form at the top to establish the readtable, and that would fail before #- would fail, or operate under an assumption made explicit elsewhere if not in the input stream that such readtables are employed.
> The other advantage of the #S approach is that if the parser is > proprietary for things like an IP address or a URL, it's easier to > conjure a "parser" for #S-style structures (since it's just an > application of GETF) than for the other notations you suggest, even if > they are more compact.
Compactness is not the driving concern. The driving concern is the ability to register types (or whatever else is suitable) so that the syntax is _not_ open-ended as far as the reading process is concerned, such as #. is. #. also returns objects of type t, whatever is returned as the primary value of the form evaluated, which may be a strain on the human reader of the code. #/.../ would return objects of a known type, identified by name. #S has this feature, but it requires a parsed-out list of arguments. There are good reasons we invent new syntaxes, such as for pathnames, symbols-with-packages, etc, even though they have some costs: e.g., #S(symbol :name "FOO" :package "BAR") is conceptually the same as bar:foo.
#:Erik -- I found no peace in solitude. I found no chaos in catastrophe. -- :wumpscut:
I really wish ICAD didn't clobbered defmethod either. My personal preference is to use pure Lisp (especially CLOS) over IDL whenever possible. We deal with enormous amounts of data and the difference between loop and let-streams is significant.
david.coo...@genworks.com wrote: > Dear Barry, Tim, and Kent,
> Thank you for your replies. The defmethod of print-object is > what the doctor ordered. I couldn't define a new print-object > method for this point type itself, as doing so would have > affected the printing of points everywhere else in the > application (e.g. in object inspectors etc.)
> So what I ended up doing was (the point type I am dealing > with supports accessors get-x, get-y, and get-z):
> (I had to specify the "cl" package with defmethod because > by default any package using the "icad-supported" package > sees the Flavors defmethod rather than the CLOS one).
> There is of course some overhead involved in creating > all those temporary structs when doing the output, but > for my usage this will not be an issue.