Mercurial > vim
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 |