0
0
mirror of https://github.com/vim/vim.git synced 2025-09-23 03:43:49 -04:00

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>
This commit is contained in:
Doug Kearns
2023-12-14 20:26:26 +01:00
committed by Christian Brabandt
parent 549f8c0b4e
commit 74da0ee0a2
8 changed files with 714 additions and 607 deletions

View File

@@ -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): > below for how to do this more efficiently): >
class TextPosition class TextPosition
this.lnum: number var lnum: number
this.col: number var col: number
def new(lnum: number, col: number) def new(lnum: number, col: number)
this.lnum = lnum this.lnum = lnum
@@ -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 from outside the class or its sub-classes, you can make them protected. This
is done by prefixing an underscore to the name: > is done by prefixing an underscore to the name: >
this._lnum: number var _lnum: number
this._col number var _col number
Now you need to provide methods to get the value of the protected variables. 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 These are commonly called getters. We recommend using a name that starts with
@@ -209,8 +209,8 @@ Many constructors take values for the object variables. Thus you very often
see this pattern: > see this pattern: >
class SomeClass class SomeClass
this.lnum: number var lnum: number
this.col: number var col: number
def new(lnum: number, col: number) def new(lnum: number, col: number)
this.lnum = lnum this.lnum = lnum
@@ -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: > results in a much shorter class definition than what we started with: >
class TextPosition class TextPosition
public this.lnum: number public var lnum: number
public this.col: number public var col: number
def new(this.lnum, this.col) def new(this.lnum, this.col)
enddef enddef
@@ -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: > prefix in the class where they are defined: >
class OtherThing class OtherThing
this.size: number var size: number
static totalSize: number static var totalSize: number
def new(this.size) def new(this.size)
totalSize += this.size totalSize += this.size
@@ -297,9 +297,9 @@ underscore as the first character in the name, and it can be made public by
prefixing "public": > prefixing "public": >
class OtherThing class OtherThing
static total: number # anybody can read, only class can write static var total: number # anybody can read, only class can write
static _sum: number # only class can read and write static var _sum: number # only class can read and write
public static result: number # anybody can read and write public static var result: number # anybody can read and write
endclass endclass
< <
*class-method* *class-method*
@@ -308,8 +308,8 @@ variables but they have no access to the object variables, they cannot use the
"this" keyword: "this" keyword:
> >
class OtherThing class OtherThing
this.size: number var size: number
static totalSize: number static var totalSize: number
# Clear the total size and return the value it had before. # Clear the total size and return the value it had before.
static def ClearTotalSize(): number static def ClearTotalSize(): number
@@ -345,14 +345,14 @@ outside of the defining class: >
vim9script vim9script
class Vehicle class Vehicle
static nextID: number = 1000 static var nextID: number = 1000
static def GetID(): number static def GetID(): number
nextID += 1 nextID += 1
return nextID return nextID
enddef enddef
endclass endclass
class Car extends Vehicle class Car extends Vehicle
this.myID: number var myID: number
def new() def new()
this.myID = Vehicle.GetID() this.myID = Vehicle.GetID()
enddef enddef
@@ -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: > class, for which objects can be created. Example: >
abstract class Shape abstract class Shape
this.color = Color.Black var color = Color.Black
this.thickness = 10 var thickness = 10
endclass endclass
class Square extends Shape class Square extends Shape
this.size: number var size: number
def new(this.size) def new(this.size)
enddef enddef
endclass endclass
class Triangle extends Shape class Triangle extends Shape
this.base: number var base: number
this.height: number var height: number
def new(this.base, this.height) def new(this.base, this.height)
enddef enddef
@@ -430,8 +430,8 @@ interface called HasSurface, which specifies one method Surface() that returns
a number. This example extends the one above: > a number. This example extends the one above: >
abstract class Shape abstract class Shape
this.color = Color.Black var color = Color.Black
this.thickness = 10 var thickness = 10
endclass endclass
interface HasSurface interface HasSurface
@@ -439,7 +439,7 @@ a number. This example extends the one above: >
endinterface endinterface
class Square extends Shape implements HasSurface class Square extends Shape implements HasSurface
this.size: number var size: number
def new(this.size) def new(this.size)
enddef enddef
@@ -450,8 +450,8 @@ a number. This example extends the one above: >
endclass endclass
class Triangle extends Shape implements HasSurface class Triangle extends Shape implements HasSurface
this.base: number var base: number
this.height: number var height: number
def new(this.base, this.height) def new(this.base, this.height)
enddef enddef
@@ -598,13 +598,13 @@ Items in a class ~
*E1318* *E1325* *E1388* *E1318* *E1325* *E1388*
Inside a class, in between `:class` and `:endclass`, these items can appear: Inside a class, in between `:class` and `:endclass`, these items can appear:
- An object variable declaration: > - An object variable declaration: >
this._protectedVariableName: memberType var _protectedVariableName: memberType
this.readonlyVariableName: memberType var readonlyVariableName: memberType
public this.readwriteVariableName: memberType public var readwriteVariableName: memberType
- A class variable declaration: > - A class variable declaration: >
static _protectedClassVariableName: memberType static var _protectedClassVariableName: memberType
static readonlyClassVariableName: memberType static var readonlyClassVariableName: memberType
static public readwriteClassVariableName: memberType static var public readwriteClassVariableName: memberType
- A constructor method: > - A constructor method: >
def new(arguments) def new(arguments)
def newName(arguments) def newName(arguments)
@@ -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. 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. Avoid doing this for more complex types and when the type will be incomplete.
For example: > For example: >
this.nameList = [] var nameList = []
This specifies a list, but the item type is unknown. Better use: > 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. The initialization isn't needed, the list is empty by default.
*E1330* *E1330*
Some types cannot be used, such as "void", "null" and "v:none". Some types cannot be used, such as "void", "null" and "v:none".
@@ -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: > return type, but without the body and without `:enddef`. Example: >
interface HasSurface interface HasSurface
this.size: number var size: number
def Surface(): number def Surface(): number
endinterface endinterface
@@ -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: > variables, in the order they were specified. Thus if your class looks like: >
class AutoNew class AutoNew
this.name: string var name: string
this.age: number var age: number
this.gender: Gender var gender: Gender
endclass endclass
Then the default constructor will be: > Then the default constructor will be: >
@@ -690,8 +690,8 @@ value for the object variables will be used. This is a more useful example,
with default values: > with default values: >
class TextPosition class TextPosition
this.lnum: number = 1 var lnum: number = 1
this.col: number = 1 var col: number = 1
endclass endclass
If you want the constructor to have mandatory arguments, you need to write it If you want the constructor to have mandatory arguments, you need to write it
@@ -947,26 +947,26 @@ Following that Vim object variables could be declared like this: >
Some users pointed out that this looks more like an assignment than a Some users pointed out that this looks more like an assignment than a
declaration. Adding "var" changes that: > declaration. Adding "var" changes that: >
class Point class Point
var this.x: number var x: number
var this.y = 0 var y = 0
endclass endclass
We also need to be able to declare class variables using the "static" keyword. We also need to be able to declare class variables using the "static" keyword.
There we can also choose to leave out "var": > There we can also choose to leave out "var": >
class Point class Point
var this.x: number var x: number
static count = 0 static count = 0
endclass endclass
Or do use it, before "static": > Or do use it, before "static": >
class Point class Point
var this.x: number var x: number
var static count = 0 var static count = 0
endclass endclass
Or after "static": > Or after "static": >
class Point class Point
var this.x: number var x: number
static var count = 0 static var count = 0
endclass endclass
@@ -974,9 +974,16 @@ This is more in line with "static def Func()".
There is no clear preference whether to use "var" or not. The two main There is no clear preference whether to use "var" or not. The two main
reasons to leave it out are: 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. 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 ~ Using "ClassName.new()" to construct an object ~

