Monday 13 September 2010

Zope Interfaces on Anonymous Functions.

Pretty old, but It's something I've not come across yet as a Zope coder. I was reading about Zope Interfaces vs. Python's ABC and found that in Zope you can attach interfaces to any object in Python, not just classes, and since pretty much everything in Python is an object.....
You can never have too many examples of getting stuff to work, so to illustrate the point, I give you: attaching an interface to an anonymous function.

from zope.interface import Interface, implements, directlyProvides
from zope.component import getGlobalSiteManager, adapts

class ILambdaExpression(Interface):
pass
class IConcreteInterface(Interface):
pass

class MyAdapter(object):
implements(IConcreteInterface)
adapts(ILambdaExpression)
def __init__(self, lambda_exp):
self.lambda_exp = lambda_exp
def __call__(self):
return filter(self.lambda_exp, [1,2,3,4,5,6])

gsm = getGlobalSiteManager()
gsm.registerAdapter(MyAdapter)

myFilter = lambda i : i > 3
directlyProvides(myFilter, ILambdaExpression)

result = IConcreteInterface(myFilter)()
print result

>>> [4, 5, 6]

Simple but pretty cool.

Tuesday 10 August 2010

Error checking II

Last month I wrote a blog on why error checking and correction should be documented better and discussed more. In addition the "how" of error checking, it also seems like the "where" to error check can be ill documented and is effected by the tools and frameworks you maybe using.

When designing a function/method one decision that always needs to be made is whether to throw an exception or return a error/default value on an irrecoverable error. The best solution is normally to throw the exception. Returning a default value can make the API more complex, reduces the details about the original error and makes the code difficult to extend and debug. Catching the exception and returning a sensible default value is usually best left to the last point at which you can intercept it. This generally means directly before it hits the user interface.
def myFunction():
"""Allows an errors in doSomething to propagate.
Returns an array or throws an exception."""
return doSomething()

def myDefaultFunction():
"""Returns a default value.
Returns an array.
"""
result = []
try:
result = doSomething()
except StandardError:
pass
return result

A good example of why this can get messy is the MVC architecture pattern. MVC separates the data logic (Model), presentation logic (View) and the Controller which negotiate responses and submissions. The natural place for those pesky unresolved errors is in the View where they can be handled appropriately. The problem occurs because in a lot of frameworks the View is often synonymous with a template that doesn't have the necessary control to handle uncaught exceptions*. So we have to move the logic out, but the View has access to both the Model and the Controller (if it doesn't, it's not MVC) and we don't really want to have to catch exceptions and return default values in the Model. The Model controls the data and is important to the business logic; errors here need to be explicit, not default. So this leaves is with a bit of a mismatch of requirements that can further muddy the waters leading to clear and concise error checking.

* There is a lot of ambiguity in the definition of MVC, but the fact remains that a lot of frameworks explicitly allow the user access to both the View logic, be it template, presentation code, or both, and the Model (context).

Friday 2 July 2010

Error checking should be a first class citizen.

I don't think that error checking gets the attention it deserves. It should be one of the very first things that you learn to do properly when your developing in a new language and yet documentation on doing it "properly" is thin on the ground. Good error checking is fundamental to good code, but what's considered good changes depending on what your doing and in what language.

Python, for example, has very good exception checking; but do you use exception check all the time or do explicit checks for known errors? Well after some digging around the Python glossary states:
EAFP: Easier to ask for forgiveness than permission. This common Python coding style assumes the existence of valid keys or attributes and catches exceptions if the assumption proves false. This clean and fast style is characterized by the presence of many try and except statements. The technique contrasts with the LBYL style common to many other languages such as C.
So exception checking is considered a common style in Python, and further checks turn up this blog on the performance on Python's exception checking. After my own checks is seems that the exception block adds only a very minimal amount of overhead to the execution speed. The overhead from a try block is likely to be less than anything other than the most cursory explicit checks and you can error check a loop with a single try, whereas explicit check would have to be called per iteration. On the down side, if an exception in thrown, it's expensive. A good rule of thumb would be to use exception checking when code is unlikely to fail and explicit checks where it is.

Javascript is another language that supports exception checking, however there have been many articles indicating that using it can (under certain circumstances) severely impact performance-critical areas of code and should be avoided. In addition unlike most languages Javascript does not raise an error when trying to access an invalid property (it returns 'undefined') so this type of error would not be caught by a try block anyway. Finally Javascript errors do not cause a unilateral exit, it only stop the execution of of the current function and attempts to continue. This can of course cause cascading errors, but more importantly can lead to a more robust program if it designed to suit this style.

These are just some quick examples, and doesn't begin to cover things like custom exception re-raising, but it took a surprising amount of reading to find out these few scant details. Shouldn't these discussions be formalised right after basic syntax in the manual?