| 
									
										
										
										
											2025-02-16 16:15:50 +01:00
										 |  |  | *vim9class.txt*	For Vim version 9.1.  Last change: 2025 Feb 16 | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		  VIM REFERENCE MANUAL	  by Bram Moolenaar | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-24 11:01:23 +01:00
										 |  |  | Vim9 classes, objects, interfaces, types and enums.		*vim9-class* | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 1.  Overview			|Vim9-class-overview| | 
					
						
							|  |  |  | 2.  A simple class		|Vim9-simple-class| | 
					
						
							| 
									
										
										
										
											2023-09-18 19:56:49 +02:00
										 |  |  | 3.  Class variables and methods	|Vim9-class-member| | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | 4.  Using an abstract class	|Vim9-abstract-class| | 
					
						
							|  |  |  | 5.  Using an interface		|Vim9-using-interface| | 
					
						
							|  |  |  | 6.  More class details		|Vim9-class| | 
					
						
							|  |  |  | 7.  Type definition		|Vim9-type| | 
					
						
							|  |  |  | 8.  Enum			|Vim9-enum| | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 9.  Rationale | 
					
						
							|  |  |  | 10. To be done later | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ============================================================================== | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 1. Overview					*Vim9-class-overview* | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The fancy term is "object-oriented programming".  You can find lots of study | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | material on this subject.  Here we document what |Vim9| script provides, | 
					
						
							|  |  |  | assuming you know the basics already.  Added are helpful hints about how to | 
					
						
							| 
									
										
										
										
											2023-10-21 11:59:42 +02:00
										 |  |  | use this functionality effectively.  Vim9 classes and objects cannot be used | 
					
						
							|  |  |  | in legacy Vim scripts and legacy functions. | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | The basic item is an object: | 
					
						
							|  |  |  | - An object stores state.  It contains one or more variables that can each | 
					
						
							|  |  |  |   have a value. | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | - An object provides functions that use and manipulate its state.  These | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  |   functions are invoked "on the object", which is what sets it apart from the | 
					
						
							|  |  |  |   traditional separation of data and code that manipulates the data. | 
					
						
							|  |  |  | - An object has a well defined interface, with typed member variables and | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  |   methods. | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | - Objects are created from a class and all objects have the same interface. | 
					
						
							|  |  |  |   This does not change at runtime, it is not dynamic. | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | An object can only be created by a class.  A class provides: | 
					
						
							|  |  |  | - A new() method, the constructor, which returns an object for the class. | 
					
						
							|  |  |  |   This method is invoked on the class name: MyClass.new(). | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | - State shared by all objects of the class: class variables (class members). | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | - A hierarchy of classes, with super-classes and sub-classes, inheritance. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | An interface is used to specify properties of an object: | 
					
						
							|  |  |  | - An object can declare several interfaces that it implements. | 
					
						
							|  |  |  | - Different objects implementing the same interface can be used the same way. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The class hierarchy allows for single inheritance.  Otherwise interfaces are | 
					
						
							|  |  |  | to be used where needed. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Class modeling ~ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | You can model classes any way you like.  Keep in mind what you are building, | 
					
						
							|  |  |  | don't try to model the real world.  This can be confusing, especially because | 
					
						
							|  |  |  | teachers use real-world objects to explain class relations and you might think | 
					
						
							|  |  |  | your model should therefore reflect the real world.  It doesn't!  The model | 
					
						
							|  |  |  | should match your purpose. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | Keep in mind that composition (an object contains other objects) is often | 
					
						
							|  |  |  | better than inheritance (an object extends another object).  Don't waste time | 
					
						
							|  |  |  | trying to find the optimal class model.  Or waste time discussing whether a | 
					
						
							|  |  |  | square is a rectangle or that a rectangle is a square.  It doesn't matter. | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ============================================================================== | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 2.  A simple class				*Vim9-simple-class* | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | Let's start with a simple example: a class that stores a text position (see | 
					
						
							|  |  |  | below for how to do this more efficiently): > | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	class TextPosition | 
					
						
							| 
									
										
										
										
											2023-12-14 20:26:26 +01:00
										 |  |  | 	   var lnum: number | 
					
						
							|  |  |  | 	   var col: number | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	   def new(lnum: number, col: number) | 
					
						
							|  |  |  | 	      this.lnum = lnum | 
					
						
							|  |  |  | 	      this.col = col | 
					
						
							|  |  |  | 	   enddef | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	   def SetLnum(lnum: number) | 
					
						
							|  |  |  | 	      this.lnum = lnum | 
					
						
							|  |  |  | 	   enddef | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	   def SetCol(col: number) | 
					
						
							|  |  |  | 	      this.col = col | 
					
						
							|  |  |  | 	   enddef | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	   def SetPosition(lnum: number, col: number) | 
					
						
							|  |  |  | 	      this.lnum = lnum | 
					
						
							|  |  |  | 	      this.col = col | 
					
						
							|  |  |  | 	   enddef | 
					
						
							|  |  |  | 	 endclass | 
					
						
							| 
									
										
										
										
											2022-12-11 15:53:04 +00:00
										 |  |  | <							*object* *Object* | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | You can create an object from this class with the new() method: > | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var pos = TextPosition.new(1, 1) | 
					
						
							| 
									
										
										
										
											2023-12-21 08:34:15 -08:00
										 |  |  | < | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | The object variables "lnum" and "col" can be accessed directly: > | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	echo $'The text position is ({pos.lnum}, {pos.col})' | 
					
						
							| 
									
										
										
										
											2024-01-01 20:50:51 +01:00
										 |  |  | <						    *E1317* *E1327* *:this* | 
					
						
							| 
									
										
										
										
											2023-12-21 08:34:15 -08:00
										 |  |  | If you have been using other object-oriented languages you will notice that in | 
					
						
							| 
									
										
										
										
											2024-01-07 17:52:10 +03:00
										 |  |  | Vim, within a class definition, the declared object members are consistently | 
					
						
							|  |  |  | referred to with the "this." prefix.  This is different from languages like | 
					
						
							|  |  |  | Java and TypeScript.  The naming convention makes the object members easy to | 
					
						
							|  |  |  | spot.  Also, when a variable does not have the "this." prefix you know it is | 
					
						
							|  |  |  | not an object variable. | 
					
						
							| 
									
										
										
										
											2023-12-21 08:34:15 -08:00
										 |  |  | 								*E1411* | 
					
						
							|  |  |  | From outside the class definition, access an object's methods and variables by | 
					
						
							|  |  |  | using the object name followed by a dot following by the member: > | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pos.lnum | 
					
						
							| 
									
										
										
										
											2024-01-07 17:52:10 +03:00
										 |  |  | 	pos.SetCol(10) | 
					
						
							| 
									
										
										
										
											2023-12-21 08:34:15 -08:00
										 |  |  | < | 
					
						
							|  |  |  | 							*E1405* *E1406* | 
					
						
							|  |  |  | A class name cannot be used as an expression.  A class name cannot be used in | 
					
						
							|  |  |  | the left-hand-side of an assignment. | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | Object variable write access ~ | 
					
						
							| 
									
										
										
										
											2023-11-11 08:53:32 +01:00
										 |  |  | 						    *read-only-variable* | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | Now try to change an object variable directly: > | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	pos.lnum = 9 | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | <							*E1335* | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | This will give you an error!  That is because by default object variables can | 
					
						
							|  |  |  | be read but not set.  That's why the TextPosition class provides a method for | 
					
						
							|  |  |  | it: > | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	pos.SetLnum(9) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | Allowing to read but not set an object variable is the most common and safest | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | way.  Most often there is no problem using a value, while setting a value may | 
					
						
							|  |  |  | have side effects that need to be taken care of.  In this case, the SetLnum() | 
					
						
							|  |  |  | method could check if the line number is valid and either give an error or use | 
					
						
							|  |  |  | the closest valid value. | 
					
						
							| 
									
										
										
										
											2023-11-11 08:53:32 +01:00
										 |  |  | 					*:public* *public-variable* *E1331* | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | If you don't care about side effects and want to allow the object variable to | 
					
						
							|  |  |  | be changed at any time, you can make it public: > | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-29 01:08:24 +03:00
										 |  |  | 	public var lnum: number | 
					
						
							|  |  |  | 	public var col: number | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | Now you don't need the SetLnum(), SetCol() and SetPosition() methods, setting | 
					
						
							|  |  |  | "pos.lnum" directly above will no longer give an error. | 
					
						
							| 
									
										
										
										
											2023-09-18 19:56:49 +02:00
										 |  |  | 							*E1326* | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | If you try to set an object variable that doesn't exist you get an error: > | 
					
						
							| 
									
										
										
										
											2022-12-31 15:30:45 +00:00
										 |  |  | 	pos.other = 9 | 
					
						
							| 
									
										
										
										
											2023-09-18 19:56:49 +02:00
										 |  |  | <	E1326: Member not found on object "TextPosition": other ~ | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-18 19:56:49 +02:00
										 |  |  | 							*E1376* | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | A object variable cannot be accessed using the class name. | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-11 08:53:32 +01:00
										 |  |  | Protected variables ~ | 
					
						
							|  |  |  | 					*protected-variable* *E1332* *E1333* | 
					
						
							|  |  |  | On the other hand, if you do not want the object variables to be read directly | 
					
						
							|  |  |  | from outside the class or its sub-classes, you can make them protected.  This | 
					
						
							|  |  |  | is done by prefixing an underscore to the name: > | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-14 20:26:26 +01:00
										 |  |  | 	var _lnum: number | 
					
						
							| 
									
										
										
										
											2024-01-07 17:52:10 +03:00
										 |  |  | 	var _col: number | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-11 08:53:32 +01:00
										 |  |  | Now you need to provide methods to get the value of the protected variables. | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | These are commonly called getters.  We recommend using a name that starts with | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | "Get": > | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def GetLnum(): number | 
					
						
							|  |  |  | 	   return this._lnum | 
					
						
							|  |  |  | 	enddef | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-07 17:52:10 +03:00
										 |  |  | 	def GetCol(): number | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 	   return this._col | 
					
						
							|  |  |  | 	enddef | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | This example isn't very useful, the variables might as well have been public. | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | It does become useful if you check the value.  For example, restrict the line | 
					
						
							|  |  |  | number to the total number of lines: > | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def GetLnum(): number | 
					
						
							|  |  |  | 	   if this._lnum > this._lineCount | 
					
						
							|  |  |  | 	      return this._lineCount | 
					
						
							|  |  |  | 	   endif | 
					
						
							|  |  |  | 	   return this._lnum | 
					
						
							|  |  |  | 	enddef | 
					
						
							| 
									
										
										
										
											2023-09-18 19:56:49 +02:00
										 |  |  | < | 
					
						
							| 
									
										
										
										
											2023-11-11 08:53:32 +01:00
										 |  |  | Protected methods ~ | 
					
						
							|  |  |  | 						*protected-method* *E1366* | 
					
						
							| 
									
										
										
										
											2023-08-27 19:18:23 +02:00
										 |  |  | If you want object methods to be accessible only from other methods of the | 
					
						
							|  |  |  | same class and not used from outside the class, then you can make them | 
					
						
							| 
									
										
										
										
											2023-11-11 08:53:32 +01:00
										 |  |  | protected.  This is done by prefixing the method name with an underscore: > | 
					
						
							| 
									
										
										
										
											2023-08-27 19:18:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     class SomeClass | 
					
						
							|  |  |  | 	def _Foo(): number | 
					
						
							|  |  |  | 	  return 10 | 
					
						
							|  |  |  | 	enddef | 
					
						
							|  |  |  | 	def Bar(): number | 
					
						
							|  |  |  | 	  return this._Foo() | 
					
						
							|  |  |  | 	enddef | 
					
						
							|  |  |  |     endclass | 
					
						
							|  |  |  | < | 
					
						
							| 
									
										
										
										
											2023-11-11 08:53:32 +01:00
										 |  |  | Accessing a protected method outside the class will result in an error (using | 
					
						
							| 
									
										
										
										
											2023-08-27 19:18:23 +02:00
										 |  |  | the above class): > | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     var a = SomeClass.new() | 
					
						
							|  |  |  |     a._Foo() | 
					
						
							|  |  |  | < | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | Simplifying the new() method ~ | 
					
						
							| 
									
										
										
										
											2023-09-28 22:46:37 +02:00
										 |  |  | 						*new()* *constructor* | 
					
						
							| 
									
										
										
										
											2023-12-27 10:07:09 -08:00
										 |  |  | See also |default-constructor| and |multiple-constructors|. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | Many constructors take values for the object variables.  Thus you very often | 
					
						
							|  |  |  | see this pattern: > | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | 	 class SomeClass | 
					
						
							| 
									
										
										
										
											2023-12-14 20:26:26 +01:00
										 |  |  | 	   var lnum: number | 
					
						
							|  |  |  | 	   var col: number | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	   def new(lnum: number, col: number) | 
					
						
							|  |  |  | 	      this.lnum = lnum | 
					
						
							|  |  |  | 	      this.col = col | 
					
						
							|  |  |  | 	   enddef | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | 	 endclass | 
					
						
							| 
									
										
										
										
											2023-09-28 22:18:19 +02:00
										 |  |  | < | 
					
						
							|  |  |  | 							*E1390* | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | Not only is this text you need to write, it also has the type of each | 
					
						
							| 
									
										
										
										
											2023-12-14 20:36:32 +01:00
										 |  |  | variable twice.  Since this is so common a shorter way to write new() is | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | provided: > | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	   def new(this.lnum, this.col) | 
					
						
							|  |  |  | 	   enddef | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | The semantics are easy to understand: Providing the object variable name, | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | including "this.", as the argument to new() means the value provided in the | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | new() call is assigned to that object variable.  This mechanism comes from the | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | Dart language. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | Putting together this way of using new() and making the variables public | 
					
						
							|  |  |  | results in a much shorter class definition than what we started with: > | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	class TextPosition | 
					
						
							| 
									
										
										
										
											2023-12-14 20:26:26 +01:00
										 |  |  | 	   public var lnum: number | 
					
						
							|  |  |  | 	   public var col: number | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	   def new(this.lnum, this.col) | 
					
						
							|  |  |  | 	   enddef | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	   def SetPosition(lnum: number, col: number) | 
					
						
							|  |  |  | 	      this.lnum = lnum | 
					
						
							|  |  |  | 	      this.col = col | 
					
						
							|  |  |  | 	   enddef | 
					
						
							|  |  |  | 	 endclass | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | The sequence of constructing a new object is: | 
					
						
							|  |  |  | 1. Memory is allocated and cleared.  All values are zero/false/empty. | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | 2. For each declared object variable that has an initializer, the expression | 
					
						
							|  |  |  |    is evaluated and assigned to the variable.  This happens in the sequence | 
					
						
							|  |  |  |    the variables are declared in the class. | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 3. Arguments in the new() method in the "this.name" form are assigned. | 
					
						
							|  |  |  | 4. The body of the new() method is executed. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | If the class extends a parent class, the same thing happens.  In the second | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | step the object variables of the parent class are initialized first.  There is | 
					
						
							|  |  |  | no need to call "super()" or "new()" on the parent. | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-28 23:06:48 +02:00
										 |  |  | 							*E1365* | 
					
						
							| 
									
										
										
										
											2023-08-20 18:20:17 +02:00
										 |  |  | When defining the new() method the return type should not be specified.  It | 
					
						
							|  |  |  | always returns an object of the class. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-11 22:07:05 +01:00
										 |  |  | The new() method can be made a protected method by using "_new()".  This can | 
					
						
							|  |  |  | be used to support the singleton design pattern. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-28 23:06:48 +02:00
										 |  |  | 							*E1386* | 
					
						
							|  |  |  | When invoking an object method, the method name should be preceded by the | 
					
						
							| 
									
										
										
										
											2023-12-14 20:36:32 +01:00
										 |  |  | object variable name.  An object method cannot be invoked using the class | 
					
						
							| 
									
										
										
										
											2023-09-28 23:06:48 +02:00
										 |  |  | name. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | ============================================================================== | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-18 19:56:49 +02:00
										 |  |  | 3.  Class Variables and Methods			*Vim9-class-member* | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-18 19:56:49 +02:00
										 |  |  | 					    *:static* *E1337* *E1338* *E1368* | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | Class members are declared with "static".  They are used by the name without a | 
					
						
							| 
									
										
										
										
											2023-09-18 19:56:49 +02:00
										 |  |  | prefix in the class where they are defined: > | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	class OtherThing | 
					
						
							| 
									
										
										
										
											2023-12-14 20:26:26 +01:00
										 |  |  | 	   var size: number | 
					
						
							|  |  |  | 	   static var totalSize: number | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	   def new(this.size) | 
					
						
							|  |  |  | 	      totalSize += this.size | 
					
						
							|  |  |  | 	   enddef | 
					
						
							|  |  |  | 	endclass | 
					
						
							| 
									
										
										
										
											2023-01-09 20:12:45 +00:00
										 |  |  | <							*E1340* *E1341* | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | Since the name is used as-is, shadowing the name by a method argument name | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | or local variable name is not allowed. | 
					
						
							| 
									
										
										
										
											2023-01-09 20:12:45 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-28 23:06:48 +02:00
										 |  |  | 					    *E1374* *E1375* *E1384* *E1385* | 
					
						
							| 
									
										
										
										
											2023-09-18 19:56:49 +02:00
										 |  |  | To access a class member outside of the class where it is defined, the class | 
					
						
							|  |  |  | name prefix must be used.  A class member cannot be accessed using an object. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-11 08:53:32 +01:00
										 |  |  | Just like object members the access can be made protected by using an | 
					
						
							|  |  |  | underscore as the first character in the name, and it can be made public by | 
					
						
							|  |  |  | prefixing "public": > | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     class OtherThing | 
					
						
							| 
									
										
										
										
											2023-12-14 20:26:26 +01:00
										 |  |  | 	static var total: number	  # anybody can read, only class can write | 
					
						
							|  |  |  | 	static var _sum: number	          # only class can read and write | 
					
						
							|  |  |  | 	public static var result: number  # anybody can read and write | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  |     endclass | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | < | 
					
						
							| 
									
										
										
										
											2023-09-18 19:56:49 +02:00
										 |  |  | 							*class-method* | 
					
						
							|  |  |  | Class methods are also declared with "static".  They can use the class | 
					
						
							|  |  |  | variables but they have no access to the object variables, they cannot use the | 
					
						
							| 
									
										
										
										
											2023-10-03 04:47:13 +09:00
										 |  |  | "this" keyword: | 
					
						
							| 
									
										
										
										
											2023-09-18 19:56:49 +02:00
										 |  |  | > | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 	class OtherThing | 
					
						
							| 
									
										
										
										
											2023-12-14 20:26:26 +01:00
										 |  |  | 	   var size: number | 
					
						
							|  |  |  | 	   static var totalSize: number | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | 	   # Clear the total size and return the value it had before. | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 	   static def ClearTotalSize(): number | 
					
						
							|  |  |  | 	      var prev = totalSize | 
					
						
							|  |  |  | 	      totalSize = 0 | 
					
						
							|  |  |  | 	      return prev | 
					
						
							|  |  |  | 	   enddef | 
					
						
							|  |  |  | 	endclass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-04 23:05:33 +03:00
										 |  |  | Inside the class, the class method can be called by name directly, outside the | 
					
						
							|  |  |  | class, the class name must be prefixed: `OtherThing.ClearTotalSize()`.  Also, | 
					
						
							|  |  |  | the name prefix must be used for public class methods in the special contexts | 
					
						
							|  |  |  | of class variable initializers and of lambda expressions and nested functions: | 
					
						
							|  |  |  | > | 
					
						
							|  |  |  |     class OtherThing | 
					
						
							|  |  |  | 	static var name: string = OtherThing.GiveName() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	static def GiveName(): string | 
					
						
							|  |  |  | 	    def DoGiveName(): string | 
					
						
							|  |  |  | 		return OtherThing.NameAny() | 
					
						
							|  |  |  | 	    enddef | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    return DoGiveName() | 
					
						
							|  |  |  | 	enddef | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	static def NameAny(): string | 
					
						
							|  |  |  | 	    return "any" | 
					
						
							|  |  |  | 	enddef | 
					
						
							|  |  |  |     endclass | 
					
						
							|  |  |  | < | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-11 08:53:32 +01:00
										 |  |  | Just like object methods the access can be made protected by using an | 
					
						
							|  |  |  | underscore as the first character in the method name: > | 
					
						
							| 
									
										
										
										
											2023-08-27 19:18:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     class OtherThing | 
					
						
							|  |  |  | 	static def _Foo() | 
					
						
							|  |  |  | 	    echo "Foo" | 
					
						
							|  |  |  | 	enddef | 
					
						
							|  |  |  | 	def Bar() | 
					
						
							| 
									
										
										
										
											2023-09-18 19:56:49 +02:00
										 |  |  | 	    _Foo() | 
					
						
							| 
									
										
										
										
											2023-08-27 19:18:23 +02:00
										 |  |  | 	enddef | 
					
						
							|  |  |  |     endclass | 
					
						
							| 
									
										
										
										
											2023-08-29 22:26:30 +02:00
										 |  |  | < | 
					
						
							|  |  |  | 							*E1370* | 
					
						
							| 
									
										
										
										
											2023-12-24 11:03:31 +01:00
										 |  |  | Note that constructors cannot be declared as "static". They are called like a | 
					
						
							|  |  |  | static but execute as an object method; they have access to "this". | 
					
						
							| 
									
										
										
										
											2023-08-27 19:18:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-18 19:56:49 +02:00
										 |  |  | To access the class methods and class variables of a super class in an | 
					
						
							|  |  |  | extended class, the class name prefix should be used just as from anywhere | 
					
						
							|  |  |  | outside of the defining class: > | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     vim9script | 
					
						
							|  |  |  |     class Vehicle | 
					
						
							| 
									
										
										
										
											2023-12-14 20:26:26 +01:00
										 |  |  | 	static var nextID: number = 1000 | 
					
						
							| 
									
										
										
										
											2023-09-18 19:56:49 +02:00
										 |  |  | 	static def GetID(): number | 
					
						
							|  |  |  | 	    nextID += 1 | 
					
						
							|  |  |  | 	    return nextID | 
					
						
							|  |  |  | 	enddef | 
					
						
							|  |  |  |     endclass | 
					
						
							|  |  |  |     class Car extends Vehicle | 
					
						
							| 
									
										
										
										
											2023-12-14 20:26:26 +01:00
										 |  |  | 	var myID: number | 
					
						
							| 
									
										
										
										
											2023-09-18 19:56:49 +02:00
										 |  |  | 	def new() | 
					
						
							|  |  |  | 	    this.myID = Vehicle.GetID() | 
					
						
							|  |  |  | 	enddef | 
					
						
							|  |  |  |     endclass | 
					
						
							|  |  |  | < | 
					
						
							|  |  |  | Class variables and methods are not inherited by a child class.  A child class | 
					
						
							|  |  |  | can declare a static variable or a method with the same name as the one in the | 
					
						
							|  |  |  | super class.  Depending on the class where the member is used the | 
					
						
							|  |  |  | corresponding class member will be used.  The type of the class member in a | 
					
						
							|  |  |  | child class can be different from that in the super class. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-21 16:46:18 +01:00
										 |  |  | The double underscore (__) prefix for a class or object method name is | 
					
						
							|  |  |  | reserved for future use. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-16 14:11:19 +01:00
										 |  |  | 					*object-final-variable* *E1409* | 
					
						
							|  |  |  | The |:final| keyword can be used to make a class or object variable a | 
					
						
							|  |  |  | constant.  Examples: > | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class A | 
					
						
							|  |  |  | 	final v1 = [1, 2]		# final object variable | 
					
						
							|  |  |  | 	public final v2 = {x: 1}	# final object variable | 
					
						
							|  |  |  | 	static final v3 = 'abc'		# final class variable | 
					
						
							|  |  |  | 	public static final v4 = 0z10	# final class variable | 
					
						
							|  |  |  |     endclass | 
					
						
							|  |  |  | < | 
					
						
							|  |  |  | A final variable can be changed only from a constructor function.  Example: > | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class A | 
					
						
							|  |  |  | 	final v1: list<number> | 
					
						
							|  |  |  | 	def new() | 
					
						
							|  |  |  | 	    this.v1 = [1, 2] | 
					
						
							|  |  |  | 	enddef | 
					
						
							|  |  |  |     endclass | 
					
						
							|  |  |  |     var a = A.new() | 
					
						
							|  |  |  |     echo a.v1 | 
					
						
							|  |  |  | < | 
					
						
							|  |  |  | Note that the value of a final variable can be changed.  Example: > | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class A | 
					
						
							|  |  |  | 	public final v1 = [1, 2] | 
					
						
							|  |  |  |     endclass | 
					
						
							|  |  |  |     var a = A.new() | 
					
						
							|  |  |  |     a.v1[0] = 6			# OK | 
					
						
							|  |  |  |     a.v1->add(3)		# OK | 
					
						
							|  |  |  |     a.v1 = [3, 4]		# Error | 
					
						
							|  |  |  | < | 
					
						
							|  |  |  | 							*E1408* | 
					
						
							|  |  |  | Final variables are not supported in an interface.  A class or object method | 
					
						
							|  |  |  | cannot be final. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					*object-const-variable* | 
					
						
							|  |  |  | The |:const| keyword can be used to make a class or object variable and the | 
					
						
							|  |  |  | value a constant.  Examples: > | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class A | 
					
						
							|  |  |  | 	const v1 = [1, 2]		# const object variable | 
					
						
							|  |  |  | 	public const v2 = {x: 1}	# const object variable | 
					
						
							|  |  |  | 	static const v3 = 'abc'		# const class variable | 
					
						
							|  |  |  | 	public static const v4 = 0z10	# const class variable | 
					
						
							|  |  |  |     endclass | 
					
						
							|  |  |  | < | 
					
						
							|  |  |  | A const variable can be changed only from a constructor function. Example: > | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class A | 
					
						
							|  |  |  | 	const v1: list<number> | 
					
						
							|  |  |  | 	def new() | 
					
						
							|  |  |  | 	    this.v1 = [1, 2] | 
					
						
							|  |  |  | 	enddef | 
					
						
							|  |  |  |     endclass | 
					
						
							|  |  |  |     var a = A.new() | 
					
						
							|  |  |  |     echo a.v1 | 
					
						
							|  |  |  | < | 
					
						
							|  |  |  | A const variable and its value cannot be changed.  Example: > | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class A | 
					
						
							|  |  |  | 	public const v1 = [1, 2] | 
					
						
							|  |  |  |     endclass | 
					
						
							|  |  |  |     var a = A.new() | 
					
						
							|  |  |  |     a.v1[0] = 6			# Error | 
					
						
							|  |  |  |     a.v1->add(3)		# Error | 
					
						
							|  |  |  |     a.v1 = [3, 4]		# Error | 
					
						
							|  |  |  | < | 
					
						
							|  |  |  | 							 *E1410* | 
					
						
							|  |  |  | Const variables are not supported in an interface.  A class or object method | 
					
						
							|  |  |  | cannot be a const. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | ============================================================================== | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | 4.  Using an abstract class			*Vim9-abstract-class* | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | An abstract class forms the base for at least one sub-class.  In the class | 
					
						
							|  |  |  | model one often finds that a few classes have the same properties that can be | 
					
						
							|  |  |  | shared, but a class with these properties does not have enough state to create | 
					
						
							|  |  |  | an object from.  A sub-class must extend the abstract class and add the | 
					
						
							|  |  |  | missing state and/or methods before it can be used to create objects for. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | For example, a Shape class could store a color and thickness.  You cannot | 
					
						
							|  |  |  | create a Shape object, it is missing the information about what kind of shape | 
					
						
							|  |  |  | it is.  The Shape class functions as the base for a Square and a Triangle | 
					
						
							|  |  |  | class, for which objects can be created.  Example: > | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	abstract class Shape | 
					
						
							| 
									
										
										
										
											2023-12-14 20:26:26 +01:00
										 |  |  | 	   var color = Color.Black | 
					
						
							|  |  |  | 	   var thickness = 10 | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | 	endclass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	class Square extends Shape | 
					
						
							| 
									
										
										
										
											2023-12-14 20:26:26 +01:00
										 |  |  | 	   var size: number | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	   def new(this.size) | 
					
						
							|  |  |  | 	   enddef | 
					
						
							|  |  |  | 	endclass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	class Triangle extends Shape | 
					
						
							| 
									
										
										
										
											2023-12-14 20:26:26 +01:00
										 |  |  | 	   var base: number | 
					
						
							|  |  |  | 	   var height: number | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	   def new(this.base, this.height) | 
					
						
							|  |  |  | 	   enddef | 
					
						
							|  |  |  | 	endclass | 
					
						
							|  |  |  | < | 
					
						
							|  |  |  | An abstract class is defined the same way as a normal class, except that it | 
					
						
							|  |  |  | does not have any new() method. *E1359* | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-21 21:24:23 +09:00
										 |  |  | 					    *abstract-method* *E1371* *E1372* | 
					
						
							| 
									
										
										
										
											2023-09-08 19:27:51 +02:00
										 |  |  | An abstract method can be defined in an abstract class by using the "abstract" | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | prefix when defining the method: > | 
					
						
							| 
									
										
										
										
											2023-09-08 19:27:51 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	abstract class Shape | 
					
						
							|  |  |  | 	   abstract def Draw() | 
					
						
							|  |  |  | 	endclass | 
					
						
							| 
									
										
										
										
											2023-09-18 19:56:49 +02:00
										 |  |  | < | 
					
						
							| 
									
										
										
										
											2023-11-02 20:43:57 +01:00
										 |  |  | A static method in an abstract class cannot be an abstract method. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-18 19:56:49 +02:00
										 |  |  | 						*E1373* | 
					
						
							| 
									
										
										
										
											2024-01-07 17:52:10 +03:00
										 |  |  | A non-abstract class extending the abstract class must implement all the | 
					
						
							|  |  |  | abstract methods.  The signature (arguments, argument types and return type) | 
					
						
							|  |  |  | must be exactly the same.  If the return type of a method is a class, then | 
					
						
							|  |  |  | that class or one of its subclasses can be used in the extended method. | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ============================================================================== | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 5.  Using an interface				*Vim9-using-interface* | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | The example above with Shape, Square and Triangle can be made more useful if | 
					
						
							|  |  |  | we add a method to compute the surface of the object.  For that we create the | 
					
						
							|  |  |  | interface called HasSurface, which specifies one method Surface() that returns | 
					
						
							|  |  |  | a number.  This example extends the one above: > | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	abstract class Shape | 
					
						
							| 
									
										
										
										
											2023-12-14 20:26:26 +01:00
										 |  |  | 	   var color = Color.Black | 
					
						
							|  |  |  | 	   var thickness = 10 | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 	endclass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	interface HasSurface | 
					
						
							|  |  |  | 	   def Surface(): number | 
					
						
							|  |  |  | 	endinterface | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	class Square extends Shape implements HasSurface | 
					
						
							| 
									
										
										
										
											2023-12-14 20:26:26 +01:00
										 |  |  | 	   var size: number | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	   def new(this.size) | 
					
						
							|  |  |  | 	   enddef | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	   def Surface(): number | 
					
						
							|  |  |  | 	      return this.size * this.size | 
					
						
							|  |  |  | 	   enddef | 
					
						
							|  |  |  | 	endclass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	class Triangle extends Shape implements HasSurface | 
					
						
							| 
									
										
										
										
											2023-12-14 20:26:26 +01:00
										 |  |  | 	   var base: number | 
					
						
							|  |  |  | 	   var height: number | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	   def new(this.base, this.height) | 
					
						
							|  |  |  | 	   enddef | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	   def Surface(): number | 
					
						
							|  |  |  | 	      return this.base * this.height / 2 | 
					
						
							|  |  |  | 	   enddef | 
					
						
							|  |  |  | 	endclass | 
					
						
							| 
									
										
										
										
											2023-09-18 19:56:49 +02:00
										 |  |  | < | 
					
						
							|  |  |  | 					*E1348* *E1349* *E1367* *E1382* *E1383* | 
					
						
							| 
									
										
										
										
											2023-01-09 20:12:45 +00:00
										 |  |  | If a class declares to implement an interface, all the items specified in the | 
					
						
							| 
									
										
										
										
											2023-09-18 19:56:49 +02:00
										 |  |  | interface must appear in the class, with the same types. | 
					
						
							| 
									
										
										
										
											2023-01-09 20:12:45 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | The interface name can be used as a type: > | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var shapes: list<HasSurface> = [ | 
					
						
							|  |  |  | 				Square.new(12), | 
					
						
							|  |  |  | 				Triangle.new(8, 15), | 
					
						
							|  |  |  | 				] | 
					
						
							|  |  |  | 	for shape in shapes | 
					
						
							|  |  |  | 	   echo $'the surface is {shape.Surface()}' | 
					
						
							|  |  |  | 	endfor | 
					
						
							| 
									
										
										
										
											2023-09-18 19:56:49 +02:00
										 |  |  | < | 
					
						
							| 
									
										
										
										
											2023-09-27 19:02:01 +02:00
										 |  |  | 					*E1378* *E1379* *E1380* *E1387* | 
					
						
							|  |  |  | An interface can contain only object methods and read-only object variables. | 
					
						
							| 
									
										
										
										
											2023-11-11 08:53:32 +01:00
										 |  |  | An interface cannot contain read-write or protected object variables, | 
					
						
							|  |  |  | protected object methods, class variables and class methods. | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-18 19:56:49 +02:00
										 |  |  | An interface can extend another interface using "extends".  The sub-interface | 
					
						
							|  |  |  | inherits all the instance variables and methods from the super interface. | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ============================================================================== | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | 6.  More class details				*Vim9-class* *Class* *class* | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | Defining a class ~ | 
					
						
							|  |  |  | 					*:class* *:endclass* *:abstract* | 
					
						
							|  |  |  | A class is defined between `:class` and `:endclass`.  The whole class is | 
					
						
							|  |  |  | defined in one script file.  It is not possible to add to a class later. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-11 15:53:04 +00:00
										 |  |  | A class can only be defined in a |Vim9| script file.  *E1316* | 
					
						
							| 
									
										
										
										
											2024-04-13 17:58:09 +02:00
										 |  |  | A class cannot be defined inside a function.  *E1429* | 
					
						
							| 
									
										
										
										
											2022-12-08 15:32:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | It is possible to define more than one class in a script file.  Although it | 
					
						
							|  |  |  | usually is better to export only one main class.  It can be useful to define | 
					
						
							|  |  |  | types, enums and helper classes though. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The `:abstract` keyword may be prefixed and `:export` may be used.  That gives | 
					
						
							|  |  |  | these variants: > | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	class ClassName | 
					
						
							|  |  |  | 	endclass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	export class ClassName | 
					
						
							|  |  |  | 	endclass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	abstract class ClassName | 
					
						
							|  |  |  | 	endclass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	export abstract class ClassName | 
					
						
							|  |  |  | 	endclass | 
					
						
							|  |  |  | < | 
					
						
							|  |  |  | 							*E1314* | 
					
						
							|  |  |  | The class name should be CamelCased.  It must start with an uppercase letter. | 
					
						
							|  |  |  | That avoids clashing with builtin types. | 
					
						
							| 
									
										
										
										
											2022-12-11 15:53:04 +00:00
										 |  |  | 							*E1315* | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | After the class name these optional items can be used.  Each can appear only | 
					
						
							|  |  |  | once.  They can appear in any order, although this order is recommended: > | 
					
						
							|  |  |  | 	extends ClassName | 
					
						
							|  |  |  | 	implements InterfaceName, OtherInterface | 
					
						
							|  |  |  | 	specifies SomeInterface | 
					
						
							| 
									
										
										
										
											2025-02-16 16:15:50 +01:00
										 |  |  | < | 
					
						
							|  |  |  | The "specifies" feature is currently not implemented. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							*E1355* *E1369* | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | Each variable and method name can be used only once.  It is not possible to | 
					
						
							|  |  |  | define a method with the same name and different type of arguments.  It is not | 
					
						
							| 
									
										
										
										
											2024-01-07 17:52:10 +03:00
										 |  |  | possible to use a public and protected member variable with the same name.  An | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | object variable name used in a super class cannot be reused in a child class. | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | Object Variable Initialization ~ | 
					
						
							| 
									
										
										
										
											2023-11-11 08:53:32 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | If the type of a variable is not explicitly specified in a class, then it is | 
					
						
							|  |  |  | set to "any" during class definition.  When an object is instantiated from the | 
					
						
							|  |  |  | class, then the type of the variable is set. | 
					
						
							| 
									
										
										
										
											2023-08-22 21:29:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-29 22:50:02 +02:00
										 |  |  | The following reserved keyword names cannot be used as an object or class | 
					
						
							|  |  |  | variable name: "super", "this", "true", "false", "null", "null_blob", | 
					
						
							|  |  |  | "null_dict", "null_function", "null_list", "null_partial", "null_string", | 
					
						
							|  |  |  | "null_channel" and "null_job". | 
					
						
							| 
									
										
										
										
											2023-08-22 21:29:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | Extending a class ~ | 
					
						
							|  |  |  | 							*extends* | 
					
						
							| 
									
										
										
										
											2023-01-09 20:12:45 +00:00
										 |  |  | A class can extend one other class. *E1352* *E1353* *E1354* | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | The basic idea is to build on top of an existing class, add properties to it. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The extended class is called the "base class" or "super class".  The new class | 
					
						
							|  |  |  | is called the "child class". | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | Object variables from the base class are all taken over by the child class.  It | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | is not possible to override them (unlike some other languages). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						*E1356* *E1357* *E1358* | 
					
						
							| 
									
										
										
										
											2023-10-02 21:43:58 +02:00
										 |  |  | Object methods of the base class can be overruled.  The signature (arguments, | 
					
						
							| 
									
										
										
										
											2023-10-06 10:24:10 -07:00
										 |  |  | argument types and return type) must be exactly the same.  If the return type | 
					
						
							|  |  |  | of a method is a class, then that class or one of its subclasses can be used | 
					
						
							|  |  |  | in the extended method.  The method of the base class can be called by | 
					
						
							|  |  |  | prefixing "super.". | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-18 19:56:49 +02:00
										 |  |  | 						*E1377* | 
					
						
							| 
									
										
										
										
											2023-11-11 08:53:32 +01:00
										 |  |  | The access level of a method (public or protected) in a child class should be | 
					
						
							| 
									
										
										
										
											2023-09-18 19:56:49 +02:00
										 |  |  | the same as the super class. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | Other object methods of the base class are taken over by the child class. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | Class methods, including methods starting with "new", can be overruled, like | 
					
						
							|  |  |  | with object methods.  The method on the base class can be called by prefixing | 
					
						
							|  |  |  | the name of the class (for class methods) or "super.". | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | Unlike other languages, the constructor of the base class does not need to be | 
					
						
							|  |  |  | invoked.  In fact, it cannot be invoked.  If some initialization from the base | 
					
						
							|  |  |  | class also needs to be done in a child class, put it in an object method and | 
					
						
							|  |  |  | call that method from every constructor(). | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | If the base class did not specify a new() method then one was automatically | 
					
						
							|  |  |  | created.  This method will not be taken over by the child class.  The child | 
					
						
							|  |  |  | class can define its own new() method, or, if there isn't one, a new() method | 
					
						
							|  |  |  | will be added automatically. | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | A class implementing an interface ~ | 
					
						
							| 
									
										
										
										
											2023-09-27 19:02:01 +02:00
										 |  |  | 					*implements* *E1346* *E1347* *E1389* | 
					
						
							| 
									
										
										
										
											2023-01-09 20:12:45 +00:00
										 |  |  | A class can implement one or more interfaces.  The "implements" keyword can | 
					
						
							|  |  |  | only appear once *E1350* .  Multiple interfaces can be specified, separated by | 
					
						
							|  |  |  | commas.  Each interface name can appear only once. *E1351* | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | A class defining an interface ~ | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 							*specifies* | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | A class can declare its interface, the object variables and methods, with a | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | named interface.  This avoids the need for separately specifying the | 
					
						
							| 
									
										
										
										
											2022-12-08 15:32:33 +00:00
										 |  |  | interface, which is often done in many languages, especially Java. | 
					
						
							| 
									
										
										
										
											2025-02-16 16:15:50 +01:00
										 |  |  | TODO: This is currently not implemented. | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-11 15:53:04 +00:00
										 |  |  | Items in a class ~ | 
					
						
							| 
									
										
										
										
											2023-09-27 19:02:01 +02:00
										 |  |  | 						*E1318* *E1325* *E1388* | 
					
						
							| 
									
										
										
										
											2023-02-27 15:49:53 +00:00
										 |  |  | Inside a class, in between `:class` and `:endclass`, these items can appear: | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | - An object variable declaration: > | 
					
						
							| 
									
										
										
										
											2023-12-14 20:26:26 +01:00
										 |  |  | 	var _protectedVariableName: memberType | 
					
						
							|  |  |  | 	var readonlyVariableName: memberType | 
					
						
							|  |  |  | 	public var readwriteVariableName: memberType | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | - A class variable declaration: > | 
					
						
							| 
									
										
										
										
											2023-12-14 20:26:26 +01:00
										 |  |  | 	static var _protectedClassVariableName: memberType | 
					
						
							|  |  |  | 	static var readonlyClassVariableName: memberType | 
					
						
							| 
									
										
										
										
											2024-01-07 17:52:10 +03:00
										 |  |  | 	public static var readwriteClassVariableName: memberType | 
					
						
							| 
									
										
										
										
											2022-12-11 15:53:04 +00:00
										 |  |  | - A constructor method: > | 
					
						
							| 
									
										
										
										
											2023-02-20 20:44:55 +00:00
										 |  |  | 	def new(arguments) | 
					
						
							|  |  |  | 	def newName(arguments) | 
					
						
							| 
									
										
										
										
											2023-09-18 19:56:49 +02:00
										 |  |  | - A class method: > | 
					
						
							|  |  |  | 	static def SomeMethod(arguments) | 
					
						
							| 
									
										
										
										
											2023-11-11 08:53:32 +01:00
										 |  |  | 	static def _ProtectedMethod(arguments) | 
					
						
							| 
									
										
										
										
											2022-12-11 15:53:04 +00:00
										 |  |  | - An object method: > | 
					
						
							| 
									
										
										
										
											2023-02-20 20:44:55 +00:00
										 |  |  | 	def SomeMethod(arguments) | 
					
						
							| 
									
										
										
										
											2023-11-11 08:53:32 +01:00
										 |  |  | 	def _ProtectedMethod(arguments) | 
					
						
							| 
									
										
										
										
											2023-09-18 19:56:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | For the object variable the type must be specified.  The best way is to do | 
					
						
							|  |  |  | this explicitly with ": {type}".  For simple types you can also use an | 
					
						
							|  |  |  | initializer, such as "= 123", and Vim will see that the type is a number. | 
					
						
							|  |  |  | Avoid doing this for more complex types and when the type will be incomplete. | 
					
						
							|  |  |  | For example: > | 
					
						
							| 
									
										
										
										
											2023-12-14 20:26:26 +01:00
										 |  |  | 	var nameList = [] | 
					
						
							| 
									
										
										
										
											2022-12-31 15:30:45 +00:00
										 |  |  | This specifies a list, but the item type is unknown.  Better use: > | 
					
						
							| 
									
										
										
										
											2023-12-14 20:26:26 +01:00
										 |  |  | 	var nameList: list<string> | 
					
						
							| 
									
										
										
										
											2022-12-31 15:30:45 +00:00
										 |  |  | The initialization isn't needed, the list is empty by default. | 
					
						
							|  |  |  | 							*E1330* | 
					
						
							|  |  |  | Some types cannot be used, such as "void", "null" and "v:none". | 
					
						
							| 
									
										
										
										
											2022-12-11 15:53:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-03 16:26:58 +01:00
										 |  |  | Builtin Object Methods ~ | 
					
						
							|  |  |  |                                                        *builtin-object-methods* | 
					
						
							|  |  |  | Some of the builtin functions like |empty()|, |len()| and |string()| can be | 
					
						
							|  |  |  | used with an object.  An object can implement a method with the same name as | 
					
						
							|  |  |  | these builtin functions to return an object-specific value. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-16 16:15:50 +01:00
										 |  |  | 							*E1412* | 
					
						
							| 
									
										
										
										
											2024-03-03 16:26:58 +01:00
										 |  |  | The following builtin methods are supported: | 
					
						
							| 
									
										
										
										
											2025-02-16 16:15:50 +01:00
										 |  |  | 							*object-empty()* | 
					
						
							| 
									
										
										
										
											2024-03-03 16:26:58 +01:00
										 |  |  |     empty()  Invoked by the |empty()| function to check whether an object is | 
					
						
							|  |  |  | 	     empty.  If this method is missing, then true is returned.  This | 
					
						
							|  |  |  | 	     method should not accept any arguments and must return a boolean. | 
					
						
							| 
									
										
										
										
											2025-02-16 16:15:50 +01:00
										 |  |  | 							*object-len()* | 
					
						
							| 
									
										
										
										
											2024-03-03 16:26:58 +01:00
										 |  |  |     len()    Invoked by the |len()| function to return the length of an | 
					
						
							|  |  |  | 	     object.  If this method is missing in the class, then an error is | 
					
						
							|  |  |  | 	     given and zero is returned.  This method should not accept any | 
					
						
							|  |  |  | 	     arguments and must return a number. | 
					
						
							| 
									
										
										
										
											2025-02-16 16:15:50 +01:00
										 |  |  | 							*object-string()* | 
					
						
							| 
									
										
										
										
											2024-03-03 16:26:58 +01:00
										 |  |  |     string() Invoked by the |string()| function to get a textual | 
					
						
							|  |  |  | 	     representation of an object.  Also used by the |:echo| command | 
					
						
							|  |  |  | 	     for an object.  If this method is missing in the class, then a | 
					
						
							|  |  |  | 	     built-in default textual representation is used.  This method | 
					
						
							|  |  |  | 	     should not accept any arguments and must return a string. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-16 16:15:50 +01:00
										 |  |  | 							*E1413* | 
					
						
							| 
									
										
										
										
											2024-03-03 16:26:58 +01:00
										 |  |  | A class method cannot be used as a builtin method. | 
					
						
							| 
									
										
										
										
											2022-12-11 15:53:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | Defining an interface ~ | 
					
						
							| 
									
										
										
										
											2024-01-01 20:50:51 +01:00
										 |  |  | 					*Interface* *:interface* *:endinterface* | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | An interface is defined between `:interface` and `:endinterface`.  It may be | 
					
						
							|  |  |  | prefixed with `:export`: > | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	interface InterfaceName | 
					
						
							|  |  |  | 	endinterface | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	export interface InterfaceName | 
					
						
							|  |  |  | 	endinterface | 
					
						
							| 
									
										
										
										
											2023-01-09 20:12:45 +00:00
										 |  |  | <							*E1344* | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | An interface can declare object variables, just like in a class but without | 
					
						
							|  |  |  | any initializer. | 
					
						
							| 
									
										
										
										
											2023-01-09 20:12:45 +00:00
										 |  |  | 							*E1345* | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | An interface can declare methods with `:def`, including the arguments and | 
					
						
							|  |  |  | return type, but without the body and without `:enddef`.  Example: > | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	interface HasSurface | 
					
						
							| 
									
										
										
										
											2023-12-14 20:26:26 +01:00
										 |  |  | 	   var size: number | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 	   def Surface(): number | 
					
						
							|  |  |  | 	endinterface | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-09 20:12:45 +00:00
										 |  |  | An interface name must start with an uppercase letter. *E1343* | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | The "Has" prefix can be used to make it easier to guess this is an interface | 
					
						
							|  |  |  | name, with a hint about what it provides. | 
					
						
							| 
									
										
										
										
											2023-01-09 20:12:45 +00:00
										 |  |  | An interface can only be defined in a |Vim9| script file.  *E1342* | 
					
						
							| 
									
										
										
										
											2023-09-18 19:56:49 +02:00
										 |  |  | An interface cannot "implement" another interface but it can "extend" another | 
					
						
							|  |  |  | interface. *E1381* | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-20 20:44:55 +00:00
										 |  |  | null object ~ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-27 15:49:53 +00:00
										 |  |  | When a variable is declared to have the type of an object, but it is not | 
					
						
							| 
									
										
										
										
											2023-02-20 20:44:55 +00:00
										 |  |  | initialized, the value is null.  When trying to use this null object Vim often | 
					
						
							|  |  |  | does not know what class was supposed to be used.  Vim then cannot check if | 
					
						
							| 
									
										
										
										
											2024-01-07 17:52:10 +03:00
										 |  |  | a variable name is correct and you will get a "Using a null object" error, | 
					
						
							| 
									
										
										
										
											2023-10-03 04:47:13 +09:00
										 |  |  | even when the variable name is invalid. *E1360* *E1362* | 
					
						
							| 
									
										
										
										
											2023-02-20 20:44:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | Default constructor ~ | 
					
						
							| 
									
										
										
										
											2023-09-28 22:46:37 +02:00
										 |  |  | 							*default-constructor* | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | In case you define a class without a new() method, one will be automatically | 
					
						
							|  |  |  | defined.  This default constructor will have arguments for all the object | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | variables, in the order they were specified.  Thus if your class looks like: > | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	class AutoNew | 
					
						
							| 
									
										
										
										
											2023-12-14 20:26:26 +01:00
										 |  |  | 	   var name: string | 
					
						
							|  |  |  | 	   var age: number | 
					
						
							|  |  |  | 	   var gender: Gender | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 	endclass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | Then the default constructor will be: > | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-13 18:43:22 +00:00
										 |  |  | 	def new(this.name = v:none, this.age = v:none, this.gender = v:none) | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 	enddef | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-13 18:43:22 +00:00
										 |  |  | The "= v:none" default values make the arguments optional.  Thus you can also | 
					
						
							|  |  |  | call `new()` without any arguments.  No assignment will happen and the default | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | value for the object variables will be used.  This is a more useful example, | 
					
						
							| 
									
										
										
										
											2022-12-13 18:43:22 +00:00
										 |  |  | with default values: > | 
					
						
							| 
									
										
										
										
											2022-12-11 15:53:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	class TextPosition | 
					
						
							| 
									
										
										
										
											2023-12-14 20:26:26 +01:00
										 |  |  | 	   var lnum: number = 1 | 
					
						
							|  |  |  | 	   var col: number = 1 | 
					
						
							| 
									
										
										
										
											2022-12-11 15:53:04 +00:00
										 |  |  | 	endclass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | If you want the constructor to have mandatory arguments, you need to write it | 
					
						
							|  |  |  | yourself.  For example, if for the AutoNew class above you insist on getting | 
					
						
							|  |  |  | the name, you can define the constructor like this: > | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-13 18:43:22 +00:00
										 |  |  | 	def new(this.name, this.age = v:none, this.gender = v:none) | 
					
						
							| 
									
										
										
										
											2022-12-11 15:53:04 +00:00
										 |  |  | 	enddef | 
					
						
							| 
									
										
										
										
											2023-12-05 08:19:06 -08:00
										 |  |  | < | 
					
						
							|  |  |  | When using the default new() method, if the order of the object variables in | 
					
						
							|  |  |  | the class is changed later, then all the callers of the default new() method | 
					
						
							| 
									
										
										
										
											2024-01-07 17:52:10 +03:00
										 |  |  | need to change.  To avoid this, the new() method can be explicitly defined | 
					
						
							| 
									
										
										
										
											2023-12-05 08:19:06 -08:00
										 |  |  | without any arguments. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							*E1328* | 
					
						
							| 
									
										
										
										
											2022-12-13 18:43:22 +00:00
										 |  |  | Note that you cannot use another default value than "v:none" here.  If you | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | want to initialize the object variables, do it where they are declared.  This | 
					
						
							| 
									
										
										
										
											2022-12-13 18:43:22 +00:00
										 |  |  | way you only need to look in one place for the default values. | 
					
						
							| 
									
										
										
										
											2022-12-11 15:53:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-11 08:53:32 +01:00
										 |  |  | All object variables will be used in the default constructor, including | 
					
						
							|  |  |  | protected access ones. | 
					
						
							| 
									
										
										
										
											2023-01-09 20:12:45 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | If the class extends another one, the object variables of that class will come | 
					
						
							| 
									
										
										
										
											2023-01-09 20:12:45 +00:00
										 |  |  | first. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | Multiple constructors ~ | 
					
						
							| 
									
										
										
										
											2023-12-27 10:07:09 -08:00
										 |  |  | 						*multiple-constructors* | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | Normally a class has just one new() constructor.  In case you find that the | 
					
						
							|  |  |  | constructor is often called with the same arguments you may want to simplify | 
					
						
							|  |  |  | your code by putting those arguments into a second constructor method.  For | 
					
						
							|  |  |  | example, if you tend to use the color black a lot: > | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def new(this.garment, this.color, this.size) | 
					
						
							|  |  |  | 	enddef | 
					
						
							|  |  |  | 	... | 
					
						
							|  |  |  | 	var pants = new(Garment.pants, Color.black, "XL") | 
					
						
							|  |  |  | 	var shirt = new(Garment.shirt, Color.black, "XL") | 
					
						
							|  |  |  | 	var shoes = new(Garment.shoes, Color.black, "45") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Instead of repeating the color every time you can add a constructor that | 
					
						
							|  |  |  | includes it: > | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def newBlack(this.garment, this.size) | 
					
						
							|  |  |  | 	   this.color = Color.black | 
					
						
							|  |  |  | 	enddef | 
					
						
							|  |  |  | 	... | 
					
						
							|  |  |  | 	var pants = newBlack(Garment.pants, "XL") | 
					
						
							|  |  |  | 	var shirt = newBlack(Garment.shirt, "XL") | 
					
						
							|  |  |  | 	var shoes = newBlack(Garment.shoes, "9.5") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Note that the method name must start with "new".  If there is no method called | 
					
						
							|  |  |  | "new()" then the default constructor is added, even though there are other | 
					
						
							|  |  |  | constructor methods. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-11 19:58:55 +01:00
										 |  |  | Using variable type "any" for an Object~ | 
					
						
							|  |  |  | 							*obj-var-type-any* | 
					
						
							|  |  |  | You can use a variable declared with type "any" to hold an object.  e.g. | 
					
						
							|  |  |  | > | 
					
						
							|  |  |  |     vim9script | 
					
						
							|  |  |  |     class A | 
					
						
							|  |  |  | 	var n = 10 | 
					
						
							|  |  |  | 	def Get(): number | 
					
						
							|  |  |  | 	    return this.n | 
					
						
							|  |  |  | 	enddef | 
					
						
							|  |  |  |     endclass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def Fn(o: any) | 
					
						
							|  |  |  | 	echo o.n | 
					
						
							|  |  |  | 	echo o.Get() | 
					
						
							|  |  |  |     enddef | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     var a = A.new() | 
					
						
							|  |  |  |     Fn(a) | 
					
						
							|  |  |  | < | 
					
						
							|  |  |  | In this example, Vim cannot determine the type of the parameter "o" for | 
					
						
							|  |  |  | function Fn() at compile time.  It can be either a |Dict| or an |Object| | 
					
						
							|  |  |  | value.  Therefore, at runtime, when the type is known, the object member | 
					
						
							|  |  |  | variable and method are looked up.  This process is not efficient, so it is | 
					
						
							|  |  |  | recommended to use a more specific type whenever possible for better | 
					
						
							|  |  |  | efficiency. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-12 17:36:40 +01:00
										 |  |  | Compiling methods in a Class ~ | 
					
						
							|  |  |  | 							*class-compile* | 
					
						
							|  |  |  | The |:defcompile| command can be used to compile all the class and object | 
					
						
							|  |  |  | methods defined in a class: > | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-12 17:36:40 +01:00
										 |  |  | 	defcompile MyClass	# Compile class "MyClass" | 
					
						
							|  |  |  | 	defcompile		# Compile the classes in the current script | 
					
						
							|  |  |  | < | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | ============================================================================== | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-01 20:50:51 +01:00
										 |  |  | 7.  Type definition				*typealias* *Vim9-type* *:type* | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-14 20:03:03 +01:00
										 |  |  | 					*E1393* *E1395* *E1396* *E1397* *E1398* | 
					
						
							|  |  |  | A type definition is giving a name to a type specification.  This is also | 
					
						
							|  |  |  | known as a "type alias".  The type alias can be used wherever a built-in type | 
					
						
							|  |  |  | can be used.  Example: > | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     type ListOfStrings = list<string> | 
					
						
							|  |  |  |     var s: ListOfStrings = ['a', 'b'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def ProcessStr(str: ListOfStrings): ListOfStrings | 
					
						
							|  |  |  | 	return str | 
					
						
							|  |  |  |     enddef | 
					
						
							|  |  |  |     echo ProcessStr(s) | 
					
						
							|  |  |  | < | 
					
						
							|  |  |  | 							*E1394* | 
					
						
							|  |  |  | A type alias name must start with an upper case character.  Only existing | 
					
						
							|  |  |  | types can be aliased. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							*E1399* | 
					
						
							|  |  |  | A type alias can be created only at the script level and not inside a | 
					
						
							|  |  |  | function.  A type alias can be exported and used across scripts. | 
					
						
							| 
									
										
										
										
											2023-10-06 10:24:10 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-14 20:03:03 +01:00
										 |  |  | 					*E1400* *E1401* *E1402* *E1403* *E1407* | 
					
						
							|  |  |  | A type alias cannot be used as an expression.  A type alias cannot be used in | 
					
						
							|  |  |  | the left-hand-side of an assignment. | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-14 20:03:03 +01:00
										 |  |  | For a type alias name, the |typename()| function returns the type that is | 
					
						
							|  |  |  | aliased: > | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-14 20:03:03 +01:00
										 |  |  |     type ListOfStudents = list<dict<any>> | 
					
						
							|  |  |  |     echo typename(ListOfStudents) | 
					
						
							|  |  |  |     typealias<list<dict<any>>> | 
					
						
							|  |  |  | < | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | ============================================================================== | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | 8.  Enum					*Vim9-enum* *:enum* *:endenum* | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-28 10:36:42 +01:00
										 |  |  | 						*enum* *E1418* *E1419* *E1420* | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | An enum is a type that can have one of a list of values.  Example: > | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-29 15:33:12 +01:00
										 |  |  |     enum Color | 
					
						
							| 
									
										
										
										
											2024-03-28 10:36:42 +01:00
										 |  |  | 	White, | 
					
						
							|  |  |  | 	Red, | 
					
						
							|  |  |  | 	Green, Blue, Black | 
					
						
							| 
									
										
										
										
											2024-12-29 15:33:12 +01:00
										 |  |  |     endenum | 
					
						
							| 
									
										
										
										
											2024-03-28 10:36:42 +01:00
										 |  |  | < | 
					
						
							|  |  |  | 						*enumvalue* *E1422* | 
					
						
							|  |  |  | The enum values are separated by commas.  More than one enum value can be | 
					
						
							|  |  |  | listed in a single line.  The final enum value should not be followed by a | 
					
						
							|  |  |  | comma. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | An enum value is accessed using the enum name followed by the value name: > | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     var a: Color = Color.Blue | 
					
						
							|  |  |  | < | 
					
						
							|  |  |  | Enums are treated as classes, where each enum value is essentially an instance | 
					
						
							|  |  |  | of that class.  Unlike typical object instantiation with the |new()| method, | 
					
						
							|  |  |  | enum instances cannot be created this way. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | An enum can only be defined in a |Vim9| script file.	*E1414* | 
					
						
							|  |  |  | An enum cannot be defined inside a function. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							*E1415* | 
					
						
							|  |  |  | An enum name must start with an uppercase letter.  The name of an enum value | 
					
						
							|  |  |  | in an enum can start with an upper or lowercase letter. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							*E1416* | 
					
						
							|  |  |  | An enum can implement an interface but cannot extend a class: > | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     enum MyEnum implements MyIntf | 
					
						
							|  |  |  | 	Value1, | 
					
						
							|  |  |  | 	Value2 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def SomeMethod() | 
					
						
							|  |  |  | 	enddef | 
					
						
							|  |  |  |     endenum | 
					
						
							|  |  |  | < | 
					
						
							|  |  |  | 							*enum-constructor* | 
					
						
							|  |  |  | The enum value objects in an enum are constructed like any other objects using | 
					
						
							|  |  |  | the |new()| method.  Arguments can be passed to the enum constructor by | 
					
						
							|  |  |  | specifying them after the enum value name, just like calling a function.  The | 
					
						
							|  |  |  | default constructor doesn't have any arguments. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							*E1417* | 
					
						
							|  |  |  | An enum can contain class variables, class methods, object variables and | 
					
						
							|  |  |  | object methods.  The methods in an enum cannot be |:abstract| methods. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The following example shows an enum with object variables and methods: > | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     vim9script | 
					
						
							|  |  |  |     enum Planet | 
					
						
							|  |  |  | 	Earth(1, false), | 
					
						
							|  |  |  | 	Jupiter(95, true), | 
					
						
							|  |  |  | 	Saturn(146, true) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var moons: number | 
					
						
							|  |  |  | 	var has_rings: bool | 
					
						
							|  |  |  | 	def GetMoons(): number | 
					
						
							|  |  |  | 	    return this.moons | 
					
						
							|  |  |  | 	enddef | 
					
						
							|  |  |  |     endenum | 
					
						
							|  |  |  |     echo Planet.Jupiter.GetMoons() | 
					
						
							|  |  |  |     echo Planet.Earth.has_rings | 
					
						
							|  |  |  | < | 
					
						
							|  |  |  | 						*E1421* *E1423* *E1424* *E1425* | 
					
						
							| 
									
										
										
										
											2024-04-04 23:05:33 +03:00
										 |  |  | Enums and their values are immutable.  They cannot be utilized as numerical or | 
					
						
							|  |  |  | string types.  Enum values can declare mutable instance variables. | 
					
						
							| 
									
										
										
										
											2024-03-28 10:36:42 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 						*enum-name* | 
					
						
							|  |  |  | Each enum value object has a "name" instance variable which contains the name | 
					
						
							|  |  |  | of the enum value.  This is a readonly variable. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						*enum-ordinal* *E1426* | 
					
						
							|  |  |  | Each enum value has an associated ordinal number starting with 0.  The ordinal | 
					
						
							|  |  |  | number of an enum value can be accessed using the "ordinal" instance variable. | 
					
						
							|  |  |  | This is a readonly variable.  Note that if the ordering of the enum values in | 
					
						
							|  |  |  | an enum is changed, then their ordinal values will also change. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						*enum-values* | 
					
						
							|  |  |  | All the values in an enum can be accessed using the "values" class variable | 
					
						
							|  |  |  | which is a List of the enum objects.  This is a readonly variable. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Example: > | 
					
						
							|  |  |  |     enum Planet | 
					
						
							|  |  |  | 	Mercury, | 
					
						
							|  |  |  | 	Venus, | 
					
						
							|  |  |  | 	Earth | 
					
						
							|  |  |  |     endenum | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     echo Planet.Mercury | 
					
						
							|  |  |  |     echo Planet.Venus.name | 
					
						
							|  |  |  |     echo Planet.Venus.ordinal | 
					
						
							|  |  |  |     for p in Planet.values | 
					
						
							|  |  |  | 	# ... | 
					
						
							|  |  |  |     endfor | 
					
						
							|  |  |  | < | 
					
						
							|  |  |  | An enum is a class with class variables for the enum value objects and object | 
					
						
							|  |  |  | variables for the enum value name and the enum value ordinal: > | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     enum Planet | 
					
						
							|  |  |  | 	Mercury, | 
					
						
							|  |  |  | 	Venus | 
					
						
							|  |  |  |     endenum | 
					
						
							|  |  |  | < | 
					
						
							|  |  |  | The above enum definition is equivalent to the following class definition: > | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class Planet | 
					
						
							|  |  |  |       public static final Mercury: Planet = Planet.new('Mercury', 0) | 
					
						
							|  |  |  |       public static final Venus: Planet = Planet.new('Venus', 1) | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-28 10:36:42 +01:00
										 |  |  |       public static const values: list<Planet> = [Planet.Mercury, Planet.Venus] | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-28 10:36:42 +01:00
										 |  |  |       public const name: string | 
					
						
							|  |  |  |       public const ordinal: number | 
					
						
							|  |  |  |     endclass | 
					
						
							|  |  |  | < | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | ============================================================================== | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 9.  Rationale | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Most of the choices for |Vim9| classes come from popular and recently | 
					
						
							|  |  |  | developed languages, such as Java, TypeScript and Dart.  The syntax has been | 
					
						
							|  |  |  | made to fit with the way Vim script works, such as using `endclass` instead of | 
					
						
							|  |  |  | using curly braces around the whole class. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Some common constructs of object-oriented languages were chosen very long ago | 
					
						
							|  |  |  | when this kind of programming was still new, and later found to be | 
					
						
							|  |  |  | sub-optimal.  By this time those constructs were widely used and changing them | 
					
						
							|  |  |  | was not an option.  In Vim we do have the freedom to make different choices, | 
					
						
							|  |  |  | since classes are completely new.  We can make the syntax simpler and more | 
					
						
							|  |  |  | consistent than what "old" languages use.  Without diverting too much, it | 
					
						
							|  |  |  | should still mostly look like what you know from existing languages. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Some recently developed languages add all kinds of fancy features that we | 
					
						
							|  |  |  | don't need for Vim.  But some have nice ideas that we do want to use. | 
					
						
							|  |  |  | Thus we end up with a base of what is common in popular languages, dropping | 
					
						
							|  |  |  | what looks like a bad idea, and adding some nice features that are easy to | 
					
						
							|  |  |  | understand. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The main rules we use to make decisions: | 
					
						
							|  |  |  | - Keep it simple. | 
					
						
							|  |  |  | - No surprises, mostly do what other languages are doing. | 
					
						
							|  |  |  | - Avoid mistakes from the past. | 
					
						
							|  |  |  | - Avoid the need for the script writer to consult the help to understand how | 
					
						
							|  |  |  |   things work, most things should be obvious. | 
					
						
							|  |  |  | - Keep it consistent. | 
					
						
							|  |  |  | - Aim at an average size plugin, not at a huge project. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Using new() for the constructor ~ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Many languages use the class name for the constructor method.  A disadvantage | 
					
						
							|  |  |  | is that quite often this is a long name.  And when changing the class name all | 
					
						
							|  |  |  | constructor methods need to be renamed.  Not a big deal, but still a | 
					
						
							|  |  |  | disadvantage. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Other languages, such as TypeScript, use a specific name, such as | 
					
						
							|  |  |  | "constructor()".  That seems better.  However, using "new" or "new()" to | 
					
						
							|  |  |  | create a new object has no obvious relation with "constructor()". | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | For |Vim9| script using the same method name for all constructors seemed like | 
					
						
							|  |  |  | the right choice, and by calling it new() the relation between the caller and | 
					
						
							|  |  |  | the method being called is obvious. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | No overloading of the constructor ~ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | In Vim script, both legacy and |Vim9| script, there is no overloading of | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | methods.  That means it is not possible to use the same method name with | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | different types of arguments.  Therefore there also is only one new() | 
					
						
							|  |  |  | constructor. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | With |Vim9| script it would be possible to support overloading, since | 
					
						
							|  |  |  | arguments are typed.  However, this gets complicated very quickly.  Looking at | 
					
						
							|  |  |  | a new() call one has to inspect the types of the arguments to know which of | 
					
						
							|  |  |  | several new() methods is actually being called.  And that can require | 
					
						
							|  |  |  | inspecting quite a bit of code.  For example, if one of the arguments is the | 
					
						
							|  |  |  | return value of a method, you need to find that method to see what type it is | 
					
						
							|  |  |  | returning. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Instead, every constructor has to have a different name, starting with "new". | 
					
						
							|  |  |  | That way multiple constructors with different arguments are possible, while it | 
					
						
							|  |  |  | is very easy to see which constructor is being used.  And the type of | 
					
						
							|  |  |  | arguments can be properly checked. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | No overloading of methods ~ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Same reasoning as for the constructor: It is often not obvious what type | 
					
						
							|  |  |  | arguments have, which would make it difficult to figure out what method is | 
					
						
							|  |  |  | actually being called.  Better just give the methods a different name, then | 
					
						
							|  |  |  | type checking will make sure it works as you intended.  This rules out | 
					
						
							|  |  |  | polymorphism, which we don't really need anyway. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-09 20:12:45 +00:00
										 |  |  | Single inheritance and interfaces ~ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Some languages support multiple inheritance.  Although that can be useful in | 
					
						
							|  |  |  | some cases, it makes the rules of how a class works quite complicated. | 
					
						
							|  |  |  | Instead, using interfaces to declare what is supported is much simpler.  The | 
					
						
							|  |  |  | very popular Java language does it this way, and it should be good enough for | 
					
						
							| 
									
										
										
										
											2023-02-02 13:59:48 +00:00
										 |  |  | Vim.  The "keep it simple" rule applies here. | 
					
						
							| 
									
										
										
										
											2023-01-09 20:12:45 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | Explicitly declaring that a class supports an interface makes it easy to see | 
					
						
							|  |  |  | what a class is intended for.  It also makes it possible to do proper type | 
					
						
							|  |  |  | checking.  When an interface is changed any class that declares to implement | 
					
						
							|  |  |  | it will be checked if that change was also changed.  The mechanism to assume a | 
					
						
							|  |  |  | class implements an interface just because the methods happen to match is | 
					
						
							|  |  |  | brittle and leads to obscure problems, let's not do that. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | Using "this.variable" everywhere ~ | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | The object variables in various programming languages can often be accessed in | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | different ways, depending on the location.  Sometimes "this." has to be | 
					
						
							|  |  |  | prepended to avoid ambiguity.  They are usually declared without "this.". | 
					
						
							|  |  |  | That is quite inconsistent and sometimes confusing. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | A very common issue is that in the constructor the arguments use the same name | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | as the object variable.  Then for these variables "this." needs to be prefixed | 
					
						
							|  |  |  | in the body, while for other variables this is not needed and often omitted. | 
					
						
							|  |  |  | This leads to a mix of variables with and without "this.", which is | 
					
						
							|  |  |  | inconsistent. | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-07 17:52:10 +03:00
										 |  |  | For |Vim9| classes the "this." prefix is always used for declared methods and | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | variables.  Simple and consistent.  When looking at the code inside a class | 
					
						
							|  |  |  | it's also directly clear which variable references are object variables and | 
					
						
							|  |  |  | which aren't. | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | Using class variables ~ | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | Using "static variable" to declare a class variable is very common, nothing | 
					
						
							|  |  |  | new here.  In |Vim9| script these can be accessed directly by their name. | 
					
						
							|  |  |  | Very much like how a script-local variable can be used in a method.  Since | 
					
						
							|  |  |  | object variables are always accessed with "this." prepended, it's also quickly | 
					
						
							|  |  |  | clear what kind of variable it is. | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | TypeScript prepends the class name before the class variable name, also inside | 
					
						
							|  |  |  | the class.  This has two problems: The class name can be rather long, taking | 
					
						
							|  |  |  | up quite a bit of space, and when the class is renamed all these places need | 
					
						
							|  |  |  | to be changed too. | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | Declaring object and class variables ~ | 
					
						
							| 
									
										
										
										
											2023-01-09 20:12:45 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | The main choice is whether to use "var" as with variable declarations. | 
					
						
							|  |  |  | TypeScript does not use it: > | 
					
						
							|  |  |  | 	class Point { | 
					
						
							|  |  |  | 	  x: number; | 
					
						
							|  |  |  | 	  y = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | Following that Vim object variables could be declared like this: > | 
					
						
							| 
									
										
										
										
											2023-01-09 20:12:45 +00:00
										 |  |  | 	class Point | 
					
						
							|  |  |  | 	  this.x: number | 
					
						
							|  |  |  | 	  this.y = 0 | 
					
						
							|  |  |  | 	endclass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Some users pointed out that this looks more like an assignment than a | 
					
						
							| 
									
										
										
										
											2024-01-07 17:52:10 +03:00
										 |  |  | declaration.  Adding "var" and omitting "this." changes that: > | 
					
						
							| 
									
										
										
										
											2023-01-09 20:12:45 +00:00
										 |  |  | 	class Point | 
					
						
							| 
									
										
										
										
											2023-12-14 20:26:26 +01:00
										 |  |  | 	  var x: number | 
					
						
							|  |  |  | 	  var y = 0 | 
					
						
							| 
									
										
										
										
											2023-01-09 20:12:45 +00:00
										 |  |  | 	endclass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | We also need to be able to declare class variables using the "static" keyword. | 
					
						
							| 
									
										
										
										
											2023-01-09 20:12:45 +00:00
										 |  |  | There we can also choose to leave out "var": > | 
					
						
							|  |  |  | 	class Point | 
					
						
							| 
									
										
										
										
											2023-12-14 20:26:26 +01:00
										 |  |  | 	  var x: number | 
					
						
							| 
									
										
										
										
											2023-01-09 20:12:45 +00:00
										 |  |  | 	  static count = 0 | 
					
						
							|  |  |  | 	endclass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Or do use it, before "static": > | 
					
						
							|  |  |  | 	class Point | 
					
						
							| 
									
										
										
										
											2023-12-14 20:26:26 +01:00
										 |  |  | 	  var x: number | 
					
						
							| 
									
										
										
										
											2023-01-09 20:12:45 +00:00
										 |  |  | 	  var static count = 0 | 
					
						
							|  |  |  | 	endclass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Or after "static": > | 
					
						
							|  |  |  | 	class Point | 
					
						
							| 
									
										
										
										
											2023-12-14 20:26:26 +01:00
										 |  |  | 	  var x: number | 
					
						
							| 
									
										
										
										
											2023-01-09 20:12:45 +00:00
										 |  |  | 	  static var count = 0 | 
					
						
							|  |  |  | 	endclass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This is more in line with "static def Func()". | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | There is no clear preference whether to use "var" or not.  The two main | 
					
						
							|  |  |  | reasons to leave it out are: | 
					
						
							| 
									
										
										
										
											2023-12-14 20:26:26 +01:00
										 |  |  | 1. TypeScript and other popular languages do not use it. | 
					
						
							| 
									
										
										
										
											2023-01-09 20:12:45 +00:00
										 |  |  | 2. Less clutter. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-14 20:26:26 +01:00
										 |  |  | However, it is more common for languages to reuse their general variable and | 
					
						
							|  |  |  | function declaration syntax for class/object variables and methods.  Vim9 also | 
					
						
							|  |  |  | reuses the general function declaration syntax for methods.  So, for the sake | 
					
						
							|  |  |  | of consistency, we require "var" in these declarations. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | Using "ClassName.new()" to construct an object ~ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Many languages use the "new" operator to create an object, which is actually | 
					
						
							|  |  |  | kind of strange, since the constructor is defined as a method with arguments, | 
					
						
							|  |  |  | not a command.  TypeScript also has the "new" keyword, but the method is | 
					
						
							|  |  |  | called "constructor()", it is hard to see the relation between the two. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | In |Vim9| script the constructor method is called new(), and it is invoked as | 
					
						
							|  |  |  | new(), simple and straightforward.  Other languages use "new ClassName()", | 
					
						
							|  |  |  | while there is no ClassName() method, it's a method by another name in the | 
					
						
							|  |  |  | class called ClassName.  Quite confusing. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-11 08:53:32 +01:00
										 |  |  | Vim9class access modes ~ | 
					
						
							|  |  |  | 						    *vim9-access-modes* | 
					
						
							|  |  |  | The variable access modes, and their meaning, supported by Vim9class are | 
					
						
							|  |  |  | 	|public-variable|	read and write from anywhere | 
					
						
							|  |  |  | 	|read-only-variable|	read from anywhere, write from inside the | 
					
						
							|  |  |  | 				class and sub-classes | 
					
						
							|  |  |  | 	|protected-variable|	read and write from inside the class and | 
					
						
							|  |  |  | 				sub-classes | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The method access modes are similar, but without the read-only mode. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | Default read access to object variables ~ | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | Some users will remark that the access rules for object variables are | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | asymmetric.  Well, that is intentional.  Changing a value is a very different | 
					
						
							|  |  |  | action than reading a value.  The read operation has no side effects, it can | 
					
						
							|  |  |  | be done any number of times without affecting the object.  Changing the value | 
					
						
							|  |  |  | can have many side effects, and even have a ripple effect, affecting other | 
					
						
							|  |  |  | objects. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | When adding object variables one usually doesn't think much about this, just | 
					
						
							|  |  |  | get the type right.  And normally the values are set in the new() method. | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | Therefore defaulting to read access only "just works" in most cases.  And when | 
					
						
							|  |  |  | directly writing you get an error, which makes you wonder if you actually want | 
					
						
							|  |  |  | to allow that.  This helps writing code with fewer mistakes. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-11 08:53:32 +01:00
										 |  |  | Making object variables protected with an underscore ~ | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-11 08:53:32 +01:00
										 |  |  | When an object variable is protected, it can only be read and changed inside | 
					
						
							|  |  |  | the class (and in sub-classes), then it cannot be used outside of the class. | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | Prepending an underscore is a simple way to make that visible.  Various | 
					
						
							|  |  |  | programming languages have this as a recommendation. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | In case you change your mind and want to make the object variable accessible | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | outside of the class, you will have to remove the underscore everywhere. | 
					
						
							|  |  |  | Since the name only appears in the class (and sub-classes) they will be easy | 
					
						
							|  |  |  | to find and change. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The other way around is much harder: you can easily prepend an underscore to | 
					
						
							| 
									
										
										
										
											2023-11-11 08:53:32 +01:00
										 |  |  | the object variable inside the class to make it protected, but any usage | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | elsewhere you will have to track down and change.  You may have to make it a | 
					
						
							|  |  |  | "set" method call.  This reflects the real world problem that taking away | 
					
						
							|  |  |  | access requires work to be done for all places where that access exists. | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-11 08:53:32 +01:00
										 |  |  | An alternative would have been using the "protected" keyword, just like | 
					
						
							|  |  |  | "public" changes the access in the other direction.  Well, that's just to | 
					
						
							|  |  |  | reduce the number of keywords. | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-11 08:53:32 +01:00
										 |  |  | No private object variables ~ | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-24 14:36:17 -07:00
										 |  |  | Some languages provide several ways to control access to object variables. | 
					
						
							|  |  |  | The most known is "protected", and the meaning varies from language to | 
					
						
							| 
									
										
										
										
											2023-11-11 08:53:32 +01:00
										 |  |  | language.  Others are "shared", "private", "package" and even "friend". | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | These rules make life more difficult.  That can be justified in projects where | 
					
						
							|  |  |  | many people work on the same, complex code where it is easy to make mistakes. | 
					
						
							|  |  |  | Especially when refactoring or other changes to the class model. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The Vim scripts are expected to be used in a plugin, with just one person or a | 
					
						
							|  |  |  | small team working on it.  Complex rules then only make it more complicated, | 
					
						
							| 
									
										
										
										
											2023-04-22 22:40:14 +01:00
										 |  |  | the extra safety provided by the rules isn't really needed.  Let's just keep | 
					
						
							|  |  |  | it simple and not specify access details. | 
					
						
							| 
									
										
										
										
											2022-12-04 20:13:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ============================================================================== | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 10. To be done later | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Can a newSomething() constructor invoke another constructor?  If yes, what are | 
					
						
							|  |  |  | the restrictions? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Thoughts: | 
					
						
							|  |  |  | - Generics for a class: `class <Tkey, Tentry>` | 
					
						
							|  |  |  | - Generics for a function: `def <Tkey> GetLast(key: Tkey)` | 
					
						
							|  |  |  | - Mixins: not sure if that is useful, leave out for simplicity. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Some things that look like good additions: | 
					
						
							|  |  |  | - For testing: Mock mechanism | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | An important class to be provided is "Promise".  Since Vim is single | 
					
						
							|  |  |  | threaded, connecting asynchronous operations is a natural way of allowing | 
					
						
							|  |  |  | plugins to do their work without blocking the user.  It's a uniform way to | 
					
						
							|  |  |  | invoke callbacks and handle timeouts and errors. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  vim:tw=78:ts=8:noet:ft=help:norl: |