Tutorial — Creating New Objects

Object-Oriented Programming (OOP) Review

Basic Concepts

object

An object in the OO sense is data structure that “knows about” its data. More formally, an object has associated, or bound, functionality that enables it to manipulate its own values.

As a simple example, a timer object might consist of a numeric value (the elapsed time) along with associated “start”, “stop” & “reset” functions used to begin timing, stop timing & restore the count to zero.

Data & Code

Objects, therefore, combine data and code (functions) that use that data. The set of data and functions for an object are called its members. (The timer object mentioned above has four members: one data member and three function members.)

The set of object members is specified by a design, usually called a class. All objects with the same set of members–that is, which share the same design–are said to have the same type.

Class & Object

The Object-Oriented idea divides into two important parts: The design of the object (class) and the physical object (instance) itself. For a given type of object, there is only one class defining that object, but there can be as many instances of that object as desired.

Properties & Fields & Methods (Oh, My!)

Different Object-Oriented Programming Languages (OOPLs) use different terms for the data and code members. Object data comes as properties, fields, member data or instance data. In all cases, every object of the same type has the same set. In particular, each object has its own copy of the set. Changes made to the data of one object do not affect other objects.

Object code is usually comes as methods, but sometimes as functions or sub-routines. Again, in all cases, every object of the same type has the same set. However, the difference this time is that objects of a class typically share the same code set.

Zen

A large part of successful OOP is the good design of new object types!

class

A class defines a type of object.

This definition can be entirely abstract, such as when referring to the native types of any language (see native language types). It can also be very concrete, such as in languages (such as Smalltalk or Lisp) in which classes are first-class objects. In the middle, it can be a compile-type construct that is largely lost in the output code (such as in C++).

What a Class Does:

Typically, a class defines any of several things. Some are shared by each instance object of the class, others are particular to the class itself.

  • Instance Data Members The set of data contained in each instance object of the class.
  • Instance Methods The set of functions that an instance object can “do”.
  • Class Data Members A single set of data owned by the class itself.
  • Class Methods A set of functions that the class itself can “do”.
  • Constructor (Destructor) Methods Methods that are called automatically when an instance object is created (or destroyed).

