How do I access an unknown instance's slot using a string? - lisp

Problem
Given an instance, inst and a string attr containing the name of a slot, how can I obtain the value of the slot attr on inst?
Of course, if attr were a symbol rather than a string, I would typically just use (slot-value inst attr), but it seems I need the package information to properly call intern (see below).
Minimal example
(defpackage :pack1
(:use :common-lisp)
(:export :*inst*))
(in-package :pack1)
(defclass temp-class ()
((temp-slot :initarg :temp-slot)))
(defvar *inst* (make-instance 'temp-class :temp-slot "value"))
(defpackage :pack2
(:use :common-lisp :pack1)
(:import-from :pack1 :temp-class))
(in-package :pack2)
(let ((inst *inst*) ; In the real example, inst gets defined outside my control,
; in yet another package
(attr "temp-slot"))
(format t "Given package name: ~S; " ; prints fine
(slot-value inst (intern (string-upcase attr) :pack1)))
(format t "No package name: ~S; " ; signals an error
(slot-value inst (intern (string-upcase attr)))))
Prior art
From this question, I figured out that my problem was that intern was creating symbols in a different package than the one in which the class was defined.
It seems from this question, that I can't extract the package information simply from the instance, so I'll have to figure out another way (besides using intern to get there)
Background
I'm working on py-format a Common Lisp port of
Python's {}-formatting. To implement the Python . operator (getattr) I need to convert the
string following the dot into a slot on the object preceding the dot.

Given an instance, inst and a string attr containing the name of a slot, how can I obtain the value of the slot attr on inst?
Slots don't have strings as slots names, but symbols. Since slot names can be arbitrary symbols, there is no general way to get a slot-value if all you have is a string.
CL-USER 124 > (defclass foo ()
((s) ; the slot-name is cl-user::s
(system::s) ; the slot-name is system::s
(#:s))) ; the slot-name is #:s
#<STANDARD-CLASS FOO 413054236B>
The last slot-name is an uninterned symbol. It is in no package.
Thus you can't look it up in any way, if you haven't stored it somewhere.
CL-USER 125 > (make-instance 'foo)
#<FOO 402013F043>
CL-USER 126 > (describe *)
#<FOO 402013F043> is a FOO
S #<unbound slot>
S #<unbound slot>
S #<unbound slot>
As you see above, it has three slots. Each symbol has the name s, but is really a different symbol.
You can get the slot names via introspection:
CL-USER 127 > (mapcar #'slot-definition-name
(class-direct-slots (find-class 'foo)))
(S SYSTEM::S #:S)
For portable functions see CLOSER-MOP.

Related

How to use a parameter in a macro call?

I have defined the following simple macro:
(defmacro define-class (class-name)
`(defclass ,class-name ()()))
And now I want to use it in the following function:
(defun create-data (mode)
(define-class mode))
After compiling the last function I get the following message, the variable MODE is defined but never used.
And when I execute the function to create a class "myclass", I get instead the creation of a class of type "mode":
(create-data 'myclass)
#<STANDARD-CLASS MODE>
Seems that my argument is not used? How can I get the function create-data to use the argument?
defclass isn't a function but a macro. It uses the name provided in the source (mode in your case) and it's not the same as your variable mode. In fact some CL implementations would warn you that argument mode is never used.
You can macroexpand it (macroexpand '(defclass mode ()())) to check what it becomes in your implementation. I get this in CLISP (I've cleaned it up a little):
(progn
(eval-when (compile load eval)
(apply #'ensure-class
'mode ; notice mode is quoted
:direct-superclasses (list)
:direct-slots (list)
:metaclass clos::<standard-class>
(append '(:fixed-slot-locations nil)
(list :direct-default-initargs nil
:documentation nil
:generic-accessors 't))))
(find-class 'mode)) ; notice mode is quoted
The expansion is imlementation dependent but the result is the same in all. mode is the name of the class being defined and not what you pass as argument.
You should use (define-class myclass) instead of (create-data 'myclass).
I would use something like this:
CL-USER 86 > (defmacro define-class (class-name)
`(defclass ,class-name ()()))
DEFINE-CLASS
CL-USER 87 > (defun create-data (mode)
(funcall (compile nil `(lambda ()
(define-class ,mode)))))
CREATE-DATA
CL-USER 88 > (create-data 'bar)
#<STANDARD-CLASS BAR 402016CC73>
Above uses code generation and the built-in compiler.

Common Lisp: Hunchentoot: Strange behavior with ASSOC

I'm using this plist as a datastructure:
SHALA-SYS> (pass-of (student-from-name "mozart reina"))
(:TYPE M :START-DATE #2015-01-03T15:29:25.000000+09:00 :AMT 17000)
And using this table as a reference to match the types with certain numerical values:
(defparameter *type-map* '((M . 30)
(E . 30)
(W . 7)))
So using assoc in the REPL works as expected:
SHALA-SYS> (assoc (getf (pass-of (student-from-name "mozart reina"))
:type)
*type-map*)
(M . 30)
But when I run the exact same code in Hunchentoot I get nil instead:
(define-easy-handler (dummy-fn :uri "/dummy-fn") ()
(standard-page (:title "")
(htm
(fmt "~A" (assoc (getf (pass-of (student-from-name "mozart reina"))
:type)
*type-map*)))))
NIL
Has anyone had this experience? The only thing I can think of is that somehow MongoDB, which I'm using to persist the data, is somehow screwing with the symbols since it saves them as strings but I run intern on them to get turn them back into symbols, and the REPL doesn't have a problem with it.
This is a FAQ: Using symbols as keys does not seem to work.
If one wants to use symbols as keys into data structures like property-lists, assoc-lists, hash-tables, CLOS objects, ... then one has to make sure that the symbols are interned in the correct package. cl:*package* is the current package and this variable may have different values. For example during development and runtime of a program the value of the default package may be different.
When using CL:INTERN it is useful to give the package as an argument or to bind the cl:*package* variable.
CL-USER 10 > (intern "FOO")
FOO
NIL
CL-USER 11 > (symbol-package *)
#<The COMMON-LISP-USER package, 155/256 internal, 0/4 external>
CL-USER 12 > (INTERN "FOO" "HTTP-USER")
HTTP-USER::FOO
NIL
CL-USER 13 > (let ((*package* (find-package "HTTP-USER")))
(intern "FOO"))
HTTP-USER::FOO
:INTERNAL

combining two variables into one function name in macro

I was toying around with macros and clos, where I created an "object" macro to create instances
(defmacro object (class &rest args)
`(make-instance ',class ,#args))
Now doing this, I also ended up kind of wanting to do something similar for accessor functions created by clos. Example:
(defclass person () ((name :accessor person-name :initarg :name)))
then creating the instance
(setf p1 (object person :name "tom"))
now to get the name from the object obviously I would call person-name, however just as with the object macro, I wanted to create a "gets" macro to do this. So ideally:
(gets person name p1) which then would return the name.
The problem then is the binding of person and name (person-name) and how to do that. Is there anyway to get those two arguments bound together in the macro? sort of like:
(defmacro gets (class var object)
`(,class-,var ,object))
I think I may have misunderstood the original intent. At first I thought you were asking how to generate the accessor names for the class definition, which third part of the answer addresses. After reading through a second time, it actually sounds like you want to generate a new symbol and call it with some argument. That's easy enough too, and is given in the second part of this answer. Both the second and third parts depend on being able to create a symbol with a name that's built from the names of other symbols, and that's what we start with.
"Concatenating" symbols
Each symbol has a name (a string) that you can obtain with symbol-name. You can use concatenate to create a new string from some old strings, and then use intern to get a symbol with the new name.
(intern (concatenate 'string
(symbol-name 'person)
"-"
(symbol-name 'name)))
;=> PERSON-NAME
Reconstructing an accessor name
(defmacro gets (class-name slot-name object)
(let ((accessor-name
(intern (concatenate 'string
(symbol-name class-name)
"-"
(symbol-name slot-name))
(symbol-package class-name))))
`(,accessor-name ,object)))
(macroexpand-1 '(gets person name some-person))
;=> (PERSON-NAME SOME-PERSON)
For a number of reasons, though, this isn't very robust. (i) You don't know whether or not the slot has an accessor of the form <class-name>-<slot-name>. (ii) Even if the slot does have an accessor of the form <class-name>-<slot-name>, you don't know what package it's in. In the code above, I made the reasonable assumption that it's the same as the package of the class name, but that's not at all required. You could have, for instance:
(defclass a:person ()
((b:name :accessor c:person-name)))
and then this approach wouldn't work at all. (iii) This doesn't work with inheritance very well. If you subclass person, say with north-american-person, then you can still call person-name with a north-american-person, but you can't call north-american-person-name with anything. (iv) This seems to be reïnventing slot-value. You can already access the value of a slot using the name of the slot alone with (slot-value object slot-name), and I don't see any reason that your gets macro shouldn't just expand to that. There you wouldn't have to worry about the particular name of the accessor (if it even has one), or the package of the class name, but just the actual name of the slot.
Generating accessor names
You just need to extract the names of the symbols and to generate a new symbol with the desired name.
If you want to automatically generate accessors with defstruct style names, you can do it like this:
(defmacro define-class (name direct-superclasses slots &rest options)
(flet ((%slot (slot)
(destructuring-bind (slot-name &rest options)
(if (listp slot) slot (list slot))
`(,slot-name ,#options :accessor ,(intern (concatenate 'string
(symbol-name name)
"-"
(symbol-name slot-name)))))))
`(defclass ,name ,direct-superclasses
,(mapcar #'%slot slots)
,#options)))
You can check that this produces the kind of code that you'd expect by looking at the macroexpansion:
(pprint (macroexpand-1 '(define-class person ()
((name :type string :initarg :name)
(age :type integer :initarg :age)
home))))
(DEFCLASS PERSON NIL
((NAME :TYPE STRING :INITARG :NAME :ACCESSOR PERSON-NAME)
(AGE :TYPE INTEGER :INITARG :AGE :ACCESSOR PERSON-AGE)
(HOME :ACCESSOR PERSON-HOME)))
And we can see that it works as expected:
(define-class person ()
((name :type string :initarg :name)
(age :type integer :initarg :age)
home))
(person-name (make-instance 'person :name "John"))
;=> "John"
Other comments on your code
(defmacro object (class &rest args)
`(make-instance ',class ,#args))
As Rainer pointed out this isn't very useful. For most cases, it's the same as
(defun object (class &rest args)
(apply 'make-instance class args))
except that you can (funcall #'object …) and (apply #'object …) with the function, but you can't with the macro.
Your gets macro isn't really any more useful than slot-value, which takes an object and the name of a slot. It doesn't require the name of the class, and it will work even if the class doesn't have a reader or accessor.
Don't (naïvely) create symbol names with format
I've been creating symbol names with concatenate and symbol-name. Sometimes you'll see people use format to construct the names, e.g., (format nil "~A-~A" 'person 'name), but that's prone to issues with capitalization settings that can be changed. For instance, in the following, we define a function foo-bar, and note that the format based approach fails, but the concatenate based approach works.
CL-USER> (defun foo-bar ()
(print 'hello))
FOO-BAR
CL-USER> (foo-bar)
HELLO
HELLO
CL-USER> (setf *print-case* :capitalize)
:Capitalize
CL-USER> (funcall (intern (concatenate 'string (symbol-name 'foo) "-" (symbol-name 'bar))))
Hello
Hello
CL-USER> (format nil "~a-~a" 'foo 'bar)
"Foo-Bar"
CL-USER> (intern (format nil "~a-~a" 'foo 'bar))
|Foo-Bar|
Nil
CL-USER> (funcall (intern (format nil "~a-~a" 'foo 'bar)))
; Evaluation aborted on #<Undefined-Function Foo-Bar {1002BF8AF1}>.
The issue here is that we're not preserving the case of the symbol names of the arguments. To preserve the case, we need to explicitly extract the symbol names, rather than letting the print functions map the symbol name to some other string. To illustrate the problem, consider:
CL-USER> (setf (readtable-case *readtable*) :preserve)
PRESERVE
;; The symbol-names of foo and bar are "foo" and "bar", but
;; you're upcasing them, so you end up with the name "FOO-BAR".
CL-USER> (FORMAT NIL "~{~A~^-~}" (MAPCAR 'STRING-UPCASE '(foo bar)))
"FOO-BAR"
;; If you just concatenate their symbol-names, though, you
;; end up with "foo-bar".
CL-USER> (CONCATENATE 'STRING (SYMBOL-NAME 'foo) "-" (SYMBOL-NAME 'bar))
"foo-bar"
;; You can map symbol-name instead of string-upcase, though, and
;; then you'll get the desired result, "foo-bar"
CL-USER> (FORMAT NIL "~{~A~^-~}" (MAPCAR 'SYMBOL-NAME '(foo bar)))
"foo-bar"
This function creates symbols from string designators:
(defun symb (&rest args)
(intern (format nil "~{~a~^-~}" (mapcar #'string args))))
The function uses format, yet passes Joshua's test:
CL-USER> (symb 'foo :bar "BAZ")
FOO-BAR-BAZ
NIL
CL-USER> (defun foo-bar ()
(print 'hello))
FOO-BAR
CL-USER> (foo-bar)
HELLO
HELLO
CL-USER> (setf *print-case* :capitalize)
:Capitalize
CL-USER> (funcall (symb 'foo 'bar))
Hello
Hello
If you want your gets to use accessor methods:
(defmacro gets (class var object)
`(,(intern (format nil "~a-~a" (symbol-name class) (symbol-name var))) ,object))
In general, what you're trying to accomplish is not really useful. make-instance is a well known symbol, easily greppable, part of the standard and optimized by some implementations when the class name is constant. So with your object macro, you're just saving a few characters and a single-quote. Usually, one hides make-instance in specific cases where you don't want to provide a direct way to initialize instances, or more likely, when you want to provide layers of initialization (e.g. phases of initialization, Lisp slots and foreign objects).
PS: I remember vaguely that someone prominent in the standardization of Common Lisp argued in favor of always wrapping/hiding make-instance in a function (e.g. make-<class-name>), but I can't find either a reference or the reasoning.
PPS: Here's a rather old discussion (2004) about it in comp.lang.lisp (and another one from 2002). The main reasons people cite in favor of constructor functions are:
Required arguments; achievable at runtime instead of at compile-time with :initform (error ...) in a slot that requires a provided initial value
Generally, hide implementation details: class instance, structure instance, cons, something else
2.1. Not wanting to export the actual class name
2.2. Being able to return an instance of some other class, usually a subclass
Convenient shorthand for a specific class
I striked always, because it seems proponents to constructor functions for CLOS objects don't necessarily want to hide the protocol that make-instance follows (allocate-instance, initialize-instance → shared-initialize) to implementers or extenders of the API or framework, although they might want to hide it to the consumers of the API or framework.
For something faster, you might want to access slots directly, but that doesn't use accessor methods, and hence doesn't support side-effects, e.g. :before and :after methods:
(defmacro gets (class var object)
(let ((object-var (gensym)))
`(let ((,object-var ,object))
(declare (optimize (speed 3) (safety 0) (debug 0))
(type ,class ,object-var))
(slot-value ,object-var ',var))))
This might be a direct slot access on some implementations.
Finally, you also have with-slots and with-accessors in the standard.
Try playing with something like this:
(let ((a 'a)
(dash '-)
(b 'b))
`(,a,dash,b))
The other possibilities is to use intern, or more user friendly, alexandria's symbolicate.

What is the difference between a keyword symbol and a quoted symbol?

What is the difference between the keyword symbol
:foo
and the quoted symbol:
'foo
Both stand for themselves, and can be used as an identifier. I can see that keyword symbols are mainly used for named parameters, but I was asking myself if it was not possible to implement this using quoted symbols as well?
In other words: Why do I need both?
First: 'something is a shorter notation for (quote something). The reader will transform the quote character into a list with the symbol cl:quote as the first item. For the evaluator it means: don't evaluate something, just return it as a result.
CL-USER 22 > '(quote foo)
(QUOTE FOO)
CL-USER 23 > ''foo
(QUOTE FOO)
CL-USER 24 > (read-from-string "'foo")
(QUOTE FOO)
The colon : is a package marker. If the package name is missing, the symbol is in the KEYWORD package.
We can give foo a value:
CL-USER 11 > (setq foo 10)
10
foo evaluates to its value.
CL-USER 12 > foo
10
A quoted symbol evaluates to the symbol.
CL-USER 13 > 'foo
FOO
We can't give :foo a value:
CL-USER 14 > (setq :foo 10)
Error: Cannot setq :FOO -- it is a keyword.
1 (abort) Return to level 0.
2 Return to top loop level 0.
Type :b for backtrace or :c <option number> to proceed.
Type :bug-form "<subject>" for a bug report template or :? for other options.
CL-USER 15 : 1 > :top
:foo already has a value: itself.
CL-USER 16 > :foo
:FOO
Naturally a quoted :foo evaluates to :foo.
CL-USER 17 > ':foo
:FOO
The symbol foo is in some package, here CL-USER.
CL-USER 18 > (symbol-package 'foo)
#<The COMMON-LISP-USER package, 92/256 internal, 0/4 external>
The symbol :foo is in the KEYWORD package.
CL-USER 19 > (symbol-package ':foo)
#<The KEYWORD package, 0/4 internal, 6230/8192 external>
Since :foo is the value of :foo we can also write:
CL-USER 20 > (symbol-package :foo)
#<The KEYWORD package, 0/4 internal, 6230/8192 external>
:foo is an abbreviation for keyword:foo. Thus the symbol is in the keyword package and it is exported.
CL-USER 21 > keyword:foo
:FOO
So keyword symbols are self-evaluation constant symbols in the keyword package. They are used as markers in data structures and in keyword arglists. The good things: you don't need to struggle with packages and they evaluate to themselves - so a quote is not needed.
DIfferences between keywords and other symbols
Rainer Joswig's answer describes the symbols themselves pretty well. To summarize, though, each symbol belongs to a package. p::foo (or p:foo, if it's external) is a symbol in the package p. If you try to evaluate it as form, you'll get its symbol-value, which you can set with set, or `(setf symbol-value):
CL-USER> (set 'foo 'bar)
BAR
CL-USER> foo
BAR
CL-USER> (setf (symbol-value 'foo) 'baz)
BAZ
CL-USER> foo
BAZ
There's a special package named keyword. You can write keyword::foo if you want, but all of the keyword package's symbol are external, so you can write keyword:foo instead. Because they're so commonly used, though, you even get a special syntax for them: :foo. They've also got the special property that you can't set their value; their values are themselves:
CL-USER> :foo
:FOO
CL-USER> (symbol-value :bar)
:BAR
And that's really all there is that makes keyword symbols special, in and of themselves.
Keywords and other symbols as keyword names in lambda lists
What's probably a bit more important is that they are, by default, used as indicators for "keyword arguments" in lambda lists. E.g.,
CL-USER> ((lambda (&key foo bar)
(list foo bar))
:bar 23 :foo 12)
(12 23)
I can see that keyword symbols are mainly used for named parameters,
but I was asking myself if it was not possible to implement this using
quoted symbols as well?
The syntax for lambda lists actually lets you do a lot more customization with the keyword arguments. A common thing is to specify default values:
CL-USER> ((lambda (&key (foo 'default-foo) bar)
(list foo bar))
:bar 23)
(DEFAULT-FOO 23)
You can also provide a variable name that gets bound to a boolean indicating whether the parameter was specified or not:
CL-USER> ((lambda (&key (foo 'default-foo foo-p) (bar 'default-bar bar-p))
(format t "~{~A:~7t~A~%~}"
(list 'foo foo
'foo-p foo-p
'bar bar
'bar-p bar-p)))
:bar 23)
FOO: DEFAULT-FOO
FOO-P: NIL
BAR: 23
BAR-P: T
The full syntax for from 3.4.1 Ordinary Lambda Lists lets us do even more, though. It's
lambda-list::= (var*
[&optional {var | (var [init-form [supplied-p-parameter]])}*]
[&rest var]
[&key {var | ({var | (keyword-name var)} [init-form [supplied-p-parameter]])}* [&allow-other-keys]]
[&aux {var | (var [init-form])}*])
Note that you can specify the keyword-name. It defaults to the symbol in the keyword package with the same name as var, but you can actually provide it and specify your own "keywords". This can be handy, e.g., if you want a descriptive keyword name but don't want such a long variable name:
CL-USER> ((lambda (&key ((:home-directory dir)))
(list dir))
:home-directory "/home/me")
("/home/me")
You can also use it to specify keyword names that aren't keyword symbols:
CL-USER> ((lambda (&key ((surprise surprise)))
(list surprise))
'surprise "hello world!")
("hello world!")
You can combine the two, too:
CL-USER> ((lambda (&key ((hidden-parameter secret)))
(format t "the secret is ~A" secret))
'hidden-parameter 42)
the secret is 42
You can mix that with default values as well, but you probably get the point by now.

Variable as table name using Lisp/Postmodern/PostgreSQL

Can someone please give an example of how to write a row to a table using a variable as the table name in Lisp/Postmodern/S-SQL/PostgreSQL?
I am currently able to write to a table in PostgreSQL with :insert-into using the following function:
(defun save-event (table-name cost event-id)
(defprepared insert-event
(sql-compile `(:insert-into ,table-name :set 'cost ,cost
'event-id ,event-id)))
(insert-event))
Using the input syntax:
(save-event 'table-name 33 1)
However, if I try and pass a string containing the desired table name to the function as follows:
(defparameter x "table-name")
(apply #'funcall `(save-event ',x 44 2))
I get the following error message:
Database error 42601: syntax error at or near "E'table-name'"
Query: INSERT INTO E'table-name' (cost, event_id) VALUES (44, 2)
[Condition of type CL-POSTGRES-ERROR:SYNTAX-ERROR-OR-ACCESS-VIOLATION]
I have been stuck on this for quite a while, tried almost everything. Got me stumped.
If the code expects a symbol as table name you cannot pass a string, you must intern it.
Something like the following should work...
(defparameter x "table-name")
(save-event (intern x) 44 2)
In common lisp a symbol is a symbol and a string is a string. To get a string from a symbol you need to call (symbol-name x) to get a symbol from a string you need to call (intern x).
Quasiquoting (back quoting) is not going to do this transformation. In other words:
(let ((test "foo"))
`(this is a ,test))
--> (THIS IS A "foo")`
Depending on how the symbol is going to be used by that library may be even an "uninterned" symbol can be used instead of a regular interned symbol.
Those symbols can be created with (make-symbol x) but if this is acceptable or not depends on how the symbol is being used in the code; note also that while (intern x) will always return the same symbol if you call it multiple times with the same string this is not true for (make-symbol x) that instead will return a different fresh uninterned symbol each time is called.
(make-symbol "X")
--> #:X
(symbol-name (make-symbol "X"))
--> "X"
(eq (make-symbol "X") (make-symbol "X"))
--> NIL
(eq (intern "X") (intern "X"))
--> T