2.2. Defining Classes and Creating Objects

Objects are usually models of conceptual or real-world entities; they consist of a combination of data, which models the state of the entity and operations which model the behavior of the entity. The body of a Sather class consists of a list of features which define the data and behavior of the class. A class defines a new type and may be used to create object instances of that type.[1]

[1] This is only true for reference, immutable and some kinds of external classes. Abstract a, partial and most external classes cannot have instances.

We will start by describing the data elements and then move on to the operations. In subsequent sections, we will describe the definition of object behavior in the form of routines. We will then point out that Sather provides a level of abstraction, which permits the state and behavior of the object to be treated in a uniform manner. Finally, we will describe the somewhat unusual meaning of assignment in Sather that makes this uniformity possible.

2.2.1. Defining Simple Classes

The state of a class is defined by attributes, which are have the prefix attr:
class POINT is
   attr x:INT;
   attr y:INT;
end;

The POINT class above defines an 'x' and a 'y' attribute both of which are integers. This class is useless, as it stands, since it provides no way to create instances of itself.

Object Creation: create and new

To make objects of the POINT class, we have to introduce a create routine
class POINT is
   attr x, y:INT;

   create(xvalue,yvalue:INT):POINT is
      res:POINT := new;
      res.x := xvalue;
      res.y := yvalue;
      return res;
   end;
end;

The create routine first calls the special expression 'new'. 'new' creates a new uninitialized instance of the POINT class and returns it. All the attributes in the new instance have default 'void' values. It then assigns the 'x' and 'y' attributes of this new instance to xvalue and yvalue respectively. Instances of the POINT class can then be created as shown below
p:POINT := POINT::create(3,5);

Since creation is such a common operation, Sather provides a special shorthand for calls to the routine 'create'. The 'create' routine shown could be invoked with the # sign as shown below
point:POINT := #POINT(3,5);

Expressions using the # sign are referred to as creation expressions, and are a convenient shorthand used for creating new objects and initializing their attributes.

Attribute access

When an object of the class POINT is created, the 'x' and 'y' attributes may be accessed by 'dotting' into the object.
a:POINT := #POINT(3,5);
-- Create a new point
#OUT + a.x ;
-- Prints out the value of 'x', which is 3
a.x := 5;
-- Sets the value of the 'x' attribute to 5

Points to note

2.2.2. Checking whether an object has been created

Before a variable is assigned to an object, the variable has the void value. The expression 'void' may be used to determine whether a value is void or not.

The following example will print out the string "a is void!" since a POINT is a reference class and 'a' has not been created.
a:POINT;

if void(a) then 
   #OUT + "a is void!";
end;

In the second version, the string "a is not void!" will be printed since an object has been assigned to the variable 'a':
a:POINT := #POINT(3,5);

if void(a) then  
   #OUT + "a is void!"
else
   #OUT + "a is not void!"
end;

Note that the above test will not work in the same way for some of the built-in classes such as integers and booleans[2].

[2] The void test returns true for all integers with a value of 0 and booleans with a value of false. In general, the void test is not useful for immutable classes.

2.2.3. Types Introduced

Each Sather variable and object has an associated type. The type of the object indicates the class that was used to create the object. In the following example, both 'a' and 'b' have the type POINT, indicating that they are associated with instances of the POINT class.
a:POINT := #POINT(2,3);
b:POINT := #POINT(4,5);

In this example, the type of the variable 'a' is the same as the type of the object to which it is assigned. This is always the case with the reference classes we have seen so far.

When we introduce abstract classes (unnamedlink), we will see that some Sather variables can hold objects of many different types. In this case, it is useful to distinguish between the type of the variable (called the declared type) and the type of the object that it holds (called the actual type or the concrete type).

2.2.4. Hiding features: private and readonly

A fundamental feature of object oriented programming languages is that they permit an object to hide certain features which are for internal use only. Attributes may be completely hidden by marking them private. Routines may likewise be marked private, meaning that they cannot be accessed outside the original class. Attributes can also be hidden so that they can be read but not modified from outside the class, by marking them readonly.
class POINT2 is
   private attr x:INT;
   -- x cannot be seen from outside
   readonly attr y:INT;
   -- y cannot be changed from outside
   create(xvalue,yvalue:INT):POINT is
      res:POINT := new;
      res.x := xvalue;
      res.y := yvalue;
      return res
   end;
end;

This restricts external access to the attributes in the object
foo is
   -- some other piece of code
   a:POINT2 := #POINT2(3,5);     -- Create a new POINT2
   #OUT + a.y;                   -- Print out '5'
   -- Illegal: #OUT + a.x;
   -- Illegal: a.y := 10;
end;

Points to note