Skip to content

Commit

Permalink
patch 9.0.2167: Vim9: not consistently using :var for declarations
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
dkearns authored and chrisbra committed Dec 14, 2023
1 parent 549f8c0 commit 74da0ee
Show file tree
Hide file tree
Showing 8 changed files with 714 additions and 607 deletions.
101 changes: 54 additions & 47 deletions runtime/doc/vim9class.txt
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ Let's start with a simple example: a class that stores a text position (see
below for how to do this more efficiently): >
class TextPosition
this.lnum: number
this.col: number
var lnum: number
var col: number
def new(lnum: number, col: number)
this.lnum = lnum
Expand Down Expand Up @@ -156,8 +156,8 @@ 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: >
this._lnum: number
this._col number
var _lnum: number
var _col number
Now you need to provide methods to get the value of the protected variables.
These are commonly called getters. We recommend using a name that starts with
Expand Down Expand Up @@ -209,8 +209,8 @@ Many constructors take values for the object variables. Thus you very often
see this pattern: >
class SomeClass
this.lnum: number
this.col: number
var lnum: number
var col: number
def new(lnum: number, col: number)
this.lnum = lnum
Expand All @@ -235,8 +235,8 @@ Putting together this way of using new() and making the variables public
results in a much shorter class definition than what we started with: >
class TextPosition
public this.lnum: number
public this.col: number
public var lnum: number
public var col: number
def new(this.lnum, this.col)
enddef
Expand Down Expand Up @@ -277,8 +277,8 @@ Class members are declared with "static". They are used by the name without a
prefix in the class where they are defined: >
class OtherThing
this.size: number
static totalSize: number
var size: number
static var totalSize: number
def new(this.size)
totalSize += this.size
Expand All @@ -297,9 +297,9 @@ underscore as the first character in the name, and it can be made public by
prefixing "public": >
class OtherThing
static total: number # anybody can read, only class can write
static _sum: number # only class can read and write
public static result: number # anybody can read and write
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
endclass
<
*class-method*
Expand All @@ -308,8 +308,8 @@ variables but they have no access to the object variables, they cannot use the
"this" keyword:
>
class OtherThing
this.size: number
static totalSize: number
var size: number
static var totalSize: number
# Clear the total size and return the value it had before.
static def ClearTotalSize(): number
Expand Down Expand Up @@ -345,14 +345,14 @@ outside of the defining class: >
vim9script
class Vehicle
static nextID: number = 1000
static var nextID: number = 1000
static def GetID(): number
nextID += 1
return nextID
enddef
endclass
class Car extends Vehicle
this.myID: number
var myID: number
def new()
this.myID = Vehicle.GetID()
enddef
Expand Down Expand Up @@ -380,20 +380,20 @@ 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
this.color = Color.Black
this.thickness = 10
var color = Color.Black
var thickness = 10
endclass
class Square extends Shape
this.size: number
var size: number
def new(this.size)
enddef
endclass
class Triangle extends Shape
this.base: number
this.height: number
var base: number
var height: number
def new(this.base, this.height)
enddef
Expand Down Expand Up @@ -430,16 +430,16 @@ interface called HasSurface, which specifies one method Surface() that returns
a number. This example extends the one above: >
abstract class Shape
this.color = Color.Black
this.thickness = 10
var color = Color.Black
var thickness = 10
endclass
interface HasSurface
def Surface(): number
endinterface
class Square extends Shape implements HasSurface
this.size: number
var size: number
def new(this.size)
enddef
Expand All @@ -450,8 +450,8 @@ a number. This example extends the one above: >
endclass
class Triangle extends Shape implements HasSurface
this.base: number
this.height: number
var base: number
var height: number
def new(this.base, this.height)
enddef
Expand Down Expand Up @@ -598,13 +598,13 @@ Items in a class ~
*E1318* *E1325* *E1388*
Inside a class, in between `:class` and `:endclass`, these items can appear:
- An object variable declaration: >
this._protectedVariableName: memberType
this.readonlyVariableName: memberType
public this.readwriteVariableName: memberType
var _protectedVariableName: memberType
var readonlyVariableName: memberType
public var readwriteVariableName: memberType
- A class variable declaration: >
static _protectedClassVariableName: memberType
static readonlyClassVariableName: memberType
static public readwriteClassVariableName: memberType
static var _protectedClassVariableName: memberType
static var readonlyClassVariableName: memberType
static var public readwriteClassVariableName: memberType
- A constructor method: >
def new(arguments)
def newName(arguments)
Expand All @@ -620,9 +620,9 @@ 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: >
this.nameList = []
var nameList = []
This specifies a list, but the item type is unknown. Better use: >
this.nameList: list<string>
var nameList: list<string>
The initialization isn't needed, the list is empty by default.
*E1330*
Some types cannot be used, such as "void", "null" and "v:none".
Expand All @@ -646,7 +646,7 @@ An interface can declare methods with `:def`, including the arguments and
return type, but without the body and without `:enddef`. Example: >
interface HasSurface
this.size: number
var size: number
def Surface(): number
endinterface
Expand Down Expand Up @@ -674,9 +674,9 @@ defined. This default constructor will have arguments for all the object
variables, in the order they were specified. Thus if your class looks like: >
class AutoNew
this.name: string
this.age: number
this.gender: Gender
var name: string
var age: number
var gender: Gender
endclass
Then the default constructor will be: >
Expand All @@ -690,8 +690,8 @@ value for the object variables will be used. This is a more useful example,
with default values: >
class TextPosition
this.lnum: number = 1
this.col: number = 1
var lnum: number = 1
var col: number = 1
endclass
If you want the constructor to have mandatory arguments, you need to write it
Expand Down Expand Up @@ -947,36 +947,43 @@ Following that Vim object variables could be declared like this: >
Some users pointed out that this looks more like an assignment than a
declaration. Adding "var" changes that: >
class Point
var this.x: number
var this.y = 0
var x: number
var y = 0
endclass
We also need to be able to declare class variables using the "static" keyword.
There we can also choose to leave out "var": >
class Point
var this.x: number
var x: number
static count = 0
endclass
Or do use it, before "static": >
class Point
var this.x: number
var x: number
var static count = 0
endclass
Or after "static": >
class Point
var this.x: number
var x: number
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:
1. TypeScript, Java and other popular languages do not use it.
1. TypeScript and other popular languages do not use it.
2. Less clutter.

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.

