This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-02-05
Channels
- # adventofcode (8)
- # aleph (42)
- # announcements (4)
- # beginners (157)
- # boot (4)
- # calva (1)
- # cider (6)
- # cljdoc (8)
- # cljs-dev (1)
- # cljsrn (3)
- # clojure (50)
- # clojure-europe (9)
- # clojure-italy (16)
- # clojure-nl (2)
- # clojure-russia (6)
- # clojure-spec (59)
- # clojure-uk (25)
- # clojurescript (20)
- # core-async (41)
- # cursive (30)
- # data-science (9)
- # datomic (20)
- # fulcro (28)
- # kaocha (9)
- # nrepl (1)
- # off-topic (3)
- # om (3)
- # pathom (10)
- # re-frame (8)
- # reagent (2)
- # ring-swagger (38)
- # rum (9)
- # shadow-cljs (209)
- # spacemacs (7)
- # tools-deps (11)
- # vim (6)
- # yada (2)
I agree. But, you know that programmers likes a challenge. To me has been a big challenge start with clojure and learn how to work with emacs at the same time. It’s hard but i like it
I’ve been listening to a great podcast called Coding Blocks, just listening to their series on the book Clean Architecture, which is very C-descendent focused, and it made me wonder: are their any resources out there for Clojure that tackle similar concepts?
I’ve watched this video (https://www.youtube.com/watch?v=0EX3UIl-Sd8) some time ago, which kinda talks about using Clean Architecture when using clojure
Awesome, thanks! I’ll give that a watch
Hi all, cider has been giving me the following error on blank projects/lein profiles and I am not quite sure how I am supposed to figure out what the culprit is. I would appreciate any help or nudges in the right direction. Thanks!
@mitchell_clojure It's just a warning so you can ignore it. If you ask in #cider they might be able to help you make it go away.
(it's a standard warning from the slf4j Java logging library that appears when you don't have certain other libraries on your classpath)
Thanks, Sean. Really appreciate it.
@charlesg3 That seems to have done the trick. Thanks a ton. Is this an isolated issue somehow? Or well documented anywhere? I did some searching on github but maybe I was not self-reliant enough.
@mitchell_clojure If I understood the way it was explained to me when I had this problem: any time you rely on a library that uses the slf4j
logger, you'll get that message, because it's warning you that no one told it what code to run for logging. Including slf4j-nop
tells it, explicitly, what you want to happen is a no-op, i.e., to do nothing. (Which is what it defaulted to, but it warned you it was doing so.)
No idea. I just experienced the same issue on several projects, did some searching... found that solution and use it on all projects that use logging.
Interesting. Thanks for the help and have a great night!
Any strategies for avoiding symbol name clashes instead of using synonyms. For example for symbols like update
, get
, name
ect
Do you mean as top-level definitions or as local symbols in let
?
Well as a general rule of thumb I thought it was a good idea to avoid using built in symbols altogether. Solutions for both ideally
I find myself thinking about this whenever I write code to do crud operations as update
is taken
For top-level definitions, there's no problem really. If the ideal name for something matches a clojure.core
function, you can still use it in your namespace. You can use :refer-clojure :exclude [...]
in ns
to avoid pulling in the matching core functions -- which also acts as documentation that you plan to override them -- and them you can refer to the core
versions with clojure.core/<function>
if you need to. It's recommended to put your version of such functions near the end of your file so you are less likely to use them by accident (instead of clojure.core/<function>
). That's why we have namespaces.
For local symbols shadowing clojure.core
functions, that can be okay too -- again, if that's the obvious name to use -- and linters like Eastwood should be able to warn you that you're doing that (using Eastwood is a good idea anyway!).
In clojure.java.jdbc
, I use update!
rather than update
since it involves a side-effect on an external resource so it (potentially) would not be safe in a transaction. I tend to use !
to indicate side-effects at the edge of the system -- although that library has query
rather than query!
even tho' it could return different results at different time.
So it's essentially a trade off between the occasional confusion caused by overriding core functions and the confusion of choosing a poor alternative symbol name?
Zach Tellman's excellent "Elements of Clojure" has plenty to say on this topic -- highly recommended.
Yes, exactly that trade off.
Thanks for your help 🙂 I checkout "Elements of Clojure" now
From Zach's book
If these functions are in a namespace specific to payloads, they can simply be called get, delete, and compress-and-get. We can assume that other namespaces will refer to our namespace with a prefix, such as payload/get or p/get. This means that shadowing Clojure functions like get is safe and useful, but we should take care to specify this at the top of our namespace:
(again, why we don't use :use
or :refer :all
in most cases -- and prefer :as
instead)
Yea I very rarely refer to a symbol without prefixing with a namespace alias (using :as
) for that reason.
(aside: I'm curious as to where it is 4pm right now?)
Queensland Australia :flag-au:
Ah, I have Sydney as 5pm on my world clock and expected all of Eastern Australia to be on that TZ... am I incorrect?
Oh, you're west of that?
Sydney & NSW is on daylight savings. I'm pretty sure none of Queensland is
(sorry, my Australian geography is poor)
TIL! Yeah, just looked that up. You stopped doing DST in 1992. Very smart of you. Wish we'd do it here in California! 🙂
You will never get rid of your timezone troubles. I live in The Netherlands, where we used to have a offset of +00:19:32 until 1937, thats bugging me in code sometimes 😛
(for example, when someone tries to be funny and put an epoch on 01-01-1900 at 00:00 local time)
Yea. Daylight savings seems to just confuse things to me.
Indeed.
Ah so Queensland is AEST, and everything else on the east is AEDT
Back to your question, I just looked in our codebase and send
, update
, and get
are the most common names we override of the core functions.
We also have one namespace that overrides find
and reset!
, and another that overrides set!
, and one that overrides +
, -
, and *
That's good to know that others do that. I've just avoided it entirely as when I've done it in the past, it was incredibly confusing to debug without realising it's overridden. Although its one of those things where once you've done it your on the lookout when your debugging similar issues in the future.
I'd much rather use the correct name though
You usually get warnings when you override at the top-level but not local let
bindings. I've certainly shot myself in the foot by shadowing name
and key
and a few others in let
... 😞
I made some wrapper functions for promises in cljs and it drove me nuts not using resolve
. I actually just used p-resolve
instead but always hated it
resolve
on a promise? Interesting.
(.-resolve promise-obj)
actually nevermind
I got deref
confused with resolve
Interesting that you seem happy to overload namespace aliases (e.g., o
) with local variables (argument o
) 🙂
As I understand it they don't clash
But I guess it is kind of strange
They don't, and lots of people do that. But given you asked about strategies to avoid clashes... 🙂
(and it is extremely common to alias clojure.string
to str
which of course matches a core function!)
Yea I've used that too
I was more accepting of that because it didn't clash and require debugging. I'm not sure I've ever been confused with ns alias vs symbol. However I've had tough times debugging symbol clashing with symbol
It always happened with name
Yeah, name
is a common source of clashes I think.
and I destructure a lot too so namespaced keywords didnt really help {:keys [foo/name]}
makes name
available
destructuring was my primary source of clashes as apposed to let. As it's easy to rename a symbol in let to something else. Destructuring isn't as simple you either need to name the key something else, or use alias {foo-name :foo/name}
Which means it's not as elegant as keys 😞. However Ill override from now on when in makes sense
Even with a local name
binding, you can still always use clojure.core/name
to disambiguate. But, yeah, it takes care (use Eastwood!).
yea hence the only real downside to overloading is understanding code and debugging a unknown clash
Hello Clojurians! I want to learn Clojure by building projects or solving a problem or writing a compiler. Although I am familiar with basic syntax but I never got to building anything. I tend to appreciate a language and learn more by building. Can anyone please recommend any free online course(prefer videos) or beginner level Github repo which can be used as a reference.
@abiduzair420 maybe @plexus’s https://lambdaisland.com would suit your need.
How to require a cheshire in my repl, started by lein repl
? This is being run outside of a project
@mario.cordova.862 but you have the dependency on your REPL’s classpath?
Thank you for linking this! I can't afford Lambda Island or Purely Functional tv yet but have never come across this one.
@dpsutton did you watch all of them? I’m still curious why he says “why not use HOFs”
i haven't seen that one. i think i still have a membership. it's crazy reasonable like $3 a month or something
There’s also this paid one: https://purelyfunctional.tv/ by @ericnormand
> Clojure is a functional programming language, so we should use Higher Order Functions all the time right? Maybe not, let's talk about the downsides.
off the top of my head, higher order functions capture the value of a var, so don't see redefs (unless you explicitly use the var...)
(fn what-it-does [y] (foo x y))
is better than both - it also has a readable name in a stack trace
not me, I never get stack traces because my code is perfect
Yeah it is not free. This has been an issue in my Clojure learning journey. I understand they do it for a living but I wish there was one full-fledged course
plexus and tim both have free subsets of their videos. clojure for the brave and true is the entry for a huge portion of professional clojurists and is free online
Alright I shall try the brave book. Thank you @borkdude @dpsutton for your time
and of course there's always #beginners with lots of people here explicitly to help and chat 🙂
Yes that's the best part about Clojure community.
I mean, just the Brave book is probably not enough info to land something is it?
if you're a programmer and learn clojure from brave I bet you could work on a code base if you had coworkers in the room. I think you could land an entry clojure job with some programming chops and comfort with brave
hi, i'm trying to create an array of enum with
(into-array org.lmdbjava.DbiFlags '(DbiFlags/MDB_CREATE))
but i get java.lang.IllegalArgumentException: array element type mismatch
and i don't understand why@gabriele.carrettoni that is a list with a symbol in it
I'd try (into-array org.lmdbjava.DbiFlags [DbiFlags/MDB_CREATE])
@noisesmiththanks, what a stupid mistake
demonstrating the issue more directly:
(ins)user=> (type Math/PI)
java.lang.Double
(ins)user=> (type 'Math/PI)
clojure.lang.Symbol
still doesn't work because
No matching method openDbi found taking 2 args for class org.lmdbjava.Env$Builder
but you didn't even call the method
(in the code you shared)
(deftype Lmdb [global-options]
AStorage
(open-conn [this db]
(let [env (doto (Env/create)
(.setMapSize 10485760)
(.setMaxDbs 5)
(.open (.-file db) nil))
db (.openDbi env
(.-name db)
(into-array DbiFlags [DbiFlags/MDB_CREATE]))]
(->LmdbConnection env db))))
as you can see here https://github.com/lmdbjava/lmdbjava/blob/master/src/main/java/org/lmdbjava/Env.java#L262
why is DbiFlags an arg there and what is its value? n/m I misread
you might want to type hint args to help the method dispatch properly
right, there are multiple methods with the same arity, and clojure has to decide when compiling which method to call
(deftype Lmdb [global-options]
AStorage
(open-conn [this db]
(let [env (-> (Env/create)
(.setMapSize 10485760)
(.setMaxDbs 5)
(.open (.-file db) nil))
db (.openDbi env
(.-name db)
(into-array DbiFlags [DbiFlags/MDB_CREATE]))]
(->LmdbConnection env db))))
this worksso your first arg was the wrong type (the builder instead of the thing it returns when you call .open on it)?
yes and
No matching method openDbi found taking 2 args for class org.lmdbjava.Env$Builder
yeah, doto would do that
is there any way to clean this up?
(->> (repeat 100 {})
(map make-purchase-event)
(partition-all 10)
(pmap batch-send-txn))
batch-send-txn is io sending to SQS. It seems to be taking a long time and i can’t seem to get comp working correctlymy first concern is where that data goes. If nothing consumes the result of pmap, it is lazy and the code doesn't run
it just goes to sqs, and then we read from the result of pmap if all messages were sent successfully
that's totally broken
I misread what you said here, "we read from the result of pmap if all messages were sent correctly" sounded like "first we verify all messages were sent, then we consume the result of pmap", which would be a deadlock, as no side effects would happen until you consume from the pmap output
also, do verify that whatever consumes from the pmap result is eager, this is a common source of bugs
pmap is a red flag for me in code reviews - it gets used wrong more often than it gets used correctly
sure. the problem i suppose is that its easy to use, but apparently also eeasy to misuse. it uses futures under the hood which seem to be good for io though, yes?
sure - but see my other remarks
@ben.borders out of the 100000 values supplied to pmap here, only 32 are consumed
(ins)user=> (def processed (atom #{}))
#'user/processed
(ins)user=> (do (pmap #(swap! processed conj %) (range 100000)) nil)
nil
(ins)user=> (count @processed)
32
how do you know they are consumed? who consumed the return value of pmap?
it's not easy to use, it's hard to use correctly. if you don't consume the return value from pmap, it does nearly nothing
the 32 is just a batching artifact
in a future clojure version that could change to 100, or 0
OK - if you are consuming the return value of pmap eagerly, I'm not sure where your bottleneck would be. Note that the batching that pmap applies internally assumes that your code is CPU bound, and you probably shouldn't use pmap for io bound code
it limits the concurrency based on the number of physical processors visible to your runtime
interesting.. that all makes sense.. seems its allocated here:
(+ 2 (.. Runtime getRuntime availableProcessors))
then i guess im back to square 0 of the best way to parallelize io calls like this. maybe in a go-loop where each io op dispatches a thread?
the claypoole library has parameterized versions of this stuff using thread pools
the problem with using go-loop is you are introducing a heavyweight library that has a long startup time and many ways to use it wrong, for something that doesn't require any of its unique features
interesting. I suppose so. Then i guess i need to manually pick my parallelism myself. Can use a loop i suppose and dispatch the # of futures = to my parallelism and deref them all afterwords in a map to ensure doneness.
instead of deref in a map (once again lazy), perhaps group-by with a failure checking function so you get a list of success and a list of failure (eager)