[Gllug] OSS CMSs

Richard Jones rich at annexia.org
Sun May 1 07:21:29 UTC 2005


On Thu, Apr 28, 2005 at 07:23:01PM +0100, Doug Winter wrote:
> Richard Jones wrote:
> >Well, it's a dynamically typed language, so like all the other dynamic
> >languages we're talking about (Python, Ruby), it suffers in comparison
> >to the better statically typed languages with type inference (OCaml,
> >Haskell, SML).
> 
> I'm intrigued - can you give me an example of your point?

Consider the following function (I know it's dumb - it's just an
example):

  let drain_stack s =
    while not s#empty do
      s#pop ()
    done

('obj#foo' is the method call operator, like 'obj->foo' or 'obj.foo'
in whatever is your favourite language).  This function "drains" a
stack object - repeatedly calling the pop method until the stack is
empty.

Imagine the equivalent function in Perl or Python.  This function will
work fine provided you always pass an object ('s') which has 'empty'
and 'pop' methods.  If you accidentally call 'drain_stack' with
something else - an integer, for example, or an object which doesn't
have either of these methods - then it'll throw a runtime error.

Consider the equivalent function in Java.  Actually there are two
possibilities for Java.  One case is you've got a superclass /
interface called 'Stack', and you've defined 's' as having type
'Stack'.  Something like:

  public static void drain_stack (Stack s) { ... }

In this case you are restricted to passing objects with the correct
interface - this is more restrictive than Perl or Python where you
don't need to worry about setting up class hierarchies in advance.

Another case is that you pass a Java 'Object' and use reflection.
This case gives you the equivalent expressivity to Perl or Python, but
(as with Perl/Python) with the risk of getting a runtime error because
you passed in an 'Object' which lacks the two methods required.

	OK, so let's get on to my actual point ... !

Your customer calls you up one day saying that your program has
broken, and you track it down to the wrong type of object being passed
into 'drain_stack' - specifically an object which lacks the required
two methods.  They're not happy.  You resolve to write a test which
will catch this sort of error in future to avoid similar embarrassment
happening again.

How do you go about this?  Well, with extreme difficulty in Perl,
Python, or Java-with-reflection.

What if there was a language which actually checked this stuff for you
_at compile time_?  Well, of course there is.  I'm talking (in this
case) about OCaml.  When you type the above function definition into
OCaml, it prints out the expected type (using its type inference
system):

val drain_stack : < empty : bool;
                    pop : unit -> 'a;
                    .. > -> unit = <fun>

The <...> notation means an object, in this case, an object with two
methods ('empty' and 'pop'), and any other methods ('..').  It's
saying there that the 'drain_stack' function is expecting an object
with those two methods.  [Note that the object doesn't need to have a
specific superclass.]

And furthermore, it'll check each and every call to 'drain_stack',
automatically, to ensure that you always call it with the right type.
At compile time.  So the executable you get out cannot contain this
class of errors.  It can't contain any type errors.

Another thing to note: We didn't need to provide any type information.
OCaml works this all out for you.  This is type inference.

Rich.

-- 
Richard Jones, CTO Merjis Ltd.
Merjis - web marketing and technology - http://merjis.com
Team Notepad - intranets and extranets for business - http://team-notepad.com
-- 
Gllug mailing list  -  Gllug at gllug.org.uk
http://lists.gllug.org.uk/mailman/listinfo/gllug




More information about the GLLUG mailing list