Menu Close

Articles

Level: Object Oriented

Object-oriented programming (OOP) is a programming paradigm based on the concept of “objects”, which may contain data, in the form of fields, often known as attributes; and code, in the form of procedures, often known as methods.

Object Oriented

Level include object oriented features that can be combined with structured programming and functional programming to create heterogeneous programs. Level uses a single inheritance model. All classes are extensions of a single class called Object. In this regard Level is very similar to Java.

  • Level classes are based on single inheritance paradigm;
  • Classes are equivalent to types with attached methods;
  • One module can implement one or more classes;
  • Some classes are private to module members only;
  • A module can export one or more classes to become public classes;
  • One class can be instantiated. We can have multiple instances of a class;

OOP Structures

#FeatureDescription
1ClassObject template has: properties, methods
2FeatureAbstract specification define: forward methods
3ObjectThe root class of all classes

New keywords

We reserve several new keyword to enable the new features for Level 2.

KeywordDescription
REGIONSCreate regions in class
publicdeclare public object properties
privatedeclare private object variables
disposeregion executed before object is removed from memory
STRUCTUREAllow creation of data models
classdefine class that is an object template
featuredefine abstract class with forward declaration
extendspecify base class for inheritance
enablea class enable features
methoddeclare a method into a class
TYPESNew types
baseReference to base class (used in extend)
selfReference to current object in constructor
ObjectDefault base class | Root class

Class Section

A class is a named section of code that represents an object template. A class implement code required to create objects. Objects are state machines that are instantiated on demand. The most important characteristics of objects are:

  • Encapsulation: each object has it’s own states;
  • Inheritance: an object inherit class members;
  • Polymorphic: an object can play multiple roles;

A class is a mixture of data properties and methods associated to these properties. A class is like a record type that have methods. The difference is that record are static structures while classes are more dynamic. We can extend a class and we can implement class features.

Class syntax:

class <class_name>(<param> <type>[,<param> <type>]...) [extend <base_class>] is 
  <class_members>

  <object_properties>;
  <object_methods>;
[public]
  <object_properties>;
  <object_methods>;
begin 
 <constructor_executable>;
  ... 
  [self: base();] -- self object initialization
  ...
  return self; -- return object "self"
[recover]
  <constructor_recover_region>
[finalize]
  <constructor_finalize_region>
[dispose]
  <object_dispose_region> 
end class;

Parameters

A class can have parameters used for object initialization. We can define optional parameters with default value using assignment (param_name:value type). Parameters can be native types, objects or pointers. All parameters are pass by value except pointers that are @ references.

creation of a new object based on a class

let
  <object_name>:ClassName;
do
  <object_name>:=ClassName(<param>:value[,<param>:value]...);
  ...
end do;

Note: Unlike Java we do not have to use New keyword to create a new object. We just use assign operator follow by class constructor call with parameters. The parameters can be called by position or by name using pair-up operator “:”.

Constructor

A class has one single constructor that starts using begin keyword and is a mandatory region. The most basic constructor can assign values to attributes and properties. Sometimes constructor execute calculations and make initialization. The implementation region can use one or more return clauses that can be used to create a flexible constructor.

Self Object

Variable “self” is similar to “this”, do not confuse the two. The object self  is the instance of the class that is about to be created while “this” is  used for program, procedures and functions.

Object self  is the constructor result variable visible from class constructor. In constructor self must be explicit initialized with base class constructor. If there is no base class, the self is initialized to Object() that is the base class of all classes.

Self Initialization: The self object is implicit declared but we need to initialize this object:

self:=<base_class>(<arguments>);

This convention provide opportunity to create a flexible constructor using decision statements based on parameter values.

if <condition> then
  self:=<base_class>(<some_arguments>);
else
  self:=<base_class>(<other_arguments>);
end if;

Class Regions

