Object-oriented programming Reference

# Getting started

## Select the object-oriented programming profile

To undertake object-oriented programming (OOP) with Elan, you should first be reasonably familiar with procedural programming with Elan. Start by switching to the object-oriented profile from the menu at the top of the IDE. This will still allow you to do procedural programming, but changes two things:

- The list of demo programs will now show only programs that use OOP - except that Snake is offered in both procedural and object-oriented forms for direct comparison. We will be referring to code within the OOP demo programs within this text.
- It will change some of the options available on the new code menus in the editor:
  - At the global level, it will offer: concrete class and abstract class
  - Within a concrete class or abstract class the new code menu will show an entirely new list of instructions, collectively known as ‘members’ (plus comment) that may be defined within within them.

In the following section we will describe 10 principles that define the essence of OOP, illustrated with example code - where possible from the demo programs.

# Principles of object-oriented programming

Important. Every textbook on OOP differs slightly in the definition of core principles, and every language that supports OOP differs in the rules that it enforces. The following 10 principles are based on widely recognised best practices in OOP. When coding with Elan, in whichever of the supported languages - Python, VB, C#, or Java (or the Elan Reference Language) - these principles are, wherever possible, enforced by the Elan tooling. The resulting code is always valid syntax for the chosen language - but may depend upon common library methods defined in the Elan library. Also, if you go on to write code in any of those languages outside Elan, you will find that the same principles are not necessarily enforced. Though that might appear to offer you more freedom, sticking voluntarily to the principles that you learned in Elan will result in better code and fewer problems.

## A class is a user-defined data structure type

In procedural programming with Elan, there is a fixed set of types available to you to represent data - the only exception being enums which offer a very limited form of 'user-defined' type (UDT). OOP makes it easy to define far richer forms of UDTs. The simplest and most common way to do this is to define a concrete class which is one of the new options made available at global (file) level when using Elan with the object-oriented profile selected.

