It looks like metadata cannot be attached to primitive values:
(with-meta "abc" {:test :test})
java.lang.ClassCastException: java.lang.String cannot be cast to
clojure.lang.IObj
Is there any reason for primitive values to be excluded (except for
implementation difficulties)?
Also, what are the rules for "propagating" or discarding metadata?
I have noticed that "cons" propagates metadata attached to its second
argument (only) to its value while "concat" does not (although they
still may be present somewhere in the result):
user=> (def a (with-meta '(1) {:test :test}))
#<Var: user/a>
user=> (def b (with-meta '(2 3) {:test2 :test2}))
#<Var: user/b>
user=> (def c (concat a b))
#<Var: user/c>
user=> ^c
nil
user=> ^(first c)
nil
user=> ^(rest c)
{:test2 :test2}
Cheers,
-r.
I'm sorry for the delay. I was playing with clojure a bit, actually
trying to write some non-trivial (for me) code.
While I understand that adding metadata to primitive values is
difficult, I found lack of this possibility a bit disturbing. Please
consider following scenario:
I would like to process generic data that are either primitive
scalars, vectors or maps with quite a lot of less frequently used data
attached (i.e. metadata). However, because I can't add metadata to
primitive values I have to revert to wrapping these primitive values
with maps. Once I have maps there - there is no appealing reason for
me to add metadata to them - all necessary information can be added
directly to map. Then, to make the code more generic I wrap lists and
vectors with maps again. This way I get a working, although ugly,
solution which doesn't use metadata at all and where all values have a
following form:
{:val <primitive value, vector, list or map>,
:meta1 <...>, :meta2 <...>, ...}
This allows me to access both value and "metadata" in a uniform way
regardless of the value type. Unfortunately, retrieving the value
alone is much more elaborate than it would be if I could simply use
metadata construct in the first place. This additional complexity is
especially painful when these data are part of a public interface in
my code.
Do you think this use case is legitimate enough to try to change the
current metadata mechanism? If not, how would you design a cleaner
data structure that can either be a primitive scalar value or a vector
and has metadata attached?
Regards,
-r.
OK. Sorry for asking. I thought that since Clojure is using boxed data
types there might have been some flexibility in this area.
> > If not, how would you design a cleaner
> > data structure that can either be a primitive scalar value or a vector
> > and has metadata attached?
> >
>
> Clojure vectors support metadata. Are you really going to attach
> metadata to ints and strings? For what kind of information?
I wrote a scheme reader which parses s-expressions and returns a tree
of tokens with embedded additional information (file names,
line/column numbers, original (textual) representation etc.). The
problem is that these tokens include strings and numerals that do not
support attaching metadata. Currently I am wrapping each symbol with a
map, where I can embed additional information even without clojure's
metadata. That works reasonably well (i.e. I can live without
primitive values with metadata) but makes interface between reader and
whatever procedure consuming its output more complicated (I need to
specify the format or each token or build an abstraction layer).
Ideally, at the reader's output I'd like to have a simple tree of
symbols/numbers/strings with all other information available through
metadata.
Thanks,
-r.