This also allows for a natural use of "final" and "const" in the future.


Using "ClassName.new()" to construct an object ~

Expand Down
11 changes: 6 additions & 5 deletions src/errors.h
Original file line number Diff line number Diff line change
Expand Up @@ -3402,11 +3402,12 @@ EXTERN char e_object_required_found_str[]
INIT(= N_("E1327: Object required, found %s"));
EXTERN char e_constructor_default_value_must_be_vnone_str[]
INIT(= N_("E1328: Constructor default value must be v:none: %s"));
// E1329 unused
EXTERN char e_invalid_class_variable_declaration_str[]
INIT(= N_("E1329: Invalid class variable declaration: %s"));
EXTERN char e_invalid_type_for_object_variable_str[]
INIT(= N_("E1330: Invalid type for object variable: %s"));
EXTERN char e_public_must_be_followed_by_this_or_static[]
INIT(= N_("E1331: Public must be followed by \"this\" or \"static\""));
EXTERN char e_public_must_be_followed_by_var_or_static[]
INIT(= N_("E1331: Public must be followed by \"var\" or \"static\""));
EXTERN char e_public_variable_name_cannot_start_with_underscore_str[]
INIT(= N_("E1332: Public variable name cannot start with underscore: %s"));
EXTERN char e_cannot_access_protected_variable_str[]
Expand Down Expand Up @@ -3487,8 +3488,8 @@ EXTERN char e_cannot_access_protected_method_str[]
INIT(= N_("E1366: Cannot access protected method: %s"));
EXTERN char e_variable_str_of_interface_str_has_different_access[]
INIT(= N_("E1367: Access level of variable \"%s\" of interface \"%s\" is different"));
EXTERN char e_static_cannot_be_followed_by_this[]
INIT(= N_("E1368: Static cannot be followed by \"this\" in a variable name"));
EXTERN char e_static_must_be_followed_by_var_or_def[]
INIT(= N_("E1368: Static must be followed by \"var\" or \"def\""));
EXTERN char e_duplicate_variable_str[]
INIT(= N_("E1369: Duplicate variable: %s"));
EXTERN char e_cannot_define_new_method_as_static[]
Expand Down
2 changes: 1 addition & 1 deletion src/testdir/test_vim9_builtin.vim
Original file line number Diff line number Diff line change
Expand Up @@ -4845,7 +4845,7 @@ def Test_values()
vim9script

class Foo
this.val: number
var val: number
def Add()
echo this.val
enddef
Expand Down

0 comments on commit 74da0ee

Please sign in to comment.