Classes

From Rosetta Code
Task
Classes
You are encouraged to solve this task according to the task description, using any language you may know.

The purpose of this task is to create a basic class with a method, a constructor, an instance variable and how to instantiate it.

Ada

Class is used in many languages to provide both encapsulation, or grouping of data and actions, and also as type definition. Ada packages provide encapsulation or grouping while type definitions are done using the type reserved word. Types participating in inheritance are named tagged record types.

A package specification has the following form:

package My_Package is
   type My_Type is tagged private;
   procedure Some_Procedure(Item : out My_Type);
    function Set(Value : in Integer) return My_Type;
private
   type My_Type is tagged record
      Variable : Integer := -12;
   end record;
end My_Package;

The type declaration at the top of the package gives public visibility to the private tagged type My_Type. Since My_Type is declared to be private the public has no visibility to its structure. The type must be treated as a black box. The private section of the package specification includes the actual tagged record definition. Note that the data member Variable is initialized to -12. This corresponds to a default constructor for the type.

The package body must contain the implementation of the procedures and functions declared in the package specification.

package body My_Package is
   procedure Some_Procedure(Item : out My_Type) is
   begin
      Item := 2 * Item;
   end Some_Procedure;

   function Set(Value : Integer) return My_Type is
      Temp : My_Type;
   begin
      Temp.Variable := Value;
      return Temp;
   end Set;

end My_Package; The Set function acts as a conversion constructor for My_Type.

An instance is typically created outside the package:

with My_Package; use My_Package;

procedure Main is
   Foo : My_Type; -- Foo is created and initialized to -12
begin
   Some_Procedure(Foo); -- Foo is doubled
   Foo := Set(2007); -- Foo.Variable is set to 2007
end Main;

BASIC

Compiler: QBasic 4.5

 DECLARE SUB MyClassDelete (pthis AS MyClass)
 DECLARE SUB MyClassSomeMethod (pthis AS MyClass)
 DECLARE SUB MyClassInit (pthis AS MyClass)
 TYPE MyClass
   Variable AS INTEGER
 END TYPE
 DIM obj AS MyClass
 MyClassInit obj
 MyClassSomeMethod obj
 SUB MyClassInit (pthis AS MyClass)
   pthis.Variable = 0
 END SUB
 SUB MyClassSomeMethod (pthis AS MyClass)
   pthis.Variable = 1
 END SUB

C

Compiler: GCC 4.0.2

 typedef struct MyClass
 {
   int variable;
 } MyClass;
 struct MyClass*  MyClass_new()
 {
   struct MyClass* pthis = (struct MyClass*)malloc( sizeof(struct MyClass) );
   //memset(pthis, 0, sizeof(struct MyClass) );
   pthis->variable = 0;
   return pthis;
 }
 void MyClass_delete(struct MyClass** pthis)
 {
   if(pthis && *pthis)
   {
     free(*pthis);
     *pthis = NULL;
   }
 }
 struct void MyClass_someMethod(struct MyClass* pthis)
 {
   pthis->variable = 1;
 }
 struct MyClass* obj = MyClass_new();
 MyClass_someMethod(obj);
 MyClass_delete(&obj);

C++

Compiler: GCC 4.0.2

 class MyClass
 {
 public:
   void someMethod(); // member function = method
   MyClass(); // constructor
 private:
   int variable; // member variable = instance variable
 };
 
 // implementation of constructor
 MyClass::MyClass():
   variable(0)
 {
   // here could be more code
 }
 
 // implementation of member function
 void MyClass::someMethod()
 {
   variable = 1; // alternatively: this->variable = 1
 }
 
 // Create an instance as variable
 MyClass instance;
 
 // Create an instance on free store
 MyClass* pInstance = new MyClass;
 // Instances allocated with new must be explicitly destroyed when not needed any more:
 delete pInstance;

Note: MyClass instance(); would not define an instance, but declare a function returning an instance. Accidentally declaring functions when object definitions are wanted is a rather common bug in C++.

Functions can also be defined inline:

 class MyClass
 {
 public:
   MyClass(): variable(0) {}
   void someMethod() { variable = 1; }
 private:
   int variable;
 };

Note that member functions in C++ by default are not polymorphic; if you want a polymorphic member function, you have to mark it as virtual. In that case, you should also add a virtual destructor, even if that is empty. Example:

 class MyClass
 {
 public:
   virtual void someMethod(); // this is polymorphic
   virtual ~MyClass(); // destructor
 };