In the Snake object-oriented demo you can find three examples of concrete classes. Only the 'signature' of each class is shown here - not the instructions contained within the classes:
+class Snake Name? inheritance?1 +constructor(parameter definitions?) 2 new code end constructor +function toString name?(parameter definitions?) returns String Type? 3 return "undefined"value or expression?4 end function end class +class Apple Name? inheritance?5 +constructor(parameter definitions?) 6 new code end constructor +function toString name?(parameter definitions?) returns String Type? 7 return "undefined"value or expression?8 end function end class +class Square Name? inheritance?9 +constructor(parameter definitions?) 10 new code end constructor +function toString name?(parameter definitions?) returns String Type? 11 return "undefined"value or expression?12 end function end class
+class Snake Name? inheritance? # concrete class 1 +def __init__(self: Snake) -> None: 2 new code +def toString name?(self: Snake) -> str Type?: # function method 3 return "undefined"value or expression?4 +class Apple Name? inheritance? # concrete class 5 +def __init__(self: Apple) -> None: 6 new code +def toString name?(self: Apple) -> str Type?: # function method 7 return "undefined"value or expression?8 +class Square Name? inheritance? # concrete class 9 +def __init__(self: Square) -> None: 10 new code +def toString name?(self: Square) -> str Type?: # function method 11 return "undefined"value or expression?12
+class Snake Name? inheritance? {1 +public Snake(parameter definitions?) { 2 new code } // constructor +public string Type? toString name?(parameter definitions?) { // function method 3 return "undefined"value or expression?;4 } // function method } // class +class Apple Name? inheritance? {5 +public Apple(parameter definitions?) { 6 new code } // constructor +public string Type? toString name?(parameter definitions?) { // function method 7 return "undefined"value or expression?;8 } // function method } // class +class Square Name? inheritance? {9 +public Square(parameter definitions?) { 10 new code } // constructor +public string Type? toString name?(parameter definitions?) { // function method 11 return "undefined"value or expression?;12 } // function method } // class
+Class Snake Name? inheritance?1 +Sub New(parameter definitions?) 2 new code End Sub +Function toString name?(parameter definitions?) As String Type? 3 Return "undefined"value or expression?4 End Function End Class +Class Apple Name? inheritance?5 +Sub New(parameter definitions?) 6 new code End Sub +Function toString name?(parameter definitions?) As String Type? 7 Return "undefined"value or expression?8 End Function End Class +Class Square Name? inheritance?9 +Sub New(parameter definitions?) 10 new code End Sub +Function toString name?(parameter definitions?) As String Type? 11 Return "undefined"value or expression?12 End Function End Class
public class Global {
+class Snake Name? inheritance? {1 +public Snake(parameter definitions?) { 2 new code } // constructor +public String Type? toString name?(parameter definitions?) { // function method 3 return "undefined"value or expression?;4 } // function method } // class +class Apple Name? inheritance? {5 +public Apple(parameter definitions?) { 6 new code } // constructor +public String Type? toString name?(parameter definitions?) { // function method 7 return "undefined"value or expression?;8 } // function method } // class +class Square Name? inheritance? {9 +public Square(parameter definitions?) { 10 new code } // constructor +public String Type? toString name?(parameter definitions?) { // function method 11 return "undefined"value or expression?;12 } // function method } // class
}

Within the definition of each class you will find several property instructions. Each property has unique name (within the class). A class may defined multiple properties of the same type, for example, the `SquareSquareSquareSquareSquare` class in Snake defines:

+constructor(parameter definitions?) 0 new code end constructor
property x as Int Code does not parse as Elan.
property x as Int Code does not parse as Elan.
+Sub New(parameter definitions?) 0 new code End Sub
property x as Int Code does not parse as Elan.
+constructor(parameter definitions?) 0 new code end constructor
property y as Int Code does not parse as Elan.
property y as Int Code does not parse as Elan.
+Sub New(parameter definitions?) 0 new code End Sub
property y as Int Code does not parse as Elan.
or properties may have different types, for example the `TuringMachineTuringMachineTuringMachineTuringMachineTuringMachine` class in the Roman Numerals Turing Machine demo has these:- the class may have multiple properties of the same type but with different names, or define
+constructor(parameter definitions?) 0 new code end constructor
property initialState as String Code does not parse as Elan.
property initialState as String Code does not parse as Elan.
+Sub New(parameter definitions?) 0 new code End Sub
property initialState as String Code does not parse as Elan.
+constructor(parameter definitions?) 0 new code end constructor
property currentState as String Code does not parse as Elan.
property currentState as String Code does not parse as Elan.
+Sub New(parameter definitions?) 0 new code End Sub
property currentState as String Code does not parse as Elan.
+constructor(parameter definitions?) 0 new code end constructor
property headPosition as Int Code does not parse as Elan.
property headPosition as Int Code does not parse as Elan.
+Sub New(parameter definitions?) 0 new code End Sub
property headPosition as Int Code does not parse as Elan.
+constructor(parameter definitions?) 0 new code end constructor
property haltState as String Code does not parse as Elan.
property haltState as String Code does not parse as Elan.
+Sub New(parameter definitions?) 0 new code End Sub
property haltState as String Code does not parse as Elan.
+constructor(parameter definitions?) 0 new code end constructor
property rules as List Code does not parse as Elan.
property rules as List Code does not parse as Elan.
+Sub New(parameter definitions?) 0 new code End Sub
property rules as List Code does not parse as Elan.
+constructor(parameter definitions?) 0 new code end constructor
property tape as String Code does not parse as Elan.
property tape as String Code does not parse as Elan.
+Sub New(parameter definitions?) 0 new code End Sub
property tape as String Code does not parse as Elan.

### Defining a class

Selecting concrete class from the new code menu inserts a template like this:

+class Name Name? inheritance?1 +constructor(parameter definitions parameter definitions?) 2 new code end constructor +function toString name?(parameter definitions parameter definitions?) returns String Type? 3 return "undefined"value or expression?4 end function end class
+class Name Name? inheritance? # concrete class 1 +def __init__(self: Name) -> None: 2 new code +def toString name?(self: Name) -> str Type?: # function method 3 return "undefined"value or expression?4
+class Name Name? inheritance? {1 +public Name(parameter definitions parameter definitions?) { 2 new code } // constructor +public string Type? toString name?(parameter definitions parameter definitions?) { // function method 3 return "undefined"value or expression?;4 } // function method } // class
+Class Name Name? inheritance?1 +Sub New(parameter definitions parameter definitions?) 2 new code End Sub +Function toString name?(parameter definitions parameter definitions?) As String Type? 3 Return "undefined"value or expression?4 End Function End Class
public class Global {
+class Name Name? inheritance? {1 +public Name(parameter definitions parameter definitions?) { 2 new code } // constructor +public String Type? toString name?(parameter definitions parameter definitions?) { // function method 3 return "undefined"value or expression?;4 } // function method } // class
}
where the only thing you must provide is a unique name for the class, which must start with a capital letter, followed by other letters, digits or underscores. (We will look at the roles of the constructor, and the toString function later on.)

## An object is an instance of a class

Every object in code is an instance of a specific class. The class may be thought of as a 'template' for defining instances. Each instance holds its own specific value for each of the properties defined in the class.

An new object may be created and assigned to a variable definition, for example:

variable apple name? set to new Apple()value or expression?0
apple name? = Apple()value or expression? # variable definition 0
var apple name? = new Apple()value or expression?;0
Dim apple name? = New Apple()value or expression? ' variable definition 0
var apple name? = new Apple()value or expression?;0
variable snake name? set to new Snake()value or expression?0
snake name? = Snake()value or expression? # variable definition 0
var snake name? = new Snake()value or expression?;0
Dim snake name? = New Snake()value or expression? ' variable definition 0
var snake name? = new Snake()value or expression?;0

Note that the type of each variable is determined by the class of the instance so that the `appleappleappleappleapple` variable may subsequently be reassigned to a different instance of `AppleAppleAppleAppleApple` but may not be reassigned to an instance of a different class (nor any other type).

A new instance may also be created as part of an expression without having to be assigned to a variable, for example:

return new Square(newX, newY) Code does not parse as Elan.
return new Square(newX, newY) Code does not parse as Elan.
return new Square(newX, newY) Code does not parse as Elan.
return new Square(newX, newY) Code does not parse as Elan.
return new Square(newX, newY) Code does not parse as Elan.

### Reading properties

Wherever you have a reference to an object, your code may read and make use of the publicly-visible properties of that object using 'dot syntax', for example (from the Pathfinder demo):

+if distViaCurrent < neighbour.distFromStart condition? then 0 new code end if
+if distViaCurrent < neighbour.distFromStart condition?: 0 new code
+if (distViaCurrent < neighbour.distFromStart condition?) { 0 new code } // if
+If distViaCurrent < neighbour.distFromStart condition? Then 0 new code End If
+if (distViaCurrent < neighbour.distFromStart condition?) { 0 new code } // if
is comparing the value of the variable `distViaCurrentdistViaCurrentdistViaCurrentdistViaCurrentdistViaCurrent` to the property named `distFromStartdistFromStartdistFromStartdistFromStartdistFromStart` of the object named `neighbourneighbourneighbourneighbourneighbour`.

## The constructor initialises the properties

When coding with Elan every class must define a constructor, the template for which is created when you define a new class, and which may be edited, though not deleted. The role of the constructor is to initialise the properties whenever an instance of that class is created.

The only properties that don't need to be initialised are properties of type `IntintintIntegerint`, `FloatfloatdoubleDoubledouble`, or `BooleanboolboolBooleanbool` - which are automatically initialised to the default value of each type - `00000`, `0.00.00.00.00.0`, or `falseFalsefalseFalsefalse` respectively. All other properties must be explicitly initialised within the constructor. Here is simple example of properties being initialised within the constructor for `SquareSquareSquareSquareSquare` in the Snake demo:

constructor(x as Int, y as Int) reassign this.x to x reassign this.y to y end constructor Code does not parse as Elan.
constructor(x as Int, y as Int) reassign this.x to x reassign this.y to y end constructor Code does not parse as Elan.
constructor(x as Int, y as Int) reassign this.x to x reassign this.y to y end constructor Code does not parse as Elan.
constructor(x as Int, y as Int) reassign this.x to x reassign this.y to y end constructor Code does not parse as Elan.
constructor(x as Int, y as Int) reassign this.x to x reassign this.y to y end constructor Code does not parse as Elan.

### Note:

- Even properties that are automatically initialised may be explicitly initialised in the constructor.
- It is quite common to initialise strings to an empty string - `""""""""""` and a list to any empty list of the appropriate member-type, for example `new List Code does not parse as Elan.new List Code does not parse as Elan.new List Code does not parse as Elan.new List Code does not parse as Elan.new List Code does not parse as Elan.` - though you may choose any value.
- If you don't you want every instance of a class to be initialised with the same value, the specific value for an instance is specified via paramaters added into the constructor definition.
- When a new instance is created, arguments for each parameter must be specified (as they would be for a procedure or function), so creating a new `SquareSquareSquareSquareSquare` for example takes the form `variable tailname? set to new Square(20, 15)value or expression?0tailname? = Square(20, 15)value or expression? # variable definition0var tailname? = new Square(20, 15)value or expression?;0Dim tailname? = New Square(20, 15)value or expression? ' variable definition0var tailname? = new Square(20, 15)value or expression?;0`
- A property is initialised within the construction using a reassign variable instruction - since a property may be thought of as a named variable that holds a value specific to each instance of the class.
- the name of the property being reassigned must be prefixed by this self Me this Me followed by a dot.

## Objects may have associations to other objects

So far we have looked at properties where the type is one of the standard library types. However, a class may define one or more properties where the type is a class - either of the same type as the class in which the property is defined, or - more commonly - of a different class. Each such property is referred to as an 'association' or 'associated object'. If the type of a property is a list, or other data structure, where the member type is a class, then it is often referred to as a 'multiple association' - with the ordinary kind of association referred to as 'single association'. The `SnakeSnakeSnakeSnakeSnake` class shows both kinds of association (only relevant parts of the class are shown only here):

+class Snake Name? inheritance?1 +constructor(parameter definitions parameter definitions?) 2 variable tail name? set to new Square(20, 15)value or expression?3 reassign this.currentDir variableName? to Direction.right value or expression?4 reassign this.body variableName? to [tail]value or expression?5 reassign this.head variableName? to tail.getAdjacentSquare(this.currentDir)value or expression?6 reassign this.priorTail variableName? to tail value or expression?7 end constructor private property currentDir name? as Direction Type?8 private property head name? as Square Type?9 private property body name? as List<of Square>Type?10 private property priorTail name? as Square Type?11 +function toString name?(parameter definitions?) returns String Type? 12 return "undefined"value or expression?13 end function end class
+class Snake Name? inheritance? # concrete class 1 +def __init__(self: Snake) -> None: 2 tail name? = Square(20, 15)value or expression? # variable definition 3 self.currentDir variableName? = Direction.right value or expression? # reassign variable 4 self.body variableName? = [tail]value or expression? # reassign variable 5 self.head variableName? = tail.getAdjacentSquare(self.currentDir)value or expression? # reassign variable 6 self.priorTail variableName? = tail value or expression? # reassign variable 7 currentDir name?: Direction Type? # private property 8 head name?: Square Type? # private property 9 body name?: list[Square]Type? # private property 10 priorTail name?: Square Type? # private property 11 +def toString name?(self: Snake) -> str Type?: # function method 12 return "undefined"value or expression?13
+class Snake Name? inheritance? {1 +public Snake(parameter definitions parameter definitions?) { 2 var tail name? = new Square(20, 15)value or expression?;3 this.currentDir variableName? = Direction.right value or expression?; // reassign variable 4 this.body variableName? = [tail]value or expression?; // reassign variable 5 this.head variableName? = tail.getAdjacentSquare(this.currentDir)value or expression?; // reassign variable 6 this.priorTail variableName? = tail value or expression?; // reassign variable 7 } // constructor private Direction Type? currentDir name? {get; private set;} // private property 8 private Square Type? head name? {get; private set;} // private property 9 private List<Square>Type? body name? {get; private set;} // private property 10 private Square Type? priorTail name? {get; private set;} // private property 11 +public string Type? toString name?(parameter definitions?) { // function method 12 return "undefined"value or expression?;13 } // function method } // class
+Class Snake Name? inheritance?1 +Sub New(parameter definitions parameter definitions?) 2 Dim tail name? = New Square(20, 15)value or expression? ' variable definition 3 Me.currentDir variableName? = Direction.right value or expression? ' reassign variable 4 Me.body variableName? = {tail}value or expression? ' reassign variable 5 Me.head variableName? = tail.getAdjacentSquare(Me.currentDir)value or expression? ' reassign variable 6 Me.priorTail variableName? = tail value or expression? ' reassign variable 7 End Sub Private Property currentDir name? As Direction Type?8 Private Property head name? As Square Type?9 Private Property body name? As List(Of Square)Type?10 Private Property priorTail name? As Square Type?11 +Function toString name?(parameter definitions?) As String Type? 12 Return "undefined"value or expression?13 End Function End Class
public class Global {
+class Snake Name? inheritance? {1 +public Snake(parameter definitions parameter definitions?) { 2 var tail name? = new Square(20, 15)value or expression?;3 this.currentDir variableName? = Direction.right value or expression?; // reassign variable 4 this.body variableName? = [tail]value or expression?; // reassign variable 5 this.head variableName? = tail.getAdjacentSquare(this.currentDir)value or expression?; // reassign variable 6 this.priorTail variableName? = tail value or expression?; // reassign variable 7 } // constructor private Direction Type? currentDir name?; // private property 8 private Square Type? head name?; // private property 9 private List<Square>Type? body name?; // private property 10 private Square Type? priorTail name?; // private property 11 +public String Type? toString name?(parameter definitions?) { // function method 12 return "undefined"value or expression?;13 } // function method } // class
}

### Note:

- The`SnakeSnakeSnakeSnakeSnake` is always initialised to the same values, so the constructor does not need to define any parameters.
- The `currentDircurrentDircurrentDircurrentDircurrentDir` property is of type `DirectionDirectionDirectionDirectionDirection` (which is an enum) and is initialised to `Direction.rightDirection.rightDirection.rightDirection.rightDirection.right`.
- The `bodybodybodybodybody` property is a multiple association - defined as a list of type `Square`
- The constructor defines a variable `tail Code does not parse as Elan.Square`
- The constructor defines a variable `tail Code does not parse as Elan.Square`
- The constructor defines a variable `tail Code does not parse as Elan.Square`
- The constructor defines a variable `tail Code does not parse as Elan.Square`
- The constructor defines a variable `tail Code does not parse as Elan.` used only for the purpose of initialising properties. It is first used to initialise the `bodybodybodybodybody` as a list containing only the `tailtailtailtailtail` and is finally used to define the `priorTailpriorTailpriorTailpriorTailpriorTail` which is a single association of type `SquareSquareSquareSquareSquare`. In between it is used in an expression to determine the initial value for the `headheadheadheadhead` property using a function (more on this in the next heading).
- It is thus legitimate to call functions within the constructor. A constructor may not call any procedure, however. And you should avoid doing any work in a constructor other than determining appropriate values for initialising its properties.

## Classes provide behaviour through methods

In the last code example `tail.getAdjacentSquare(this.currentDir)tail.getAdjacentSquare(self.currentDir)tail.getAdjacentSquare(this.currentDir)tail.getAdjacentSquare(Me.currentDir)tail.getAdjacentSquare(this.currentDir)` calls a function method, using 'dot syntax' on the the variable `tailtailtailtailtail`, which is an instance of class `SquareSquareSquareSquareSquare`. Defining a function method, or a procedure method, on a class has these advantages:

- they are invoked on an instance using 'dot-syntax' as we shown in the previous example
- they have access to all the properties belonging to that same instance, and can also invoke other methods on the same object, in both cases prefixed by this self Me this Me dot.

Properties on a class define the data (or 'state') for each instance of the class; methods define the behaviour for the object.

## A function method provides information based on the parameters specified in combination with the object's properties

Function methods defined on a class, are similar to global functions in that they act like 'queries', returning information that is determined by the values of the parameters. The difference is that a function method defined on a class, may additionally make use of information obtained from the properties of the object (directly or indirectly) - to determine the information to be returned. But like a global function, a function method defined on a class may not cause any side effects, which means that it may not update any property. The body of the getAdjacentSquare accesses the objects `xxxxx` and `yyyyy` properties and uses this, together with the `DirectionDirectionDirectionDirectionDirection` parameter to create and return a new instance of `SquareSquareSquareSquareSquare` with different `xxxxx` and `yyyyy` properties:

+function getAdjacentSquare name?(d as Direction parameter definitions?) returns Square Type? 1 variable newX name? set to this.x value or expression?2 variable newY name? set to this.y value or expression?3 +if d is Direction.left condition? then 4 reassign newX variableName? to this.x - 1 value or expression?5 elif d is Direction.right condition? then 6 reassign newX variableName? to this.x + 1 value or expression?7 elif d is Direction.up condition? then 8 reassign newY variableName? to this.y - 1 value or expression?9 elif d is Direction.down condition? then 10 reassign newY variableName? to this.y + 1 value or expression?11 end if return new Square(newX, newY)value or expression?12 end function
+def getAdjacentSquare name?(d: Direction parameter definitions?) -> Square Type?: # function 1 newX name? = self.x value or expression? # variable definition 2 newY name? = self.y value or expression? # variable definition 3 +if d == Direction.left condition?: 4 newX variableName? = self.x - 1 value or expression? # reassign variable 5 elif d == Direction.right condition?: # else if 6 newX variableName? = self.x + 1 value or expression? # reassign variable 7 elif d == Direction.up condition?: # else if 8 newY variableName? = self.y - 1 value or expression? # reassign variable 9 elif d == Direction.down condition?: # else if 10 newY variableName? = self.y + 1 value or expression? # reassign variable 11 return Square(newX, newY)value or expression?12
+static Square Type? getAdjacentSquare name?(Direction d parameter definitions?) { // function 1 var newX name? = this.x value or expression?;2 var newY name? = this.y value or expression?;3 +if (d == Direction.left condition?) { 4 newX variableName? = this.x - 1 value or expression?; // reassign variable 5 } else if (d == Direction.right condition?) {6 newX variableName? = this.x + 1 value or expression?; // reassign variable 7 } else if (d == Direction.up condition?) {8 newY variableName? = this.y - 1 value or expression?; // reassign variable 9 } else if (d == Direction.down condition?) {10 newY variableName? = this.y + 1 value or expression?; // reassign variable 11 } // if return new Square(newX, newY)value or expression?;12 } // function
+Function getAdjacentSquare name?(d As Direction parameter definitions?) As Square Type? 1 Dim newX name? = Me.x value or expression? ' variable definition 2 Dim newY name? = Me.y value or expression? ' variable definition 3 +If d = Direction.left condition? Then 4 newX variableName? = Me.x - 1 value or expression? ' reassign variable 5 ElseIf d = Direction.right condition? Then 6 newX variableName? = Me.x + 1 value or expression? ' reassign variable 7 ElseIf d = Direction.up condition? Then 8 newY variableName? = Me.y - 1 value or expression? ' reassign variable 9 ElseIf d = Direction.down condition? Then 10 newY variableName? = Me.y + 1 value or expression? ' reassign variable 11 End If Return New Square(newX, newY)value or expression?12 End Function
public class Global {
+static Square Type? getAdjacentSquare name?(Direction d parameter definitions?) { // function 1 var newX name? = this.x value or expression?;2 var newY name? = this.y value or expression?;3 +if (d == Direction.left condition?) { 4 newX variableName? = this.x - 1 value or expression?; // reassign variable 5 } else if (d == Direction.right condition?) {6 newX variableName? = this.x + 1 value or expression?; // reassign variable 7 } else if (d == Direction.up condition?) {8 newY variableName? = this.y - 1 value or expression?; // reassign variable 9 } else if (d == Direction.down condition?) {10 newY variableName? = this.y + 1 value or expression?; // reassign variable 11 } // if return new Square(newX, newY)value or expression?;12 } // function
}

The toString function method returns a string that represents the object in some way. It is called automatically whenever you call print with a variable that holds an instance of the class. If you don't need to print an object in text form on the display, it is safe to leave the default implementation toString - that was created when you added the class, and which returns an empty string `""""""""""`. If you do intend to print an object in text form then you can define the string to be returned, incorporating one or more of the object's properties to help identify the particular object. For example, you might edit the method defined on the `SnakeSnakeSnakeSnakeSnake` class to:

+function toString name?(parameter definitions parameter definitions?) returns String Type? 1 return $"A snake with {this.body.length() + 1} segments"value or expression?2 end function
+def toString name?(parameter definitions parameter definitions?) -> str Type?: # function 1 return f"A snake with {self.body.length() + 1} segments"value or expression?2
+static string Type? toString name?(parameter definitions parameter definitions?) { // function 1 return $"A snake with {this.body.length() + 1} segments"value or expression?;2 } // function
+Function toString name?(parameter definitions parameter definitions?) As String Type? 1 Return $"A snake with {Me.body.length() + 1} segments"value or expression?2 End Function
public class Global {
+static String Type? toString name?(parameter definitions parameter definitions?) { // function 1 return String.format("A snake with % segments", this.body.length() + 1)value or expression?;2 } // function
}
(You might like to try this out, temporarilyadding the instruction `print(snakearguments?)0print(snakearguments?)0Console.WriteLine(snakearguments?); // print0Console.WriteLine(snakearguments?) ' print0System.out.println(snakearguments?); // print0` into the main routine.)

## A procedure method changes the state of the object, and/or interacts with the system

Procedure methods, like function methods, may define parameters and may also read the values of the object's properties. Like global procedures they may also generate side effects, and this includes changing the values of the object's properties, and may call other procedures, on the same object, or associated objects. For example, the clockTick procedure method defined in the `SnakeSnakeSnakeSnakeSnake` class, changes the position of various segments, and, if the `headheadheadheadhead` now covers the same space as the `appleappleappleappleapple` changes the position of the apple (passed into the method as a parameter) by calling the newRandomPosition procedure method on `appleappleappleappleapple`:

+procedure clockTick name?(key as String, apple as Apple parameter definitions?) 1 call this.setDirection procedureName?(key arguments?)2 reassign this.priorTail variableName? to this.body[0]value or expression?3 variable body name? set to this.body value or expression?4 call body.append procedureName?(this.head arguments?)5 reassign this.head variableName? to this.head.getAdjacentSquare(this.currentDir)value or expression?6 +if this.head.equals(apple.location)condition? then 7 call apple.newRandomPosition procedureName?(this arguments?)8 else 9 reassign this.body variableName? to this.body.subList(1, this.body.length())value or expression?10 end if end procedure
+def clockTick name?(key: str, apple: Apple parameter definitions?) -> None: # procedure 1 self.setDirection procedureName?(key arguments?) # call procedure 2 self.priorTail variableName? = self.body[0]value or expression? # reassign variable 3 body name? = self.body value or expression? # variable definition 4 body.append procedureName?(self.head arguments?) # call procedure 5 self.head variableName? = self.head.getAdjacentSquare(self.currentDir)value or expression? # reassign variable 6 +if self.head.equals(apple.location)condition?: 7 apple.newRandomPosition procedureName?(self arguments?) # call procedure 8 else:9 self.body variableName? = self.body.subList(1, self.body.length())value or expression? # reassign variable 10
+static void clockTick name?(string key, Apple apple parameter definitions?) { // procedure 1 this.setDirection procedureName?(key arguments?); // call procedure 2 this.priorTail variableName? = this.body[0]value or expression?; // reassign variable 3 var body name? = this.body value or expression?;4 body.append procedureName?(this.head arguments?); // call procedure 5 this.head variableName? = this.head.getAdjacentSquare(this.currentDir)value or expression?; // reassign variable 6 +if (this.head.equals(apple.location)condition?) { 7 apple.newRandomPosition procedureName?(this arguments?); // call procedure 8 } else {9 this.body variableName? = this.body.subList(1, this.body.length())value or expression?; // reassign variable 10 } // if } // procedure
+Sub clockTick name?(key As String, apple As Apple parameter definitions?) ' procedure 1 Me.setDirection procedureName?(key arguments?) ' call procedure 2 Me.priorTail variableName? = Me.body[0]value or expression? ' reassign variable 3 Dim body name? = Me.body value or expression? ' variable definition 4 body.append procedureName?(Me.head arguments?) ' call procedure 5 Me.head variableName? = Me.head.getAdjacentSquare(Me.currentDir)value or expression? ' reassign variable 6 +If Me.head.equals(apple.location)condition? Then 7 apple.newRandomPosition procedureName?(Me arguments?) ' call procedure 8 Else 9 Me.body variableName? = Me.body.subList(1, Me.body.length())value or expression? ' reassign variable 10 End If End Sub
public class Global {
+static void clockTick name?(String key, Apple apple parameter definitions?) { // procedure 1 this.setDirection procedureName?(key arguments?); // call procedure 2 this.priorTail variableName? = this.body[0]value or expression?; // reassign variable 3 var body name? = this.body value or expression?;4 body.append procedureName?(this.head arguments?); // call procedure 5 this.head variableName? = this.head.getAdjacentSquare(this.currentDir)value or expression?; // reassign variable 6 +if (this.head.equals(apple.location)condition?) { 7 apple.newRandomPosition procedureName?(this arguments?); // call procedure 8 } else {9 this.body variableName? = this.body.subList(1, this.body.length())value or expression?; // reassign variable 10 } // if } // procedure
}

## Objects should represent the principal nouns in the application domain

The word 'encapsulation' is often used in descriptions of object-oriented programming. But that word has two rather different meanings in plain English. Fortunately, both of the meanings of 'encapsulation' apply.

The first meaning of encapsulation is similar to 'represents' - as in 'Our school motto encapsulates the ethos and culture of the school'. (The second meaning will be addressed in the next principle.) Thus, objects should represent, or encapsulate, the principal concepts in the application domain. A rule of thumb is that the classes defined in a program should correspond to the main nouns used when describing the purpose and operation of the program in plain English. You can see this in the Snake demo, where the code defines three classes, named `SnakeSnakeSnakeSnakeSnake`, `AppleAppleAppleAppleApple`, and `SquareSquareSquareSquareSquare` - all nouns that would be recognised by anyone who understands how to play the game Snake, but who does not necessarily know anything about programming.

One of the claimed benefits of this is that it makes programs easier to read, and to update in response to new requirements, because the structure of the code corresponds more closely to the language of the application domain. If the user, or the business customer that owns the game, says that they want the snake to be a different colour, or for there to be two apples at once (in different positions) - it will be easier for the programmer to identity where within the program the code must be changed that in a procedural implementation. You can try this for yourself, by asking a user to specify similar small changes to the presentation and/or game rules, and testing how long it takes you to update the procedural, and object-oriented, versions of the Snake program as required.

Importantly, the class does not just represent all the information associated with the noun - it also encapsulates the behaviour needed from that thing, in the form of methods. This is sometimes stated as representing the know-whats for the thing (as properties), and the know how-to's as methods.

## Objects should hide state behind methods, where possible

This principle corresponds to the second meaning of 'encapsulation': sealing. Think of the related word: 'capsule'. You can only access the capabilities of an object through its public members. All the 'members' defined on a class (that is: its properties and methods) are public - although properties are public only for reading, not for modifying. However, it is possible to make any property or method private - such that it can be accessed from code within the class, but not from outside. To do this, you bring up the context menu on the instruction (by right-mouse-click or Ctrl-m) and select make private (a change that can be reversed with make public).A method might be made private because it just provides help to one or more public methods, but is not expected to be useful in its own right. However, a property is often made private to implement the principle of 'information' hiding.

Some textbooks suggest that every property - for example `dateOfBirthdateOfBirthdateOfBirthdateOfBirthdateOfBirth` - should be private, and that access should be via a 'getter' - a function method typically named getDateOfBirth, and a 'setter' - a procedure method typically named setDateOfBirth. But that idea is not really hiding the information. Real information hiding is to prevent external code from accessing the data and instead provide them with public methods that provide more useful services. For example, in the Snake demo, all the `headheadheadheadhead` and `bodybodybodybodybody` properties are private, but the function method bodyCovers allows external code to test whether the snake (body or head) covers a given square, passed in as a parameter. This method is called from within the newRandomPosition defined by the `AppleAppleAppleAppleApple` class, to ensure that the next apple is not created directly underneath the snake.

## A concrete class may optionally inherit from an abstract class

In many applications two or more of the classes will be seen as having quite a lot in common. When this situation identified, there might be a case for making them inherit from a common 'abstract' class. For example, in a school administration system, you might define classes named Pupil, Teacher, and Parent, but these might all inherit from a common abstract class named Individual. The Person class can then be described as the 'superclass' of the other three, and they as the 'subclasses' of Individual.

An abstract class is created, at global level, with an abstract class instruction, and the template requires a name (beginning with a capital letter) to be specified.

The main differences between an abstract and a concrete super-class are:

- an abstract class cannot be instantiated. If, using the example above, you were to write: `new Individual()Individual()new Individual()New Individual()new Individual()` you will get a compile-error message: Individual must be concrete to create instance.
- an abstract class has no constructor (it also does not need toString because every concrete class must define one.
- the new code menus, as well as offering the property, procedure method, and function method options as in a concrete class, also offer abstract procedure method, and abstract function method. A concrete class must provide a concrete (normal) implementation of each abstract member defined in its superclass, or any abstract class above it in the hierarchy.

Earlier we learned about association between objects. Association may be characterised by the 'has a' relationship, as in a 'Student has a personal tutor' (meaning that the Student class defines a property named 'tutor' - which is of type Teacher. Bt contrast inheritance may be characterised as an 'is a' relationship, as in 'a Student is an Individual'.

There are two principal motivations from making two or more classes inherit from a common abstract class:

- To reduce repetition of common properties and methods - which may be defined on the abstract superclass and then not repeated in the subclasses. For example it might be that Individual define a (string) property named 'emailAddress' and define a common procedure method named 'sendMessage'.
- To allow instances of any of the subclasses to be handled by external code without having to know the individual subclass of each instance. This principle is known as 'type substitutability' and is a form of a more general principle know as 'polymorphism' - meaning 'of multiple forms'. For example, the user might define a special interest group that included some pupils, parents, and teachers, and so would be defined as a list of type Individual. This then makes it easy to send a message to all the members of the group, by invoking the method 'sendMessage' on each member in turn, without having to identify the type each member.

Some textbooks emphasise the first of those two motivations, but it is the second one that is far more important. Indeed, inheritance is the most over-used, and the most frequently abused, concepts in OOP. For that reason, irrespective of the programming language being used, Elan deliberately enforces principles of good OOP from the outset. For example:

- Each class may inherit from one superclass only
- The superclass must be an abstract class - no class may inherit from another concrete class.
- A abstract class may inherit from another abstract class - to form a 'hierarchy' of abstraction, if desired.
- A concrete class may inherit concrete (ordinary) members from its superclass, but it may not override them.

The last point is controversial - since all the supported programming languages allow overriding. But overriding (of concrete methods) breaks the 'O' of the widely-quoted 'SOLID' principles of oop: that classes should be 'Open for extension, but closed for modification'.

## Application logic should be well-distributed across classes

In Elan, an object-oriented program still needs a procedural main method to execute.

The Java language is unusual in that even the main routine must defined within a class - Elan handles this by including a class named `Global Code does not parse as Elan.Global Code does not parse as Elan.Global Code does not parse as Elan.Global Code does not parse as Elan.Global Code does not parse as Elan.` as part of the file boilerplate, but treats the instructions directly within this class as being 'global' in nature. Any user-defined classes are added within this, and Elan does not allow properties to be added directly within that `Global Code does not parse as Elan.Global Code does not parse as Elan.Global Code does not parse as Elan.Global Code does not parse as Elan.Global Code does not parse as Elan.` class since these would be, effectively, just global variables in disguise.

In general good OOP design means aiming to keep the functionality well-distributed among the user-defined classes. Inevitably, some classes are going to define more methods, and/or more-complex methods, than others. But you should be wary of a situation where one class is doing most of the work, and the other classes act as little more than data structures without encapsulated behaviour. All too often that one big class is instantiated only once (this pattern is known as a 'singleton'), by the main routine. While singletons are not always a bad idea, a singleton that does most of the work of the program - sometimes irreverently referred to as a 'god class' - is really just a procedural program in disguise.

A useful check on your design is to look at the distribution of instructions in the program (not counting instructions within tests, which are not part of the executable program) as in the the following summary of the Snake - object-oriented demo:

Class | Properties | Methods (excl. constructor & toString) | No. of instructions | Notes
--- | --- | --- | --- | ---
`SnakeSnakeSnakeSnakeSnake` | 46 |  | 57 | singleton - but an extended version of the game might have multiple instances.
`SnakeSnakeSnakeSnakeSnake` | 12 |  | 16 | ditto
`SquareSquareSquareSquareSquare` | 22 |  | 22 | Many instances created in the game. Both Snake and Apple have associations to one or more Squares
Instructions not in a user-defined class | 12 | 13 | e.g. in main method, enums, or global procedures/functions, excluding tests
Total instructions | 96 | excluding tests

# Global Instructions

Coding with Elan using the object-oriented profile offers all the global instructions uses in the procedural profile plus two new ones: concrete class and abstract class

## Concrete class

#### Examples of concrete classes

From the Snake - object-oriented demo:

+class Apple Name? inheritance?1 +constructor(parameter definitions parameter definitions?) 2 reassign this.location variableName? to new Square(0, 0)value or expression?3 end constructor property location name? as Square Type?4 +procedure newRandomPosition name?(snake as Snake parameter definitions?) 5 variable changePosition name? set to true value or expression?6 +while changePosition condition? 7 variable ranX name? set to randint(0, 39)value or expression?8 variable ranY name? set to randint(0, 29)value or expression?9 reassign this.location variableName? to new Square(ranX, ranY)value or expression?10 +if not snake.bodyCovers(this.location)condition? then 11 reassign changePosition variableName? to false value or expression?12 end if end while end procedure +procedure updateBlocks name?(blocks as List<of List<of Int>>parameter definitions?) 13 reassign blocks[this.location.x][this.location.y]variableName? to red value or expression?14 end procedure +function toString name?(parameter definitions parameter definitions?) returns String Type? 15 return $"an Apple at {this.location}"value or expression?16 end function end class
+class Apple Name? inheritance? # concrete class 1 +def __init__(self: Apple) -> None: 2 self.location variableName? = Square(0, 0)value or expression? # reassign variable 3 location name?: Square Type? # property 4 +def newRandomPosition name?(self: Apple, snake: Snake parameter definitions?) -> None: # procedure method 5 changePosition name? = True value or expression? # variable definition 6 +while changePosition condition?: 7 ranX name? = randint(0, 39)value or expression? # variable definition 8 ranY name? = randint(0, 29)value or expression? # variable definition 9 self.location variableName? = Square(ranX, ranY)value or expression? # reassign variable 10 +if not snake.bodyCovers(self.location)condition?: 11 changePosition variableName? = False value or expression? # reassign variable 12 +def updateBlocks name?(self: Apple, blocks: list[list[int]]parameter definitions?) -> None: # procedure method 13 blocks[self.location.x][self.location.y]variableName? = red value or expression? # reassign variable 14 +def toString name?(self: Apple) -> str Type?: # function method 15 return f"an Apple at {self.location}"value or expression?16
+class Apple Name? inheritance? {1 +public Apple(parameter definitions parameter definitions?) { 2 this.location variableName? = new Square(0, 0)value or expression?; // reassign variable 3 } // constructor public Square Type? location name? {get; private set;} // property 4 +public void newRandomPosition name?(Snake snake parameter definitions?) { // procedure method 5 var changePosition name? = true value or expression?;6 +while (changePosition condition?) { 7 var ranX name? = randint(0, 39)value or expression?;8 var ranY name? = randint(0, 29)value or expression?;9 this.location variableName? = new Square(ranX, ranY)value or expression?; // reassign variable 10 +if (!snake.bodyCovers(this.location)condition?) { 11 changePosition variableName? = false value or expression?; // reassign variable 12 } // if } // while } // procedure method +public void updateBlocks name?(List<List<int>> blocks parameter definitions?) { // procedure method 13 blocks[this.location.x][this.location.y]variableName? = red value or expression?; // reassign variable 14 } // procedure method +public string Type? toString name?(parameter definitions parameter definitions?) { // function method 15 return $"an Apple at {this.location}"value or expression?;16 } // function method } // class
+Class Apple Name? inheritance?1 +Sub New(parameter definitions parameter definitions?) 2 Me.location variableName? = New Square(0, 0)value or expression? ' reassign variable 3 End Sub Property location name? As Square Type?4 +Sub newRandomPosition name?(snake As Snake parameter definitions?) ' procedure method 5 Dim changePosition name? = True value or expression? ' variable definition 6 +While changePosition condition? 7 Dim ranX name? = randint(0, 39)value or expression? ' variable definition 8 Dim ranY name? = randint(0, 29)value or expression? ' variable definition 9 Me.location variableName? = New Square(ranX, ranY)value or expression? ' reassign variable 10 +If Not snake.bodyCovers(Me.location)condition? Then 11 changePosition variableName? = False value or expression? ' reassign variable 12 End If End While End Sub +Sub updateBlocks name?(blocks As List(Of List(Of Integer))parameter definitions?) ' procedure method 13 blocks[Me.location.x][Me.location.y]variableName? = red value or expression? ' reassign variable 14 End Sub +Function toString name?(parameter definitions parameter definitions?) As String Type? 15 Return $"an Apple at {Me.location}"value or expression?16 End Function End Class
public class Global {
+class Apple Name? inheritance? {1 +public Apple(parameter definitions parameter definitions?) { 2 this.location variableName? = new Square(0, 0)value or expression?; // reassign variable 3 } // constructor public Square Type? location name?; // property 4 +public void newRandomPosition name?(Snake snake parameter definitions?) { // procedure method 5 var changePosition name? = true value or expression?;6 +while (changePosition condition?) { 7 var ranX name? = randint(0, 39)value or expression?;8 var ranY name? = randint(0, 29)value or expression?;9 this.location variableName? = new Square(ranX, ranY)value or expression?; // reassign variable 10 +if (!snake.bodyCovers(this.location)condition?) { 11 changePosition variableName? = false value or expression?; // reassign variable 12 } // if } // while } // procedure method +public void updateBlocks name?(List<List<int>> blocks parameter definitions?) { // procedure method 13 blocks[this.location.x][this.location.y]variableName? = red value or expression?; // reassign variable 14 } // procedure method +public String Type? toString name?(parameter definitions parameter definitions?) { // function method 15 return String.format("an Apple at %", this.location)value or expression?;16 } // function method } // class
}

From the Blackjack demo:

+class Card Name? inheritance?1 property suit name? as Suit Type?2 property rank name? as String Type?3 property faceDown name? as Boolean Type?4 +constructor(rank as String, suit as Suit, facedown as Boolean parameter definitions?) 5 reassign this.rank variableName? to rank value or expression?6 reassign this.suit variableName? to suit value or expression?7 reassign this.faceDown variableName? to facedown value or expression?8 end constructor +procedure turnFaceUp name?(parameter definitions parameter definitions?) 9 reassign this.faceDown variableName? to false value or expression?10 end procedure +procedure turnFaceDown name?(parameter definitions parameter definitions?) 11 reassign this.faceDown variableName? to true value or expression?12 end procedure +function toString name?(parameter definitions parameter definitions?) returns String Type? 13 return $"{this.rank}{symbolForSuit(this.suit)}"value or expression?14 end function end class
+class Card Name? inheritance? # concrete class 1 suit name?: Suit Type? # property 2 rank name?: str Type? # property 3 faceDown name?: bool Type? # property 4 +def __init__(self: Card, rank: str, suit: Suit, facedown: bool parameter definitions?) -> None: 5 self.rank variableName? = rank value or expression? # reassign variable 6 self.suit variableName? = suit value or expression? # reassign variable 7 self.faceDown variableName? = facedown value or expression? # reassign variable 8 +def turnFaceUp name?(self: Card) -> None: # procedure method 9 self.faceDown variableName? = False value or expression? # reassign variable 10 +def turnFaceDown name?(self: Card) -> None: # procedure method 11 self.faceDown variableName? = True value or expression? # reassign variable 12 +def toString name?(self: Card) -> str Type?: # function method 13 return f"{self.rank}{symbolForSuit(self.suit)}"value or expression?14
+class Card Name? inheritance? {1 public Suit Type? suit name? {get; private set;} // property 2 public string Type? rank name? {get; private set;} // property 3 public bool Type? faceDown name? {get; private set;} // property 4 +public Card(string rank, Suit suit, bool facedown parameter definitions?) { 5 this.rank variableName? = rank value or expression?; // reassign variable 6 this.suit variableName? = suit value or expression?; // reassign variable 7 this.faceDown variableName? = facedown value or expression?; // reassign variable 8 } // constructor +public void turnFaceUp name?(parameter definitions parameter definitions?) { // procedure method 9 this.faceDown variableName? = false value or expression?; // reassign variable 10 } // procedure method +public void turnFaceDown name?(parameter definitions parameter definitions?) { // procedure method 11 this.faceDown variableName? = true value or expression?; // reassign variable 12 } // procedure method +public string Type? toString name?(parameter definitions parameter definitions?) { // function method 13 return $"{this.rank}{symbolForSuit(this.suit)}"value or expression?;14 } // function method } // class
+Class Card Name? inheritance?1 Property suit name? As Suit Type?2 Property rank name? As String Type?3 Property faceDown name? As Boolean Type?4 +Sub New(rank As String, suit As Suit, facedown As Boolean parameter definitions?) 5 Me.rank variableName? = rank value or expression? ' reassign variable 6 Me.suit variableName? = suit value or expression? ' reassign variable 7 Me.faceDown variableName? = facedown value or expression? ' reassign variable 8 End Sub +Sub turnFaceUp name?(parameter definitions parameter definitions?) ' procedure method 9 Me.faceDown variableName? = False value or expression? ' reassign variable 10 End Sub +Sub turnFaceDown name?(parameter definitions parameter definitions?) ' procedure method 11 Me.faceDown variableName? = True value or expression? ' reassign variable 12 End Sub +Function toString name?(parameter definitions parameter definitions?) As String Type? 13 Return $"{Me.rank}{symbolForSuit(Me.suit)}"value or expression?14 End Function End Class
public class Global {
+class Card Name? inheritance? {1 public Suit Type? suit name?; // property 2 public String Type? rank name?; // property 3 public bool Type? faceDown name?; // property 4 +public Card(String rank, Suit suit, bool facedown parameter definitions?) { 5 this.rank variableName? = rank value or expression?; // reassign variable 6 this.suit variableName? = suit value or expression?; // reassign variable 7 this.faceDown variableName? = facedown value or expression?; // reassign variable 8 } // constructor +public void turnFaceUp name?(parameter definitions parameter definitions?) { // procedure method 9 this.faceDown variableName? = false value or expression?; // reassign variable 10 } // procedure method +public void turnFaceDown name?(parameter definitions parameter definitions?) { // procedure method 11 this.faceDown variableName? = true value or expression?; // reassign variable 12 } // procedure method +public String Type? toString name?(parameter definitions parameter definitions?) { // function method 13 return String.format("%%", this.rank, symbolForSuit(this.suit))value or expression?;14 } // function method } // class
}

From the Pathfinder demo:

+class Point Name? inheritance?1 property x name? as Int Type?2 property y name? as Int Type?3 property isEmpty name? as Boolean Type?4 +constructor(x as Int, y as Int parameter definitions?) 5 +if (x < 0) or (y < 0)condition? then 6 reassign this.isEmpty variableName? to true value or expression?7 else 8 reassign this.x variableName? to x value or expression?9 reassign this.y variableName? to y value or expression?10 end if end constructor +function minDistTo name?(p as Point parameter definitions?) returns Float Type? 11 return sqrt(pow((p.x - this.x), 2) + pow((p.y - this.y), 2))value or expression?12 end function +function isAdjacentTo name?(p as Point parameter definitions?) returns Boolean Type? 13 return (this.minDistTo(p) is 1) or (this.minDistTo(p).round(4) is sqrt(2).round(4))value or expression?14 end function # Returns the 8 theoretically-neighbouring points, whether or not within bounds comment? +function neighbouringPoints name?(parameter definitions parameter definitions?) returns List<of Point>Type? 15 return [new Point(this.x - 1, this.y - 1), new Point(this.x, this.y - 1), new Point(this.x + 1, this.y - 1), new Point(this.x - 1, this.y), new Point(this.x + 1, this.y), new Point(this.x - 1, this.y + 1), new Point(this.x, this.y + 1), new Point(this.x + 1, this.y + 1)]value or expression?16 end function +function toString name?(parameter definitions parameter definitions?) returns String Type? 17 return $"{this.x},{this.y}"value or expression?18 end function end class
+class Point Name? inheritance? # concrete class 1 x name?: int Type? # property 2 y name?: int Type? # property 3 isEmpty name?: bool Type? # property 4 +def __init__(self: Point, x: int, y: int parameter definitions?) -> None: 5 +if (x < 0) or (y < 0)condition?: 6 self.isEmpty variableName? = True value or expression? # reassign variable 7 else:8 self.x variableName? = x value or expression? # reassign variable 9 self.y variableName? = y value or expression? # reassign variable 10 +def minDistTo name?(self: Point, p: Point parameter definitions?) -> float Type?: # function method 11 return sqrt(pow((p.x - self.x), 2) + pow((p.y - self.y), 2))value or expression?12 +def isAdjacentTo name?(self: Point, p: Point parameter definitions?) -> bool Type?: # function method 13 return (self.minDistTo(p) == 1) or (self.minDistTo(p).round(4) == sqrt(2).round(4))value or expression?14 # Returns the 8 theoretically-neighbouring points, whether or not within bounds comment? +def neighbouringPoints name?(self: Point) -> list[Point]Type?: # function method 15 return [Point(self.x - 1, self.y - 1), Point(self.x, self.y - 1), Point(self.x + 1, self.y - 1), Point(self.x - 1, self.y), Point(self.x + 1, self.y), Point(self.x - 1, self.y + 1), Point(self.x, self.y + 1), Point(self.x + 1, self.y + 1)]value or expression?16 +def toString name?(self: Point) -> str Type?: # function method 17 return f"{self.x},{self.y}"value or expression?18
+class Point Name? inheritance? {1 public int Type? x name? {get; private set;} // property 2 public int Type? y name? {get; private set;} // property 3 public bool Type? isEmpty name? {get; private set;} // property 4 +public Point(int x, int y parameter definitions?) { 5 +if ((x < 0) || (y < 0)condition?) { 6 this.isEmpty variableName? = true value or expression?; // reassign variable 7 } else {8 this.x variableName? = x value or expression?; // reassign variable 9 this.y variableName? = y value or expression?; // reassign variable 10 } // if } // constructor +public double Type? minDistTo name?(Point p parameter definitions?) { // function method 11 return sqrt(pow((p.x - this.x), 2) + pow((p.y - this.y), 2))value or expression?;12 } // function method +public bool Type? isAdjacentTo name?(Point p parameter definitions?) { // function method 13 return (this.minDistTo(p) == 1) || (this.minDistTo(p).round(4) == sqrt(2).round(4))value or expression?;14 } // function method // Returns the 8 theoretically-neighbouring points, whether or not within bounds comment? +public List<Point>Type? neighbouringPoints name?(parameter definitions parameter definitions?) { // function method 15 return [new Point(this.x - 1, this.y - 1), new Point(this.x, this.y - 1), new Point(this.x + 1, this.y - 1), new Point(this.x - 1, this.y), new Point(this.x + 1, this.y), new Point(this.x - 1, this.y + 1), new Point(this.x, this.y + 1), new Point(this.x + 1, this.y + 1)]value or expression?;16 } // function method +public string Type? toString name?(parameter definitions parameter definitions?) { // function method 17 return $"{this.x},{this.y}"value or expression?;18 } // function method } // class
+Class Point Name? inheritance?1 Property x name? As Integer Type?2 Property y name? As Integer Type?3 Property isEmpty name? As Boolean Type?4 +Sub New(x As Integer, y As Integer parameter definitions?) 5 +If (x < 0) Or (y < 0)condition? Then 6 Me.isEmpty variableName? = True value or expression? ' reassign variable 7 Else 8 Me.x variableName? = x value or expression? ' reassign variable 9 Me.y variableName? = y value or expression? ' reassign variable 10 End If End Sub +Function minDistTo name?(p As Point parameter definitions?) As Double Type? 11 Return sqrt(pow((p.x - Me.x), 2) + pow((p.y - Me.y), 2))value or expression?12 End Function +Function isAdjacentTo name?(p As Point parameter definitions?) As Boolean Type? 13 Return (Me.minDistTo(p) = 1) Or (Me.minDistTo(p).round(4) = sqrt(2).round(4))value or expression?14 End Function ' Returns the 8 theoretically-neighbouring points, whether or not within bounds comment? +Function neighbouringPoints name?(parameter definitions parameter definitions?) As List(Of Point)Type? 15 Return {New Point(Me.x - 1, Me.y - 1), New Point(Me.x, Me.y - 1), New Point(Me.x + 1, Me.y - 1), New Point(Me.x - 1, Me.y), New Point(Me.x + 1, Me.y), New Point(Me.x - 1, Me.y + 1), New Point(Me.x, Me.y + 1), New Point(Me.x + 1, Me.y + 1)}value or expression?16 End Function +Function toString name?(parameter definitions parameter definitions?) As String Type? 17 Return $"{Me.x},{Me.y}"value or expression?18 End Function End Class
public class Global {
+class Point Name? inheritance? {1 public int Type? x name?; // property 2 public int Type? y name?; // property 3 public bool Type? isEmpty name?; // property 4 +public Point(int x, int y parameter definitions?) { 5 +if ((x < 0) || (y < 0)condition?) { 6 this.isEmpty variableName? = true value or expression?; // reassign variable 7 } else {8 this.x variableName? = x value or expression?; // reassign variable 9 this.y variableName? = y value or expression?; // reassign variable 10 } // if } // constructor +public double Type? minDistTo name?(Point p parameter definitions?) { // function method 11 return sqrt(pow((p.x - this.x), 2) + pow((p.y - this.y), 2))value or expression?;12 } // function method +public bool Type? isAdjacentTo name?(Point p parameter definitions?) { // function method 13 return (this.minDistTo(p) == 1) || (this.minDistTo(p).round(4) == sqrt(2).round(4))value or expression?;14 } // function method // Returns the 8 theoretically-neighbouring points, whether or not within bounds comment? +public List<Point>Type? neighbouringPoints name?(parameter definitions parameter definitions?) { // function method 15 return [new Point(this.x - 1, this.y - 1), new Point(this.x, this.y - 1), new Point(this.x + 1, this.y - 1), new Point(this.x - 1, this.y), new Point(this.x + 1, this.y), new Point(this.x - 1, this.y + 1), new Point(this.x, this.y + 1), new Point(this.x + 1, this.y + 1)]value or expression?;16 } // function method +public String Type? toString name?(parameter definitions parameter definitions?) { // function method 17 return String.format("%,%", this.x, this.y)value or expression?;18 } // function method } // class
}

#### What you need to know about a concrete class

- A concrete class is a type of user-defined data-structure that holds data in properties, as well as methods to provide behaviour.
- A new class is defined by adding a concrete class instruction at global level, which requires a name (starting with an initial capital) to be specified
- All concrete classes must define a constructor, and a toString method, but the template for the class provides minimal valid implementations of these which you may expand or modify.
- You create an instance of the class using the class name and providing any require arguments (as specified by the class' constructor) for example: `variable applename? set to new Apple()value or expression?0applename? = Apple()value or expression? # variable definition0var applename? = new Apple()value or expression?;0Dim applename? = New Apple()value or expression? ' variable definition0var applename? = new Apple()value or expression?;0` or `variable startname? set to new Point(5, 5)value or expression?0startname? = Point(5, 5)value or expression? # variable definition0var startname? = new Point(5, 5)value or expression?;0Dim startname? = New Point(5, 5)value or expression? ' variable definition0var startname? = new Point(5, 5)value or expression?;0`.
- All properties must be initialised within the constructor (except for numeric or Boolean properties which have the default value for their type until changed)
- Function methods provide information derived from the properties of the instance, and or from parameters provided to it.
- toString is an ordinary function method but with a specific name; it is called if an instance of the class is printed, or inserted into an interpolated string; typically toString will include one or more of the object's properties.
- Procedure methods make changes to the properties of the instance and/or depend on the system in some way.
- Any property or method may be made private (using an action on the context menu for the instruction), such that it may ony be accessed by code within the same class.
- Once you have an instance in a variable you can access its public methods using dot-syntax; however, properties may be only be read by external code - to modify properties from outside you need to go through a procedure method defined on that class.
- A class may optionally inherit from a single abstract class.

## Abstract class

#### Example of an abstract class

From the Blackjack demo, the abstract class `PlayerPlayerPlayerPlayerPlayer` - which is inherited by the concrete classes `HumanPlayerHumanPlayerHumanPlayerHumanPlayerHumanPlayer` and Dealer - defines public concrete properties, public concrete methods, plus three abstract methods, two of which are accompanied by private 'helper' methods to which subclasses may delegate part or all of their implementations.

abstract class Player property name as String property points as Int property cards as List property handTotal as Int property softAce as Boolean property status as Status property hasTurn as Boolean procedure startTurn() if this.status is Status.active then reassign this.hasTurn to true end if end procedure procedure determineOutcomeAndUpdatePoints(dealer as Dealer) variable playerOutcome set to determinePlayerOutcome(dealer, this) if playerOutcome is Outcome.winDouble then call this.changePointsBy(2) call dealer.changePointsBy(-2) elif playerOutcome is Outcome.win then call this.changePointsBy(1) call dealer.changePointsBy(-1) elif playerOutcome is Outcome.lose then call this.changePointsBy(-1) call dealer.changePointsBy(1) end if end procedure procedure evaluateStatus(newCard as Card) if (this.cardCount() is 2) and (this.handTotal is 21) then reassign this.status to Status.blackjack elif (this.handTotal > 21) and (this.softAce) then reassign this.handTotal to this.handTotal - 10 reassign this.softAce to false elif this.handTotal > 21 then reassign this.status to Status.bust elif this.handTotal is 21 then reassign this.status to Status.standing end if if this.status isnt Status.active then reassign this.hasTurn to false end if end procedure procedure stand() reassign this.status to Status.standing reassign this.hasTurn to false end procedure procedure draw() variable newCard set to dealCard(random()) variable cards set to this.cards call cards.append(newCard) if newCard.rank.equals("A") then call this.addAce() else reassign this.handTotal to this.handTotal + rankValue()[newCard.rank] end if call this.evaluateStatus(newCard) end procedure procedure addAce() if this.softAce then reassign this.handTotal to this.handTotal + 1 else reassign this.handTotal to this.handTotal + 11 reassign this.softAce to true end if end procedure function cardCount() returns Int return this.cards.length() end function procedure changePointsBy(amount as Int) reassign this.points to this.points + amount end procedure abstract procedure newHand() private procedure newHandHelper() reassign this.hasTurn to false reassign this.softAce to false reassign this.cards to new List
abstract class Player property name as String property points as Int property cards as List property handTotal as Int property softAce as Boolean property status as Status property hasTurn as Boolean procedure startTurn() if this.status is Status.active then reassign this.hasTurn to true end if end procedure procedure determineOutcomeAndUpdatePoints(dealer as Dealer) variable playerOutcome set to determinePlayerOutcome(dealer, this) if playerOutcome is Outcome.winDouble then call this.changePointsBy(2) call dealer.changePointsBy(-2) elif playerOutcome is Outcome.win then call this.changePointsBy(1) call dealer.changePointsBy(-1) elif playerOutcome is Outcome.lose then call this.changePointsBy(-1) call dealer.changePointsBy(1) end if end procedure procedure evaluateStatus(newCard as Card) if (this.cardCount() is 2) and (this.handTotal is 21) then reassign this.status to Status.blackjack elif (this.handTotal > 21) and (this.softAce) then reassign this.handTotal to this.handTotal - 10 reassign this.softAce to false elif this.handTotal > 21 then reassign this.status to Status.bust elif this.handTotal is 21 then reassign this.status to Status.standing end if if this.status isnt Status.active then reassign this.hasTurn to false end if end procedure procedure stand() reassign this.status to Status.standing reassign this.hasTurn to false end procedure procedure draw() variable newCard set to dealCard(random()) variable cards set to this.cards call cards.append(newCard) if newCard.rank.equals("A") then call this.addAce() else reassign this.handTotal to this.handTotal + rankValue()[newCard.rank] end if call this.evaluateStatus(newCard) end procedure procedure addAce() if this.softAce then reassign this.handTotal to this.handTotal + 1 else reassign this.handTotal to this.handTotal + 11 reassign this.softAce to true end if end procedure function cardCount() returns Int return this.cards.length() end function procedure changePointsBy(amount as Int) reassign this.points to this.points + amount end procedure abstract procedure newHand() private procedure newHandHelper() reassign this.hasTurn to false reassign this.softAce to false reassign this.cards to new List
abstract class Player property name as String property points as Int property cards as List property handTotal as Int property softAce as Boolean property status as Status property hasTurn as Boolean procedure startTurn() if this.status is Status.active then reassign this.hasTurn to true end if end procedure procedure determineOutcomeAndUpdatePoints(dealer as Dealer) variable playerOutcome set to determinePlayerOutcome(dealer, this) if playerOutcome is Outcome.winDouble then call this.changePointsBy(2) call dealer.changePointsBy(-2) elif playerOutcome is Outcome.win then call this.changePointsBy(1) call dealer.changePointsBy(-1) elif playerOutcome is Outcome.lose then call this.changePointsBy(-1) call dealer.changePointsBy(1) end if end procedure procedure evaluateStatus(newCard as Card) if (this.cardCount() is 2) and (this.handTotal is 21) then reassign this.status to Status.blackjack elif (this.handTotal > 21) and (this.softAce) then reassign this.handTotal to this.handTotal - 10 reassign this.softAce to false elif this.handTotal > 21 then reassign this.status to Status.bust elif this.handTotal is 21 then reassign this.status to Status.standing end if if this.status isnt Status.active then reassign this.hasTurn to false end if end procedure procedure stand() reassign this.status to Status.standing reassign this.hasTurn to false end procedure procedure draw() variable newCard set to dealCard(random()) variable cards set to this.cards call cards.append(newCard) if newCard.rank.equals("A") then call this.addAce() else reassign this.handTotal to this.handTotal + rankValue()[newCard.rank] end if call this.evaluateStatus(newCard) end procedure procedure addAce() if this.softAce then reassign this.handTotal to this.handTotal + 1 else reassign this.handTotal to this.handTotal + 11 reassign this.softAce to true end if end procedure function cardCount() returns Int return this.cards.length() end function procedure changePointsBy(amount as Int) reassign this.points to this.points + amount end procedure abstract procedure newHand() private procedure newHandHelper() reassign this.hasTurn to false reassign this.softAce to false reassign this.cards to new List
abstract class Player property name as String property points as Int property cards as List property handTotal as Int property softAce as Boolean property status as Status property hasTurn as Boolean procedure startTurn() if this.status is Status.active then reassign this.hasTurn to true end if end procedure procedure determineOutcomeAndUpdatePoints(dealer as Dealer) variable playerOutcome set to determinePlayerOutcome(dealer, this) if playerOutcome is Outcome.winDouble then call this.changePointsBy(2) call dealer.changePointsBy(-2) elif playerOutcome is Outcome.win then call this.changePointsBy(1) call dealer.changePointsBy(-1) elif playerOutcome is Outcome.lose then call this.changePointsBy(-1) call dealer.changePointsBy(1) end if end procedure procedure evaluateStatus(newCard as Card) if (this.cardCount() is 2) and (this.handTotal is 21) then reassign this.status to Status.blackjack elif (this.handTotal > 21) and (this.softAce) then reassign this.handTotal to this.handTotal - 10 reassign this.softAce to false elif this.handTotal > 21 then reassign this.status to Status.bust elif this.handTotal is 21 then reassign this.status to Status.standing end if if this.status isnt Status.active then reassign this.hasTurn to false end if end procedure procedure stand() reassign this.status to Status.standing reassign this.hasTurn to false end procedure procedure draw() variable newCard set to dealCard(random()) variable cards set to this.cards call cards.append(newCard) if newCard.rank.equals("A") then call this.addAce() else reassign this.handTotal to this.handTotal + rankValue()[newCard.rank] end if call this.evaluateStatus(newCard) end procedure procedure addAce() if this.softAce then reassign this.handTotal to this.handTotal + 1 else reassign this.handTotal to this.handTotal + 11 reassign this.softAce to true end if end procedure function cardCount() returns Int return this.cards.length() end function procedure changePointsBy(amount as Int) reassign this.points to this.points + amount end procedure abstract procedure newHand() private procedure newHandHelper() reassign this.hasTurn to false reassign this.softAce to false reassign this.cards to new List
abstract class Player property name as String property points as Int property cards as List property handTotal as Int property softAce as Boolean property status as Status property hasTurn as Boolean procedure startTurn() if this.status is Status.active then reassign this.hasTurn to true end if end procedure procedure determineOutcomeAndUpdatePoints(dealer as Dealer) variable playerOutcome set to determinePlayerOutcome(dealer, this) if playerOutcome is Outcome.winDouble then call this.changePointsBy(2) call dealer.changePointsBy(-2) elif playerOutcome is Outcome.win then call this.changePointsBy(1) call dealer.changePointsBy(-1) elif playerOutcome is Outcome.lose then call this.changePointsBy(-1) call dealer.changePointsBy(1) end if end procedure procedure evaluateStatus(newCard as Card) if (this.cardCount() is 2) and (this.handTotal is 21) then reassign this.status to Status.blackjack elif (this.handTotal > 21) and (this.softAce) then reassign this.handTotal to this.handTotal - 10 reassign this.softAce to false elif this.handTotal > 21 then reassign this.status to Status.bust elif this.handTotal is 21 then reassign this.status to Status.standing end if if this.status isnt Status.active then reassign this.hasTurn to false end if end procedure procedure stand() reassign this.status to Status.standing reassign this.hasTurn to false end procedure procedure draw() variable newCard set to dealCard(random()) variable cards set to this.cards call cards.append(newCard) if newCard.rank.equals("A") then call this.addAce() else reassign this.handTotal to this.handTotal + rankValue()[newCard.rank] end if call this.evaluateStatus(newCard) end procedure procedure addAce() if this.softAce then reassign this.handTotal to this.handTotal + 1 else reassign this.handTotal to this.handTotal + 11 reassign this.softAce to true end if end procedure function cardCount() returns Int return this.cards.length() end function procedure changePointsBy(amount as Int) reassign this.points to this.points + amount end procedure abstract procedure newHand() private procedure newHandHelper() reassign this.hasTurn to false reassign this.softAce to false reassign this.cards to new List

#### What you need to know about as abstract class

- An abstract class is like a concrete class except that:
  - It may not be instantiated directly, and hence has no constructor.
  - A concrete class may inherit from it; this is specified in the concrete class, by entering the name of the desired abstract 'superclass' in the the field labelled inheritance. Note that when this has been entered the editor will add the syntax for inheritance appropriate to the language being used.
  - It may define concrete members (as found on concrete classes) and/or abstract members.
  - Any concrete class that inherits from an abstract class, must provide concrete implementations of all abstract members defined on its immediate superclass, and on any abstract classes defined in its hierarchy.
- An abstract class must be declared in the code above any class that inherits from it.
- Inheritance hierarchies must form a tree, that is you must avoid creating a circular dependency where, for example, type A inherits from type B, which inherits from type `CCCCC`, which inherits from type `AAAAA`.

#### More advanced techniques

#### Delegation

If you want sub-classes to be able to define their own implementation of a common method, then that method should be made abstract. If it turns out that several of the sub-classes need the same, or very similar, implementations (and duplication of code is always to be avoided, according to the DRY principle - Don't Repeat Yourself) then you use the pattern of 'delegation'. This means defining the method as abstract, but also providing a private implementation (or part-implementation) with a slightly different name, which sub-classes may call from their own implementations. You can see an example of this in the Blackjack demo:

- The abstract class named `PlayerPlayerPlayerPlayerPlayer` defines `abstract procedure newHand() Code does not parse as Elan.abstract procedure newHand() Code does not parse as Elan.abstract procedure newHand() Code does not parse as Elan.abstract procedure newHand() Code does not parse as Elan.abstract procedure newHand() Code does not parse as Elan.`.
- It also defines a concrete procedure method named `newHandHelpernewHandHelpernewHandHelpernewHandHelpernewHandHelper`.
- The subclass `HumanPlayerHumanPlayerHumanPlayerHumanPlayerHumanPlayer` defines its implementation of newHand as just `call this.newHandHelperprocedureName?(arguments?)0self.newHandHelperprocedureName?(arguments?) # call procedure0this.newHandHelperprocedureName?(arguments?); // call procedure0Me.newHandHelperprocedureName?(arguments?) ' call procedure0this.newHandHelperprocedureName?(arguments?); // call procedure0`.
- The subclass `DealerDealerDealerDealerDealer` defines a more complex implementation of newHand with five instructions, but these include `call this.newHandHelperprocedureName?(arguments?)0self.newHandHelperprocedureName?(arguments?) # call procedure0this.newHandHelperprocedureName?(arguments?); // call procedure0Me.newHandHelperprocedureName?(arguments?) ' call procedure0this.newHandHelperprocedureName?(arguments?); // call procedure0` to do the common part of the task.

# Statement Instructions

Coding with Elan using the object-oriented profile offers the same statement instructions used in the procedural profile.

# Member instructions

Member instructions (also referred to simply as 'members') may be added only with a concrete class or abstract class. Hence, these method instructions may be created only when the profile is set to object-oriented (or functional - which includes all OOP capabilities).

## Constructor

#### Examples of constructors

From the Snake - object-oriented demo, where the `SquareSquareSquareSquareSquare` class defines this constructor:

+class Square Name? inheritance?1 +constructor(x as Int, y as Int parameter definitions?) 2 reassign this.x variableName? to x value or expression?3 reassign this.y variableName? to y value or expression?4 end constructor +function toString name?(parameter definitions?) returns String Type? 5 return "undefined"value or expression?6 end function end class
+class Square Name? inheritance? # concrete class 1 +def __init__(self: Square, x: int, y: int parameter definitions?) -> None: 2 self.x variableName? = x value or expression? # reassign variable 3 self.y variableName? = y value or expression? # reassign variable 4 +def toString name?(self: Square) -> str Type?: # function method 5 return "undefined"value or expression?6
+class Square Name? inheritance? {1 +public Square(int x, int y parameter definitions?) { 2 this.x variableName? = x value or expression?; // reassign variable 3 this.y variableName? = y value or expression?; // reassign variable 4 } // constructor +public string Type? toString name?(parameter definitions?) { // function method 5 return "undefined"value or expression?;6 } // function method } // class
+Class Square Name? inheritance?1 +Sub New(x As Integer, y As Integer parameter definitions?) 2 Me.x variableName? = x value or expression? ' reassign variable 3 Me.y variableName? = y value or expression? ' reassign variable 4 End Sub +Function toString name?(parameter definitions?) As String Type? 5 Return "undefined"value or expression?6 End Function End Class
public class Global {
+class Square Name? inheritance? {1 +public Square(int x, int y parameter definitions?) { 2 this.x variableName? = x value or expression?; // reassign variable 3 this.y variableName? = y value or expression?; // reassign variable 4 } // constructor +public String Type? toString name?(parameter definitions?) { // function method 5 return "undefined"value or expression?;6 } // function method } // class
}

which requires the programmer to provide values for parameters `xxxxx` and `yyyyy` when instantiating a `SquareSquareSquareSquareSquare`, and assigns these parameters to the corresponding properties of the object.

From the Blackjack demo, where the `GameGameGameGameGame` class defines this constructor:

constructor(dealerStartPoints as Int) reassign this.dealer to new Dealer(dealerStartPoints) reassign this.players to new List() reassign this.message to "" end constructor Code does not parse as Elan.
constructor(dealerStartPoints as Int) reassign this.dealer to new Dealer(dealerStartPoints) reassign this.players to new List() reassign this.message to "" end constructor Code does not parse as Elan.
constructor(dealerStartPoints as Int) reassign this.dealer to new Dealer(dealerStartPoints) reassign this.players to new List() reassign this.message to "" end constructor Code does not parse as Elan.
constructor(dealerStartPoints as Int) reassign this.dealer to new Dealer(dealerStartPoints) reassign this.players to new List() reassign this.message to "" end constructor Code does not parse as Elan.
constructor(dealerStartPoints as Int) reassign this.dealer to new Dealer(dealerStartPoints) reassign this.players to new List() reassign this.message to "" end constructor Code does not parse as Elan.

Note that the single parameter defined in the instructor does not correspond directly to the any property defined on `GameGameGameGameGame`, but is used to create a new instance of `DealerDealerDealerDealerDealer` for its own `dealerdealerdealerdealerdealer` (association) property. Its `playerplayerplayerplayerplayer` property is a 'multiple association' and is initialised to a new (empty) list of type `PlayerPlayerPlayerPlayerPlayer`.

#### What you need to know about a constructors

- A concrete class must have a constructor - so when a new concrete class is created, it includes a minimal default implementation.
- The purpose of the constructor is to initialise all properties (except, optionally, for properties of numeric or Boolean types - if you are happy for them to take the default values for those types).
<
- A property is initialised using a reassign instruction, prefixing the name of the propery as in this example: `reassign this.xvariableName? to xvalue or expression?0self.xvariableName? = xvalue or expression? # reassign variable0this.xvariableName? = xvalue or expression?; // reassign variable0Me.xvariableName? = xvalue or expression? ' reassign variable0this.xvariableName? = xvalue or expression?; // reassign variable0` - the prefix means that you can have a parameter with the same name, with no risk of ambiguity.

- The constructor may make use of the object's function methods and/or global methods to calculate values to be assigned to its properties.
- However, a constructor may not call any procedure - internal or external - because constructing a new instance should have no side-effects.

## Property

#### Examples of properties

From the Snake - object-oriented demo, where the `GameGameGameGameGame` class defines these properties:

+constructor(parameter definitions?) 0 new code end constructor
property dealer as Dealer Code does not parse as Elan.
property dealer as Dealer Code does not parse as Elan.
+Sub New(parameter definitions?) 0 new code End Sub
property dealer as Dealer Code does not parse as Elan.
property players as List&let;of Player> Code does not parse as Elan.
property players as List&let;of Player> Code does not parse as Elan.
property players as List&let;of Player> Code does not parse as Elan.
property players as List&let;of Player> Code does not parse as Elan.
property players as List&let;of Player> Code does not parse as Elan.
+constructor(parameter definitions?) 0 new code end constructor
property message as String Code does not parse as Elan.
property message as String Code does not parse as Elan.
+Sub New(parameter definitions?) 0 new code End Sub
property message as String Code does not parse as Elan.

#### What you need to know about properties

- A property is a named value defined on a concrete or abstract class with a name conforming to the standard rules for an identifier.
- The type of a property, unlike a variable, is explicitly defined, as shown in the examples above. It may be a standard library type (including data structures), or the name of another used-defined class, or a data structure of another class type (see examples above).
- Every property must be initialsed within a constructor unless it is of a numeric or Boolean type - which have default values.
- A property is public by default, but may be specified as private (visible only to code inside the class) though the make private action on the context menu (or reverted to public with make public.
- The public properties of an instance may be read by code outside the class using dot-syntax, but may only be modified (from outside) via an appropriate procedure method.

#### More advanced techniques

### Optional ('Maybe') associations

When a class property is optional, it is defined with the type `MaybeMaybeMaybeMaybeMaybe`.

Before reading the property's value, you must test if it has a value with function hasValue which returns a `BooleanboolboolBooleanbool`. If `trueTruetrueTruetrue` is returned, then you retrieve the value with function getValue; if `falseFalsefalseFalsefalse` is returned, then it has no current value, and using getValue will give a runtime error.

To update the property's value, use function setValue. To restore it to having no value, use function clearValue.

Here a pupil (of class Pupil) that optionally has a tutor (of class Teacher):

+main 1 variable tTom name? set to new Teacher()value or expression?2 variable pPete name? set to new Pupil()value or expression?3 +if pPete.tutor.hasValue()condition? then 4 print(pPete.tutor arguments?)5 end if print(p arguments?)6 end main +class Teacher Name? inheritance?7 +constructor(parameter definitions parameter definitions?) 8 new code end constructor +function toString name?(parameter definitions parameter definitions?) returns String Type? 9 return "a Teacher"value or expression?10 end function end class +class Pupil Name? inheritance?11 +constructor(parameter definitions parameter definitions?) 12 reassign this.tutor variableName? to new Maybe<of Teacher>()value or expression?13 end constructor property tutor name? as Maybe<of Teacher>Type?14 +function toString name?(parameter definitions parameter definitions?) returns String Type? 15 return "a Pupil"value or expression?16 end function end class
+def main() -> None: 1 tTom name? = Teacher()value or expression? # variable definition 2 pPete name? = Pupil()value or expression? # variable definition 3 +if pPete.tutor.hasValue()condition?: 4 print(pPete.tutor arguments?)5 print(p arguments?)6 +class Teacher Name? inheritance? # concrete class 7 +def __init__(self: Teacher) -> None: 8 new code +def toString name?(self: Teacher) -> str Type?: # function method 9 return "a Teacher"value or expression?10 +class Pupil Name? inheritance? # concrete class 11 +def __init__(self: Pupil) -> None: 12 self.tutor variableName? = Maybe[Teacher]()value or expression? # reassign variable 13 tutor name?: Maybe[Teacher]Type? # property 14 +def toString name?(self: Pupil) -> str Type?: # function method 15 return "a Pupil"value or expression?16 main()
+static void main() { 1 var tTom name? = new Teacher()value or expression?;2 var pPete name? = new Pupil()value or expression?;3 +if (pPete.tutor.hasValue()condition?) { 4 Console.WriteLine(pPete.tutor arguments?); // print 5 } // if Console.WriteLine(p arguments?); // print 6 } // main +class Teacher Name? inheritance? {7 +public Teacher(parameter definitions parameter definitions?) { 8 new code } // constructor +public string Type? toString name?(parameter definitions parameter definitions?) { // function method 9 return "a Teacher"value or expression?;10 } // function method } // class +class Pupil Name? inheritance? {11 +public Pupil(parameter definitions parameter definitions?) { 12 this.tutor variableName? = new Maybe<Teacher>()value or expression?; // reassign variable 13 } // constructor public Maybe<Teacher>Type? tutor name? {get; private set;} // property 14 +public string Type? toString name?(parameter definitions parameter definitions?) { // function method 15 return "a Pupil"value or expression?;16 } // function method } // class
+Sub main() 1 Dim tTom name? = New Teacher()value or expression? ' variable definition 2 Dim pPete name? = New Pupil()value or expression? ' variable definition 3 +If pPete.tutor.hasValue()condition? Then 4 Console.WriteLine(pPete.tutor arguments?) ' print 5 End If Console.WriteLine(p arguments?) ' print 6 End Sub +Class Teacher Name? inheritance?7 +Sub New(parameter definitions parameter definitions?) 8 new code End Sub +Function toString name?(parameter definitions parameter definitions?) As String Type? 9 Return "a Teacher"value or expression?10 End Function End Class +Class Pupil Name? inheritance?11 +Sub New(parameter definitions parameter definitions?) 12 Me.tutor variableName? = New Maybe(Of Teacher)()value or expression? ' reassign variable 13 End Sub Property tutor name? As Maybe(Of Teacher)Type?14 +Function toString name?(parameter definitions parameter definitions?) As String Type? 15 Return "a Pupil"value or expression?16 End Function End Class
public class Global {
+static void main() { 1 var tTom name? = new Teacher()value or expression?;2 var pPete name? = new Pupil()value or expression?;3 +if (pPete.tutor.hasValue()condition?) { 4 System.out.println(pPete.tutor arguments?); // print 5 } // if System.out.println(p arguments?); // print 6 } // main +class Teacher Name? inheritance? {7 +public Teacher(parameter definitions parameter definitions?) { 8 new code } // constructor +public String Type? toString name?(parameter definitions parameter definitions?) { // function method 9 return "a Teacher"value or expression?;10 } // function method } // class +class Pupil Name? inheritance? {11 +public Pupil(parameter definitions parameter definitions?) { 12 this.tutor variableName? = new Maybe<Teacher>()value or expression?; // reassign variable 13 } // constructor public Maybe<Teacher>Type? tutor name?; // property 14 +public String Type? toString name?(parameter definitions parameter definitions?) { // function method 15 return "a Pupil"value or expression?;16 } // function method } // class
}

## Function method

#### Examples of function methods

From the Roman Numerals Turing Machine demo, where the `Turing Machine Code does not parse as Elan.Turing Machine Code does not parse as Elan.Turing Machine Code does not parse as Elan.Turing Machine Code does not parse as Elan.Turing Machine Code does not parse as Elan.` class defines these two function methods:

+function isHalted name?(parameter definitions parameter definitions?) returns Boolean Type? 1 return this.currentState.equals(this.haltState)value or expression?2 end function +function findMatchingRule name?(parameter definitions parameter definitions?) returns Rule Type? 3 variable matches name? set to this.rules.filter(lambda r as Rule => (r.currentState.equals(this.currentState)) and (r.currentSymbol.equals(this.tape[this.headPosition])))value or expression?4 +if matches.length() is 0 condition? then 5 throw ElanRuntimeError exception type? $"No rule matching state {this.currentState} and symbol {this.tape[this.headPosition]}"message?6 end if return matches.head()value or expression?7 end function
+def isHalted name?(parameter definitions parameter definitions?) -> bool Type?: # function 1 return self.currentState.equals(self.haltState)value or expression?2 +def findMatchingRule name?(parameter definitions parameter definitions?) -> Rule Type?: # function 3 matches name? = self.rules.filter(lambda r: Rule: (r.currentState.equals(self.currentState)) and (r.currentSymbol.equals(self.tape[self.headPosition])))value or expression? # variable definition 4 +if matches.length() == 0 condition?: 5 raise ElanRuntimeError exception type?(f"No rule matching state {self.currentState} and symbol {self.tape[self.headPosition]}"message?)6 return matches.head()value or expression?7
+static bool Type? isHalted name?(parameter definitions parameter definitions?) { // function 1 return this.currentState.equals(this.haltState)value or expression?;2 } // function +static Rule Type? findMatchingRule name?(parameter definitions parameter definitions?) { // function 3 var matches name? = this.rules.filter(Rule r => (r.currentState.equals(this.currentState)) && (r.currentSymbol.equals(this.tape[this.headPosition])))value or expression?;4 +if (matches.length() == 0 condition?) { 5 throw new ElanRuntimeError exception type?($"No rule matching state {this.currentState} and symbol {this.tape[this.headPosition]}"message?);6 } // if return matches.head()value or expression?;7 } // function
+Function isHalted name?(parameter definitions parameter definitions?) As Boolean Type? 1 Return Me.currentState.equals(Me.haltState)value or expression?2 End Function +Function findMatchingRule name?(parameter definitions parameter definitions?) As Rule Type? 3 Dim matches name? = Me.rules.filter(Function (r As Rule) (r.currentState.equals(Me.currentState)) And (r.currentSymbol.equals(Me.tape[Me.headPosition])))value or expression? ' variable definition 4 +If matches.length() = 0 condition? Then 5 Throw New ElanRuntimeError exception type?($"No rule matching state {Me.currentState} and symbol {Me.tape[Me.headPosition]}"message?)6 End If Return matches.head()value or expression?7 End Function
public class Global {
+static bool Type? isHalted name?(parameter definitions parameter definitions?) { // function 1 return this.currentState.equals(this.haltState)value or expression?;2 } // function +static Rule Type? findMatchingRule name?(parameter definitions parameter definitions?) { // function 3 var matches name? = this.rules.filter((Rule r) -> (r.currentState.equals(this.currentState)) && (r.currentSymbol.equals(this.tape[this.headPosition])))value or expression?;4 +if (matches.length() == 0 condition?) { 5 throw new ElanRuntimeError exception type?(String.format("No rule matching state % and symbol %", this.currentState, this.tape[this.headPosition])message?);6 } // if return matches.head()value or expression?;7 } // function
}

#### What you need to know about function methods

- A function method provides information based on the parameters specified in combination with the object's properties.
- A function method broadly follows the same rules as an ordinary (global) function - so it may not create any side effects nor.
- However, a function method may read, and hence depend upon, the properties of the object on which it is defined.
- A function method is public by default, but may be specified as private (visible only to code inside the class) though the make private action on the context menu (or reverted to public with make public).
- A function method may be called (within an expression) on an object in code outside the class using dot-syntax on the variable holding the instance.
- A function method may be invoked from within another method inside the class using, for example `this.methodName()self.methodName()this.methodName()Me.methodName()this.methodName()`.

## Procedure method

#### Examples of procedure methods

From the Roman Numerals Turing Machine demo, where the `Turing Machine Code does not parse as Elan.Turing Machine Code does not parse as Elan.Turing Machine Code does not parse as Elan.Turing Machine Code does not parse as Elan.Turing Machine Code does not parse as Elan.` defines these procedure methods (among others):

+procedure setTape name?(tape as String parameter definitions?) 1 reassign this.tape variableName? to tape value or expression?2 end procedure
+def setTape name?(tape: str parameter definitions?) -> None: # procedure 1 self.tape variableName? = tape value or expression? # reassign variable 2
+static void setTape name?(string tape parameter definitions?) { // procedure 1 this.tape variableName? = tape value or expression?; // reassign variable 2 } // procedure
+Sub setTape name?(tape As String parameter definitions?) ' procedure 1 Me.tape variableName? = tape value or expression? ' reassign variable 2 End Sub
public class Global {
+static void setTape name?(String tape parameter definitions?) { // procedure 1 this.tape variableName? = tape value or expression?; // reassign variable 2 } // procedure
}

This is the simplest form of a procedure method, which allows the `tapetapetapetapetape` property (a string) to be set to a new value by code outside the class.

+procedure singleStep name?(parameter definitions parameter definitions?) 1 variable rule name? set to this.findMatchingRule()value or expression?2 call this.execute procedureName?(rule arguments?)3 end procedure
+def singleStep name?(parameter definitions parameter definitions?) -> None: # procedure 1 rule name? = self.findMatchingRule()value or expression? # variable definition 2 self.execute procedureName?(rule arguments?) # call procedure 3
+static void singleStep name?(parameter definitions parameter definitions?) { // procedure 1 var rule name? = this.findMatchingRule()value or expression?;2 this.execute procedureName?(rule arguments?); // call procedure 3 } // procedure
+Sub singleStep name?(parameter definitions parameter definitions?) ' procedure 1 Dim rule name? = Me.findMatchingRule()value or expression? ' variable definition 2 Me.execute procedureName?(rule arguments?) ' call procedure 3 End Sub
public class Global {
+static void singleStep name?(parameter definitions parameter definitions?) { // procedure 1 var rule name? = this.findMatchingRule()value or expression?;2 this.execute procedureName?(rule arguments?); // call procedure 3 } // procedure
}

This method made use of a function method on the same class - findMatchingRule() - and then calls another procedure on the same instance - execute - passing it the found `rulerulerulerulerule`.

#### What you need to know about procedure methods

- A procedure method changes the state of the object, and/or interacts with the system
- A procedure method broadly follows the same rules as an ordinary (global) function - so it may not create any side effects nor.
- However, a procedure method may read, and hence depend upon, the properties of the object on which it is defined.
- A procedure method is public by default, but may be specified as private (visible only to code inside the class) though the make private action on the context menu (or reverted to public with make public).
- A procedure method may be called (using a call procedure instruction) on an object in code outside the class using dot-syntax on the variable holding the instance.
- A procedure method may be called from within another method inside the class using, for example `call this.methodNameprocedureName?(arguments?)0self.methodNameprocedureName?(arguments?) # call procedure0this.methodNameprocedureName?(arguments?); // call procedure0Me.methodNameprocedureName?(arguments?) ' call procedure0this.methodNameprocedureName?(arguments?); // call procedure0`.

## Abstract function

#### Examples of abstract functions

From the Blackjack demo, where the abstract class `PlayerPlayerPlayerPlayerPlayer` defines this abstract function:

abstract function getMessage() returns String Code does not parse as Elan.
abstract function getMessage() returns String Code does not parse as Elan.
abstract function getMessage() returns String Code does not parse as Elan.
abstract function getMessage() returns String Code does not parse as Elan.
abstract function getMessage() returns String Code does not parse as Elan.

which is implemented (as a concrete function method) by the subclasses, including on `DealerDealerDealerDealerDealer`:

+function getMessage name?(parameter definitions parameter definitions?) returns String Type? 1 variable msg name? set to ""value or expression?2 +if this.hasPlayed condition? then 3 reassign msg variableName? to this.getMessageHelper() + $" - hand total: {this.handTotal}"value or expression?4 end if return msg value or expression?5 end function
+def getMessage name?(parameter definitions parameter definitions?) -> str Type?: # function 1 msg name? = ""value or expression? # variable definition 2 +if self.hasPlayed condition?: 3 msg variableName? = self.getMessageHelper() + f" - hand total: {self.handTotal}"value or expression? # reassign variable 4 return msg value or expression?5
+static string Type? getMessage name?(parameter definitions parameter definitions?) { // function 1 var msg name? = ""value or expression?;2 +if (this.hasPlayed condition?) { 3 msg variableName? = this.getMessageHelper() + $" - hand total: {this.handTotal}"value or expression?; // reassign variable 4 } // if return msg value or expression?;5 } // function
+Function getMessage name?(parameter definitions parameter definitions?) As String Type? 1 Dim msg name? = ""value or expression? ' variable definition 2 +If Me.hasPlayed condition? Then 3 msg variableName? = Me.getMessageHelper() + $" - hand total: {Me.handTotal}"value or expression? ' reassign variable 4 End If Return msg value or expression?5 End Function
public class Global {
+static String Type? getMessage name?(parameter definitions parameter definitions?) { // function 1 var msg name? = ""value or expression?;2 +if (this.hasPlayed condition?) { 3 msg variableName? = this.getMessageHelper() + String.format(" - hand total: %", this.handTotal)value or expression?; // reassign variable 4 } // if return msg value or expression?;5 } // function
}

which makes use of a method getMessageHelper() that is defined as (private) concrete function method on the superclass (`PlayerPlayerPlayerPlayerPlayer`).

#### What you need to know about p abstract functions

- An abstract function method may be defined only on an abstract class .
- Any concrete subclass must then implement a concrete (regular) function to match.

## Abstract procedure

#### Examples of abstract procedure

From the Blackjack demo, where the abstract class `PlayerPlayerPlayerPlayerPlayer` defines this abstract function:

abstract procedure nextAction(dealerFaceCard as Card) Code does not parse as Elan.
abstract procedure nextAction(dealerFaceCard as Card) Code does not parse as Elan.
abstract procedure nextAction(dealerFaceCard as Card) Code does not parse as Elan.
abstract procedure nextAction(dealerFaceCard as Card) Code does not parse as Elan.
abstract procedure nextAction(dealerFaceCard as Card) Code does not parse as Elan.

which is implemented (as a concrete function method) by the subclass `DealerDealerDealerDealerDealer` using simple logic to implement the standard rules that a Blackjack dealer must always follow:

+procedure nextAction name?(faceCard as Card parameter definitions?) 1 +if this.handTotal < 17 condition? then 2 call this.draw procedureName?(arguments?)3 else 4 call this.stand procedureName?(arguments?)5 end if end procedure
+def nextAction name?(faceCard: Card parameter definitions?) -> None: # procedure 1 +if self.handTotal < 17 condition?: 2 self.draw procedureName?(arguments?) # call procedure 3 else:4 self.stand procedureName?(arguments?) # call procedure 5
+static void nextAction name?(Card faceCard parameter definitions?) { // procedure 1 +if (this.handTotal < 17 condition?) { 2 this.draw procedureName?(arguments?); // call procedure 3 } else {4 this.stand procedureName?(arguments?); // call procedure 5 } // if } // procedure
+Sub nextAction name?(faceCard As Card parameter definitions?) ' procedure 1 +If Me.handTotal < 17 condition? Then 2 Me.draw procedureName?(arguments?) ' call procedure 3 Else 4 Me.stand procedureName?(arguments?) ' call procedure 5 End If End Sub
public class Global {
+static void nextAction name?(Card faceCard parameter definitions?) { // procedure 1 +if (this.handTotal < 17 condition?) { 2 this.draw procedureName?(arguments?); // call procedure 3 } else {4 this.stand procedureName?(arguments?); // call procedure 5 } // if } // procedure
}

and on the subclass `HumanPlayerHumanPlayerHumanPlayerHumanPlayerHumanPlayer` by code that usesinput/output methods to obtain the next action from the user:

+procedure nextAction name?(dealerFaceCard as Card parameter definitions?) 1 variable key name? set to ""value or expression?2 call clearKeyBuffer procedureName?(?)3 +while key.equals("")condition? 4 reassign key variableName? to waitForKey()value or expression?5 +if key.equals("d")condition? then 6 call this.draw procedureName?(arguments?)7 elif key.equals("s")condition? then 8 call this.stand procedureName?(arguments?)9 else 10 reassign key variableName? to ""value or expression?11 end if end while end procedure
+def nextAction name?(dealerFaceCard: Card parameter definitions?) -> None: # procedure 1 key name? = ""value or expression? # variable definition 2 clearKeyBuffer procedureName?(?) # call procedure 3 +while key.equals("")condition?: 4 key variableName? = waitForKey()value or expression? # reassign variable 5 +if key.equals("d")condition?: 6 self.draw procedureName?(arguments?) # call procedure 7 elif key.equals("s")condition?: # else if 8 self.stand procedureName?(arguments?) # call procedure 9 else:10 key variableName? = ""value or expression? # reassign variable 11
+static void nextAction name?(Card dealerFaceCard parameter definitions?) { // procedure 1 var key name? = ""value or expression?;2 clearKeyBuffer procedureName?(?); // call procedure 3 +while (key.equals("")condition?) { 4 key variableName? = waitForKey()value or expression?; // reassign variable 5 +if (key.equals("d")condition?) { 6 this.draw procedureName?(arguments?); // call procedure 7 } else if (key.equals("s")condition?) {8 this.stand procedureName?(arguments?); // call procedure 9 } else {10 key variableName? = ""value or expression?; // reassign variable 11 } // if } // while } // procedure
+Sub nextAction name?(dealerFaceCard As Card parameter definitions?) ' procedure 1 Dim key name? = ""value or expression? ' variable definition 2 clearKeyBuffer procedureName?(?) ' call procedure 3 +While key.equals("")condition? 4 key variableName? = waitForKey()value or expression? ' reassign variable 5 +If key.equals("d")condition? Then 6 Me.draw procedureName?(arguments?) ' call procedure 7 ElseIf key.equals("s")condition? Then 8 Me.stand procedureName?(arguments?) ' call procedure 9 Else 10 key variableName? = ""value or expression? ' reassign variable 11 End If End While End Sub
public class Global {
+static void nextAction name?(Card dealerFaceCard parameter definitions?) { // procedure 1 var key name? = ""value or expression?;2 clearKeyBuffer procedureName?(?); // call procedure 3 +while (key.equals("")condition?) { 4 key variableName? = waitForKey()value or expression?; // reassign variable 5 +if (key.equals("d")condition?) { 6 this.draw procedureName?(arguments?); // call procedure 7 } else if (key.equals("s")condition?) {8 this.stand procedureName?(arguments?); // call procedure 9 } else {10 key variableName? = ""value or expression?; // reassign variable 11 } // if } // while } // procedure
}

#### What you need to know about p abstract procedures

- An abstract abstract_procedure method may be defined only on an abstract class .
- Any concrete subclass must then implement a concrete (regular) function to match.

## Comment

See Comments

Elan Language Reference go to the top 