Fork me on GitHub
#clojure
<
2017-05-26
>
lumengxi00:05:14

@noisesmith that only works in repl right?

noisesmith00:05:31

right, there’s no lein command that does that

lumengxi00:05:10

ok, trying to do this in Jenkins

noisesmith00:05:12

technomancy has been working on a new test runner though https://github.com/circleci/circleci.test

noisesmith00:05:04

you can always create a lein command that runs a specific bit of clojure code in the context of your project (but at that point you would find it easier to use boot probably)

lumengxi00:05:54

yea, thanks, good to know

qqq03:05:12

What is the right primitive for this: (1) I can always dereference OBJ to get latest value. (2) There is a "function" attached to OBJ< of type "old-state -> value -> new-state" (3) There is an incoming "stream of values", which must be processed, in order, exactly once. (4) the attached function is NOT guaranteed to be pure

qqq03:05:27

(I'm looking for a concnernccy primitive / possibly using go blocks)

john03:05:43

an atom?

qqq03:05:57

isn't the swap! function supposed to be pure

qqq03:05:04

since there's contention and thed compare + swap might fail

qqq03:05:14

I'm thinking something that's almost queue like

john03:05:20

you can use an add-watch

qqq03:05:35

so push all the non pure parts into the watcher function ?

john03:05:43

potentially

john03:05:09

I don't see a purity warning on add-watch. I'm fairly sure it will be called once and only once

john03:05:14

But add-watch does handle old-state/new-state

john03:05:54

You could probably piece together a core.async thing as well, but I find simple atoms to be easier for simpler problems.

john03:05:14

You can also attach validators

wottis04:05:30

Does someone have an idea how that could be done even faster with the help of reducers, if that's even possible?

wottis04:05:26

Though pmap to me is very satisfying but, unfortunately codewars kinda doesn't like it Oo.

liminal1804:05:18

Hey aside from the official docs on the website and the youtube video from the language creator can anyone recommend good clojure tutorials for basic concurrent programming. Maybe a simple start project for concurrency

mping10:05:47

hi all, is there a nice browser automation lib out there? clj-webdriver is my last resort

qqq11:05:22

I'm writing a lot of cljC lately. Is there a wa yto unify cljs.core.async anc clojure.core.async ?

qqq11:05:29

Trying to cut down on the number of #? I have to use

rauh11:05:50

@qqq Just try to require clojure.core.async, it should rewrite it to cljs.core.async, kinda recent feature

qqq11:05:51

where is this 'rewirte namesapces' feature ou speak of documented?

qqq11:05:44

:refer now features macro inference. There is no longer any need to supply both :refer and :refer-macros in the same :require, the compiler will figure it out. clojure.* namespaces will now automatically be aliased to their ClojureScript equivalents. For example this means that the following is perfectly valid ClojureScript: -- oh man, those are awesome

qqq11:05:34

We also have a new feature that is relevant for tooling such as Figwheel and cljs-devtools - :preloads. This should now be the standard way to inject some bit of side-effecting setup after core but before user code (i.e. connecting REPLs to standard ports, etc.). ^^ -- is there more detail on this feature ?

qqq11:05:45

currently, I'm using boot to inject preloads

qqq11:05:53

but this sounds like there a way to inject them directly via the *.cljs file ?

leonoel14:05:46

what is the good way of optimizing access to a native array of integers ?

leonoel14:05:21

I tried with aset-int, and profiling gives much worse results than with a simple aset

dpsutton14:05:00

are they densely packed together?

dpsutton14:05:57

ah, i am misremembering. there's an int-map datastructure but that appears to not be what you want

dpsutton14:05:16

i thought i remembered it being holding integers, but it's holding integers as keys to the map

leonoel15:05:40

my use case is a heap implementation, mutability is ok and size is bounded

leonoel15:05:07

sounded like a good match for native arrays

joshjones15:05:08

is there a reason you don't want to use a transient vector?

leonoel15:05:59

I could use a transient vector, I just want maximal performance bc it's pretty hot code

leonoel15:05:03

maybe I should just write it in plain java

joshjones15:05:40

aset-int is having to coerce to ints, so i'm not surprised that it is slow. have you tried int-array? i would benchmark the transient vector to see if meets your needs

leonoel15:05:23

yes the array is created with int-array but I thought aset-int was a kind of optimized version of aset for native int arrays

leonoel15:05:04

if it's slower I don't see the point, you could just use aset with a int coercion

leonoel15:05:43

but I may miss something

leonoel15:05:10

thanks for the tips anyways !

john15:05:21

@mping Yes, there is a more modern version of clj-webdriver I believe

john15:05:50

meaning, it depends on a more recent version of the web driver

mping16:05:43

@john is it under “clj-webdriver”? the github says “unmaintained” :thinking_face:

john16:05:26

It's slightly different. One sec

john16:05:08

yeah, that's it

tmarble16:05:24

And I might even fix those issues :)

