Return statement

After lots of back and forth discussion and debate, a new feature was added to Hy: explicit return statement. While this is pretty standard thing in most languages, it’s rather rare in languages of lisp family.

Hy has always had an implicit return. That is, value of the last evaluated form is result of the function call:

=> (defn add [a b]
...  (+ a b))
=> (add 1 2)
3

I like how this looks, purely from point of view of aesthetics. If I’m going to stare at code for hours, I might as well stare some pleasant looking code. Most, if not all, code can be written with implicit returns. On my experience, it’s often matter of splitting functions at certain (I hesitate to call them correct) points and having certain abstractions. But in cases where one doesn’t want to jump through the hoops required for using implicit returns, explicit return is useful tool. It’s kind of like the infamous goto, useful and good tool, if you know when to use it.

Previous example using explicit return would look like (this is silly, I know):

=> (defn add [a b]
...  (return (+ a b)))
=> (add 1 2)
3

So, when is explicit return nice thing to have? For example, when you have a while loop that is doing some processing and you want to return a value when certain condition is met. Compare the following examples:

(defn process []
  (while True
    (if (friday? (datetime.now))
      (return "It's Friday!")
      (sleep 1000))))

and

(def process []
  (while True
    (if (friday? (datetime.now))
      (break)
      (sleep 1000)))
  "It's Friday!")

One might argue that the former way is easier or more familiar to read and understand. But it probably depends on what one has gotten used to.

More illustrative example is where function has a long running loop that we want to break out of as soon as solution is found, but return some default value when solution isn’t found. Compare the following examples:

(defn process [x]
  (setv result? None)
  (for [n (range 1 1000000)]
    (setv temp (calculate x n))
    (if (satisfactory? temp)
      (do (setv result? temp)
          (break))))
  (if result?
    result?
    "No result found"))

and

(defn process [x]
  (for [n (range 1 1000000)]
    (setv temp (calculate x n))
    (if (satisfactory? temp)
      (return temp)))
  "No result found")

The latter one is shorter and easier to read. This is a good example where return might be useful. I’m sure one can write the explicit loop out of the algorigth and come up with a cleaner version that stops processing as soon as the solution has been found.

(defn process [x]
  (first-or-default (filter satisfactory?
                            (map (fn [n] (calculate x n))
                                 (range 1 1000000)))
                    "No result found"))

Well, not quite sure about the cleaner, but at least we don’t have explicit for there anymore.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s