Naming Functions...

9 views
Skip to first unread message

Wardrop

unread,
Feb 3, 2010, 10:47:32 PM2/3/10
to Clojure
I've always struggled when it comes to defining good names for
functions and methods. Now that I'm learning Clojure, function naming
becomes even more imperative, as you don't have classes and objects to
help give meaning to a method. I'm finding at the moment that I'm
spending half my time thinking of decent names for functions. I'm just
wondering what process you all use when it comes to naming functions?

David Nolen

unread,
Feb 3, 2010, 11:06:18 PM2/3/10
to clo...@googlegroups.com
Can you give a more specific example of something that your having a problem with?

Jonathan Smith

unread,
Feb 4, 2010, 12:15:13 AM2/4/10
to Clojure
A function would be named based on what it is that it does.

Difficulty naming functions would imply to me that the functions
involved do not contain a clear functionality.

The names of the functions should sort of be an 'emergent property' of
a larger process of reasoning through the programming problem.

As I see it, there are two ways to do this...
The first (systematic):

1.) break the program into reasonable steps
(a concise description of the step being the function name)
2.) make a function for each step.
3.) break each function into steps
4.) goto 2 until you are able to describe different pieces of the
program in the base language.

the second (haphazard):
1.) start writing code into a function (name of overall functionality)
2.) when the code gets to a certain size, decide that you have too
much code in the function.
3.) look for different pieces of the task that you could potentially
pull out and name, or patterns that repeat more than once.
4.) pull them out and use them as functions.
5.) loop through this process of expanding the code and rewriting it
until you are done.

I could write these as functions