C#

 public class MyClass
 {
   public MyClass()
   {
   }
   public void SomeMethod()
   {
   }
   private int _variable;
   public int Variable
   {
     get { return _variable; }
     set { _variable = value; }
   }
   public static void Main()
   {
     // instantiate it
     MyClass instance = new MyClass();
     // invoke the method
     instance.SomeMethod();
     // set the variable
     instance.Variable = 99;
     // get the variable
     System.Console.WriteLine( "Variable=" + instance.Variable.ToString() );
   }
 }

Objective-C

Compiler: GCC 4.0.1 (apple)

Interface:

// There are no class variables, so static variables are used.
static int myClassVariable = 0;

@interface MyClass : NSObject
{
    int variable; // instance variable
}

- (int)variable; // Typical accessor - you should use the same name as the variable

@end

Implementation:

@implementation MyClass

// Was not declared because init is defined in NSObject
- init
{
    if (self = [super init])
        variable = 0;
    return self;
}

- (int)variable
{
    return variable;
}

@end

Using the class:

// Creating an instance
MyClass *mc = [[MyClass alloc] init];

// Sending a message
[mc variable];

// Releasing it. When its reference count goes to zero, it will be deallocated
[mc release];

Common Lisp

(defclass circle ()
  ((radius :initarg :radius
           :initform 1.0
           :type number
           :reader radius)))
(defmethod area ((shape circle))
  (* pi (expt (radius shape) 2)))