View File

@@ -3402,11 +3402,12 @@ EXTERN char e_object_required_found_str[]
INIT(= N_("E1327: Object required, found %s")); INIT(= N_("E1327: Object required, found %s"));
EXTERN char e_constructor_default_value_must_be_vnone_str[] EXTERN char e_constructor_default_value_must_be_vnone_str[]
INIT(= N_("E1328: Constructor default value must be v:none: %s")); 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[] EXTERN char e_invalid_type_for_object_variable_str[]
INIT(= N_("E1330: Invalid type for object variable: %s")); INIT(= N_("E1330: Invalid type for object variable: %s"));
EXTERN char e_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 \"this\" or \"static\"")); INIT(= N_("E1331: Public must be followed by \"var\" or \"static\""));
EXTERN char e_public_variable_name_cannot_start_with_underscore_str[] EXTERN char e_public_variable_name_cannot_start_with_underscore_str[]
INIT(= N_("E1332: Public variable name cannot start with underscore: %s")); INIT(= N_("E1332: Public variable name cannot start with underscore: %s"));
EXTERN char e_cannot_access_protected_variable_str[] EXTERN char e_cannot_access_protected_variable_str[]
@@ -3487,8 +3488,8 @@ EXTERN char e_cannot_access_protected_method_str[]
INIT(= N_("E1366: Cannot access protected method: %s")); INIT(= N_("E1366: Cannot access protected method: %s"));
EXTERN char e_variable_str_of_interface_str_has_different_access[] EXTERN char e_variable_str_of_interface_str_has_different_access[]
INIT(= N_("E1367: Access level of variable \"%s\" of interface \"%s\" is different")); INIT(= N_("E1367: Access level of variable \"%s\" of interface \"%s\" is different"));
EXTERN char e_static_cannot_be_followed_by_this[] EXTERN char e_static_must_be_followed_by_var_or_def[]
INIT(= N_("E1368: Static cannot be followed by \"this\" in a variable name")); INIT(= N_("E1368: Static must be followed by \"var\" or \"def\""));
EXTERN char e_duplicate_variable_str[] EXTERN char e_duplicate_variable_str[]
INIT(= N_("E1369: Duplicate variable: %s")); INIT(= N_("E1369: Duplicate variable: %s"));
EXTERN char e_cannot_define_new_method_as_static[] EXTERN char e_cannot_define_new_method_as_static[]

