Fork me on GitHub
#clojure
<
2020-05-07
>
sofra00:05:36

Curious question I just thought of that I don’t really know the answer to. Does Clojure structural sharing mean that if I create copies of the same data structure in a larger data structure there is only one copy in memory, or does each copy take up more memory? e.g. (into [] (repeat 10 {:a "foo" :b "bar"})) is there 10 copies in memory or just one?

didibus00:05:14

I'm not entirely sure, but I think there would be 10 copies. That said, both keywords and strings are interned in Clojure, so there's always only one copy of them

didibus00:05:20

So like, irregardless of structural sharing, there is always only one copy of equal keywords and strings

didibus00:05:46

But structural sharing doesn't share between equal elements, it shares parent node in the tree of changes

noisesmith00:05:57

@didibus @sofra repeat will give you the same object N times, period

noisesmith00:05:41

you'll have 10 pointers filling the [] of course, but the map itself is only created once

sofra00:05:00

:thumbsup:

noisesmith00:05:02

also you should write your code so the difference wouldn't matter :D

didibus00:05:12

Oh right, that too. But I assumed the question meant more: (repeatedly #(identity {:a "foo"}))

noisesmith00:05:44

even that, the clojure compiler only creates that hash map literal once, and identity doesn't touch it, just returns it

sofra00:05:25

thanks @noisesmith, I think that clears it up

noisesmith00:05:39

but agreed with @didibus that this isn't structural sharing - it's just normal behavior

didibus00:05:53

Hum, true true, because the literal can be treated as a value. Okay so: (repeatedly #(hash-map :a "foo"))then

noisesmith00:05:04

(though behavior that you're less likely to take advantage of in a language where data isn't immutable)

noisesmith00:05:19

that would create new hash maps yeah

didibus00:05:42

In which case structural sharing would not dedupe these correct?

noisesmith00:05:01

because hey, you might redefine hash-map in the middle of realizing that lazy seq, and clojure promises to role with that

noisesmith00:05:15

(please dont' redefine hash-map in the middle of a lazy-seq or otherwise)

noisesmith00:05:50

@didibus right, none of these examples so far are structural sharing

didibus00:05:39

Cool, I wonder how all this plays with regards to performance and cache hits

andy.fingerhut01:05:02

If you want to see whether structural sharing is occurring, and exactly how, in Clojure/Java (not ClojureScript), I have a little library that graphically draws the JVM objects in memory used to represent Clojure values. I included a little gallery of example images it created in the docs for the library here: https://github.com/jafingerhut/cljol/blob/master/doc/README-gallery.md

👍 24
andy.fingerhut01:05:25

That gallery does not currently contain any examples of structural sharing, but it would be easy to add some.

lilactown01:05:06

would be super useful to have in CLJS too! 😄

andy.fingerhut02:05:24

If you know how to implement the JVM parts of that cljol library in JavaScript, I would consider it. I don't know how to do the necessary object walking and getting current addresses of JavaScript runtime objects.

Temsan08:05:06

Hi everyone, I'm using ring-swagger + spec-tools and trying to send array-like query param to the server from Swagger UI: What I want to see: `orders?status=NEW&status=PROGRESS`, but the request was sent in comma-separated form: `orders?status=NEW,PROGRESS` How can I fix it? Seems like I need to add `explode true` in serialization params... Thanks in advance!

Elso09:05:38

Is there some way to have maps printed with clojure.tools.logging be pretty-printed?

acron13:05:21

If I have a symbol 'foo/bar where foo is an aliased ns, how can I find out the full, un-aliased ns?

Alex Miller (Clojure team)13:05:29

I guess resolve will give you the var, you may be asking for the alias resolution particularly?

bronsa13:05:37

yea hthat only works if foo/bar is an existing var

Alex Miller (Clojure team)13:05:59

you can use ns-aliases to resolve aliases

acron13:05:02

@alexmiller facepalm resolve, of course. thanks

bronsa13:05:08

user=> (alias 'foo 'user)
nil
user=> (ns-name ((ns-aliases *ns*) (symbol (namespace 'foo/bar))))
user

Alex Miller (Clojure team)13:05:08

(.name (get (ns-aliases *ns*) 'foo))

Alex Miller (Clojure team)13:05:28

using ns-name is better of course

acron13:05:06

(defn resolve-symb-alias [s]
  (symbol (str (get (ns-aliases *ns*) (symbol (namespace s))))
          (name s)))

acron13:05:11

that's what I had..

acron13:05:30

even had the answer in the name of the fn!

Joshua Ewulo16:05:22

Dear all, I am new to Clojure. I am using Cursive on IntelliJ. I can Build my project but when I try to run it I get this error. Error running 'test (1)': failed to access class com.intellij.execution.impl.ProcessStreamsSynchronizer from class com.intellij.execution.impl.ConsoleViewRunningState (com.intellij.execution.impl.ProcessStreamsSynchronizer is in unnamed module of loader com.intellij.util.lang.UrlClassLoader @7f9a81e8; com.intellij.execution.impl.ConsoleViewRunningState is in unnamed module of loader http://com.intellij.ide.plugins.cl.PluginClassLoader @7b0d6c9c). Does anybody understand what I am doing wrong?

andy.fingerhut16:05:24

You may find help here, but I wanted to mention that there is also a #cursive channel available.

kelveden17:05:07

Sounds like you're not the only one though: https://github.com/cursive-ide/cursive/issues/2350

kelveden17:05:50

So, judging by the final comment in that thread, maybe try uninstalling IntelliJ and reinstalling with latest Cursive?

Joshua Ewulo18:05:10

Thanks for the answers. I reinstalled IntelliJ and installed the latest Cursive from https://plugins.jetbrains.com/plugin/8090-cursive. I still get the same error I am afraid.

cfleming23:05:32

@U0136V3DUUV That bug is fixed in the latest EAP, doc about how to install EAP versions is here: https://cursive-ide.com/userguide/index.html#eap

👍 4
pseud14:05:12

… and the alternative (as I did) is installing IntelliJ 2019.3 (Jetbrains lets you download older versions) and using that instead. (BTW - cool to see you’re still lingering around and offering support cfleming. Love the product !)

Parenoid19:05:18

in terminal emacs, I just want to press a binding and see the ClojureDoc with examples for a symbol under the cursor and I want to see the results in emacs as opposed to having it launch the browser... I had this once but I think it became deprecated... also, it seems that cider has to be running for quite a few approaches to this, which is less than ideal for just reviewing/learning-from code I don't want to start a repl for. Any ideas?

Parenoid19:05:37

I like terminal emacs so much, but it is so great to get instant docs for the methods of objects in most languages and editors. There has to be a way!

Parenoid19:05:16

And, of course, it needs to be ClojureDocs as I can't really understand a lot of the official docs for functions.

andy.fingerhut19:05:40

You may get an answer here, but wanted to let you know there is an #emacs channel too

Parenoid19:05:05

I figured I'd have better luck here, but is there a respected way to essentially post to two channels?

Parenoid19:05:42

in the past I've tried the 'posted a question about <this channel's topic> to <some other channel>' but that has produced minimal results, lol.

Parenoid19:05:03

and I suspect it's probably frowned upon, dunno.

andy.fingerhut19:05:08

It depends on what the channels are, and the question. A lot of Clojure users use Emacs, but not all, and Emacs is pretty fragmented in the ways that people use it for Clojure development, too (e.g. Cider vs. not-Cider, spacemacs vs. doom emacs vs. seventeen other make-it-easier-to-give-you-a-canned-setup add-ons that I don't keep track of).

😆 4
Parenoid19:05:27

haha yeah...

Parenoid19:05:39

that's my downfall, my addiction to terminal emacs.

andy.fingerhut19:05:44

It is not encouraged. If you do not get an answer here for an hour or three, I don't think anyone would object if you repeated on another channel more focused on the question.

Parenoid19:05:12

this might end up being my contribution in the end as I need it so bad.

Parenoid19:05:21

not that I'd know how to start, lol.

Parenoid19:05:50

the whole thing is making me better at reading the 'official' docs, however, as that is available in a cider-connected repl via cider-doc. so that's good.

Parenoid19:05:17

I feel like if I could understand those, it would be a superpower.

dpsutton19:05:57

CIDER offers this but requires a running nrepl

Parenoid20:05:53

@U11BV7MTK do you mean the community docs via cider?

Parenoid20:05:19

that somehow stopped working for me a while ago, and I think I recall it having been abandoned... but let me try it again.

dpsutton20:05:46

if you are jacked in, C-c C-d c

Parenoid20:05:58

I would only have to one cider session running at any time, very doable at all times.

dpsutton20:05:01

or m-x cider-clojuredocs

Parenoid20:05:44

aha, yeah...

Wrong type argument: char-or-string-p, nil

dpsutton20:05:00

is your CIDER version up to date?

Parenoid20:05:11

let me see, probably not!

dpsutton20:05:17

and if so, try m-x toggle-debug-on-error and see where the error is

Parenoid20:05:33

CIDER 0.24.0 (India)

Parenoid20:05:53

I'll debug now...

Parenoid20:05:59

what does the India refer to?

Parenoid20:05:16

is that colloquial versioning system?

Parenoid20:05:50

that was from M-x cider-version

dpsutton20:05:43

the maintainer names the releases after places he releases from. i believe that one was released in india at the conference there

Parenoid20:05:47

ok, tried to answer this for myself... but where do I see the output of toggle-debug-on-error?

dpsutton20:05:25

it will pop up a window

Parenoid20:05:14

aha... and I'm using terminal emacs... so that may be what's going on.

Parenoid20:05:28

I guess I need it in a new frame.

Parenoid20:05:53

I wonder if the stringp nil error is from my emacs not being able to open a new window.

Parenoid20:05:31

I'll ask in #cider

dpsutton20:05:36

window in emacs parlance is just another buffer

Parenoid20:05:47

ah ok nevermind that route

dpsutton20:05:23

and here's the clojuredocs open in terminal emacs

Parenoid20:05:43

omg omg omg

Parenoid20:05:47

that's exactly what I need

Parenoid20:05:01

my learning/development would be like 100% faster

Parenoid20:05:24

I know it sounds crazy, but going to the browser... well, it draws me out of the code...

Parenoid20:05:45

ok, if it's all I do today, I need to get this working.

Parenoid20:05:26

I appreciate you pnging me a carrot of inspiration.

Parenoid21:05:56

I pasted the debug into #cider.

Parenoid22:05:22

and also the possible offending line of code (which I hardly understand)

Parenoid06:05:31

I resolved the issue... it was a cider-nrepl mismatch issue. I have clojuredocs in emacs. Thank you all for the help and the screenshot inspiration of how it should look when I got it working.

Parenoid19:05:09

the official docs for 'get' state that it

Returns the value mapped to key, not-found or nil if key not present.
but
(get ["foo" "bar"] 1)
returns "bar".

Parenoid19:05:18

is 1 an implicit key or something?

Parenoid19:05:44

it seems that the docs are saying get works on maps, not vectors, via keys.

jlmr19:05:56

@patrickanium when get is used on a vector it uses the key you pass as the index. In this case that returns “bar”

jlmr19:05:48

If you passed 0 it would return “foo”.

Parenoid20:05:26

it is interesting this is not at all indicated in the docs. or am I supposed to understand this from the docs?

Parenoid20:05:40

(thank you for the answer!)

hiredman20:05:04

mapped can mean different things

hiredman20:05:12

in the case of a map, a key is mapped to a value

hiredman20:05:20

for a vector an index is mapped to a value

Parenoid20:05:20

I still can't figure out if I'm just too dense to understand the official clojure documentation, or if it's somehow scant.

krzyz04:05:25

You’re reading the wrong docs. That stuff is more of a reference for functions, to remind you in general what they do. If you want to get a solid understanding of the language, I highly recommend you read the documentation on http://clojure.org. For example, the fact that vectors are functions of their indices is mentioned on this page: https://clojure.org/reference/data_structures

Parenoid20:05:45

in this case, now I'm lined out (and grateful for the explanation)

hiredman20:05:52

similar for strings, a index is mapped to a character

hiredman20:05:04

user=> (get "foo" 1)
\o
user=>

andy.fingerhut20:05:54

The official Clojure docs are (in)famously terse.

Parenoid20:05:40

man, can't help with getting people into the language.

Parenoid20:05:01

I feel like if I could understand them, I'd rock.

Parenoid20:05:09

like, read one line, understand the function.

andy.fingerhut20:05:10

There is http://ClojureDocs.org as you know, and books, tutorials, etc.

Parenoid20:05:33

but in the 'get' example above... not sure I could/would have realized that it works on vectors, etc.

Parenoid20:05:07

actually, I'm want to know what I would have to know to be able to deduce how it behaves on other things than maps.

andy.fingerhut20:05:13

Anyone is free to write and publish docs for all 600+ built-in functions that they like better, of course. Except for http://ClojureDocs.org and books like Clojure: The Essential Reference (which probably took many person-years to write), no one has volunteered.

andy.fingerhut20:05:22

In fairness, I should say that others have created valuable resources over the last 12 years, but the 2 other main ones I recall right now no longer exist.

andy.fingerhut20:05:21

Lots of blog articles, etc. on various topics. Creating a reference for all Clojure functions is a lot to write that almost no one takes on, or finishes.

Parenoid20:05:46

I know, but as someone learning the language... I'm not sure I'm up for writing docs... I need to read them! ;-D

andy.fingerhut20:05:12

The simple answer is: Don't rely only on the built-in doc strings. Find other sources that help you, too.

Parenoid20:05:55

ah, ok... I got used to languages like JavaScript where you just casually move through the code and an intelligible explanation appears...

Parenoid20:05:23

(multiple) browser trips for every new function is pretty brutal.

andy.fingerhut20:05:26

Does the text for get on http://ClojureDocs.org make it any clearer for you? If so, your project to make that quickly accessible in your IDE is a very good recommendation that you are already following.

Parenoid20:05:52

that's what I'm working on ATM... I can get it via cider, it seems.

andy.fingerhut20:05:21

Thank the contributors. They made it happen. God had nothing to do with it 🙂

Parenoid20:05:04

haha indeed.

Parenoid20:05:25

let's be clear, though... y'all are gods to me.

Parenoid20:05:28

a pantheon.

andy.fingerhut20:05:16

Some people find the Clojure cheatsheet useful, not because it provides better docs, but because it organizes (most, not all) of Clojure's built-in functions and macros into related groups: https://jafingerhut.github.io

Parenoid21:05:52

thank you so much for this cheatsheet. it's a great quiz type thing... look at a function and guess what it does, mouse over for answer. it's inspiring for other things I'm learning.

andy.fingerhut21:05:37

Sure, glad you find it useful.

Parenoid21:05:15

plus, knowing which of the 600 aforementioned functions are more likely good to know.

Parenoid21:05:29

if I learn everything on this sheet I'll be way ahead.

Parenoid20:05:27

this is very helpful. a map of sorts.

kenny21:05:49

Why does halt-when not appear to work with sequence?

(sequence (halt-when odd? vector) [2 2 1 2])
=> (2 2)

ghadi21:05:13

certain transducible contexts (chan/sequence/into) do not expose the completed value

ghadi21:05:09

It doesn't make sense in the sequence or chan case I think it's a bug that #'into doesn't gel with halt-when

kenny21:05:18

I think it could make sense to expose it. I would like a lazy sequence of results and a secondary value that contains an error, if one occurred.

ghadi21:05:27

I don't see how that would work with sequence

ghadi21:05:40

an example would be helpful

kenny21:05:22

The result of halt-when's retf would be the end result. Something like this is the alternative, I think.

(def my-seq (sequence xf my-seq))
(doseq [item (filter #(not (error? %)) my-seq)]
  (process-item item))
(some error? my-seq)

kenny21:05:47

It requires iterating my-seq twice.

ghadi21:05:12

you've hidden the return values of sequence

ghadi21:05:39

(sequence (halt-when odd? vector) [2 2 1 2]) what would this return?

kenny21:05:25

Presumably [the-sequence failing-val], though, perhaps this is what you're getting at, failing-val may not have been realized yet.

ghadi21:05:01

you can't check the predicate without realizing the value

kenny21:05:32

Right. Thus you saying "It doesn't make sense in the sequence or chan case"

ghadi21:05:06

it doesn't compute not because of the realization aspect, but because of the nature of those transducible contexts

ghadi21:05:26

channels' "step" is putting an item in a channel

ghadi21:05:16

can't have the completion function synthesizing things that weren't there and putting them in the channel (Flushing something like partition-all is different)

ghadi21:05:44

sequence's "step" is adding to the rest part of an ISeq

ghadi21:05:50

demand-driven iteration

kenny21:05:33

Anything that is iterative/step based therefore will not work with halt-when, right? It only works for eager reduces.

ghadi21:05:21

halt-when is no different than take in that it chooses to abort the stepping process

ghadi21:05:12

(sequence xf coll) and (chan buf xf) do not expose the completed value

✔️ 4
ghadi21:05:35

no matter the xform

Parenoid22:05:24

I posted a debug to my cider-clojuredocs issue to #cider if anyone is able to look at it https://clojurians.slack.com/archives/C0617A8PQ/p1588888419018300