Tutorial

Setting up your Environment

You’ll first need to download the latest version of Objeck. The language runs on Windows, OS X and Linux. Target binaries (i.e. .obe and .obl) are cross platform compatible. The compiler and virtual machine are located in the “/bin” directory of the distribution along with supporting libraries.

Hello World!

  1. class Hello {
  2.   function : Main(args : String[]) ~ Nil {
  3.     "Hello World"->PrintLine();
  4.     "Καλημέρα κόσμε"->PrintLine();
  5.     "こんにちは 世界"->PrintLine();
  6.   }
  7. }

Save the code above in file called “hello.obs”. To compile the code execute the following command:

obc -src hello.obs -dest hello.obe

This command compiles the source file “hello.obs” into the target file “hello.obe” and links in any dependent libraries. To run the program execute the command:

obr hello.obe

Command line arguments

The program below prints out the number of arguments passed to it via the command line. It then prints out each argument. All basic datatypes support the Print and PrintLine methods. The each statement provides an index that can be used to loop through all of the elements in an array or Vector.

  1. class Command {
  2.   function : Main(args : String[]) ~ Nil {
  3.     args->Size()->PrintLine();
  4.     each(: args) {
  5.       args[i]->PrintLine();
  6.     };
  7.   }
  8. }

Save the program above in file called “cmd_line.obe”. To compile the code execute the command:

obc -src cmd_line.obs -dest cmd_line.obe

To run the program execute the command:

obr cmd_line.obe hello world again

Statements, Control Flow, Etc.

The programming example below is a simple code parser for a small subset of the language. The complete program and be viewed and download here. This program looks for language specific tokens (i.e. reserved words, numbers and symbols). We’ll walk-thru this program to illustrate how statements, control flow, collections and file access are done.

You might have noticed that the Parse function uses the keyword native. This keyword tells the runtime system to compile this function into machine code before executing it. In general, functions that are frequently called are better candidates for native compilation as there’s some overhead involved in converting bytecode into machine code. A good example of a program that benefits from JIT compilation can be viewed here this program is part of the CLBG suite.

Save the program above in file called “parser.obe”. To compile the code execute the command below. Note, we’re using the shared library “colllect.obl”. This library contains collection classes that are used in the program.

obc -src parser.obs -lib colllect.obl -dest parser.obe

This command compiles the source file “parser.obs” into the target file “parser.obe” and links in any dependent libraries. To run the program execute the command:

obr parser.obe parser.obl

Storing reserved words

  1. reserved := StringMap->New();
  2. reserved->Insert("method", "keyword: method");
  3. reserved->Insert("function", "keyword: function");
  4. reserved->Insert("Int", "keyword: Int");
  5. reserved->Insert("Float", "keyword: Float");
  6. reserved->Insert("class", "keyword: class");
  7. reserved->Insert("bundle", "keyword: bundle");
  8. reserved->Insert("native", "keyword: native");

The block of code above is adding keywords to a StringMap instance named reserved. The StringMap class is derivative of the more general Map class, which provides support for managing key/value pairs. Keys within a Map must implement the Compare interface.

