Whilst trying to minimise the visible surface areas of namespaces, I've often felt the need for a def- function/macro that marks a def'ed var with :private metadata. An analog of defn-, if you will.
Is there a reason that I shouldn't do this or a reason that it doesn't seem to be a member of the core lib?
In the spirit of Hunt & Thomas' "Select isn't broken", when I encounter something this trivial, useful and absent I tend to conclude that I'm the one who's got things wrong.
Thanks in advance,
Rob.
Clojure 1.2: (def ^{:private true} size 25)
Clojure 1.3: (def ^:private size 25)
I think probably the reason against it is that generally there is not
as much reason to use a constant, for example, outside of its
namespace as there is with functions, and therefore more need for
marking functions meant only for internal use as such (but that is
just guessing at other peoples' thought processes).
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clo...@googlegroups.com
> Note that posts from new members are moderated - please be patient with your first post.
> To unsubscribe from this group, send email to
> clojure+u...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
+1
I add the private meta-data by hand, but (defn- foo 2) is so much more succinct than (def ^:private foo 2) - where ^:private is almost half the declaration. I also find the placement of the meta-data tag to be intrusive and disruptive when reading... but that's just a personal peccadillo.
I find your comments that you don't feel as much need to mark defs as private as often as defns really interesting, because it is quite different to my own practice. I tend to look at ^:private primarily as a way to inform users of a namespace that this def is something they can safely ignore because it is an implementation detail; you only need to pay attention to this if you're going to modify the code.
I've spent 5 mins looking at random source files from a few clojure projects and I seem to use more defs than most people. I tend to pull out a fairly high percentage of literals into expanatory defs, whereas the small sample of files that I trolled through seemed to have a different feel for the tipping point when a def is appropriate.
I am surprised at other comments in this chain where people would rather see the removal of def- than the addition of additional variants of def derivatives. I'm not arguing that I'm right, or that things should change, but personally I feel that controlling the exposed surface area of an API is crucial to comprehensibility and maintainability, and that making minimisation of surface area as trivial as possible will benefit us all.
Thanks to everyone for taking the time to write down their thoughts,
R.
Sent from my iPad
(def ^:private ^:dynamic foo …)
I'm guessing we haven't seen the last of the ^:bar sort of var metadata.
- Chas
We will see this subject line in this mailing list every few months until the end of time, or until def- is added to core.
The burden, no matter how distributed, of answering that question forevermore greatly outweighs the burden of moving a def- macro from a contrib file to a core file. It even outweighs the aesthetic concerns (which I confess I don't understand).
-----
Brian Marick, Artisanal Labrador
Contract programming in Ruby and Clojure
Occasional consulting on Agile
www.exampler.com, www.twitter.com/marick
So be it.
> The burden, no matter how distributed, of answering that question forevermore greatly outweighs the burden of moving a def- macro from a contrib file to a core file. It even outweighs the aesthetic concerns (which I confess I don't understand).
Alan covered the biggest problem succinctly: it pollutes the language core to provide convenience APIs that are combinatorial in nature.
I don't really think the people that want def- need it in the language core. They just want to know where to get it, and maybe automatically include it in their own projects. So make a community-centralized, maven-ready, CI-friendly place to put such things. In fact: such a place already exists: https://github.com/clojure/core.incubator. Add a slew of custom def forms to incubator.clj and party on.
Stu
I mean this in the friendliest and most supportive possible way, but since Justin Gehtland recently called me an iconoclast, I am obliged:
The API already contains `find` and `contains?`, which are woefully misleading names. That's not a big deal: I'm *terrible* at naming. I tell people that all the time. I've learned to accept it. It doesn't detract from my wonderfulness. It doesn't detract from the underlying wonderfulness of the software I produce. It just means I have to rethink and revise names, especially after other people use them and say "WTF??".
It's a shame it's too late to do that for `find` and `contains?`. Fortunately, additions are easier than changes.
I hope `def-` hasn't become an issue of pride, a matter of digging in. I sense it has. I hope `def` is not a matter of saying "But if we make this one exception, we have no principled reason to reject any other exception." That's not how human negotiation and communication works.
I really think `def-` would be a good gesture, a minor but emblematic step on the way to widespread acceptance of Clojure, which (for my sake) I really, really, really hope for.
This argument supports my position, not yours. It is much easier to revise names in an incubator library, rather than experimenting in core.
> I really think `def-` would be a good gesture, a minor but emblematic step on the way to widespread acceptance of Clojure, which (for my sake) I really, really, really hope for.
I don't understand how a casual approach to adding things to core would be a good gesture to anybody. Can you send me a list of languages that add features to core after this level of discussion (and without clear agreement) because some people find them useful? I am not aware of any.
To restate my earlier point: "Why isn't this in core?" and "Why isn't this conveniently available to me?" are very different questions. If you have a problem that can be trivially solved outside of core, why are you in such a hurry to change core? Making unnecessary changes at the bottom strikes me as bad design and bad stewardship.
Here's a thought experiment: There is a ton of useful stuff in my .emacs file. I can think of a few dozen things in my .emacs file that are in the "def-" category for me, e.g. I like them, and I want them around always, and immediately when I launch. So those things are core to me. What do you think would happen if I joined the emacs dev list, picked my very favorite convenience, and said "please add this to emacs core?" Emacs doesn't work that way. It is modular, and people solve problems in *libraries*. Sometimes large groups of people agree about certain things. Even then you often get awesome tools like the emacs starter kit *without* changes to emacs core.
The clojure.core namespace evolves at the speed of design, not at the speed of itch-scratching. I think this is a fundamental value.
Stu
Alan covered the biggest problem succinctly: it pollutes the language core to provide convenience APIs that are combinatorial in nature.
Fair enough. Maybe pollution wasn't the best word. Introducing a combinatorial set of names is a [some other word for bad thing] for core, even if we agree what the names mean.
> I think the big issue here is
I think that the big issue here is that we do not agree on how careful the dev team should be about adding things to core. I think we should be quite careful. The name is "core" not "kitchen-sink". If anything, core is already too big.
> that certain functions in Clojure core *imply* the existence of other certain functions in the core. When they don't exist, it comes as a surprise. Surprise is bad.
Agreed, but this is how you argue for a complete set, not for a convenient subset. No one seems to be asking for defmacro-, even though core itself defines a private macro.
> defn- implies the existence of def-
Then let us deprecate defn-.
> The other example that immediately leaps to mind is that the family of get-in, get, and update-in implies the existence of update. It is rather startling to me that update does not exist in the core.
This is a good question. I don't know why I never noticed its absence. Have other people missed this?
Stu
>> The other example that immediately leaps to mind is that the family of get-in, get, and update-in implies the existence of update. It is rather startling to me that update does not exist in the core.
>
> This is a good question. I don't know why I never noticed its absence. Have other people missed this?
What would an `update` function do? update-in is for swapping out a value accessible via a particular "chain" of keys. Dropping the -in suffix implies to me that `update` would operate on the top-level data structure, but that's what assoc/dissoc/conj do already.
- Chas
a) Clojure's declare before use semantics make ordering technically important rather than simply a matter of aesthetic or conceptual grouping.
b) If I have several constants, trying to scope them only to the functions that use them isn't easy/always possible.
c) I have assumed ( based on no evidence ) that Clojure would be lazy enough to defer initialisation of def'd items until they were used, but a top level let would always have to be executed at file load time.
d) I find that indenting almost the whole file because it is inside the let.. displeasing. But not indenting it is worse. I'm a bit neurotic about layout.
if you think it is a good practice, I might well have another try at it and see if I can make peace with it.
R.
I really like the comparison core/kitchen sink :)))
I find it appropriate.
It never really bothered me to require an external lib to get these
fancy definitions. And I use them every where ....
Core should restricted to ... core things. What makes Clojure run by itself.
Syntactic sugar needs to hosted elsewhere. def- and similar are just that,
syntactic sugar. They're not needed to get Clojure up and running.
And yes, defn- should be located elsewhere than in core. +1 for moving it
out of core, at least, defn- should not be make publicly available by core.
By the time we get Clojure written in itself, the core has to be cleaned up of
non-essential things and moved to layers were implementation differences have less/no impacts
while helping shrink it.
Luc P.
--
Luc P.
================
The rabid Muppet
What really puzzles me is that it doesn't seem to be generally
regarded as idiomatic Clojure style to just use top-level (let)s for
your "private" globals. This has lots of benefits:
- If you do this you can make them actually, genuinely private, rather
than just marked as "please don't use this"
- You get more self-documenting source code: (let [x 1] (defn foo []
(...use x...))) is clear about how and where x will be used, while
(def- x 1) (defn foo [] (...use x...)) leaves open the possibility
that x is important all over the namespace.
- You avoid runtime var-deref costs for constants that will never
change.
I find this style so useful and readable that I'm curious why it isn't
more popular in the community at large.
I'm of more or less the opposite appearance: anything that core itself
uses, and that therefore already exists in core, and that is likely to
be useful to a significant number of users, ought to be public.
Otherwise it will end up wastefully duplicated in core and at least
one third-party library, and there might even be a lot of
wheel-reinvention -- with some of them probably turning out square.
--
Protege: What is this seething mass of parentheses?!
Master: Your father's Lisp REPL. This is the language of a true
hacker. Not as clumsy or random as C++; a language for a more
civilized age.
A self contained complete starter env (e.g. including all the modular contribs) is a good idea. It should not be core.
Stu
I’m not sure that Clojure needs something as packaged as the Haskell Platform (http://hackage.haskell.org/platform/), and it certainly should not be part of core.
I would say about half the calls to update-in I've written took literal
vectors with one expression in them. Including the two earlier today.
While I noticed `update' was missing, it didn't bother me.
--
Stephen Compall
^aCollection allSatisfy: [:each|aCondition]: less is better