> (defvar *c* (make-instance 'circle :radius 2))
> (area *c*)
12.566370614359172d0

E

In E, classes, constructors, and instance variables are not built into the language. This is an example of the basic convention; different cases may call for objects built in different ways.

def makeColor(name :String) {
    def color {
        to colorize(thing :String) {
          return `$name $thing`
        }
    }
    return color
}

Example interactive session creating and using it:

? def red := makeColor("red")
# value: <color>
? red.colorize("apple")
# value: "red apple"

Forth

Interpreter: WinForth

ANSI Forth has no object oriented features, but as Forth is a very easy language to extend, many object oriented programming systems have been implemented for it over the years. WinForth has one such system, which is described here.

Declare a class

:class MyClass <super Object

  int memvar

  :m ClassInit: ( -- )
       ClassInit: super
       1 to memvar ;m

  :m ~: ( -- )  ." Final " show: [ Self ] ;m

  :m set: ( n -- )  to memvar ;m
  :m show: ( -- ) ." Memvar = " memvar . ;m

;class

Allocate a static object

MyClass newInstance

Allocate a dynamic object, saving its pointer in a global variable.

New> MyClass  value newInstance

Call member functions

10 set: newInstance
show: newInstance

Free a dynamically allocated object

newInstance dispose
0 to newInstance   \ no dangling pointers!

Example of dynamic allocation and local variable use"

: test { \ obj -- }
    New> MyClass to obj
      show: obj
      1000 set: obj
    obj dispose ;

Java

Platform: J2SE/

 public class MyClass {
 
   // instance variable
   private int variable;  // Note: instance variables are usually "private"
 
   /**
   * The constructor
   */
   public MyClass() {
     // creates a new instance
   }
 
   /**
   * A method
   */
   public void someMethod() {
    this.variable = 1; // Note: "this." is optional
                       // variable = 1; works also
   }
 }

JavaScript

Interpreter: Firefox 2.0

//constructor
function MyClass(initVal) {
    //instance variable
    if(initVal == undefined) {
        this.number = 1;
    }
    else {
        this.number = initVal;
    }
}

//method of MyClass
MyClass.prototype.getDouble = function() {
    return this.number * 2;
};

var instance1 = new MyClass; //or "new MyClass();"
instance1.number = 5;
alert( instance1.getDouble() ); //10

var instance2 = new MyClass(3);
alert( instance2.getDouble() ); //6

Oberon-2

Compiler: OO2C 2.1.11

MODULE M;

   TYPE
      T = POINTER TO TDesc;
      TDesc = RECORD
         x: INTEGER
      END;

   PROCEDURE New*(): T;
      VAR t: T;
   BEGIN
      NEW(t); t.x := 0;
      RETURN t
   END New;


   PROCEDURE (t: T) Increment*;
   BEGIN
      INC(t.x)
   END Increment;

END M.

Exported procedures are marked with an asterisk (*). There is nothing special about the constructor New, it is just a function that returns a new object of type T. The name of the method receiver can also be chosen freely. INC is a predeclared procedure that increments its argument.

Perl

Interpreter: perl 5.8.6

The implementation (there are no declarations):

{
     # a class is a package (i.e. a namespace) with methods in it
    package MyClass;

     # a constructor is a function that returns a blessed reference
    sub new {
        my $class = shift;
        bless {variable => 0}, $class;
         # the instance object is a hashref in disguise.
         # (it can be a ref to anything.)
    };

     # an instance method is a function that takes an object as first argument.
     # the -> invocation syntax takes care of that nicely, see Usage paragraph below.
    sub someMethod {
        my $self = shift;
        $self->{variable} = 1;
    };
};

Using the class:

my $instance = MyClass->new;    # invoke constructor method

$instance->someMethod;    # invoke method on object instance
 # instance deallocates when the last reference falls out of scope

Pop11

Object system is implemented as a library, so we must first load it.

uses objectclass;
define :class MyClass;
    slot value = 1;
enddefine;

Defining class MyClass automatically defines two constructors, newMyClass and consMyClass and slot (instance variable) accessors, so we can immediately start using our new class:

;;; Construct instance with default slot values
lvars instance1 = newMyClass();
;;; Construct instance with explicitely given slot values
lvars instance2 = consMyClass(15);
;;; Print slot value using dot notation
instance1.value =>
instance2.value =>
;;; Print slot value using funtional notation
value(instance1) =>
;;; Change slot value
12 -> value(instance1);
;;; Print it
value(instance1) =>

We can add methods at any time (even after creating an instance):

define :method reset(x : MyClass);
   0 -> value(x);
enddefine;
reset(instance1);
;;; Print it
instance1 =>


Python

Interpreter: Python 2.5

class MyClass:
    name2 = 2 # Class attribute

    def __init__(self):
        """
        Constructor  (Technically an initializer rather than a true "constructor")
        """
        self.name1 = 0 # Instance attribute
  
    def someMethod(self):
        """
        Method
        """
        self.name1 = 1
        MyClass.name2 = 3
  
  
myclass = MyClass() # class name, invoked as a function is the constructor syntax.

class MyOtherClass:
    count = 0  # Population of "MyOtherClass" objects
    def __init__(self, name, gender="Male", age=None):
        """
        One initializer required, others are optional (with different defaults)
        """
        MyOtherClass.count += 1
        self.name = name
        self.gender = gender
        if age is not None:
            self.age = age
    def __del__(self):
        MyOtherClass.count -= 1

person1 = MyOtherClass("John")
print person1.name, person1.gender  # "John Male"
print person1.age                   # Raises AttributeError exception!
person2 = MyOtherClass("Jane", "Female", 23)
print person2.name, person2.gender, person2.age  # "Jane Female 23"
  
  

Python allows for very flexible argument passing including normal named parameters, defaulted/optional named parameters, up to one "varargs" tuple, and any number of keywords arguments (which are all passed in the form of a single dictionary (associative array), and any non-ambiguous combination of these). All types of argument passing for functions can also be used for object instantiation/initialization (passed to the special __init__() method) as shown.

New-style classes inherit from "object" or any descendent of the "object" class:

class MyClass(object):
    ...

These "new-style" classes support some features which were unavailable in "classic classes". New features include a __new__() with lower level control over object instantiation, metaclass support, static methods, class methods, "properties" (managed attributes) and "slots" (attribute restrictions).

Ruby

class MyClass
  @@classVar
  def initialize
    @instanceVar = 0
  end
  def someMethod
    @instanceVar = 1
    @@classVar = 3
  end
end
myclass = MyClass.new

Turbo Pascal

Note: This is not part of standard Pascal, but Turbo Pascal specific Compiler: Turbo Pascal 6.0

type
 MyClass = object
            variable: integer;
            constructor init;
            destructor done;
            procedure someMethod;
           end;

constructor MyClass.init;
 begin
  variable := 0;
 end;

procedure MyClass.someMethod;
 begin
  variable := 1;
 end;

var
 instance: MyClass; { as variable }
 pInstance: ^MyClass; { on free store }

begin
 { create instances }
 instance.init;
 new(pInstance, init); { alternatively: pInstance := new(MyClass, init); }
 
 { call method }
 instance.someMethod;
 pInstance^.someMethod;
 
 { get rid of the objects }
 instance.done;
 dispose(pInstance, done);
end;