john16:05:39

They really oughta just link directly to webica from their "unmaintained" disclosure.

john16:05:40

People come asking if something like webica exists all the time.

bfabry16:05:03

random thought: reverse destructuring would save a lot of boilerplate sometimes. (let [foo {:keys [bash bar baz]}]

noisesmith16:05:11

what would that do?

noisesmith16:05:10

would it be equivalent to (let [foo {:bash bash :bar bar :baz baz}] ...) ? because there’s a macro in flatland/useful that does that

bfabry16:05:32

yeah exactly

bfabry16:05:44

interesting, maybe I should look into including flatland in my projects

noisesmith16:05:49

I should really pull flatland/useful into my project

dpsutton16:05:11

puts all args to a function into a map?

noisesmith16:05:27

@dpsutton not just that - it also keys the map based on local binding names

noisesmith16:05:37

something I find myself doing a lot when I refactor hairy functions

bfabry17:05:12

I mostly just find myself wanting to do it a lot when adding log lines

noisesmith17:05:27

oh, to show value of locals - yeah I do that sometimes too (though I’ve found that for debugging putting the value in a vector inside an atom helps me fix things much faster… but I do the same “key is local name” hash map for that too so…)

bfabry17:05:27

yeah most of the clojure I write runs on a distributed system where there's no such thing as mutable state, step debugger, etc, so this might be a lot more common a pattern for me than most 😅

matan17:05:53

how is one typically expected to search its api other than looking in the source?

noisesmith17:05:00

@bfabry same with mine - what I’m talking about is a top level def with (atom []) and then adding a swap! inside my function so that I store the data, then in the repl I can play with the data that is actually in play

noisesmith17:05:12

it’s not any more work than adding logging is, and it’s a lot more useful

noisesmith17:05:46

@matan I just look at the source

matan17:05:01

yep I figured so

noisesmith17:05:04

the namespaces are organized by the kind of thing they are good for (maps, namespaces, macros…)

noisesmith17:05:33

@matan oh, btw, I have a work-in-progress lib to dump data from the repl to be used in unit tests (related to some ideas we talked about here about capturing data) https://github.com/noisesmith/poirot today I’m working on doing the same thing with cljs data (working around browser limitations makes that a little weird)

matan17:05:28

@noisesmith I will definitely have a look

noisesmith17:05:41

it’s an intentionally tiny api - dump data from a repl, restore data inside a unit test (probably selecting and renaming the dump files in between via your OS)

matan18:05:21

One concern might be, avoiding a user unintentionally rewriting a data file already in use by a test. What do you think? maybe add some kind of warning or require an extra argument, for rewriting an existing one?

noisesmith18:05:55

if you don’t specify a name, the default has a time stamp - but yeah, refusing to overwrite might be friendly

noisesmith18:05:12

or just appending a number like the browser does

noisesmith18:05:46

since it’s meant to be used interactively there’s room to be a little fiddly if needed

matan18:05:04

Yes I understand the point about fiddly. but say you add a test and rewrite a file created few months ago... some mortals may not realize they've altered an existing test file until they run the tests and analyze the errors

matan18:05:39

@noisesmith I might make a PR to allow modifying the target directory, after you flesh out some more of it of course

noisesmith18:05:00

it uses env to set the target directory

noisesmith18:05:29

a planned direction for development is to get sane read-handlers and write-handlers for the common app data that isn’t in edn - stuff like atoms and refs - since I really do find myself needing to debug functions that take data with atoms in it sometimes

matan18:05:14

yep, good point, if this isn't much of a detour into bytecode detail or something like that .. I wonder how tractable that line of development might be

noisesmith19:05:09

matan: it was actually easier than expected

peregrine.circle=> (p/dump (atom {:a 0 :b 1}))
"./test/data/class-clojure.lang.Atom-2017-05-26-12-33-15.transit.json"
peregrine.circle=> (p/restore *1)
#object[clojure.lang.Atom 0x4805de96 {:status :ready, :val {:a 0, :b 1}}]
I’ll have it pushed later

matan15:05:52

@noisesmith Now that I try to play with it, I forgot how to make a dependency to a snapshot version. Are you pushing this to any public repository yet?

noisesmith15:05:50

yeah - noisesmith/poirot

noisesmith15:05:02

the latest version on github isn't deployed - cljs bugs

noisesmith15:05:18

but you can play with it by running lein install after cloning the repo

noisesmith18:05:49

transit supports custom tags, so it’s actually strightforward, it’s just a question of implementing it I think (see how it handles queus currently)

lmergen18:05:35

how common is the practice of putting your tests at the bottom of a source file actually ? i’ve never done this, but it seems to go very well with a repl-driven development style

neverfox18:05:16

Any reason lein uberjar would be so slow when run inside the official Docker image? If I just create a new lein app, mount the directory into the container and docker run with lein uberjar, it takes much longer to complete the standalone.jar than it does directly on my Mac host. Using Docker for Mac fwiw. On any code that’s more involved than the hello world generated by lein new app, it seems to never finish.

noisesmith18:05:37

is it downloading all the deps?

neverfox18:05:26

In the case of the hello world, there are none. In the larger case, I already have them baked in to an image extended from the official image

neverfox18:05:40

Plus I’m watching the console output

noisesmith18:05:41

you always have deps, clojure.jar is a dep

neverfox18:05:48

it hangs after doing the slim jar

neverfox18:05:15

In other words, it’s the time after the compilation is done and between X-SNASHOT.jar and X-SNAPSHOT-standalone.jar

neverfox18:05:35

takes minutes, whereas outside of Docker takes seconds

neverfox18:05:43

It’s baffling. I wonder if it’s something with Docker for Mac in particular, but I don’t have a different setup to try.

neverfox19:05:59

# steps to recreate
lein new app docker-lein-uberjar
docker run -it --rm -v $(pwd)/docker-lein-uberjar:/checkout -w /checkout clojure:alpine lein uberjar

# output
Retrieving org/clojure/clojure/1.8.0/clojure-1.8.0.pom from central
Retrieving org/sonatype/oss/oss-parent/7/oss-parent-7.pom from central
Retrieving org/clojure/clojure/1.8.0/clojure-1.8.0.jar from central
Compiling docker-lein-uberjar.core
Created /checkout/target/uberjar/docker-lein-uberjar-0.1.0-SNAPSHOT.jar
# Relatively long pause
Created /checkout/target/uberjar/docker-lein-uberjar-0.1.0-SNAPSHOT-standalone.jar

drewverlee19:05:33

are their any clojure libraries in need of a maintainer, also is there a programmatic way to figure this out? Building the tool to find this out might be kind of cool…

pasi19:05:47

is there anything like prettier (which is an autoformat tool for JS) for Clojure?

pasi19:05:16

just getting started witih Clojure but prettier has made my life so much nicer that I already miss similar functionality when I work with other languages 🙂

weavejester19:05:34

cljfmt tends to err on the side of the user, changing wrong things but keeping the syntax otherwise. zprint, I believe, just formats everything the way it wants.

noisesmith19:05:06

cljfmt was a game changer for me, it’s totally normal now to not check in code to our app unless we’ve fixed it with cljfmt and that solves so many annoyances

tanzoniteblack19:05:10

^^^ The real “problem” with using the same handle on github and slack and being prolific: whenever anyone mentions a library you wrote, you get summoned 🙂

pasi19:05:50

ok, cool. Thanks. I actually think I'd prefer a way very opinionated formatter, especially because I'm totally new to lispy languages

dpsutton19:05:21

this can get annoying. emacs is hard coded to scoot single ; comments over to the right and cursive likes them at the beginning of the line

tclamb20:05:24

dpsutton: emacs doesn't scoot double ;; comments for me, is cursive okay with those?

dpsutton21:05:26

i don't use cursive but i think the standard is ;; stays on the left margin

cfleming01:05:07

@dpsutton Cursive can be configured to move them over too: Settings-&gt;Editor-&gt;Code Style-&gt;Clojure-&gt;Comment alignment column

dpsutton01:05:41

Straight from the source. Thanks

cfleming01:05:13

It’s actually set to column 60 by default, if that’s not working let me know.

pasi19:05:32

and it's how I use prettier with JS. I just let it fix everything on save. It's great for productivity, just let the tool fix formatting and focus on real issues

dpsutton19:05:34

and they will constantly diff

weavejester19:05:02

@pasi, what editor are you using?

neverfox19:05:27

Was about to ask the same thing.

pasi19:05:40

atom for now (because it's what I use at work for everything else). I'm pretty flexible though

weavejester19:05:58

@pasi are you using parinfer?

weavejester19:05:12

If you’re new to lispy languages, I’d recommend that.

pasi19:05:24

yeah, I installed Parinfer

pasi19:05:40

found a helpful "getting started with Clojure in Atom" gist

weavejester19:05:48

There’s Cursive if you want a “real” IDE

neverfox19:05:33

or Spacemacs/CIDER if you think “real” IDEs are overrated

weavejester19:05:14

Parinfer should handle the formatting of brackets for you, which is most of Clojure’s formatting right there 🙂

neverfox19:05:14

Yeah, Clojure demands a lot less in terms of linting than something like JS in the first place.

dpsutton19:05:18

lisps are very readable when aligned and almost unbearable when not aligned

pasi19:05:01

nod. I'll make a note of those formatters in case I still feel like I need one after getting hang of the syntax

neverfox20:05:53

@noisesmith You might be interested to learn that it is creating the uberjar, just very slowly. I monitored the file and it’s constantly growing. When I build the source into the image,it ran as fast as it usually does. It seems the speed issue is coming from when I mount the source as a volume and it’s having to compile a jar onto that host volume. More evidence it might be a bottleneck in docker.

shader21:05:50

is there a preferred pattern-matching library/macro? or an alternative that can solve similar problems? I'm trying to implement dispatch off of a set of actions that can be received in messages over ZMQ

noisesmith21:05:07

multimethods and routers both work for simple dispatch with heirarchies

noisesmith21:05:21

what kind of patterns do you think you’d be looking for in messages?

shader21:05:53

@noisesmith [<peer-id> "action" & args] - I'd like to capture the peer id, and dispatch on action

shader21:05:10

I found matchure and have just now started an implementation using it, but it's quite old...

noisesmith21:05:13

a defmulti can do that easily

noisesmith21:05:55

I mean, if you prefer a matching lib that’s fine, and the clojure.core.match lib is probably the best maintained

noisesmith21:05:05

but you do not need a full matcher and clojure.core can handle that

noisesmith21:05:20

(defmulti zmq-message (fn [peer-id action & args] action)) (defmethod zmq-message "frob" [peer-id _ & args] …)

noisesmith21:05:55

where “frob” is replaced by actual action string of course

shader21:05:34

thanks; I prefer avoiding introducing new dependencies where possible anyway

noisesmith21:05:13

this way different namespaces or optional submodules can make new message handling extensions too, which can be a nice way to grow a design sometimes

ericnormand22:05:36

@noisesmith you can also do something similar with a case statement

ericnormand22:05:49

if they all have similar structure

noisesmith22:05:30

that’s true

ericnormand22:05:52

(let [[peer-id action & args] msg]
  (case action
    "foo" (do-foo peer-id args)
    "bar" (do-bar peer-id args)))

noisesmith22:05:20

yeah, it’s remarkable how similar a router, a hash-map, a multimethod, and a case statement can be sometimes

shader22:05:48

I like the multimethod solution, because I was going to have function definitions for each action anyway

gmercer23:05:11

loom is asking for one