View File

@@ -4845,7 +4845,7 @@ def Test_values()
vim9script vim9script
class Foo class Foo
this.val: number var val: number
def Add() def Add()
echo this.val echo this.val
enddef enddef

File diff suppressed because it is too large Load Diff

View File

@@ -3062,15 +3062,15 @@ def Test_disassemble_interface_static_member()
var lines =<< trim END var lines =<< trim END
vim9script vim9script
interface I interface I
this.o_var: number var o_var: number
this.o_var2: number var o_var2: number
endinterface endinterface
class C implements I class C implements I
public static s_var: number public static var s_var: number
this.o_var: number var o_var: number
public static s_var2: number public static var s_var2: number
this.o_var2: number var o_var2: number
endclass endclass
def F1(i: I) def F1(i: I)
@@ -3124,7 +3124,7 @@ def Test_disassemble_class_variable()
vim9script vim9script
class A class A
public static val = 10 public static var val = 10
def Foo(): number def Foo(): number
val = 20 val = 20
return val return val
@@ -3173,7 +3173,7 @@ def Test_disassemble_ifargnotset()
var lines =<< trim END var lines =<< trim END
vim9script vim9script
class A class A
this.val: number = 10 var val: number = 10
endclass endclass
g:instr = execute('disassemble A.new') g:instr = execute('disassemble A.new')
END END

View File

@@ -393,7 +393,7 @@ def Test_typealias_import()
lines =<< trim END lines =<< trim END
vim9script vim9script
export class MyClass export class MyClass
this.val = 10 var val = 10
endclass endclass
END END
writefile(lines, 'Xtypeexport4.vim', 'D') writefile(lines, 'Xtypeexport4.vim', 'D')
@@ -537,7 +537,7 @@ def Test_typealias_class()
var lines =<< trim END var lines =<< trim END
vim9script vim9script
class C class C
this.color = 'green' var color = 'green'
endclass endclass
type MyClass = C type MyClass = C
var o: MyClass = MyClass.new() var o: MyClass = MyClass.new()

