You would need access to the "def" attribute of the
PersistentStructMap, to test that the map's def is identical to the
def in your test-function (or to compare the set of keyslots in your
map to the keyslots in the def, which would be a looser "duck typing"
comparison but might be more practical).
But scanning the Java source for PersistentStructMap, it looks like
the "def" attribute is not public and so cannot be read from Clojure.
I think this ought to be changed, and you might consider writing a
patch to add a couple new methods:
PersistentMap.getDef, returning a Def
Def.getKeyslots, returning an IPersistentMap
Or alternately, just make both of these attributes public, but I
suspect that Rich might reject such a patch.
From there you could write the comparison function in Clojure (or add
an instanceOf method to the Def class, that could do your testing for
you).
Hope this helps,
Graham
It doesn't look like it. It appears that although the StructMap keeps
a reference to the Def, there's no way to get it back out. Even if
there were, I'm not sure how you'd get back to the name given to the
Def -- in fact, there could be many (or no) names. Here's an
anonymous struct:
user=> (struct (create-struct :a :b) 1 2)
{:a 1, :b 2}
I suppose you could try to use an incompatible accessor -- if there's
no exeception, you know it's the right kind of struct:
user=> (defstruct foo :a :b)
user=> (defstruct bar :c :d)
user=> ((accessor foo :a) (struct foo))
nil
user=> ((accessor foo :a) (struct bar))
java.lang.Exception: Accessor/struct mismatch
But this all seems a little wrong. I think structs are meant to be
just a little performance (memory) improvement over a regular hashmap.
It seems like meta-data would be a better fit, but I'm not quite sure
how to use it:
user=> (defstruct mystruct :a :b)
user=> (def v1 #^mystruct {})
user=> ^v1
{:tag mystruct}
user=> (def v2 #^mystruct (struct mystruct 1 2))
user=> ^v2
nil
--Chouser
Right, but you could have a predicate, (mystruct?), that compared an
instance's Def for identity with mystruct's Def. Again, though, I
wonder if duck-typing would make more sense here (comparing the set of
keyslots, rather than comparing Defs for identity).
I see that Parth was asking for a type-of-struct function, and in my
response I was thinking in terms of a predicate, which isn't the same
thing. Though in practice a predicate often suffices.
Graham
Hi mac,
Sure, I can see that working. But I also see the benefit of exploiting
the (currently-hidden) metadata inside a struct Def, namely its set of
keyslots, or its identity. Rather than having to tack on extra
metadata (adding a designer burden) we could use the Def's own
properties for dispatch.
E.g., If we could access the keyslots of a Def, I could write a
multimethod that dispatches on any struct-map that has both :label and
:coordinates attributes, so that I could plot it on a visual map
(duck-typing in all its glory: if it quacks like a plot-point, we can
use it as a plot-point) without the struct-map having to be rigged
with metadata at some prior stage.
Dispatch is just one case, as you mentioned in your second message,
but similarly the keyslot map could be used in other cases too (e.g.
writing a (plot-point?) predicate that tested for {:label
:coordinates} as a subset).
Of course, "real" duck-typing would be instance based -- I would ask
an instance if it had {:label :coordinates} values, not inspect its
def/type. Still I suspect there is a case for the def/type inspection
as well.
The more I think about it, though, I suspect that instance-testing
makes the most sense in most cases, and struct-map types aren't really
types in any meaningful way. How's that for circular reasoning! :-)
Circularly yours,
Graham