Fork me on GitHub
#clojure
<
2018-02-03
>
matan11:02:16

so the other day I've been suggested here using emacs + cider for the best clojure workflow. learning emacs felt like travelling back several decades in time. it seems every IDE action from window manipulation to repl usage entails series of idiosyncratic keyboard combinations to be memorized and habituated. is it really worth it? what's your advice?

joelsanchez11:02:45

I use cursive (Intellij IDEA plugin for clojure), many other people do. it just works.

joelsanchez11:02:14

join #cursive if you have questions

gklijs11:02:53

I also enjoy cursive very much, a lot of stuff like git integration, and creating tasks works just like I'm used to in Java.

matan11:02:38

Really other than being free for commercial use, what's so phenomenal for clojure dev in emacs+cider?

joelsanchez12:02:37

personal taste, emacs love, total customization if you have years of free time

joelsanchez12:02:59

for example Cursive can't be customized in fundamental ways...just setting tweaking

gklijs12:02:15

And there is the atom/protorepl option which even some people coming from emacs prefer. Cursive can become a but sluggish at times.

andrewboltachev14:02:45

Should I use this: https://github.com/cognitect/transit-clj#usage if I want only to convert Clojure data structure like {:a 1 :b 2} to JSON-transit format?

blueberry17:02:27

@matan idea + cursive to emacs + cider is like guitar hero to the real guitar. i guess it is easier to start with.

fmnoise17:02:42

guitar hero has nothing to do with real guitar 😂

fmnoise17:02:44

@matan Before emacs I've used Atom + protorepl, then tried Cursive, but because I don't like IDEs, I've decided to try emacs, spent about a week to make its shortcuts the same as I've used previously and now I'm completely happy with it. Some points: - emacs language is lisp, kinda ugly but lisp anyway, personally I feel more pleasure writing it than coffeescript for Atom - emacs changes you into workflow to keyboard-centric operations and convenient shortcuts, everything is configurable - emacs + cider gives the most deep integration of clojure into editor I've ever seen - emacs is console application(despite has gui version), so you can do stuff without leaving your terminal, and you have all that context menus/autocomplete stuff right there, also emacs can be anything, from db client to chat app - magit gives the most convenient git workflow I've ever seen

fmnoise17:02:35

in few words: emacs + cider + magit is an IDE that doesn't look like IDE

matan19:02:51

@U4BEW7F61 thanks a lot, would you have your custom config which (resembles atom?) easily exportable to share?

fmnoise17:02:16

why I hate IDEA-style IDEs is their obtrusiveness and resources consumption, Atom/Sublime are great in that sense but don't give you so deep language integration feeling as emacs does, also neither Coffee nor Python are not languages which I'd like to use for editor customization, but elisp is closer to being that one. My ideal editor should be configured in clojure 😄

joelsanchez17:02:24

wouldn't say Atom's resource consumption is great

fmnoise19:02:31

comparing to RubyMine few years ago I saw terrific difference, and startup time is not good for IDEA even these days, but I agree that Atom is not the fastest editor

schmee18:02:22

if I write (let [[x y] [1 2]]), does Clojure allocate a vector for [x y] or does it unroll that into local variables at compile time?

noisesmith18:02:57

the best way to answer that is with no.disassemble

rauh18:02:02

@schmee It will allocate a vec

noisesmith18:02:40

it creates a vector - and a lot of other stuff too - even if you are returning nil

schmee18:02:58

seems like it

schmee18:02:12

the take-away here is to not use destructuring in tight loops

bronsa18:02:53

all the code you're seeing there is about creating [1 2]

bronsa18:02:25

ah nevermind I see now what you mean

bronsa18:02:28

had to scroll up :)

schmee18:02:42

