# If you already understand OOP but are new to coding with Elan...

Be aware that Elan imposes a set of rules on the use of OOP, and which Elan enforces for all the supported languages - even though the individual languages, when used outside Elan, might not impose those constraints. These constraints are all good discipline: recognised by experts in OOP. So learning OOP within Elan will give you a better understanding and lead to fewer problems.

Before trying to writ

# Exploring the 'Snake

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 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? 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? 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? 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
+class Snake Name? inheritance? 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? 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? 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

This example illustrates an important principle of OOP: an object-oriented program should largely consist of the definition of types, the names and definitions of which correspond to entities in program's 'domain'. Here the domain is a game of 'snake' - which incorporate the concepts of a snake, an apple, and many squares. The program might included classes to represent, game, player, board, and others. The decision as to which entities from the domain should represented in code comes with experience - based on how much value would be added to the program by defining such a class - and some programmers will opt for more than others. The important principle is that each class should sound familiar to someone who is familiar with the problem domain (in this case: with the game of 'snake') but is not necessarily a programmer.

## Instances

Each concrete class may be thought of as a template, from which one or more 'instances' are created. It is valid to define a concrete class that is instantiated only once within the program, but most classes that you define should be instantiated multiple times. When a class is instantiated, the instance is assigned to a variable, and we can see two (of more) separate examples of this from Snake here:

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
variable tail name? set to new Square(20, 15)value or expression?0
tail name? = Square(20, 15)value or expression? # variable definition 0
var tail name? = new Square(20, 15)value or expression?;0
Dim tail name? = New Square(20, 15)value or expression? ' variable definition 0
var tail name? = new Square(20, 15)value or expression?;0

## Members

Each concrete classes contains other instructions., collectively known as the 'members' of the class. The following different kinds of members can be seen:

### Property

