Object-oriented programming Reference

Getting started

Select the object-oriented programming paradigm

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 paradigm from the menu at the top of the IDE. This will still allow you to do procedural programming, but changes two things:

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 paradigm 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 SnakeName? inheritance?40 +constructor(parameter definitions?) 41 new code end constructor +function toStringname?(parameter definitions?) returns StringType? 42 return "undefined"value or expression?43 end function end class
+class SnakeName? inheritance?: # concrete class44 +def __init__(self: Snake) -> None: 45 new code # end constructor +def toStringname?(self: Snake) -> strType?: # function method46 return "undefined"value or expression?47 # end function method # end class
+class SnakeName? inheritance? {48 +public Snake(parameter definitions?) { 49 new code } // end constructor +public stringType? toStringname?(parameter definitions?) { // function method50 return "undefined"value or expression?;51 } // end function method } // end class
+Class SnakeName? inheritance?52 +Sub New(parameter definitions?) 53 new code End Sub +Function toStringname?(parameter definitions?) As StringType? 54 Return "undefined"value or expression?55 End Function End Class
+class SnakeName? inheritance? {56 +public Snake(parameter definitions?) { 57 new code } // end constructor +public StringType? toStringname?(parameter definitions?) { // function method58 return "undefined"value or expression?;59 } // end function method } // end 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:

NameType
xxxxxIntintintIntegerint
yyyyyIntintintIntegerint

or properties may have different types, for example the TuringMachineTuringMachineTuringMachineTuringMachineTuringMachine class in the Roman Numerals Turing Machine demo has these:

NameType
initialStateinitialStateinitialStateinitialStateinitialStateStringstrstringStringString
currentStatecurrentStatecurrentStatecurrentStatecurrentStateStringstrstringStringString
headPositionheadPositionheadPositionheadPositionheadPositionIntintintIntegerint
haltStatehaltStatehaltStatehaltStatehaltStateStringstrstringStringString
rulesrulesrulesrulesrulesList<of Rule>list[Rule]List<Rule>List(Of Rule)List<Rule>
tapetapetapetapetapeStringstrstringStringString

Defining a class

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

+class NameName? inheritance?60 +constructor(parameter definitionsparameter definitions?) 61 new code end constructor +function toStringname?(parameter definitionsparameter definitions?) returns StringType? 62 return "undefined"value or expression?63 end function end class
+class NameName? inheritance?: # concrete class64 +def __init__(self: Name) -> None: 65 new code # end constructor +def toStringname?(self: Name) -> strType?: # function method66 return "undefined"value or expression?67 # end function method # end class
+class NameName? inheritance? {68 +public Name(parameter definitionsparameter definitions?) { 69 new code } // end constructor +public stringType? toStringname?(parameter definitionsparameter definitions?) { // function method70 return "undefined"value or expression?;71 } // end function method } // end class
+Class NameName? inheritance?72 +Sub New(parameter definitionsparameter definitions?) 73 new code End Sub +Function toStringname?(parameter definitionsparameter definitions?) As StringType? 74 Return "undefined"value or expression?75 End Function End Class
+class NameName? inheritance? {76 +public Name(parameter definitionsparameter definitions?) { 77 new code } // end constructor +public StringType? toStringname?(parameter definitionsparameter definitions?) { // function method78 return "undefined"value or expression?;79 } // end function method } // end 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 applename? set to new Apple()value or expression?80
applename? = Apple()value or expression? # variable definition81
var applename? = new Apple()value or expression?;82
Dim applename? = New Apple()value or expression? ' variable definition83
var applename? = new Apple()value or expression?;84
variable snakename? set to new Snake()value or expression?85
snakename? = Snake()value or expression? # variable definition86
var snakename? = new Snake()value or expression?;87
Dim snakename? = New Snake()value or expression? ' variable definition88
var snakename? = new Snake()value or expression?;89

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:

+function emptyPointname?(parameter definitionsparameter definitions?) returns PointType? 90 return new Point(-1, -1)value or expression?91 end function
+def emptyPointname?(parameter definitionsparameter definitions?) -> PointType?: # function92 return Point(-1, -1)value or expression?93 # end function
+static PointType? emptyPointname?(parameter definitionsparameter definitions?) { // function94 return new Point(-1, -1)value or expression?;95 } // end function
+Function emptyPointname?(parameter definitionsparameter definitions?) As PointType? 96 Return New Point(-1, -1)value or expression?97 End Function
+static PointType? emptyPointname?(parameter definitionsparameter definitions?) { // function98 return new Point(-1, -1)value or expression?;99 } // end function

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.distFromStartcondition? then 100 new code end if
+if distViaCurrent < neighbour.distFromStartcondition?: 101 new code # end if
+if (distViaCurrent < neighbour.distFromStartcondition?) { 102 new code } // end if
+If distViaCurrent < neighbour.distFromStartcondition? Then 103 new code End If
+if (distViaCurrent < neighbour.distFromStartcondition?) { 104 new code } // end 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 BooleanboolboolBooleanboolean - 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:

+class SquareName? inheritance?105 +constructor(x as Int, y as Intparameter definitions?) 106 assign this.xvariableName? to xvalue or expression?107 assign this.yvariableName? to yvalue or expression?108 end constructor property xname? as IntType?109 property yname? as IntType?110 # Methods not shown herecomment? +function toStringname?(parameter definitionsparameter definitions?) returns StringType? 111 return "{this.x}, {this.y}"value or expression?112 end function end class
+class SquareName? inheritance?: # concrete class113 +def __init__(self: Square, x: int, y: intparameter definitions?) -> None: 114 self.xvariableName? = xvalue or expression? # assignment115 self.yvariableName? = yvalue or expression? # assignment116 # end constructor xname?: intType? # property117 yname?: intType? # property118 # Methods not shown herecomment? +def toStringname?(self: Square) -> strType?: # function method119 return "{this.x}, {this.y}"value or expression?120 # end function method # end class
+class SquareName? inheritance? {121 +public Square(int x, int yparameter definitions?) { 122 this.xvariableName? = xvalue or expression?; // assignment123 this.yvariableName? = yvalue or expression?; // assignment124 } // end constructor public intType? xname? {get; private set;} // property125 public intType? yname? {get; private set;} // property126 // Methods not shown herecomment? +public stringType? toStringname?(parameter definitionsparameter definitions?) { // function method127 return "{this.x}, {this.y}"value or expression?;128 } // end function method } // end class
+Class SquareName? inheritance?129 +Sub New(x As Integer, y As Integerparameter definitions?) 130 Me.xvariableName? = xvalue or expression? ' assignment131 Me.yvariableName? = yvalue or expression? ' assignment132 End Sub Property xname? As IntegerType?133 Property yname? As IntegerType?134 ' Methods not shown herecomment? +Function toStringname?(parameter definitionsparameter definitions?) As StringType? 135 Return "{this.x}, {this.y}"value or expression?136 End Function End Class
+class SquareName? inheritance? {137 +public Square(int x, int yparameter definitions?) { 138 this.xvariableName? = xvalue or expression?; // assignment139 this.yvariableName? = yvalue or expression?; // assignment140 } // end constructor public intType? xname?; // property141 public intType? yname?; // property142 // Methods not shown herecomment? +public StringType? toStringname?(parameter definitionsparameter definitions?) { // function method143 return "{this.x}, {this.y}"value or expression?;144 } // end function method } // end class

Note:

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 SnakeName? inheritance?145 +constructor(parameter definitionsparameter definitions?) 146 variable tailname? set to new Square(20, 15)value or expression?147 assign this.currentDirvariableName? to Direction.rightvalue or expression?148 assign this.bodyvariableName? to [tail]value or expression?149 assign this.headvariableName? to tail.getAdjacentSquare(this.currentDir)value or expression?150 assign this.priorTailvariableName? to tailvalue or expression?151 end constructor private property currentDirname? as DirectionType?152 private property headname? as SquareType?153 private property bodyname? as List<of Square>Type?154 private property priorTailname? as SquareType?155 +function toStringname?(parameter definitions?) returns StringType? 156 return "undefined"value or expression?157 end function end class
+class SnakeName? inheritance?: # concrete class158 +def __init__(self: Snake) -> None: 159 tailname? = Square(20, 15)value or expression? # variable definition160 self.currentDirvariableName? = Direction.rightvalue or expression? # assignment161 self.bodyvariableName? = [tail]value or expression? # assignment162 self.headvariableName? = tail.getAdjacentSquare(self.currentDir)value or expression? # assignment163 self.priorTailvariableName? = tailvalue or expression? # assignment164 # end constructor currentDirname?: DirectionType? # private property165 headname?: SquareType? # private property166 bodyname?: list[Square]Type? # private property167 priorTailname?: SquareType? # private property168 +def toStringname?(self: Snake) -> strType?: # function method169 return "undefined"value or expression?170 # end function method # end class
+class SnakeName? inheritance? {171 +public Snake(parameter definitionsparameter definitions?) { 172 var tailname? = new Square(20, 15)value or expression?;173 this.currentDirvariableName? = Direction.rightvalue or expression?; // assignment174 this.bodyvariableName? = new [] {tail}value or expression?; // assignment175 this.headvariableName? = tail.getAdjacentSquare(this.currentDir)value or expression?; // assignment176 this.priorTailvariableName? = tailvalue or expression?; // assignment177 } // end constructor private DirectionType? currentDirname? {get; private set;} // private property178 private SquareType? headname? {get; private set;} // private property179 private List<Square>Type? bodyname? {get; private set;} // private property180 private SquareType? priorTailname? {get; private set;} // private property181 +public stringType? toStringname?(parameter definitions?) { // function method182 return "undefined"value or expression?;183 } // end function method } // end class
+Class SnakeName? inheritance?184 +Sub New(parameter definitionsparameter definitions?) 185 Dim tailname? = New Square(20, 15)value or expression? ' variable definition186 Me.currentDirvariableName? = Direction.rightvalue or expression? ' assignment187 Me.bodyvariableName? = {tail}value or expression? ' assignment188 Me.headvariableName? = tail.getAdjacentSquare(Me.currentDir)value or expression? ' assignment189 Me.priorTailvariableName? = tailvalue or expression? ' assignment190 End Sub Private Property currentDirname? As DirectionType?191 Private Property headname? As SquareType?192 Private Property bodyname? As List(Of Square)Type?193 Private Property priorTailname? As SquareType?194 +Function toStringname?(parameter definitions?) As StringType? 195 Return "undefined"value or expression?196 End Function End Class
+class SnakeName? inheritance? {197 +public Snake(parameter definitionsparameter definitions?) { 198 var tailname? = new Square(20, 15)value or expression?;199 this.currentDirvariableName? = Direction.rightvalue or expression?; // assignment200 this.bodyvariableName? = list(tail)value or expression?; // assignment201 this.headvariableName? = tail.getAdjacentSquare(this.currentDir)value or expression?; // assignment202 this.priorTailvariableName? = tailvalue or expression?; // assignment203 } // end constructor private DirectionType? currentDirname?; // private property204 private SquareType? headname?; // private property205 private List<Square>Type? bodyname?; // private property206 private SquareType? priorTailname?; // private property207 +public StringType? toStringname?(parameter definitions?) { // function method208 return "undefined"value or expression?;209 } // end function method } // end class

Note:

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:

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 getAdjacentSquarename?(d as Directionparameter definitions?) returns SquareType? 210 variable newXname? set to this.xvalue or expression?211 variable newYname? set to this.yvalue or expression?212 +if d is Direction.leftcondition? then 213 assign newXvariableName? to this.x - 1value or expression?214 elif d is Direction.rightcondition? then215 assign newXvariableName? to this.x + 1value or expression?216 elif d is Direction.upcondition? then217 assign newYvariableName? to this.y - 1value or expression?218 elif d is Direction.downcondition? then219 assign newYvariableName? to this.y + 1value or expression?220 end if return new Square(newX, newY)value or expression?221 end function
+def getAdjacentSquarename?(d: Directionparameter definitions?) -> SquareType?: # function222 newXname? = self.xvalue or expression? # variable definition223 newYname? = self.yvalue or expression? # variable definition224 +if d == Direction.leftcondition?: 225 newXvariableName? = self.x - 1value or expression? # assignment226 elif d == Direction.rightcondition?: # else if227 newXvariableName? = self.x + 1value or expression? # assignment228 elif d == Direction.upcondition?: # else if229 newYvariableName? = self.y - 1value or expression? # assignment230 elif d == Direction.downcondition?: # else if231 newYvariableName? = self.y + 1value or expression? # assignment232 # end if return Square(newX, newY)value or expression?233 # end function
+static SquareType? getAdjacentSquarename?(Direction dparameter definitions?) { // function234 var newXname? = this.xvalue or expression?;235 var newYname? = this.yvalue or expression?;236 +if (d == Direction.leftcondition?) { 237 newXvariableName? = this.x - 1value or expression?; // assignment238 } else if (d == Direction.rightcondition?) {239 newXvariableName? = this.x + 1value or expression?; // assignment240 } else if (d == Direction.upcondition?) {241 newYvariableName? = this.y - 1value or expression?; // assignment242 } else if (d == Direction.downcondition?) {243 newYvariableName? = this.y + 1value or expression?; // assignment244 } // end if return new Square(newX, newY)value or expression?;245 } // end function
+Function getAdjacentSquarename?(d As Directionparameter definitions?) As SquareType? 246 Dim newXname? = Me.xvalue or expression? ' variable definition247 Dim newYname? = Me.yvalue or expression? ' variable definition248 +If d = Direction.leftcondition? Then 249 newXvariableName? = Me.x - 1value or expression? ' assignment250 ElseIf d = Direction.rightcondition? Then251 newXvariableName? = Me.x + 1value or expression? ' assignment252 ElseIf d = Direction.upcondition? Then253 newYvariableName? = Me.y - 1value or expression? ' assignment254 ElseIf d = Direction.downcondition? Then255 newYvariableName? = Me.y + 1value or expression? ' assignment256 End If Return New Square(newX, newY)value or expression?257 End Function
+static SquareType? getAdjacentSquarename?(Direction dparameter definitions?) { // function258 var newXname? = this.xvalue or expression?;259 var newYname? = this.yvalue or expression?;260 +if (d == Direction.leftcondition?) { 261 newXvariableName? = this.x - 1value or expression?; // assignment262 } else if (d == Direction.rightcondition?) {263 newXvariableName? = this.x + 1value or expression?; // assignment264 } else if (d == Direction.upcondition?) {265 newYvariableName? = this.y - 1value or expression?; // assignment266 } else if (d == Direction.downcondition?) {267 newYvariableName? = this.y + 1value or expression?; // assignment268 } // end if return new Square(newX, newY)value or expression?;269 } // end 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 toStringname?(parameter definitionsparameter definitions?) returns StringType? 270 return $"A snake with {this.body.length() + 1} segments"value or expression?271 end function
+def toStringname?(parameter definitionsparameter definitions?) -> strType?: # function272 return f"A snake with {self.body.length() + 1} segments"value or expression?273 # end function
+static stringType? toStringname?(parameter definitionsparameter definitions?) { // function274 return $"A snake with {this.body.length() + 1} segments"value or expression?;275 } // end function
+Function toStringname?(parameter definitionsparameter definitions?) As StringType? 276 Return $"A snake with {Me.body.length() + 1} segments"value or expression?277 End Function
+static StringType? toStringname?(parameter definitionsparameter definitions?) { // function278 return String.format("A snake with % segments", this.body.length() + 1)value or expression?;279 } // end function
(You might like to try this out, temporarilyadding the instruction print(snakearguments?)5print(snakearguments?)6Console.WriteLine(snakearguments?); // print statement7Console.WriteLine(snakearguments?) ' print statement8System.out.println(snakearguments?); // print statement9 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 clockTickname?(key as String, apple as Appleparameter definitions?) 280 call this.setDirectionprocedureName?(keyarguments?)281 assign this.priorTailvariableName? to this.body[0]value or expression?282 variable bodyname? set to this.bodyvalue or expression?283 call body.appendprocedureName?(this.headarguments?)284 assign this.headvariableName? to this.head.getAdjacentSquare(this.currentDir)value or expression?285 +if this.head.equals(apple.location)condition? then 286 call apple.newRandomPositionprocedureName?(thisarguments?)287 else288 assign this.bodyvariableName? to this.body.subList(1, this.body.length())value or expression?289 end if end procedure
+def clockTickname?(key: str, apple: Appleparameter definitions?) -> None: # procedure290 self.setDirectionprocedureName?(keyarguments?) # procedure call291 self.priorTailvariableName? = self.body[0]value or expression? # assignment292 bodyname? = self.bodyvalue or expression? # variable definition293 body.appendprocedureName?(self.headarguments?) # procedure call294 self.headvariableName? = self.head.getAdjacentSquare(self.currentDir)value or expression? # assignment295 +if self.head.equals(apple.location)condition?: 296 apple.newRandomPositionprocedureName?(selfarguments?) # procedure call297 else:298 self.bodyvariableName? = self.body.subList(1, self.body.length())value or expression? # assignment299 # end if # end procedure
+static void clockTickname?(string key, Apple appleparameter definitions?) { // procedure300 this.setDirectionprocedureName?(keyarguments?); // procedure call301 this.priorTailvariableName? = this.body[0]value or expression?; // assignment302 var bodyname? = this.bodyvalue or expression?;303 body.appendprocedureName?(this.headarguments?); // procedure call304 this.headvariableName? = this.head.getAdjacentSquare(this.currentDir)value or expression?; // assignment305 +if (this.head.equals(apple.location)condition?) { 306 apple.newRandomPositionprocedureName?(thisarguments?); // procedure call307 } else {308 this.bodyvariableName? = this.body.subList(1, this.body.length())value or expression?; // assignment309 } // end if } // end procedure
+Sub clockTickname?(key As String, apple As Appleparameter definitions?) ' procedure310 Me.setDirectionprocedureName?(keyarguments?) ' procedure call311 Me.priorTailvariableName? = Me.body(0)value or expression? ' assignment312 Dim bodyname? = Me.bodyvalue or expression? ' variable definition313 body.appendprocedureName?(Me.headarguments?) ' procedure call314 Me.headvariableName? = Me.head.getAdjacentSquare(Me.currentDir)value or expression? ' assignment315 +If Me.head.equals(apple.location)condition? Then 316 apple.newRandomPositionprocedureName?(Mearguments?) ' procedure call317 Else318 Me.bodyvariableName? = Me.body.subList(1, Me.body.length())value or expression? ' assignment319 End If End Sub
+static void clockTickname?(String key, Apple appleparameter definitions?) { // procedure320 this.setDirectionprocedureName?(keyarguments?); // procedure call321 this.priorTailvariableName? = this.body[0]value or expression?; // assignment322 var bodyname? = this.bodyvalue or expression?;323 body.appendprocedureName?(this.headarguments?); // procedure call324 this.headvariableName? = this.head.getAdjacentSquare(this.currentDir)value or expression?; // assignment325 +if (this.head.equals(apple.location)condition?) { 326 apple.newRandomPositionprocedureName?(thisarguments?); // procedure call327 } else {328 this.bodyvariableName? = this.body.subList(1, this.body.length())value or expression?; // assignment329 } // end if } // end 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:

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:

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:

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 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 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). For example, the Snake - object-oriented demo has a total of 96 instructions (excluding tests), of which just 12 are not in a user-defined class (they are all in the main routine). The allocation of the other instructions is as follows:

ClassPropertiesMethods (excl. constructor & toString)No. of instructionsNotes
SnakeSnakeSnakeSnakeSnake4657singleton - but an extended version of the game might have multiple instances.
AppleAppleAppleAppleApple1216ditto
SquareSquareSquareSquareSquare2222Many instances created in the game. Both Snake and Apple have associations to one or more Squares

Global Instructions

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

Concrete class

Examples of a concrete class

From the Snake - object-oriented demo:

+class AppleName? inheritance?330 +constructor(parameter definitionsparameter definitions?) 331 assign this.locationvariableName? to new Square(0, 0)value or expression?332 end constructor property locationname? as SquareType?333 +procedure newRandomPositionname?(snake as Snakeparameter definitions?) 334 variable changePositionname? set to truevalue or expression?335 +while changePositioncondition? 336 variable ranXname? set to randint(0, 39)value or expression?337 variable ranYname? set to randint(0, 29)value or expression?338 assign this.locationvariableName? to new Square(ranX, ranY)value or expression?339 +if not snake.bodyCovers(this.location)condition? then 340 assign changePositionvariableName? to falsevalue or expression?341 end if end while end procedure +procedure updateBlocksname?(blocks as List<of List<of Int>>parameter definitions?) 342 assign blocks[this.location.x][this.location.y]variableName? to redvalue or expression?343 end procedure +function toStringname?(parameter definitionsparameter definitions?) returns StringType? 344 return $"an Apple at {this.location}"value or expression?345 end function end class
+class AppleName? inheritance?: # concrete class346 +def __init__(self: Apple) -> None: 347 self.locationvariableName? = Square(0, 0)value or expression? # assignment348 # end constructor locationname?: SquareType? # property349 +def newRandomPositionname?(self: Apple, snake: Snakeparameter definitions?) -> None: # procedure method350 changePositionname? = Truevalue or expression? # variable definition351 +while changePositioncondition?: 352 ranXname? = randint(0, 39)value or expression? # variable definition353 ranYname? = randint(0, 29)value or expression? # variable definition354 self.locationvariableName? = Square(ranX, ranY)value or expression? # assignment355 +if not snake.bodyCovers(self.location)condition?: 356 changePositionvariableName? = Falsevalue or expression? # assignment357 # end if # end while # end procedure method +def updateBlocksname?(self: Apple, blocks: list[list[int]]parameter definitions?) -> None: # procedure method358 blocks[self.location.x][self.location.y]variableName? = redvalue or expression? # assignment359 # end procedure method +def toStringname?(self: Apple) -> strType?: # function method360 return f"an Apple at {self.location}"value or expression?361 # end function method # end class
+class AppleName? inheritance? {362 +public Apple(parameter definitionsparameter definitions?) { 363 this.locationvariableName? = new Square(0, 0)value or expression?; // assignment364 } // end constructor public SquareType? locationname? {get; private set;} // property365 +public void newRandomPositionname?(Snake snakeparameter definitions?) { // procedure method366 var changePositionname? = truevalue or expression?;367 +while (changePositioncondition?) { 368 var ranXname? = randint(0, 39)value or expression?;369 var ranYname? = randint(0, 29)value or expression?;370 this.locationvariableName? = new Square(ranX, ranY)value or expression?; // assignment371 +if (!snake.bodyCovers(this.location)condition?) { 372 changePositionvariableName? = falsevalue or expression?; // assignment373 } // end if } // end while } // end procedure method +public void updateBlocksname?(List<List<int>> blocksparameter definitions?) { // procedure method374 blocks[this.location.x][this.location.y]variableName? = redvalue or expression?; // assignment375 } // end procedure method +public stringType? toStringname?(parameter definitionsparameter definitions?) { // function method376 return $"an Apple at {this.location}"value or expression?;377 } // end function method } // end class
+Class AppleName? inheritance?378 +Sub New(parameter definitionsparameter definitions?) 379 Me.locationvariableName? = New Square(0, 0)value or expression? ' assignment380 End Sub Property locationname? As SquareType?381 +Sub newRandomPositionname?(snake As Snakeparameter definitions?) ' procedure method382 Dim changePositionname? = Truevalue or expression? ' variable definition383 +While changePositioncondition? 384 Dim ranXname? = randint(0, 39)value or expression? ' variable definition385 Dim ranYname? = randint(0, 29)value or expression? ' variable definition386 Me.locationvariableName? = New Square(ranX, ranY)value or expression? ' assignment387 +If Not snake.bodyCovers(Me.location)condition? Then 388 changePositionvariableName? = Falsevalue or expression? ' assignment389 End If End While End Sub +Sub updateBlocksname?(blocks As List(Of List(Of Integer))parameter definitions?) ' procedure method390 blocks(Me.location.x)(Me.location.y)variableName? = redvalue or expression? ' assignment391 End Sub +Function toStringname?(parameter definitionsparameter definitions?) As StringType? 392 Return $"an Apple at {Me.location}"value or expression?393 End Function End Class
+class AppleName? inheritance? {394 +public Apple(parameter definitionsparameter definitions?) { 395 this.locationvariableName? = new Square(0, 0)value or expression?; // assignment396 } // end constructor public SquareType? locationname?; // property397 +public void newRandomPositionname?(Snake snakeparameter definitions?) { // procedure method398 var changePositionname? = truevalue or expression?;399 +while (changePositioncondition?) { 400 var ranXname? = randint(0, 39)value or expression?;401 var ranYname? = randint(0, 29)value or expression?;402 this.locationvariableName? = new Square(ranX, ranY)value or expression?; // assignment403 +if (!snake.bodyCovers(this.location)condition?) { 404 changePositionvariableName? = falsevalue or expression?; // assignment405 } // end if } // end while } // end procedure method +public void updateBlocksname?(List<List<int>> blocksparameter definitions?) { // procedure method406 blocks[this.location.x][this.location.y]variableName? = redvalue or expression?; // assignment407 } // end procedure method +public StringType? toStringname?(parameter definitionsparameter definitions?) { // function method408 return String.format("an Apple at %", this.location)value or expression?;409 } // end function method } // end class

From the Blackjack demo:

+class CardName? inheritance?410 property suitname? as SuitType?411 property rankname? as StringType?412 property faceDownname? as BooleanType?413 +constructor(rank as String, suit as Suit, facedown as Booleanparameter definitions?) 414 assign this.rankvariableName? to rankvalue or expression?415 assign this.suitvariableName? to suitvalue or expression?416 assign this.faceDownvariableName? to facedownvalue or expression?417 end constructor +procedure turnFaceUpname?(parameter definitionsparameter definitions?) 418 assign this.faceDownvariableName? to falsevalue or expression?419 end procedure +procedure turnFaceDownname?(parameter definitionsparameter definitions?) 420 assign this.faceDownvariableName? to truevalue or expression?421 end procedure +function toStringname?(parameter definitionsparameter definitions?) returns StringType? 422 return $"{this.rank}{symbolForSuit(this.suit)}"value or expression?423 end function end class
+class CardName? inheritance?: # concrete class424 suitname?: SuitType? # property425 rankname?: strType? # property426 faceDownname?: boolType? # property427 +def __init__(self: Card, rank: str, suit: Suit, facedown: boolparameter definitions?) -> None: 428 self.rankvariableName? = rankvalue or expression? # assignment429 self.suitvariableName? = suitvalue or expression? # assignment430 self.faceDownvariableName? = facedownvalue or expression? # assignment431 # end constructor +def turnFaceUpname?(self: Card) -> None: # procedure method432 self.faceDownvariableName? = Falsevalue or expression? # assignment433 # end procedure method +def turnFaceDownname?(self: Card) -> None: # procedure method434 self.faceDownvariableName? = Truevalue or expression? # assignment435 # end procedure method +def toStringname?(self: Card) -> strType?: # function method436 return f"{self.rank}{symbolForSuit(self.suit)}"value or expression?437 # end function method # end class
+class CardName? inheritance? {438 public SuitType? suitname? {get; private set;} // property439 public stringType? rankname? {get; private set;} // property440 public boolType? faceDownname? {get; private set;} // property441 +public Card(string rank, Suit suit, bool facedownparameter definitions?) { 442 this.rankvariableName? = rankvalue or expression?; // assignment443 this.suitvariableName? = suitvalue or expression?; // assignment444 this.faceDownvariableName? = facedownvalue or expression?; // assignment445 } // end constructor +public void turnFaceUpname?(parameter definitionsparameter definitions?) { // procedure method446 this.faceDownvariableName? = falsevalue or expression?; // assignment447 } // end procedure method +public void turnFaceDownname?(parameter definitionsparameter definitions?) { // procedure method448 this.faceDownvariableName? = truevalue or expression?; // assignment449 } // end procedure method +public stringType? toStringname?(parameter definitionsparameter definitions?) { // function method450 return $"{this.rank}{symbolForSuit(this.suit)}"value or expression?;451 } // end function method } // end class
+Class CardName? inheritance?452 Property suitname? As SuitType?453 Property rankname? As StringType?454 Property faceDownname? As BooleanType?455 +Sub New(rank As String, suit As Suit, facedown As Booleanparameter definitions?) 456 Me.rankvariableName? = rankvalue or expression? ' assignment457 Me.suitvariableName? = suitvalue or expression? ' assignment458 Me.faceDownvariableName? = facedownvalue or expression? ' assignment459 End Sub +Sub turnFaceUpname?(parameter definitionsparameter definitions?) ' procedure method460 Me.faceDownvariableName? = Falsevalue or expression? ' assignment461 End Sub +Sub turnFaceDownname?(parameter definitionsparameter definitions?) ' procedure method462 Me.faceDownvariableName? = Truevalue or expression? ' assignment463 End Sub +Function toStringname?(parameter definitionsparameter definitions?) As StringType? 464 Return $"{Me.rank}{symbolForSuit(Me.suit)}"value or expression?465 End Function End Class
+class CardName? inheritance? {466 public SuitType? suitname?; // property467 public StringType? rankname?; // property468 public booleanType? faceDownname?; // property469 +public Card(String rank, Suit suit, boolean facedownparameter definitions?) { 470 this.rankvariableName? = rankvalue or expression?; // assignment471 this.suitvariableName? = suitvalue or expression?; // assignment472 this.faceDownvariableName? = facedownvalue or expression?; // assignment473 } // end constructor +public void turnFaceUpname?(parameter definitionsparameter definitions?) { // procedure method474 this.faceDownvariableName? = falsevalue or expression?; // assignment475 } // end procedure method +public void turnFaceDownname?(parameter definitionsparameter definitions?) { // procedure method476 this.faceDownvariableName? = truevalue or expression?; // assignment477 } // end procedure method +public StringType? toStringname?(parameter definitionsparameter definitions?) { // function method478 return String.format("%%", this.rank, symbolForSuit(this.suit))value or expression?;479 } // end function method } // end class

From the Pathfinder demo:

+class PointName? inheritance?480 property xname? as IntType?481 property yname? as IntType?482 property isEmptyname? as BooleanType?483 +constructor(x as Int, y as Intparameter definitions?) 484 +if (x < 0) or (y < 0)condition? then 485 assign this.isEmptyvariableName? to truevalue or expression?486 else487 assign this.xvariableName? to xvalue or expression?488 assign this.yvariableName? to yvalue or expression?489 end if end constructor +function minDistToname?(p as Pointparameter definitions?) returns FloatType? 490 return sqrt(pow((p.x - this.x), 2) + pow((p.y - this.y), 2))value or expression?491 end function +function isAdjacentToname?(p as Pointparameter definitions?) returns BooleanType? 492 return (this.minDistTo(p) is 1) or (this.minDistTo(p).round(4) is sqrt(2).round(4))value or expression?493 end function # Returns the 8 theoretically-neighbouring points, whether or not within boundscomment? +function neighbouringPointsname?(parameter definitionsparameter definitions?) returns List<of Point>Type? 494 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?495 end function +function toStringname?(parameter definitionsparameter definitions?) returns StringType? 496 return $"{this.x},{this.y}"value or expression?497 end function end class
+class PointName? inheritance?: # concrete class498 xname?: intType? # property499 yname?: intType? # property500 isEmptyname?: boolType? # property501 +def __init__(self: Point, x: int, y: intparameter definitions?) -> None: 502 +if (x < 0) or (y < 0)condition?: 503 self.isEmptyvariableName? = Truevalue or expression? # assignment504 else:505 self.xvariableName? = xvalue or expression? # assignment506 self.yvariableName? = yvalue or expression? # assignment507 # end if # end constructor +def minDistToname?(self: Point, p: Pointparameter definitions?) -> floatType?: # function method508 return sqrt(pow((p.x - self.x), 2) + pow((p.y - self.y), 2))value or expression?509 # end function method +def isAdjacentToname?(self: Point, p: Pointparameter definitions?) -> boolType?: # function method510 return (self.minDistTo(p) == 1) or (self.minDistTo(p).round(4) == sqrt(2).round(4))value or expression?511 # end function method # Returns the 8 theoretically-neighbouring points, whether or not within boundscomment? +def neighbouringPointsname?(self: Point) -> list[Point]Type?: # function method512 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?513 # end function method +def toStringname?(self: Point) -> strType?: # function method514 return f"{self.x},{self.y}"value or expression?515 # end function method # end class
+class PointName? inheritance? {516 public intType? xname? {get; private set;} // property517 public intType? yname? {get; private set;} // property518 public boolType? isEmptyname? {get; private set;} // property519 +public Point(int x, int yparameter definitions?) { 520 +if ((x < 0) || (y < 0)condition?) { 521 this.isEmptyvariableName? = truevalue or expression?; // assignment522 } else {523 this.xvariableName? = xvalue or expression?; // assignment524 this.yvariableName? = yvalue or expression?; // assignment525 } // end if } // end constructor +public doubleType? minDistToname?(Point pparameter definitions?) { // function method526 return sqrt(pow((p.x - this.x), 2) + pow((p.y - this.y), 2))value or expression?;527 } // end function method +public boolType? isAdjacentToname?(Point pparameter definitions?) { // function method528 return (this.minDistTo(p) == 1) || (this.minDistTo(p).round(4) == sqrt(2).round(4))value or expression?;529 } // end function method // Returns the 8 theoretically-neighbouring points, whether or not within boundscomment? +public List<Point>Type? neighbouringPointsname?(parameter definitionsparameter definitions?) { // function method530 return new [] {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?;531 } // end function method +public stringType? toStringname?(parameter definitionsparameter definitions?) { // function method532 return $"{this.x},{this.y}"value or expression?;533 } // end function method } // end class
+Class PointName? inheritance?534 Property xname? As IntegerType?535 Property yname? As IntegerType?536 Property isEmptyname? As BooleanType?537 +Sub New(x As Integer, y As Integerparameter definitions?) 538 +If (x < 0) Or (y < 0)condition? Then 539 Me.isEmptyvariableName? = Truevalue or expression? ' assignment540 Else541 Me.xvariableName? = xvalue or expression? ' assignment542 Me.yvariableName? = yvalue or expression? ' assignment543 End If End Sub +Function minDistToname?(p As Pointparameter definitions?) As DoubleType? 544 Return sqrt(pow((p.x - Me.x), 2) + pow((p.y - Me.y), 2))value or expression?545 End Function +Function isAdjacentToname?(p As Pointparameter definitions?) As BooleanType? 546 Return (Me.minDistTo(p) = 1) Or (Me.minDistTo(p).round(4) = sqrt(2).round(4))value or expression?547 End Function ' Returns the 8 theoretically-neighbouring points, whether or not within boundscomment? +Function neighbouringPointsname?(parameter definitionsparameter definitions?) As List(Of Point)Type? 548 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?549 End Function +Function toStringname?(parameter definitionsparameter definitions?) As StringType? 550 Return $"{Me.x},{Me.y}"value or expression?551 End Function End Class
+class PointName? inheritance? {552 public intType? xname?; // property553 public intType? yname?; // property554 public booleanType? isEmptyname?; // property555 +public Point(int x, int yparameter definitions?) { 556 +if ((x < 0) || (y < 0)condition?) { 557 this.isEmptyvariableName? = truevalue or expression?; // assignment558 } else {559 this.xvariableName? = xvalue or expression?; // assignment560 this.yvariableName? = yvalue or expression?; // assignment561 } // end if } // end constructor +public doubleType? minDistToname?(Point pparameter definitions?) { // function method562 return sqrt(pow((p.x - this.x), 2) + pow((p.y - this.y), 2))value or expression?;563 } // end function method +public booleanType? isAdjacentToname?(Point pparameter definitions?) { // function method564 return (this.minDistTo(p) == 1) || (this.minDistTo(p).round(4) == sqrt(2).round(4))value or expression?;565 } // end function method // Returns the 8 theoretically-neighbouring points, whether or not within boundscomment? +public List<Point>Type? neighbouringPointsname?(parameter definitionsparameter definitions?) { // function method566 return list(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?;567 } // end function method +public StringType? toStringname?(parameter definitionsparameter definitions?) { // function method568 return String.format("%,%", this.x, this.y)value or expression?;569 } // end function method } // end 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?10applename? = Apple()value or expression? # variable definition11var applename? = new Apple()value or expression?;12Dim applename? = New Apple()value or expression? ' variable definition13var applename? = new Apple()value or expression?;14 or variable startname? set to new Point(5, 5)value or expression?15startname? = Point(5, 5)value or expression? # variable definition16var startname? = new Point(5, 5)value or expression?;17Dim startname? = New Point(5, 5)value or expression? ' variable definition18var startname? = new Point(5, 5)value or expression?;19.
  • 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 DealerDealerDealerDealerDealer - 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 PlayerName? inheritance?570 property namename? as StringType?571 property pointsname? as IntType?572 property cardsname? as List<of Card>Type?573 property handTotalname? as IntType?574 property softAcename? as BooleanType?575 property statusname? as StatusType?576 property hasTurnname? as BooleanType?577 +procedure startTurnname?(parameter definitionsparameter definitions?) 578 +if this.status is Status.activecondition? then 579 assign this.hasTurnvariableName? to truevalue or expression?580 end if end procedure +procedure determineOutcomeAndUpdatePointsname?(dealer as Dealerparameter definitions?) 581 variable playerOutcomename? set to determinePlayerOutcome(dealer, this)value or expression?582 +if playerOutcome is Outcome.winDoublecondition? then 583 call this.changePointsByprocedureName?(2arguments?)584 call dealer.changePointsByprocedureName?(-2arguments?)585 elif playerOutcome is Outcome.wincondition? then586 call this.changePointsByprocedureName?(1arguments?)587 call dealer.changePointsByprocedureName?(-1arguments?)588 elif playerOutcome is Outcome.losecondition? then589 call this.changePointsByprocedureName?(-1arguments?)590 call dealer.changePointsByprocedureName?(1arguments?)591 end if end procedure +procedure evaluateStatusname?(newCard as Cardparameter definitions?) 592 +if (this.cardCount() is 2) and (this.handTotal is 21)condition? then 593 assign this.statusvariableName? to Status.blackjackvalue or expression?594 elif (this.handTotal > 21) and (this.softAce)condition? then595 assign this.handTotalvariableName? to this.handTotal - 10value or expression?596 assign this.softAcevariableName? to falsevalue or expression?597 elif this.handTotal > 21condition? then598 assign this.statusvariableName? to Status.bustvalue or expression?599 elif this.handTotal is 21condition? then600 assign this.statusvariableName? to Status.standingvalue or expression?601 end if +if this.status isnt Status.activecondition? then 602 assign this.hasTurnvariableName? to falsevalue or expression?603 end if end procedure +procedure standname?(parameter definitionsparameter definitions?) 604 assign this.statusvariableName? to Status.standingvalue or expression?605 assign this.hasTurnvariableName? to falsevalue or expression?606 end procedure +procedure drawname?(parameter definitionsparameter definitions?) 607 variable newCardname? set to dealCard(random())value or expression?608 variable cardsname? set to this.cardsvalue or expression?609 call cards.appendprocedureName?(newCardarguments?)610 +if newCard.rank.equals("A")condition? then 611 call this.addAceprocedureName?(arguments?)612 else613 assign this.handTotalvariableName? to this.handTotal + rankValue()[newCard.rank]value or expression?614 end if call this.evaluateStatusprocedureName?(newCardarguments?)615 end procedure +procedure addAcename?(parameter definitionsparameter definitions?) 616 +if this.softAcecondition? then 617 assign this.handTotalvariableName? to this.handTotal + 1value or expression?618 else619 assign this.handTotalvariableName? to this.handTotal + 11value or expression?620 assign this.softAcevariableName? to truevalue or expression?621 end if end procedure +function cardCountname?(parameter definitionsparameter definitions?) returns IntType? 622 return this.cards.length()value or expression?623 end function +procedure changePointsByname?(amount as Intparameter definitions?) 624 assign this.pointsvariableName? to this.points + amountvalue or expression?625 end procedure abstract procedure newHandname?(parameter definitionsparameter definitions?)626 +private procedure newHandHelpername?(parameter definitionsparameter definitions?) 627 assign this.hasTurnvariableName? to falsevalue or expression?628 assign this.softAcevariableName? to falsevalue or expression?629 assign this.cardsvariableName? to new List<of Card>()value or expression?630 assign this.handTotalvariableName? to 0value or expression?631 assign this.statusvariableName? to Status.activevalue or expression?632 call this.drawprocedureName?(arguments?)633 call this.drawprocedureName?(arguments?)634 end procedure abstract function getMessagename?(parameter definitionsparameter definitions?) returns StringType?635 +private function getMessageHelpername?(parameter definitionsparameter definitions?) returns StringType? 636 variable msgname? set to ""value or expression?637 variable statusname? set to this.statusvalue or expression?638 +if this.hasTurncondition? then 639 assign msgvariableName? to msg + " - PLAYING"value or expression?640 elif status is Status.standingcondition? then641 assign msgvariableName? to msg + " - STANDING"value or expression?642 elif status is Status.blackjackcondition? then643 assign msgvariableName? to msg + " - BLACKJACK"value or expression?644 elif status is Status.bustcondition? then645 assign msgvariableName? to msg + " - BUST"value or expression?646 end if return msgvalue or expression?647 end function abstract procedure nextActionname?(dealerFaceCard as Cardparameter definitions?)648 end abstract class
+class PlayerName?(ABC) inheritance?: # abstract class649 namename?: strType? # property650 pointsname?: intType? # property651 cardsname?: list[Card]Type? # property652 handTotalname?: intType? # property653 softAcename?: boolType? # property654 statusname?: StatusType? # property655 hasTurnname?: boolType? # property656 +def startTurnname?(self: Player) -> None: # procedure method657 +if self.status == Status.activecondition?: 658 self.hasTurnvariableName? = Truevalue or expression? # assignment659 # end if # end procedure method +def determineOutcomeAndUpdatePointsname?(self: Player, dealer: Dealerparameter definitions?) -> None: # procedure method660 playerOutcomename? = determinePlayerOutcome(dealer, self)value or expression? # variable definition661 +if playerOutcome == Outcome.winDoublecondition?: 662 self.changePointsByprocedureName?(2arguments?) # procedure call663 dealer.changePointsByprocedureName?(-2arguments?) # procedure call664 elif playerOutcome == Outcome.wincondition?: # else if665 self.changePointsByprocedureName?(1arguments?) # procedure call666 dealer.changePointsByprocedureName?(-1arguments?) # procedure call667 elif playerOutcome == Outcome.losecondition?: # else if668 self.changePointsByprocedureName?(-1arguments?) # procedure call669 dealer.changePointsByprocedureName?(1arguments?) # procedure call670 # end if # end procedure method +def evaluateStatusname?(self: Player, newCard: Cardparameter definitions?) -> None: # procedure method671 +if (self.cardCount() == 2) and (self.handTotal == 21)condition?: 672 self.statusvariableName? = Status.blackjackvalue or expression? # assignment673 elif (self.handTotal > 21) and (self.softAce)condition?: # else if674 self.handTotalvariableName? = self.handTotal - 10value or expression? # assignment675 self.softAcevariableName? = Falsevalue or expression? # assignment676 elif self.handTotal > 21condition?: # else if677 self.statusvariableName? = Status.bustvalue or expression? # assignment678 elif self.handTotal == 21condition?: # else if679 self.statusvariableName? = Status.standingvalue or expression? # assignment680 # end if +if self.status != Status.activecondition?: 681 self.hasTurnvariableName? = Falsevalue or expression? # assignment682 # end if # end procedure method +def standname?(self: Player) -> None: # procedure method683 self.statusvariableName? = Status.standingvalue or expression? # assignment684 self.hasTurnvariableName? = Falsevalue or expression? # assignment685 # end procedure method +def drawname?(self: Player) -> None: # procedure method686 newCardname? = dealCard(random())value or expression? # variable definition687 cardsname? = self.cardsvalue or expression? # variable definition688 cards.appendprocedureName?(newCardarguments?) # procedure call689 +if newCard.rank.equals("A")condition?: 690 self.addAceprocedureName?(arguments?) # procedure call691 else:692 self.handTotalvariableName? = self.handTotal + rankValue()[newCard.rank]value or expression? # assignment693 # end if self.evaluateStatusprocedureName?(newCardarguments?) # procedure call694 # end procedure method +def addAcename?(self: Player) -> None: # procedure method695 +if self.softAcecondition?: 696 self.handTotalvariableName? = self.handTotal + 1value or expression? # assignment697 else:698 self.handTotalvariableName? = self.handTotal + 11value or expression? # assignment699 self.softAcevariableName? = Truevalue or expression? # assignment700 # end if # end procedure method +def cardCountname?(self: Player) -> intType?: # function method701 return self.cards.length()value or expression?702 # end function method +def changePointsByname?(self: Player, amount: intparameter definitions?) -> None: # procedure method703 self.pointsvariableName? = self.points + amountvalue or expression? # assignment704 # end procedure method @abstractmethod
def newHandname?(parameter definitionsparameter definitions?) -> None
  pass
# abstract procedure705
+def newHandHelpername?(self: Player) -> None: # private procedure method706 self.hasTurnvariableName? = Falsevalue or expression? # assignment707 self.softAcevariableName? = Falsevalue or expression? # assignment708 self.cardsvariableName? = list[Card]()value or expression? # assignment709 self.handTotalvariableName? = 0value or expression? # assignment710 self.statusvariableName? = Status.activevalue or expression? # assignment711 self.drawprocedureName?(arguments?) # procedure call712 self.drawprocedureName?(arguments?) # procedure call713 # end procedure method @abstractmethod
def getMessagename?(parameter definitionsparameter definitions?) -> strType?:
  pass
# abstract function714
+def getMessageHelpername?(self: Player) -> strType?: # private function method715 msgname? = ""value or expression? # variable definition716 statusname? = self.statusvalue or expression? # variable definition717 +if self.hasTurncondition?: 718 msgvariableName? = msg + " - PLAYING"value or expression? # assignment719 elif status == Status.standingcondition?: # else if720 msgvariableName? = msg + " - STANDING"value or expression? # assignment721 elif status == Status.blackjackcondition?: # else if722 msgvariableName? = msg + " - BLACKJACK"value or expression? # assignment723 elif status == Status.bustcondition?: # else if724 msgvariableName? = msg + " - BUST"value or expression? # assignment725 # end if return msgvalue or expression?726 # end function method @abstractmethod
def nextActionname?(dealerFaceCard: Cardparameter definitions?) -> None
  pass
# abstract procedure727
# end class
+abstract class PlayerName? inheritance? {728 public stringType? namename? {get; private set;} // property729 public intType? pointsname? {get; private set;} // property730 public List<Card>Type? cardsname? {get; private set;} // property731 public intType? handTotalname? {get; private set;} // property732 public boolType? softAcename? {get; private set;} // property733 public StatusType? statusname? {get; private set;} // property734 public boolType? hasTurnname? {get; private set;} // property735 +public void startTurnname?(parameter definitionsparameter definitions?) { // procedure method736 +if (this.status == Status.activecondition?) { 737 this.hasTurnvariableName? = truevalue or expression?; // assignment738 } // end if } // end procedure method +public void determineOutcomeAndUpdatePointsname?(Dealer dealerparameter definitions?) { // procedure method739 var playerOutcomename? = determinePlayerOutcome(dealer, this)value or expression?;740 +if (playerOutcome == Outcome.winDoublecondition?) { 741 this.changePointsByprocedureName?(2arguments?); // procedure call742 dealer.changePointsByprocedureName?(-2arguments?); // procedure call743 } else if (playerOutcome == Outcome.wincondition?) {744 this.changePointsByprocedureName?(1arguments?); // procedure call745 dealer.changePointsByprocedureName?(-1arguments?); // procedure call746 } else if (playerOutcome == Outcome.losecondition?) {747 this.changePointsByprocedureName?(-1arguments?); // procedure call748 dealer.changePointsByprocedureName?(1arguments?); // procedure call749 } // end if } // end procedure method +public void evaluateStatusname?(Card newCardparameter definitions?) { // procedure method750 +if ((this.cardCount() == 2) && (this.handTotal == 21)condition?) { 751 this.statusvariableName? = Status.blackjackvalue or expression?; // assignment752 } else if ((this.handTotal > 21) && (this.softAce)condition?) {753 this.handTotalvariableName? = this.handTotal - 10value or expression?; // assignment754 this.softAcevariableName? = falsevalue or expression?; // assignment755 } else if (this.handTotal > 21condition?) {756 this.statusvariableName? = Status.bustvalue or expression?; // assignment757 } else if (this.handTotal == 21condition?) {758 this.statusvariableName? = Status.standingvalue or expression?; // assignment759 } // end if +if (this.status != Status.activecondition?) { 760 this.hasTurnvariableName? = falsevalue or expression?; // assignment761 } // end if } // end procedure method +public void standname?(parameter definitionsparameter definitions?) { // procedure method762 this.statusvariableName? = Status.standingvalue or expression?; // assignment763 this.hasTurnvariableName? = falsevalue or expression?; // assignment764 } // end procedure method +public void drawname?(parameter definitionsparameter definitions?) { // procedure method765 var newCardname? = dealCard(random())value or expression?;766 var cardsname? = this.cardsvalue or expression?;767 cards.appendprocedureName?(newCardarguments?); // procedure call768 +if (newCard.rank.equals("A")condition?) { 769 this.addAceprocedureName?(arguments?); // procedure call770 } else {771 this.handTotalvariableName? = this.handTotal + rankValue()[newCard.rank]value or expression?; // assignment772 } // end if this.evaluateStatusprocedureName?(newCardarguments?); // procedure call773 } // end procedure method +public void addAcename?(parameter definitionsparameter definitions?) { // procedure method774 +if (this.softAcecondition?) { 775 this.handTotalvariableName? = this.handTotal + 1value or expression?; // assignment776 } else {777 this.handTotalvariableName? = this.handTotal + 11value or expression?; // assignment778 this.softAcevariableName? = truevalue or expression?; // assignment779 } // end if } // end procedure method +public intType? cardCountname?(parameter definitionsparameter definitions?) { // function method780 return this.cards.length()value or expression?;781 } // end function method +public void changePointsByname?(int amountparameter definitions?) { // procedure method782 this.pointsvariableName? = this.points + amountvalue or expression?; // assignment783 } // end procedure method abstract void newHandname?(parameter definitionsparameter definitions?); // abstract procedure784 +protected void newHandHelpername?(parameter definitionsparameter definitions?) { // private procedure method785 this.hasTurnvariableName? = falsevalue or expression?; // assignment786 this.softAcevariableName? = falsevalue or expression?; // assignment787 this.cardsvariableName? = new List<Card>()value or expression?; // assignment788 this.handTotalvariableName? = 0value or expression?; // assignment789 this.statusvariableName? = Status.activevalue or expression?; // assignment790 this.drawprocedureName?(arguments?); // procedure call791 this.drawprocedureName?(arguments?); // procedure call792 } // end procedure method abstract stringType? getMessagename?(parameter definitionsparameter definitions?); // abstract function793 +protected stringType? getMessageHelpername?(parameter definitionsparameter definitions?) { // private function method794 var msgname? = ""value or expression?;795 var statusname? = this.statusvalue or expression?;796 +if (this.hasTurncondition?) { 797 msgvariableName? = msg + " - PLAYING"value or expression?; // assignment798 } else if (status == Status.standingcondition?) {799 msgvariableName? = msg + " - STANDING"value or expression?; // assignment800 } else if (status == Status.blackjackcondition?) {801 msgvariableName? = msg + " - BLACKJACK"value or expression?; // assignment802 } else if (status == Status.bustcondition?) {803 msgvariableName? = msg + " - BUST"value or expression?; // assignment804 } // end if return msgvalue or expression?;805 } // end function method abstract void nextActionname?(Card dealerFaceCardparameter definitions?); // abstract procedure806 } // end class
+MustInherit Class PlayerName? inheritance?807 Property namename? As StringType?808 Property pointsname? As IntegerType?809 Property cardsname? As List(Of Card)Type?810 Property handTotalname? As IntegerType?811 Property softAcename? As BooleanType?812 Property statusname? As StatusType?813 Property hasTurnname? As BooleanType?814 +Sub startTurnname?(parameter definitionsparameter definitions?) ' procedure method815 +If Me.status = Status.activecondition? Then 816 Me.hasTurnvariableName? = Truevalue or expression? ' assignment817 End If End Sub +Sub determineOutcomeAndUpdatePointsname?(dealer As Dealerparameter definitions?) ' procedure method818 Dim playerOutcomename? = determinePlayerOutcome(dealer, Me)value or expression? ' variable definition819 +If playerOutcome = Outcome.winDoublecondition? Then 820 Me.changePointsByprocedureName?(2arguments?) ' procedure call821 dealer.changePointsByprocedureName?(-2arguments?) ' procedure call822 ElseIf playerOutcome = Outcome.wincondition? Then823 Me.changePointsByprocedureName?(1arguments?) ' procedure call824 dealer.changePointsByprocedureName?(-1arguments?) ' procedure call825 ElseIf playerOutcome = Outcome.losecondition? Then826 Me.changePointsByprocedureName?(-1arguments?) ' procedure call827 dealer.changePointsByprocedureName?(1arguments?) ' procedure call828 End If End Sub +Sub evaluateStatusname?(newCard As Cardparameter definitions?) ' procedure method829 +If (Me.cardCount() = 2) And (Me.handTotal = 21)condition? Then 830 Me.statusvariableName? = Status.blackjackvalue or expression? ' assignment831 ElseIf (Me.handTotal > 21) And (Me.softAce)condition? Then832 Me.handTotalvariableName? = Me.handTotal - 10value or expression? ' assignment833 Me.softAcevariableName? = Falsevalue or expression? ' assignment834 ElseIf Me.handTotal > 21condition? Then835 Me.statusvariableName? = Status.bustvalue or expression? ' assignment836 ElseIf Me.handTotal = 21condition? Then837 Me.statusvariableName? = Status.standingvalue or expression? ' assignment838 End If +If Me.status <> Status.activecondition? Then 839 Me.hasTurnvariableName? = Falsevalue or expression? ' assignment840 End If End Sub +Sub standname?(parameter definitionsparameter definitions?) ' procedure method841 Me.statusvariableName? = Status.standingvalue or expression? ' assignment842 Me.hasTurnvariableName? = Falsevalue or expression? ' assignment843 End Sub +Sub drawname?(parameter definitionsparameter definitions?) ' procedure method844 Dim newCardname? = dealCard(random())value or expression? ' variable definition845 Dim cardsname? = Me.cardsvalue or expression? ' variable definition846 cards.appendprocedureName?(newCardarguments?) ' procedure call847 +If newCard.rank.equals("A")condition? Then 848 Me.addAceprocedureName?(arguments?) ' procedure call849 Else850 Me.handTotalvariableName? = Me.handTotal + rankValue()(newCard.rank)value or expression? ' assignment851 End If Me.evaluateStatusprocedureName?(newCardarguments?) ' procedure call852 End Sub +Sub addAcename?(parameter definitionsparameter definitions?) ' procedure method853 +If Me.softAcecondition? Then 854 Me.handTotalvariableName? = Me.handTotal + 1value or expression? ' assignment855 Else856 Me.handTotalvariableName? = Me.handTotal + 11value or expression? ' assignment857 Me.softAcevariableName? = Truevalue or expression? ' assignment858 End If End Sub +Function cardCountname?(parameter definitionsparameter definitions?) As IntegerType? 859 Return Me.cards.length()value or expression?860 End Function +Sub changePointsByname?(amount As Integerparameter definitions?) ' procedure method861 Me.pointsvariableName? = Me.points + amountvalue or expression? ' assignment862 End Sub MustOverride Sub newHandname?(parameter definitionsparameter definitions?)863 +Protected Sub newHandHelpername?(parameter definitionsparameter definitions?) ' private procedure method864 Me.hasTurnvariableName? = Falsevalue or expression? ' assignment865 Me.softAcevariableName? = Falsevalue or expression? ' assignment866 Me.cardsvariableName? = New List(Of Card)()value or expression? ' assignment867 Me.handTotalvariableName? = 0value or expression? ' assignment868 Me.statusvariableName? = Status.activevalue or expression? ' assignment869 Me.drawprocedureName?(arguments?) ' procedure call870 Me.drawprocedureName?(arguments?) ' procedure call871 End Sub MustOverride Function getMessagename?(parameter definitionsparameter definitions?) As StringType?872 +Protected Function getMessageHelpername?(parameter definitionsparameter definitions?) As StringType? 873 Dim msgname? = ""value or expression? ' variable definition874 Dim statusname? = Me.statusvalue or expression? ' variable definition875 +If Me.hasTurncondition? Then 876 msgvariableName? = msg + " - PLAYING"value or expression? ' assignment877 ElseIf status = Status.standingcondition? Then878 msgvariableName? = msg + " - STANDING"value or expression? ' assignment879 ElseIf status = Status.blackjackcondition? Then880 msgvariableName? = msg + " - BLACKJACK"value or expression? ' assignment881 ElseIf status = Status.bustcondition? Then882 msgvariableName? = msg + " - BUST"value or expression? ' assignment883 End If Return msgvalue or expression?884 End Function MustOverride Sub nextActionname?(dealerFaceCard As Cardparameter definitions?)885 End Class
+abstract class PlayerName? inheritance? {886 public StringType? namename?; // property887 public intType? pointsname?; // property888 public List<Card>Type? cardsname?; // property889 public intType? handTotalname?; // property890 public booleanType? softAcename?; // property891 public StatusType? statusname?; // property892 public booleanType? hasTurnname?; // property893 +public void startTurnname?(parameter definitionsparameter definitions?) { // procedure method894 +if (this.status == Status.activecondition?) { 895 this.hasTurnvariableName? = truevalue or expression?; // assignment896 } // end if } // end procedure method +public void determineOutcomeAndUpdatePointsname?(Dealer dealerparameter definitions?) { // procedure method897 var playerOutcomename? = determinePlayerOutcome(dealer, this)value or expression?;898 +if (playerOutcome == Outcome.winDoublecondition?) { 899 this.changePointsByprocedureName?(2arguments?); // procedure call900 dealer.changePointsByprocedureName?(-2arguments?); // procedure call901 } else if (playerOutcome == Outcome.wincondition?) {902 this.changePointsByprocedureName?(1arguments?); // procedure call903 dealer.changePointsByprocedureName?(-1arguments?); // procedure call904 } else if (playerOutcome == Outcome.losecondition?) {905 this.changePointsByprocedureName?(-1arguments?); // procedure call906 dealer.changePointsByprocedureName?(1arguments?); // procedure call907 } // end if } // end procedure method +public void evaluateStatusname?(Card newCardparameter definitions?) { // procedure method908 +if ((this.cardCount() == 2) && (this.handTotal == 21)condition?) { 909 this.statusvariableName? = Status.blackjackvalue or expression?; // assignment910 } else if ((this.handTotal > 21) && (this.softAce)condition?) {911 this.handTotalvariableName? = this.handTotal - 10value or expression?; // assignment912 this.softAcevariableName? = falsevalue or expression?; // assignment913 } else if (this.handTotal > 21condition?) {914 this.statusvariableName? = Status.bustvalue or expression?; // assignment915 } else if (this.handTotal == 21condition?) {916 this.statusvariableName? = Status.standingvalue or expression?; // assignment917 } // end if +if (this.status != Status.activecondition?) { 918 this.hasTurnvariableName? = falsevalue or expression?; // assignment919 } // end if } // end procedure method +public void standname?(parameter definitionsparameter definitions?) { // procedure method920 this.statusvariableName? = Status.standingvalue or expression?; // assignment921 this.hasTurnvariableName? = falsevalue or expression?; // assignment922 } // end procedure method +public void drawname?(parameter definitionsparameter definitions?) { // procedure method923 var newCardname? = dealCard(random())value or expression?;924 var cardsname? = this.cardsvalue or expression?;925 cards.appendprocedureName?(newCardarguments?); // procedure call926 +if (newCard.rank.equals("A")condition?) { 927 this.addAceprocedureName?(arguments?); // procedure call928 } else {929 this.handTotalvariableName? = this.handTotal + rankValue()[newCard.rank]value or expression?; // assignment930 } // end if this.evaluateStatusprocedureName?(newCardarguments?); // procedure call931 } // end procedure method +public void addAcename?(parameter definitionsparameter definitions?) { // procedure method932 +if (this.softAcecondition?) { 933 this.handTotalvariableName? = this.handTotal + 1value or expression?; // assignment934 } else {935 this.handTotalvariableName? = this.handTotal + 11value or expression?; // assignment936 this.softAcevariableName? = truevalue or expression?; // assignment937 } // end if } // end procedure method +public intType? cardCountname?(parameter definitionsparameter definitions?) { // function method938 return this.cards.length()value or expression?;939 } // end function method +public void changePointsByname?(int amountparameter definitions?) { // procedure method940 this.pointsvariableName? = this.points + amountvalue or expression?; // assignment941 } // end procedure method abstract void newHandname?(parameter definitionsparameter definitions?); // abstract procedure942 +protected void newHandHelpername?(parameter definitionsparameter definitions?) { // private procedure method943 this.hasTurnvariableName? = falsevalue or expression?; // assignment944 this.softAcevariableName? = falsevalue or expression?; // assignment945 this.cardsvariableName? = new List<Card>()value or expression?; // assignment946 this.handTotalvariableName? = 0value or expression?; // assignment947 this.statusvariableName? = Status.activevalue or expression?; // assignment948 this.drawprocedureName?(arguments?); // procedure call949 this.drawprocedureName?(arguments?); // procedure call950 } // end procedure method abstract StringType? getMessagename?(parameter definitionsparameter definitions?); // abstract function951 +protected StringType? getMessageHelpername?(parameter definitionsparameter definitions?) { // private function method952 var msgname? = ""value or expression?;953 var statusname? = this.statusvalue or expression?;954 +if (this.hasTurncondition?) { 955 msgvariableName? = msg + " - PLAYING"value or expression?; // assignment956 } else if (status == Status.standingcondition?) {957 msgvariableName? = msg + " - STANDING"value or expression?; // assignment958 } else if (status == Status.blackjackcondition?) {959 msgvariableName? = msg + " - BLACKJACK"value or expression?; // assignment960 } else if (status == Status.bustcondition?) {961 msgvariableName? = msg + " - BUST"value or expression?; // assignment962 } // end if return msgvalue or expression?;963 } // end function method abstract void nextActionname?(Card dealerFaceCardparameter definitions?); // abstract procedure964 } // end class

What you need to know about an 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 Code does not parse as Elan.Code does not parse as Elan.Code does not parse as Elan.Code does not parse as Elan.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?)20self.newHandHelperprocedureName?(arguments?) # procedure call21this.newHandHelperprocedureName?(arguments?); // procedure call22Me.newHandHelperprocedureName?(arguments?) ' procedure call23this.newHandHelperprocedureName?(arguments?); // procedure call24.
  • The subclass DealerDealerDealerDealerDealer defines a more complex implementation of newHand with five instructions, but these include call this.newHandHelperprocedureName?(arguments?)25self.newHandHelperprocedureName?(arguments?) # procedure call26this.newHandHelperprocedureName?(arguments?); // procedure call27Me.newHandHelperprocedureName?(arguments?) ' procedure call28this.newHandHelperprocedureName?(arguments?); // procedure call29 to do the common part of the task.

Statement Instructions

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

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 paradigm is set to object-oriented (or functional - which includes all OOP capabilities).

Constructor

Examples of a constructor

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

+class SquareName? inheritance?965 +constructor(x as Int, y as Intparameter definitions?) 966 assign this.xvariableName? to xvalue or expression?967 assign this.yvariableName? to yvalue or expression?968 end constructor # other code not showncomment? +function toStringname?(parameter definitionsparameter definitions?) returns StringType? 969 return "{this.x}, {this.y}"value or expression?970 end function end class
+class SquareName? inheritance?: # concrete class971 +def __init__(self: Square, x: int, y: intparameter definitions?) -> None: 972 self.xvariableName? = xvalue or expression? # assignment973 self.yvariableName? = yvalue or expression? # assignment974 # end constructor # other code not showncomment? +def toStringname?(self: Square) -> strType?: # function method975 return "{this.x}, {this.y}"value or expression?976 # end function method # end class
+class SquareName? inheritance? {977 +public Square(int x, int yparameter definitions?) { 978 this.xvariableName? = xvalue or expression?; // assignment979 this.yvariableName? = yvalue or expression?; // assignment980 } // end constructor // other code not showncomment? +public stringType? toStringname?(parameter definitionsparameter definitions?) { // function method981 return "{this.x}, {this.y}"value or expression?;982 } // end function method } // end class
+Class SquareName? inheritance?983 +Sub New(x As Integer, y As Integerparameter definitions?) 984 Me.xvariableName? = xvalue or expression? ' assignment985 Me.yvariableName? = yvalue or expression? ' assignment986 End Sub ' other code not showncomment? +Function toStringname?(parameter definitionsparameter definitions?) As StringType? 987 Return "{this.x}, {this.y}"value or expression?988 End Function End Class
+class SquareName? inheritance? {989 +public Square(int x, int yparameter definitions?) { 990 this.xvariableName? = xvalue or expression?; // assignment991 this.yvariableName? = yvalue or expression?; // assignment992 } // end constructor // other code not showncomment? +public StringType? toStringname?(parameter definitionsparameter definitions?) { // function method993 return "{this.x}, {this.y}"value or expression?;994 } // end function method } // end 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:

+class GameName? inheritance?995 +constructor(dealerStartPoints as Intparameter definitions?) 996 assign this.dealervariableName? to new Dealer(dealerStartPoints)value or expression?997 assign this.playersvariableName? to new List<of Player>()value or expression?998 assign this.messagevariableName? to ""value or expression?999 end constructor #  other code not showncomment? +function toStringname?(parameter definitionsparameter definitions?) returns StringType? 1000 return "a Game"value or expression?1001 end function end class
+class GameName? inheritance?: # concrete class1002 +def __init__(self: Game, dealerStartPoints: intparameter definitions?) -> None: 1003 self.dealervariableName? = Dealer(dealerStartPoints)value or expression? # assignment1004 self.playersvariableName? = list[Player]()value or expression? # assignment1005 self.messagevariableName? = ""value or expression? # assignment1006 # end constructor #  other code not showncomment? +def toStringname?(self: Game) -> strType?: # function method1007 return "a Game"value or expression?1008 # end function method # end class
+class GameName? inheritance? {1009 +public Game(int dealerStartPointsparameter definitions?) { 1010 this.dealervariableName? = new Dealer(dealerStartPoints)value or expression?; // assignment1011 this.playersvariableName? = new List<Player>()value or expression?; // assignment1012 this.messagevariableName? = ""value or expression?; // assignment1013 } // end constructor //  other code not showncomment? +public stringType? toStringname?(parameter definitionsparameter definitions?) { // function method1014 return "a Game"value or expression?;1015 } // end function method } // end class
+Class GameName? inheritance?1016 +Sub New(dealerStartPoints As Integerparameter definitions?) 1017 Me.dealervariableName? = New Dealer(dealerStartPoints)value or expression? ' assignment1018 Me.playersvariableName? = New List(Of Player)()value or expression? ' assignment1019 Me.messagevariableName? = ""value or expression? ' assignment1020 End Sub '  other code not showncomment? +Function toStringname?(parameter definitionsparameter definitions?) As StringType? 1021 Return "a Game"value or expression?1022 End Function End Class
+class GameName? inheritance? {1023 +public Game(int dealerStartPointsparameter definitions?) { 1024 this.dealervariableName? = new Dealer(dealerStartPoints)value or expression?; // assignment1025 this.playersvariableName? = new List<Player>()value or expression?; // assignment1026 this.messagevariableName? = ""value or expression?; // assignment1027 } // end constructor //  other code not showncomment? +public StringType? toStringname?(parameter definitionsparameter definitions?) { // function method1028 return "a Game"value or expression?;1029 } // end function method } // end class

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 constructor

  • 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 – assign this.xvariableName? to xvalue or expression?30self.xvariableName? = xvalue or expression? # assignment31this.xvariableName? = xvalue or expression?; // assignment32Me.xvariableName? = xvalue or expression? ' assignment33this.xvariableName? = xvalue or expression?; // assignment34 – 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 a property

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

Code does not parse as Elan.
Code does not parse as Elan.
Code does not parse as Elan.
Code does not parse as Elan.
Code does not parse as Elan.
Code does not parse as Elan.
Code does not parse as Elan.
Code does not parse as Elan.
Code does not parse as Elan.
Code does not parse as Elan.
Code does not parse as Elan.
Code does not parse as Elan.
Code does not parse as Elan.
Code does not parse as Elan.
Code does not parse as Elan.

What you need to know about a property

  • 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 BooleanboolboolBooleanboolean. 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 1033 variable tTomname? set to new Teacher()value or expression?1034 variable pPetename? set to new Pupil()value or expression?1035 +if pPete.tutor.hasValue()condition? then 1036 print(pPete.tutorarguments?)1037 end if print(parguments?)1038 end main
+def main() -> None: 1039 tTomname? = Teacher()value or expression? # variable definition1040 pPetename? = Pupil()value or expression? # variable definition1041 +if pPete.tutor.hasValue()condition?: 1042 print(pPete.tutorarguments?)1043 # end if print(parguments?)1044 # end main
+static void main() { 1045 var tTomname? = new Teacher()value or expression?;1046 var pPetename? = new Pupil()value or expression?;1047 +if (pPete.tutor.hasValue()condition?) { 1048 Console.WriteLine(pPete.tutorarguments?); // print statement1049 } // end if Console.WriteLine(parguments?); // print statement1050 } // end main
+Sub main() 1051 Dim tTomname? = New Teacher()value or expression? ' variable definition1052 Dim pPetename? = New Pupil()value or expression? ' variable definition1053 +If pPete.tutor.hasValue()condition? Then 1054 Console.WriteLine(pPete.tutorarguments?) ' print statement1055 End If Console.WriteLine(parguments?) ' print statement1056 End Sub
+static void main() { 1057 var tTomname? = new Teacher()value or expression?;1058 var pPetename? = new Pupil()value or expression?;1059 +if (pPete.tutor.hasValue()condition?) { 1060 System.out.println(pPete.tutorarguments?); // print statement1061 } // end if System.out.println(parguments?); // print statement1062 } // end main

Function method

Examples of a function method

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

+function isHaltedname?(parameter definitionsparameter definitions?) returns BooleanType? 1063 return this.currentState.equals(this.haltState)value or expression?1064 end function
+def isHaltedname?(parameter definitionsparameter definitions?) -> boolType?: # function1065 return self.currentState.equals(self.haltState)value or expression?1066 # end function
+static boolType? isHaltedname?(parameter definitionsparameter definitions?) { // function1067 return this.currentState.equals(this.haltState)value or expression?;1068 } // end function
+Function isHaltedname?(parameter definitionsparameter definitions?) As BooleanType? 1069 Return Me.currentState.equals(Me.haltState)value or expression?1070 End Function
+static booleanType? isHaltedname?(parameter definitionsparameter definitions?) { // function1071 return this.currentState.equals(this.haltState)value or expression?;1072 } // end function

What you need to know about a function method

  • 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 a procedure method

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

+procedure setTapename?(tape as Stringparameter definitions?) 1073 assign this.tapevariableName? to tapevalue or expression?1074 end procedure
+def setTapename?(tape: strparameter definitions?) -> None: # procedure1075 self.tapevariableName? = tapevalue or expression? # assignment1076 # end procedure
+static void setTapename?(string tapeparameter definitions?) { // procedure1077 this.tapevariableName? = tapevalue or expression?; // assignment1078 } // end procedure
+Sub setTapename?(tape As Stringparameter definitions?) ' procedure1079 Me.tapevariableName? = tapevalue or expression? ' assignment1080 End Sub
+static void setTapename?(String tapeparameter definitions?) { // procedure1081 this.tapevariableName? = tapevalue or expression?; // assignment1082 } // end 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 singleStepname?(parameter definitionsparameter definitions?) 1083 variable rulename? set to this.findMatchingRule()value or expression?1084 call this.executeprocedureName?(rulearguments?)1085 end procedure
+def singleStepname?(parameter definitionsparameter definitions?) -> None: # procedure1086 rulename? = self.findMatchingRule()value or expression? # variable definition1087 self.executeprocedureName?(rulearguments?) # procedure call1088 # end procedure
+static void singleStepname?(parameter definitionsparameter definitions?) { // procedure1089 var rulename? = this.findMatchingRule()value or expression?;1090 this.executeprocedureName?(rulearguments?); // procedure call1091 } // end procedure
+Sub singleStepname?(parameter definitionsparameter definitions?) ' procedure1092 Dim rulename? = Me.findMatchingRule()value or expression? ' variable definition1093 Me.executeprocedureName?(rulearguments?) ' procedure call1094 End Sub
+static void singleStepname?(parameter definitionsparameter definitions?) { // procedure1095 var rulename? = this.findMatchingRule()value or expression?;1096 this.executeprocedureName?(rulearguments?); // procedure call1097 } // end 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 a procedure method

  • 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 procedure call/b>) 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?)35self.methodNameprocedureName?(arguments?) # procedure call36this.methodNameprocedureName?(arguments?); // procedure call37Me.methodNameprocedureName?(arguments?) ' procedure call38this.methodNameprocedureName?(arguments?); // procedure call39.

Abstract function

Examples of an abstract function

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

Code does not parse as Elan.
Code does not parse as Elan.
Code does not parse as Elan.
Code does not parse as Elan.
Code does not parse as Elan.

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

+function getMessagename?(parameter definitionsparameter definitions?) returns StringType? 1098 variable msgname? set to ""value or expression?1099 +if this.hasPlayedcondition? then 1100 assign msgvariableName? to this.getMessageHelper() + $" - hand total: {this.handTotal}"value or expression?1101 end if return msgvalue or expression?1102 end function
+def getMessagename?(parameter definitionsparameter definitions?) -> strType?: # function1103 msgname? = ""value or expression? # variable definition1104 +if self.hasPlayedcondition?: 1105 msgvariableName? = self.getMessageHelper() + f" - hand total: {self.handTotal}"value or expression? # assignment1106 # end if return msgvalue or expression?1107 # end function
+static stringType? getMessagename?(parameter definitionsparameter definitions?) { // function1108 var msgname? = ""value or expression?;1109 +if (this.hasPlayedcondition?) { 1110 msgvariableName? = this.getMessageHelper() + $" - hand total: {this.handTotal}"value or expression?; // assignment1111 } // end if return msgvalue or expression?;1112 } // end function
+Function getMessagename?(parameter definitionsparameter definitions?) As StringType? 1113 Dim msgname? = ""value or expression? ' variable definition1114 +If Me.hasPlayedcondition? Then 1115 msgvariableName? = Me.getMessageHelper() + $" - hand total: {Me.handTotal}"value or expression? ' assignment1116 End If Return msgvalue or expression?1117 End Function
+static StringType? getMessagename?(parameter definitionsparameter definitions?) { // function1118 var msgname? = ""value or expression?;1119 +if (this.hasPlayedcondition?) { 1120 msgvariableName? = this.getMessageHelper() + String.format(" - hand total: %", this.handTotal)value or expression?; // assignment1121 } // end if return msgvalue or expression?;1122 } // end 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 an abstract function

  • 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 an abstract procedure

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

Code does not parse as Elan.
Code does not parse as Elan.
Code does not parse as Elan.
Code does not parse as Elan.
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 nextActionname?(faceCard as Cardparameter definitions?) 1123 +if this.handTotal < 17condition? then 1124 call this.drawprocedureName?(arguments?)1125 else1126 call this.standprocedureName?(arguments?)1127 end if end procedure
+def nextActionname?(faceCard: Cardparameter definitions?) -> None: # procedure1128 +if self.handTotal < 17condition?: 1129 self.drawprocedureName?(arguments?) # procedure call1130 else:1131 self.standprocedureName?(arguments?) # procedure call1132 # end if # end procedure
+static void nextActionname?(Card faceCardparameter definitions?) { // procedure1133 +if (this.handTotal < 17condition?) { 1134 this.drawprocedureName?(arguments?); // procedure call1135 } else {1136 this.standprocedureName?(arguments?); // procedure call1137 } // end if } // end procedure
+Sub nextActionname?(faceCard As Cardparameter definitions?) ' procedure1138 +If Me.handTotal < 17condition? Then 1139 Me.drawprocedureName?(arguments?) ' procedure call1140 Else1141 Me.standprocedureName?(arguments?) ' procedure call1142 End If End Sub
+static void nextActionname?(Card faceCardparameter definitions?) { // procedure1143 +if (this.handTotal < 17condition?) { 1144 this.drawprocedureName?(arguments?); // procedure call1145 } else {1146 this.standprocedureName?(arguments?); // procedure call1147 } // end if } // end procedure

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

+procedure nextActionname?(dealerFaceCard as Cardparameter definitions?) 1148 variable keyname? set to ""value or expression?1149 call clearKeyBufferprocedureName?(arguments?)1150 +while key.equals("")condition? 1151 assign keyvariableName? to waitForKey()value or expression?1152 +if key.equals("d")condition? then 1153 call this.drawprocedureName?(arguments?)1154 elif key.equals("s")condition? then1155 call this.standprocedureName?(arguments?)1156 else1157 assign keyvariableName? to ""value or expression?1158 end if end while end procedure
+def nextActionname?(dealerFaceCard: Cardparameter definitions?) -> None: # procedure1159 keyname? = ""value or expression? # variable definition1160 clearKeyBufferprocedureName?(arguments?) # procedure call1161 +while key.equals("")condition?: 1162 keyvariableName? = waitForKey()value or expression? # assignment1163 +if key.equals("d")condition?: 1164 self.drawprocedureName?(arguments?) # procedure call1165 elif key.equals("s")condition?: # else if1166 self.standprocedureName?(arguments?) # procedure call1167 else:1168 keyvariableName? = ""value or expression? # assignment1169 # end if # end while # end procedure
+static void nextActionname?(Card dealerFaceCardparameter definitions?) { // procedure1170 var keyname? = ""value or expression?;1171 clearKeyBufferprocedureName?(arguments?); // procedure call1172 +while (key.equals("")condition?) { 1173 keyvariableName? = waitForKey()value or expression?; // assignment1174 +if (key.equals("d")condition?) { 1175 this.drawprocedureName?(arguments?); // procedure call1176 } else if (key.equals("s")condition?) {1177 this.standprocedureName?(arguments?); // procedure call1178 } else {1179 keyvariableName? = ""value or expression?; // assignment1180 } // end if } // end while } // end procedure
+Sub nextActionname?(dealerFaceCard As Cardparameter definitions?) ' procedure1181 Dim keyname? = ""value or expression? ' variable definition1182 clearKeyBufferprocedureName?(arguments?) ' procedure call1183 +While key.equals("")condition? 1184 keyvariableName? = waitForKey()value or expression? ' assignment1185 +If key.equals("d")condition? Then 1186 Me.drawprocedureName?(arguments?) ' procedure call1187 ElseIf key.equals("s")condition? Then1188 Me.standprocedureName?(arguments?) ' procedure call1189 Else1190 keyvariableName? = ""value or expression? ' assignment1191 End If End While End Sub
+static void nextActionname?(Card dealerFaceCardparameter definitions?) { // procedure1192 var keyname? = ""value or expression?;1193 clearKeyBufferprocedureName?(arguments?); // procedure call1194 +while (key.equals("")condition?) { 1195 keyvariableName? = waitForKey()value or expression?; // assignment1196 +if (key.equals("d")condition?) { 1197 this.drawprocedureName?(arguments?); // procedure call1198 } else if (key.equals("s")condition?) {1199 this.standprocedureName?(arguments?); // procedure call1200 } else {1201 keyvariableName? = ""value or expression?; // assignment1202 } // end if } // end while } // end procedure

What you need to know about an abstract procedure

  • 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