This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-12-15
Channels
- # adventofcode (39)
- # aws (1)
- # beginners (39)
- # boot (1)
- # calva (79)
- # cider (8)
- # cljdoc (13)
- # cljs-dev (45)
- # clojure (89)
- # clojure-berlin (2)
- # clojure-europe (1)
- # clojure-uk (1)
- # clojurescript (7)
- # datomic (1)
- # emacs (6)
- # figwheel-main (2)
- # fulcro (29)
- # hyperfiddle (21)
- # juxt (1)
- # leiningen (1)
- # lumo (3)
- # music (1)
- # off-topic (20)
- # pedestal (23)
- # portkey (3)
- # reagent (2)
- # rum (1)
- # shadow-cljs (27)
- # vim (5)
If a cljs client library for that exists what needs to be maintained with it? Once it implements the spec, has tests, and has been battle tested isn’t it done?
Hi. Bumped into strange issue with protocols. lein check
started to fail on CI: the load order of the files changed (it’s not deterministic) and because of that, a satisfies?
fails on a protocol. I tried to find a minimal case that errors, here it is: https://github.com/ikitommi/fun. Is this a bug or a feature? As the load
is only called by lein check
, one should not bump into this kind of problem with actual usage?
Hmm, I guess this could happen also when reloading namespaces with tools like tools.namespace
.
even simpler thing that fails:
(defprotocol Fun
(fun [this]))
(defn instance []
(reify
Fun
(fun [this] "this is fun")))
(satisfies? Fun (instance))
; true
(defprotocol Fun
(fun [this]))
(satisfies? Fun (instance))
; false
I want to add metadata to a primitive, like an int. I think it should work on boxed ints.
(with-meta (bigint 10) {:a 42}) ;ClassCastException class clojure.lang.BigInt cannot be cast to class clojure.lang.IObj
How can I reify up the thing I want in a way that behaves like a boxed primitive?
package clojure.lang;
public abstract class Obj implements clojure.lang.IObj, java.io.Serializable {
final clojure.lang.IPersistentMap _meta;
public Obj(clojure.lang.IPersistentMap meta) { /* compiled code */ }
public Obj() { /* compiled code */ }
public final clojure.lang.IPersistentMap meta() { /* compiled code */ }
public abstract clojure.lang.Obj withMeta(clojure.lang.IPersistentMap iPersistentMap);
}
if you really want to carry metadata with an int just put the int in a map with the metadata
and at that point, you might as well just attach the data directly and not through metadata
Yes but can't I extend-protocol (or something) java.lang.Integer or clojure.lang.BigInt into an IObj
FWIW, datafy solves the same problem by putting atom (and other derefable) values in a singleton vector: https://github.com/clojure/clojure/blob/master/src/clj/clojure/datafy.clj#L49
If this is impossible, what exactly is the reason why
java abstract classes are not portable?
you cannot implement an interface on a class that is already defined. BigInt already exists and is declared and it does not implement the IObj interface. You cant redefine BigInt to implement it
the reason it is different for protocols is because protocols, while they are made into interfaces, will fallback to looking up the type in a map to see if it satisfies the protocol
Why doesnt BigInt implement IObj
=> clojure.lang.BigInt
so is it possible to reify a DustinBigInt which duck types like a big int and implements the thing i want
java is fine
will it seamlessly unbox as a clojure value? Quack like an int?
(+ (bigint 10) 1)
=> 11N
(defn +
"Returns the sum of nums. (+) returns 0. Does not auto-promote
longs, will throw on overflow. See also: +'"
{:inline (nary-inline 'add 'unchecked_add)
:inline-arities >1?
:added "1.2"}
([] 0)
([x] (cast Number x))
([x y] (. clojure.lang.Numbers (add x y)))
([x y & more]
(reduce1 + (+ x y) more)))
Yeah, this is a rabbit hole
i need to tag a dbid that came out of datomic with the database it came out of, because it will remove a layer of boxing
currently use edn to do it
user=> (defn foo [] "bar")
#'user/foo
user=> (= foo (with-meta foo {:bar "baz"}))
false
I thought metadata wasn’t supposed to effect equalityfunctions are reference equality
(= inc (with-meta inc {:a 10}))
=> false
(= [1] (with-meta [1] {:a 10}))
=> true
I guess I got tripped up with this bit of documentation:
An important thing to understand about metadata is that it is not considered to be part of the value of an object. As such, metadata does not impact equality (or hash codes). Two objects that differ only in metadata are equal.
but then, I don’t know how you do that with functions unless you attach it to the var/symbol
you attach it to the var/symbol
I was originally doing this to compare to CLJS, which doesn’t have var’s to attach metadata
it's hitting the function equality paath in =, which is just reference equality, and the wrapped ref is different
No, it's a weird hyperfiddle thing. Our urls look like this:
and that #entity tag is used to distinguish tempids from strings in the url
and further our code paths use it, so there's this dumb wrapper type everywhere
Alex has posted good stuff on reddit: https://www.reddit.com/r/Clojure/comments/a6g8bw/clojure_doesnt_allow_metadata_on_primitives_this/
user=> (type foo)
user$foo
user=> (type (with-meta foo {:a "b"}))
clojure.lang.AFunction$1
it’s kind of obscured what interfaces a function created by defn
actually implements. I was thinking it was probably an instance of AFn
but I can’t confirm thatuser=> (defn foo [] 42)
#'user/foo
user=> (ancestors (class foo))
#{clojure.lang.AFn clojure.lang.IFn java.util.Comparator java.util.concurrent.Callable java.lang.Object clojure.lang.IObj java.io.Serializable clojure.lang.AFunction java.lang.Runnable clojure.lang.IMeta clojure.lang.Fn}
user=>
with-meta is designed for use with values with value equality, but function objects have reference equality which with-meta breaks
Perhaps one could imagine modifying clojure.core/= so that when comparing two functions, whether they have metadata or not, would do (identical? x y) on the functions x and y, ignoring the metadata associated with them. I have a hard time believing that the core team would consider that an important enough change in behavior to make, unless there is some use case they have in mind that would make something easier for them to do.
(= (fn [x] (inc (inc x))) (fn [x] (* 2 x)))
Oh, i thought it already did that
Apparently it does not, given this Clojure 1.10.0-RC5 session:
user=> (def f1 (fn [x] (inc x))) #'user/f1 user=> (def f2 (with-meta f1 {:a 5})) #'user/f2 user=> (meta f1) nil user=> (meta f2) {:a 5} user=> (= f1 f2) false
yea i give up, i have no idea how metadata works now
In that case I believe clojure.core/= is comparing whether f1 and f2 are identical objects in memory, including the metadata, and they are not.
That is just a special case for functions. For immutable Clojure collections, the metadata is ignored when comparing collections.
I would argue that in 99.99% of cases you shouldn't be worried about doing = between Clojure functions anyway. Only exceptions I can think of are really special cases involving implementing dev tools, or attempting to serialize functions across a wire.
I can guess that others are more imaginitive than I in finding reasons to want to use = to compare functions to each other, but you run up against the halting problem if you are thinking that two independently defined functions should ever return true when comparing them.
A recent example is the case where you want to see if someone dynamically rebound a function. https://github.com/clojure/clojure/blob/master/src/clj/clojure/main.clj#L275
My hunch is that lack of equality for fns when meta is involved is simply an oversight.
Note: My guess above on the core team's inclinations are simply that: my guess. Anyone who wishes for a change in behavior in this area is welcome to file a JIRA ticket and see how it goes.
Given the existence of REBL and its uses of metadata, for all I know a change in behavior there might become welcome.
It was always my thought what most people think as fn meta is actually meta on the var holding the fn.
thats a good point