Reading a file

  1. reader := FileReader->New(file);
  2. while(reader->IsEOF() <> true) {
  3.   line := reader->ReadString();
  4.   line_num := line_num + 1;

FileReader is a class that allows programmers to read files. In our program, we’re opening a file and reading each line of that file until we hit the EOF marker. Each line is then parsed for tokens of interest.

Skipping whitespace

  1. # skip whitespace
  2. while((line->Get(i) = ' ' | line->Get(i) = '\t') & i < line->Size()) {
  3.   i += 1;
  4. };

Checking for reserved words

  1. result := reserved->Find(string)->As(String);
  2. if(result <> Nil) {
  3.   result->PrintLine();
  4. };

On line 45, we’re using the StringMap Find method to see if the String we’ve parsed contains a reserved word. The As operation is used to cast the result to a String. The left-hand side variable “result” will automatically be assigned a String type. The type that the “result” variable is referencing to may not be changed in the future. Variables can also be explicitly typed during declaration. For example, line 45 could be rewritten as follows:

  1. result : String := reserved->Find(string);

Checking for symbols

  1. select(line->Get(i)) {
  2.   label '(': {
  3.     "opren"->PrintLine();
  4.   }
  5.  
  6.   label ')': {
  7.     "cpren"->PrintLine();
  8.   }

The block of code above uses a select statement to test if we’ve parsed a symbol of interest. Each block of code within a label has it’s own local scope allowing programmers to easily declare variables. The other keyword is used to catch values that fall-thru the select. Select statements are very efficient as the compiler generates instruction equivalents of “jump tables” for fast evaluation.

Classes and Interfaces

The programming example below highlights some of the object-oriented features of the language. The complete program and be viewed and download here. Objeck is a strongly typed language and doen’t support the runtime modification of class definitions. The language does support the dynamic casting of object and interface references along with the runtime resolution of virtual methods.

Interfaces and Inheritance

An interface is an object contract that guarantees that certain functions and/or methods have implemented by a given class. A class may implement more than one interface and interfaces may be inherited from one another. Interfaces can be casted to concrete object instances using the As keyword. The TypeOf keyword is used to determine if an object instance belongs to a given class or interface. For example:

  1. type_of := pinto->TypeOf(Vehicle);
  2. type_of->PrintLine();
  3. type_of := star_ship->TypeOf(Vehicle);
  4. type_of->PrintLine();	
  5. type_of := pinto->TypeOf(StarShip);
  6. type_of->PrintLine();

A new class can be inherited from any existing class. The parent class can be declared in program source or in a shared library. An inheriting class may override any of it’s parent methods or functions. If a class is inherited from a shared library it doesn’t have direct access to its parent’s member variables. Indirect access to parent member variables can be provided via getters.

Save the program above in file called “cls_inf.obe”. To compile the code execute the command below:

obc -src cls_inf.obs -dest cls_inf.obe

This command compiles the source file “cls_inf.obs” into the target file “cls_inf.obe” and links in any dependent libraries. To run the program execute the command:

obr cls_inf.obe

Introspection

The program below prints out metadata about the String class. Object metadata is encoded into programs at compile time and can may be accessed by any program at runtime. From an object instance its Class can be obtained. The Class allows an programmer get additional information about the object, for examples it’s methods.

  1. use IO;
  2.  
  3. class Introspection {
  4.   function : Main(args : String[]) ~ Nil {
  5.     s := String->New();
  6.     c := s->GetClass();
  7.     "======"->PrintLine();
  8.     Console->Print("class=")->PrintLine(c->GetName());
  9.     "======"->PrintLine();
  10.     m := c->GetMethods();
  11.     each(i : m) {
  12.       "  ------"->PrintLine();
  13.       Console->Print(" method=")->PrintLine(m[i]->GetName());
  14.       b := m[i]->GetName()->Equals("  New");
  15.       Console->Print("  is constructor=")->PrintLine(b);
  16.       p := m[i]->GetParameters();
  17.       Console->Print("  number of parameters=")->PrintLine(p->Size());
  18.       each(j : p) {
  19.         a := p[j];
  20.         dim := a->GetDimension();
  21.         select(a->GetType()) {
  22.           label TypeId->BOOL: {
  23.             Console->Print("   parameter type=bool, dim=")->PrintLine(dim);
  24.           }
  25.  
  26.           label TypeId->BYTE: {
  27.             Console->Print("   parameter type=byte, dim=")->PrintLine(dim);
  28.           }
  29.  
  30.           label TypeId->CHAR: {
  31.             Console->Print("   parameter type=char, dim=")->PrintLine(dim);
  32.           }
  33.  
  34.           label TypeId->INT: {
  35.             Console->Print("   parameter type=int, dim=")->PrintLine(dim);
  36.           }
  37.  
  38.           label TypeId->FLOAT: {
  39.             Console->Print("   parameter type=floaat, dim=")->PrintLine(dim);
  40.           }
  41.  
  42.           label TypeId->CLASS: {
  43.             Console->Print("   parameter type=class, name=")->Print(a->GetClassName())
  44.               ->Print(", dim=")->PrintLine(dim);
  45.           }
  46.  
  47.           label TypeId->FUNC: {
  48.             Console->Print("   parameter type=function, dim=")->PrintLine(dim);
  49.           }
  50.         };
  51.       };
  52.     };
  53.   }
  54. }

Save the program above in file called “introspec.obe”. To compile the code execute the command below:

obc -src introspec.obs -dest introspec.obe

This command compiles the source file “introspec.obs” into the target file “introspec.obe” and links in any dependent libraries. To run the program execute the command:

obr introspec.obe

HTTP and XML

The language include a HttpClient that allows programmers to access web-based HTTP resources. This client may be used to fetch an XML document from a web server and then parse the document using XmlParser class. The XmlParser allows a programmer parse XML documents and integrate them using DOM style APIs. The HTTP and XML frameworks are native code and run on all supported platforms.

HTTP and cookie support

The HttpClient class support both GET and POST requests. In addition, cookies can be enabled to maintain session information between calls. The example below makes two GET requests. The first request sets a cookie, while the second request reads the cookie that was set prior. Here’s an addition example that makes a POST request to a server passing an XML SOAP message and then parses the response.

  1. use System.IO.Net;
  2. use Collection;
  3.  
  4. class HttpTest {
  5.   function : Main(args : String[]) ~ Nil {
  6.     client := HttpClient->New();
  7.     # enable cookies
  8.     client->CookiesEnabled(true);
  9.     # request creates a cookie
  10.     lines := client->Get("http://www.rexswain.com/cgi-bin/cookie.cgi?create", 80);
  11.     each(i : lines) {
  12.       lines->Get(i)->String)->PrintLine();
  13.     };
  14.     # request sends back cookie
  15.     lines := client->Get("http://www.rexswain.com/cgi-bin/cookie.cgi", 80);
  16.     each(i : lines) {
  17.       lines->Get(i)->String)->PrintLine();
  18.     };
  19.   }
  20. }