(Different languages support different class mechanisms. For example, VB lacks the concept of class data, and Java doesn't support destructor methods as it does constructor methods.)

Zen

A class is often referred to as an object “cookie cutter”. It defines the shape of an object and enables you to make many identical copies (instances) of that shape.

method

A method is a function bound to a class or object.

At their heart, methods are just functions. They can take arguments or not, return a value or not, have lots of code or very little.

Methods differ from ordinary functions only in that they may only be called in the context of a class or an object. In the former case, an object instance is required to invoke the method; in the latter only the class is required.

Instance Methods & Static Methods

Methods come in two basic flavors: Instance (object) and static (class). Instance Methods are bound to object instances (and require an object to call). Static Methods are bound to class definitions (and may be called without an object).

Not all OOPLs support both method types.

instance

An instance is a physical object based on a class.

In many languages, the keyword new is associated with creating new object instances. Some languages require that the programmer explicitly clean up object instances (for example, C++ requires you to delete any object you create with new), while others (e.g. Java, VB) automatically remove unused objects (in a process called garbage collection).

this, self, me

Inside an instance method, there is a “current” object–the object used to invoke the method! The current object is referred to variously as this (C++, Java,JavaScript), self (Smalltalk) or Me (VB).

Different languages provide access to the default object in different ways. For example, in many languages, you can refer to members by their name with no qualifying reference. The language assumes the context of the object. Other languages require a notation specifying the current object.

Classes

member data (instance data, properties, fields)

Member data is the data contained in each object instance.

Each instance of a class (object) has its own copy of the set of data items defined by the class. The set is the same for all objects of a class, but each object has its own values in that set.

Member Access

A common notation programming languages use to access object members is the “dot notation”. (This applies mainly to C-descended and related languages. There are a number of languages with vastly different notation schemes!) This notation requires an object reference–for example, an object instance name–a dot and a member name:

object.member

Combined like this, the expression refers to the member's value. As an expression with a value, you can use it to assign the member value to something else:

some_variable = object.member

If the member is writable, it can be the target of an assignment:

object.member = new_value

Many languages have ways to specify whether a member is writable–or even if it is accessible! Members that are not accessible are called private or protected. Members that are accessible are called public (or rarely, exported).

Properties & Fields

Some languages (such as VB) distinguish between properties and public instance data (fields). The more “pure” an OOPL is, the less likely it is to support fields. Typically such languages require all object data access be through property methods Others prohibit it as a style rule and require you write “get” and “set” methods for all object data.

Adding New Members

A few languages (such as JavaScript) allow you to dynamically add new members to objects after they are created. In cases like this, objects start off with an identical set of data members, but may gain new ones later. Some languages (again, JavaScript) allow you to add new members to objects or to their class. (In the latter case, all objects instantly inherit the new member!)

member methods (object functions)

Member methods are the functions bound to (associated with) an object instance.

As with fields, every instance of a class has the same set of member methods. However, unlike with fields, most languages use a single, common set of methods shared by all object instances.

Similar again to fields, you can only call Member Methods “on” or “through” an object instance. That is, you need to have an object in hand in order to call its methods!

(Compare this to static methods that do not require a object instance.)

Method Access

In most languages, you access member methods as you do object properties or fields. The “dot” notation is common:

object.method()

C++, Java, JavaScript and Visual BASIC all use this notation. A common requirement is the parenthesis. C++, Java and JavaScript require the parenthesis. Visual BASIC has certain circumstances that make it optional.

This Object

Inside an instance method, there is a “current” object–the object used to invoke the method. The current object is referred to variously as this (C++, Java,JavaScript), self (Smalltalk) or Me (VB). Some languages allow you to refer to class members by default, others require a reference to the “this” object. For example, the following JavaScript snippet sets two fields on the current object to zero:

    this.x = 0;
    this.y = 0;

static methods (class functions)

Static Methods are functions bound to a class, rather than any specific instance of that class.

As with instance methods, there is one set of functions shared by the class. The difference is static methods don't require an object to call. (In fact, a language need not provide a means to call static methods through objects!)

Java's Static Math Methods

An example of static methods is the Math methods in Java. Because Java is 100% Object-Oriented, it does not support stand-alone functions. (Math functions are often stand-alone functions in languages that support the concept.) Therefore Java has a Math class that contains all the math functions.

The irony is that you can't instance a Math object in Java. (Requiring all functions be methods forces a requirement for non-instance-able class definitions!)

constructor (destructor) ctor (dtor)

A function that constructs (destructs) and object. The terms are often abbreviated: ctor (dtor).

Some languages allow you to define a function (a constructor) that is called any time you create an object instance. And some of them allow you to define a function (a destructor) called whenever an object is destoyed.

Constructor (Destructor) Functions

An alternate meaning of the term refers to a function that creates (destroys) an object. The difference is significant! In the primary case, these functions are called as a result of object creation (and destruction). In the alternate case, the functions are called in order to create (and destroy) objects.

The constructor functions we will build for JavaScript are constuctors in the alternate sense: We call them in order to create new objects.

RAII

Languages with guarenteed ctor/dtor behavior enable a design technique called RAII. (Resource Allocation Is Initialization) This techique uses the ctor to allocate/open/bind a resource, and the dtor to deallocate/close/unbind that resource. Because the ctor/dtor behavior is guarenteed by the language, resource management occurs in a managed, segmented fashion.

The archtypal example of this is the lowly String object that allocates memory space for the string on construction and deallocates it upon destruction.

Advanced Concepts

Data Encapsulation/Hiding

Data encapsulation refers to how an object encapsulates its data members into a single unit. This allows the programmer to treat a collection of highly-related values as a single unit.

Any language that provides data structures provides data encapsulation. Data encapsulation alone is not an Object-Oriented trait.

Data hiding refers to how an object can prevent outsiders from accessing–or even seeing–the member data. Access to the object's data is mediated through regular or property methods that can control access and value.

Data hiding (along with encapsulation) is an Object-Oriented trait.

Types of Access

Languages often control how different entities can access object members. For example, some members might be accessible only to the methods of the class, while others might be accessible to any holder of an object. These are often called, respectively, private and public members.

Class/Interface Inheritance

Inheritance is a vital characteristic of Object-Orientation. Some will say a language is not OO unless it support inheritance in some form.

The basic idea of inheritance is that a child class inherits part of its design from a parent class. The parent/child relationship is also called super-class/sub-class or base class/derived class.

Types of Inheritance

There are two basic types of inheritance: Class and Interface.

When you use Class Inheritance, new classes inherit everything about a parent class. They inherit the design of instance objects as well as the methods. In many languages, a parent class can restrict what a child class can access, but even so, the child inherits the full power of the parent.

This form of inheritance implements a classically-touted strength of OOP: code re-use. The idea is that derived classes can use the code of the base class to do much of their work.

In addition, derived classes can often override inherited features and therefore modify inherited behavior. Alternately, they can act as wrappers, invoking the parent method at some point, but also adding their own processing.

When you use Interface Inheritance, new classes inherit only the design of a class.

Specifically, this means you inherit the public set of methods as a specification of required methods. You do not inherit the method code itself. (You may also inherit data members and/or private members; it depends on the language.)

The downside that you need to re-implement all the inherited methods is balanced by the upside that multiple inheritance is much easier. This, in turn, allows class designs to share identity outside of class hierarchies. For example, extremely separate class types, such as disk files and network acess, might share an interface that allows the user to treat them as similar data streams. (In fact, this is a common approach in languages that support it.)

Interface Classes

In languages with native support for interface inheritance, it is common to design classes where the methods have no code. These classes are intended as interface specification classes. Other classes will inherit and implement the specified interface. Doing so allows objects of that class to be treated as though they were objects of the interface design class.

Inheritance Breaks Encapsulation?

Some feel that class inheritance with protected members breaks encapsulation. The idea is that the child classes gain access to members of the parent class, and this breaks the encapsulation of the parent. The child can therefore expose data the parent class designer intended as normally hidden.

Object Polymorphism

Object Polymorphism refers to the ability to treat a collection of different objects as a collection of a more basic single object.

The important characteristic of object polymorphism is a shared set of basic properties and methods. In most cases, the shared set is obtained through class or interface inheritance. In some cases, the shared set can be obtained by high-level design. That is, objects are designed to share attributes without inheriting them from language constructs.

Object Polymorphism is the final leg in what many consider the Object-Oriented Stool. (The other two are the previous two topics: Data Encapsulation/Hiding & Class/Interface Inheritance.)

Class-based Polymorphism

Class-based Polymorphism treats all derived objects as though they were instances of the base class.

Consider the base class, Animal, and three derived classes: Dog, Cat & Horse. Because all members of the derived classes inherit the Animal base class, any instance of a derived class has Animal traits. For example, if Animal defines a Speak() method, then Dogs, Cats & Horses know how to Speak.

Usually, the Animal class would implement a default Speak() method, and each child class would re-implement it their own way. For example, the Animal default might be a simple "Hello" (or maybe the default Animal is mute!), but Dogs Speak() "Woof!", Cats Speak() "Meow", and Horses Speak() "Neigh!".

If a child class does not override a method, it inherits that method. If we add a new class, Dolphin and don't override Speak(), we inherit the one from Animal (in which case having the default be mute would be a good idea).

The big deal is that you can write code that works with Animals and have it work with Dogs, Cats & Horses. For example, you could write a function that takes any object derived from Animal and asks it to speak. The actual output depends on what type of Animal is actually passed (Dogs Speak() "Woof!", etc.).

Function Hello_Animal(critter As Animal)
    // Ask Animal to Speak...
    Call critter.Speak()
End Function

Note that this code works even with classes derived from Animal someday in the future. It doesn't matter, it only matters that the object has an Animal for a parent.

Interface-based Polymorphism

Interface-based Polymorphism is similar to Class-based Polymorphism, but doesn't require all objects to descend from a common ancestor.

Consider a re-design of Animals that allows for talking robots. Robots are not Animals, so we can't let them inherit Animal properties. Therefore, we need a way to define an interface we can use to deal with both Robots and Animals.

To do this, we can define an interface class, ItSpeaks with a method, Speak().

The Animal class no longer defines a Speak() method (nor does the Machine class from which Robot presumably descends).

Instead, Dog, Cat, Horse & Robot implement the ItSpeaks interface (class). In most languages, this means you are required to define a Speak() method. The end result is the same as in class-based polymorphism: each class has a method that implements its particular Speak().

A big difference is that, here, no parent method provides a default behavior.

Another difference lies in how we write a general function for handling speaking objects:

Function Hello_Speaker(object As ItSpeaks)
    // Ask Object to Speak...
    Call object.Speak()
End Function

Rather than taking a base class as an argument, we take an interface object. Any object implementing that interface is a candidate for speaking.

In some languages, both types of argument may involve classes for which no real objects are ever instanced. This is especially true for interface classes: there is no such thing as an ItSpeaks object. It is often the case for base classes: in most designs, you probably wouldn't have generic Animal objects.

Object Polymorphism

Some languages allow you to have polymorphism at the object level. This is the broadest form of polymorphism, because code that refers to a property works with any object, so long as that object has a property with that name.

This behavior generally requires a dynamic, general language (such as JavaScript). Languages that support this generally view object properties as a collection indexed by name. Consequently, such languages are often slower than languages that view members as known table offsets.

Polymorphic Magic

Part of the magic of OOP lies in how child objects override parent methods combined with the ability to call the appropriate method even when holding a base reference. In the Animal example, the function only knows it has an Animal, it doesn't know what kind!. Under-the-hood Magical Object-Oriented machinary binds a Speak() request to a generic Animal reference to the correct Speak() method for the object actually passed into the function. The ItSpeaks example is similar in that the function only knows it has an object that implements ItSpeaks.

Functional Polymorphism

Functional Polymorphism is the ability to have identically-named functions distinquished by their arguments. It is a different and unrelated type of polymorphism that it is supported by all types of languages (not just OO languages). What's more, some Object-Oriented languages (such as C++ and Java) have functional polymorphism, and others (such as Visual BASIC and JavaScript) do not.

native language types

OOP is about creating new types, but most programming languages come with a set of built in, or native types. Along with these types (or classes), comes a set of things the language can do with variables of that type. For example, if they are numeric types, you can add and subtract them.

In a sense, if you've used any programming language, you've done object-oriented programming, because at some level, all language data objects are just that: objects. And the language provides associated functionality in what might well be considered a set of “methods”. Plus, many native types are opaque to the user (data hiding!).

Data Type Handling

One of the big ways languages vary is in how they handle data types and in what types are native to the language. For example, languages can be static or dynamic, specific or general, restrictive or permissive in how they handle types and values. Often a language is referred to by one or more of these characteristics. For example, c is permissive about type, so is sometimes referred to as a permissive language. Likewise, c is called a static language, because it uses a static (early-binding) type system.

Static languages require knowing the types of all objects ahead of time–usually at compile time. In static languages, you must usually declare all variables as having a type.

Dynamic languages can handle objects of unknown type at run time. In dynamic languages, you can declare variables without specifying a type.

Compiled languages tend to be statically typed; script languages are typically dynamic.

Note that there is a difference between static/dynamic typing and untyped languages. In the former, the variables all have types. The difference is that dynamic languages don't bind to specific types until run time when the actual type is known. In a truely untyped language, values don't have any type information at all. You can't say that a given variable is a string or an integer; the value depends on the situation.

Specific languages require specific handling of values. For example, in c you can't assign a string to an integer and expect anything meaningful. (On the other hand, c is permissive, so you can often actually do the assignment.)

General languages (typically “script” languages, such as perl) allow assigning the string, “4”, to an numeric variable with the expected results: the variable takes on the value 4. (What can be surprising in some languages is that now the variable is a string!)

Compiled languages tend to be specific data handlers; script languages are often general.

Restrictive languages are fussy about the values of your types. For example, Ada–a very restrictive language–would not allow you to add or subtract Fahrenheit and centigrade temperatures, if you had those readings in variables of Fahrenheit and centigrade type.

Permissive languages don't restrict what you can assign to a variable, which can lead to dangerous situations (such as the example above, assigning a string value to an integer in c).

Examples

The c languages (c, C++ plus a few “alikes”) have the native char, short, int & long integer types, as well as the float & double real types.

Java has non-Object native types similar to the c types, but also has an object reference data type.

JavaScript has no primative types, it has only the object reference variable (var). The language core defines several native types, including String, Number & Date.

Visual BASIC has (in addition to a number of special types) the Integer, Long, String & Date types.

The inscrutable perl has scalar, array and hash types (plus a few others).

Alphabet Soup

OOP
Object-Oriented Programming—writing a program using an OOPL The basic tenents of OOP are:
  1. Data Encapsulation/Hiding,
  2. Class/Interface Inheritance &
  3. Object Polymorphism.
It is possible to use OOD techniques in a non-OOPL and therefore do a sort of OOP. Typically, there is a requirement to manually implement and maintain one, or more of, the three basics listed above.
PP
Procedural Programming—the “old-fashioned” way of writing a program. PP consists of unassociated functions (unassociated except by fiat or mechanical visibility) that may handle similar data.
If OOP can be thought of as “noun-oriented”, PP is “verb-oriented”.
FP
Functional Programming—another vastly different way of writing programs. In FP, the function is a primary language construct, and recursive function solutions are typical. Often in FPLs (Functional Programming Languages), variables are immutable: once set, they may not be modified. This, along with the imposed functional program structure, is thought to lend to automated proof of program correctness. (Similar to how some math functions can be proven correct in mechanical fashion.)
OO
Object-Oriented—Anything to do with Object-Oriented Programing or Design
OOD
Object-Oriented Design—program design analysis using OO principles
OO(P)L
Object-Oriented (Programming) Language—a language that supports OOP natively
OOPSL
Object-Oriented Programming Systems & Languages—fancyspeak for OO