This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-12-16
Channels
- # adventofcode (93)
- # beginners (104)
- # boot (1)
- # cider (4)
- # cljsjs (2)
- # clojure (174)
- # clojure-austin (1)
- # clojure-greece (5)
- # clojure-spec (13)
- # clojure-uk (32)
- # clojurescript (15)
- # core-logic (13)
- # cursive (13)
- # data-science (8)
- # datomic (11)
- # duct (1)
- # fulcro (22)
- # instaparse (23)
- # jobs (1)
- # lein-figwheel (5)
- # off-topic (13)
- # onyx (13)
- # parinfer (1)
- # pedestal (19)
- # re-frame (33)
- # specter (26)
- # unrepl (22)
there’s definitely nothing that replaces it
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 😛
one factor here is how strong clojure is for compatibility - which means clojure libraries don’t need to churn to stay compatible
(comparatively at least to other ecosystems)
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
it’s mainly a bunch of macros
@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.
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.
So if you can't necessarily go by commits or github stars how can you tell?
https://crossclj.info is useful for seeing which libs are used by open source projects
yeah - I'd never had that issue before, but it's up now
and anything from the clojure.core team will say prominently that it isn’t ready for usage if that’s the case
@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/
@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...
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.
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
...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).
(that is, when I bump up my own project version from 0.x.x to 1.x.x)
clojure.java.jdbc
for example just released 0.7.4
yesterday after about six years of updates.
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”
any particular reason to never call a release 1.0.0 ?
@Justin yeah in my experience version strings are much less meaningful in the clojure ecosystem
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.
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)
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.
"well you were born in the year 1.0.0, so that means you're still young but your API is stable" - sure, ok 🙂
@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...
...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.
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.
(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 firstHere'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
@seancorfield I think the backwards-compatibility culture is great. No arguments there.
@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.
Other communities (especially extremely large, diverse communities) use version numbers as a mechanism for signaling how much confidence you should have in their software
@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).
(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!)
@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.
> 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.
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.
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.
The kubernetes project for instance has yet another set of cultural norms that differ from JS and Clojure communities. It goes on and on.
(which is an interesting read, by the way: https://kubernetes.io/docs/reference/deprecation-policy/)
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.
@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.
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.
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 😉
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.
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
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.
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.
(I mostly do C++ to pay the bills though so the levels of verbosity are quite different heh)
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
So I'm quietly waiting for the right moment to re-implement his thing in a couple of lines of macro 😉
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.
so there are some nice things in modern c++, but it’s still pretty verbose compared to clojure
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.
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 ?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
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.
@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, ...
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
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).
Does that help @leira?
@seancorfield it helps a lot thx
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
@qqq maybe check out the Nord color scheme for inspiration: https://github.com/arcticicestudio/nord
More inspiration here, esp. if you use IntelliJ: http://color-themes.com/
If you want really general color stuff, you can visit http://www.colourlovers.com and find colors that are complementary, suggested palettes, etc
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
There's a ton of stuff you can do in emacs, including using org-mode in your comments, which supports folding
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"
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?
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" ]
Is there any reason uses 2 + Runtime.getRuntime().availableProcessors()
for Agent/pooledExecutor
(https://github.com/clojure/clojure/blob/clojure-1.9.0/src/jvm/clojure/lang/Agent.java#L50) and pmap
(https://github.com/clojure/clojure/blob/clojure-1.9.0/src/clj/clojure/core.clj#L6941)? Why the 2 +
?
@seancorfield that code seems to defy the normal order of compilation, in that it refers to fib
in its own def
inition, and it's not obvious how the compiler handles that!
@octo221which means ?
@leonoel which means ?
it means you are allowed to self-refer the var you're defining, as long as the access is deferred (what lazy-seq does)
@leonoel what do you mean by 'root value' ?
which in this case is (concat [1 1] (lazy-seq (map + (rest fib) fib)))
yes, but during the evaluation of that, the root value is undefined, that's why you need to defer
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 ?
but this isn't a dynamic var
static vars have always one value and this value can be a sentinel if this var has not yet been bound
ok so we could just say 'value' in this case
alright so the point is that lazy-seq
defers evaluation (until realized by take
or something)
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...)
and when the def
is evaluated, the lazy-seq
isn't actually realized, it's only created
it's confusing because it doesn't read like that
it reads as an atomic definition
there's no indication as to the 2-pass evaluation
I think it's hard to reason about time in that code
no I've only ever seen that example - it's lovely though!
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))
So that's exactly what the lazy-seq
does (it's a macro that wrapps the code in a function)
@rauh or delay
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.
that doesn't sound enjoyable
Your mind probably woulnt' have a problem with that code: (def foo [0 1 (fn [] [2 3 (foo)])])
, right?
it's pretty straightforward - you just need an object that holds a function and an optional value
Hi. What lib you would recommend to use with GraphQL? I found several and don't know which I should to choose
I understand right what I need to use GraphQL both in cljs and clj sides of my site?
@kgofhedgehogs lacinia
@hee-foo, thanks
@gklijs, joined, thanks
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
So there is/was fnparse, but the original is super stale the maintainer vanished and there’s no clear winner of the forks.
Instaparse exists and I’d suggest you start there. Using the ordered choice operator you can optimize your grammars moderately well.
@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
@borkdude try replacing unordered choice |
with ordered choice /
in your grammar and see how that does.
@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.
One issue is that Instaparse has to generate nested items first which get resolved in the transform phase
You can. That’s how my first compiler written in fnparse worked. You can also use Antlr4 visitors/listeners to perform evaluation during parsing.
Instaparse doesn’t and won’t support doing this for good reason. I talked to @U0516PHE3 about this at some point.
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.
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.
Kern implementation: https://github.com/borkdude/aoc2017/blob/master/src/day16.clj#L115
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
I see this one isn't out yet by the way, no idea what is its table of contents like https://www.amazon.com/Programming-Clojure-Alex-Miller/dp/1680502468/ref=sr_1_7?s=books&ie=UTF8&qid=1513463397&sr=1-7&keywords=clojure
Is there anyone using Lacinia ? Great job! But, I am so sceptic. I have some questions.
@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.
@scknkkrer at #graphql there are quit some questions, I also want to try it at somewhere soon
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?
@U06C62LJW You might not be running the server on async-mode? Adding {:async? true}
to jetty opts enables the async chain.
@U055NJ5CC It turned out that I needed to make httpkit understand ring-async
Which requires a tiny wrapper
@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
Agreed. I may take a crack at the advice for httpkit offered here: https://www.booleanknot.com/blog/2016/07/15/asynchronous-ring.html
(that's also where i got the tiny wrapper, ring->httpkit
)
Ah, nevermind. I just needed to show httpkit how to interface with ring-async
@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 TBox
s are the same, which my experiments seem to confirm.