1
0
Fork 0
mirror of https://github.com/vim/vim synced 2025-03-23 02:05:11 +01: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: 

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
No known key found for this signature in database
GPG key ID: F3F92DA383FDDE09
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): >
class TextPosition
this.lnum: number
this.col: number
var lnum: number
var col: number
def new(lnum: number, col: number)
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
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
@ -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
@ -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
@ -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
@ -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*
@ -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
@ -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
@ -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
@ -430,8 +430,8 @@ 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
@ -439,7 +439,7 @@ a number. This example extends the one above: >
endinterface
class Square extends Shape implements HasSurface
this.size: number
var size: number
def new(this.size)
enddef
@ -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
@ -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)
@ -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".
@ -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
@ -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: >
@ -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
@ -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
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
@ -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
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 ~

View file

@ -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[]
@ -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[]

View file

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

View file

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

View file

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

View file

@ -1558,9 +1558,9 @@ early_ret:
has_public = TRUE;
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;
}
}
@ -1615,30 +1615,39 @@ early_ret:
}
has_static = TRUE;
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):
// "this._varname"
// "this.varname"
// "public this.varname"
if (STRNCMP(p, "this", 4) == 0)
// "var _varname"
// "var varname"
// "public var varname"
// 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]))
{
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 = p;
char_u *varname_end = NULL;
type_T *type = NULL;
char_u *init_expr = NULL;
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 == '_')
{
// private variables are not supported in an interface
@ -1662,7 +1671,7 @@ early_ret:
vim_free(init_expr);
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)
{
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
{
if (is_class)