Most classes define several properties. A property has name (like a variable) and a type, which might be a standard simple type or data structure, but can also be a user-defined type - which indicates that the property contains a reference to an instance of that type. (This pattern is often referred to as an 'association' between instances. Like a variable, the value of a property may change during the program run. However, each instance holds its own value for each of the properties defined on its class. Here are some examples of properties being defined (the examples are taken from different classes), showing the name and type of each:

+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.
taken from `SquareSquareSquareSquareSquare`
+constructor(parameter definitions?) 0 new code end constructor
property location as Square Code does not parse as Elan.
property location as Square Code does not parse as Elan.
+Sub New(parameter definitions?) 0 new code End Sub
property location as Square Code does not parse as Elan.
taken from `AppleAppleAppleAppleApple`
+constructor(parameter definitions?) 0 new code end constructor
private property body as List Code does not parse as Elan.
private property body as List Code does not parse as Elan.
+Sub New(parameter definitions?) 0 new code End Sub
private property body as List Code does not parse as Elan.
taken from `SnakeSnakeSnakeSnakeSnake`

Within the same class the value of a property may be read, or written to using the following syntax (taken from `SnakeSnakeSnakeSnakeSnake`):

reassign this.priorTail variableName? to this.body[0]value or expression?0
self.priorTail variableName? = self.body[0]value or expression? # reassign variable 0
this.priorTail variableName? = this.body[0]value or expression?; // reassign variable 0
Me.priorTail variableName? = Me.body[0]value or expression? ' reassign variable 0
this.priorTail variableName? = this.body[0]value or expression?; // reassign variable 0

where the value of the property named `priorTailpriorTailpriorTailpriorTailpriorTail` is being changed to hold the first element from the list of squares held in the property named `bodybodybodybodybody`. In both cases the keyword `thisthisthisthisthis` refers to the current instance (i.e. the instance to which the code is applied). It is followed by a dot and the name of the property - an example of 'dot syntax'.

### Constructor

Each class must define one, and only one, constructor. The role of the constructor is to 'initialise' (set the initial values) of the properties. The constructor is called each time an instance of a class is created. In the constructor for `SquareSquareSquareSquareSquare`:

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.

the value of the properties `xxxxx` and `yyyyy` are set to the values defined by the two parameters. Although the parameters have the same names as the properties they ambiguity is avoided because the property is always prefixed by `thisthisthisthisthis`.

The constructor for `SnakeSnakeSnakeSnakeSnake` does not define any parameters, because a snake is instantiated only once within each game, and always to the same size and initial position:

constructor()
constructor()
constructor()
constructor()
constructor()

Note, however, that within the constructor, it creates a new instance of `SquareSquareSquareSquareSquare`, passing in the arguments `2020202020` and `1515151515`, which the square's constructor requires. It also makes used of getAdjacentSquare

which is an example of using a method - which we shall explore next.

### Methods

The properties on a class define the state of an instance; the methods define its behaviour. Methods on a concrete class have two distinct forms: function method and procedure method. These mirror the distinction between a (global) function and procedure. A function is a 'query' that returns information based on the parameters that are supplied to it, but in the case of a function method (defined within a class), in addition to the parameter values, it has access to the property values of the instance - which is legitimate because it is only ever called via that instance. Thus, in the example above, getAdjacentSquare is invoked on the variable `tailtailtailtailtail` (an instance of `SquareSquareSquareSquareSquare`), and is passed the value of `currentDircurrentDircurrentDircurrentDircurrentDir` as an argument. Looking at the definition of getAdjacentSquare within the class `SquareSquareSquareSquareSquare`:

+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
+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

we see that the direction (assigned to the parameter `ddddd`) is used together with the square's `xxxxx` and `yyyyy` properties to identify the coordinates `newXnewXnewXnewXnewX` and `newYnewYnewYnewYnewY` for the adjacent square in the specified direction, and use those to create and return a new instance of `SquareSquareSquareSquareSquare` with those two new coordinates.

Similarly a procedure method is like a global procedure except that it is defined within a class, is accessed only via an instance of that class, using dot syntax, and also has internal access to the properties of that instance. Both kinds of procedure may be thought of as 'commands': they make changes to the state of the system. A common use of procedure methods is to change the values of one or more properties and/or to make changes outside the object. The method newRandomPosition defined on the class `AppleAppleAppleAppleApple`:

+procedure newRandomPosition name?(snake as Snake parameter definitions?) 1 variable changePosition name? set to true value or expression?2 +while changePosition condition? 3 variable ranX name? set to randint(0, 39)value or expression?4 variable ranY name? set to randint(0, 29)value or expression?5 reassign this.location variableName? to new Square(ranX, ranY)value or expression?6 +if not snake.bodyCovers(this.location)condition? then 7 reassign changePosition variableName? to false value or expression?8 end if end while end procedure
+def newRandomPosition name?(snake: Snake parameter definitions?) -> None: # procedure 1 changePosition name? = True value or expression? # variable definition 2 +while changePosition condition?: 3 ranX name? = randint(0, 39)value or expression? # variable definition 4 ranY name? = randint(0, 29)value or expression? # variable definition 5 self.location variableName? = Square(ranX, ranY)value or expression? # reassign variable 6 +if not snake.bodyCovers(self.location)condition?: 7 changePosition variableName? = False value or expression? # reassign variable 8
+static void newRandomPosition name?(Snake snake parameter definitions?) { // procedure 1 var changePosition name? = true value or expression?;2 +while (changePosition condition?) { 3 var ranX name? = randint(0, 39)value or expression?;4 var ranY name? = randint(0, 29)value or expression?;5 this.location variableName? = new Square(ranX, ranY)value or expression?; // reassign variable 6 +if (!snake.bodyCovers(this.location)condition?) { 7 changePosition variableName? = false value or expression?; // reassign variable 8 } // if } // while } // procedure
+Sub newRandomPosition name?(snake As Snake parameter definitions?) ' procedure 1 Dim changePosition name? = True value or expression? ' variable definition 2 +While changePosition condition? 3 Dim ranX name? = randint(0, 39)value or expression? ' variable definition 4 Dim ranY name? = randint(0, 29)value or expression? ' variable definition 5 Me.location variableName? = New Square(ranX, ranY)value or expression? ' reassign variable 6 +If Not snake.bodyCovers(Me.location)condition? Then 7 changePosition variableName? = False value or expression? ' reassign variable 8 End If End While End Sub
+static void newRandomPosition name?(Snake snake parameter definitions?) { // procedure 1 var changePosition name? = true value or expression?;2 +while (changePosition condition?) { 3 var ranX name? = randint(0, 39)value or expression?;4 var ranY name? = randint(0, 29)value or expression?;5 this.location variableName? = new Square(ranX, ranY)value or expression?; // reassign variable 6 +if (!snake.bodyCovers(this.location)condition?) { 7 changePosition variableName? = false value or expression?; // reassign variable 8 } // if } // while } // procedure

changes the `locationlocationlocationlocationlocation` to a new `SquareSquareSquareSquareSquare` - which requires it to be a procedure method. (A second reason is that it uses the system method randint - which depends upon, and changes, data held in the system.) Note that this procedure method makes use of the function method `bodyCoversbodyCoversbodyCoversbodyCoversbodyCovers`, defined on `SnakeSnakeSnakeSnakeSnake`.

A function method may also use other function methods and global functions, but may not call any procedure, whether global or procedure method.

### toString method

Every class must define a function method named toString, which defines no parameters and returns a `StringstrstringStringString`. The returned string is considered to be a representation of the instance: toString is called automatically when an instance printed, or is used within a field in an interpolated string. The string might be as generic as 'a Person', use one or more properties to identify the instance as e.g 'Charlie Smith', or even list, or summarise all the data held by the object.

## Creating a new concrete class

A new concrete class is added into your code, at global level, with the concrete class instruction. The template includes an empty constructor, and a default implementation of toString:

+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? 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
+class Name Name? inheritance? 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

You must complete the template, by giving the class a name, which must start with a capital letter (because a class defines a type), followed by any alphabetic or numeric characters, or underlines. In toString you should, at some point, replace `"undefined""undefined""undefined""undefined""undefined"` with something more specific.

Then via the new code prompt, which will offer you the appropriate options, add properties and methods. All properties must be initialised in the constructor, except those of types `IntintintIntegerint`, `FloatfloatdoubleDoubledouble`, which take on the default values of the type - although such properties may optionally be initialised to different values. Note in particular that properties of type `StringstrstringStringString` must be initialised, even if only to an empty string `""""""""""`.

# Inheritance

A concrete class may inherit from a single abstract class, and/or from one or more interfaces. It may not inherit from more than one abstract class. Nor may it inherit from another concrete class. Abstract class An abstract class may not be instantiate directly, and hence neither needs, nor allows, a constructor. It may define the following types of member - Property, Function method, Procedure method - Abstract Property, abstract function, abstract Intro What is OOP and its advantages Allows you to work with custom data structures that represent the domain of your application in a way that it easier to read, write, and modify. Example: Snake OOP vs. Snake Procedural Particularly well suited to simulations and games, graphics, or complex business applications – give examples of objects. You can define and use objects where needed within a procedural programming, but the OOP paradigm means using the ‘object model’ as the primary design pattern. Class and instance The example programs We will be referring to the following demo programs: … Class defines type and may be thought of as a template, used to create one or more instances. Class is defined in one place And instantiated, and subsequently used, in other places Example of Snake OOP Snake Defined here (the code within the definition is not shown here) Instantiated here and assigned to variable named snake Apple Defined here (the code within the definition is not shown here) Instantiated here and assigned to the variable named apple Square Instantiated many times to show each segment of the snake’s body and the apple. Whenever the snake moves a new instance of Square is added to the front (the ‘head’) and the one at the tail end is discarded. Class definition Adding a new class Select class from new code menu – at global (file) level show You must give it a name. Because a class defines a type the name must start with a capital letter. Examples of valid class names including use of camel case. Within the class, two members are defined in the template (because every class must have them both) : a constructor and a toString method. If you look at each of the classes in Snake_OOP you will see that each has these somewhere, but with some additions/modifications. Properties Almost all classes define one or more properties – which define the data items. Each has a name and type. See examples Properties are like variables, except that they are associated separately with each instance. Thus the class X might define a property y, which will contain z1 for one instance, and z2 for another. Properties are defined within a class using the the property instruction. Example A property of a numeric type (float or integer) will automatically be initialised to the value 0, and a Boolean type to false. All other properties must be explicitly initialised within the constructor. Whenever a value is specified for a property, it is done with a change variable instruction. In the following example the property x is initialised to …. Or you can allow value(s to be specified as parameters in the constructor, and then these values are used within the constructor to initialise one or more properties, for example: If the constructor defines parameters (as above) then appropriate values must be provided when you create a new instance. For example: Then, you can read the properties of an object instance that is held in Using property values within the toString method ToString is a function method that returns a string, but takes no parameters. However, like other methods it can make use of the instance’s properties To string is used: - When printing an object e.g. - Referencing an object within an interpolated string e.g. By default the toString returns ‘undefined’. You can edit this so that it returns `a student` but it is often more useful more useful to return a string that is derived from one or more of the instances properties, for example: - Returning a single identifier - Returning type plus identifier - Summarising all the properties Updating properties of an object Although you can read the value of an ordinary property from code that it outside the class (for example in main) you cannot directly update a property from outside the class. For example, if you try to write this code: You will get the error Xxx If you want to be able to update an property from code outside you need to write a method Private property What this looks like What it means Encapsulation and information hiding Associations Basic types e.g. numbers, strings, Boolean Single association Other UDT (class) or less-commonly another instance of the same type e.g. Best friend Multiple association List of value types, or of associated objects - referrerd Optional association Methods A method (more completely called an ‘instance method’) is a function or procedure that is defined within a class. These methods (unless defined as private) can be Function methods Think of them as queries on the object. They can return information from object’s Procedure methods Make changes to the object and/or depend upon the system. So they f