Friday, February 22, 2008

Hey Ruby: Where's the Main Program?

So as I get deeper into Ruby and Rails, I've found I've been going absolutely nuts! trying to understand how the programs work.

I think I finally figured out my problem. (That's right, it's a problem with ME for a change!)

There's no 'main' in a Ruby program.

Most executables - as in /usr/local/bin/foo - are two to ten line Ruby scripts which set up some environment variables and 'require' the 'real' script. The 'real' script usually 'require's a bunch of other scripts, instantiates an object, and calls what appears to be a random method.

That's it.

Step back and contrast this with C, Java, Python*, FORTRAN, COBOL, the Boot Sequence of a computer, ... Need I go on? Everyplace else there is (or pretty much is) a well known function, procedure, 'program', file or something where execution starts for every program which is written. Even Javascript kicks off with an 'onload' function (except in JQuery, but I think that's really a wrapper).

Notice I've left out Lisp, Scheme, Smalltalk and a whole bunch of other languages.

I don't know much about them - from a practical point of view - except that they are interpreted, don't (to my knowledge) have a 'main' entry point, and allow programmers to modify the base system so that it is unique to their program.

Now, I know someone might argue that all Ruby programs start by firing up the interpreter and loading the environment, so I'm wrong - as usual. But that's not what I'm talking about.

'main' is the start of the logic of the program. Knowing this gives (the generic) you a place to start unraveling the logic of a program. This seems like a 'good thing' (trade mark), but is it?

The whole idea of 'main' was really invented so that other programs (loaders) would know where to start executing a program. This is a 'convenience' with compiled programs: programs where the source code is processed into (possibly virtual) machine instructions and then further processed into an executable image saved in a file. This executable image is then loaded, source code agnostically, into the execution environment of a computer and run. It's a simple fact that the 'loader' needs a place to start and it doesn't know from beans about the source code - hence the well known 'main'.

You don't need this for interpreted, dynamic languages, but the S/W community seems to have carried this structure forward.

I think Ruby represents a significant break from this architecture.

Ruby 'programs' seem to be a bunch of symbiotic objects, executing in a common (probably specialized) runtime environment. Various behaviors (programs) can be achieved by instantiating different objects and calling appropriate 'starting' methods. This is similar to, but much more fluid than, writing a program within the constraints of a published API for, say, Windows, or a purchased library.

I like it.

I don't know how to understand it easily yet, nor do I think anyone really knows how to document it yet, but I think it's an advance.

* Python really doesn't have a 'main' either, but it has taken the 'flavor' of 'main' stipulating that code can be conditionally executed if it is 'run' as though it were the 'main' program AND a chunk of code is included of the form:

if __name__ == '__main__':
some code

This chunk typically goes at the bottom and is encouraged when the code in the file can server either as the basis for a stand-alone program or an importable unit to another OR for testing.