It seems the last discussion on namespaces was not clear yet (62 comments point at it) Looking at trees in nature they π²π΄ they do not have branches or roots ginger_root root_vegetable which do not serve any purpose or are not alive. If we make the var itself the module that leads to smaller programs without unused code and the function call graph is equal to the dependency graph then. Tooling it not there yet and deployment artifacts. So vars/namespaces would have to disappear and maybe just 'form' call the new atomic code unit. Also editors would need to change. Or I just don't get namespaces please prove me wrong.
It was pretty clearly stated in the thread by multiple parties that there is no real reduction of complexity/increased program tractability by having functions be 1-to-1 with namespaces. Frankly, I'm sympathetic to the notion that it would increase complexity by imploding commonly used idioms for hierarchically organising code by the concerns it addresses. >trees in nature Software libraries and the programs built from them are not individual instances of arboreal trees or rhizomes, even though your example falls apart because one can find vestigial or dead roots on plants due to evolutionary pressure and soil conditions, and that the liveness of a node on your dependency/call graph has nothing to do with everyone else's. If a library provides a suite of functions, I would like to be able access functions sharing the same general domain of responsibility under a single namespace, and am pretty taken aback at the suggestion that I should geometrically increase the number of requires in my code, resulting in a tangible decrease in readability because now I have to reference 50 separate files to read my way through the call-stack instead of 1-5 in exchange for a few kB that no one missed to begin with. Why should I factor out helper functions into their own nses and incrementally require them to conform to this pattern, when they're all going to be depended on by the caller of the final function anyway? Because of a Naturalistic Fallacy? I don't mind if someone wants to play code golf with the size of their compiled artefact, but I have a hard time seeing why I should be held to that standard when there is no real engineering benefit to it. They way you talk about small binary sizes and graph isomorphisms sound more motivated by abstract personal aesthetics than the need to address a particular theoretical or engineering problem in context. As Ben Sless pointed out, if you really cared about dead code elimination that much, a tree shaker would be far better to implement and of far more use to everyone else than re-architecting the entire language and overturning decades of idioms to enforce one (questionable) interpretation of how namespaces should be employed. P.S. there was no real need to make this a new thread, you could have just replied to the previous one.
You asked the same question just a couple of months ago, and got pretty much the same answer: it's a bad idea in Clojure. https://clojurians.slack.com/archives/C03S1KBA2/p1780981948858489
I don't know if this will shake your brain enough, but here is a language that at one level does what you are suggesting: https://elm-lang.org/
There are still libraries and modules, but because dynamism is so heavily restricted the compiler can reliably tree shake down to the individual function. That is a benefit gained by accepting a fairly harsh restriction
To get that benefit in languages that allow for significant dynamism (like Java, JavaScript, Python, Clojure, etc.) you need to either β’ Make an assumption that said dynamism will not be relied upon β’ Manually bundle things into very small units (like https://github.com/lodash/lodash/tree/main)
A namespace is a mechanism to group functions with a strong cohesion. You could use other mechanisms like the folder structure or a database or jar files for grouping. That does not really matter. Most developers prefer namespaces, because then they have all these things on one screen and they can scroll up or down, which for most people is a very intuitive way for representing something.
I guess it's also a stylistic choice where to place vars. It differs between projects and teams. At the end of the day it's the vars which are the main unit of code and namespace just a bag. You are right that folders would still group vars if each is in a different place. In my experience it is more fun if I don't see anything not concerned with the current function at hand, I want no context to understand something than the function itself and it's direct dependencies.
You can have everything organised in a flat way without namespaces. I know this from Fortran at work. For me it is really hard to work without any hirarchical structure. So I am happy to have something like namespaces. You should read what cohesion means. It is a principle concept of software design. Things that belong together should be together. If you e.g. implement a stack you want to have the pop operation next to the push operation, because they share the same concepts. One helps to understand the other. And one alone is does not make sense. You have things in a namespace, because you want to see and probably use them always together. If you implement Tetris you want the shape of the blocks in one place so that it is easy for you to get an overview of what blocks exist.
I am building a game engine and an editor on a widget base for all data types we need tooltips, editor widgets , live game runtime state widgets, so I created a folder for each data type with all it's behaviors for different concerns (they are dispatched by type) It wouldn't make sense to have it the same namespace ui widget creation, tooltip texts, runtime state validation, etc )
Too many concerns basically forced this architecture on me
Yes that is a good example where namespaces dont make much sense. You must decide wether you group things that share similar algorithms (in OOP you would use the visitor pattern) or that share the same data (in OOP you would define a class). Luckily Clojure does not require much acrobatic from you, so you can do what fits for you. But I think your situation in not typical for Clojure. I came from OOP and thought a lot in classes and encapsulation and had suffered the problems of these concepts. So I am happy that I dont need this any more. Maybe you are trying to avoid everything, which is far similar to OOP. Could this be? But going away from namespaces for me would be too much. You should not go too far and deny everything. Namespaces are not the evil thing, that classes are. You cannot instantiate a namespace.
I have tried organizing noun namespace with verbs or verb with all nouns but both is not right if there are too many concerns
I understand you that you have types and behaviours. You have to make a decision wether you organise your things by types or by behaviours and wether to call that a namespace. In OOP you have to make the decision according to where you expect changes. If you change a behavior and your structure is by types, you have to change all types. Not good. If your structure is by behaviour and you change one behavior, you only have to change it in one place (for all typed together). Better. So you have to speculate the future. In OOP we are so conerned of such important decisions, because a wrong decision causes much maintenance cost. But in Clojure this is not relevant. Because for examole multimethods can dispatch on anythig you like. So you can organise your things however you like. It makes no difference. If you are happy without namespaces, perfect.
I've only recently encountered SIMD from the Mitchell Hashimoto blog post and I noticed that there is some support for this in the JVM. It looks to me like SIMD operates on the how of implementation, whereas my subjective experience of FP is that it is more about the what of implementation. (I hope that makes sense π ) Since there is so much experience here; Have you applied SIMD in clojure code? I'm curious about practical use-cases, the opportunity for getting more out of existing hardware, and about mixing SIMD with "normal" map/reduce style processing.
isn't the Java Vector API still in incubation? I don't think SIMD would work with "normal" Clojure code as persistent vectors aren't contiguous arrays in memory
included in JDK 26 it seems, so has released this year
I had the same intuition. In a way it feels like this is a case of "impedance mismatch" between FP and SIMD (?)
I haven't tried it, but gut feeling says marshaling from/to Vector API arrays would make it difficult to integrate and get perf benefits... but I guess some very specialized number crunching use-case would benefit
I forget to paste the link to the blog post: https://mitchellh.com/writing/everyone-should-know-simd.
String parsing using SIMD is great stuff, the entire world will benefit
do you have an example of SIMD in Clojure for string parsing? or just in general
Just in general - SIMD JSON parsing is the best example
https://github.com/techascent/tech.ml.dataset is great, love it, use it all the time (but I am a professional number cruncher). IIRC the backing library (https://github.com/cnuernber/dtype-next) doesn't use SIMD (yet?) but is explicitly an implementation of contiguous in-memory arrays of primitive types that shows how such things can be incorporated into a more "functional" paradigm. worth checking out if you haven't already: https://www.youtube.com/watch?v=5mUGu4RlwKE
A bit late to the party but Stratum makes heavy use of SIMD and the new Java Vector incubator: https://github.com/replikativ/stratum Similarly https://github.com/replikativ/raster Also uses some
I don't really understand defonce ? It often just ends up messing up my REPL state. You just lose the ability to reload things, and if it contains a class for example, then it can result it a stale class and cause cast class exceptions.
if it contains stuff loaded then itβs helpful. (defonce ^:private initialized (atom #{})),
(defonce ^:private executor
(delay (Executors/newSingleThreadExecutor
(reify ThreadFactory
(newThread [_ r]
(doto (Thread. r)
(.setName "dependency-event-worker")
(.setDaemon true)))))))And what if that atom state gets corrupted and you want to reset it? Or if you've changed the name of the thread?
(def executor nil) and then reeval
I'm often not in the same namespace though, so it's kind of annoying. Or if it's from a library
i donβt find the need to clobber defonces i guess. very infrequent. itβs usually state that i would only care about if i were working in that namespace
defonce rhymes with Beyonce. if used properly it actually avoids that stale class problem (that's one of the primary uses). if clojure restarted faster it wouldn't be as neccessary
Well, the deftype got reloaded, but not the var with an instance of it
defonce rhymes with Deftones
i use potemkin for those types of problems. not redefining the type is very nice
What feature of potemkin prevents reloading the deftype?
It seems with clj-reload you can annotate the deftype so it does not get refreshed. But still, I'm too dumb to pay attention to what I need to mark to not reload and what I can reload. I think I prefer the default to be that my state is also reloaded
it just keeps a copy of itself, and if itβs not changed wonβt reevaluate
i donβt use auto reloader
Oh ya, that is nice haha
also nice for protocol redeifnition
Would be nice actually if the core ones behaved that way
i think i saw Alex talk about interest in approaching that
if you search here you might find it. iβd be interested in seeing his thoughts on it
It's possible most of my defonce woes over the years were all related to this. I also have the alternate issue with defmulti, which secretly doesn't reload, even if it changed
defonce is very useful in CLJS hot-reload/REPL situations too
fwiw you can clobber corrupted state without changing namespaces using alter-var-root
you can switch namespaces without the risk of making broken namespaces by using (doto 'some.ns require in-ns) - the require is a no-op if the ns is loaded properly, but it prevents creating a broken namespaces as in-ns usually would if you hadn't used the ns form first