Fork me on GitHub
#clojure
<
2018-08-20
>
octahedrion10:08:06

hmm I'm still having trouble using deps.edn with a dependency transitively dependent on a maven artifact with :classifier - because the artifact names are the same & so would lead to duplicate keys in the :deps map

jeroenvandijk10:08:37

I think if you use :local/root the key is not being used in the lookup. So you could use anything for the key even {foo/bar123 {:local/root "/path/here"}} I believe

alexmiller12:08:36

you can probably hack around it with something like @jeroenvandijk’s suggestion

octahedrion13:08:38

@alexmiller in the end I solved it by downloading the offending artifact and using :extra-paths

dpsutton15:08:03

on the clojure page about protocols it mentions parenthetically > Which interfaces are implemented is a design-time choice of the type author, cannot be extended later (although interface injection might eventually address this) Does this exist or perhaps will soon? Not sure if anyone knew if this was on the radar or had a ticket in jira

alexmiller15:08:42

not to my knowledge

👍 1
roklenarcic16:08:02

is it possible to somehow specify classloader when loading namespaces from a file with load-string?

roklenarcic16:08:23

or is there some other way to do that?

emccue17:08:27

@beoliver This doesnt work, but the general idea is to catch std-err and see if the words "Reflection warning" are there

emccue17:08:03

massively hacky to depend on the structure of error messages

emccue17:08:10

but it would work

emccue17:08:38

hypothetically

emccue17:08:39

and as always, someone please jump in to set me straight

dpsutton18:08:51

is there a good way to find consumers of a library? Wondering how widespread org.clojure/data.finger-tree usage ever got

dpsutton18:08:23

cljdoc doesn't seem to offer a search by dependency. I can't remember the name of the other online source browser for clojure but i thought i remembered it might have a feature to search by dependency

dpsutton18:08:23

you maintain cljdoc correct? is this feature on your roadmap by any chance?

martinklepsch18:08:59

yeah (re maintaining) — it's not planned for near future but eventually we might have data in appropriate shapes to answer these kinds of questions

beoliver19:08:02

A question about meta-data - the documentation states *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.* yet the following seems to suggest otherwise

> (identical? identical? identical?)
true
> (identical? (with-meta identical? {}) identical?)
false
> (= (with-meta identical? {}) identical?)
false
> (= (with-meta identical? {}) (with-meta identical? {}))
false

dpsutton19:08:57

follow up: does anyone know of writing about meta data anywhere? It seems "wrong" to me and a constant source of bugs with macros and such

dpsutton19:08:18

i've never had to use it so i wanted to see how others have used and and why they chose that over making it explicit

dpsutton21:08:12

so that is emitting type tags. I get that. I was thinking more of people who actually use meta to stash information and not just for annotation of compiler information

dpsutton21:08:24

but thanks for sharing that. that's an interesting solution

hiredman19:08:42

equality for functions is not something you really have anyway

hiredman19:08:16

you have pointer equality, and with-meta has to return a new pointer

hiredman19:08:53

for example (identical? (fn []) (fn [])) is false

beoliver19:08:19

sure - but try it with any named function

hiredman19:08:47

because you are using the name, you are literally getting the same function object

hiredman19:08:52

so of course they are identical

hiredman19:08:58

same pointer

beoliver20:08:17

thats what I mean... they are the same object

hiredman20:08:28

with-meta never returns the same object

hiredman20:08:09

"with-meta in the general case will never return the same object, but it has some optimizations to sometimes return the same object in some cases"

beoliver20:08:04

then it's a bit of a stretch to say *metadata does not impact equality* no?

ghadi20:08:55

the whole point of metadata is not to impact equality

hiredman20:08:55

it kind of depends

mg20:08:03

functions don’t really have value semantics

hiredman20:08:20

it starts off saying "metadata is that it is not considered to be part of the value of an object"

mg20:08:42

> (= (fn [x] x) (fn [x] x))
false

dpsutton20:08:02

that was acknowledged earlier

hiredman20:08:22

functions are not values in clojure in the same sense that the collection data types are

mg20:08:26

ah, missed that because there was no monospace font 😄

beoliver20:08:58

@hiredman I didn't actually expect (identical? identical? identical?) to be true...

hiredman20:08:25

why would it not be true?

hiredman20:08:50

(def identical? ...) creates a var holding some value

hiredman20:08:16

references to the identical? name then cause the compiler to generate a var deref

