This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2015-12-08
Channels
- # admin-announcements (3)
- # beginners (284)
- # boot (179)
- # cider (15)
- # cljs-dev (6)
- # cljsrn (95)
- # clojure (105)
- # clojure-austria (4)
- # clojure-berlin (9)
- # clojure-germany (4)
- # clojure-japan (3)
- # clojure-russia (65)
- # clojurebridge (1)
- # clojurescript (109)
- # code-reviews (16)
- # cursive (27)
- # datavis (19)
- # datomic (68)
- # devcards (7)
- # funcool (31)
- # jobs (1)
- # ldnclj (2)
- # lein-figwheel (3)
- # leiningen (4)
- # off-topic (419)
- # om (255)
- # parinfer (39)
- # portland-or (2)
- # re-frame (28)
- # reagent (14)
- # slack-help (12)
- # spacemacs (1)
@borkdude interesting. I suspect most of the 'issues' they mention apply equally to Clojure?
@agile_geek: Coda's criticisms mostly ring true with my experiences back in the Scala 2.7 / 2.8 / 2.9 days but we chose to go to Clojure instead. We have not regretted that decision and we have not found similar problems with Clojure (we did not have performance problems with either language). /cc @borkdude
@seancorfield: interesting. Yammer's comments about not finding Scala dev's easily would apply x5 for Clojure and I think this is the largest hint about why they backed out Scala. They are trying to commoditise development and make developers more fungible.
getting up to speed writing "idiomatic" (whatever that means) scala vs clojure doesn't require the same amount of time/effort either
@mpenet: do you mean idiomatic Scala is faster to get up to speed on (assuming you're hiring Java dev's)?
It looks to me like their issues stem from not understanding how to best use the language for their use case as it's hard to get experienced dev's. It's something that worries me about Clojure too as both languages are young and we haven't learned all the patterns and pitfalls yet.
In my experience finding clojure devs or having a decent dev get up to speed with clojure isnt that difficult
@mpenet: I would say there's less to learn to write idiomatic Clojure. I must not be a decent developer then as 19 years of pure OO and Java meant I found the learning curve very steep!
@agile_geek: I would expect the same things with clojure, maybe even worse performance in some cases. don't know
Yes, it's also very easy to learn from other's people code, given how few building blocks there are. Back then I got a team of Java/C devs in a large company writing "ok" clj code in a couple of weeks, and in 2 months or so they would write quality clj code. Mostly through code reviews and using nicely written libs as examples
@mpenet: I think you've proved my points: 1. I am not a good developer 😉 2. You need mentoring and an experienced developer to code review.
@agile_geek: I've heard from a Scala guy who rewrote a for loop to a while loop with vars, because in his system, too many objects were moved to old generation and then requiring too much heap memory
@agile_geek: it was a system that processed many messages a second running on AWS
agile_geek: just read lots of code, reviews are nice but you can get there by yourself too
about perf we also have options in extreme cases, either writing in java the slow bits or JNI when it makes sense (rarely).
@mpenet: although I don't do Clojure for the 'day job' I've been using it for side projects for 3 years and pretty much having to learn it on my own with a little help from Clojure Dojo's but it's been painful...but then I'm old!
I posted this in #C053PTJE6 but maybe also relevant to our discussion here: I was wondering why this Clojure program takes ages to manipulate a mutable array, while a comparable Scala program only takes 2 seconds on my Macbook Air. Clojure: https://gist.github.com/borkdude/8bf5780efa371455e83d Scala: https://gist.github.com/borkdude/62094893df250225c9bc
@borkdude: Hmm, that's interesting. If you want you can compare with mine - https://gitlab.com/jaen/advent-of-code/blob/master/6/lights.clj - but I've used core.matrix.
there's something else not right either. When I do C-c C-k in Emacs, the code takes too long to evaluate. When I switch namespace, it takes a few seconds. It might be a problem with Cider, etc.
maybe I know what it is: kibit etc are trying to evaluate my code too and are creating this huge array every time.
Yeah, I've also converted things to use loop
and it didn't seem to have helped for some reason
@dm3: my program now looks like this: http://stackoverflow.com/questions/34153369/why-is-this-clojure-program-working-on-a-mutable-array-so-slow
(defn process-line [command ^ints coords] ; left top right bottom
(let [left (aget coords 0)
top (aget coords 1)
right (aget coords 2)
bottom (aget coords 3)]
(time
(loop [i left]
(when (<= i right)
(loop [j top]
(when (<= j bottom)
(case command
:turn-off (aset ^longs grid i j -1)
:turn-on (aset ^longs grid i j 1)
:toggle (aset ^longs grid i j (* -1 (aget grid i j))))
(recur (unchecked-inc j))))
(recur (unchecked-inc i)))))))
"Elapsed time: 19.703443 msecs"
"Elapsed time: 251.43566 msecs"
"Elapsed time: 483.458811 msecs"
"Elapsed time: 2044.198587 msecs"
"Elapsed time: 1014.591659 msecs"
"Elapsed time: 49.72036 msecs"
"Elapsed time: 558.516576 msecs"
"Elapsed time: 522.276886 msecs"
"Elapsed time: 118.047631 msecs"
"Elapsed time: 37.807507 msecs"
"Elapsed time: 149.030111 msecs"
"Elapsed time: 2560.647433 msecs"
"Elapsed time: 609.248053 msecs"
"Elapsed time: 301.237468 msecs"
"Elapsed time: 94.728694 msecs"
"Elapsed time: 1544.405323 msecs"
"Elapsed time: 489.866394 msecs"
"Elapsed time: 3104.153334 msecs"
"Elapsed time: 100.474167 msecs"
"Elapsed time: 700.43767 msecs"
"Elapsed time: 0.467456 msecs"
"Elapsed time: 5.8063 msecs"
"Elapsed time: 135.177811 msecs"
"Elapsed time: 893.965435 msecs"
"Elapsed time: 431.381867 msecs"
"Elapsed time: 132.645449 msecs"
"Elapsed time: 611.209867 msecs"
"Elapsed time: 2.890451 msecs"
"Elapsed time: 2467.134139 msecs"
"Elapsed time: 1324.462145 msecs"
"Elapsed time: 266.358281 msecs"
"Elapsed time: 1018.531767 msecs"
"Elapsed time: 227.757252 msecs"
"Elapsed time: 70.854271 msecs"
"Elapsed time: 642.159927 msecs"
(defn make-grid []
(let [^"[[J" grid (make-array Long/TYPE grid-size grid-size)]
(loop [i 0]
(loop [j 0]
(let [^"[J" d1 (aget grid i)]
(aset d1 j -1))
(when (< (inc j) grid-size)
(recur (inc j))))
(when (< (inc i) grid-size)
(recur (inc i))))
grid))
(defn process-line [command ^ints coords] ; left top right bottom
(let [left (aget coords 0)
top (aget coords 1)
right (aget coords 2)
bottom (aget coords 3)]
(loop [i left]
(when (<= i right)
(loop [j top]
(when (<= j bottom)
(case command
:turn-off (aset ^longs (aget ^"[[J" grid i) j -1)
:turn-on (aset ^longs (aget ^"[[J" grid i) j 1)
:toggle (aset ^longs (aget ^"[[J" grid i) j (* -1 (aget ^longs (aget ^"[[J" grid i) j))))
(recur (unchecked-inc j))))
(recur (unchecked-inc i))))))
The question is then why aset
with multiple indices is written in a way that does not optimise.
I guess you'll be able to find a patch providing optimized inlined versions for more arities somewhere in Clojure JIRA
That ticket has 0 votes - voting helps us determine priority
and maybe I shouldn't have needed them. I saw a solution using regular vectors, but I wonder how that would have performed
Certainly faster than the version with reflection, but probably noticeably slower than core.matrix. I think it strikes nice balance between performance and readability
No, that's a conjecture. But since you say you've seen that I would certainly try it for comparison if you'd link it.
╭─jaen@himitsu ~/projects/adventofcode/6 ‹2.2.0› ‹master*›
╰─$ ./lights.clj
# of lights lit: 569999
"Elapsed time: 6345.035897 msecs"
Total brightness: 17836115
"Elapsed time: 6327.370421 msecs"
╭─jaen@himitsu ~/projects/adventofcode/6 ‹2.2.0› ‹master*›
╰─$ ./lights.clj
LIGHTS ON: 569999
"Elapsed time: 6010.859778 msecs"
TOTAL BRIGHTNESS: 1.7836115E7
"Elapsed time: 15314.694691 msecs"
I should've upgraded when I bought this Macbook Air, totally sucks for this kind of problem in Clojure 😉
Second part in my code is probably this slow, because I multiply the whole 1000x1000 grid element-wise; I couldn't find a way to multiply only a subset of a matrix with core.matrix.
15 seconds on my Pro, still not that good, but better. What kind of hardware do you have?
I guess twice the clock (and possibly newer generation) could account for that difference
maybe using a single vector would have been viable too and using a transient way of updating it
good. using a transient vector 11 seconds on my macbook air (vs 86 seconds persistent vector)
@agile_geek: if you're really steeped in OOP then FP can be hard / painful to learn. Of all the folks I've watched learning Clojure those with years of Java had the most trouble.
😄 that's been my experience.
As for old, I'm 53 and had been doing OOP for 20 years before learning Clojure (a decade of C++, a decade of Java, roughly), but before all that OOP I'd done some FP way back in the 80's which really helped me.
My early Clojure was far from idiomatic 😢
@seancorfield: you have 3 years on me. I had no FP in the 80's just procedural code (Fortran, COBOL, PL-1, Basic, etc.)
I taught myself OOP and Java..
and FP and Clojure now but learning a new paradigm 20 years on is hard.
I had to teach myself OOP too as I'd been raised on procedural stuff (like you, COBOL, FORTRAN, PL/1 etc).
A kindred spirit!
But I'd encountered APL during college (in my industrial placement year) and then Lisp in my final year and then SASL, ML, and Miranda in my research years before I became a C and COBOL dev 😃
Forgetting all the bad stuff you learn with Java really can be tough (and I truly believe Java is bad for you - worse than BASIC ever was).
of course you can do anything, monads, lenses, etc, in Clojure, but with typical I mean what you'll see in an average program
I don't have much programming experience (couple-ish years) but I wouldn't say learning OOP as a paradign is necessarily hard, it's just "stuff with state doing things". Using OOP effectively though, that's a different beast.
For example when I tried to learn about event sourcing from the OO viewpoint I couldn't make head or tails out of it.
So I don't think OOP is hard in and of itself, but makes other things harder than they necessarily are.
OOP is a fine tool, it’s just not the right tool for every job. I like building stateful objects to encapsulate stateful things, even in clojure; e.g. a persistent http client. I don’t miss writing custom objects for every domain data type.
Getting clojure and the FP concepts behind it was far easier than getting OOP. Considering the fact I have been doing OOP for almost 10 years and still feel like a rat in a labyrinth in it. Especially in a large code base. In the books, OOP is dead easy. Pizzathing PizzaThingProvider PizzaDto, it's all cool, but mix like several thousand of them and try to remember all the mistakes or shortcuts you took in the last 5 years^^
Yeah, that's exactly what I mean. OOP itself it's easy, usage of OOP not necessarily so. Thinking in terms of data transforms is usually easier, even in the imperative world (that PS3 presentation where data-driven code was ~5x faster than pure OOP anyone?).
@borkdude: does that mean the Clojure version is faster than the Scala version?
@seancorfield: about the same now
@seancorfield: the solution comes down to manipulating a mutable array. Faster than Java/Scala we can't get on the JVM I think
@seancorfield: of course this could be implemted by manipulating bits, that would be even faster, but we might as well go to assembly then.
I imagine #(toggle-grid! grid %1 %2)
should have been #(update-grid! grid %1 %2 toggle)
, yes?
its from http://adventofcode.com/day/6 i’m not sure how much code existed
@borkdude: still slightly slower than my version (probably because you have the left/top/bottom/right exploded like that) but ~500-600 msecs
If I typehint an arg it complains I can't typehint something with a primitive initializer
Hah, there was a conflicting type hint further in the code, that was a bit of a confusing error message.
@borkdude: with some further changes I've gotten it down to ~370msecs. Looks ugly as hell, but is fast ; d
@jaen: in your last loop based version the case is still inside the loop, you should see a speedup by moving the case out of the loop, because clojure is not smart enough to optimize a constant switch like that
yeah, I made the same suggestion on stackoverflow
@jaen: leiningen has some settings set that slow down execution. You might want to google that, AFAIK you can turn them off too
Setting up project with lein-cljsbuild
to have a console repl, hot reloading, mutliple builds and other such niceties was a major pain
You can take a look at https://github.com/martinklepsch/tenzing, https://github.com/Deraen/saapas or this thing of mine - https://gitlab.com/jaen/clj-cljs-presentation/tree/master - if you want to see how a boot project set up for Clojurescript development looks.
My project has a few niceties over two former projects in that it uses boot-middleman (slightly modified to support specified output dir) for things like stylesheets or statis HTML, hot reloading with component (also slightly modified to work with regex exclusions) and a dev handler that works well with F5'ing an SPA (redirects any URL to the index.html).
@jaen: that's what I made closp for. I was trying boot back then, but it has 3 or 4 defects that make it unusable on windows which keeps every windows user from using it
I am not saying leiningen is better than boot or so. It's just, it doesnt work on windows, which is a pity, I like the concept itself very much
@cab: I've just noticed it was a bit old; I've updated it right now. It even now has a fancy thing that reloads dependencies from resources/dependencies.edn
on the fly, a la vinyasa for lein. It doesn't always work (when transitive deps conflict for example) but most of time it's awesome to add a dep and have it Just Work™ with restarting the process. But this is a bit non standard, so like I said - learn from the first two projects I linked and you can compare that with my changes afterwards.
At least I know how it is annoying when a game I would want to play won't get a linux port ; d
I remember trying things like chestnut and such a year ago and having problem to get it to behave as well.
Like I say, maybe it's cool now and you don't have to use boot, I didn't have a reason to re-evaluate that choice thus far though.
@jaen Having used Linux for a long time I feel with you 😄 Based on chestnut and luminus basically means I adapted it to make everything work. Where everything is related to the delveopment workflow like hot code reloading and instant change pushes to the browser and uberjar and tests and integration tests and authentication and stuff that you might need some day. I totally agree, everything did not work out of the box back then, therefore, a template that makes it work. Was my only choice back then and probably still is today regarding boot.
Well, if you made everything work reliably then I imagine there's little reason to use boot, yeah.
Though I'm pretty curious why anyone would want to go back to Windows after using a better OS (be it MacOS or Linux).
Yay, OS-Wars. I have been a linux proponent for many years, convinced my mother, my sister, my room mates to use it, they all still do. However, when I got my newborn all of a sudden my spare time shrank ad infinitum and I felt what it takes to have to make stuff work all the time. Things like energy mode for laptops where you have to fiddle endlessly and still don't manage to use as few power as windows does. Or the last thing I remember was that I could not reliably switch between two sound devices on my desktop on gnome. Yea, all that stuff that tikes time and googling somehow just works for me on Windows. So I got converted, it's sad, but true.
@sveri: but why not Mac then. It combines the Just Works™ of Windows with not wanting to kill yourself when developing.
At least that's what I wanted to do when I had to develop on Windows and that's actually what made me switch to Linux - I couldn't for the life of me figure out how to install SFML.
@jaen: Easy, I don't want to pay more money for the same hardware. Whenever I buy a new laptop I look how the same mac would cost me and just instantly turn back. No reason to pay 3 - 600€ more just for the fun of it
@naomarik: it's probably more than that; you have a browser repl for sure, but you have other things as well, like hot code reloading, just repl doesn't provide.
Sometimes of course it bites me. Stuff like Haskell seems to work better on linux. Vagrant, Docker and some other things. I always wanted to try bazel and see if I could make it work for clojure, but it does not work on windows either.
@jaen yeah, i love the hot code loading, been using that now, but trying to get the full repl experience going... i'm assuming it's possible to use the same figwheel nrepl that is in context of the browser?
@sveri: I don't think a comparable quality ultrabook with Windows is any cheaper, but if you don't need such high build quality then I guess you can save hunderds of bucks by not going with a Mac for sure.
I would say it makes sense to buy Macbook if one saves 3-6 hours of tinkering with Windows, even if the hardware is more expensive than comparable Windows laptop
@naomarik: it's been a long time since I tried figwheel, but I think it's REPL connected to the browser so whatever you did there, was reflected in your app state in the browser.
@sveri: about docker - oh yeah, I've a university project now and I packed things up with docker, because apart from one girl everyone else is running Windows.
For your convenience: > You can take a look at https://github.com/martinklepsch/tenzing, https://github.com/Deraen/saapas or this thing of mine - https://gitlab.com/jaen/clj-cljs-presentation/tree/master - if you want to see how a boot project set up for Clojurescript development looks.
jaen i've essentially just started hacking on this today and chose luminus with its built in generators
everything kinda works well but i feel that the cljs repl should be on browser and not in its own environment
Also, I wholeheartedly suggest trying Cursive as your development enironment, it's awesome
I thought you've meant this, but your last comment made me think I misunderstood you ; d
i downloaded cursive today and seems like 9000 more select boxes and dropdowns to learn on top of the 90 new terms i've learned in the past few days
@cfleming: wheee. I'm trying to learn me some paredit, but it's a bit rough. Parinfer would be awesome.
What trips me up the most if I somehow end up with unbalanced params and it doesn't let me delete the ending paren wherever I want
@cab - check out https://github.com/dvcrn/proton
interesting @donmullen
@cfleming: one point bbatsov made for CIDER was that cause cursive is completely yours, what would happen if you decided to abandon the project?
I thought that was a bit of a straw man to be honest, if you look at the commit graphs it’s really only bbatsov and amalabarba working on CIDER right now.
@naomarik: as for debugging, I've seen CIDER is starting to get some debugging, but it's still considerably behind IntelliJ+Cursive and for some inexplicable reason my Clojure workflow hinges heavily on debuggability
Well, I’ve had discussions with both JetBrains and Cognitect, and JetBrains at least have access to the source.
just that this is time investment, learning these tools. so trying to make a well informed decision
And it would be able to inspect Clojurescript structures in debugger and eval Clojurescript code? D :
are there any compelling features that cursive has at the moment that CIDER doesn't? or vice versa
They have pros and cons - IntelliJ’s is based on JDI, so it’s heavily line based - CIDER’s is expression based
> crappy programmers think they dont need to debug @cab: well, yeah, I kind of agree with that, but for some reason people are surprised when I say I lean heavily on debugging in Clojure and say they don't ever have to do that, so maybe I'm the odd one out.
@cfleming: wow, if it'll be able to do that then that's awesome. Not being able to eval Clojurescript on a breakpoint is about the only thing missing in the Clojurescript debugging story.
@cfleming: would love to see them; even if i noticed there's a few killer things cursive does that cider cannot, i'd be very interested
@naomarik: yeah, when I first came to Clojure and learned there's no binding.pry
equivalent I was like "how you can guys live without debugging" and then after some time I've come across Cursive
@cfleming: much wow, such awesome. My eyes are totally sparkling. Though I imagine it'll be a while before that comes.
@naomarik: Based on conversations, the main feature Cursive has that CIDER doesn’t is stability - it pretty much always works with no fiddling.
@naomarik: See here for more opinions: https://cursiveclojure.com/archive/1643.html
@cfleming: yeah +1 on that. CIDER isn't always that stable and often requires a REPL to analyze stuff. It interferes with your process, where Cursive is independent.
@cab: I’ve had a new IP assigned to my Debian 7 VPS. I’ve updated /etc/network/interfaces to look like this:
auto lo eth1
iface lo inet loopback
# The primary network interface
allow-hotplug eth0
iface eth0 inet dhcp
iface eth1 inet static
address 149.210.165.105
netmask 255.255.255.0
gateway 149.210.165.1
Perhaps I need some special interface name for a virtual network interface of some kind?
does boot have no figwheel repl equivalent? where you can get access to entire app state in a repl?
For example I have this wrapped into a simple function - https://gitlab.com/jaen/clj-cljs-presentation/blob/master/build.boot#L88 -
Both boot reload and boot cljs repl have to be in the pipeline before boot cljs for it to work.
If the projects I linked are too complex for you right now this one is probably the simplest I've found - https://github.com/adzerk-oss/boot-cljs-example