This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-11-07
Channels
- # aleph (15)
- # beginners (186)
- # boot (11)
- # bristol-clojurians (1)
- # clara (1)
- # cljdoc (2)
- # cljs-dev (5)
- # clojure (57)
- # clojure-austin (1)
- # clojure-dev (87)
- # clojure-italy (7)
- # clojure-spec (5)
- # clojure-uk (56)
- # clojurescript (18)
- # cursive (29)
- # data-science (10)
- # datomic (84)
- # duct (83)
- # figwheel-main (4)
- # fulcro (42)
- # jobs (3)
- # lambdaisland (2)
- # off-topic (28)
- # parinfer (3)
- # portkey (3)
- # re-frame (28)
- # reitit (7)
- # remote-jobs (8)
- # shadow-cljs (29)
- # spacemacs (30)
- # specter (6)
- # sql (8)
- # tools-deps (60)
what would be a name convention to remove-attribute-key
, that does
(dissoc my-obj :attribute)
more on name convention: what is the best practice for boolean functions?
has-something?
or
something?
Any other?my personal preferences:
I would name (dissoc obj :something)
remove-something
i.e. drop the -key
I don't care for the has
I would make a map key end with ?
only if the associated value is definitely a boolean
actually maybe the has-
isn't bad. I suppose the value under the key IS an attribute. (attribute? obj)
makes me think your checking if obj is an attribute, not if obj contains an attribute
maybe (contains-attribute? obj)
mainly because that naming is more similar to the already existing contains?
I would use prefixes like has-
if it conveys some information that ?
doesn’t cover, and ?
tends to implicitly mean “is”.
For example, (has-rabbit? hat)
seems a lot less ambiguous than (rabbit? hat)
, whereas (rabbit? animal)
is unambiguous.
A rule of thumb that I see emerging for me, is that if it’s harder to name something rather than understanding what it does, perhaps avoid naming? I have to read the elements of clojure again :)
@orestis That's very inspiring. I often find myself in this situation. I guess it's worse because of my OO background.
It helps immensely to have a naming buddy if you’re working in a team. In some recent work I named some weird function aaa
and moved on, then asked for help. This was JS, which does make things more verbose though, so naming is more important.
I don't think naming an invocation of a core function adds to readability (re: the (dissoc obj :something)
example above).
It's like Stuart Sierra's advice not to name (map some-fn coll)
how so, if you partially applied map, then it makes sense to name the intend of your partial application right.
“This map function really only adds 2 to every element”
I'd have to concur. Why are you going to wrap 3 words into a whole function just to name it. That's a terrible abstraction. If you think of an abstraction as something that says more with less. Which often words in a language are. That function is a way to say more with less. So if many lines of logic is given a name, that name is now an abstract representation of the concrete implementation of the function's logic. dissoc
is already an abstraction of that sort. Remember how complicated removing a node in a tree is? Well that's dissoc
for you. But now, we don't need to mention all the step of that for someone to understand the gist of the process, it is just dissoc
. Now sure, in English, many things have synonyms, but I'm not sure in code that makes it any better. Now, a better abstraction is if this was related to your domain problem in some way. Say it was remove-from-user. Now at first, that's just (dissoc user something)
. But eventually that could involve many more things happening, maybe you push some audit trail to some DB before this happens for example. So while I still think it is premature to create this abstraction, eventually, it could make sense, and would be much better. Otherwise, you are just making people believe lots is happening and have them dig up the function to see that nope, it's 1 line of code.
@lennart.buit I'm not sure what the others truly meant, but I think your example is different. You're talking about creating an add2 function which takes a collection and adds 2 to every element.
Yeah I am trying to find what Stuart Sierra had to say about naming map invocations
yeah, but thats basically a partial application of map right
(def add2 (partial map #(+ 2 %))
so, how is that different than calling #(dissoc % :user)
by its name, e.g. remove-user
. That is also a partial application abeit with its arguments reversed. Where to you draw the line.
Sorry if I come about as being rude, I am trying to understand ^^
This is the blog post btw: https://stuartsierra.com/2016/01/09/how-to-name-clojure-functions
Ya, there's no real wrong and right here. Mostly style. Let me think where I draw the line, it's mostly intuition in practice, so it's hard for me to define some rules about it
So, (remove-user) to me is much better. That's what I meant in my long comment above. It creates a domain level abstraction.
But you have to balance that with a few considerations, such as, how much reuse are you going to get out of this? Does the implementation need to be modified or extended transparently from the caller? If neither of these are true, especially the latter, you are just obscuring the code through an extra jump.
Yeah, exactly that
There is indeed a fine line between sensible abstractions and adding abstractions for the sake of adding abstractions :’)
In my opinion it is often a case of that, when someone puts every little thing behind a component of some sort, without good reasons, it tends to code that is actually less readable because now everything is too small to understand the bigger picture, and you just have to look here and then there and back over here to put the pieces together, where you'd rather they'd all fit in your screen in one read.
Well, that particular blog post not that great, C2 wiki has it much better: http://wiki.c2.com/?RavioliCode
Spaghetti code I think everyone knows. When all things depend on all other, and everything is coupled to everything else.
Lasagna is when you've got layers of layers of layers. Where most layers do nothing except take from the below layer and give it to the bottom layer.
Ravioli code is when your components are so small, that they no longer are responssible for anything relevant to the problem on their own.
That said, of the three, ravioli is the least harmful in my opinion. And I rarely see code reach that point, most programmers are too lazy to factor things out to that level.
the naming tho
is this not lazy?
(reduce + (take n (filter even? (range))))
timed out during a coding challenge so I'm wondering whether that's a server / speed / lazy-seq issue
hmm, is this the fastest way of summing a seq/vector of (for example even) numbers?
(defn f-one [n]
(reduce + (for [x (range 1 (* n 2))]
(if (even? x) x 0))))
(defn f-two [n]
(reduce + (take n (filter even? (range)))))
(println (str
(time (dotimes [x 1000]
(f-one 5000)))
(time (dotimes [x 1000]
(f-two 5000)))))
First one works, the second one times out.that's the one! thanks
f-two
shouldn’t time out though:
user=> (time (reduce + (take 100000 (filter even? (range)))))
"Elapsed time: 60.656893 msecs"
9999900000
also, the fastest way to sum even numbers from 2 to n 😉
(defn sum-of-first-n-even [n] (* n (dec n)))
(dec n) though
or are my functions wrong
for now I conclude that I definitely need a coffee
Don't know why it times out on your end? What do you even mean by time out? OutOfMemory? Infinite Loop?
user=> (time (f-one 1000000))
"Elapsed time: 62.203734 msecs"
user=> (time (f-two 1000000))
"Elapsed time: 605.268095 msecs"
It was a quick online challenge, it didn't specify the error. But yeah that was probably it, I'm assuming they had a time limit for each computation
Also, the transducer one with (range n) is a bug, as it does not behave the same way as f-one and f-two.
Hum, though on repeated usage, seems like they probably average pretty similar to one another
Probably a criterium bench would show us better if one is actually faster then the other
user=> (defn end ^long [^long n] (* n (dec n)))
#'user/end
user=> (time (end 1000000))
"Elapsed time: 0.03092 msecs"
999999000000
Oh damn, adding a type hint to n makes it take 2ms:
(defn f-four [^long n]
(loop [c 0 i 0 sum 0]
(if (>= c n)
sum
(recur (inc c) (+ i 2) (+ i sum)))))
user=> (time (f-four 1000000))
"Elapsed time: 1.433124 msecs"
999999000000
Type Hints for the win!If you are familiar with Java and its performance characteristics, decompiling JVM bytecodes produced by Clojure back to Java source code can be illuminating (or disassembling back to JVM byte codes can also be done, if you are familiar with those, but I would guess more people are familiar with Java source than JVM bytecode). https://github.com/clojure-goes-fast/clj-java-decompiler
also, https://github.com/gtrak/no.disassemble is invaluable for this stuff
Yes, no.disassemble if you are familiar with, or willing to learn, JVM byte codes.
I have a sort of naive implementation going through list of users, check for updated items and insert them to DB
(defn sync-calendar [user]
(run! #(insert-event-to-db % user) (get-events (:id user)))
(let [users (select :users)]
(run! sync-calendar users))
The problem with this pseudocode is that it only inserts events to DB for last user in list. Events for other users gets inserted as well (DB correctly returns new event with generated id from sequence) however it won't get commited to the DB permanently, only events for last user in list will. I am using Postgres and Korma if it mattersWithout seeing more of your code, it's kinda hard to tell. I don't know how many people still use Korma (is it still being maintained?). If you were using plain ol' clojure.java.jdbc
I could probably help more in the #sql channel.
I have a current system in another language and would like to move some functions over to clojure
Yes you can, Datomic ions will save you a ton of hassle for making a production-ready cloud deployment of this API, and Datomic is a pretty darn good database for most information systems. Having said that, assessing whether it's the "best way" or not would require a lot more detailed knowledge of your project, and using Ions will still leave a lot of decisions to be made for implementing this API.
As I understood datomic is using the api gateway as glue, so I guess this would mean exposing those endpoints to other users/services.
yeah I want to expose the endpoints to other services, but basically the questions is if I can run functions on ions just like on a regular clojure instance?
What do you think about this? https://docs.snapcraft.io/java-applications/7819 with clojure?
there are any best practice on negative
functions?
Is it better to use
(defn not-something [] ...)
(not-something?)
...or
(defn something [] ...)
(not something?)
personal taste would be to write them in positive form
I think the existing predicates back that up as well - http://blog.cognitect.com/blog/2016/8/9/focus-on-spec-predicates
because something?
reads better than (not (not-something? ...))
But, yeah, better to always have positive predicates since we already have if-not
and when-not
having both would be very unwise.
Just wondering, whats the reasoning behind having an explicit if-not
?
it feels like ruby’s unless
, and that somehow always makes me confused
is there a recommended alternative to Oracle for Clojureists?
@U9TSSLS2J OpenJDK, or IBM JDK, or the Azul JDK are all not owned by Oracle. Also self-hosted ClojureScript, which completely avoids Java. Finally you have ClojureCLR running on .net
Thank you, @U0K064KQV!
try using unless/else
, that really messes with your brain
java -version
openjdk version "1.8.0_181"
OpenJDK Runtime Environment (build 1.8.0_181-8u181-b13-1ubuntu0.18.04.1-b13)
OpenJDK 64-Bit Server VM (build 25.181-b13, mixed mode)
I just want to try something not owned by Oracle 😉
Also, I'm on windows
OpenJDK would be fine
but there are a few options: AdoptOpenJDK, Zulu
just wondering if anyone knows of one that works well
Oh, red hat is supplying OpenJDK builds; https://developers.redhat.com/products/openjdk/download/
openjdk is the reference implementation, so you can't really go wrong with that
adoptopenjdk is probably among the easiest ways to get it on windows
TIL that there are, by default, no standard binaries for OpenJDK on windows
I'm hoping someone can help we clojure.core.async. I'm playing around with go blocks that loop over the content of a channel and output the transformed values to another block. It works, except when I get to 8 go-loops being evaluated into the REPL I get an infinite hang. I think that the loops are parking/stopping when there are no more elements, so I'm not quite sure why this is happening. I'll post my little code snippet to recreate it as a reply to this message to keep from polluting the main channel
(defn increment-by-one
[input-chan]
(let [c (chan 10)]
(go (loop []
(let [result (<!! input-chan)]
(if (= result :last)
(>!! c :last)
(do (>!! c (inc result))
(recur))))))
c))
(defn print-results
[c]
(loop []
(let [result (<!! c)]
(when-not (= result :last)
(prn result)
(recur)))))
(-> (let [c (chan 100)] (dotimes [n 10] (>!! c 1)) (>!! c :last) c)
increment-by-one ;; 1
increment-by-one ;; 2
increment-by-one ;; 3
increment-by-one ;; 4
increment-by-one ;; 5
increment-by-one ;; 6
increment-by-one ;; 7
print-results)
use <! instead of <!!
the blocking is caused by using >!!
inside go
go blocks are not for parallelization, they are for coordinating things, it's easy to lock them up
that makes sense! I will remember to use <! inside of go blocks. Thanks a lot @U051SS2EU and @U1XTUTPMY
in general, the core.async docs are good at specifying if an operation is blocking or parking
parking ops are only possible inside go blocks, and blocking ops should not be done inside go blocks
if you need to do something that blocks from the logical flow of a go block, there's core.async/thread which returns a channel you can park on with <!
, but uses its own larger thread pool
so it won't starve your go blocks
what is the best way to achieve parallelization with async? Is thread the right way to go?
you can replace (go (something-that-takes-forever) (<! foo))
with (go (<! (async/thread (something-that-takes-forever)) (<! foo))
yes - or you can use a proper thread pool library like claypoole and then use core.async at the boundaries where coordination is needed
the key is often separating the concepts of parallelism (which you do to make things faster) and asynchronous coordination (which you need to do because parallelism gets messy)
core.async is really good at the second part
right, I'm currently trying to write a library where you can define 'jobs', which are a series of functions to be applied to some data set - but I'm only providing a certain set of ways to pass a function, so that I can make assumptions on how to parallelize and coordinate their data behind the scenes. Sounds like I need to read up on where to use threading and async.
@trailcapital you are doing something that blocks rather than parking
>!!
blocks a thread
use >!
inside go
core.async only uses a small number of threads, and it is easy to starve the pool if you do anything that blocks inside the body of go
how workable is lighttable as a clojure ide? is it just a prototype, or can people actual be productive with it for nontrivial projects?
if you want a real IDE, your best bet is probably Cursive with Intellij Idea
my problem with intellij is that it's bloated and has way more than what's necessary or even useful for pure clojure projects
if it's a fresh install it'll ask about plugin sets and you can disable the unnecessary ones. Or go into settings -> plugins to disable after install. I've never checked for Intellij configurations, I haven't seen it used like that (like Eclipse did).
okay, got rid of everything but Cursive and git integrations. is there anything else that's useful?
I was so sad when the debugger wasn’t really working all too nice with Clojure 😞
well it does work like it can break on breakpoints
but in Java, intellij is just plain better at evaluating local variables
and ‘step’ is just strange in functional code
I dont know, I am mostly back to debugging with repl and println, If anyone knows any better debugging tools I’d like to know
given that locals are usually immutable, using swap! to append a hash-map of locals onto a global atom is extremely useful
call function, play with the data it added to your atom, edit code, etc.
in some ways this is better than standard debugging via stepping because you are using the real language and repl, not a almost-compatible subsystem
I’ll check that out
I have been clojuring for about a month or so, so I am finding my footing still ^^
wrt to step and local vars, is this a general problem with debugging in LISPs, or does Clojure suffer especially because of the underlying Java runtime?
Nah its just Intellij IDEAs debugger being written specifically for the Java language on the JVM.
it kinda works for Clojure, since it is using the same provisions of the JVM to break on breakpoints. Its just way more useful when you are programming in Java instead of Clojure
I tend to prefer REPL and test-based debugging to step-debugging anyway, to be honest - even in other languages, unless there is a significant compilation cost I tend to prefer iterating on tests and/or running things from a REPL over ever touching a debugger unless I'm trying to figure out some really sneaky bug
But I would encourage the use of tests, too - often the stuff you're trying to verify from the REPL can just as easily be written into a test (sometimes more easily) you can then run from the REPL either manually or automatically. Bonus: now you have a decent starting point you can use, after cleanup, for your actual tests
ofcourse, but I like to use it when I want to trace some - typically - integration type problem through the application
testing you should do for sure!
the JVM is such a cool piece of tech, it always amazes me how much control you have over it even when it is running
And no, there's nothing inherent to Lisps that prevent having debuggers. In fact, I beliebe they were first to have one. It's only a matter of lack of resource and interest
I like that I am able to quickly move from project A to project B or C relatively quickly using the same window
You could also look at inspections. I don't know if it's smart enough to only run on appropriate file types, if it isn't then turning them off would make it faster.
I've heard good things about lighttable, but it doesn't have the developer resources you see in other IDEs/editors so there are a few convenience things that might be missing
Personally I just use neovim with vim-fireplace and a couple other goodies to give me cider-nrepl, autocomplete, and commands for evaluating, docs lookups, etc
some people have raved about maria and nightcode, though, when it comes to IDE stuff
wrt to step and local vars, is this a general problem with debugging in LISPs, or does Clojure suffer especially because of the underlying Java runtime?
I'm surprised that so few people seem to use a debugger in Clojure. I never found it that useful in Java / Scala, and only use a REPL in Haskell, but I find it invaluable in Smalltalk, and I assumed this would extend to other dynamic languages. then again, whenever I heard about debugging in LISP, it was with CL's SLIME, so maybe CIDER's debugger is inferior?
I’ve used ciders debugger to debug a single function and it works pretty well. I don’t know about larger systems though or conditional breakpoints and whatnot.
oh cool, thanks!
definitely watching that soon
@joebetz91 it turns out that Clojure REPLs give you a lot of debugging power - see for example https://clojure.org/guides/repl/enhancing_your_repl_workflow#debugging-tools-and-techniques
And if you're on Clojure 1.10, tap>
adds a lot more power (since you can easily leave it in the code and just hook up whatever "taps" you want, dynamically in the REPL, whenever you need/want them).
@joebetz91 I use the Cursive debugger every now and again. REPL is great, but it is nice to be able to fire up the debugger too, when needed.
And if you're on Clojure 1.10, tap>
adds a lot more power (since you can easily leave it in the code and just hook up whatever "taps" you want, dynamically in the REPL, whenever you need/want them).