comparison runtime/doc/vim9class.txt @ 33942:3bba09502b8d v9.0.2167

patch 9.0.2167: Vim9: not consistently using :var for declarations Commit: https://github.com/vim/vim/commit/74da0ee0a24799a312a3a8a65858237185ef7a23 Author: Doug Kearns <dougkearns@gmail.com> Date: Thu Dec 14 20:26:26 2023 +0100 patch 9.0.2167: Vim9: not consistently using :var for declarations Problem: Vim9-script object/class variable declarations use syntax that is inconsistent with the rest of the language. Solution: Use :var to declare object and class variables. closes: #13670 Signed-off-by: Doug Kearns <dougkearns@gmail.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
author Christian Brabandt <cb@256bit.org>
date Thu, 14 Dec 2023 20:30:06 +0100
parents 050160b94f02
children 27746ed6cb05
comparison
equal deleted inserted replaced
33941:8845f55a6c20 33942:3bba09502b8d
76 76
77 Let's start with a simple example: a class that stores a text position (see 77 Let's start with a simple example: a class that stores a text position (see
78 below for how to do this more efficiently): > 78 below for how to do this more efficiently): >
79 79
80 class TextPosition 80 class TextPosition
81 this.lnum: number 81 var lnum: number
82 this.col: number 82 var col: number
83 83
84 def new(lnum: number, col: number) 84 def new(lnum: number, col: number)
85 this.lnum = lnum 85 this.lnum = lnum
86 this.col = col 86 this.col = col
87 enddef 87 enddef
154 *protected-variable* *E1332* *E1333* 154 *protected-variable* *E1332* *E1333*
155 On the other hand, if you do not want the object variables to be read directly 155 On the other hand, if you do not want the object variables to be read directly
156 from outside the class or its sub-classes, you can make them protected. This 156 from outside the class or its sub-classes, you can make them protected. This
157 is done by prefixing an underscore to the name: > 157 is done by prefixing an underscore to the name: >
158 158
159 this._lnum: number 159 var _lnum: number
160 this._col number 160 var _col number
161 161
162 Now you need to provide methods to get the value of the protected variables. 162 Now you need to provide methods to get the value of the protected variables.
163 These are commonly called getters. We recommend using a name that starts with 163 These are commonly called getters. We recommend using a name that starts with
164 "Get": > 164 "Get": >
165 165
207 *new()* *constructor* 207 *new()* *constructor*
208 Many constructors take values for the object variables. Thus you very often 208 Many constructors take values for the object variables. Thus you very often
209 see this pattern: > 209 see this pattern: >
210 210
211 class SomeClass 211 class SomeClass
212 this.lnum: number 212 var lnum: number
213 this.col: number 213 var col: number
214 214
215 def new(lnum: number, col: number) 215 def new(lnum: number, col: number)
216 this.lnum = lnum 216 this.lnum = lnum
217 this.col = col 217 this.col = col
218 enddef 218 enddef
233 233
234 Putting together this way of using new() and making the variables public 234 Putting together this way of using new() and making the variables public
235 results in a much shorter class definition than what we started with: > 235 results in a much shorter class definition than what we started with: >
236 236
237 class TextPosition 237 class TextPosition
238 public this.lnum: number 238 public var lnum: number
239 public this.col: number 239 public var col: number
240 240
241 def new(this.lnum, this.col) 241 def new(this.lnum, this.col)
242 enddef 242 enddef
243 243
244 def SetPosition(lnum: number, col: number) 244 def SetPosition(lnum: number, col: number)
275 *:static* *E1337* *E1338* *E1368* 275 *:static* *E1337* *E1338* *E1368*
276 Class members are declared with "static". They are used by the name without a 276 Class members are declared with "static". They are used by the name without a
277 prefix in the class where they are defined: > 277 prefix in the class where they are defined: >
278 278
279 class OtherThing 279 class OtherThing
280 this.size: number 280 var size: number
281 static totalSize: number 281 static var totalSize: number
282 282
283 def new(this.size) 283 def new(this.size)
284 totalSize += this.size 284 totalSize += this.size
285 enddef 285 enddef
286 endclass 286 endclass
295 Just like object members the access can be made protected by using an 295 Just like object members the access can be made protected by using an
296 underscore as the first character in the name, and it can be made public by 296 underscore as the first character in the name, and it can be made public by
297 prefixing "public": > 297 prefixing "public": >
298 298
299 class OtherThing 299 class OtherThing
300 static total: number # anybody can read, only class can write 300 static var total: number # anybody can read, only class can write
301 static _sum: number # only class can read and write 301 static var _sum: number # only class can read and write
302 public static result: number # anybody can read and write 302 public static var result: number # anybody can read and write
303 endclass 303 endclass
304 < 304 <
305 *class-method* 305 *class-method*
306 Class methods are also declared with "static". They can use the class 306 Class methods are also declared with "static". They can use the class
307 variables but they have no access to the object variables, they cannot use the 307 variables but they have no access to the object variables, they cannot use the
308 "this" keyword: 308 "this" keyword:
309 > 309 >
310 class OtherThing 310 class OtherThing
311 this.size: number 311 var size: number
312 static totalSize: number 312 static var totalSize: number
313 313
314 # Clear the total size and return the value it had before. 314 # Clear the total size and return the value it had before.
315 static def ClearTotalSize(): number 315 static def ClearTotalSize(): number
316 var prev = totalSize 316 var prev = totalSize
317 totalSize = 0 317 totalSize = 0
343 extended class, the class name prefix should be used just as from anywhere 343 extended class, the class name prefix should be used just as from anywhere
344 outside of the defining class: > 344 outside of the defining class: >
345 345
346 vim9script 346 vim9script
347 class Vehicle 347 class Vehicle
348 static nextID: number = 1000 348 static var nextID: number = 1000
349 static def GetID(): number 349 static def GetID(): number
350 nextID += 1 350 nextID += 1
351 return nextID 351 return nextID
352 enddef 352 enddef
353 endclass 353 endclass
354 class Car extends Vehicle 354 class Car extends Vehicle
355 this.myID: number 355 var myID: number
356 def new() 356 def new()
357 this.myID = Vehicle.GetID() 357 this.myID = Vehicle.GetID()
358 enddef 358 enddef
359 endclass 359 endclass
360 < 360 <
378 create a Shape object, it is missing the information about what kind of shape 378 create a Shape object, it is missing the information about what kind of shape
379 it is. The Shape class functions as the base for a Square and a Triangle 379 it is. The Shape class functions as the base for a Square and a Triangle
380 class, for which objects can be created. Example: > 380 class, for which objects can be created. Example: >
381 381
382 abstract class Shape 382 abstract class Shape
383 this.color = Color.Black 383 var color = Color.Black
384 this.thickness = 10 384 var thickness = 10
385 endclass 385 endclass
386 386
387 class Square extends Shape 387 class Square extends Shape
388 this.size: number 388 var size: number
389 389
390 def new(this.size) 390 def new(this.size)
391 enddef 391 enddef
392 endclass 392 endclass
393 393
394 class Triangle extends Shape 394 class Triangle extends Shape
395 this.base: number 395 var base: number
396 this.height: number 396 var height: number
397 397
398 def new(this.base, this.height) 398 def new(this.base, this.height)
399 enddef 399 enddef
400 endclass 400 endclass
401 < 401 <
428 we add a method to compute the surface of the object. For that we create the 428 we add a method to compute the surface of the object. For that we create the
429 interface called HasSurface, which specifies one method Surface() that returns 429 interface called HasSurface, which specifies one method Surface() that returns
430 a number. This example extends the one above: > 430 a number. This example extends the one above: >
431 431
432 abstract class Shape 432 abstract class Shape
433 this.color = Color.Black 433 var color = Color.Black
434 this.thickness = 10 434 var thickness = 10
435 endclass 435 endclass
436 436
437 interface HasSurface 437 interface HasSurface
438 def Surface(): number 438 def Surface(): number
439 endinterface 439 endinterface
440 440
441 class Square extends Shape implements HasSurface 441 class Square extends Shape implements HasSurface
442 this.size: number 442 var size: number
443 443
444 def new(this.size) 444 def new(this.size)
445 enddef 445 enddef
446 446
447 def Surface(): number 447 def Surface(): number
448 return this.size * this.size 448 return this.size * this.size
449 enddef 449 enddef
450 endclass 450 endclass
451 451
452 class Triangle extends Shape implements HasSurface 452 class Triangle extends Shape implements HasSurface
453 this.base: number 453 var base: number
454 this.height: number 454 var height: number
455 455
456 def new(this.base, this.height) 456 def new(this.base, this.height)
457 enddef 457 enddef
458 458
459 def Surface(): number 459 def Surface(): number
596 596
597 Items in a class ~ 597 Items in a class ~
598 *E1318* *E1325* *E1388* 598 *E1318* *E1325* *E1388*
599 Inside a class, in between `:class` and `:endclass`, these items can appear: 599 Inside a class, in between `:class` and `:endclass`, these items can appear:
600 - An object variable declaration: > 600 - An object variable declaration: >
601 this._protectedVariableName: memberType 601 var _protectedVariableName: memberType
602 this.readonlyVariableName: memberType 602 var readonlyVariableName: memberType
603 public this.readwriteVariableName: memberType 603 public var readwriteVariableName: memberType
604 - A class variable declaration: > 604 - A class variable declaration: >
605 static _protectedClassVariableName: memberType 605 static var _protectedClassVariableName: memberType
606 static readonlyClassVariableName: memberType 606 static var readonlyClassVariableName: memberType
607 static public readwriteClassVariableName: memberType 607 static var public readwriteClassVariableName: memberType
608 - A constructor method: > 608 - A constructor method: >
609 def new(arguments) 609 def new(arguments)
610 def newName(arguments) 610 def newName(arguments)
611 - A class method: > 611 - A class method: >
612 static def SomeMethod(arguments) 612 static def SomeMethod(arguments)
618 For the object variable the type must be specified. The best way is to do 618 For the object variable the type must be specified. The best way is to do
619 this explicitly with ": {type}". For simple types you can also use an 619 this explicitly with ": {type}". For simple types you can also use an
620 initializer, such as "= 123", and Vim will see that the type is a number. 620 initializer, such as "= 123", and Vim will see that the type is a number.
621 Avoid doing this for more complex types and when the type will be incomplete. 621 Avoid doing this for more complex types and when the type will be incomplete.
622 For example: > 622 For example: >
623 this.nameList = [] 623 var nameList = []
624 This specifies a list, but the item type is unknown. Better use: > 624 This specifies a list, but the item type is unknown. Better use: >
625 this.nameList: list<string> 625 var nameList: list<string>
626 The initialization isn't needed, the list is empty by default. 626 The initialization isn't needed, the list is empty by default.
627 *E1330* 627 *E1330*
628 Some types cannot be used, such as "void", "null" and "v:none". 628 Some types cannot be used, such as "void", "null" and "v:none".
629 629
630 630
644 *E1345* 644 *E1345*
645 An interface can declare methods with `:def`, including the arguments and 645 An interface can declare methods with `:def`, including the arguments and
646 return type, but without the body and without `:enddef`. Example: > 646 return type, but without the body and without `:enddef`. Example: >
647 647
648 interface HasSurface 648 interface HasSurface
649 this.size: number 649 var size: number
650 def Surface(): number 650 def Surface(): number
651 endinterface 651 endinterface
652 652
653 An interface name must start with an uppercase letter. *E1343* 653 An interface name must start with an uppercase letter. *E1343*
654 The "Has" prefix can be used to make it easier to guess this is an interface 654 The "Has" prefix can be used to make it easier to guess this is an interface
672 In case you define a class without a new() method, one will be automatically 672 In case you define a class without a new() method, one will be automatically
673 defined. This default constructor will have arguments for all the object 673 defined. This default constructor will have arguments for all the object
674 variables, in the order they were specified. Thus if your class looks like: > 674 variables, in the order they were specified. Thus if your class looks like: >
675 675
676 class AutoNew 676 class AutoNew
677 this.name: string 677 var name: string
678 this.age: number 678 var age: number
679 this.gender: Gender 679 var gender: Gender
680 endclass 680 endclass
681 681
682 Then the default constructor will be: > 682 Then the default constructor will be: >
683 683
684 def new(this.name = v:none, this.age = v:none, this.gender = v:none) 684 def new(this.name = v:none, this.age = v:none, this.gender = v:none)
688 call `new()` without any arguments. No assignment will happen and the default 688 call `new()` without any arguments. No assignment will happen and the default
689 value for the object variables will be used. This is a more useful example, 689 value for the object variables will be used. This is a more useful example,
690 with default values: > 690 with default values: >
691 691
692 class TextPosition 692 class TextPosition
693 this.lnum: number = 1 693 var lnum: number = 1
694 this.col: number = 1 694 var col: number = 1
695 endclass 695 endclass
696 696
697 If you want the constructor to have mandatory arguments, you need to write it 697 If you want the constructor to have mandatory arguments, you need to write it
698 yourself. For example, if for the AutoNew class above you insist on getting 698 yourself. For example, if for the AutoNew class above you insist on getting
699 the name, you can define the constructor like this: > 699 the name, you can define the constructor like this: >
945 endclass 945 endclass
946 946
947 Some users pointed out that this looks more like an assignment than a 947 Some users pointed out that this looks more like an assignment than a
948 declaration. Adding "var" changes that: > 948 declaration. Adding "var" changes that: >
949 class Point 949 class Point
950 var this.x: number 950 var x: number
951 var this.y = 0 951 var y = 0
952 endclass 952 endclass
953 953
954 We also need to be able to declare class variables using the "static" keyword. 954 We also need to be able to declare class variables using the "static" keyword.
955 There we can also choose to leave out "var": > 955 There we can also choose to leave out "var": >
956 class Point 956 class Point
957 var this.x: number 957 var x: number
958 static count = 0 958 static count = 0
959 endclass 959 endclass
960 960
961 Or do use it, before "static": > 961 Or do use it, before "static": >
962 class Point 962 class Point
963 var this.x: number 963 var x: number
964 var static count = 0 964 var static count = 0
965 endclass 965 endclass
966 966
967 Or after "static": > 967 Or after "static": >
968 class Point 968 class Point
969 var this.x: number 969 var x: number
970 static var count = 0 970 static var count = 0
971 endclass 971 endclass
972 972
973 This is more in line with "static def Func()". 973 This is more in line with "static def Func()".
974 974
975 There is no clear preference whether to use "var" or not. The two main 975 There is no clear preference whether to use "var" or not. The two main
976 reasons to leave it out are: 976 reasons to leave it out are:
977 1. TypeScript, Java and other popular languages do not use it. 977 1. TypeScript and other popular languages do not use it.
978 2. Less clutter. 978 2. Less clutter.
979
980 However, it is more common for languages to reuse their general variable and
981 function declaration syntax for class/object variables and methods. Vim9 also
982 reuses the general function declaration syntax for methods. So, for the sake
983 of consistency, we require "var" in these declarations.
984
985 This also allows for a natural use of "final" and "const" in the future.
979 986
980 987
981 Using "ClassName.new()" to construct an object ~ 988 Using "ClassName.new()" to construct an object ~
982 989
983 Many languages use the "new" operator to create an object, which is actually 990 Many languages use the "new" operator to create an object, which is actually