gat@robotics.Jpl.Nasa.Gov (Erann Gat) (10/10/90)
Is there any way in Common Lisp to test if an object is a structure? There doesn't seem to be a structurep function. E.
moore%cdr.utah.edu@cs.utah.edu (Tim Moore) (10/10/90)
In article <753@forsight.Jpl.Nasa.Gov> gat@robotics.Jpl.Nasa.Gov (Erann Gat) writes: >Is there any way in Common Lisp to test if an object is a structure? There >doesn't seem to be a structurep function. > >E. Not portably. If your Common Lisp has a fully integrated CLOS, then (defun structurep (x) (typep (class-of x) 'structure-class)) should work. If not... Most implementations leave clues around that a given type is a structure; a glance at a structured type's property list can be instructive. From these clues you can construct your own structure-type-p, e.g. in Utah Common Lisp you could write (defun structure-type-p (x) (get x 'lisp::structure-info)) Then structurep is (defun structurep (x) (structure-type-p (type-of x))) Dick Waters' XP pretty printer uses this technique. Also, all implementations probably have a structure-p predicate that is not documented; you can root around with apropos and use it if you dare. Tim Moore moore@cs.utah.edu {bellcore,hplabs}!utah-cs!moore "Ah, youth. Ah, statute of limitations." -John Waters
cowan@marob.masa.com (John Cowan) (10/10/90)
In article <753@forsight.Jpl.Nasa.Gov> gat@robotics.Jpl.Nasa.Gov (Erann Gat) writes: >Is there any way in Common Lisp to test if an object is a structure? There >doesn't seem to be a structurep function. No, there isn't, and that's intentional. Some of the Common Lisp standard types, notably STREAM, READTABLE, RANDOM-STATE, PATHNAME, and PACKAGE may be implemented using the structure mechanism, but this fact is hidden from the user. A STRUCTUREP function would be unable to discriminate between these implementation-defined structures and user-defined ones. There's very little you can say about a structure qua structure, anyway. The names of the {access, constructor} functions aren't deducible from the outside, given that the default names can be overridden at DEFSTRUCT time. -- cowan@marob.masa.com (aka ...!hombre!marob!cowan) e'osai ko sarji la lojban
gat@robotics.Jpl.Nasa.Gov (Erann Gat) (10/11/90)
In article <1990Oct10.091722.4495@hellgate.utah.edu>, moore%cdr.utah.edu@cs.utah.edu (Tim Moore) writes: > In article <753@forsight.Jpl.Nasa.Gov> gat@robotics.Jpl.Nasa.Gov (Erann Gat) writes: > >Is there any way in Common Lisp to test if an object is a structure? There > >doesn't seem to be a structurep function. > > > >E. > > Not portably. Thanks, that's what I wanted to know. In a later article, Tim writes: > Incidently, I feel that Common Lisp, with the exception of call/cc, > has the same semantic power (and much more) of scheme. Any > disagreement? (Warning, religious war ahead!) You are right, of course. However, there are a number of things that you can do in T which you can't do in Common Lisp. Among these are: 1. Create callable objects (which allow you to do things like SETF a locative passed to a function as an argument) 2. Tell if an object is a structure :-) Personally, I think that it's the "and much more" part that is Common Lisp's biggest problem. It's getting to the point where it is very difficult to get a grip on the entire language. Not only does this make CL hard to write, it encourages writing code that is nearly impossible to read without a copy of CLTL in hand (and sometimes even then). (It also makes it harder to tell when some crtitical feature has been omitted from the language :->) Just my opinion. E.
moore%cdr.utah.edu@cs.utah.edu (Tim Moore) (10/11/90)
In article <754@forsight.Jpl.Nasa.Gov> gat@robotics.Jpl.Nasa.Gov (Erann Gat) writes: >You are right, of course. However, there are a number of things that you >can do in T which you can't do in Common Lisp. Among these are: > >1. Create callable objects (which allow you to do things like SETF a locative >passed to a function as an argument) I'm not sure what you mean by this. If you mean that T has locatives, it's not hard to simulate locatives in Common Lisp (see Lisp Pointers, vol. 2 no. 2); they're just closures that encapsulate the information needed to store into the general variable (I think that's essentially what they are in T; feel free to correct me). I think that locatives a la Lisp Machine Lisp (essentially pointers) are impractical without massive gc complexity or microcode support. >2. Tell if an object is a structure :-) It's unclear why you want to do this. Only system code should really need a structurep. >Personally, I think that it's the "and much more" part that is Common >Lisp's biggest problem. It's getting to the point where it is very difficult >to get a grip on the entire language. Not only does this make CL hard to >write, it encourages writing code that is nearly impossible to read without >a copy of CLTL in hand (and sometimes even then). (It also makes it harder >to tell when some crtitical feature has been omitted from the language :->) The "hard-to-write" argument is the one I hear most frequently, especially around here (where we are close to finishing a CL implementation). I think only a handful of people (Lisp implementors) really care about this. I don't think Common Lisp function names are cryptic. There are a few macros whose syntax is unfortunate, mostly for hysterical raisons. I keep a copy of CLTL around when I write code, mostly to check that what I'm about to write isn't already part of the language. It's easy to write obscure code in any Lisp. > >Just my opinion. >E. That's what the net is for! Tim Moore moore@cs.utah.edu {bellcore,hplabs}!utah-cs!moore "Ah, youth. Ah, statute of limitations." -John Waters
gat@robotics.Jpl.Nasa.Gov (Erann Gat) (10/11/90)
In article <27133D6E.715C@marob.masa.com>, cowan@marob.masa.com (John Cowan) writes: > In article <753@forsight.Jpl.Nasa.Gov> gat@robotics.Jpl.Nasa.Gov (Erann Gat) writes: > >Is there any way in Common Lisp to test if an object is a structure? There > >doesn't seem to be a structurep function. > > No, there isn't, and that's intentional. Some of the Common Lisp standard > types, notably STREAM, READTABLE, RANDOM-STATE, PATHNAME, and PACKAGE > may be implemented using the structure mechanism, but this fact is hidden > from the user. A STRUCTUREP function would be unable to discriminate > between these implementation-defined structures and user-defined ones. Oh, come on! Since the implementation gets to define structurep, it can make explicit checks to exclude other types which the implementation implements as structures. It may not be pretty or efficient, but it's certainly not impossible! > There's very little you can say about a structure qua structure, anyway. > The names of the {access, constructor} functions aren't deducible from the > outside, given that the default names can be overridden at DEFSTRUCT time. This strikes me as another severe deficiency in Common Lisp. Suppose I wanted to write a function that took an arbitrary structure and printed out all the slot names and values. This can't be done in CL, but the inspector can do it so the underlying capability must be there (at least in every implementation I've ever used). This is another example of something that can be done in T but not in CL. (BTW, this function might want to be able to check that its argument was indeed a structure before proceeding.) None of these "impossible" or "impractical" arguments will stand up. It is possible to implement a T-style structure system within Common Lisp. (The details are left as an excercise for the reader.) Perhaps structurep will appear in CLTL3. (Perhaps everyone will see the light and start using T. Perhaps we can banish Fortran. Perhaps the horse will sing. :->) E.
gat@robotics.Jpl.Nasa.Gov (Erann Gat) (10/11/90)
In article <1990Oct10.130925.18317@hellgate.utah.edu>, moore%cdr.utah.edu@cs.utah.edu (Tim Moore) writes: > In article <754@forsight.Jpl.Nasa.Gov> gat@robotics.Jpl.Nasa.Gov (Erann Gat) writes: > >You are right, of course. However, there are a number of things that you > >can do in T which you can't do in Common Lisp. Among these are: > > > >1. Create callable objects (which allow you to do things like SETF a locative > >passed to a function as an argument) > > I'm not sure what you mean by this. See chapter 7 of the T manual. > If you mean that T has locatives, No, I mean callable objects. (See note above.) > it's not hard to simulate locatives in Common Lisp (see Lisp Pointers, > vol. 2 no. 2); they're just closures that encapsulate the information This sounds like a handy book. Where do I find it? > It's unclear why you want to do this. Only system code should really > need a structurep. There are dozens of applications I can think of for structurep. My particular reason is that I have a stream to which I wish to print arbitrary objects but on which it is important that no #S read macros appear. (The reason for that is too lengthy to go into here, and entirely beside the point in any case.) Therefore, I need to be able to tell if the object I am about to print out is a structure so that I can intercept the print function. (And yes, I know about the :print-function option to defstruct. I want to be able to print out structures created by other people as well!) > >Personally, I think that it's the "and much more" part that is Common > >Lisp's biggest problem. It's getting to the point where it is very difficult > >to get a grip on the entire language. Not only does this make CL hard to > >write, it encourages writing code that is nearly impossible to read without > >a copy of CLTL in hand (and sometimes even then). (It also makes it harder > >to tell when some crtitical feature has been omitted from the language :->) > > The "hard-to-write" argument is the one I hear most frequently, > especially around here (where we are close to finishing a CL > implementation). I think only a handful of people (Lisp implementors) > really care about this. I think that the people who buy Common Lisp implementations and have to pay for thousands of obscure features that they never use might care about it as well. > I don't think Common Lisp function names are cryptic. There are a few > macros whose syntax is unfortunate, mostly for hysterical raisons. > > I keep a copy of CLTL around when I write code, mostly to check that > what I'm about to write isn't already part of the language. It's easy > to write obscure code in any Lisp. How can you be sure that what you are writing isn't already part of the language, but that it has an obscure name and is tucked away in a remote corner of Steele's tome? I tend to discover surprizing new features of CL on a fairly regular basis (and pity the poor programmer who spends hours searching through the book saying to himself, "There's just got to be a way to test for structures, there's just got to be! :->) > >Just my opinion. > That's what the net is for! Thanks. E.
gat@robotics.Jpl.Nasa.Gov (Erann Gat) (10/11/90)
In article <1990Oct10.130925.18317@hellgate.utah.edu>, moore%cdr.utah.edu@cs.utah.edu (Tim Moore) writes: > I don't think Common Lisp function names are cryptic. There are a few > macros whose syntax is unfortunate, mostly for hysterical raisons. ^^^^^^^^^^ With this I heartily agree! :-) E.
eliot@phoenix.Princeton.EDU (Eliot Handelman) (10/11/90)
In article <1990Oct10.091722.4495@hellgate.utah.edu>, moore%cdr.utah.edu@cs.utah.edu (Tim Moore) writes: > In article <753@forsight.Jpl.Nasa.Gov> gat@robotics.Jpl.Nasa.Gov (Erann Gat) writes: > >Is there any way in Common Lisp to test if an object is a structure? There > >doesn't seem to be a structurep function. > > ;> >E. ;> ;> Not portably. You can do this, though: >(defstruct structure) >(defstruct (foo (:include structure)) blah) >(structure-p (make-foo)) T Zetalisp, I think, did something like that automatically. the "structure" structure would have DOCUMENTATION as one of its slots, eg. (I've read most of the lisp machine manual, but I don't know too much about its internals, on the other hand.) --eliot
moore%cdr.utah.edu@cs.utah.edu (Tim Moore) (10/11/90)
In article <756@forsight.Jpl.Nasa.Gov> gat@robotics.Jpl.Nasa.Gov (Erann Gat) writes: >In article <1990Oct10.130925.18317@hellgate.utah.edu>, moore%cdr.utah.edu@cs.utah.edu (Tim Moore) writes: >> In article <754@forsight.Jpl.Nasa.Gov> gat@robotics.Jpl.Nasa.Gov (Erann Gat) writes: >> >You are right, of course. However, there are a number of things that you >> >can do in T which you can't do in Common Lisp. Among these are: >> > >> >1. Create callable objects (which allow you to do things like SETF a locative >> >passed to a function as an argument) >> >> I'm not sure what you mean by this. > >See chapter 7 of the T manual. OK, I have. It looks like callable objects are an abstraction of the objects-as-closures style that has appeared in other articles today. Nice as far as that style of object-oriented programming goes. >> it's not hard to simulate locatives in Common Lisp (see Lisp Pointers, >> vol. 2 no. 2); they're just closures that encapsulate the information > >This sounds like a handy book. Where do I find it? > Lisp Pointers is a periodical that is published irregularly. It is now a publication of the ACM. >> It's unclear why you want to do this. Only system code should really >> need a structurep. > >There are dozens of applications I can think of for structurep. My particular >reason is that I have a stream to which I wish to print arbitrary objects >but on which it is important that no #S read macros appear. (The reason >for that is too lengthy to go into here, and entirely beside the point in >any case.) Therefore, I need to be able to tell if the object I am about >to print out is a structure so that I can intercept the print function. >(And yes, I know about the :print-function option to defstruct. I want >to be able to print out structures created by other people as well!) > It's true that there aren't any facilities for getting at the slots of an arbitrary structured type (unless you have the source of the defstruct). I don't know whether this is good or bad. slots of a structured type must exist somewhere in the system in order to support inheritance in a practical manner. It seems like a bad idea to overide a structure's print function, unless you are handling *print-circle*, *print-length*, etc. You might get a nasty surprise. You could print the object to a string and strip the #S... >> I don't think Common Lisp function names are cryptic. There are a few >> macros whose syntax is unfortunate, mostly for hysterical raisons. >> >> I keep a copy of CLTL around when I write code, mostly to check that >> what I'm about to write isn't already part of the language. It's easy >> to write obscure code in any Lisp. > >How can you be sure that what you are writing isn't already part of the >language, but that it has an obscure name and is tucked away in a remote >corner of Steele's tome? I tend to discover surprizing new features of >CL on a fairly regular basis (and pity the poor programmer who spends hours >searching through the book saying to himself, "There's just got to be a >way to test for structures, there's just got to be! :->) I use the index. It's not much different from browsing the Unix manuals for C libraries. Also, experience helps, as with any large language or system. Tim Moore moore@cs.utah.edu {bellcore,hplabs}!utah-cs!moore "Ah, youth. Ah, statute of limitations." -John Waters
gat@robotics.Jpl.Nasa.Gov (Erann Gat) (10/11/90)
In article <1990Oct10.165312.29838@hellgate.utah.edu>, moore%cdr.utah.edu@cs.utah.edu (Tim Moore) writes: > You could print the object to a string and > strip the #S... That's actually not a bad solution to the puzzle: (defun structurep (thing) (equal "#S" (subseq (format nil "~S" thing) 0 2))) This would work for any structure which did not have a :print-function defined. (What a horrible hack, though!) E.
lgm@cbnewsc.att.com (lawrence.g.mayka) (10/11/90)
In article <755@forsight.Jpl.Nasa.Gov>, gat@robotics.Jpl.Nasa.Gov (Erann Gat) writes: > In article <27133D6E.715C@marob.masa.com>, cowan@marob.masa.com (John Cowan) writes: > > In article <753@forsight.Jpl.Nasa.Gov> gat@robotics.Jpl.Nasa.Gov (Erann Gat) writes: > > >Is there any way in Common Lisp to test if an object is a structure? There > > >doesn't seem to be a structurep function. > > > > No, there isn't, and that's intentional. Some of the Common Lisp standard > > types, notably STREAM, READTABLE, RANDOM-STATE, PATHNAME, and PACKAGE > > may be implemented using the structure mechanism, but this fact is hidden > > from the user. A STRUCTUREP function would be unable to discriminate > > between these implementation-defined structures and user-defined ones. > > Oh, come on! Since the implementation gets to define structurep, it > can make explicit checks to exclude other types which the implementation > implements as structures. It may not be pretty or efficient, but it's > certainly not impossible! As someone else has pointed out, ANSI Common Lisp integrates DEFSTRUCTs into the object system (CLOS). One can therefore test for a structure with (TYPEP obj 'STRUCTURE-OBJECT) or (TYPEP (CLASS-OF obj) 'STRUCTURE-CLASS) Predefined types such as STREAM may have a metaclass of either BUILT-IN-CLASS, STRUCTURE-CLASS, or STANDARD-CLASS. > > There's very little you can say about a structure qua structure, anyway. > > The names of the {access, constructor} functions aren't deducible from the > > outside, given that the default names can be overridden at DEFSTRUCT time. > > This strikes me as another severe deficiency in Common Lisp. Suppose I > wanted to write a function that took an arbitrary structure and printed > out all the slot names and values. This can't be done in CL, but the The metaobject protocol (not yet officially standardized, though large parts have been informally agreed upon by major vendors) helps out here: (DOLIST (slot-descriptor (CLASS-SLOTS (CLASS-OF obj))) (LET ((slot-name (SLOT-DEFINITION-NAME slot-descriptor))) (FORMAT T "~&~S : ~S~&" slot-name (SLOT-VALUE obj slot-name)))) Lawrence G. Mayka AT&T Bell Laboratories lgm@iexist.att.com Standard disclaimer.
pazzani@ics.uci.edu (Michael Pazzani) (10/11/90)
In article <758@forsight.Jpl.Nasa.Gov> gat@robotics.Jpl.Nasa.Gov (Erann Gat) writes: >That's actually not a bad solution to the puzzle: > >(defun structurep (thing) > (equal "#S" (subseq (format nil "~S" thing) 0 2))) > >This would work for any structure which did not have a :print-function >defined. (What a horrible hack, though!) > >E. If you get to define the structures (rather than using a large existing program), you could do this in a different way: (defstruct struct) ;; It has no slots, but a struct-p is created now just include struct in every structure you care about, and struct-p will work on them. (defstruct (pig (:include struct)) piglets) (defstruct (goat (:include struct)) kids) etc. (struct-p (make-pig :piglets nil)) Mike
cowan@marob.masa.com (John Cowan) (10/11/90)
Erann Gat writes: [is there a STRUCTUREP in Common Lisp?] I write: [No; standard types can be implemented as structures] Erann replies: >Oh, come on! Since the implementation gets to define structurep, it >can make explicit checks to exclude other types which the implementation >implements as structures. It may not be pretty or efficient, but it's >certainly not impossible! The point is that the non-existence of STRUCTUREP allows freedom to the implementor to make certain choices. Structures are a "raw" construct in CL, with very few specific semantics (see below). >Suppose I >wanted to write a function that took an arbitrary structure and printed >out all the slot names and values. This can't be done in CL, but the >inspector can do it so the underlying capability must be there (at least >in every implementation I've ever used). This is another example of something >that can be done in T but not in CL. (BTW, this function might want to >be able to check that its argument was indeed a structure before proceeding.) The underlying capability is indeed there; however, the implementation is not required to expose it to the user in any systematic way that might constrain >how< this capability is provided. >It is >possible to implement a T-style structure system within Common Lisp. (The >details are left as an excercise for the reader.) Perhaps structurep will >appear in CLTL3. Not only do I know it's possible, I've actually done it. I have a nearly- complete implementation of T3.0 written in Common Lisp (1st ed.). T structures are all instances of a single CL structure type, T::STRUCT, which uses an auxiliary CL structure T::STYPE to hold T-structure-type meta-information. My point is that Common Lisp structures >aren't< T structures, and aren't meant to be. CL structures are a layer of syntactic sugar that allow you to define handy {access, construct, print} functions, and take care of some of the work. The underlying datatype can be a list, a vector, or a MacLisp hunk (i.e. a cons with != 2 components). The "hunk-level" access provided in MacLisp is not standardized by CL, so you can't reliably get at it, and implementers who think they can do better than hunks are free to do so. CL is not designed to require retaining any meta-information at run time about structures, except for what is needed by debugging tools (inspector, etc.) whose interfaces are not standardized. T structures, OTOH, are much more abstract, with considerable meta-information, more like T objects. In fact, we can say that structures only exist in T as a way of making certain kinds of rather "passive" objects more efficient. -- cowan@marob.masa.com (aka ...!hombre!marob!cowan) e'osai ko sarji la lojban
gat@robotics.Jpl.Nasa.Gov (Erann Gat) (10/12/90)
In article <2713DF17.555@ics.uci.edu>, pazzani@ics.uci.edu (Michael Pazzani) writes: > If you get to define the structures (rather than using a large existing > program), you could do this in a different way: > > (defstruct struct) ;; It has no slots, but a struct-p is created > > now just include struct in every structure you care about, and struct-p > will work on them. If I get to define all the structures then I could just as easily just check for all the structure types that I have derfined. There's no sport in that. I want to be able to tell if someone else's data object is a structure. There is actually a portable definition of structurp which no one seems to have thought of. The number of core data types in Common Lisp is finite. Therefore, one can check to see if an object is a structure simply by checking that it is NOT anything else. i.e. something like (defun structurep (object) (and (not (numberp object)) (not (consp object)) (not (symbolp object)) ... [ probably ten or fifteen more would do ] (commonp object))) Of course, in CLTL2 they took out commonp (on the grounds that it wasn't useful for anything!) but they added CLOS which lets you test for structures in other ways. E.
gat@robotics.Jpl.Nasa.Gov (Erann Gat) (10/12/90)
In article <2714943B.1332@marob.masa.com>, cowan@marob.masa.com (John Cowan) writes: > The underlying capability is indeed there; however, the implementation is > not required to expose it to the user in any systematic way that might > constrain >how< this capability is provided. Sorry, I don't see how the requirement to provide structurep to the user would in any way constrain an implementation. As you yourself acknowledge the capability must already exist (mandated implicitly by other parts of the standard) - what impact could it have to require that this capability be exposed in a standard way? E.
jeff@aiai.ed.ac.uk (Jeff Dalton) (10/12/90)
In article <27133D6E.715C@marob.masa.com> cowan@marob.masa.com (John Cowan) writes: >In article <753@forsight.Jpl.Nasa.Gov> gat@robotics.Jpl.Nasa.Gov (Erann Gat) writes: >>Is there any way in Common Lisp to test if an object is a structure? There >>doesn't seem to be a structurep function. >No, there isn't, and that's intentional. Some of the Common Lisp standard >types, notably STREAM, READTABLE, RANDOM-STATE, PATHNAME, and PACKAGE >may be implemented using the structure mechanism, but this fact is hidden >from the user. A STRUCTUREP function would be unable to discriminate >between these implementation-defined structures and user-defined ones. So? Is that supposed to be a bad thing (that some built-in types might be structures)? Note that in Common Lisps with an integrated CLOS (which is how they'll probably all be after a while) you *can* find out if a type is a structure. >There's very little you can say about a structure qua structure, anyway. >The names of the {access, constructor} functions aren't deducible from the >outside, given that the default names can be overridden at DEFSTRUCT time. That's why you need more than STRUCTUREP.
jeff@aiai.ed.ac.uk (Jeff Dalton) (10/18/90)
In article <2714943B.1332@marob.masa.com> cowan@marob.masa.com (John Cowan) writes: >Erann Gat writes: >>Oh, come on! Since the implementation gets to define structurep, it >>can make explicit checks to exclude other types which the implementation >>implements as structures. It may not be pretty or efficient, but it's >>certainly not impossible! > >The point is that the non-existence of STRUCTUREP allows freedom to the >implementor to make certain choices. Structures are a "raw" construct >in CL, with very few specific semantics (see below). Yes, it allows certain choices. But are they choices worth allowing? Earlier you write: [No; standard types can be implemented as structures] Why is *that* a problem? It looks like you're talking about a different aspect of the structure issue in this message. Anyway ... It's a pain that one cannot determine whether an object is a structure and find out what slots it has. For example, you may want to write a print function that works like the normal one in somce cases but not in others. You can't, because the information needed for the normal case isn't available in portable form. (Yes, this is the same example given before.) A number of people have written their own macro, on top of DEFSTRUCT, just to provide such capabilities. Note that (1) they can do this, and (2) the implementation has the same freedom it had before. (BTW, I'm glad to hear you've implemented a T in CL. Good idea.) >My point is that Common Lisp structures >aren't< T structures, and aren't >meant to be. CL structures are a layer of syntactic sugar that allow you >to define handy {access, construct, print} functions, and take care of >some of the work. The underlying datatype can be a list, a vector, or >a MacLisp hunk (i.e. a cons with != 2 components). The "hunk-level" >access provided in MacLisp is not standardized by CL, so you can't reliably >get at it, and implementers who think they can do better than hunks are >free to do so. CL is not designed to require retaining any meta-information >at run time about structures, except for what is needed by debugging >tools (inspector, etc.) whose interfaces are not standardized. 1. STRUCTUREP should probably be true only of structures defined without using the :TYPE option. (N.B. that prevents the name from being a valid type specifier.) 2. DEFSTRUCT defines the name as a type specifier, defines a predicate, and causes a certain syntax to be used when printing. This suggests that structures can be recognized with a fair degree of reliability. STRUCTUREP would have the same reliability (or lack of it), but it shouldn't be harder to provide STRUCTUREP than to provide the predicates. 3. CLtL II says structure types created by DEFSTRUCT must be disjoint from (among other types) CONS and ARRAY. So the freedom to make the underlying type be a list or vector has been removed. -- Jeff