clojure-uk

A place for people in the UK, near the UK, visiting the UK, planning to visit the UK or just vaguely interested to randomly chat about things (often vi and emacs, occasionally clojure). More general the #ldnclj
mccraigmccraig 2020-08-12T06:47:30.306300Z

måning

dharrigan 2020-08-12T07:09:20.306500Z

Good Morning!

jiriknesl 2020-08-12T07:11:35.306700Z

Good morning

dominicm 2020-08-12T08:01:59.306900Z

Morning 🌄

dharrigan 2020-08-12T08:20:27.307700Z

I've started to see a bit more letfn in my travels around the clojure codespace. Do people find them useful?

dominicm 2020-08-12T08:20:45.308Z

Not really. I rarely see them.

Jakob Durstberger 2020-08-12T08:26:58.309100Z

Good Morning ☀️ 🔥 💀

2020-08-12T08:28:11.309200Z

I use them from time to time; though often you end up needing a let anyway if you need more non function bindings. They can be good for implementing localised statemachines that close over some common bindings.

2020-08-12T08:31:02.309400Z

Unlike def they support forward declaration, so they’re good at handling mutual recursion etc e.g. forward declaration:

(letfn [(a [] (println :a) (b)) (b [] (println :b))] (a))

2020-08-12T08:32:39.309700Z

mutual recursion makes them quite good for parsers etc

alexlynham 2020-08-12T08:37:06.309900Z

morning

alexlynham 2020-08-12T08:37:25.310Z

I don't think I've ever used a letfn in production code

dharrigan 2020-08-12T08:42:01.310100Z

I see, so in a you're forward referencing b even although it's not defined just yet.

dharrigan 2020-08-12T08:42:58.310800Z

Would it be a considered a code smell? (apart from the usecase referenced by Rick)?

alexlynham 2020-08-12T08:51:31.310900Z

idk I tend to consider anything that's not super primitive a code smell haha

alexlynham 2020-08-12T08:52:01.311Z

i try to write code that i can debug while tired, under stress cos prod is down

alexlynham 2020-08-12T08:52:05.311100Z

:D

2020-08-12T09:03:05.311200Z

:thumbsup:

2020-08-12T09:12:06.316Z

Even though a let in that case is arguably a little better I personally wouldn’t really consider it a code smell if it was a standalone letfn it’s something I’d probably only change if you ended up needing to add new bindings that would mean you had something like (let [bar ,,,] (letfn [(foo [] ,,,)],,,)) in which case I’d wait till that point before refactoring it into (let [foo (fn [] ,,,) bar ,,,] ,,,)

2020-08-12T09:23:38.318200Z

Just checked and https://github.com/bbatsov/clojure-style-guide doesn’t mention letfn (not even in issues) so it seems in eight+ years nobody has thought using it is particularly smelly

2020-08-12T09:25:24.320100Z

clj-kondo also doesn’t seem to lint it as a potential smell either; though it does check it’s used properly… clj-kondo could easily check it was only used for forward declaration or mutually recursive uses; so if it’s something you care about, you could possibly open an issue on that repo for discussion.

2020-08-12T09:26:01.320600Z

I think the main argument against using it, is that it’s less familiar to people than let and let is more general; though some may consider the extra specificity of it as a benefit

2020-08-12T09:35:05.325500Z

Just scanned one of our larger code bases for uses of it, and it’s currently used in two places… none of which use it for forward declaration or mutual recursion…. both cases define it immediately at the top of the function definition to define a localised helper function that closes over some of the outer arguments; and that helper is repeatedly used multiple times within the body. Personally I think this can be a good use of it, as the letfn makes it very clear that the helper is local where as merging it into the let it wraps would hide the helpers important role.

alexlynham 2020-08-12T09:51:19.330300Z

I tend to just define the helper at the top of a regular let since there's usually other bindings

alexlynham 2020-08-12T09:51:36.330400Z

tho i'm sure you can find examples in code where i totally break that rule

borkdude 2020-08-12T10:42:08.330700Z

I would use letfn for mutually recursive functions, not for anything else

2020-08-12T11:02:48.330800Z

would you consider adding a lint for it to clj-kondo?

borkdude 2020-08-12T11:03:54.331Z

well, it's not bad to use it, just unnecessary. I think a warning might be a bit too much

2020-08-12T11:04:22.331200Z

Yeah that’s my feeling too

2020-08-12T11:04:50.331400Z

it’s not particularly hard to read; and it’s not very commonly used anyway

dharrigan 2020-08-12T11:33:09.331800Z

Thanks everyone! A very informative disscussion!

alexlynham 2020-08-12T11:43:32.331900Z

possibly sacrilige here but I'm enjoying peering into purescript JS dev

👿 1
1
alexlynham 2020-08-12T11:43:39.332Z

halogen is p like re-frame

alexlynham 2020-08-12T11:43:51.332100Z

you can really see the ML <-> lisp connection in the DSL

thomas 2020-08-12T13:01:42.332600Z

morning

Jakob Durstberger 2020-08-12T14:54:07.333800Z

I have looked into Haskell and Purescript with Halogen a lot last year and in the end I found myself fighting against the typechecker a lot. I was really excited about this whole idea of explicit side effects until I tried to build actual software 😄

alexlynham 2020-08-12T15:09:23.334700Z

yeah that's largely been my experience too

alexlynham 2020-08-12T15:10:42.334800Z

but although I love re-frame I've often found cljs pretty difficult to love (although shadow has massively improved that tbf) and types in node land make a fair bit of sense, as well as being able to do monadic stuff around asyncs and whatnot

2020-08-12T16:30:00.335Z

Morn

2020-08-12T19:53:50.335100Z

Bro it's 5.30pm

thomas 2020-08-12T19:54:52.335300Z

We run UGT here, so morning is perfectly fine

thomas 2020-08-12T19:55:38.335500Z

http://www.total-knowledge.com/~ilya/mips/ugt.html

2020-08-12T19:55:53.335700Z

But I think he's in Cambridge 😂

thomas 2020-08-12T19:57:07.335900Z

that is the beauty of UGT, it doesn't matter where you are.

2020-08-12T19:57:21.336100Z

Oh I wasn't aware of Universal Greeting time

thomas 2020-08-12T19:57:23.336300Z

nor where anyone else is

2020-08-12T19:57:30.336500Z

Good morning then

thomas 2020-08-12T19:58:08.336700Z

that is ok.... instead of having the conversation of morning... no here where I am it is not morning we just discuss UGT instead

thomas 2020-08-12T19:58:10.336900Z

🙂

2020-08-12T22:02:09.337100Z

Yep, that's pretty much how it works 😃... @zyxmndaleyjes ;)...