user=> (macroexpand '(let [[x y] [1 2]]))
(let* [vec__30228 [1 2] x (clojure.core/nth vec__30228 0 nil) y (clojure.core/nth vec__30228 1 nil)])

bronsa18:02:25

but yeah clojure still destructures all your args even if you don't use them

schmee18:02:36

I guess you could write a variant of destructuring that expands to locals instead?

bronsa18:02:37

just the fact of destructuring them could side-effect

bronsa18:02:52

@schmee how would you do that

bronsa18:02:59

it'd only work if you were destructuring constants

bronsa18:02:03

which you never are in practice

schmee18:02:21

I don’t know, I’m just thinking out loud 🙂

bronsa18:02:28

yeah, it's just not possible

bronsa18:02:46

imagine (let [[x y] z])

bronsa18:02:15

now the code to bind x and y you'd write manually would be the same as the one destructure emits

bronsa18:02:52

so don't avoid destructure

bronsa18:02:57

it's very optimized already

schmee18:02:25

that makes sense 👍

noisesmith18:02:14

I've definitely seen cases where directly accessing the positional vals in a collection was computationally cheaper than destructuring

schmee18:02:44

how about keys destructuring? that seems to expands to get calls. does get give you maximum performance on records or do you need to use keywords for that?

bronsa18:02:26

@noisesmith only when you have rest arguments

bronsa18:02:41

because then it has to destructure as a seq rather than as an indexed

bronsa18:02:14

hence the switch from nth to nthnext

noisesmith18:02:24

@schmee keywords use get under the hood - you can also destructure with :strs or :syms

noisesmith18:02:00

(err, not the function get, but the method get uses iirc)

bronsa18:02:00

but even that is then optimized for working for both seqs and seqs of indexed colls

bronsa18:02:39

so it's not the fastest way to destructure e.g. a cons list, but it's not the slowest way to destructure a vector sequentially

schmee18:02:35

@noisesmith ahh, cause get calls into RT.valAt, which uses ILookup, and by the looks of macroexpanding a defrecord that seems to be about as fast as it can get 🙂

bronsa18:02:40

wasn't true before 1.9

schmee18:02:57

it’s really fun to dig into stuff like this 🙂

bronsa18:02:07

yeah Ilookup on a record will cache the keyword lookup into a direct field get

bronsa18:02:04

so when you're doing (:foo my-record) it's internally there's a cache doing essentially (if (= key :foo) (.-foo my-record) (get my-record :foo)

bronsa18:02:46

it's a bit more involved than that since there's two levels to the optimization but it's a good approximation

schmee18:02:08

where does that caching happen?

bronsa18:02:19

IKeywordLookup / ILookupThunk

bronsa18:02:41

and then the compiler emits a monomorphic cache in bytecode

bronsa18:02:15

which does basically (if (= (class key) __prev) (thunk key) (do (set! __prev (class key)) (set! thunk (getThunk x key)) (get x key))

schmee18:02:35

thanks for the explanation! 🙂

bronsa18:02:37

thunk for :foo being that (if (= key :foo) (.-foo my-record) (get my-record :foo)) snippet from above

schmee18:02:00

Am I correct that that stuff happens in KeywordInvokeExpr in the compiler?

schmee18:02:29

and KeywordLookupSite

schmee18:02:01

man, I gotta write my own compiler, this stuff is awesome 😄

schmee18:02:37

would there be any benefit to using invokedynamic for this stuff?

jtth19:02:33

I asked this in the #clojurescript channel two hours ago and got nothing, so maybe one more try: Newbie question: is there a kind of minimal front-end template or framework or concept around deploying clojurescript in a way that isn't an SPA with a lightweight backend? Clojurescript would be used here and there for this and that feature (draggable cards, &c, whatever) but the page wouldn't be structured as an SPA. Is that a thing? If it is, can someone point me in a direction?

hagmonk19:02:55

@jtth you can include compiled ClojureScript in a regular webpage just fine. I built a Grafana plugin this way. I used shadow-cljs to compile the CLJS, then grunt to wrap it in a shadowjs module.

hagmonk19:02:10

The main bump you might encounter is that non-optimized builds will try to include dependencies using document.write, which is prohibited after page load. Easiest thing to do is build with whitespace, simple, or advanced optimizations

hagmonk19:02:05

@jtth jump in the #shadow-cljs channel if you have questions on that tool. I found it easy to use, and being packaged via npm was convenient (and less scary to JS colleagues)

hagmonk19:02:40

Does anyone know if there are idioms around retrieving items from a collection via an index? For instance, if one had a collection type that included its own index, it wouldn't necessarily make sense to search the collection with filter if the index could be used instead.

hagmonk19:02:16

The best I can come up with is implementing ILookup and have get return a collection

tbaldridge20:02:55

@hagmonk I'd say ILookup is fine, but have it return an iterator or lazy collection of some sort. No reason to new up a whole collection just to hand over those values.

tbaldridge20:02:19

That's the way the Datomic API works (d/datoms db :eavt e-val) => iterator of datoms where e = e-val

hagmonk21:02:05

@tbaldridge that's a good idea ... for context I'm writting some wrapper functionality around the IntervalTree class in https://github.com/Breinify/brein-time-utilities

russell21:02:40

I seem to remember that a few weeks ago someone released a relatively large real-world clojure/datomic app on github (I think it was for some sort of ecommerce site but I could be wrong). But my google skills are failing me and I can’t find the link - does anyone remember it?

noisesmith21:02:15

@russell any chance it was one of the circleCI codebases? https://github.com/circleci

hagmonk21:02:18

huh, I remember seeing this too. Could have sworn it was on /r/clojure, but cannot find it there now ...

hagmonk21:02:36

slackbot says that was shared in the last hour anyway :)

joelsanchez21:02:56

bad time for this because demo's currently not running 😛

russell21:02:42

It wasn’t ventas or circleci but those are nice example projects as well, thank you!

hagmonk21:02:43

but a good time for @russell to be looking :)

