This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
- # announcements (5)
- # babashka (1)
- # beginners (193)
- # calva (79)
- # cider (18)
- # clara (4)
- # clojure (38)
- # clojure-europe (12)
- # clojure-france (8)
- # clojure-nl (12)
- # clojure-sweden (1)
- # clojure-uk (50)
- # clojurescript (37)
- # conjure (30)
- # cursive (3)
- # data-science (2)
- # datalog (7)
- # datomic (12)
- # events (2)
- # expound (3)
- # figwheel-main (1)
- # fulcro (45)
- # graalvm (1)
- # jobs (1)
- # jobs-discuss (11)
- # luminus (1)
- # malli (5)
- # off-topic (32)
- # reagent (6)
- # reitit (32)
- # shadow-cljs (25)
- # spacemacs (2)
- # sql (22)
- # vim (6)
I've started to see a bit more
letfn in my travels around the clojure codespace. Do people find them useful?
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.
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))
I see, so in
a you're forward referencing
b even although it's not defined just yet.
Would it be a considered a code smell? (apart from the usecase referenced by Rick)?
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 ,,,] ,,,)
Just checked and
letfn (not even in issues) so it seems in eight+ years nobody has thought using it is particularly smelly
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.
I think the main argument against using it, is that it’s less familiar to people than
let is more general; though some may consider the extra specificity of it as a benefit
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.
I tend to just define the helper at the top of a regular let since there's usually other bindings
well, it's not bad to use it, just unnecessary. I think a warning might be a bit too much
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 😄
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
that is ok.... instead of having the conversation of morning... no here where I am it is not morning we just discuss UGT instead