A class have several declaration sub-regions: {class, private, public} that are used to define “class members” and “object members”.  The class regions tarts after keyword “is” and continue until a new regions starts or we reach begin keyword. Private and public regions are optional.

Class Members

You can call class members using the class name with dot operator. Class members can be: {“variables”, “functions”}. By using these regions we can use a class as a containers to enclose general functionality. Class variables and functions are shared between objects and are public. That means if we change value of one variable all objects will see the new value.

We use double dot notation to get a member of a class:

module_name.ClassName.member_name;

Object Members

Object members are private or public depending on the region. Public members can be called by the parent program using the qualified dot notation: We use dot “.” operator after the object name.  Members can be: { attributes, properties, methods }. We do not have keywords: _attribute_ or _property_.  An attribute is a naked variable. A property is a private attribute that needs methods to be accessed.

Attributes

Attributes are used to store object data. An object can be used as data container or a data processor or both. Attributes are not created in memory until an object is instantiated. Attributes can be public or private. Public attributes are called properties. A developer can make an attribute read only or write only using methods. If an object is read/write methods are not required. Just make the attribute public.

It is a good convention to have prefix “a_” used for all attributes. Doing this you can distinguish between variable that can use prefix “v_” and all attributes. Notice attributes are private and are accessible in constructor to assign initial values even if they are read only properties.

Example:

-- define a class person  
class Person(p_name string, p_age integer) is
  person_count:0 Integer;  !class member
private
  a_name: String; -- private attribute
  a_age:  Integer;-- private attribute  
public -- object data 
  method grow is
  begin
    a_age+=1; 
  end method;
  method display() is
  begin
    print("My name is:" & a_name ); 
    print("I'm #d old." & a_age  ); 
  end method;    
  -- make name a read only property
  method name => String is
    result:=_name;
  end method;
  method age => String is
    result:=self._age;
  end method; 
begin
  self:=Object();   --> explicit object initialization
  a_name:=p_name;   --> assign parameter value to property
  a_age:=p_age;     --> use a method like a procedure call
  person_count += 1; --> we count the objects created
  return self;
dispose
  person_count -= 1; --> we count the objects created
end class;

The Object class

There is a special class that has name “Object” and represents the root class. All classes either extend Object class or another class derived from Object class, forming a tree. Level language implements a single class tree starting from Object root class. Therefore Level has single inheritance versus Python that have multiple inheritance.

Declaring objects

An object is a reference to a memory location representing a dynamic structure.  We create this structure at run-time from a class using the class constructor. Objects are class instances. An object is an independent “state machine”. After instantiation we can change it’s states and inquiry it’s current states.

Declare two objects using predefined classes as type.

variable 
  <var_name>[,var_name]:<class_name>; 

Object Instantiation

A class definition occupy very little memory. When a new object is created using class constructor a new memory space is reserved for the object properties. This new memory is not released until the object is out of scope.

The class itself also need memory. This is allocated when parent module is imported. When class is out of scope all it’s objects will be released to from memory but not the class. We keep the class definition in memory until the program terminates. Class variables are static.

References to objects

We define references to objects using operator “@” that create a pointer. A pointer can borrow a reference from another object. We can initialize a reference with a new object without borrowing using operator initialization operator “=”.

Level assign operator “=” is making a copy and do not transfer a reference. If a developer wish to create a reference to an object it is possible only by using pointer notation: “@” and address operator “?” .

We can use digraph operators: “==” and “~=” with object references and object variables. This will compare first the address and second the value of attributes for two objects. If the attribute of the objects match and objects have same class then the objects are equal.

Example:

program test_ref is
  o,n: Object;  -- declare 2 void objects
  r: @Object;   -- void reference to object
begin
  o:=Object(); -- create empty object
  n:=Object(); -- create empty object
  r?=o;        -- borrowing address from "o" into "r"   
  if o==r then
    print("o and r objects are equal");
  else 
    print("o and n are different"); 
  end if;
end program;
o and r objects are equal

Read next: Declarative Programming