It's very handy that :keywords act as functions and maps do too:
(:start voyage) => 5
(voyage :start) => 5
It's idiomatic Clojure, I think. I've been experimenting with a style of
top-down TDD that puts off deciding about the "shape" of data as long as one
can. [I hasten to add this is not a style for all problems: it's not what you'd
use to come up with clojure.zip, for example.] Since Midje currently only lets
you stub out vars, not keywords, using that particular style leaves you with
code like this:
(def start :start)
(def end :end)
(def circular? [voyage)
(= (start voyage) (end voyage)))
"Stubbing out keywords" can be done, which would give you the more (I think)
idiomatic:
(def circular? [voyage)
(= (:start voyage) (:end voyage)))
Question is: should I invest in doing it? Which depends on how much it's worth.
Which leads to two questions:
* Is the `def start :start` alternative so offensive to your eye that it'd make
you reluctant to try top-down TDD? (Note that the keyword-ey variant comes out
just fine from bottom-up TDD.) That matters to me, because after a decade of
not understanding top-down TDD, I finally did, so I have the zeal of the
convert.
* What does it mean - to the reader - to see (:start voyage) in code as opposed
to (start voyage)? What expectations does (start voyage) set up that (:start
voyage) wouldn't? Midje is supposed to help with the whole
principle-of-least-surprise thing.
** (:start voyage) could just mean "I didn't want to bother to write an
accessor function".
** It could mean that voyage is a composite object with a distinct piece that
is its start, as opposed to a calculation of some sort, and that the difference
between the two is important. I'm wondering, though, if that distinction really
makes sense. There is, first, the hoary old encapsulation argument: that you
use explicit getters and setters on a Point so that the caller needn't care
whether the underlying coordinates are cartesian or polar. And especially in a
context of pure functions, where (f constant) will always have the same value,
whether that's a stored, calculated, or calculated-and-memoized value seems
irrelevant.
** It could mean "there are no nasty surprises here". I vividly remember
debugging a Smalltalk program and discovering what I'd been ignoring as a
simple getter actually had hundreds of lines of code behind it. Using a keyword
as a getter wouldn't have misled me so. (:start voyage) also makes it clear
that the code is fast, whereas (start voyage) allows for anything - perhaps a
leisurely calculation involving database queries.
++ It could mean: "Picking good names is hard. Many words in English can be
either a noun or a verb. Does (start voyage) mean 'commence traveling' or 'make
a property of the voyage available'? (:start voyage) eliminates the possibility
of that confusion, saving me some mental name-picking anguish."
I'm interested in what you think when you see a keyword, and what it would mean
if you didn't.
(Sorry for the long note, but this way I get to use some of my B.A 1981,
English Literature, background!
http://en.wikipedia.org/wiki/Reader-response_criticism
-----
Brian Marick, Artisanal Labrador
Contract programming in Ruby and Clojure
Occasional consulting on Agile
www.exampler.com, www.twitter.com/marick
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en