type of structure

70 views
Skip to first unread message

Parth Malwankar

unread,
Aug 20, 2008, 7:11:55 AM8/20/08
to Clojure
If I create a structure:

(defstruct mystruct :a :b)

Is there any way of identifying an instance of it. I know
about multimethods and using that with something like
:type as a struct field.

I am just wondering if there is something like sclass
that would be a 'class' equivalent for structure

(sclass (struct mystruct)) => mystruct

(class (struct mystruct)) gives clojure.lang.PersistentStructMap
as expected.

Thanks.
Parth

Graham Fawcett

unread,
Aug 20, 2008, 9:22:08 AM8/20/08
to clo...@googlegroups.com

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

Chouser

unread,
Aug 20, 2008, 9:46:30 AM8/20/08
to clo...@googlegroups.com
On Wed, Aug 20, 2008 at 7:11 AM, Parth Malwankar
<parth.m...@gmail.com> wrote:
>
> (sclass (struct mystruct)) => mystruct

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

Graham Fawcett

unread,
Aug 20, 2008, 10:58:19 AM8/20/08
to clo...@googlegroups.com
On Wed, Aug 20, 2008 at 9:46 AM, Chouser <cho...@gmail.com> wrote:
>
> On Wed, Aug 20, 2008 at 7:11 AM, Parth Malwankar
> <parth.m...@gmail.com> wrote:
>>
>> (sclass (struct mystruct)) => mystruct
>
> 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.

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

mac

unread,
Aug 20, 2008, 11:23:09 AM8/20/08
to Clojure


On Aug 20, 4:58 pm, "Graham Fawcett" <graham.fawc...@gmail.com> wrote:
Don't know if this is what you were looking for but you can tack on
any metadata you like to a struct and check that for your "type".
That's what I do when I want polymorphism. With that solution you
don't need to have the type intrude on the actual data in the struct
instance.
Example:
(defstruct happy-struct :x :y)

(defn make-happy-struct
"Creates a new happy-struct instance."
[x y]
(with-meta (struct happy-struct x y) {:type :happy}))

(defn dispatch [instance & args]
(:type ^instance))

(defmulti happy-func dispatch)

(defmethod happy-func :happy
[instance z]
(println "And the result is:" (+ (:x instance) (:y instance) z)))

(def inst (make-happy-struct 10 20))

^inst
=> {:type :happy}

(happy-func inst 30)
=> And the result is: 60

/mac

mac

unread,
Aug 20, 2008, 11:37:10 AM8/20/08
to Clojure
Just to clarify myself in case you were just looking for type info,
you can ignore most of what I wrote with defmulti and that stuff. Just
look at with-meta and the dispatch function, which picks out the value
of the :type entry in the metadata. (:type ^instance)

/mac

Graham Fawcett

unread,
Aug 20, 2008, 12:33:11 PM8/20/08
to clo...@googlegroups.com
On Wed, Aug 20, 2008 at 11:23 AM, mac <markus.g...@gmail.com> wrote:
> On Aug 20, 4:58 pm, "Graham Fawcett" <graham.fawc...@gmail.com> wrote:
>> 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).
>>
> Don't know if this is what you were looking for but you can tack on
> any metadata you like to a struct and check that for your "type".
> That's what I do when I want polymorphism. With that solution you
> don't need to have the type intrude on the actual data in the struct
> instance.

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

mac

unread,
Aug 20, 2008, 2:35:12 PM8/20/08
to Clojure
> 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! :-)

I was going to write some counter argument here but I sort of agree
with you so I guess I got nothing.
The case for being able to check the Def of a structmap instance I
think would be what you already described; to check the type without
using metadata. But I don't think exposing the Def would be considered
pretty since the structs are just supposed to be slightly more
efficient hashmaps right? But what do I know, I'm a total Lisp/Clojure
noob ;)
Anyway, I guess I would do duck typing the way you described it with
the instances, by checking for non-nil returns on the relevant keys.
Thanks for that idea by the way, hadn't occurred to me before.
Although you would have to be careful with that. If there are two
different maps that have the same keys but they contain different
types of values you could get in trouble with such a dispatch.
Requires using quite specific key names - or checking the type of the
values too if the values exist ;)

/mac

On Aug 20, 6:33 pm, "Graham Fawcett" <graham.fawc...@gmail.com> wrote:

Parth Malwankar

unread,
Aug 21, 2008, 8:53:24 AM8/21/08
to Clojure


On Aug 20, 9:33 pm, "Graham Fawcett" <graham.fawc...@gmail.com> wrote:
> On Wed, Aug 20, 2008 at 11:23 AM, mac <markus.gustavs...@gmail.com> wrote:
> > On Aug 20, 4:58 pm, "Graham Fawcett" <graham.fawc...@gmail.com> wrote:
> >> 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).
>
> > Don't know if this is what you were looking for but you can tack on
> > any metadata you like to a struct and check that for your "type".
> > That's what I do when I want polymorphism. With that solution you
> > don't need to have the type intrude on the actual data in the struct
> > instance.

Thanks mac. This example using meta data was very helpful.

>
> 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.

Yes. If we could use properties from def that would be really nice
and would probably make the code cleaner.

Rich Hickey

unread,
Aug 25, 2008, 1:18:41 PM8/25/08
to Clojure


On Aug 20, 9:46 am, Chouser <chou...@gmail.com> wrote:
> On Wed, Aug 20, 2008 at 7:11 AM, Parth Malwankar
>
Yes. These are some of the many reasons:

structs can be anonymous

They are just an optimization

Metadata can be used for type and other tagging, and the same method
will work for other non-struct maps

We need to get away from putting single 'types' on information, they
are just maps

There could be many taxonomies of 'types', having a privileged one is
just a recipe for yet-another-type-system

Using metadata/attributes will work with the new a la carte hierarchy
and isa dispatch stuff.

Structs are dynamic - would the 'types' of instances created from two
revisions of the same-named defstruct be the same?

If I give you struct types, you'll next ask for struct derivation

etc :)

Rich

Stuart Sierra

unread,
Aug 26, 2008, 11:06:46 AM8/26/08
to Clojure
On Aug 25, 1:18 pm, Rich Hickey <richhic...@gmail.com> wrote:
> If I give you struct types, you'll next ask for struct derivation
>
> etc :)

Long live Clojure, defender of the dynamic, protector of the
functional, and arch-nemesis of static types!
-Stuart
Reply all
Reply to author
Forward
0 new messages