hagmonk21:02:36

I looked through all projects on github, written in clojure, updated in the last several weeks, that had a string match for "datomic"

hagmonk22:02:03

ventas was definitely the one I was thinking of, doesn't seem to be any other full stack one posted recently ...

hagmonk22:02:11

further back is the clojureacademy site, which is not ecommerce: https://github.com/clojurecademy/clojurecademy

russell22:02:30

Maybe it was a longer time ago. I think it was maybe a european startup sort of company that exited somehow and just released their github repo? maybe it was all just a dream…

hagmonk22:02:15

... like datoms in the rain

russell22:02:28

the projects posted are great to look at, can’t complain since I didn’t know what I was looking for anyway, now I’m just bothered by remembering something that doesn’t exist!

joelsanchez22:02:42

run and read the code before ventas turns into an incomprehensible monolith

hagmonk22:02:45

Once I had the idea to add "browser friendly" endpoints to a pedestal based API server. "I'll just throw a little bit of cljs in and render a cool page that's more friendly than the browser's json plugin"

hagmonk22:02:16

Thus did the monolith begin to take shape. The first victim was my project.clj ...

joelsanchez22:02:28

can relate, though it was worse some months ago

hagmonk22:02:50

yeah your project.clj looks more clean than mine. I'm importing a lot of libs for java interop - which feels like organizing an arranged marriage between hostile mafia families

hagmonk22:02:13

"I can't believe you disrespected log4j by loading apache commons first"

hagmonk22:02:43

"I'm not even loading apache commons, who the hell is pulling that in?"

joelsanchez22:02:12

i feel like I can't add one more dependency without triggering chaos across my transitive dependencies

joelsanchez22:02:26

just something will break

joelsanchez22:02:04

the other day i added pomegranate and it somehow needed a more recent version of plexus utils...`lein deps :tree` didnt even print a conflict there

hagmonk22:02:14

I was really surprised to learn how hands off leiningen is with dependency management, before this I was under the false impression that magic was happening

joelsanchez22:02:48

regarding log4j, I really had to understand its universe before taming it

joelsanchez22:02:00

so glad that I did, now, though...

joelsanchez22:02:39

now datomic logs through timbre happily!

hagmonk22:02:47

I started using stuart's boilerplate code for that, I haven't yet swallowed the log4j / logback frog

hagmonk22:02:10

this guy, for folks following at home: https://github.com/stuartsierra/log.dev

hagmonk22:02:41

it produces the magical recipe needed to lift the curse of log4j error messages every time your app starts :)

joelsanchez22:02:26

invaluable then 🙂 I, apparently (according to a comment of mine in my project.clj) "redirected everything to slf4j and then redirected slf4j to timbre"

joelsanchez22:02:35

surely that must make some sense

hagmonk22:02:56

commit timestamp: 2:38am ;)

joelsanchez22:02:26

;;TODO: Sleep

hagmonk22:02:12

having complained about this, I went back to a ruby project and the wholesale lack of standardized logging infra is actually even more intractable than java logging

hagmonk22:02:55

we had a splunk thingy that would give you nice structured logs if you promised to print one well-formed line of json per log event

hagmonk22:02:21

trivial to set up in java - assuming you've come as far as we have in understanding it

hagmonk22:02:15

impossible in ruby - several deep libraries were setting up their own Logger instances and it would have required careful engineering effort and monkeypatches out the wazoo

hagmonk22:02:36

(for small values of impossible)

joelsanchez22:02:57

never did Ruby but used to do PHP - prefer not to comment

hagmonk22:02:12

I traveled through those lands when PHP/FI walked the earth. I saw many unholy things.

hagmonk22:02:56

"form interpreter"

hagmonk22:02:33

effectively it was the first big rewrite of PHP into something somewhat usable

hagmonk22:02:10

it's kind of nice, they have a history page describing it: http://php.net/manual/phpfi2.php#history

hagmonk22:02:31

oh crap, this was in 1996. I have carbon dated myself

joelsanchez22:02:28

I think you did! 🙂 very interesting