(defn systematic [idea]
(let [sub-ideas (partition-idea idea)]
(map #(unless (atomic? %1) (systematic %1)) sub-ideas))

(defn haphazard [functionality]
(let [[refactored-functionality & new-functions] (extract-
functionality functionality)]
(map #(unless (atomic? %1) (haphazard %1)) new-functions)))

Ideally these functions lead to the same output.
In my use of map I am assuming a lazy programmer without a deadline.
In the case of a motivated programmer, we might use dolist.
In the case of a lazy programmer with a deadline, we might use doall
or dorun..

Wardrop

unread,
Feb 4, 2010, 2:04:23 AM2/4/10
to Clojure
I often myself creating functions which perform a rather clear and
simple task, but which is hard to describe, either because I don't
know the term for what I've just implemented, or because the function
is difficult to summarise in a couple of words. As an example, I've
just created a function which determines how many times the value n,
can be divided by the base, until n becomes smaller than the base.
Here's the implementation...

(defn <insert-name-here> [n base]
(loop [n n count 0]
(if (< n base)
{:val n :count count}
(recur (float (/ n base)) (inc count)))))

This can be used among other things, to determine how to format bytes.
Say I have a file that's 6,789,354 bytes, and I want to display that
in a more readable manner, I could use my unnamed function like so
(<unnamed> 6789354 1024), and get a new appropriately rounded number,
including the number of times it has been rounded, which I can use the
pick the appropriate suffix from a list ("Bytes", "KB", "MB", "GB",
"TB).

I mean, what the hell would you name this function, or would you not
create such an obscure and generalised function to start with?

Michael Wood

unread,
Feb 4, 2010, 2:28:35 AM2/4/10
to clo...@googlegroups.com
On 4 February 2010 09:04, Wardrop <t...@tomwardrop.com> wrote:
> I often myself creating functions which perform a rather clear and
> simple task, but which is hard to describe, either because I don't
> know the term for what I've just implemented, or because the function
> is difficult to summarise in a couple of words. As an example, I've
> just created a function which determines how many times the value n,
> can be divided by the base, until n becomes smaller than the base.
> Here's the implementation...
>
> (defn <insert-name-here> [n base]
>  (loop [n n count 0]
>    (if (< n base)
>      {:val n :count count}
>      (recur (float (/ n base)) (inc count)))))
>
> This can be used among other things, to determine how to format bytes.
> Say I have a file that's 6,789,354 bytes, and I want to display that
> in a more readable manner, I could use my unnamed function like so
> (<unnamed> 6789354 1024), and get a new appropriately rounded number,
> including the number of times it has been rounded, which I can use the
> pick the appropriate suffix from a list ("Bytes", "KB", "MB", "GB",
> "TB).

I would probably split that up:

The division can just use /, so no need for a separate function.
The rest can be done like this:

(defn logn [n x]
(/ (java.lang.Math/log x) (java.lang.Math/log n)))

Then you could have a function that formats file sizes:

(defn format-file-size [num-bytes]
(let [base 1024
val (float (/ num-bytes base))
times (int (logn base num-bytes))]
...)

Not sure if that helps with your general question, though :)

> I mean, what the hell would you name this function, or would you not
> create such an obscure and generalised function to start with?

--
Michael Wood <esio...@gmail.com>

Laurent PETIT

unread,
Feb 4, 2010, 6:43:32 AM2/4/10
to clo...@googlegroups.com
I would do as you do, finding a name, hopefully good enough to prevent
an imperative need to jump to the function definition when re-reading
the code 6 months later.

Anyway, would you have written this particular function as a method of
a class, would the problem of giving it a "short but meaningful name"
rather than "long and meaningful name" have been easier ?

2010/2/4 Wardrop <t...@tomwardrop.com>:

> --
> 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

Michał Marczyk

unread,
Feb 4, 2010, 7:40:48 AM2/4/10
to clo...@googlegroups.com
On 4 February 2010 08:04, Wardrop <t...@tomwardrop.com> wrote:
> (defn <insert-name-here> [n base]
>  (loop [n n count 0]
>    (if (< n base)
>      {:val n :count count}
>      (recur (float (/ n base)) (inc count)))))
>
> [ ... ]

>
> I mean, what the hell would you name this function, or would you not
> create such an obscure and generalised function to start with?

How about significand-and-exponent-in-radix? :-)

(Or for a shorter name maybe sci-notation-map or something...)

In fact, I might generalise it further to accept an optional argument
-- defaulting to 0 -- to determine how the result is to be normalised:

user> (defn significand-and-exponent-in-radix
([n radix] (significand-and-exponent-in-radix n radix 1))
([n radix o]
(let [threshold (Math/pow radix o)]


(loop [n n count 0]

(if (< n threshold)
{:significand n :exponent count}
(recur (double (/ n radix)) (inc count)))))))
#'user/significand-and-exponent-in-radix
user> (Math/pow 10 1)
10.0
user> (significand-and-exponent-in-radix 1000 10)
{:significand 1.0, :exponent 3}
user> (significand-and-exponent-in-radix 1000 10 0)
{:significand 0.1, :exponent 4}

Also, add docstrings. With the REPL at hand, the explanation of
anything unclear from your function's name is one (doc ...) call away
if you do.

All best,
Michał

Erik Price

unread,
Feb 4, 2010, 2:00:55 PM2/4/10
to clo...@googlegroups.com
What kind of naming convention is appropriate for a function that
operates on a sequence, and, as one of its return values, returns a
new head for (or in other words a subsequence within) that sequence?
For example, a function that consumes some portion of a stream. Or is
it not conventional for a stream-consuming function to work that way?

e

Meikel Brandmeyer

unread,
Feb 4, 2010, 2:21:08 PM2/4/10
to clo...@googlegroups.com
Hi,

There is no naming convention: filter, remove, take, take-nth, drop-while, ... are all examples of that.

Sincerely
Meikel

Wardrop

unread,
Feb 4, 2010, 8:48:01 PM2/4/10
to Clojure
Hi Michael,

Thanks for the implementation suggestion. I left school 2 years only
so missed out on some of the more advanced mathematics, hence I was
unaware of the function and purpose of log. Since reading your post,
I've done a little bit of research on log as to educate myself. I've
now re-implemented my function using your logn implementation. It now
has a name also...

(defn recursively-divide
"Divides n by base until n is smaller than base. Returns a map
consisting of the structure {:result :times}, where :result is the
result of the recursive division, and :times is the number of times n
was divided by base."
[n base]
(let [times (int (logn base n))]
{:result (float (/ n (expt base times))) :times times}))

I've chosen "recursively-divide" as it seemed more clojuresque, as it
reads like it would in english "recursively divide n by base".

I guess if I've learnt anything from just this function alone, it's
that often names are difficult to think of when it's hard to define
exactly what it is a function is doing. If you can't easily define
what a functions purpose is, then I think that usually means it's been
poorly designed/implemented (suggesting there's a better way) or the
coder isn't exactly sure what they're trying to achieve.

> Michael Wood <esiot...@gmail.com>

Reply all
Reply to author
Forward
0 new messages