Dia Duit!
🙂
☀️ ☕
moin moin
Tach!
☕
bon jour!
Morning
I’m in a reflective mood today, good morning
boom boom
who’s there?
There's a Clojure thread on Hacker news front-page now :)
oh no
as long as comp.lang.lisp stays away
😉
I can handle them 💪
I should stop being so mean
I blame too many years trying to learn lisp from comp.lang.lisp
Oh, I know what you mean, I was there in the early 2000s learning Common Lisp...
Maybe I was that guy who offended you?
ooh... maybe
I don't think so tho. I remember how offended everyone in c.l.l was about a lisp on the jvm that betrayed the lisp machine ideals
it was one of the happiest days of my programming career
a good lisp on the jvm with good interop so that I could use the java libs I already knew? Fantastic.
For me Clojure was a way to learn about the JVM. I was only familiar with .NET and didn't like what I saw comparing the built-in date library and some more.
But I needed to work with the JVM because I was a lecturer back then and these students were mostly taught Java
Within a year or two I was running a Clojure course to teach them some next level programming :P
I was lucky to avoid teaching OOP design patterns because I couldn't comfortably teach that while knowing the alternatives
I mean, I would act neutral, but some things you can't easily hide
I like it as an intellectual thing, but I don't like it from the perspective of writing boilerplate in a language you have to work towards freedom first
oh gods, the way people abused it was terrible, but actually understanding the patterns made it easier to think your way around a problem without having to invent everything yourself
I really liked builder
the clojure data structures seem to use the flyweight pattern
yeah, you could apply some of those patterns in Clojure as well, but most of it is just plain common sense don't you think
I think they are often common sense, but that is why programmers would never know them 😉
I don't think most of them make sense in fp languages
they are very OOP
but for implementing fp languages in OOP languages (like clojure in java) I think they are probably pretty useful, just don't see them as things you can copy and paste from
yeah, maybe put it too strongly, but these books of hundreds of pages of material which would almost be trivial in Lisp/FP, it didn't sit well with me
fair enough, but that is a problem with OOP not patterns
yes, I was referring to OOP design patterns specifically
I think with Language of the System that RH is reaching for some FP patterns
Now that I'm ranting anyway: I wish core wouldn't have used the 2-arity of map, filter etc for transducer. I built a clj-kondo type system for it to reduce the amounts of errors I get because of mistakes I make with this.
I had another one right now: there was a JSON payload that silently missed a field, turns out it was because a transducer could not be serialized, yeah, duh...\
I would have preferred (mapping inc)
, (filtering odd?)
over (map inc)
and (filter inc)
any time of day
Morning
morning Jade
the whole transduce thing of • arity 0 for initialise • arity 1 for finish • arity 2 for iteration seems like a really strange design choice to me
it would certainly be clearer to declare as a record
the reason I can think of is that JVM is massively optimised for overloaded functions, and this was felt to outweight the confusing code implications?
Is there are more compelling reason that I have missed?
(Er is that what you were talking about...? Or I have missed the point?)
@borkdude thx for clj-kondo. It is making my refactoring to get around not being able to debug things a lot easier. Couldn't get through this w/o your tool.
(I'm basically coding by squiggly lines atm)
My gripe was with (map inc)
vs (map inc [1 2 3])
I would have preferred (mapping inc)
as forgetting to pass args to (map inc)
is often just a mistake in my code
@borkdude just got my emacs to talk to clj-kondo. Lovin’ it!
❤️
Here’s a couple of linters I’d like (but they’d certainly be controversial):
1. Prefer partial
over #(..)
when all you’r doing is binding variables
2. Prefer named (fn foo […] …)
over #(…)
and certainly over (fn […]…)
3. Flag #(..)
or (fn foo […] …)
spanning multiple forms/lines
I guess 1) is hard, since you have to analyze the #(..)
to understand that you’re just “currying”. 2) would be simple enough, warn/error on #(...)
or (fn [..] ..)
3) should probably be doable…
I wouldn't know why one would prefer partial over #(..) or (fn [...]), seems a bit random to me + you will lose reloading for vars you bind over with partial
3 seems a bit arbitrary to me. 2. could implement, but not sure anyone would adopt this as a linter and adhere to it strictly in their code base. As an example, I recently implemented the shadowed-var linter. In theory very useful, but after using it a bunch, I found it too restrictive myself
It might be a principle somewhere around it, but it’s basically that when I see partial
I know that there is nothing more going on than the binding of variables. If I see #(..)
I have to read the form to se e that nothing else is going on.
I’m not at all asking you to implement, but it might be fun for me to try to implement at some point.
And I could deffo see that those are not linters that everybody would use.
implementing is one thing, maintaining is another one. if something is wrong with a linter, usually I'm the one ending up fixing it, even if some other person wrote it (unfortunately). my point was more like: what's the point of implementing a linter and maintaining it indefinitely if it's too strict for anyone to use
As for 3) we have examples in our codebase of
(reduce (fn [acc x]
;; 300 lines of code
) {} lol)
Hmm, didn’t consider the maintenance part, and that’s a fair point.
ah good example, I get the point
Someone asked for “linter plugins” in Eastwood at some point.
clj-kondo has this, it's called hooks. you can use it today. docs: https://github.com/borkdude/clj-kondo/blob/master/doc/hooks.md examples: https://github.com/clj-kondo/config
Right, so I can basically figure out how to write my own linter, stick it in a hook and voila presto?
hopefully, yes
what you can do with a hook is transform the shape of a call and do some linting on the original shape of the call
so it's a kind of macroexpansion
but then using clj-kondo / rewrite-clj node primitives
The thing with partial
is somewhat related a thing I first heard on the Idealcast with Gene Kim and Michael Nygaard. Then I heard it again on an episode of the Corecursive podcast.
The thing in the podcasts was something like “The more abstract the types of the parameters of the function, the less the function can do”
So if you have a fn signature fn T t => T
(sorry about the syntax) where T
is some type, then this fn can only do one thing.
in Haskell yes, in Clojure we don't have this
if you have a fn signature fn Int i => Int
you have a function that can do an infinite amount of things
So if you have (map (partial ...) foos)
you know that you’re only binding parameters, whereas if you have
(map #(….) foos)
anything can happen.
I don't really see the improvement. (partial foobar 3)
or #(foobar 3 %)
convey the same information and don't guarantee anything about potential side effects
partial returns a closure. e.g. (partial foobar x)
will capture x at one point in time. any changes to x
won't be seen in that closure. which prohibits REPL-driven development.
My point is that the moment I see partial
I can almost ignore the rest, but I have to read #(…)
to the end to see that there is nothing else going on.
Right, didn’t consider that one.
I didn't know about not seeing the redef of foo
I'm not saying: always use this or that, but a linter will say that and this is where I see not many people using it in the long run
that is a sneaky gotcha
I tend to do C-c C-k
in emacs which solves the redef of foo
I do that too (so hopefully that works)
not if foo
is from another namespace, unless you're into the entire REPL reloaded workflow
I only really do C-x C-e when I'm doing stuff in rich comment blocks
anyway, good night all 😉
Is the grownup telling us to go to bed?
Sounds like good advice.
Good night
I don't like partial because it obscures the arguments expected by the new function you've created. I've ended up in a muddle because of that many times.
when you choose partial
you are signalling that you expect at least two different arities, and that is a feature,
seems to me