Fork me on GitHub
#clojure
<
2018-10-25
>
gleisonsilva00:10:53

hello! can u help me to figure out how do design a simple thing? let's say that I've defined a simple map with configuration values as myns.core/conf. let's say also that I have a second namespace myns.other-ns where a function needs to use some values in myns.core/conf can I call, in myns.other-ns/my-function direct on that map inside the first namespace? or it is always better pass in the conf as a parameter to myns.other-n/my-funciton?

gleisonsilva00:10:54

in another words, how is the 'best' way to share this conf map between namespaces?

seancorfield00:10:03

I would always pass the configuration as a parameter.

seancorfield00:10:31

Globals -- your def of myns.core/conf -- make testing and maintenance hard. You should try to avoid them altogether if you can.

seancorfield00:10:32

(that's assuming configuration could potentially change from run to run)

gleisonsilva00:10:53

yes... it changes... the values are read from a .edn file

seancorfield00:10:10

Then it should not be a global def at all.

seancorfield00:10:01

The value bound to a def is evaluated when the namespace is loaded and having side-effects occur during namespace loading is a Bad Thing(tm).

gleisonsilva00:10:12

I should, then, read the conf file in core namespace and always pass the values as parameter to the functions?

seancorfield00:10:01

Read the conf file at program startup, and always pass it as a parameter.

seancorfield00:10:21

(it will make your life much easier in the long run)

gleisonsilva00:10:24

but how to workaround that? I mean.. I need to read the conf file and 'keep' that value in memory to use on the subsequence calls to functions..

gleisonsilva00:10:02

I should define an atom and swap it on loading the conf file?

gleisonsilva00:10:49

or just use a 'load-conf function` just in time to call the "entry point function"?

seancorfield00:10:43

The former is just another global variable. And a mutable one at that.

seancorfield00:10:57

Have you looked at Component or Integrant?

gleisonsilva00:10:11

another thing... I have several values inside this conf file...

gleisonsilva00:10:27

and several of that are used in diferent functions

gleisonsilva00:10:56

no... i'm not using that libraries..

seancorfield00:10:01

They are designed for "global state" that has a lifecycle -- you could have a Configuration component that reads the EDN file when you start it up. And then pass that Configuration component into your entry point function.

seancorfield00:10:39

Once the config is loaded, it should be treated as just another immutable map of data as you're passing it -- or parts of it -- around your app.

👍 4
😀 4
Dormo02:10:32

Can you depend on the ordering of a map? For example, if I were to do (vec {:first :foo :second :bar}) can I depend on it returning: [[:first :foo] [:second :bar]] ?

Dormo02:10:17

Versus returning [[:second :bar] [:first :foo]]

andy.fingerhut02:10:14

In certain special circumstances, yes, but those circumstances are likely to be so easily broken that I wouldn't recommend it.

andy.fingerhut02:10:19

Circumstance 1: You create an array-map using the function of that name. Down-side - as soon as you do other normal map operations on it like assoc, merge, etc., and it gets over a small size near 8 key/value pairs, it will return you a hash-map, where the order is gone.

andy.fingerhut02:10:03

Circumstance 2: You use a sorted-map, which sorts key/value pairs on the value of the key, a priority-map, which sorts them on the value of their values, or an ordering-map, which sorts them on the order that the key was last inserted.

andy.fingerhut02:10:04

sorted-maps come built into Clojure. The other 2 require libraries that are linked from the Clojure cheatsheet: https://clojure.org/api/cheatsheet

andy.fingerhut02:10:08

Circumstance 2 is a bit more robust than #1, but even that can be broken in unexpected ways, e.g. if you do a merge on two maps, you get back a map that has the sorting properties of the first argument, not the second one.

Dormo02:10:15

I see. I'll stick to vectors of pairs when I need order, then

artur06:10:09

Is there a neater way to create a map if the keys are same as variable names?

dangercoder06:10:07

I don't understand why you would want to do that, u would like to create a map like this:

{:foo :foo
:bar :bar} 
?

dangercoder06:10:07

Not sure what you want to do, but using a set could also work 🙂

user=> (def test-set (set '(:foo :bar :jar)))
#'user/test-set
user=> test-set
#{:jar :bar :foo}
user=> (:jar test-set)
:jar
user=> 

artur06:10:09

I have a function that takes three params: id, description and owner and I want to return a map with same key names.

artur06:10:02

In javascript, this would be done like so: { id, description, owner }

Dormo06:10:30

I believe this was discussed not too long ago, actually.

☝️ 4
Dormo06:10:47

I don't think there's anything built into the language.

Dormo06:10:02

People have written macros for it, though

artur06:10:50

ok, will investigate

artur06:10:19

Not a big issue to define key and value but it seems like extra code when it could be simpler

Dormo06:10:20

I do agree it would be nice to have included in the language. I think it's a pretty common case.

Dormo06:10:26

Yeah. I agree.

artur06:10:37

Thanks Dormo

seancorfield06:10:32

It doesn't really come up in real world code all that often, to be honest.

seancorfield06:10:00

(and, yes, it has been discussed several times -- and someone created a macro for it but, ugh, that's ugly!)

seancorfield06:10:23

In real world code, it's pretty rare to have a series of variables and want a map with exactly the same key names as the variable names. Normally, you're building a map from computed values directly, or you're transforming one data structure (map) into another (map).

seancorfield06:10:38

Even if data comes at you from a vector, you can easily build a map programmatically

(zipmap [:id :description :owner] vector-of-data)
for example.

artur07:10:04

I actually think it is not that rear to see key name same as the variable name. This is exactly the reason js has the simplified syntax.

seancorfield07:10:01

It may be more common in JS. It is not that common in Clojure in my experience (over seven years of production Clojure and an 83K line code base).

☝️ 4
miikka11:10:37

It does come up in production code all the time for me (five years of Clojure with multiple big code bases) 😛

miikka11:10:32

I use the metosin/potpuri utility library, which would have (map-of foo bar) macro which expands into {:foo foo :bar bar}, but honestly I never use the macro. I just write it by hand.

artur11:10:25

I guess it depends on coding styles. For me if I name function parameters I tend to name them as they would appear in a map.

artur11:10:40

Miikka that is exactly what I was looking form 🙂 Thanks!

artur11:10:16

Yup, I like it: (swap! shopping-list assoc id (map-of id description price))

tavistock11:10:40

idk what you doing but a similar function that might help is select-keys

artur12:10:40

@U0C7D2H1U I explained above. map-of does what I was needing 🙂

artur12:10:33

So instead of doing :keyname keyname i just do (map-of keyname) and it generates {:keyname keyname} for me

tomaas09:10:13

hi, what do you use or would recommend to use for stripe? Some clojure library or interop with stripe-java?

val_waeselynck09:10:49

The Http API directly

tomaas09:10:46

from js side directly you mean?

val_waeselynck09:10:43

No, I meant from the server side

tomaas09:10:24

ok, thanks

tomaas09:10:03

I've added [cljsjs/stripe "3.0-0"] to my project.clj, then in some.cljs file i requiere [cljsjs.stripe], try to compile the file and get " No such namespace: cljsjs.stripe, could not locate cljsjs/stripe.cljs"

tomaas09:10:39

oh, it only serves as externs.js when compiling with advanced. no need to requiere in cljs anything of that. I need to add stripe.js library and use it normally with interop. Hope so 🙂

Ellie09:10:21

I am working on a luminus app using mount. I want to define a constant list, but that list is stored in the db so needs to be loaded after mounting the db component, so I can’t just def it. I could define an atom then load it in an init function, but it seems wrong to use an atom for a data structure that should never change. Any suggestions for a better way?

miikka11:10:40

You could use a promise instead of atom, it's basically an atom that can never change once it has been written.

hkjels11:10:34

I’ve found myself doing something like this quite a few times. Is there a more idiomatic way of writing this snippet that doesn’t involve a conversion between map and a list

Audrius11:10:40

Hi, please advice any data structure browsers for Emacs or REPL. something like in Intellij we have debuger's object browser.

jdt12:10:02

Good morning clojurians. lazy-seq question. I have always had difficulty wrapping my head around lazy sequences. I understand the simple examples fine but have difficulty trying to ramp up from there to more complicated data. Take the following poor example of a map of maps: {1 {101 :a 102 :b 103 :c} 2 {201 :aa 202 :bb}}. I want a seq function that will produce pairs of the form [outer-map-key inner-map-value] for each distinct bit of data. So on the example data set the seq would produce [1 :a] [1 :b] [1 :c] [2 :aa] [2:bb]. If I were simply mapping a function it would be:

(doseq [[k m] outer-map]
  (doseq [[_ v] m]
    (call-fun k v)
But I struggle to turn that into some kind of lazy sequence Any wisdom? For now I just use my mapping function (and since in my case there's a lot of data, it's probably better to avoid accidental caching and so on), but I'd really like to master lazy sequences and so far they cause me headaches.

emccue12:10:14

@dave.tenny Map works, but for this case for is your friend

kazesberger17:10:14

thx! omg it actually was a classic case of "did you try to switch it off and on again?". just made sure i enabled strict mode - which it was and then tried to reproduce -> voila it works.

8
jdt12:10:17

Ah yes, forgot about for. I'm curious though how I would produce this if I were implementing a "producer fn" using lazy-seq.

emccue12:10:36

for returns a lazy sequence (I am pretty sure)

jdt12:10:11

Yes, I think you're spot on with for, and perhaps looking at the macro expansion will yield some clues for me about writing my own producer functions on data structures with lazy-seq, which is really what I'm trying to master with my question.

jdt12:10:08

Or ... not. Ugh, that's some expansion 🙂

😁 4
jdt12:10:26

(j/k, useful bits there)

manutter5112:10:20

I think the hard part is figuring out the function to generate the next item in your list, which is kind of like figuring out recursive solutions.

jdt13:10:29

So basically code it as if I were producing a sequence recursively and insert lazy-seq before any recursive calls. Maybe that's how I should think of it.

manutter5113:10:18

I think that’s the basic idea — I’m trying to write a lazy seq for your nested map problem, but it’s been a while since I’ve done lazy seqs!

manutter5113:10:26

Ok, I have a solution, I’ll put it in a gist so as not to be a spoiler if you want to keep working at it.

manutter5113:10:42

I bet this would make a good 4clojure problem 😉

manutter5114:10:44

Probably should have pinged @jdt on that gist…

jdt14:10:15

got it, will take a look

ro614:10:51

I just rant into java.lang.AbstractMethodError: Method linked/map/LinkedMap.isEmpty()Z is abstract, which I've never seen before. My instinct says dependency version conflict maybe? More context to follow...

ro614:10:39

Manifested when trying to access the /swagger.json endpoint in a compojure-api app, so I think it's coming from the process that generates swagger.json. Maybe a Jackson lib version conflict?

dangercoder16:10:34

Anyone who used https://github.com/jarohen/chime? I've tried to start "Pollers" with it using core-asyncs go-loop but when I have too many go-loops running concurrently one is blocking all others.

dangercoder16:10:16

I guess its due to the fact that core async only have a thread pool of 8 and im using all of them now..

dangercoder16:10:15

yep.. im blocking the general core.async thread pool

dangercoder16:10:46

I need to spawn like 400 pollers that are running async

noisesmith16:10:05

you can have thousands of go loops running without blocking the pool, the real problem is doing IO or CPU intensive work inside go blocks

dangercoder16:10:31

yeah in this go-loop (from the chime poller-example) i will poll a status.

noisesmith16:10:49

use core.async/thread to do IO, it returns a channel you can park on without blocking a go thread

dangercoder16:10:59

u can use that within a go-loop? cool

noisesmith16:10:27

it's meant for use inside go / go-loop yeah

dangercoder16:10:49

ah. Thanks noisesmith

dangercoder16:10:50

in this case for me, async/<!! was the problem.

wizard 4
noisesmith16:10:36

oh, well technically that's IO :D

rickmoynihan17:10:50

Has anyone seen this warning? Using clojure 1.10-beta3

rickmoynihan17:10:51

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by clojure.lang.Reflector (file:/Users/rick/.m2/repository/org/clojure/clojure/1.10.0-beta3/clojure-1.10.0-beta3.jar) to method com.sun.org.apache.xerces.internal.jaxp.datatype.XMLGregorianCalendarImpl.toGregorianCalendar()
WARNING: Please consider reporting this to the maintainers of clojure.lang.Reflector
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

alexmiller18:10:03

Somewhere you have a reflective call to toGregorianCalendar. The Clojure reflector is finding the method on the concrete implementation class (XMLGregorianCalendarImpl) which is not module-visible.

alexmiller18:10:24

This is a warning (as you see) and should continue to work up through Java 11.

alexmiller18:10:32

There are a variety of ways to “fix” the warning:

alexmiller18:10:01

1. Stop using reflection by type-hinting the call. If it’s in a library, would be good to file an issue.

alexmiller18:10:28

2. use --illegal-access=deny. In this case, the Reflector (in Clojure 1.10+) will avoid choosing inaccessible methods and should work without a warning.

alexmiller18:10:03

3. Use other flags to either open all modules or this module up to reflective use. Not recommended.

alexmiller18:10:28

4. Ignore it - it’s just a warning (despite the admonishment)

👍 4
noisesmith17:10:50

looks like something that would happen with a recent jvm - downgrading to a 1.8 jvm should eliminate that

noisesmith17:10:30

(not that that's necessarily the right fix...)

rickmoynihan17:10:37

that was my thought

schmee17:10:14

don’t see any reason to downgrade, just ignore the warning if there is not a newer version of the library out

rickmoynihan17:10:50

Yeah, I agree & understand the message. I’m just following through on what the message suggests i.e. indirectly notifying the maintainers of clojure.lang.Reflector 🙂

rickmoynihan17:10:45

though I thought I’d ask here first, rather than bother Alex etc directly with it at this stage; as they’re busy enough 🙂

schmee17:10:03

ooooohh, I thought the issue was with the Apache library, didn’t read carefully enough!

schmee17:10:06

my bad 🙂

rickmoynihan17:10:51

well it might be… and it might be with my code too… or it could be the specific environment I’m running this in.

rickmoynihan17:10:31

I hadn’t noticed this before, but basically I’m running an interactive rebase exec with lein test over a tonne of commits; but launched it via magit/emacs rather than from my shell. It’s still going, so it could be picking up a java 9 VM or something… not sure yet. I was expecting it to run with java 1.8… but it looks like it might be finding something different.

schmee17:10:51

seems like it, the IllegalReflectiveAccess thing is for sure a JVM > 1.8 problem

rickmoynihan17:10:05

yeah that was my thought… probably the new module system

rickmoynihan17:10:50

I was assuming it’d pick up 1.8; but this is the first time I’ve run lein test through magit and interactive rebase, so it’s entirely possible it’s getting a different version of the jvm. I don’t want to rerun another process through magit whilst it’s going, as I suspect that will break things.

rickmoynihan17:10:00

Its still going, and I’ll be packing up for the day when it finishes… but can look at it tomorrow

rickmoynihan17:10:44

ok it’s actually just finished… looks like it is getting java 9 when run this way…

rickmoynihan17:10:04

I didn’t give it much thought at the time, but was expecting java 8 when I first kicked off the process.

rickmoynihan17:10:30

ok home for me! 👋

mrchance17:10:45

I found amalloys answer to "How to recur upon exception":

(defn try-times* [thunk times]
  (let [res (first (drop-while #{::fail}
                               (repeatedly times
                                           #(try (thunk)
                                                 (catch Throwable _ ::fail)))))]
    (when-not (= ::fail res)
      res)))
And was wondering if that is guaranteed to never run the thunk again after it succeeded? From what I understand about lazy sequences in Clojure I would assume that's a yes, but worrying if it's possible that larger parts of a lazy sequence get realized as an optimization

hiredman17:10:49

ugh, no, use trampoline

hiredman18:10:06

(trampoline
 (fn f []
   (try
     ...
     (catch Throwable t
       f))))

emccue18:10:49

@mrchance I don't know the exact semantics for lazy seq realization but I have a memory of a discussion about it meaning it isn't always one at a time in all situations for all kinds of lazy sequences

emccue18:10:23

In general I would just avoid using lazy sequences for side effects

emccue18:10:27

unless you are able to (doall ...) explicitly

mrchance18:10:12

@hiredman Thanks! That helps, and I saw a mosaic of Robert the Bruce recently, so that's a bonus 😉 I'll probably go with the trampoline though, finally a chance to use it, and one less dependency @emccue Yeah, precisely what I was worrying about, thank you too 🙂

mrchance18:10:30

Oh, so it does happen

emccue18:10:35

outdated reference maybe though

emccue18:10:48

but enough evidence to not rely on that behaviour

mrchance18:10:58

Exactly, wouldn't depend on it then

emccue18:10:27

also, who is what is the meaning of the reference to robert the bruce

mrchance18:10:11

> It's named after Robert the Bruce, whose determination was inspired by the sight of a spider trying (and failing) many times to build a web. 😉

mrchance18:10:27

A Scottish King, I believe

emccue18:10:35

and I learned something today

mrchance18:10:48

Hooray for programmers struggling to name their libraries

Eccentric J20:10:34

Researching for an upcoming Clojure project for work. I will need to make oauth v1 authenticated requests to an existing API. Any recommended libraries?