hiredman20:08:30

like, (fn [a] (identical? a a)) will always return true

beoliver20:08:14

@hiredman because In other languages it is not always the case

beoliver20:08:40

Prelude> let f = \x -> x
Prelude> f == f

<interactive>:8:1: error:
    • No instance for (Eq (p0 -> p0)) arising from a use of ‘==’
        (maybe you haven't applied a function to enough arguments?)
    • In the expression: f == f
      In an equation for ‘it’: it = f == f

hiredman20:08:24

that isn't == returning false though

hiredman20:08:40

that is haskell refusing to run it

hiredman20:08:48

and == is not the same thing as identical? in haskell (not 100% sure about that)

beoliver20:08:33

@hiredman I know... I can see that... I thought (identical? identical? identical?) might throw an error... thats all... nothing more.

hiredman20:08:39

anyway, I think functions supporting IMeta and using reference equality is kind of dumb, but it is what it is

beoliver20:08:51

but the same is true of = in clojure as I showed earlier

hiredman20:08:03

true of what?

hiredman20:08:47

clojure.core/= is sometimes value and sometimes reference equality depending on the types of the data being compared

hiredman20:08:23

so for the case of functions, clojurec.core/= is the same as clojure.core/identical?

andy.fingerhut20:08:35

@beoliver In Clojure, clojure.core/= is far more commonly used, and what is meant by the English word "equals" or "equality" when referring to Clojure. clojure.core/identical? is the oddball, and exists really only for the unusual cases where you might care about object identity.

andy.fingerhut20:08:31

In the text you quoted: "As such, metadata does not impact equality (or hash codes). Two objects that differ only in metadata are equal.", the words "equality" and "equal" are referring to clojure.core/= equality.

beoliver20:08:13

@andy.fingerhut - sure thats why I posted with (= identical? identical) as well

beoliver20:08:05

@andy.fingerhut I only used the (identical? identical? identical?) as it amused me

andy.fingerhut20:08:08

clojure.core/= falls back to clojure.core/identical? behavior in many cases, e.g. the arguments are not immutable values.

beoliver20:08:27

I would expect as per docs that the following would be true

(= (with-meta identical? {}) identical?)
false

andy.fingerhut20:08:01

Functions are not treated by Clojure as immutable values. clojure.core/= falls back to clojure.core/identical? when given a function as either arg.

hiredman20:08:48

the point is, implementing pointer equality and IMeta are in conflict

andy.fingerhut20:08:56

You are probably aware that trying to compare two functions for some notion of "equal arguments gives same return values" is an undecidable computational problem.

dpsutton20:08:04

> As such, metadata does not impact equality (or hash codes). he's just pointing out a counter example to this claim from the docstring

dpsutton20:08:46

i think he understands why and the codepath it takes. just pointing out an edgecase in the guarantee from the docstring

hiredman20:08:55

and basically have to be in conflict, you cannot have both behaving consistently

andy.fingerhut20:08:11

Got it. Yes, he has a counterexample. The fact that it is a counterexample, and why it is, makes sense to me from the implementation, and isn't likely to ever change (my guess). Almost no one cares about the results of comparing two functions for equality.

andy.fingerhut20:08:40

Personally, I would be very suspicious of any code that was using functions (not symbols, but the actual function values) as hash keys, set elements, or in other ways that relied on clojure.core/= behavior. I am sure there is some such Clojure code somewhere, but it sounds like an extremely specialized use case that most people would want to avoid.

hiredman20:08:34

so like, the question is, this behavior is inconsistent with the docstring and an implied should someone fix the docstring? and the reason I was discussing the mechanisms and how the behavior arises is, you can come to the conclusion that metadata on functions is bad news by understanding clojure.core/= and with-meta, and come to the same understanding andy has

john20:08:00

Yeah, maybe fns should be called out

andy.fingerhut20:08:39

If we assume for the moment that the implementation isn't going to change to match the documentation mentioned, and changing the documentation is a good idea, the qualification one would need to add to make it correct is pretty small, I think, and would likely only make sense to those with a bit of knowledge of Clojure internals, e.g. "... except for objects that implement IMeta but are not persistent collections", or something close to that.

hiredman20:08:13

except there is already a whole parallel metadata universe for things with reference equality

hiredman20:08:54

not that fns can now ever be changed to use that

beoliver20:08:52

reading https://clojure.org/reference/metadata the one emphasised sentence in italic is the problem... - metadata does not impact equality (or hash codes) ... the actual doc string is ""Returns an object of the same type and value as obj, with map m as its metadata." is slightly more open to interpretation - Same Value.

andy.fingerhut20:08:41

Starting to get into "angels dancing on the head of a pin" territory with my next comment, perhaps, but I wouldn't be surprised if the Clojure core team did not consider functions as being in the category of "values".

hiredman20:08:56

and now we have gone full circle around the contradiction. supporting with-meta implies value, reference equality implies not a value

john20:08:36

well, it works for data

john20:08:44

Wrap a fn in a data structure and then you can compare by value again between equal values (containing fns) with different meta data structures

john20:08:32

it may come down to dispatch speed on the fn interface

john20:08:41

vs slowing down java's function equality semantics

john21:08:57

Not really sure, but it seems like fns could be made to allow it. But to your point, allowing dynamic data on functions is about as antithetical to value-oriented-programming as it can get anyway. It's basically a side effecting escape hatch on everything.

emccue22:08:06

kinda wierd how the page on destructuring documents a function then claims its undocumented

emccue22:08:57

considering this is official clojure documentation, it feels a little wierd to say that clojure.core/destructure isn't documented

noisesmith22:08:07

I think they mean in-clojure docs

user=> (doc destructure)
-------------------------
clojure.core/destructure
([bindings])
nil

andy.fingerhut22:08:34

@beoliver I could easily be missing something, but as far as things that you can call with-meta on, they must be of class IObj, or something that derives from them, in the Clojure/JVM implementation. Mostly those are the persistent collections, but also symbols (which do not have the issue you pointed out -- they ignore metadata when comparing via clojure.core/=), and functions. Not counting libraries that create implementations of IObj, it seems maybe functions are the only kinds of things built into Clojure that violate the docs you pointed out.

andy.fingerhut22:08:01

There are more kinds of objects that can have metadata associated with them, e.g. namespaces, agents, atoms, refs, and probably a few other things, but you cannot call with-meta on them because they do not inherit from class IObj, only the less specific IMeta interface. They cannot violate with-meta's doc string, and I think pretty much the only way supported to attach metadata to those things is to do it when creating such an object in the first place, so they can't violate the docs, either, since you can't create two of them that are = to each other.

andy.fingerhut23:08:04

You may create an issue for the docs if you are really interested in them mentioning the exception, but it seems like a pretty small one IMO.

andy.fingerhut23:08:37

At least in the past, docs maintained by the Clojure core team tend to avoid that level of detail.

gfredericks23:08:15

is this really the easiest way to print to a gzip file using the built-in functionality? am I missing something?

(with-open [os1 (io/output-stream out-file)
              os2 (GZIPOutputStream. os1)
              w   (io/writer os2)
              pw  (java.io.PrintWriter. w)]
    (binding [*out* pw]
      ...
      ))

gfredericks23:08:51

I mostly just feel like four clauses has to be too much

csm23:08:30

I would think .close propagates down pw -> w -> os2 -> os1, so I guess that could be one clause

gfredericks23:08:44

so (with-open [thanks-noisesmith (-> out-file io/input-stream GZIPOutputStream. io/writer java.io.PrintWriter.)] ...)

noisesmith23:08:03

you need the name, but

gfredericks23:08:11

that's definitely nicer; do I need to check with each of the intermediate classes to see if they do propogate the .close?

gfredericks23:08:18

or is that a strict expectation on the jvm?

noisesmith23:08:19

it might depend on how promptly you need that to be freed? I'd imagine the finalizers would eventually know there are no references too.

gfredericks23:08:21

the claim is that .close propagates, and if that's true then I can't see how there'd be any noticeable difference

noisesmith23:08:54

hmm, yeah I don't know

csm23:08:04

it’s up to whomever implements OutputStream or Writer, but I think any built-in implementation of those behaves correctly. I’d imagine the ones http://clojure.java.io returns do, too.

gfredericks23:08:11

PrintWriter docs for close say > Closes the stream and releases any system resources associated with it. Closing a previously closed stream has no effect.

gfredericks23:08:20

which doesn't really seem to address the issue

gfredericks23:08:15

looks like you can pass the output stream directly to the printwriter though, so that saves a step

noisesmith23:08:45

yeah - http://clojure.java.io doesn't implement those interfaces, it's just wrappers of some common patterns https://github.com/clojure/clojure/blob/master/src/clj/clojure/java/io.clj