This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-02-04
Channels
- # announcements (1)
- # architecture (16)
- # asami (30)
- # babashka (1)
- # beginners (17)
- # calva (4)
- # clj-kondo (4)
- # clojure (32)
- # clojure-austin (2)
- # clojure-dev (16)
- # clojure-europe (33)
- # clojure-mexico (1)
- # clojurescript (40)
- # data-science (9)
- # emacs (33)
- # fulcro (1)
- # jackdaw (4)
- # malli (25)
- # off-topic (34)
- # pathom (23)
- # react (16)
- # reagent (8)
- # releases (5)
- # vim (46)
Question for library designers: Hypothetically, lets say you have a namespace for sequence
related helper functions and a namespace for map
related helper functions.
You now create a function that takes a sequence
and outputs a map
(e.g. group-by
). Would you put it in the map
namespace or the sequence
namespace or do something else all together?
• Arguments for the sequence
namespace:
◦ The input is a sequence
- so it's near other functions that also have sequences as inputs.
• Arguments for the map
namespace
◦ The output is a map
- so it's near other functions that also create maps.
◦ In Clojure there is only one output (returned value), but there could be several input arguments. So classifying by output is unambiguous - whilst classifying by input is ambiguous (e.g. group-by
takes a function and a sequence
).
What do you think? I guess this comes down to namespaces are hierarchical - so ultimately there are compromises when things don't neatly fit into that structure.
Namespaces aren't hierarchical, if that gets you out of your pickle. They're a graph.
Agree they're not strictly hierarchical, but they are mutually exclusive so a function is in namespace A or B (it's confusing if it's in both).
https://stuartsierra.com/2011/08/08/clojure-namespaces mentioned this dilemma
Thanks for the link - will have read through it.
Yes, one big namespace could be an option or find the commonality (e.g. sequence
and map
are both collections
).
We have a 1k line “utils” namespace at my job lol
Namespaces, especially for libraries, should align to use cases for consumers or they should be private. There’s no project where I’m working on maps or working on sequences. These shouldn’t be separate.
Just to share one datapoint: I've gotten a lot of mileage out of creating namespaces grouped by kind. I find the approach works best if you choose a namespace aliasing convention that identifies the context. For example, if your util namespace has lots of functions like blank-string?
or trim-string
I would argue that you already felt the need to highlight the context (but you're doing it as a prefix or suffix). So I would make a [app.util.string :as string]
and then in your code call string/blank?
or string/trim
. (Yes, I'm aware of clojure.string
, but it's just an example :))
Now, I'm not saying that every noun in my codebase has a separate namespace. There are several different needs for grouping:
• clustering around a specific noun/model (e.g. all string and uuid operations),
• collecting a set of disjoint alternatives (e.g. different hashing algorithms),
• hiding a complex operation (lots of helper functions and one function at the end that is part of the "public api"),
• describing some kind of domain hierarchy (parent/child relationships via sub-namespaces),
• identifying independent ownership (ie. the reverse-domain conventions)
• and so forth.
But in practice we only have one technical way to do all of the above: the namespace as segments split by .
In a way, it's a form of overloaded polymorphism. And naming is hard. :)
Supporting that idea and contradicting my own, we have clojure.set and clojure.string.
clojure.string seems to exists solely because of the clash with replace. All the regex functions are in core. I’m all for namespaces existing for pragmatic reasons like dealing with external library clashes, but within a single project, especially for something that is probably used in close to 100% of projects, I think you could have just used a prefix.
Part of the problem obviously is maintainers and users often have different mental models of libraries. I quite like it when libs go to the effort of packaging things up into a facade namespace of some sort. But if the user mental model is very type-based the it’s fine to reflect that, I guess.
> clojure.string seems to exists solely because of the clash with replace
clojure.string
namespace was added 2 years after clojure.core
string functions (like clojure.core/re-seq
). So it might have just been added because they wanted to add bunch of new string functions without cluttering the clojure.core
namespace - but didn't want to break backwards compatibility by moving old functions into the new clojure.string
namespace.
I think a prefix can be useful but would be pretty messy (e.g. clojure.string/upper-case
-> clojure.core/string-upper-case
) - if you go down the prefixing route you end up with something similar to PHP's or Excel's function library which aren't the most revered.
If you go down the prefix route - you still have the dilemma that I have which is what the prefix should be (e.g. should it be sequence-
or map-
for a function that takes a sequence and emits a map (like group-by
).
Thanks all for the responses. Seems there's no straightforward rule for this - so library writers need to balance the benefits and trade offs on a case by case basis. I would agree with@U05476190 that "naming is hard." !