This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-05-02
Channels
- # beginners (26)
- # bitcoin (1)
- # boot (9)
- # boot-dev (5)
- # cider (26)
- # cljs-dev (1)
- # clojure (190)
- # clojure-finland (1)
- # clojure-italy (42)
- # clojure-nl (20)
- # clojure-russia (3)
- # clojure-sanfrancisco (1)
- # clojure-serbia (1)
- # clojure-spec (50)
- # clojure-uk (16)
- # clojurescript (62)
- # core-async (4)
- # cryogen (1)
- # cursive (6)
- # datascript (1)
- # datomic (36)
- # duct (6)
- # editors (6)
- # emacs (14)
- # graphql (3)
- # leiningen (30)
- # off-topic (21)
- # om (7)
- # parinfer (13)
- # portkey (56)
- # re-frame (2)
- # reagent (2)
- # shadow-cljs (58)
- # vim (1)
- # yada (3)
I'm making it a goal to stop going down the path of making generalized tools before I specifically need one
I've definitely been there
That looks like a job for macros
not sure if there's an existing one though
I'm not even sure how I would implement a macro like this. My lack of Java knowledge is showing. It's essentially a pure version of try
.
Why not just use try?
yeah, seems like you can even make foo as a macro that wraps try
Gotcha here: the value in the finally clause is always run, whether you throw or not, and never returned
Just use (try ~@body true (catch Exception _ false))
(defmacro try-result [body]
(try ~body
(catch Exception e
false)
(finally
true)))
(= (try-result (/ 1 0)) false)
might require some edge cases, but the base case works
Does Slack not support Clojure highlighting?
does that make sense @sophiago?
the problem is you want to delay evaluation, other than a macro, which doesn't require anything funky like eval and escaping list forms, there isn't a straightforward way to do that
that is, delay evaluation of whatever may cause the exception
Yup, makes total sense now. I did actually try wrapping it in a delay
before using try
so that was at least the direction I was thinking
I think delay you'd eventually have to run it through the try catch pattern
once you force
(let [divide-by-zero (delay (/ 1 0))]
(try (force divide-by-zero)
(catch ArithmeticException e
false)
(finally true)))
the problem with this is you won't be able to make a function that takes the expression as an argument
cleanly that is
(defn try-result-fn [expr-literal]
(let [divide-by-zero (delay (eval expr-literal))]
(try (force divide-by-zero)
(catch ArithmeticException e
false)
(finally true))))
(try-result-fn `(/ 1 0))
maybe that's not terrible, but not sure how evil eval is in the clojure community π
I have to run to a meeting, but your macro is always hitting the catch
block in my use cases. I think due to the type of exception: (try? (apply concat [[1 2 3]]))
=> false
my mistake, I misused finally as an "else" case. Rookie move π
this seems to work, I'm sadly lost when doing macros and using stuff like ~'
I guess I'm not understanding what is ultimately trying to be accomplished that a standard try-catch-finally block can't accomplish
I'd advise not do simple abstractions of something already simple like try-catch, it hides a lot if you make it too generic
Definitely goes against Clojure philosophy
I'm not seeing the point of that
If it fails it will catch. If it didn't catch it didn't fail
Im sure someone else can think of a better use, but my logic for parsing a message from kafka was basically just to convert it from json to a map
so my function to parse the string from kafka was (fn [msg] (attempt (cheshire/parse-string msg)))
It might be just self justification, but as long as something is a pure function and doesn't do something convoluted I think its pretty much in the safe zone for not violating the clojure philosophy.
@emccue I think it's reasonable to encapsulate exceptions sometimes, and that seems like a reasonable use case, but the unwrapping and rewrapping of the success/failure values can be more trouble than it's worth, if it pollutes upstream code. Definitely a case of evaluating the trade offs carefully.
Wow, my meeting went for over two hours so I'm glad other found the discussion I provoked useful π
For perpetuity: I never use try/catch, but I very frequently have a pattern where an argument to recur
will fail right before the predicate triggers the base case and have never come up with a uniform way to handle that.
I usually can get by calling the predicate on next
of whatever coll I'm processing, but that usually ends up with unnecessary let
bindings to prevent code duplication (even though HotSpot will often inline them) and then occasionally I'm faced with situations like what prompted this where there's no analog to (empty? (next ..))
wrote this little article-like introduction to Clojure for my fellow FE team members at my workplace https://github.com/geganizharadzeatamido/clojure-wiki-for-amido/blob/master/README.md
Thank you for sharing! I was in the same position as you - hardcore JS developer (front and back) building large scale applications. Why I switched is one of those things I am still exploring. This is why I thought this writeup was a good one. I do have a few comments which I hope are seen as a way to produce a more robust argument.
RE: Ranting section Ecosystem + Tooling
I don't feel this is a valid point. Both clj/s and js have challenges regarding ecosystem and tooling. However, at the least, if nothing else, JS has a greater amount of documentation which would let it win in this category. I do believe CLJ/S can have better tooling, but its not there yet. Not compared to JS. Side Note: this includes REPL and all the other nice things experienced developers talk about.
RE: Core Library
This is where CLJ/S shines the most in comparison to JS. The language is a better design and the core libaries...well, it takes 3 separate libraries in JS just to make something akin to spec
and the these libraries are still not going to work together very well, if at all. So good point!
RE: lein, boot and deps
lein and boot are confusing. Sorry, I will take node scripts over these any day. Which is likely why I am moving toward clj
and deps.edn
. Perhaps mention these?
RE: REPL + IDE's
These are awesome, but difficult to grok for new developers. Especially given the JS feedback loop is so fast. This is NOT me saying one is better than the other, just that im not sure it would sway one way or another.
RE: Clojure outside of web dev
So can JS. Maybe provide an example of a place that JVM can go that JS cannot? Or maybe I misunderstood this point?
RE: namespaces
I would def talk about these more. Its another nice thing about clojure v. js that I really didn't notice until I was a few months in.
Hey, thanks for taking time for this reply! π
The most frustrating in JS tooling for me has always been getting to the point where Iβm ready to work on my project. At my workplace, our basic starting kit is react + redux + jest + enzyme
. And then we add things on top, depending on a project obviously.
As project grows, there are so many tiny modules I need to add to make things work. Iβll give you an example.
So some projects require us to use styled-components
, some require sass
or less
.
Now if I go down the styled-components
route, then I canβt test my components anymore, unless I add jest-styled-components
package.
Yes, itβs just a one liner to install it and probably another example would be more valid where Iβm also required to create a config file for it to work, but I think youβll get my point.
In Cljs
Iβve never had this issue. Things just work, because thereβs no magic
being added behind the scenes. Maybe the projects Iβve worked on in Clojure
havenβt been waaaay too complex, but Iβve built quite a few of them. And I felt that I was only ever adding things to my dependencies that I was actually using in my application, like a router, some middleware and etc.
Now Iβve had situations in JS, where I upgraded a certain babel-blabla
package, just because I needed some functionality from the newer version, and then suddenly another babel-blabla
stopped working. Then I had to go through issues on Github
and basically spend quite some time investigating this little detail that has nothing to do with my application. Itβs just a part of a build process and itβs not something Iβm importing in my application so to say.
Whereas in ClojureScript
, Iβve never had such problem using figwheel
.
Iβm not sure about the REPL + IDE
part you mentioned. I donβt quite understand what you meant there. But if itβs the speed youβre talking about, of showing changes in the browser, I find figwheel
to be faster than webpack
. The only complaint I would have in terms of IDEs
is that I had to learn Spacemacs
purely for Clojure
. I know I couldβve chosen something else out there, but being a vim
user seeing what Spacemacs
had to offer, I couldnβt find a good alternative out there. Iβm sure it would be easier for people using VS Code
And finally, by Clojure outside of web dev
, I actually wanted to say something like βDonβt think that youβre limited to just web dev, you can use it for anythingβ. It wasnβt a comparison to JS. The main reason why I wrote that was because this post is for my team members and previously I was showcasing Elm
to them, which is purely for Front End
. So I wanted to imply that thereβs no limit like that in Clojure
.
No problem. Conversations like this are important!
Your tooling system reflects my own. However, you gave an example of styled-components
and needing another library to regain the ability to test. The counter I have to this is two fold.
1. while CLJS can make use of the JS ecosystem, it is non-trivial to get the same level of functionality working as fluidly in CLJS- ultimately, more than 1 line of code to get things working as expected and this is way beyond an early or beginner CLJS developer....because documentation is not as abundant as JS land.
2. The libraries are not always the most current
Here is an example of what I mean. Only recently did I see a solid write up about using JSDOM as the test environment. But to do this, and really understand what this author was doing and why, you have to be no less than an experienced intermediate JS developer and it is much more than adding 1 line of code to get it working. Do you have to be intermediate to do it? No, but there are some nice extras which you will miss out on and will bite you if not configured up front. Could you use an existing solution? Point being, they both bring their challenges regarding tooling and library setup. This is seen when the CLJS application becomes large enough.
You mention dependencies you are using, breaking your app. This is a problem in software in general. Rich Hickey actually just spoke about this in the new Joy Clark podcast. It happens in CLJ/S land too. It also not fair to compare figwheel
to babel...they do different things and work for different goals. But I do appreciate that you may not have been comparing 1:1.
The part about REPL is just to say that one thought against the need for REPL is when in a language like JS or GO you have rapid enough feedback cycles you really don't miss the REPL. Is this a valid point? Maybe not, but as someone who took advantage of this rapid feedback without using the REPL, and than moving to the REPL, its a task on its own to train yourself, because I had to do this, to use it.
Figwheel being faster than webpack...they are both really fast π Not sure what we gain from this point.
Yeah, IDEs are tough. I struggled with it for a while also.
True point about CLJ/S outside of web dev.
I think that REPL driven development or to be more specific, the fact that you can evaluate the code straight inside your editor, makes a huge impact on time you spend working on something. I only look at my code in browser when there are styling changes to be done. I tend to spend good y
* good few minutes in my editor before I check what I've written, in browser. I have even spent more than an hour and afterwards, when testing things in browser, it all just worked. Also, the fact that I can add / overwrite functionality or change state of my application from REPL, make it possible for me to do things like skipping a few pages of a multi page form that requires some data from the server. It feels like I can mock stuff LIVE as I'm testing things in my browser
I found this sort of development way more powerful than what devtools offer in JS ecosystem
Agreed, but it takes some time and learning to switch over your workflow.
@bravilogy the "Clojure for Java Programmers" videos could be useful: https://www.youtube.com/watch?v=P76Vbsk_3J0
@bravilogy:
> Configuring and scaffolding your application can be a pain sometimes. A typical package.json
file includes plugins that have nothing to do with the application I'm trying to build. There's usually at least 6 lines starting with babel-
and another 6 - 7 lines of eslint-
, not to mention enzyme-
or jest-
, in a typical package.json
. And then there's a config file for jest
, webpack
, babel
, polyfill
, shim
and etc. So I end up creating these random config files to actually get to the point where I can start working on my application. And I'm not even going to mention the version incompatibilities in some cases where one plugin doesn't like another.
As much as I like Clojure(Script), the above paragraph perfectly describes how I feel about my project.clj
files for any non-trivial Clojure project I write.
@bravilogy two pedantic notes: it's JVM bytecode and "code can be compiled at runtime" is an oxymoron
It's also just difficult to make statements like that about all Lisp dialects ever. Your intention behind that one isn't true for most.
The only reason I mention things like this are because I think the main turnoff to functional languages is the idea that they're purposefully obfuscated, when in reality misunderstandings just get passed on (not saying I haven't been guilty of that myself). You can draw an easy comparison with pointers: a shocking number of professional developers don't understand them, but few would claim they're some ivory tower academic concept. It's just a field that takes learning and the job market encourages shortcuts.
@bravilogy I do think those are very important things to mention. You can just substitute "JVM bytecode" for the first part. The second requires a bit more complicated explanation so I suppose I would rephrase it focusing on the benefits. Like basically describe what a REPL is and how compilation happens there too, but I would even find phrasing to ease them into the idea of working with a REPL.
I'm guessing you can draw on experience with something similar outside of Java. Python maybe? And then highlight the fact that code is actually compiled there and that should blow some minds.
I just sort of mention it. And I think itβd be a good idea to perhaps show a few screenshots as well
Reminds me of this: https://danielcompton.net/2016/07/11/people-are-worried-about-types π
Is it a good practice to include examples in docstrings for functions ? I see it's not used in Clojure core but I am not sure if there is a standard place to include example code for a function.
it's not a rare sight but bear in mind unit tests also serve as examples
Yes, good point. But most of the users just use the jar and docstrings for docs and hence thought adding examples there will give them quick access.
Hello guys
is this very bad practice ?
@abdullahibra please use preformat back-ticks. Your code is being bolded where you have an asterisk *
i'm in situation which need to make a recursion and save some state while make this recursion to the end.
so i thought i can use an atom for keeping this state while doing recursion, maybe i can use loop/recur
you likely want to use swap! instead, but you might want not to use an atom and use loop/recur
that's good
thanks π
so this is a bad practice right?
guys if i have a tree with multiple branches and want to find subtree of node A, how can i do this using loop recur
that's my current code
anybody there/
@abdullahibra not an expert on this, but Iβd use zippers for traversing a tree like that instead of loop recur http://josf.info/blog/2014/03/21/getting-acquainted-with-clojure-zippers/
@abdullahibra first thing to try would be tree-seq
@abdullahibra that's easy with specter:
(def CHILDREN (path (srange-dynamic (fn [_] 1) count) ALL sequential?))
(def NODES
(recursive-path [] p
(continue-then-stay
[CHILDREN p]
)))
(select [NODES #(= 'A (first %))]
'(R (H (h 1) (h2)) (M (N (A (a 11)) (B (b 5))))))
;; => [(A (a 11))]
can re-use the exact same code for transformation:
(setval [NODES #(= 'A (first %)) (before-index 1)]
'(Z 0) '(R (H (h 1) (h2)) (M (N (A (a 11)) (B (b 5))))))
;; => (R (H (h 1) (h2)) (M (N (A (Z 0) (a 11)) (B (b 5)))))
and it will perform much faster than zippers
my recursive solution is ugly ?
the output has a bunch of spurious nils so it's not a solution
you are right π
specter is rescue here
Recursive solutions are often easier to read/understand. The problem with recursive solutions is that you incur stack depth correlated to tree depth. Tree depth may be unbounded in your data, but stack depth is quite finite (which eventually means you break with a stackoverflow error).
I have a recursive problem which actually seems very hard to do in a declarative/FP way. I'm wondering if there are any tricks for this kind of forward-backward recursion pattern. x_n is defined in terms of x_n+1 and y_n+1. y_n+1 is defined in terms of y_n. Every time I want to get x_n from x_n+1 I need to do the forward recursion from y_1 up to y_n+1. The imperative approach is to do the forward recursion and store it in a list, getting y_1 up to y_N. This list of y's then gets fed into the backward recursion which gets x_n from x_n+1 so get a list of x_1 up to x_N. Forming the initial list first seems very imperative. Is there a more functional declarative way?
Maybe you can use https://clojuredocs.org/clojure.core/declare it helped me getting a 'circular' dependency work.
wait, how can you derive x_n from x_n+1 ? isn't that backwards?
is there a cleaner way to handle this?
(every? (fn [k v] (empty? v)) (select-keys a [:name :type :value]))
or put another way, is it possible to get the val of a key (not as a coll with vals
) without destructuring or knowing the key ahaid of time?
alternatively (every? empty? ((juxt :name :type :value) a))
but the map version reads nicer to me
@michaellindon Normal recursive function definition could be used here, and as long as they are pure functions, you can gain a lot of efficiency in some cases by memoizing the recursive function.
For example, this is a horribly inefficient way to write a function to calculate the n-th Fibonacci number, which takes exponential time if you do not memoize it: (defn fib [n] (if (< n 2) 1 (+ (fib (- n 1) (- n 2))))
But if you memoize it, it takes linear time in n.
The core.memoize
library can help you in creating a memoized version of a function: https://github.com/clojure/core.memoize
Memoization only makes things faster if the function would be called multiple times with the same paramters, which is definitely the case for the slow-without-memoization version of fib
I show above. In the function you want to calculate, it might be the case that x and y would only be called once for each value of n anyway, in which case memoization would not help speed things up.
I have seen code in the wild that puts a function's return type hint before the name of the function (right after defn) and also right after the fn name, right before the arg list. Which is correct or are they the same? @alexmiller had suggested the latter a couple weeks ago, but the source for core functions often shows the former.
@ajs it's different depending on the situation. It's one way for deftype (I think on the arg list) and the other for defns
We were discussing normal function definitions so perhaps it's confusing for everyone as he suggested the contrary
Hrm, I may have that backwards
But I know defn and deftype are opposite
He referred to the difference between type hinting the symbol for the function's name, vs type hinting the return value. But I still see the former in core functions.
yes, from the deftype docs:
Method definitions take the form:
(methodname [args*] body)
The argument and return types can be hinted on the arg and
methodname symbols. If not supplied, they will be inferred, so type
hints should be reserved for disambiguation.
Two examples: https://stackoverflow.com/questions/6484899/type-hinting-return-value-with-or-tag-meta and https://github.com/clojure/clojurescript/blob/r1.10.238-25-g9c1c727/src/main/cljs/cljs/core.cljs#L4201-L4204
That's clojurescript, it might be different there
ROFL, then there's this gem: https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj#L684
Is it possible for a macro to include a type hint in its emitted syntax? It's hard to know since hints are stripped when things print to repl, like with macroexpand
if you want to type-hint the return type, you should put before the arg vector, the end.
yes, some core stuff does otherwise, thatβs (mostly) historical
@ajs yes, macros can return type hinted code, but doing so requires some care
(source defmethod)
is an example
Found this too: https://stackoverflow.com/questions/11919602/generating-clojure-code-with-type-hints
... I'm working with midje a lot lately, and one of the things that I find frustrating is that we can't assoc to Metaconstants. I was wondering if anyone could enlighten me about the rationale
@acripps Pretty simple, Midje is not Clojure, it's a testing DSL, and as such behaves differently than Clojure in many ways
But perhaps some examples would explain what's happening? "can't assoc into" is a bit vague, what's the error you're getting?
@tbaldridge I got that π ... I've taken a look at the source and Metaconstant implements clojure.lang.Associative, but it explicitly throws on (assoc ...) ... I would personally find assoc on Metaconstants handy (more explicit than just passing in an empty map, or a pre-populated map for unit-testing functions). I am assuming that since the implementation explicitly prohibits this, there is a rationale, I just want to understand and find out if there's a more idiomatic way to unit test where a value that I want to pass in as a metaconstant would be assoc-d
yeah, looking at it now, it also throws on some cases of equality
It's one of the problems I have with Midje, the docs explain how to use Metaconstants, and I can read the code, but I don't know the connection between the two. Here's examples, and here's the implementation. Great, what's the rationale?
exactly. I was thinking about fixing it myself, but when I looked at the code it looked to be done on purpose ... which is fine, but trying to track down the "why" is ... problematic.
From the code it looks like they are read-only. But I'm not sure why they didn't implement only read-only interfaces (ILookup vs Associative)
maybe that " (What would the name of the resulting metaconstant be?)" is the rationale ...
I guess I'm going to have to sit and ponder this for a while ... try to figure out what the implications would be if there was a way to "extend" and/or "modify" a metaconstant
So they appear to the a form of nominal programming. ...foo... == ...foo... but ...foo... != ...bar... unless declared to be
yeah ... what I really want here is to test that when I pass in a map (and I really don't care what it is, provided it contains key/value pairs that are required to operate on it), and check that the returned value contains the correct computed key/value pairs ... so "=contains=>" and (contains ...) are perfect, but the metaconstants themselves don't fully suit my needs here because I can't assoc onto them. I wonder if Mr. Marick would tell me to just use maps, or ... what?
Well, my advice would be to use spec and clojure.test
you can create a spec that says a map has to have certain keys, and what data types the values should be
and test.check will create data for you
at this point we're already invested in using midje ... we evaluated spec, clojure.test, and midje, and to those of us uninitiated the latter seemed like the best choice at the time.
... but I do appreciate the suggestion ... I'll take another look at spec next time I start on a personal project
I'm a big fan of JCuda: 1. I write some *.cu files 2. I call launch-kernel from Clojure, passing it float-arrays / grid/block sizes 3. Hypothetically, even if the Cuda code creashes, the JVM is still fine. Is there something like JCuda, but minus the GPU. So it would be like this: 1. I write some *.c files 2. I call launch-c-kernel from Clojure, passing it float-arryas / ... 3. Said C code runs IN A DIFFERENT PROCESS 4. Even i said C code crashes, my Clojure/JVM is still fine. 5. Communication between Clojure/C is via copying int/float-arrays (willing to pay this overhead in exchange for C-code crashes not crashing JVM).
@qqq, that's fairly simple to do, just need to fire up a c compiler and mmap some memory
You can use the JDK ProcessBuilder, or the JRuby guys (Charles Nutter in particular) have some ffi stuff for fork/exec, or there are probably some other options.
with ProcessBuilder you can create stdin/out pipes
if the amount of data you pass between is small, that might be ok
http://blog.headius.com/2009/05/fork-and-exec-on-jvm-jruby-to-rescue.html
prob not the newest take on that but the right ballpark
I need to do this at 60fps (iClojure is passing some data to C, C caculates some new data, and Clojure uploads it back to GPU.)
I should probably go for a long running C process with network i/o instead of forking a new C prog 60 times a second?
No, at 60fps you need mmap or a interprocess queue
but also look at https://github.com/real-logic/Aeron/wiki which is a high-speed 0 copy messaging system
yeah thatβs a whole different ball of wax so forget everything I said :)
but also ask, why? If you care that much about performance, you'll lose it in the communication unless you're super careful
@alexmiller: sorry for dripping requirements bit by bit instead of stating everything upfront
and you haven't mentioned latency
Is 'C' using the data passed to it to calculate the new data? Then that's uploaded back to the GPU? Maybe the GPU could just manipulate the data itself, directly?
60fps with 100 frames of queuing is a lot different than real time π
Yeah cuda can mmap data from local memory (or the disk, which is mind blowing),
Let me take a giant step back. I'm building a clj/cljs app that uses OpenGL/WebGL. My currentproblem with CLJS is that calculating the data for the vertex buffer objects is causing lag. On the CLJS side, I intend to have C code (running in Webassembly) to do the calculations. On the CLJ cide -- I could do the code in Cuda, but I'd prefer for both sides to share code. One solution around this mess is to do GPGPU, but vertex-transform-feedback requires WebGL2, and iPads only support webGL1, which means I can at most use "render to texture" if I want to do these computations on the GPU. Thus, I'm currently leaning towards doing these cals in C / webassembly.
I'd look at the calculations code. This is a lot of work to get around something that shouldn't be a bottleneck. Remember, Minecraft was written in Java, runs on almost everything, and consistently renders about 512k cubes at 60fps.
And doesn't use GPU shaders
I suspect Minecraft did not have code like this: (defn vec+ [lhs rhs] {:x (+ (:x lhs) (:x rhs)) :y (+ (:y lhs) (:y rhs))})
Also, I believe most minecraft cubes are static. I'm not familiar with scenes where, say, 1000 cubes are having their locations being modified independently (one uniform for all 1000 doesn't count).
Lastly, mine is a "text editor" of sorts, and people are much more tolerant of lag in fps than in wysiwyg editors.
that's probably your issue, to be honest, over use of GCs can kill performance. But rewriting that in JS/Java isn't a bad idea
Or even just switching to deftype vs maps helps a lot (I know that from personal experience)
We're getting a bit OT now, but handling 1000 objects each with their own transforms is exactly what GPUs are great for, can't you perform the transforms on the buffers during rendering, on the GPU instead of on the CPU?