 My co-worker looked a little tense. Our office is in the sixth floor, my window 
was wide open, and somehow I became slightly nervous as he walked up to it.
My co-worker looked a little tense. Our office is in the sixth floor, my window 
was wide open, and somehow I became slightly nervous as he walked up to it.
"Now, you're the Lisp aficionado here, right", he said, "You've got to help me out: 
Strings don't work in property lists!"
Oh, great. Who knows, being regarded (undeservedly) as the local Lisp, ahem, expert 
may become a factor for my job security some day, so I thought I'd better keep a 
straight face. Besides, he was still standing close to that window, and I wanted to 
leave nothing but a reassuring impression on him.
On the other hand, what the heck was he talking about?
Frantically grepping my grey cells for information on property lists,
I somehow recalled we sometimes use them as a poor man's hashtable, 
usually mapping keywords to flags. But it had been so long I used property
lists myself that I even had to look up the syntax details. 
To avoid this embarrassment next time around, here are some notes.
A property list is associated with a symbol. This flat 
and unstructured list can be thought of as a sequence of
indicator/value pairs, with the indicator being the "key",
in hash map terms. So the list starts with an indicator, followed 
by a value, followed by an indicator and its value, and so on.
This is how you usually set a symbol property:
  (setf (get 'some-symbol some-indicator) some-value)
And to inquire a symbol property, you just say something like
(get 'some-symbol some-indicator).
some-indicator can basically be any type, and so I wasn't sure what my 
co-worker meant when he said that he couldn't get strings to work, until 
he explained the details to me: He was calling some Lisp-based API 
function in our product, and that function returns a property list. 
Unfortunately, that property list was special in that somebody had
stuffed a string into it as an 
indicator, and so the property list 
looked somehow like this:
  ("foo" 42 "bar" 4711)
And indeed, if you now try to inquire the "foo" property using 
(get 'some-symbol "foo"), all you get is - 
nil.
To retrieve a property value, 
get walks the list and compares each 
indicator in the list with "foo" (in this example) - using 
eq. 
From which we can immediately conclude:
-  The correct spelling of "property list" is 
     p-e-r-f-o-r-m-a-n-c-e p-r-o-b-l-e-m, as
     each lookup requires traversing potentially all of the list.
-  eqchecks for object equality, not just value equality. Which means 
     that things like literal (!) strings or characters cannot be indicators!
In our case, we say 
(get 'some-symbol "foo"), and that "foo" string literal 
creates a 
new string object. While that new object happens to have
the same 
value as the "foo" string in the property list, it is 
not the same object.
Indeed, the 
Common Lisp HyperSpec
is quite clear on that topic: 
"Numbers and characters are not recommended for use as indicators in 
portable code since get tests with 
eq rather than eql, and 
consequently the effect of using such indicators is implementation-dependent."
It all boils down to the simple fact that 
(eq "foo" "foo") returns 
nil.
Now hopefully we can fix the API which returned those inadequate property
lists to my co-worker's code, but his code also needs to run in older 
and current installations, and so he needed a workaround of some sort.
His first idea was to get the property list and fix it up in a preprocessing 
step before using 
get or 
getf for lookup, i.e. something like this:
(defun fix-plist(plist old-indicator new-indicator)
  (let ((cnt 0))
    (mapcar 
      #'(lambda(item)
          (incf cnt)
          (if (and (oddp cnt) (equal item old-indicator))
              new-indicator item))
      plist)))
(setf my-symbol 42)
(setf (get 'my-symbol "indicator") "value") ;; mess up plist
(print (get 'my-symbol "indicator"))        ;; returns NIL
(print (getf (fix-plist (symbol-plist 'my-symbol) "indicator" :indicator) :indicator))
This works, kind of - but it is actually quite ugly. Sure, with this code, we should be
able to safely move ahead, especially since I also closed that office window in the 
meantime, but still: I really hope I'm missing something here. Any other ideas out there?
to top