Before you get started please checkout the Objeck class libraries. Over the years, Objeck has become a collect of libraries to get stuff done vs. an experiential language with evolving features. See what's available and you're interested read on!
Contents
Installation
Objeck can be installed using an installer for Windows or compressed archive. Supported platforms are Windows (x86_64 and x86), macOS (arm64 and x86_64) and Linux (x86_64 and x86).
In order to compile programs outside of the "bin" directory the "OBJECK_LIB_PATH" environment variable must be set. When this variable is set all library files must be in the directory specified.
If the Windows installer is used these variables will be automatically set after the system is restarted. For Debian and Ubuntu the location of the files is fixed by the installer so no variables are needed.
Windows
To manually setting the environment paths in Windows:
set OBJECK_LIB_PATH=C:\Users\[account]\objeck-lang\lib set PATH=%PATH%;C:\Users\[account]\objeck-lang\bin;C:\Users\[account]\objeck-lang\lib\sdl
macOS and Linux
To manually setting the environment paths in macOS and Linux:
export PATH=$PATH:/home/[account]/objeck-lang/bin export OBJECK_LIB_PATH=/home/[account]/objeck-lang/lib
Simple Compile & Execute
obc -src hello.obs obc -src 'C:\Program Files\objeck-lang\examples\encrypt.obs' -lib encrypt -dest encrypt obr hello.obe
Compile/execute for code that has library dependencies:
obc -src ..\examples\xml_path.obs -lib xml
Hello World!
class Hello {
function : Main(args : String[]) ~ Nil {
"Hello World"->PrintLine();
"Καλημέρα κόσμε"->PrintLine();
"こんにちは 世界"->PrintLine();
}
}
Save the code above in file called "hello.obs". To compile the code execute the following command:
obc -src hello.obs
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
Building Code
The Objeck compiler produces two types of binaries. The first is an executable and the second type is a library. Libraries can be linked into executables by passing the names of libraries to the compiler. As a naming convention executables end with *.obe while shared libraries end with *.obl.
Here are a few examples. The first example compiles and runs a program that processes XML. For this program we link in the collections and XML parsing libraries.
obc -src examples/2_xml.obs -lib xml obr xml_path.obe
The next example compiles and runs program that uses the encryption library.
obc -src examples/7_encrypt.obs -lib encrypt obr encryption.obe
For an extensive list of example programs check out the Rosetta code solutions. To learn more about other libraries please check out the API documentation.
TABLE 1 – COMPILER OPTIONSOption | Description |
---|---|
-src | path to source files delimited by commas |
-lib | list of linked libraries separated by commas |
-ver | displays the compiler version |
-tar | ttarget type 'lib' for linkable library or 'exe' for executable default is 'exe' |
-opt | optimization level, s0 thru s3 being most aggressive; default is s3 |
-dest | binary output filename |
-asm | emits a human readable debug byte assembly file |
-alt | use C like syntax instead of UML like default |
-debug | compile with debug symbols (must be last argument) |
-strict | exclude default system libraries and provide them manually |
Basics
Let's first look at literals, variables and control flow.
Literals and variables
Literals are defined as they are in most programming languages. In Objeck literals are treated as objects and may have methods associated with them.
'\u00BD'->PrintLine();
13->Min(3)->PrintLine();
3.89->Sin()->PrintLine();
0xCB0->PrintLine(); # hex
-0b1101->PrintLine(); # bin
052->PrintLine(); # oct
"Hello World"->Size()->PrintLine();
Here are a few examples of variable declarations and assignments. Variable types can be explicitly defined or implicitly inferred through assignments or casts. If a variable's type is inferred it cannot be redefined later in the program however it can be cast.
a : Int;
b : Float := 13.5;
c := 7.25; # type inferred as Float
d := (b * 2)->As(Int); # type inferred as Int
Also support for multi-variable assignment and negation.
a, b : Float := 13.5;
b += -a * 13;
"{$b}"->PrintLine();
a := b := c := 3.15;
"{$a} {$b} {$c}"->PrintLine();
d := a < b ? "less" : "greater"; # conditional operator
Types can also be described and referenced using aliases.
function : Multiplier(a : FloatRef, b : FloatRef) ~ \Func->Proc {
return \Func->Proc : (c) => a * b * c;
}
}
alias Func {
Proc : (FloatRef) ~ FloatRef
}
TABLE 2 – DATA TYPES
Type | Description |
---|---|
Char | Unicode character value (4-bytes POSIX, 2-bytes Windows) |
Char[] | Unicode character array (4-bytes POSIX, 2-bytes Windows) |
Bool | Boolean value (1-byte) |
Bool[] | Boolean array (1-byte) |
Byte | 1-byte integer value |
Byte[] | 1-byte integer array |
Int | 8-byte integer value (4-bytes on file system) |
Int[] | 8-byte integer array (4-bytes on file system) |
Float | 8-byte decimal value |
Float[] | 8-byte decimal array |
Object | Reference to an abstract data type (8-bytes) |
Object[] | Array of abstract data types (8-bytes) |
Function | Functional reference (8-byte, paring) |
Comments
Comments may span a single line or multiple lines. In addition, comments for bundles, classes, interfaces and functions/methods may be used to produce code documentation. Please refer to the project website for additional information about generating documentation from your code.
flag := false; # single line comment
#~
multiline comment. flag above
may be set to true or false
~#
Control Flow
As with most languages Objeck supports conditional expressions and control flow logic. One nuance is that conditional statements end with semi-colons.
If/else
An "if/else" statement is a basic control statement.
number := Console->ReadLine()->ToInt();
if(number <> 3) {
"Not equal to 3"->PrintLine();
} else if(number < 13) {
"Less than 13"->PrintLine();
} else {
"Some other number"->PrintLine();
};
Select
Select statements can be used to efficiently map integer and enum values to blocks of code.
select(c) {
label Color->Red: { "Red"->PrintLine(); }
label Color->Green: { "Green"->PrintLine(); }
label Color->Purple: { "Purple"->PrintLine(); }
other: { "Another color"->PrintLine(); }
};
select(n) {
label 9:
label 19: { n->PrintLine(); }
label 0x1b: { (3 * 9 = n)->PrintLine(); }
};
The language supports for the following looping statements
Do/While
A "do/while" loop is a basic post-test loop.
i := 0;
do {
i->PrintLine();
i += 1;
} while(i <> 10);
For
A "for" loop is a controlled loop with an explicated control expression.
location := "East Bay";
for(i := 0; i < location->Size(); i += 1;) {
location->Get(i)->PrintLine();
};
Each
An "each" loop is a controlled loop that iterates though all elements in an array or collection. Items can also be iterated in reverse using the "reverse" keyword.
area_code := Int->New[3];
area_code[0] := 5;
area_code[1] := 1;
area_code[2] := 0;
sum := 0;
each(i : values) {
sum += area_code[i];
};
sum->PrintLine();
Reverse
The "reverse" keyword iterates items in reverse.
numbers := [1, 2, 3, 4, 5];
reverse(i : numbers) {
numbers[i]->PrintLine();
};
An "each" or "reverse" loop can also bind to a variable using the assignment operator instead of a colon.
strings := Collection.Generic.Vector->New()<String>;
strings->AddBack("abd");
strings->AddBack("efg");
strings->AddBack("hij");
strings->AddBack("lmn");
reverse(string := strings) {
string += ", 123";
each(letter := string) {
letter->PrintLine();
};
};
Leaving
The "leaving" keyword is used to execute a block of code at the end of method/function
function : WriteSocket(bytes : Byte[]) ~ Nil {
client := TCPSocket->New("localhost", 4660);
leaving {
client->Close();
};
if(client->IsOpen()) {
size := bytes->Size();
size_str := size->ToString();
client->WriteString(size_str);
client->WriteBuffer(0, size, bytes)->PrintLine();
};
}
Operators
There’s support for logical, mathematical and bitwise operators. Operator precedence from weakest to strongest is: logical, [+, -] and [*, /, %, <<, >>, and, or, xor]. Operators of the same precedence are evaluated from left-to-right.
TABLE 3 - LOGICAL
Operator | Description |
---|---|
& | And |
| | Or |
= | Equal |
<> | Not equal and unary not |
< | Less than |
> | Greater than |
<= | Less than or equal |
>= | Greater than or equal |
TABLE 4 - MATHEMATICAL
Operator | Description |
---|---|
+ | Add |
+= | Add to variable |
++ | Increment variable |
- | Subtract |
-= | Subtract from variable |
-- | Decrement variable |
* | Multiply |
*= | Multiply to variable |
/ | Divide |
/= | Divide from variable |
% | Modulus |
TABLE 5 – BITWISE
Operator | Description |
---|---|
<< | Shift left |
>> | Shift right |
and | Bitwise and |
or | Bitwise or |
xor | Bitwise xor |
class Luhn {
function : IsValid(cc : String) ~ Bool {
isOdd := true; oddSum := 0; evenSum := 0;
for(i := cc->Size() - 1; i >= 0; i -= 1;) {
digit : Int := cc->Get(i) - '0';
if(isOdd) {
oddSum += digit;
} else {
evenSum += digit / 5 + (2 * digit) % 10;
};
isOdd := isOdd <> true;
};
return (oddSum + evenSum) % 10 = 0;
}
function : Main(args : String[]) ~ Nil {
IsValid("49927398716")->PrintLine();
IsValid("49927398717")->PrintLine();
IsValid("1234567812345678")->PrintLine();
IsValid("1234567812345670")->PrintLine();
}
}
Code fragment from the Base64 encoding class
# Primary encoding loop
r := ""; i : Int; a := 0;
for(i := 0; i < end; i += 3;) {
a := (data[i] << 16) or (data[i+1] << 8) or (data[i+2]);
r->Append( lut[0x3F and (a >> 18)] );
r->Append( lut[0x3F and (a >> 12)] );
r->Append( lut[0x3F and (a >> 6)] );
r->Append( lut[0x3F and a] );
};
Arrays, Strings and Classes
The language has support for dynamically allocated arrays, Unicode strings and various containers.
Arrays
Arrays can hold an indexed list of like types. Arrays are dynamically allocated from the heap and their memory managed by the garbage collector. The runtime system supports bounds checking and will cease execution (generating a stack trace) if array bounds are violated.
Allocating and indexing arrays
# allocate Int array
boxes := Int->New[2,3];
boxes[0,0] := 2;
boxes[0,1] := 4;
boxes[0,2] := 8;
boxes[1,0] := 1;
boxes[1,1] := 2;
boxes[1,2] := 3;
dims := boxes->Size(); # get the dimensions
dims[0]->PrintLine(); # dimension 1
dims[1]->PrintLine(); # dimension 2
# create some strings an iterate over them
directions := String->New[4];
directions[0] := "North";
directions[1] := "South";
directions[2] := "East";
directions[3] := "West";
each(i : directions) {
directions[i]->PrintLine();
};
Strings
Character strings are a collection of Unicode characters backed by the String class. The string class supports a number of operations such as insert, find, substring, type parsing (i.e. String to Float), etc. Variable values can also be inlined into string literals. Strings can be converted into character arrays and UTF-8 byte arrays.
name := "DJ";
name += ' ';
name += "Premier";
name->SubString(2)->PrintLine();
name->Size()->PrintLine();
Code fragment from a sundial program
"Hour\t\tsun hour angle\t\tdial hour line angle from 6am to 6pm"->PrintLine();
for(h := -6; h <= 6; h+=1;) {
hra := 15.0 * h;
hra -= lng - ref;
hla := (slat* (hra*2*Float->Pi()/360.0)->Tan())
->ArcTan() * 360.0 / (2*Float->Pi());
"HR={$h}\t\tHRA={$hra}\t\tHLA={$hla}"->PrintLine();
};
Classes and Functions
As mentioned in the introduction, Objeck supports object-oriented and functional programming concepts. To put class and functions into context the overall programing scope is as follows:
Bundles ⇒ Classes ⇒ Methods/Functions ⇒ Local blocks
Classes and interfaces
As in other languages, a class is an abstract collection of data with related operations. An interface is a set of operations (a contract) that implementing classes must honor. In Objeck, all classes and interfaces are public. Member variables of classes are protected from the outside world. However, classes that are inherited from the source of other classes may access their parent’s member variables. Outside calling classes must use "getters" and "setters" for which the compiler produces optimized code.
Classes may contain public and private methods as well as static public functions. Classes themselves may be public or private restricting private classes to bundle scope. An interface may define any type of method/function (i.e. public or private) however it cannot define implementation. Lastly, Objeck supports reflection letting programmers dynamically introspect instances at runtime.
Below is a code example of that demonstrates many of these concepts. Please refer to the API documentation to learn more about reflection and other features such as object serialization.
FIGURE 2 – CLASSES, INTERFACES AND REFLECTIONinterface Registration {
method : virtual : public : GetColor() ~ String;
method : virtual : public : GetMake() ~ String;
method : virtual : public : GetModel() ~ String;
}
enum EngineType {
Gas := 200,
Hybrid,
Electric,
Warp
}
class : public : Vehicle {
@wheels : Int;
@color : String;
@engine_type : EngineType;
New(wheels : Int, color : String, engine_type : EngineType) {
@wheels := wheels;
@color := color;
@engine_type := engine_type;
}
method : public : GetColor() ~ String {
return @color;
}
method : public : GetEngine() ~ EngineType {
return @engine_type;
}
}
class : public StarShip from Vehicle implements Registration {
New() {
Parent(13, "Metal Fuschia", EngineType->Warp);
}
method : public : GetMake() ~ String {
return "Excelsior";
}
method : public : GetModel() ~ String {
return "NX-2000";
}
method : public : EchoDescription() ~ Nil {
"Partying with the Borg, they brought drinks!"->PrintLine();
}
}
class : public Pinto from Vehicle implements Registration {
New() {
Parent();
}
method : public : GetMake() ~ String {
return "Ford";
}
method : public : GetModel() ~ String {
return "Pinto";
}
}
class : public VehicleTest {
function : Main(args : String[]) ~ Nil {
pinto := Pinto->New();
star_ship := StarShip->New();
type_of := pinto->TypeOf(Vehicle);
type_of->PrintLine();
type_of := star_ship->TypeOf(Vehicle);
type_of->PrintLine();
type_of := pinto->TypeOf(StarShip);
type_of->PrintLine();
registration := star_ship->As(Registration);
registration->GetMake()->PrintLine();
registration->GetColor()->PrintLine();
enterprise := registration->As(StarShip);
enterprise->EchoDescription();
}
}
Anonymous classes
Anonymous classes can be created that define "inline" required interface methods or functions. External variables may be referenced within an anonymous class if they’re passed as references to the class constructor.
FIGURE 3 – ANONYMOUS CLASSES WITH INHERITANCEinterface Greetings {
method : virtual : public : SayHi() ~ Nil;
}
class Hello {
function : Main(args : String[]) ~ Nil {
hey := Base->New() implements Greetings {
New() {}
method : public : SayHi() ~ Nil {
"Hey..."->PrintLine();
}
};
howdy := Base->New() implements Greetings {
New() {}
method : public : SayHi() ~ Nil {
"Howdy!"->PrintLine();
}
};
}
}
Enums and Constants
Enums are enumerated named constant values. Enums values are sequential and start from an offset. Constants, like enums, are named constant values however each value can be uniquely assigned.
FIGURE 4 – ENUMS AND CONSTANTSenum Color {
Red,
Blue,
Green
}
enum Direction {
Left := -100,
Right,
Up,
Down
}
consts Products {
Pip_Boy := 101,
Valut_Suit := 111,
Laser := 675
}
Collections
In addition, to arrays the language supports various collections such as Vectors, Lists, Maps, Stack, Queues, etc. As of version 5, a generic collections library was added. To learn more about the collections classes please check out the API documentation. In order to use these classes you must reference the collections bundle consider the following lines of code:
use Collection.Generic;
use Collection; # depreciated library
When compiling a program that uses collections you must link in the required library, for example:
obc -src genres.obs
Vectors are arrays that can be dynamically resized. They support fast indexing, iterating and appending of values. In order to improve performance memory for vectors is preallocated.
genres := Vector->New()<String>;
genres->AddBack("Hip hop");
genres->AddBack("Classical");
genres->AddBack("Jazz");
genres->AddBack("Rock");
genres->AddBack("Folk");
each(i : genres) {
genres->Get(i)->PrintLine();
};
Lists are a collection of linear linked nodes. They support the fast insertion and removal of values. Memory for nodes are allocated on-demand however nodes may not be directly indexed as with Vectors.
artists := List->New()<String>;
artists->AddBack("Hendrix");
artists->AddFront("Beck");
# move cursor back for middle insertion
artists->Back();
artists->Insert("Common");
# move cursor to start of list
artists->Rewind();
# iterate over values
while(artists->More()) {
artists->Get()->PrintLine();
artists->Next();
};
Map and Hash classes manage key/value pairs. Maps manage values in tree and allocate memory on demand. Maps are slower than hashes however manage memory better. Hashes use keys as indices into arrays and support fast insertion and deletion at the cost of memory.
area_codes := Map->New()<IntRef, String>;
area_codes->Insert(510, "Oakland");
area_codes->Insert(415, "San Francisco");
area_codes->Insert(650, "Palo Alto");
area_codes->Insert(408, "San Jose");
area_codes->Find(510)->PrintLine();
Closures and Lambda expressions
First class functions allow programmers to pass functions into methods/functions, have methods/functions return functions and use functions as variable types (i.e. can be stored in collections). In addition, Objeck supports closures and lambda expressions.
FIGURE 6 – FUNCTIONAL COMPOSITIONclass FofG {
@f : static : (Int) ~ Int;
@g : static : (Int) ~ Int;
function : Main(args : String[]) ~ Nil {
compose := Composer(F(Int) ~ Int, G(Int) ~ Int);
compose(13)->PrintLine();
}
function : F(a : Int) ~ Int {
return a + 14;
}
function : G(a : Int) ~ Int {
return a + 15;
}
function : native : Compose(x : Int) ~ Int {
return @f(@g(x));
}
function : Composer(f : (Int) ~ Int, g : (Int) ~ Int) ~ (Int) ~ Int {
@f := f;
@g := g;
return Compose(Int) ~ Int;
}
}
More concretely, functions can be used by collections to perform operations such as applying the result of a given function to all the elements within a vector.
function : native : Run() ~ Nil {
"Print roots..."->PrintLine();
values := IntVector->New([1, 2, 3, 4, 5, 100]);
squares := values->Apply(Square(Int) ~ Int);
each(i : squares) {
squares->Get(i)->PrintLine();
};
}
function : Square(value : Int) ~ Int {
return value * value;
}
Lambda expressions allow programmers to create anonymous functions and assign references to these functions. Such functions can be used for short calculations and logic. In addition to expressions, the language supports lambdas that contain 'if' and 'select' statements which return a value.
vector := Vector->New()<Func2Ref <FloatRef, FloatRef> >;
# store functions in collections
vector->AddBack(Func2Ref->New(\Func->Double : (v)
=> v * v)<FloatRef, FloatRef>);
# new function from preexisting function at run-time
vector->AddBack(Func2Ref->New(\Func->Double : (v)
=> Float->SquareRoot(v->Get()))<FloatRef, FloatRef>);
# process collection
each(i : vector) {
# return value of other functions and pass argument to other function
Show(vector->Get(i)<Func2Ref>->Get()<FloatRef, FloatRef>);
};
Objeck also supports closures allowing the value of local variables to captured and used in later invocations.
funcs := Vector->New()<FuncRef<IntRef> >;
# create 10 functions capturing i
for(i := 0; i < 10; i += 1;) {
funcs->AddBack(FuncRef->New(\() ~ IntRef : () => i * i)<IntRef>);
};
# invoke functions
each(i : funcs) {
func := funcs->Get(i)->Get()<IntRef>;
func()->Get()->PrintLine();
};
Lambda parameters types can also be inferred using the modified syntax below.
map := Map->New()>IntRef, String>;
map->Insert(1, "One");
map->Insert(3, "Three");
map->Insert(5, "Five");
map->Insert(7, "Seven");
map->Insert(9, "Nine");
map->Each(\^(k, v) => "{$k}: {$v}"->PrintLine());
JIT Compiling
To order to speed up program execution byte code for method and functions may be JIT compiled into native machine code. Methods and functions are compiled the first time they are called and subsequent calls execute the per-compiled code. To direct the runtime to JIT compile code for a given function or method use the "native" keyword. Candidates for JIT compilation are computationally expensive blocks, code with lots of loops and function that are primarily float-point calculations.
For example, observe the execution time of this prime number program with and without the use of the native keyword.
FIGURE 7 – PRIME NUMBERS USING JIT COMPILATIONclass FindPrime {
function : Main(args : System.String[]) ~ Nil {
Run(100000);
}
function : native : Run(topCandidate : Int) ~ Nil {
candidate := 2;
while(candidate <= topCandidate) {
trialDivisor := 2;
prime := 1;
found := true;
while(trialDivisor * trialDivisor <= candidate & found) {
if(candidate % trialDivisor = 0) {
prime := 0;
found := false;
}
else {
trialDivisor++;
};
};
if(found) {
candidate->PrintLine();
};
candidate++;
};
}
}
Threads
Threads can be created by subclassing the Thread class, implementing the Run(..) method, and then calling Execute(..) to start the new thread. Multiple threads can be joined together using the Join method. In addition, mutexes for critical sections are supported by instancing an instance of the ThreadMutex class and using the critical keyword for blocks of code.
# lock cache for while we search or insert content
critical(@content_mutex) {
# found in cache
found := @content_cache->Find(path_name);
if(found <> Nil) {
content := found->Get();
}
# not found, add to cache
else {
content := System.IO.Filesystem.FileReader->ReadBinaryFile(path_name);
if(content <> Nil) {
@content_cache->Insert(path_name, ByteArrayRef->New(content));
};
};
};
Programming Environment
Tools to make Objeck programming easier.
Debugger
The command line debugger allows to inspect the runtime behavior of a program. To use the debugger a program must first be compiled with debug symbols by passing the "-debug" option to the compiler. For a working example let's use the program in "Figure 1". We'll start by saving the program to a text file call "luhn.obe"
To compile the code type the following:obc -src luhn.obs -debugFor this example let’s assume the source file is in the same location as the executable. To start the debugger type the following:
obd -bin luhn.obe -src_dir .Let’s first set a breakpoint on line 17 and run the program.
> b 17 added breakpoint: file='luhn.obs:17' > r break: file='luhn.obs:17', method='Luhn->Main(..)'Next let’s list the code around the breakpoint.
> l 12: }; 13: return (oddSum + evenSum) % 10 = 0; 14: } 15: 16: function : Main(args : String[]) ~ Nil { => 17: IsValid("49927398716")->PrintLine(); 18: IsValid("49927398717")->PrintLine(); 19: IsValid("1234567812345678")->PrintLine(); 20: IsValid("1234567812345670")->PrintLine(); 21: } 22: }Now let’s step into the “IsValid” function:
> s > break: file='luhn.obs:2', method='Luhn->IsValid(..)' > l 1: class Luhn { => 2: function : IsValid(cc : String) ~ Bool { 3: isOdd := true; oddSum := 0; evenSum := 0; 4: for(i := cc->Size() - 1; i >= 0; i -= 1;) { 5: digit : Int := cc->Get(i) - '0'; 6: if(isOdd) { 7: oddSum += digit; 8: } else { 9: evenSum += digit / 5 + (2 * digit) % 10 10: }; > nLet’s print out the value for “cc”.
> p cc print: type=System.String, value="49927398716" Now let’s break on line 9 and print the value for “evenSum”. > b 9 added breakpoint: file='luhn.obs:9' > c > break: file='luhn.obs:9', method='Luhn->IsValid(..)' > n > break: file='luhn.obs:11', method='Luhn->IsValid(..)' > p evenSum print: type=Int, value=2Lastly, let’s print out the call stack before exiting.
> stack stack: frame: pos=2, class=Luhn, method=IsValid(o.System.String), file=luhn.obs:5 frame: pos=1, class=Luhn, method=Main(o.System.String*), file=luhn.obs:17 > q breakpoints cleared. goodbye.TABLE 6 – DEBUGGER COMMANDS
Command | Description | Example |
---|---|---|
[b]reak | sets a breakpoint | b luhn.obs:17 |
breaks | shows all breakpoints | |
[d]elete | deletes a breakpoint | d luhn.obs:17 |
clear | clears all breakpoints | |
[n]ext | moves to the next line within the same method/function with debug information | |
[s]tep | moves to the next line with debug information | |
[j]ump | jumps out of an existing method/function and moves to the next line with debug information | |
args | specifies program arguments | "'First' 'Second'" |
[r]un | runs loaded program | |
[m]emory | shows used memory and garbage collection threshold | memory: allocated=0.32k, threshold=3,072k |
[p]rint | prints the value of an expression, along with metadata | print: type=System.String, value="49927398716" |
[l]ist | lists a range of lines in a source file or the lines near the current breakpoint | |
[i]nfo | displays the variables for a class | program executable: file='hiya.obe' current file='fred.obs:9', method='Luhn->IsValid(..)' |
[s]tack | displays the call stack | p cc |
bin | loads a new executable binary | |
src_dir | specifies a new source directory | |
[q]uit | exits a given debugging session |
Building Libraries
Creating class libraries is pretty straightforward. Put one or more classes into one or more files and compile the code with the “-tar lib” option. Code for libraries cannot contain a “main” function.
class Pair {
@key : Compare;
@value : Base;
New(key : Compare, value : Base) {
@key := key;
@value := value;
}
method : public : GetKey() ~ Compare {
return @key;
}
method : public : Get() ~ Base {
return @value;
}
}
To compile the code type the following:
obc -src pair.obs –tar lib -dest pair.obl
To use the library in program type the following:
obc -src points.obs –lib pair
Generating a Portable Runtime
As of v6.8.0, a portable runtime environment can be created using the "obb" command
Encrypt and decrypt example:
obb -src_file encrypt_7.obe -to_dir /tmp -to_name encryptOptionally, application specific resources can be copied using the "-src_dir" option.
Examples
Please refer to the list of applications below that have been developed for more in-depth coding examples
- Gaming and graphics: 2D Side Scroller, Vibrating Rectangles, Lazy Foo SDL2 Examples
- AI: Neural Network, Tic-Tac-Toe
- Text Processing: XML[library], JSON[library], CSV[library]
- Web: RSS Reader, HTTPS Server
- Compilers: Tiny Language, Brain F**k, Lisp
- Benchmarks: Computer Language Benchmarks Game