The Inferno and the Purgatory


Let's be clear on one crucial point, Limbo and nearly all the other technologies reviewed on our page, would have been impossible without C. C is almost the mother technology when it comes to computer programming. Almost no other language has as faithful and numerous fan following. C gave computer programmer unrivaled power over there machines. Nothing can be close to matching the power and flexibility of C !

Today, we don't read the NewYork Times because it isn't written in C/C++ !! ( and besides, it's not available in India !! ). C is the first language of millions of avid programmers the world over who probably read more lines of C code than any other language, computer oriented or otherwise.

So when we learnt that our gurus, Mr. Brian Kerningham and Mr. Dennis Ritchie were involved with Inferno and Limbo, we got really excited ! We used to regularly visit the Inferno Web site twice and sometimes thrice a day, eagerly awaiting the release of this product.

The world of computers has changed radically within the last few years and words like Distributed Computing and Networking are in. Inferno is the first OS we know of whose manual mentions these important words on nearly every page ! theoretically, using Inferno, I can use my TV remote control to access a program on my computer hundreds of miles away and have the results displayed back on the television screen in my living room ! Unfortunately, no sample code to do this was provided in the Inferno and Limbo samples, so I guess you'll have to wait a while to see this stuff in action.

We were a teeny weeny bit disappointed when we first saw Limbo code. Sorry guys, but it doesn't look anything like C !! The reason we took to Java with such enthusiasm was because it looked just like C/C++, Limbo doesn't and I'm really disappointed about that.

If anyone today has any moral authority over C programmers, it is Dennis Ritchie and Brian Kerningham. If they had made sure that Limbo looked like C, half the worlds C programmers would have switched to Limbo immediately. And don't tell me they couldn't have done it ! I guess sometimes people don't realize their own significance.

We're not through nagging yet ! The smallest Limbo programs are just too large. With C, you needed just a couple of lines of code to demonstrate the hello world example. Under Limbo, that program quadruples in size and complexity.

We're not through experimenting on Limbo just yet and our criticisms of it are not thoroughly researched. But give us some time and we'll get some real dirt on Limbo !! Seriously, this tutorial is under construction, so do come back later to check how things have turned out.

Brimstone time !!

Download Inferno and the Limbo compiler from the Bell labs site on the Web. We had Windows NT installed on your machine.

The file is about 15 MB large, so make sure you've got plenty of time on your hands ( and space on your disk ) when you start the download !!

The first few hesitant steps...

These first two programs are straight from Kernigaham's tutorial on Limbo and after that we start giving our own examples. I recommend the tutorial , it's well worth the download time.

Once you've got the stuff from the 'net, go to the directory where you've installed Inferno (C:\users\inferno\ in our case ). There, create a subdirectory in users where you'll be doing all your work.

The code we've given you has absolutely no error checks or any fancy interface. It's absolutely bare and it's just there for you to learn from. However, you can flesh it out and use it elsewhere if you wish.

We're running our copy of Inferno under Windows NT. We're doing all our typing work in a DOS box because the emulator reminds us too strongly of UNIX and we'd rather do a dir instead of a ls, thank you very much !

We'll be using the suave and sophisticated EDIT for our word-processing needs.

Using EDIT, create a file called a1.b

implement zzz;
include "sys.m";
s:Sys;
include "draw.m";
zzz: module
{
init:fn(ctxt: ref Draw->Context, argv: list of string);
};
init(ctxt: ref Draw->Context, argv: list of string)
{
s=load Sys Sys->PATH;
s->print("hello, world\n");
}

The first line of any limbo program has to be an implement. We've called the file a1.b, but since we can use any name over here, zzz will suffice. Zzz is a module. How do we know ? Well look a couple of lines down the code and you'll see the line zzz : module. Now usually when you want to say "Sonal is bad" you say "Sonal is bad" ( and promptly get hit on the nose ! ). You don't say "Bad is Sonal", yet that's exactly what C forces you to do. You don't say a is an int, instead you say, int a. In Limbo, this grammatical oversight has been rectified. So when I say zzz : module, it means zzz is a module.

For the ones familiar with classes, you can carry out a mental find and replace operation where you automatically convert every instance of the word 'module' with 'class prototype'. A module is like a class. It contains no code, just variable and function prototypes. Bear in mind that all variables in Limbo are considered to be objects.

Our module zzz has one function name within it, init. After init, we place a colon and define what init is, in this case, a function which takes up two parameters. Argv and ctxt are the names of these parameters and their data types are defined after the colon. We wouldn't be using them anywhere in the program, so forget about them.

So now we've got a module. Normally, the code in zzz : module would reside in a file name zzz.m, but because we've defined only one function and we don't want things to get more complicated than necessary, we've included it into our main .b file. It's a bit like putting class prototypes in header files. In C we have functions like printf. In Limbo, when we have to call functions we have to include a .m file, a bit like the .h header files in C. If you want, you can check out the code in these .m files by opening them up in EDIT. The real code is always contained in a .b file.

In the program, we say s : Sys, i.e. small s looks like Sys. It's a lot like defining the instance of a class.

In C, by convention, Main would be called first. In the same way, in Limbo, the function init is called first. S is in a sense, a bit like a pointer, so we need to initialize it. Hence we say load a module called Sys. The operator Load realizes that the file Sys.m has been included in by us and thus initializes s to an instance of Sys.m.

In the module Sys.m there is a variable ( or object if you will ) called PATH which tells load where the code of Sys.m lies. When you run Limbo on your .b file, you get a file called a1.dis, which we'll call, for want of a better word, an .exe file, or for Java programmers, a .class file. The reason we need to specify the location of the code is because it could be on the hard disk or anywhere across the Internet.

The symbol -> ( minus greater ) is a pointer representation, but unlike in C, we don't have any real pointers here. They're too dangerous. So we use references instead, which function superficially like pointers. To call a function from within, you use the C pointer notation, even though it's not a pointer in the true sense of the word.

To run the programs, type the program name at the prompt.

Any errors and you'll know why they've called the compiler Limbo...

implement Hello2;
include "sys.m";
s: Sys;
include "draw.m";
d: Draw;
include "tk.m";
tk: Tk;
Hello2: module
{
init:   fn(ctxt: ref D->Context, argv: list of string);
};
init(ctxt: ref D->Context, argv: list of string)
{
s = load Sys Sys->PATH;
d = load Draw Draw->PATH;
tk = load Tk Tk->PATH;
t := tk->toplevel(ctxt.screen, "");
tk->cmd(t, "button .b -text {hello, world}");
tk->cmd(t, "pack .b");
tk->cmd(t, "update");
s->sleep(10000);      
}
In this program we've included another module called draw.m. Like sys.m, draw.m is a function prototype, where d looks like the object draw.m. TK is the graphical toolkit used by Limbo, and I suggest you read our tutorial on Sun's Tcklets ( or Tcl/Tk plugin ) which describes the TK toolkit in association with TCL. In this program we make tk look like the object Tk and s the object like sys in just the same way as we initialized d to draw.

When we say tk->toplevel, it obviously implies that the TK module tk contains a function called toplevel. In TK, we need a reference or a handle to a toplevel window in which we place our buttons and such. We're storing this handle in a variable called t. The second function we called from within Tk is cmd, which stands for command. We give it the handle to the toplevel window and then write code the way the TK syntax demands it. To get a button, we say button .b -text {hello, world}, to get a button with the specified text on it. You must give the pack .b command to see the button displayed ( A rule in TK ). If we hadn't used the key word update, you'd have to move the mouse over the screen so that the screen is redrawn and the button displayed. Update automatically updates the screen for you. We use sleep to make sure that the button is displayed for some time before it disappears.

To run the graphical programs, type wm/logon at the Unix prompt. The give the password Inferno in the user identification box that pops up. Click on the start button and select local disk. Then go to the relevant folder and double click on the colorful icon next to your .dis program. That's all there is to it !

Downloading files from the Internet.

implement sonal;
include "sys.m";
include "draw.m";
s: Sys;
sonal: module
{
init:   fn(ctxt: ref Draw->Context, argv: list of string);
};
init(ctxt: ref Draw->Context, argv: list of string)
{
s=load Sys  Sys->PATH;
ctl := s->open("/cmd/clone", s->ORDWR);
buf := array[32] of byte;
n := s->read(ctl, buf, len buf);
dir := "/cmd/"+string buf[0:n];
s->fprint(ctl, "exec "+"webget -s");
data := s->open(dir+"/data", s->ORDWR);
s->fprint(data, "GET %s %s %s\n","http://www.microsoft.com/","","text/html");
o := 1;
b:=  array[1] of byte;
c := array[1000] of byte;
while ( o != 0 )
{
o=s->read(data, c, len c);
s->print("\n%s\n",string c);
}
exit;
}
In the third program, we have a module named Sonal. We also include the modules sys.m and draw.m. In the init function, we first initialize s to sys. This is important as we're now dealing with files across the Internet. Limbo borrows a lot from UNIX, where almost everything is treated as a file. If you want to connect to a SMTP server, a HTTP server or any other kind of server, you have to treat the connection like a file. Limbo and Inferno both follow the same approach to Internet file transfers, which is why the file handling functions in Sys are important.

After having initialized s to Sys in the main Init function, we open a file for read/write operations. Ctl is something called a control file. We'll discuss it later. Since we've said ctl := s->open("/cmd/clone", s->ORDWR);, we don't have to specify the data type of ctl. buf is a buffer of 32 bytes. Next we have the read, which accepts the file handle, array and length of the array as parameters. It returns the number of characters it has read, which is stored in n.

Dir is a string and the plus sign (+ ) is used for string concatenation. While concatenating, we say buf[0:n], which means start from 0 and read on till you reach character n. So the line becomes /cmd/<whatever the read reads>

Fprint is a lot like the sprintf function in C and it writes to the ctl file. In this case it write the string exec webget -s. Webget is an .exe file in the same subdirectory as emu.exe. What we've done here is say that whenever we write to the file ctl, webget is called.

Next we use the function open, where the file names depend on our earlier actions. Data is the file handle. The name of the file was decided by the first open statement.

Now, whenever you want to talk to an HTTP server, you give fprint a GET, the name of the server and the mime type of the document to be retrieved. Fprint will then connect to the server automatically. To retrieve the data, all we need is a read statement. So we put the read into a while loop and keep putting the data received into an array 1000 bytes large. We also keep printing that array out onto the screen. When read returns a zero, the while loop ends and the program quits out.

implement sonal;
include "sys.m";
s: Sys;
include "draw.m";
include "html.m";
h: HTML;
include "webget.m";
w: Webget;
sonal: module
{
init:   fn(ctxt: ref Draw->Context, argv: list of string);
};
init(ctxt: ref Draw->Context, argv: list of string)
{
s  = load Sys  Sys->PATH;
w = load Webget Webget->PATH;
h = load HTML HTML->PATH;
(web,nil) := w->start();
spawn msgslave(web);
w->web.header(0,"","http://www.microsoft.com/","text/html", "");
contents := w->web.contents("nil");
t := h->lex(contents, 1);
n := len t;
for(i := 0; i<100; i++) 
s->print("%s",t[i+1].text);                         
exit;
}
msgslave(x: ref w->Webio)
{
for(;;) 
(t, msg, url) := <- x.msg;
}
Example number three was a little complicated, here's an easier way.

Here we have two new modules called webget.m and html.m. Both the modules get initialized. We've also got three initializing variables, where h stands for html and w represents webget, a module which contains the function start. As can be seen, start returns a tuple, i.e. a pair of values. One is stored in web, the other in nil.

Next we have spawn, which starts off the program msgslave, where web looks like webio, a class within a class ( known as an adt or advanced data type ) in webget. View the code and check this out yourself.

After that, we call a function from within webio, a class ( or adt ) within webget. That function is header. Only two parameters are important, the name of the server you want to connect to and the mime type. Contents holds the contents of the file. These contents are in HTML format and thus contains a whole load of troublesome tags. To get rid of these tags we use the module html, which contains a function called lex, which strips off all these HTML tags. This will display the first hundred lines of text. Because t is an array, we'll say t[1] to access character one and t[2] for character two. Text gives you the text version of the file.

Msgslave keeps executing in the background and the <- is called a channel, something we'll get into at a later stage.

NOTE : I can't help it. I have to explain my genius !! Notice the title, The inferno and the Purgatory. I guess it would surprise you to know that Purgatory is a synonym of the word limbo and it is also the name of the second half of the Inferno, by Dante. Good No ?!! :-)

To be continued...


The tutorial is a joint effort of
Mr. Vijay Mukhi
Mr. Arsalan Zaidi

Move back to the Vijay Mukhi's Technology Cornucopia Page to learn more about the other new Internet Technologies.


Vijay Mukhi's Computer Institute
VMCI, B-13, Everest Building, Tardeo, Bombay 400 034, India
E-mail:vmukhi@giasbm01.vsnl.net.in Tel : 91-22-496 4335 /6/7/8/9 Fax : 91-22-307 28 59
http://www.vijaymukhi.com