Parsing XML

Our final example highlights some of the core XML parsing capabilities that are part of the distribution. The demo program parses a WSDL document. The complete program and be viewed and download here along with the WSDL. The XML bundle also has a XmlBuilder class that allows programmers to build XML documents.

The excerpt below reads an XML file, parses it and searches for a list of element nodes.

  1. parser := XmlParser->New(FileReader->ReadFile(name));
  2. if(parser->Parse()) {
  3.   results := parser->FindElements("/wsdl:definitions/wsdl:types");

This code snippet shows to search for direct children loop thru the results.

  1. results := types->FindElements(elem_name);
  2. each(i : results) {     
  3.   elem := results->Get(i)->XMLElement);

Save the program above in file called “wsdl_parser.obe”. To compile the code execute the command below. Note, that we’re linking in classes from the “xml.obl” shared library.

obc -src wsdl_parser.obs -lib colllect.obl,xml.obl -dest wsdl_parser.obe

To run the program execute the command

obr wsdl_parser.obe 

Regular Expressions

Below is a regex program that will pull out URLs from a webpage.

  1. use HTTP;
  2. use RegEx;
  3.  
  4. class RegExUrls {
  5.   function : Main(args : String[]) ~ Nil {
  6.     if(args->Size() <> 1) { return; };
  7.  
  8.     lines := HttpClient->New()->Get(args[0]);
  9.     input := "";
  10.     each(i : lines) {
  11.       input->Append(lines->Get(i)->As(String));
  12.     };
  13.  
  14.     input->PrintLine();
  15.     expr := "(href|HREF|src|SRC)=(\"|')(http://|https://|/)?((\\w|\\d|-|_)";
  16.     expr += "+(\\.|/)?)+(\\?(\\w|\\d|-|_)+=(\\w|\\d|-|_)+)?(&(\\w|\\d|-|_)";
  17.     expr += "+=(\\w|\\d|-|_)+)?(\"|')";    
  18.     found := RegEx->New(expr)->Find(input);
  19.     "---"->PrintLine();
  20.     each(i : found) {
  21.       found->Get(i)->As(String)->PrintLine();
  22.     };
  23.   }
  24. }

Save the program above in file called “regex.obe”. To compile the code execute the command below. Note, that we’re linking in classes from the “regex.obl” shared library.

obc -src http_regex.obs -lib colllect.obl,regex.obl -dest http_regex.obe

To run the program execute the command:

obr http_regex.obe "http://daniels.du.edu"