Dec 14

Referential Transparency and Exceptions

Referential transparency ("RT") is a contract in functional programming which assures that the result of a function call returns always the same value for a given input. Any side-effect will break this contract, therefore referential transparency requires you to avoid side-effects even in failure handling.

The most concrete example of referential transparency is the functions in math: f(x) = x + 1
For  x = 1 given, regardless of how many times you call this function, it will always return the value  f(1) = 2 . The reason is that the functions in math do not introduce any side effects. Such functions are considered as "pure" functions, so they are referential transparent. Let's put the math aside and consider the following code example in Scala:

class SpaceShip {
  // some spaceship attributes/functions

  def moveBy(x, y) : Position {
    val currentPos = getCurrent()
    val newPos = Position(currentPos.x + x, currentPos.y + y)
    changePositionOnScreenBy(newPos)
    newPos
    }
}

moveBy(..) function is used to move the spacecraft from its current point in the 2D space to the next position by x,y. The actual move action (side-effect) is fulfilled by calling changePositionOnScreenBy. After this call, the spaceship gets a new position in the space. Every time you call this function, it causes the spaceship to move to the next position for the same x,y parameters given (Starting at (0,0), after 5th moveBy-call with given (x,y) = (5,5), the spaceship has the position (25,25) ). It is obviously a violation of the RT.

It is not the only way to violate RT. Let's consider the following example:

def increaseSpeed() {
  val increment : Int = throw new Exception("Engines defect");
  try {
      setNewSpeedLevel(currentLevel + increment)
  } catch {
      case e: Exception => 500 // Internal spaceship error.
  }
}

The spaceship wants to speed up, but before the expression "currentLevel + increment" is evaluated - and substituted by its result, the function call will be interrupted by the exception. What if the function execution had a chance to get to the line 4 without throwing the exception, and just for a second think about, that we are able to comment out the throw-statement while program execution so that the execution can move on without throwing the exception. Now, we are at line 4 and let's say that we are able to comment in the throw-statement back again. In this case, "currentLevel + increment" will be evaluated:

setNewSpeedLevel(currentLevel + increment) [increment/throw new Exception("Engines defect")]
setNewSpeedLevel(currentLevel + (throw new Exception("Engines defect")) )
// Exception !

At this time, however, the exception would be caught by the catch-block (line 5) and the function would return an integer value, 500, which indicates an internal spaceship error. The problem is here that the RT becomes context dependent so the substitution model reasoning does not work locally anymore. However, the RT is not broken by context dependency introduced by throwing exception, but due to catching it and altering the behaviour of the function by returning a value which is indeed expected to be a bottom value.

Bottom types point out that a function is not defined for a given input i.e returns an error, or does not return at all e.g in case it is stuck in an infinite loop. Making decisions based upon them and changing the behaviour of the function breaks its purity. Throw an exception, if it is really required and in really exceptional cases. Therefore, not catching an exception is perfectly valid to make bottom types work - or alternative, using "optional" types (in Scala and Java 8.) as bottom types.

PS: I think, it is one of the reasons why the programming languages in majority do not provide checked exceptions, at all. They compel developers to add more boilerplate code by giving them a chance to add more logic to handle exception cases, but on the other hand, it increases the complexity in programs by breaking the rules of purity.

0
comments

Jan 18

Setting up your environment for scripting with Clojure

After you step into the Clojure world, an another question you may ask yourself is how you can run the Clojure files just like any other script files (as if they're written in Bash, Perl, Python, etc.) without creating any Leiningen project ? The plugin lein-exec allows you to run your Clojure files without compiling - at least in feeling. There are also a couple of ways to achieve this, please see this Stackover thread. However, the way how lein-exec plugin solves this problem seems more natural and straightforward to me.

I assume that you have already installed Leiningen (version 2.x) to your system. If not, you can follow the installation instructions on leiningen.org.

To install the lein-exec plugin, you need follow the way you already use to install Leiningen plugins. Just add following line into your "~/.lein/profiles.clj":

{:user {:plugins [[lein-exec "0.3.1"]]}}

Your first "lein" call using lein-exec plugin lets Leiningen download and install the plugin to your system:

$ lein exec -e '(println "chuck norris doesn't say hello world.")'

As the example above demonstrates, providing -e option you can even run the Clojure snippets using lein-exec, or run the clj files:

$ lein exec ~/path/to/foo.clj

and adding an alias like "alias 'clj=lein exec'" into your ~/.bashrc, it gets even better:

$ clj ~/path/to/foo.clj

There is one more tip if you want to make Clojure files executable (like a bash script file adding shebang). To do this first download both scripts lein-exec and lein-exec-p and copy the both files into a directory which is in PATH:

$ wget https://raw.github.com/kumarshantanu/lein-exec/master/lein-exec
$ wget https://raw.github.com/kumarshantanu/lein-exec/master/lein-exec-p
$ chmod a+x lein-exec lein-exec-p
$ sudo mkdir /opt/lein-exec
$ sudo mv lein-exec lein-exec-p /opt/lein-exec
$ export PATH=$PATH:/opt/lein-exec # you can add this line into the .bashrc

Now, you're ready to write your first executable Clojure script, hello.clj:


#!/bin/bash lein-exec

(print "Chuck Norris doesn't say Hello!")

To be able to run this script, you need to make it executable and just run as any other scripts as if written in Perl, Python, Ruby, etc. :

$ chmod u+x hello.clj
$ ./hello.clj
Chuck Norris doesn't say Hello!

But, what happens if you have some dependencies to the other libraries like clojure-contrib or clj-http to make some http requests ? Fortunately, lein-exec deals with these dependencies as well. What you need is to declare these libraries at the top of your script using the function "deps" in the leiningen.exec namespace. Here is a basic example which performs an HTTP HEAD request to the blog:

#!/bin/bash lein-exec

; load dependencies required by this script
(require ' [leiningen.exec :o nly (deps) :as lein-exec])
(lein-exec/deps '[clj-http "0.7.8"])

; here is my script
(ns com.bagdemir
(:require 1))

; make a http head request
(print (clj-http.client/head "http://bagdemir.com"))

In my opinion using lein-exec is a very elegant way to write Clojure scripts. With some environment settings and a few lines of code which load all dependencies for you, you can utilize Clojure for your hacks with a scripting ninja motivation.

0
comments