What are some uses of Clojure metadata?

2019-01-23 01:42发布

问题:

How have you used metadata in your Clojure program?

I saw one example from Programming Clojure:

(defn shout [#^{:tag String} message] (.toUpperCase message))
;; Clojure casts message to String and then calls the method.

What are some uses? This form of programming is completely new to me.

回答1:

  • Docstrings are stored as metadata under the :doc key. This is probably the number 1 most apparent use of metadata.
  • Return and parameter types can be optionally tagged with metadata to improve performance by avoiding the overhead of reflecting on the types at runtime. These are also known as "type hints." #^String is a type hint.
  • Storing things "under the hood" for use by the compiler, such as the arglist of a function, the line number where a var has been defined, or whether a var holds a reference to a macro. These are usually automatically added by the compiler and normally don't need to be manipulated directly by the user.
  • Creating simple testcases as part of a function definition:

    (defn #^{:test (fn [] (assert true))} something [] nil)

    (test #'something)

If you are reading Programming Clojure, then Chapter 2 provides a good intro to metadata. Figure 2.3 provides a good summary of common metadata.



回答2:

For diversity some answer, which does not concentrate on interaction with the language itself:

You can also eg. track the source of some data. Unchecked input is marked as :tainted. A validator might check things and then set the status to :clean. Code doing security relevant things might then barf on :tainted and only accept :cleaned input.



回答3:

Meta Data was extremely useful for me for purposes of typing. I'm talking not just about type hints, but about complete custom type system. Simplest example - overloading of print-method for structs (or any other var):

(defstruct my-struct :foo :bar :baz)

(defn make-my-struct [foo bar baz]
   (with-meta (struct-map my-struct :foo foo :bar baz :baz baz)
      {:type ::my-struct}))


(defmethod print-method 
   [my-struct writer]
   (print-method ...))

In general, together with Clojure validation capabilities it may increase safety and, at the same time, flexibility of your code very very much (though it will take some more time to do actual coding).

For more ideas on typing see types-api.



回答4:

metadata is used by the compiler extensively for things like storing the type of an object.
you use this when you give type hints

(defn foo [ #^String stringy] ....

I have used it for things like storing the amount of padding that was added to a number. Its intended for information that is 'orthogonal' to the data and should not be considered when deciding if you values are the same.