View File

@@ -704,6 +704,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
2167,
/**/ /**/
2166, 2166,
/**/ /**/

View File

@@ -1558,9 +1558,9 @@ early_ret:
has_public = TRUE; has_public = TRUE;
p = skipwhite(line + 6); p = skipwhite(line + 6);
if (STRNCMP(p, "this", 4) != 0 && STRNCMP(p, "static", 6) != 0) if (STRNCMP(p, "var", 3) != 0 && STRNCMP(p, "static", 6) != 0)
{ {
emsg(_(e_public_must_be_followed_by_this_or_static)); emsg(_(e_public_must_be_followed_by_var_or_static));
break; break;
} }
} }
@@ -1615,30 +1615,39 @@ early_ret:
} }
has_static = TRUE; has_static = TRUE;
p = skipwhite(ps + 6); p = skipwhite(ps + 6);
if (STRNCMP(p, "var", 3) != 0 && STRNCMP(p, "def", 3) != 0)
{
emsg(_(e_static_must_be_followed_by_var_or_def));
break;
}
} }
// object members (public, read access, private): // object members (public, read access, private):
// "this._varname" // "var _varname"
// "this.varname" // "var varname"
// "public this.varname" // "public var varname"
if (STRNCMP(p, "this", 4) == 0) // class members (public, read access, private):
// "static var _varname"
// "static var varname"
// "public static var varname"
if (checkforcmd(&p, "var", 3))
{ {
if (p[4] != '.' || !eval_isnamec1(p[5])) char_u *varname = p;
{
semsg(_(e_invalid_object_variable_declaration_str), p);
break;
}
if (has_static)
{
emsg(_(e_static_cannot_be_followed_by_this));
break;
}
char_u *varname = p + 5;
char_u *varname_end = NULL; char_u *varname_end = NULL;
type_T *type = NULL; type_T *type = NULL;
char_u *init_expr = NULL; char_u *init_expr = NULL;
int has_type = FALSE; int has_type = FALSE;
if (!eval_isnamec1(*p))
{
if (has_static)
semsg(_(e_invalid_class_variable_declaration_str), line);
else
semsg(_(e_invalid_object_variable_declaration_str), line);
break;
}
if (!is_class && *varname == '_') if (!is_class && *varname == '_')
{ {
// private variables are not supported in an interface // private variables are not supported in an interface
@@ -1662,7 +1671,7 @@ early_ret:
vim_free(init_expr); vim_free(init_expr);
break; break;
} }
if (add_member(&objmembers, varname, varname_end, if (add_member(has_static ? &classmembers : &objmembers, varname, varname_end,
has_public, has_type, type, init_expr) == FAIL) has_public, has_type, type, init_expr) == FAIL)
{ {
vim_free(init_expr); vim_free(init_expr);
@@ -1764,42 +1773,6 @@ early_ret:
} }
} }
// class members
else if (has_static)
{
// class members (public, read access, private):
// "static _varname"
// "static varname"
// "public static varname"
char_u *varname = p;
char_u *varname_end = NULL;
int has_type = FALSE;
type_T *type = NULL;
char_u *init_expr = NULL;
if (parse_member(eap, line, varname, has_public,
&varname_end, &has_type, &type_list, &type,
&init_expr) == FAIL)
break;
if (is_reserved_varname(varname, varname_end))
{
vim_free(init_expr);
break;
}
if (is_duplicate_variable(&classmembers, &objmembers, varname,
varname_end))
{
vim_free(init_expr);
break;
}
if (add_member(&classmembers, varname, varname_end,
has_public, has_type, type, init_expr) == FAIL)
{
vim_free(init_expr);
break;
}
}
else else
{ {
if (is_class) if (is_class)