Fork me on GitHub
#clojure
<
2017-12-16
>
jgh00:12:19

is core.async still active?

jgh00:12:26

or is there a preferred alternative now

noisesmith00:12:38

there’s definitely nothing that replaces it

jgh00:12:22

i guess there’s a little activity, going through the commit history. It’s always a little disconcerting when you look at a repo and the only thing that’s changed in the last few months is the version number 😛

noisesmith00:12:28

one factor here is how strong clojure is for compatibility - which means clojure libraries don’t need to churn to stay compatible

noisesmith00:12:45

(comparatively at least to other ecosystems)

jgh00:12:01

yeah fair enough.

noisesmith00:12:05

and core.async is not something that would be getting many security updates - if outside data is directly driving core.async that’s your security problem right there

noisesmith00:12:14

it’s mainly a bunch of macros

seancorfield00:12:34

@jgh Many people new to Clojure are surprised that a lot of heavily used libraries seem to be "inactive" based on the commit history. This is often due to a library being stable, mature, and "complete" -- since it is common for libraries to have a narrow focus and therefore they are often smaller and simpler than you might find in other languages.

justinlee00:12:31

It also seems like some stable libraries that have been in use for years and are still maintained are still at a sub-one version number, which I find disconcerting.

jgh00:12:00

hard to imagine “complete” software ;)

derpocious00:12:31

So if you can't necessarily go by commits or github stars how can you tell?

noisesmith00:12:22

https://crossclj.info is useful for seeing which libs are used by open source projects

matan08:12:16

looks like the site is down today? (?!)

noisesmith21:12:24

yeah - I'd never had that issue before, but it's up now

noisesmith00:12:54

and anything from the clojure.core team will say prominently that it isn’t ready for usage if that’s the case

hagmonk00:12:01

@jgh here's my take on the same question from several months ago. It comes up a lot in the Clojure community: https://www.reddit.com/r/Clojure/comments/5vjq54/whats_the_reason_of_clojure_having_lots_of/de2w8vx/

didibus00:12:10

How often do Java standard libs change?

seancorfield00:12:04

@lee.justin.m I think that's mostly a weird historical quirk. Leiningen templates typically create a 0.1.0-SNAPSHOT project (I think?) and so folks start from there and go to 0.1.1 etc...

didibus00:12:45

I do feel something in Clojure which is sometimes weird is certain things are like half standard libs, yet library. Like core.async, you can pretty much consider it a part of the standard library, yet you need to pull it in as a dependency to use it.

noisesmith00:12:11

I’ve had people look askance when I update to a 1.x.x release - my reasoning being that this means bumping to that promises that the public facing api won’t change until that 1 becomes a 2

seancorfield00:12:37

...also, we used to have a monolithic Clojure Contrib library which was versioned along with Clojure itself and was at 1.2.0 when it was deprecated and broken up into the seed of what we have today -- and they all started out at 0.1.0(!). I believe one of them has reached 1.0.0 (maybe more than one? but only a few).

noisesmith00:12:39

(that is, when I bump up my own project version from 0.x.x to 1.x.x)

seancorfield00:12:16

clojure.java.jdbc for example just released 0.7.4 yesterday after about six years of updates.

justinlee00:12:37

I just happen to be coming over from the javascript/node community where 0.x.x means “use at your own risk” and “1.x.x” means “ready for public consumption”

noisesmith00:12:46

any particular reason to never call a release 1.0.0 ?

noisesmith01:12:13

@Justin yeah in my experience version strings are much less meaningful in the clojure ecosystem

justinlee01:12:24

I see lots of libraries that seem to be asymptotically approaching 1.0.0, which is fine as long as you understand what the convention is.

noisesmith01:12:26

for context, clojure.data.json had an incompatible api change before 1.0.0 and there was an uproar about the incompatibility (we wouldn’t have nearly as many cheshire users today if that had never happened I think)

justinlee01:12:45

But if you are just casually investigating, say, a react javascript stack vs. a reasonml stack vs. clojurescript, you can be left with the impression that everything is half-assed and broken because nothing has reached a “stable” release, which I think is a mistaken impression.

hagmonk01:12:41

It's definitely mistaken, that's basically software astrology

hagmonk01:12:15

"well you were born in the year 1.0.0, so that means you're still young but your API is stable" - sure, ok 🙂

seancorfield01:12:33

