I'd like to be able to do something like:

(defn square ^double [^double x] (* x x))
(def meta-square (with-meta square {:domain Double/TYPE :codomain Double/TYPE 
:range {:from 0.0 :to Double/POSITIVE_INFINITY :also Double/NaN}})

https://clojure.org/reference/metadata says "Symbols and collections 
support metadata...". Nothing about whether any other types do or do not 
support metadata.

The code above works, at least in the sense that it doesn't throw 
exceptions, and meta-square is a function that returns the right values, 
and has the right metadata.
That's because square is an instance of a class that extends AFunction, 
which implements IObj (
https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/AFunction.java#L18).

It doesn't work, in the sense that it violates "Two objects that differ 
only in metadata are equal." from https://clojure.org/reference/metadata. 
That is,
(= square meta-square) 
returns false. 

For my purposes, what really matters is that calling meta-square has 
roughly 30 times the cost of square itself (and about 3 times the cost of a 
version without type hints).
The reason is that meta-square is an instance of a class that extends 
RestFn 
(https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/AFunction.java#L26),
 
whose invoke() methods are  expensive.

Also, for my purposes, it would actually be better if  "Two objects that 
differ only in metadata are NOT equal." So perhaps I shouldn't be using 
metadata at all. It just seems

Options:

(1) Add a meta field to clojure.lang.AFunction (and fix equals and 
hashcode). I presume the reason there isn't already a meta field is to keep 
functions as light weight as possible. Are there good benchmarks that I 
could use to measure the cost of adding an almost always empty field? 

(2) Experiments with a mechanical wrapper class 
(https://github.com/palisades-lakes/dynamic-functions/blob/dynesty/src/main/java/palisades/lakes/dynafun/java/MetaFn.java)
 
show almost no overhead, but extending that to cover every possible 
combination of clojure.lang.IFn$DD, clojure.lang.IFn$DLD, ..., is 
impractical.

(3) Use asm to create a new class that extends the original function's 
class and implements IObj in the obvious way.

My short term plan is (2), ignoring the equals violation, and implementing 
primitive interface wrappers as needed.

Are there problems with (3) asm, as a long term solution?

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to