This is related to the thread titled "Proxying in Clojure". I've spent a lot of time studying the code in this "snake" example and have some observations I'd like to share.
First off, obviously I care about the future of Clojure or I wouldn't have spent the last six weeks or so trying to learn it.
I imagine that almost everyone on this mailing list would like to have the opportunity to spend more time on the job coding in Clojure than they get to currently. One way to make that more likely is to make it easier for others to learn Clojure. You may not be allowed to use it for production code if you're the only one in your company that can understand it.
Many examples of Clojure code work counter to this goal. This snake code is just one of them. I don't mean to pick on the authors. This code is very similar to other Clojure code I encounter daily.
Here are some things I think we could all do in our Clojure code to make it easier for others to understand.
1) There are no prizes for using one letter variable names. Pick more meaningful names.
For example, (defn collision? [{[b] :body} a] ...). What is a? It's a vector containing the x/y coordinates of the apple the snake is trying to eat. Why not name it "apple" or "apple-location"? What is b? It's a vector that represents the x/y coordinates of the head of the snake. Why not name it "head" or "snake-head"?
2) There are no prizes for writing code with zero comments. One of the strengths of Clojure is that you can accomplish a large amount in a small amount of code. That doesn't mean that readers of your code will know what is going on though.
For example, what does this do? (every? #(<= (- (a %) 10) (b %) (+ 10 (a %))) [0 1]) Well, 0 and 1 are indexes of the x and y coordinates represented by two element vectors that represent the location of the apple and the head of the snake. This tests whether every coordinate (the x and y) of the apple are "close" to the corresponding coordinate of the snake head. This certainly needs to be explained in a comment.
3) There are no prizes for cramming loads of functionality into a single line. Spread it out to make it easier to read.
For example, which of these is easier to understand?
I know my placement of the closing parens on separate lines is non-standard in the Lisp world, but I find it helps me see better where constructs end. Without doing that it feels like Python where indentation is significant. I could concede the paren placement though.
Below is the original code. Compare it to my version at http://pastie.org/348031 where variables are renamed, comments are added, and indentation is changed in a way that I feel makes it more readable.
Another example of a fairly short piece of code that is begging for comments is the example at http://clojure.org/concurrent_programming. Imagine someone who has only been learning Clojure for a couple of days and is curious about how Clojure handles concurrency trying to follow what is happening in that code.
So my main point is that if we all make an effort to make our code easier to read, it will be easier to convince other developers to consider learning Clojure which will be good for all of us.
> This is related to the thread titled "Proxying in Clojure". I've spent
> a lot of time studying the code in this "snake" example and have some
> observations I'd like to share.
> First off, obviously I care about the future of Clojure or I wouldn't
> have spent the last six weeks or so trying to learn it.
> I imagine that almost everyone on this mailing list would like to have
> the opportunity to spend more time on the job coding in Clojure than
> they get to currently. One way to make that more likely is to make it
> easier for others to learn Clojure. You may not be allowed to use it
> for production code if you're the only one in your company that can
> understand it.
> Many examples of Clojure code work counter to this goal. This snake
> code is just one of them. I don't mean to pick on the authors. This
> code is very similar to other Clojure code I encounter daily.
> Here are some things I think we could all do in our Clojure code to
> make it easier for others to understand.
> 1) There are no prizes for using one letter variable names. Pick more
> meaningful names.
> For example, (defn collision? [{[b] :body} a] ...).
> What is a? It's a vector containing the x/y coordinates of the apple
> the snake is trying to eat. Why not name it "apple" or
> "apple-location"?
> What is b? It's a vector that represents the x/y coordinates of the
> head of the snake.
> Why not name it "head" or "snake-head"?
> 2) There are no prizes for writing code with zero comments. One of the
> strengths of Clojure is that you can accomplish a large amount in a
> small amount of code. That doesn't mean that readers of your code will
> know what is going on though.
> For example, what does this do?
> (every? #(<= (- (a %) 10) (b %) (+ 10 (a %))) [0 1])
> Well, 0 and 1 are indexes of the x and y coordinates represented by
> two element vectors that represent the location of the apple and the
> head of the snake. This tests whether every coordinate (the x and y)
> of the apple are "close" to the corresponding coordinate of the snake
> head. This certainly needs to be explained in a comment.
> 3) There are no prizes for cramming loads of functionality into a
> single line. Spread it out to make it easier to read.
> For example, which of these is easier to understand?
> I know my placement of the closing parens on separate lines is
> non-standard in the Lisp world, but I find it helps me see better
> where constructs end. Without doing that it feels like Python where
> indentation is significant. I could concede the paren placement
> though.
> Below is the original code. Compare it to my version athttp://pastie.org/348031where variables are renamed, comments are
> added, and indentation is changed in a way that I feel makes it more
> readable.
> Another example of a fairly short piece of code that is begging for
> comments is the example athttp://clojure.org/concurrent_programming.
> Imagine someone who has only been learning Clojure for a couple of
> days and is curious about how Clojure handles concurrency trying to
> follow what is happening in that code.
> So my main point is that if we all make an effort to make our code
> easier to read, it will be easier to convince other developers to
> consider learning Clojure which will be good for all of us.
I'll not argue for making code harder to read, but I have to object to
most of your example.
Making something 4x longer does not make it easier to read.
Redundant comments are useless.
Trailing parens are known bad - don't use them.
Though when first learning you might wish every piece of code had a
built-in language tutorial, I'd be dismayed if, e.g., every use of
proxy contained this redundant description of how it works:
; Create a proxy object that extends JPanel and
; implements both ActionListener and KeyListener.
(proxy [JPanel ActionListener KeyListener]
[] ; arguments to the superclass constructor (none here)
; What follows are implementations of the interface methods.
etc. Most of your comments don't say anything that the code doesn't.
Those that do may be worthwhile, those that don't should not be in non-
tutorial code.
The original code was not intended as a tutorial, nor is most code,
nor should it be.
'X in Y lines of code' examples are inherently trying to be concise,
and probably not the best things to learn from initially.
On Sun, Dec 28, 2008 at 9:15 PM, Rich Hickey <richhic...@gmail.com> wrote:
> On Dec 28, 8:13 pm, "Mark Volkmann" <r.mark.volkm...@gmail.com> wrote: >> This is related to the thread titled "Proxying in Clojure". I've spent >> a lot of time studying the code in this "snake" example and have some >> observations I'd like to share.
>> First off, obviously I care about the future of Clojure or I wouldn't >> have spent the last six weeks or so trying to learn it.
>> I imagine that almost everyone on this mailing list would like to have >> the opportunity to spend more time on the job coding in Clojure than >> they get to currently. One way to make that more likely is to make it >> easier for others to learn Clojure. You may not be allowed to use it >> for production code if you're the only one in your company that can >> understand it.
>> Many examples of Clojure code work counter to this goal. This snake >> code is just one of them. I don't mean to pick on the authors. This >> code is very similar to other Clojure code I encounter daily.
>> Here are some things I think we could all do in our Clojure code to >> make it easier for others to understand.
>> 1) There are no prizes for using one letter variable names. Pick more >> meaningful names.
>> For example, (defn collision? [{[b] :body} a] ...). >> What is a? It's a vector containing the x/y coordinates of the apple >> the snake is trying to eat. Why not name it "apple" or >> "apple-location"? >> What is b? It's a vector that represents the x/y coordinates of the >> head of the snake. >> Why not name it "head" or "snake-head"?
>> 2) There are no prizes for writing code with zero comments. One of the >> strengths of Clojure is that you can accomplish a large amount in a >> small amount of code. That doesn't mean that readers of your code will >> know what is going on though.
>> For example, what does this do? >> (every? #(<= (- (a %) 10) (b %) (+ 10 (a %))) [0 1]) >> Well, 0 and 1 are indexes of the x and y coordinates represented by >> two element vectors that represent the location of the apple and the >> head of the snake. This tests whether every coordinate (the x and y) >> of the apple are "close" to the corresponding coordinate of the snake >> head. This certainly needs to be explained in a comment.
>> 3) There are no prizes for cramming loads of functionality into a >> single line. Spread it out to make it easier to read.
>> For example, which of these is easier to understand?
>> I know my placement of the closing parens on separate lines is >> non-standard in the Lisp world, but I find it helps me see better >> where constructs end. Without doing that it feels like Python where >> indentation is significant. I could concede the paren placement >> though.
>> Below is the original code. Compare it to my version athttp://pastie.org/348031where variables are renamed, comments are >> added, and indentation is changed in a way that I feel makes it more >> readable.
>> Another example of a fairly short piece of code that is begging for >> comments is the example athttp://clojure.org/concurrent_programming. >> Imagine someone who has only been learning Clojure for a couple of >> days and is curious about how Clojure handles concurrency trying to >> follow what is happening in that code.
>> So my main point is that if we all make an effort to make our code >> easier to read, it will be easier to convince other developers to >> consider learning Clojure which will be good for all of us.
> I'll not argue for making code harder to read, but I have to object to > most of your example.
> Making something 4x longer does not make it easier to read.
> Redundant comments are useless.
I agree ... if they are really redundant. For example, I don't feel that explaining the use of [0, 1] to represent indexes for x and y values is redundant.
> Trailing parens are known bad - don't use them.
I'm not disagreeing, but I'd like to hear the explanation for why they are bad. The ones that end defn's seem the same as Java's trailing braces to me.
> Though when first learning you might wish every piece of code had a > built-in language tutorial, I'd be dismayed if, e.g., every use of > proxy contained this redundant description of how it works:
> ; Create a proxy object that extends JPanel and > ; implements both ActionListener and KeyListener. > (proxy [JPanel ActionListener KeyListener] > [] ; arguments to the superclass constructor (none here)
> ; What follows are implementations of the interface methods.
Right. I agree with you there and I did put those in my code because that was my first exposure to Clojure proxies.
> etc. Most of your comments don't say anything that the code doesn't. > Those that do may be worthwhile, those that don't should not be in non- > tutorial code.
> The original code was not intended as a tutorial, nor is most code, > nor should it be.
> 'X in Y lines of code' examples are inherently trying to be concise, > and probably not the best things to learn from initially.
Even a Clojure expert would likely pause for a minute to figure out what is going on in this code in the absence of any comments.
I still think there's a benefit in experienced Clojure developers taking the extra effort to make their code more accessible to Clojure newbies, especially if we want the community to grow.
Speaking for myself, as the author of the original Snake example, I
had no intention of converting developers to Clojure, or of producing
instructive or readable code, with that snippet.
While I agree with some of your critique, I do think it is misplaced.
The aim of this particular exercise was to produce an _abnormally_
terse program, after all.
If you believe there is some utility in producing a more readable
version, as a tutorial, do not hesitate to make one and publish it!
I'll be happy to direct readers to it. :-)
On 12/29/08, Mark Volkmann <r.mark.volkm...@gmail.com> wrote:
> On Sun, Dec 28, 2008 at 9:15 PM, Rich Hickey <richhic...@gmail.com> wrote:
>> On Dec 28, 8:13 pm, "Mark Volkmann" <r.mark.volkm...@gmail.com> wrote:
>>> This is related to the thread titled "Proxying in Clojure". I've spent
>>> a lot of time studying the code in this "snake" example and have some
>>> observations I'd like to share.
>>> First off, obviously I care about the future of Clojure or I wouldn't
>>> have spent the last six weeks or so trying to learn it.
>>> I imagine that almost everyone on this mailing list would like to have
>>> the opportunity to spend more time on the job coding in Clojure than
>>> they get to currently. One way to make that more likely is to make it
>>> easier for others to learn Clojure. You may not be allowed to use it
>>> for production code if you're the only one in your company that can
>>> understand it.
>>> Many examples of Clojure code work counter to this goal. This snake
>>> code is just one of them. I don't mean to pick on the authors. This
>>> code is very similar to other Clojure code I encounter daily.
>>> Here are some things I think we could all do in our Clojure code to
>>> make it easier for others to understand.
>>> 1) There are no prizes for using one letter variable names. Pick more
>>> meaningful names.
>>> For example, (defn collision? [{[b] :body} a] ...).
>>> What is a? It's a vector containing the x/y coordinates of the apple
>>> the snake is trying to eat. Why not name it "apple" or
>>> "apple-location"?
>>> What is b? It's a vector that represents the x/y coordinates of the
>>> head of the snake.
>>> Why not name it "head" or "snake-head"?
>>> 2) There are no prizes for writing code with zero comments. One of the
>>> strengths of Clojure is that you can accomplish a large amount in a
>>> small amount of code. That doesn't mean that readers of your code will
>>> know what is going on though.
>>> For example, what does this do?
>>> (every? #(<= (- (a %) 10) (b %) (+ 10 (a %))) [0 1])
>>> Well, 0 and 1 are indexes of the x and y coordinates represented by
>>> two element vectors that represent the location of the apple and the
>>> head of the snake. This tests whether every coordinate (the x and y)
>>> of the apple are "close" to the corresponding coordinate of the snake
>>> head. This certainly needs to be explained in a comment.
>>> 3) There are no prizes for cramming loads of functionality into a
>>> single line. Spread it out to make it easier to read.
>>> For example, which of these is easier to understand?
>>> I know my placement of the closing parens on separate lines is
>>> non-standard in the Lisp world, but I find it helps me see better
>>> where constructs end. Without doing that it feels like Python where
>>> indentation is significant. I could concede the paren placement
>>> though.
>>> Below is the original code. Compare it to my version
>>> athttp://pastie.org/348031where variables are renamed, comments are
>>> added, and indentation is changed in a way that I feel makes it more
>>> readable.
>>> Another example of a fairly short piece of code that is begging for
>>> comments is the example athttp://clojure.org/concurrent_programming.
>>> Imagine someone who has only been learning Clojure for a couple of
>>> days and is curious about how Clojure handles concurrency trying to
>>> follow what is happening in that code.
>>> So my main point is that if we all make an effort to make our code
>>> easier to read, it will be easier to convince other developers to
>>> consider learning Clojure which will be good for all of us.
>> I'll not argue for making code harder to read, but I have to object to
>> most of your example.
>> Making something 4x longer does not make it easier to read.
>> Redundant comments are useless.
> I agree ... if they are really redundant. For example, I don't feel
> that explaining the use of [0, 1] to represent indexes for x and y
> values is redundant.
>> Trailing parens are known bad - don't use them.
> I'm not disagreeing, but I'd like to hear the explanation for why they
> are bad. The ones that end defn's seem the same as Java's trailing
> braces to me.
>> Though when first learning you might wish every piece of code had a
>> built-in language tutorial, I'd be dismayed if, e.g., every use of
>> proxy contained this redundant description of how it works:
>> ; Create a proxy object that extends JPanel and
>> ; implements both ActionListener and KeyListener.
>> (proxy [JPanel ActionListener KeyListener]
>> [] ; arguments to the superclass constructor (none here)
>> ; What follows are implementations of the interface methods.
> Right. I agree with you there and I did put those in my code because
> that was my first exposure to Clojure proxies.
>> etc. Most of your comments don't say anything that the code doesn't.
>> Those that do may be worthwhile, those that don't should not be in non-
>> tutorial code.
>> The original code was not intended as a tutorial, nor is most code,
>> nor should it be.
>> 'X in Y lines of code' examples are inherently trying to be concise,
>> and probably not the best things to learn from initially.
> Even a Clojure expert would likely pause for a minute to figure out
> what is going on in this code in the absence of any comments.
> I still think there's a benefit in experienced Clojure developers
> taking the extra effort to make their code more accessible to Clojure
> newbies, especially if we want the community to grow.
Mark, Thanks so much for pointing that out, it makes Clojure to belong to others. Clojure should not be only for FP experts and PH.D holders. I took time to check the background of some members in this group: we have lecturers, research scientists and others from the best technical schools. I know that for such people simplifying(through commenting and spreading codes by using methods) Clojure may kill their brain "cells". But for me and other mere mortals we need such help and as I see Clojure it may become another phenomenon in the rank of Ruby.
I think that just as important as "compactness" is the issue of
"density": the ratio
of the "conceptual weight"of the computation to the size of the code
expressing it.
if a computation is inherently complicated and I manage to squeeze it
into
a few lines (typically accomplished via an intense cognitive effort)
the resulting
code is usually hard to understand/maintain/debug because you need to
be
acquainted with all sorts of little truths and insights which are not
obvious for the casual
reader. This is what I call a high density code.
Given that Clojure is a very powerful language, I often find my self
in a situation
where I mange to write highly dense code, sometimes at the expense of
readability. In such
cases I think that the use of explaining variables, and simplified-but-
somewhat-longer expressions
is desirable.
OTOH, if the code is inherently simple (e.g.: a chain of straight-
forward transformations on a collection)
I think that using Clojure's power to reduce the line count by a
factor of more than 5 (compared to, say, Java),
is highly beneficial.
The predicament is that there's no objective way to measure
"conceptual weight" nor "density" so
this issue is largely a personal judgment call.
On Mon, Dec 29, 2008 at 12:03 AM, Abhishek Reddy <arbs...@gmail.com> wrote:
> Speaking for myself, as the author of the original Snake example, I > had no intention of converting developers to Clojure, or of producing > instructive or readable code, with that snippet.
> While I agree with some of your critique, I do think it is misplaced. > The aim of this particular exercise was to produce an _abnormally_ > terse program, after all.
> If you believe there is some utility in producing a more readable > version, as a tutorial, do not hesitate to make one and publish it! > I'll be happy to direct readers to it. :-)
I apologize for the nature of my email which somewhat singled you out.
I would like to produce a version of the snake code that could serve as an example of the kind of code that the Clojure community thinks is "good". Unless it's part of an exercise to produce the shortest code possible, I think we should always write Clojure code with a goal of making it as easy as possible for others to read, while not attempting to serve as a Clojure tutorial. Again, my goal here is to get more developers to give Clojure a shot.
My challenge to everyone on the list is to start with any version of the snake code you've seen and make it as readable as *you* think it should be by doing things like renaming variables and functions, adding comments and changing indentation. I'd really like to see what *you* think is the best way to write this code. The lessons learned from this exercise could then be applied to other code we write in the future.
<r.mark.volkm...@gmail.com> wrote: > I would like to produce a version of the snake code that could serve > as an example of the kind of code that the Clojure community thinks is > "good". Unless it's part of an exercise to produce the shortest code > possible, I think we should always write Clojure code with a goal of > making it as easy as possible for others to read, while not attempting > to serve as a Clojure tutorial. Again, my goal here is to get more > developers to give Clojure a shot.
> My challenge to everyone on the list is to start with any version of > the snake code you've seen and make it as readable as *you* think it > should be by doing things like renaming variables and functions, > adding comments and changing indentation. I'd really like to see what > *you* think is the best way to write this code. The lessons learned > from this exercise could then be applied to other code we write in the > future.
Okay, I took the challenge and produced a modified version of my earlier code where I removed what I considered to be redundant comments and did a little more renaming. You can see it at http://www.ociweb.com/mark/programming/ClojureSnake.html. Feedback is welcomed!
I also started documenting some Clojure coding guidelines aimed at making code more readable at http://www.ociweb.com/mark/programming/ClojureCodingGuidelines.html and would appreciate feedback on these. I expect there will be cases where not following these is justified, which is why I refer to them as guidelines instead of rules.
> My challenge to everyone on the list is to start with any version of
> the snake code you've seen and make it as readable as *you* think it
> should be by doing things like renaming variables and functions,
> adding comments and changing indentation. I'd really like to see what
> *you* think is the best way to write this code. The lessons learned
> from this exercise could then be applied to other code we write in the
> future.
I'll keep this as short. Thanks to the folks who contributed to the
snake code. I spent a few hours reading it, referring repeatedly to
the API documentation, renaming a few of the variables, experimenting
with snippets in REPL, and adding comments to the code so I wouldn't
forget what I'd learned. I'm not sure that's a problem, though. I
learned more in that process than I would have if the code had been
excruciatingly documented.
The level of "educational documentation" varies with the level of
experience. Too much documentation in an example is just as bad as
too little.
I also wonder whether insisting upon coding standards might deter
people from participating in this forum.
> On Mon, Dec 29, 2008 at 5:44 AM, Mark Volkmann
> <r.mark.volkm...@gmail.com> wrote:
>> I would like to produce a version of the snake code that could serve
>> as an example of the kind of code that the Clojure community thinks
>> is
>> "good". Unless it's part of an exercise to produce the shortest code
>> possible, I think we should always write Clojure code with a goal of
>> making it as easy as possible for others to read, while not
>> attempting
>> to serve as a Clojure tutorial. Again, my goal here is to get more
>> developers to give Clojure a shot.
>> My challenge to everyone on the list is to start with any version of
>> the snake code you've seen and make it as readable as *you* think it
>> should be by doing things like renaming variables and functions,
>> adding comments and changing indentation. I'd really like to see what
>> *you* think is the best way to write this code. The lessons learned
>> from this exercise could then be applied to other code we write in
>> the
>> future.
> Okay, I took the challenge and produced a modified version of my
> earlier code where I removed what I considered to be redundant
> comments and did a little more renaming. You can see it at
> http://www.ociweb.com/mark/programming/ClojureSnake.html. Feedback is
> welcomed!
> I also started documenting some Clojure coding guidelines aimed at
> making code more readable at
> http://www.ociweb.com/mark/programming/ClojureCodingGuidelines.html > and would appreciate feedback on these. I expect there will be cases
> where not following these is justified, which is why I refer to them
> as guidelines instead of rules.
Much of Norvig's "Tutorial on Good Lisp Programming Style" is
applicable to Clojure.
> <r.mark.volkm...@gmail.com> wrote:
> > I would like to produce a version of the snake code that could serve
> > as an example of the kind of code that the Clojure community thinks is
> > "good". Unless it's part of an exercise to produce the shortest code
> > possible, I think we should always write Clojure code with a goal of
> > making it as easy as possible for others to read, while not attempting
> > to serve as a Clojure tutorial. Again, my goal here is to get more
> > developers to give Clojure a shot.
> > My challenge to everyone on the list is to start with any version of
> > the snake code you've seen and make it as readable as *you* think it
> > should be by doing things like renaming variables and functions,
> > adding comments and changing indentation. I'd really like to see what
> > *you* think is the best way to write this code. The lessons learned
> > from this exercise could then be applied to other code we write in the
> > future.
> Okay, I took the challenge and produced a modified version of my
> earlier code where I removed what I considered to be redundant
> comments and did a little more renaming. You can see it athttp://www.ociweb.com/mark/programming/ClojureSnake.html. Feedback is
> welcomed!
> I also started documenting some Clojure coding guidelines aimed at
> making code more readable athttp://www.ociweb.com/mark/programming/ClojureCodingGuidelines.html > and would appreciate feedback on these. I expect there will be cases
> where not following these is justified, which is why I refer to them
> as guidelines instead of rules.
> You should consider using docstrings for documenting functions
There's a big difference between the comments directed at someone reading the code (possibly the author at a later date) and someone wishing to use it. Function-level documentation strings serve only the latter class of person.
Not sure about that; knowing what a function is for is an important starting
point to understanding it. Anyway' half of the code you work on will be
using the other half (for given values of 'half' of course ;-) .
Generally, Clojure is a Lisp so Lisp idioms should apply (closing all your
braces on the last line etc); you need to be thinking Lisp not Java, Ruby or
whatever.
> On Monday 29 December 2008 09:11, lpetit wrote:
> > You should consider using docstrings for documenting functions
> There's a big difference between the comments directed at someone
> reading the code (possibly the author at a later date) and someone
> wishing to use it. Function-level documentation strings serve only the
> latter class of person.
On Mon, Dec 29, 2008 at 11:11 AM, lpetit <laurent.pe...@gmail.com> wrote:
> You should consider using docstrings for documenting functions
Good suggestion. I've changed my code to do that. I also noticed that
I had forgotten to replace special characters with built-in entities
in my HTML, so that is fixed now. The new version is at
http://www.ociweb.com/mark/programming/ClojureSnake.html. What else
would you do different in this code? Do you think it still contains
too many comments?
> On 29 déc, 16:45, "Mark Volkmann" <r.mark.volkm...@gmail.com> wrote:
>> On Mon, Dec 29, 2008 at 5:44 AM, Mark Volkmann
>> <r.mark.volkm...@gmail.com> wrote:
>> > I would like to produce a version of the snake code that could serve
>> > as an example of the kind of code that the Clojure community thinks is
>> > "good". Unless it's part of an exercise to produce the shortest code
>> > possible, I think we should always write Clojure code with a goal of
>> > making it as easy as possible for others to read, while not attempting
>> > to serve as a Clojure tutorial. Again, my goal here is to get more
>> > developers to give Clojure a shot.
>> > My challenge to everyone on the list is to start with any version of
>> > the snake code you've seen and make it as readable as *you* think it
>> > should be by doing things like renaming variables and functions,
>> > adding comments and changing indentation. I'd really like to see what
>> > *you* think is the best way to write this code. The lessons learned
>> > from this exercise could then be applied to other code we write in the
>> > future.
>> Okay, I took the challenge and produced a modified version of my
>> earlier code where I removed what I considered to be redundant
>> comments and did a little more renaming. You can see it athttp://www.ociweb.com/mark/programming/ClojureSnake.html. Feedback is
>> welcomed!
>> I also started documenting some Clojure coding guidelines aimed at
>> making code more readable athttp://www.ociweb.com/mark/programming/ClojureCodingGuidelines.html >> and would appreciate feedback on these. I expect there will be cases
>> where not following these is justified, which is why I refer to them
>> as guidelines instead of rules.
>> --
>> R. Mark Volkmann
>> Object Computing, Inc.
> On Mon, Dec 29, 2008 at 11:11 AM, lpetit <laurent.pe...@gmail.com> wrote:
> > You should consider using docstrings for documenting functions
> Good suggestion. I've changed my code to do that. I also noticed that
> I had forgotten to replace special characters with built-in entities
> in my HTML, so that is fixed now. The new version is at
> http://www.ociweb.com/mark/programming/ClojureSnake.html. What else
> would you do different in this code? Do you think it still contains
> too many comments?
> > On 29 déc, 16:45, "Mark Volkmann" <r.mark.volkm...@gmail.com> wrote:
> >> On Mon, Dec 29, 2008 at 5:44 AM, Mark Volkmann
> >> <r.mark.volkm...@gmail.com> wrote:
> >> > I would like to produce a version of the snake code that could serve
> >> > as an example of the kind of code that the Clojure community thinks is
> >> > "good". Unless it's part of an exercise to produce the shortest code
> >> > possible, I think we should always write Clojure code with a goal of
> >> > making it as easy as possible for others to read, while not attempting
> >> > to serve as a Clojure tutorial. Again, my goal here is to get more
> >> > developers to give Clojure a shot.
> >> > My challenge to everyone on the list is to start with any version of
> >> > the snake code you've seen and make it as readable as *you* think it
> >> > should be by doing things like renaming variables and functions,
> >> > adding comments and changing indentation. I'd really like to see what
> >> > *you* think is the best way to write this code. The lessons learned
> >> > from this exercise could then be applied to other code we write in the
> >> > future.
> >> Okay, I took the challenge and produced a modified version of my
> >> earlier code where I removed what I considered to be redundant
> >> comments and did a little more renaming. You can see it athttp://
> www.ociweb.com/mark/programming/ClojureSnake.html. Feedback is
> >> welcomed!
> >> I also started documenting some Clojure coding guidelines aimed at
> >> making code more readable athttp://
> www.ociweb.com/mark/programming/ClojureCodingGuidelines.html > >> and would appreciate feedback on these. I expect there will be cases
> >> where not following these is justified, which is why I refer to them
> >> as guidelines instead of rules.
> >> --
> >> R. Mark Volkmann
> >> Object Computing, Inc.
On Mon, Dec 29, 2008 at 2:24 PM, Brian Doyle <brianpdo...@gmail.com> wrote:
> Looking at this code the uppercase variables stands out.
> This isn't idiomatic is it?
I don't know. I was following Java conventions of making constants all
uppercase. Is there a convention for this in Clojure? Is there a way I
could prevent them from being changed later? Maybe I should make them
be map entries where the keys are keywords and the values are the
integers. That seems extreme though.
> On Mon, Dec 29, 2008 at 12:19 PM, Mark Volkmann <r.mark.volkm...@gmail.com>
> wrote:
>> On Mon, Dec 29, 2008 at 11:11 AM, lpetit <laurent.pe...@gmail.com> wrote:
>> > You should consider using docstrings for documenting functions
>> Good suggestion. I've changed my code to do that. I also noticed that
>> I had forgotten to replace special characters with built-in entities
>> in my HTML, so that is fixed now. The new version is at
>> http://www.ociweb.com/mark/programming/ClojureSnake.html. What else
>> would you do different in this code? Do you think it still contains
>> too many comments?
>> > On 29 déc, 16:45, "Mark Volkmann" <r.mark.volkm...@gmail.com> wrote:
>> >> On Mon, Dec 29, 2008 at 5:44 AM, Mark Volkmann
>> >> <r.mark.volkm...@gmail.com> wrote:
>> >> > I would like to produce a version of the snake code that could serve
>> >> > as an example of the kind of code that the Clojure community thinks
>> >> > is
>> >> > "good". Unless it's part of an exercise to produce the shortest code
>> >> > possible, I think we should always write Clojure code with a goal of
>> >> > making it as easy as possible for others to read, while not
>> >> > attempting
>> >> > to serve as a Clojure tutorial. Again, my goal here is to get more
>> >> > developers to give Clojure a shot.
>> >> > My challenge to everyone on the list is to start with any version of
>> >> > the snake code you've seen and make it as readable as *you* think it
>> >> > should be by doing things like renaming variables and functions,
>> >> > adding comments and changing indentation. I'd really like to see what
>> >> > *you* think is the best way to write this code. The lessons learned
>> >> > from this exercise could then be applied to other code we write in
>> >> > the
>> >> > future.
>> >> Okay, I took the challenge and produced a modified version of my
>> >> earlier code where I removed what I considered to be redundant
>> >> comments and did a little more renaming. You can see it
>> >> athttp://www.ociweb.com/mark/programming/ClojureSnake.html. Feedback is
>> >> welcomed!
>> >> I also started documenting some Clojure coding guidelines aimed at
>> >> making code more readable
>> >> athttp://www.ociweb.com/mark/programming/ClojureCodingGuidelines.html >> >> and would appreciate feedback on these. I expect there will be cases
>> >> where not following these is justified, which is why I refer to them
>> >> as guidelines instead of rules.
>> >> --
>> >> R. Mark Volkmann
>> >> Object Computing, Inc.
>> --
>> R. Mark Volkmann
>> Object Computing, Inc.
On Dec 29, 3:40 pm, "Mark Volkmann" <r.mark.volkm...@gmail.com> wrote:
> On Mon, Dec 29, 2008 at 2:24 PM, Brian Doyle <brianpdo...@gmail.com> wrote:
> > Looking at this code the uppercase variables stands out.
> > This isn't idiomatic is it?
> I don't know. I was following Java conventions of making constants all
> uppercase. Is there a convention for this in Clojure?
Hi Mark,
There's a Common Lisp convention of surrounding constant names with
"+", like:
(def +grid-size+ 10)
but even in CL it's not followed consistently. Go with what feels
good. :)
> Is there a way I could prevent them from being changed later?
> On Mon, Dec 29, 2008 at 2:24 PM, Brian Doyle <brianpdo...@gmail.com> wrote: >> Looking at this code the uppercase variables stands out. >> This isn't idiomatic is it?
I believe the idiom for global values like this is to place asterisks around the name. Underscores (and CamelCase) should only be used when required for Java interop:
> I was following Java conventions of making constants all > uppercase. Is there a convention for this in Clojure? Is there a way I > could prevent them from being changed later?
I'm not aware of anyway to make a global constant. By using a Var as you've done, the only way to change them is to use 'def' again (which is a big hammer and very much discouraged inside regular functions) or to use 'binding' to temporarily change their values within a particular thread. I think what you have is sufficient for communicating your intended meaning.
On a more general point, I'd personally recommend being wary of over-investing in comments. This is not a radical recommendation, but I'll bring up again anyway that thought that it's better to write code in such a way that it explains itself than to add comments to code that doesn't. Only when the former is insufficient should more comments be added. Every line of comment is another line of code that must be maintained, and worse than that it's a line that no compiler or unit test is ever going to indicate as incorrect. When adding a comment, I think it's appropriate to be sure that the maintenance cost of the comment itself outweighs the maintenance cost of having no comment (or a shorter or more general comment).
An example of this point -- Abhishek's original code used a hash with:x and :y keys to indicate coordinates. I changed this to a two-element vector only in pursuit of this particular puzzle's goals, namely fewer lines of code. This is a very different goal from most code, which should be maintainability, and also different from tutorial code, which should be about teaching Clojure to someone who doesn't already know it. For either of those latter goals, I would contend Abhishek's solution was a better one -- using :x and :y help indicate what's going on without global index names (like *x-index*) or much extra commenting.
Another example -- if you find a particular use of #() to be too confusing on its own, consider replacing it with a (fn ...), which allows the naming of each argument as well as destructuring. This can again improve readability without require more comments.
I think your expanded version of the snake program may be very beneficial to some, though with a different purpose than the original version, so thanks for providing it. Personally, I wouldn't want to maintain a large codebase that was written using either style, as both are a bit extreme in opposite ends of the verbosity scale. As I've said elsewhere "golfing" is fun, if not broadly useful. Conversely, tutorial-style code may be very useful in appropriate contexts, but is hardly ever fun to write.
...and now this post is at an extreme of the verbosity scale. Sorry all, I'll quit now before I get any further behind.
> On Dec 29, 3:40 pm, "Mark Volkmann" <r.mark.volkm...@gmail.com> wrote: >> On Mon, Dec 29, 2008 at 2:24 PM, Brian Doyle <brianpdo...@gmail.com> wrote: >> > Looking at this code the uppercase variables stands out. >> > This isn't idiomatic is it?
>> I don't know. I was following Java conventions of making constants all >> uppercase. Is there a convention for this in Clojure?
> Hi Mark,
> There's a Common Lisp convention of surrounding constant names with > "+", like: > (def +grid-size+ 10) > but even in CL it's not followed consistently. Go with what feels > good. :)
>> Is there a way I could prevent them from being changed later?
> Not really, you can always re-def.
Thanks for the info. Stuart!
It's early enough in the life of Clojure that we haven't developed any deeply held habits yet. I think it would be a good idea for you and other Clojure committers to at least suggest the way you think things should be done in code. If you think surrounding names of constants with plus signs is a good way to identify them as such, I'll gladly start doing that for the sake of consistency. I don't think it's a good idea for all of us to simply do what feels good because that will make it harder to read code written by others.
On Mon, Dec 29, 2008 at 3:10 PM, Chouser <chou...@gmail.com> wrote:
> On Mon, Dec 29, 2008 at 3:40 PM, Mark Volkmann > <r.mark.volkm...@gmail.com> wrote:
>> On Mon, Dec 29, 2008 at 2:24 PM, Brian Doyle <brianpdo...@gmail.com> wrote: >>> Looking at this code the uppercase variables stands out. >>> This isn't idiomatic is it?
> I believe the idiom for global values like this is to place asterisks > around the name. Underscores (and CamelCase) should only be used when > required for Java interop:
I think that's supposed to be + instead of *, at least Common Lisp seems to use +.
> On a more general point, I'd personally recommend being wary of > over-investing in comments. This is not a radical recommendation, but > I'll bring up again anyway that thought that it's better to write code > in such a way that it explains itself than to add comments to code > that doesn't. Only when the former is insufficient should more > comments be added.
I agree completely! In some programming languages, for example Smalltalk, I feel like I can almost always write the code in a way that doesn't require comments. However, I don't feel able to do that as often in Clojure. I think it's because you can do so much with so little code in Clojure. For example, here's some code that I don't know how to rewrite in a way that I find self-explanatory:
Perhaps using your suggestion to go back and use a map with :x and :y keys instead of a two-element vector to represent x/y coordinates would help a little, but I'm still not sure the code would be immediately obvious.
Maybe it's just a matter of time before I'm good enough at reading Clojure code that I won't feel the need to add comments to these. Even if that happens though, I'll still be concerned about the ability of other developers that haven't yet reached that level of proficiency to understand my code.
> I think that's supposed to be + instead of *, at least Common Lisp > seems to use +.
I meant * -- I don't know CL at all, but the *asterisk* form is used frequently in clojure.core, while no +plus+ form ever appears. I also was careful to refer to the global nature of the Vars, not anything about const-ness.
I don't know CL that well myself, but I think the convention is to use
+ for constants (i.e. defconst) where * is used for global variables
(i.e. defparameter). In that case the + convention doesn't really
make sense in clojure as it doesn't have any notion of a constant
reference type.
On Mon, Dec 29, 2008 at 1:58 PM, Chouser <chou...@gmail.com> wrote:
> On Mon, Dec 29, 2008 at 4:40 PM, Mark Volkmann
> <r.mark.volkm...@gmail.com> wrote:
>> I think that's supposed to be + instead of *, at least Common Lisp
>> seems to use +.
> I meant * -- I don't know CL at all, but the *asterisk* form is used
> frequently in clojure.core, while no +plus+ form ever appears. I also
> was careful to refer to the global nature of the Vars, not anything
> about const-ness.
On Mon, Dec 29, 2008 at 3:58 PM, Chouser <chou...@gmail.com> wrote:
> On Mon, Dec 29, 2008 at 4:40 PM, Mark Volkmann > <r.mark.volkm...@gmail.com> wrote:
>> I think that's supposed to be + instead of *, at least Common Lisp >> seems to use +.
> I meant * -- I don't know CL at all, but the *asterisk* form is used > frequently in clojure.core, while no +plus+ form ever appears. I also > was careful to refer to the global nature of the Vars, not anything > about const-ness.
> On Mon, Dec 29, 2008 at 3:58 PM, Chouser <chou...@gmail.com> wrote:
>> On Mon, Dec 29, 2008 at 4:40 PM, Mark Volkmann
>> <r.mark.volkm...@gmail.com> wrote:
>>> I think that's supposed to be + instead of *, at least Common Lisp
>>> seems to use +.
>> I meant * -- I don't know CL at all, but the *asterisk* form is used
>> frequently in clojure.core, while no +plus+ form ever appears. I also
>> was careful to refer to the global nature of the Vars, not anything
>> about const-ness.
> On Mon, Dec 29, 2008 at 3:58 PM, Chouser <chou...@gmail.com> wrote:
> > On Mon, Dec 29, 2008 at 4:40 PM, Mark Volkmann
> > <r.mark.volkm...@gmail.com> wrote:
> >> I think that's supposed to be + instead of *, at least Common Lisp
> >> seems to use +.
> > I meant * -- I don't know CL at all, but the *asterisk* form is used
> > frequently in clojure.core, while no +plus+ form ever appears. I also
> > was careful to refer to the global nature of the Vars, not anything
> > about const-ness.