@lee.justin.m There's also a cultural thing in Clojure about version numbers -- best seen in Rich Hickey's Spec-ulation talk (but he's hinted at it in a few other talks) -- that they don't really matter: libraries should grow through accretion of functionality (only) and never break backward compatibility for a particular group/artifact. So Clojurians don't "care" that a library has a low version number, as long as it provides the functionality they want...

seancorfield01:12:19

...and libraries are often small and focused so it's also often easy to switch out a single library, and of course you end up with a large combination of libraries.

justinlee01:12:54

If the community really thinks that version numbers don’t matter, why not change them to what a lot of programmers expect? Just lop the 0 off if the library is stable. Boom, easy change in perception. Just my 2 cents as a newbie.

qqq01:12:04

(defn fu [obj funcs]
  (reduce (fn [val [k f]] (update val k f)) obj funcs))

(fu {:a 1 :b 2 :c 3 :d 4}
    {:a inc :b dec :d #(* % %)})
I created this function, fu, short hand for function update, is there a builtin like it takes two maps as arguments; the second specifies how to update the first

seancorfield01:12:45

Here's a great thread about backward compatibility (on a library that has reached 0.14.2 after close to seven years of development) https://github.com/clj-time/clj-time/issues/196

justinlee01:12:51

@seancorfield I think the backwards-compatibility culture is great. No arguments there.

hagmonk01:12:51

@lee.justin.m essentially, Clojure has a different set of cultural norms when it comes to software compatibility that get us the result we're after. It's rare for people to be burned by breakages between versions, so there is literally no pressure on the community to organize around a version number scheme, because it would convey no useful information.

hagmonk01:12:39

Other communities (especially extremely large, diverse communities) use version numbers as a mechanism for signaling how much confidence you should have in their software

seancorfield01:12:48

@lee.justin.m The specific issue in that thread is that we all decided that we couldn't change the implementation since it would change the API and so it would need to use a different group/artifact in order not to cause problems (because an application can easily pull in multiple versions of the same group/artifact and only one will win -- so that must provide an API that every library you pulled in can still use).

seancorfield01:12:03

(and the transient dependency conflict issue is also partly why folks are so conservative about change here -- since small, focused libraries get widely used by other libraries!)

justinlee01:12:56

@hagmonk @seancorfield Yea I totally get what you guys are saying, and I think all that is really great and commendable. What I’m saying is instead of sticking on 0.x.x forever, just bump to 1.x.x. That communicates “stable, use me” to every potential recruit from JS/node and probably lots of other communities as well. You don’t have to go full semver, since, as you guys are pointing out, that isn’t useful given the cultural norms.

jgh01:12:24

> for context, clojure.data.json had an incompatible api change before 1.0.0 and there was an uproar about the incompatibility (we wouldn’t have nearly as many cheshire users today if that had never happened I think) I guess if you’re not using major versions to indicate breaking changes then your versioning system may be somewhat arbitrary. In that case maybe think about using the Ubuntu versioning system.

jgh01:12:50

@hagmonk thanks for the link, i’ll give it a read

jgh01:12:45

I understand what you’re saying there but it’s often difficult to know if you’re looking at a timeless g722.c or someone’s half-baked lib that they haven’t touched in 3 years unless you have greater context on the community.

hagmonk01:12:24

The reason why not is pretty simple. If I went to the JS community and said "please just write software that is generally backwards compatible so I don't have to care about the version number", it would not fly very far. Not because there's anything wrong with the JS community, it's just that I'm asking them to change a cultural norm to suit myself.

hagmonk01:12:09

The kubernetes project for instance has yet another set of cultural norms that differ from JS and Clojure communities. It goes on and on.

jgh01:12:10

but yes i would rather have something that works and is stable than something that has bugs and people are constantly fiddling with, if those are my options.

justinlee01:12:21

@hagmonk Except that the suggestion is that you could change something that you yourself are saying doesn’t matter to you and is arbitrary anyway and might help people use clojure.

hagmonk01:12:14

Clojure has areas that need help much more seriously 🙂 The person it would be helping is the newcomer who is initially confused, but pretty quickly learns the ropes. If anything I think this cultural norm has become a source of pride and rite of passage. And from a technology perspective, we're starting to explore a world where we leave version numbers behind entirely, if you read between the lines of Rich's keynote from last year.

hagmonk01:12:43

I think all your comments are perceptive though, you are totally right that it's confusing to a newcomer more accustomed to different norms. There are many more things in Clojure that will bake your noodle than just this, trust me 😉

jgh01:12:30

Personally I don’t mind the version numbers so much. In a lot of cases they’re pretty arbitrary/meaningless. Sometimes it’s useful to indicate that stuff will break (or at least stop your package manager from updating to the breaking changes) but for the most part the numbers are not terribly valuable information.

jgh01:12:43

I’ve been updating the DigitalOcean API last night/today to add some new features to it that they’ve added in the past couple years and it’s pretty remarkable how little code it is. I’ve only really toyed around with Clojure a bit but now that I’m more independent I want to use it more seriously. It’s pretty nice having a rest api wrapper that is only, you know, ~3 lines of code per call

hagmonk01:12:20

Really the only time I'm properly alert for a sense of "abandonment" is when the code interfaces with another system that I know has evolved a great deal since then. Like, a Kafka wrapper that's several years old.

hagmonk01:12:17

But oftentimes I'll open that project up and read the source (because most of the time it's 3 lines long so it's quick to read 😉 ) to see what approach they took. The cost of spinning my own, updated take on it is often pretty low.

jgh01:12:05

(I mostly do C++ to pay the bills though so the levels of verbosity are quite different heh)

hagmonk01:12:04

My office mate is trying to convince me of the virtues of modern C++ template metaprogramming because now there are control structures or some such in there

hagmonk01:12:44

So I'm quietly waiting for the right moment to re-implement his thing in a couple of lines of macro 😉

jgh01:12:10

well, constexpr makes templates nicer so you can do stuff like if constexpr (std::is_same<T, U>()) { .. } else { ... } instead of having specialization or doing the integral constants hack.

jgh01:12:33

so there are some nice things in modern c++, but it’s still pretty verbose compared to clojure

jgh01:12:39

that said you gotta pick the right tool… I doubt I’m gonna write any media servers in Clojure anytime soon, likewise I doubt I’m going to make a rest service in C++ anytime soon.

qqq01:12:55

Is there a Clojure function that will take: as input:

float sum (int n, float * in)
{
 float  ans = 0.0
 ...
 return sum

 }

then, compile this function, and let me call it, passing it an int and float-array ?

hagmonk01:12:22

@qqq compile it such that you can invoke it from java?

qqq01:12:42

yeah, I want it to take the string, compile it as a . function, then load it so I can invoke it from Clojure via Java

didibus01:12:17

I think something like crossClj is actually a better way to judge maturity, reliability etc. Would be nice if there was a little github badge thing that would show the number of projects that have a dependency on the current repo. And maybe show how many new things took a dependency on it in the last month.

leira02:12:26

I'm having a hard time wrap my mind over this code

leira02:12:41

How exactly does this code work?

leira02:12:10

also (def fib (concat [1 1] (lazy-seq (map + (rest fib) fib))))

leira02:12:20

I can write it, but I don't fully understand it

seancorfield02:12:09

@leira I'll attempt to explain the fib definition... It's an infinite lazy sequence that starts with 1, 1, ... so that's fib within the body, so (rest fib) is 1, ... and so you're asking map to apply + to successive elements of both sequences (`map` produces its results in lazy chunks) so it'll produce 1 + 1 = 2, so now fib is 1, 1, 2, ... and we move on to the next element of each sequence argument to map and it produce 2 + 1 = 3, so now fib is 1, 1, 2, 3, ...

seancorfield02:12:27

and now map adds 3 (from (rest fib) ) to 2 (from fib) and gets 5... fib is 1, 1, 2, 3, 5, ... and so on, step-by-step

seancorfield02:12:11

The lazy-seq call just ensures that what's inside it doesn't try and evaluate anything until that part of the sequence is realized (asked for).

leira02:12:45

@seancorfield it helps a lot thx

qqq05:12:48

what's a good color for comment on a white background? I'm starting to find it's really important ot read the comments I write, they're just as important as code

hagmonk05:12:46

@qqq maybe check out the Nord color scheme for inspiration: https://github.com/arcticicestudio/nord

hagmonk05:12:56

or any solarized theme for your editor

hagmonk05:12:25

More inspiration here, esp. if you use IntelliJ: http://color-themes.com/

hagmonk05:12:07

If you want really general color stuff, you can visit http://www.colourlovers.com and find colors that are complementary, suggested palettes, etc

qqq05:12:54

maybe the right emacs solution is to have a command taht toggles comments betseen #888 and #000 , depending on whether I want to read comments or not

hagmonk05:12:39

There's a ton of stuff you can do in emacs, including using org-mode in your comments, which supports folding

qqq06:12:27

I don't know if anyone else is doing this, or is this is intentional: I'm currently reading a book on type theory, taking notes in the form as comments --- and then IK convert these comments into SPEC definitions; so spec is turning into "executable invariants"

sophiago23:12:20

Just saw this and thought it was really interesting...but I don't know what IK is. Seems like there was some part of this discussion I missed?

qqq07:12:43

can | be used in clojure at all? I want a way to separate elments in a vector, say [:a :b :c | 1 2 3 | "more info" ]

fmind08:12:42

@qqq why don't you use comma for that ?

fmind08:12:28

it seems that '|' is a vaid symol, like + or -

octahedrion12:12:38

@seancorfield that code seems to defy the normal order of compilation, in that it refers to fib in its own definition, and it's not obvious how the compiler handles that!

leonoel13:12:35

@octo221 symbols referring to vars are implicitly dereferenced by the compiler

leonoel13:12:29

it means you are allowed to self-refer the var you're defining, as long as the access is deferred (what lazy-seq does)

leonoel13:12:17

when the root value is evaluated, the var has already been created

octahedrion13:12:14

@leonoel what do you mean by 'root value' ?

leonoel13:12:51

the value held by your var

octahedrion13:12:21

which in this case is (concat [1 1] (lazy-seq (map + (rest fib) fib)))

leonoel13:12:50

yes, but during the evaluation of that, the root value is undefined, that's why you need to defer

leonoel13:12:13

try e.g (def a a)

octahedrion13:12:27

ok, just to be clear, a var has a value, are you saying it also has another value called its 'root value' ? i.e. does a var have 2 values: its value and its root-value and if so what's the difference ?

leonoel13:12:12

no, the difference is meaningful only for dynamic vars

octahedrion13:12:31

but this isn't a dynamic var

leonoel13:12:40

static vars have always one value and this value can be a sentinel if this var has not yet been bound

octahedrion13:12:58

ok so we could just say 'value' in this case

leonoel13:12:34

I guess so

octahedrion13:12:11

alright so the point is that lazy-seq defers evaluation (until realized by take or something)

octahedrion13:12:02

so what appears to be an intractable self-reference isn't really because at the time the lazy-seq is realized the var fib has a value, which is (concat...)

octahedrion13:12:54

and when the def is evaluated, the lazy-seq isn't actually realized, it's only created

octahedrion13:12:06

it's confusing because it doesn't read like that

octahedrion13:12:16

it reads as an atomic definition

octahedrion13:12:36

there's no indication as to the 2-pass evaluation

octahedrion13:12:42

I think it's hard to reason about time in that code

leonoel13:12:22

it's not that much common afaik

octahedrion13:12:43

no I've only ever seen that example - it's lovely though!

rauh13:12:12

The only way --in really most programming languages-- to write code that isnt' evaluated is to put it into a function. Naturally (def x (foo)) is different to (def x (fn[] (foo))

rauh13:12:41

So that's exactly what the lazy-seq does (it's a macro that wrapps the code in a function)

rauh13:12:03

It's just a function definition. Under the hood lazy seqs hide that.

rauh13:12:15

@octo221 Again, delay is JUST a function under the hood

rauh13:12:02

Try writing a lazy seq in Javascript. Totally possible since you have functions. You're API would just be a little different accessing that lazy seq.

octahedrion13:12:27

that doesn't sound enjoyable

rauh13:12:56

Your mind probably woulnt' have a problem with that code: (def foo [0 1 (fn [] [2 3 (foo)])]), right?

noisesmith13:12:01

it's pretty straightforward - you just need an object that holds a function and an optional value

kgofhedgehogs13:12:12

Hi. What lib you would recommend to use with GraphQL? I found several and don't know which I should to choose

kgofhedgehogs13:12:18

I understand right what I need to use GraphQL both in cljs and clj sides of my site?

christos15:12:05

is maintained by walmart

gklijs15:12:42

there is also #graphql which could be interesting if you start using it

igrishaev16:12:25

Hi! Tomorrow, on Sunday at 12am UTC, I’m going to stream live Clojure coding solving some issues for my open source Etaoin library. Recorded version will be stored on Youtube automatically. Watch it here: https://www.youtube.com/watch?v=cLL_5rETLWY

borkdude19:12:36

Is there a de facto parser combinator library for clojure?

arrdem19:12:49

So there is/was fnparse, but the original is super stale the maintainer vanished and there’s no clear winner of the forks.

arrdem19:12:06

It lets you write pretty trivial recursive decent parsers easily.

arrdem19:12:33

Instaparse exists and I’d suggest you start there. Using the ordered choice operator you can optimize your grammars moderately well.

arrdem19:12:43

Antlr4 or one of its wrappers if you really need performance.

borkdude19:12:24

@arrdem I wanted to check if I could get something faster than InstaParse and nicer than hand written (for some value of nice): https://github.com/borkdude/aoc2017/blob/master/src/day16.clj#L118

arrdem19:12:26

@borkdude try replacing unordered choice | with ordered choice / in your grammar and see how that does.

arrdem19:12:18

@borkdude Instaparse tries really hard to support ambiguously parsing syntaxes with fully unordered choice. Looks like your grammar is actually LL(1) and not ambiguous so you can use ordered choice to make it clear that your grammar is less general.

borkdude19:12:49

It actually becomes a bit slower that way

borkdude19:12:10

Not significantly, probably doesn’t help nor hurt

borkdude19:12:40

One issue is that Instaparse has to generate nested items first which get resolved in the transform phase

borkdude19:12:58

And with a parser combinator lib I might get to do that during processing

arrdem19:12:33

You can. That’s how my first compiler written in fnparse worked. You can also use Antlr4 visitors/listeners to perform evaluation during parsing.

arrdem19:12:11

Instaparse doesn’t and won’t support doing this for good reason. I talked to @U0516PHE3 about this at some point.

arrdem19:12:35

Besides you’re down in ms here, the measurement error is probably significant.

borkdude19:12:01

With | 582 ms, with / 591 ms, measured by criterium

borkdude19:12:38

As Alex explained, IP does a lot of bookkeeping, don’t know the exact details, but this can make it slower than simple hand rolled parsing.

borkdude19:12:02

Parser combinators don’t seem really popular in Clojure somehow.

the2bears19:12:10

I've been playing around a little with https://github.com/blancas/kern. I'm pretty new to parser/combinators as a tool though, so I can't comment on what's good or not so good.

the2bears20:12:42

Funny, I'm using AoC to learn this, too 🙂

wiseman23:12:18

you finally pushed me to start the advent of code. my solution to day 16: https://github.com/wiseman/advent-of-code/blob/master/2017/day16/src/day16.clj#L39-L59

matan22:12:57

advanced clojure book written from the post 1.7 perspective? recommendations anyone? 🙂

scknkkrer22:12:37

Is there anyone using Lacinia ? Great job! But, I am so sceptic. I have some questions.

seancorfield22:12:25

@matan Programming Clojure 3rd Ed would be a good purchase -- assuming you like e-books and don't mind getting updates while it's in pre-release form? Otherwise I'd recommend Clojure Applied if you want something beyond intro/mid-level.

gklijs22:12:01

@scknkkrer at #graphql there are quit some questions, I also want to try it at somewhere soon

isaac_cambron22:12:46

I have a probably dumb compojure-api question. (happy to take it somewhere else there's a better channel for this). I think I'm missing something very obvious, but if I return a core.async channel from a route in compojure-api, I get an error about channels not implementing render. I'm running 2.0-alpha16 and doing something super similar to the example in the readme. I'm sure this will be a facepalm moment, but what's the obvious thing I'm missing?

ikitommi08:12:59

@U06C62LJW You might not be running the server on async-mode? Adding {:async? true} to jetty opts enables the async chain.

ikitommi08:12:28

there is also #ring for ring async and #ring-swagger with c-api things too

isaac_cambron16:12:21

@U055NJ5CC It turned out that I needed to make httpkit understand ring-async

isaac_cambron16:12:49

Which requires a tiny wrapper

ikitommi21:12:57

@U06C62LJW would be nice If the tiny wrappers were available for all. Needed for Aleph & Immutant too. Best would be do PRs to all the servers to have the async? option

isaac_cambron21:12:07

Agreed. I may take a crack at the advice for httpkit offered here: https://www.booleanknot.com/blog/2016/07/15/asynchronous-ring.html

isaac_cambron21:12:39

(that's also where i got the tiny wrapper, ring->httpkit)

scknkkrer23:12:18

@gklijs thank you. 😇

isaac_cambron23:12:38

Ah, nevermind. I just needed to show httpkit how to interface with ring-async

xiongtx23:12:42

@tbaldridge Was just revisiting this article: http://blog.cognitect.com/blog/2016/9/15/works-on-my-machine-understanding-var-bindings-and-roots and noticed that there was never a follow-up on Var$TBox 😛 > The rationale behind TBox-es will have to wait until a later time What's the reason Frame bindings are maps of Var -> TBox instead of just Var -> <value>? Since dvals is thread-local, all threads a Frame's TBoxs are the same, which my experiments seem to confirm.