runtime(doc): Vim9: Consistenly use class/object variable and class/object method in help (#13149)
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
committed by
GitHub
parent
abc808112e
commit
c3b315f496
@ -37,7 +37,7 @@ The basic item is an object:
|
|||||||
functions are invoked "on the object", which is what sets it apart from the
|
functions are invoked "on the object", which is what sets it apart from the
|
||||||
traditional separation of data and code that manipulates the data.
|
traditional separation of data and code that manipulates the data.
|
||||||
- An object has a well defined interface, with typed member variables and
|
- An object has a well defined interface, with typed member variables and
|
||||||
member functions.
|
methods.
|
||||||
- Objects are created from a class and all objects have the same interface.
|
- Objects are created from a class and all objects have the same interface.
|
||||||
This does not change at runtime, it is not dynamic.
|
This does not change at runtime, it is not dynamic.
|
||||||
|
|
||||||
@ -103,7 +103,7 @@ You can create an object from this class with the new() method: >
|
|||||||
|
|
||||||
var pos = TextPosition.new(1, 1)
|
var pos = TextPosition.new(1, 1)
|
||||||
|
|
||||||
The object members "lnum" and "col" can be accessed directly: >
|
The object variables "lnum" and "col" can be accessed directly: >
|
||||||
|
|
||||||
echo $'The text position is ({pos.lnum}, {pos.col})'
|
echo $'The text position is ({pos.lnum}, {pos.col})'
|
||||||
< *E1317* *E1327*
|
< *E1317* *E1327*
|
||||||
@ -111,28 +111,30 @@ If you have been using other object-oriented languages you will notice that
|
|||||||
in Vim the object members are consistently referred to with the "this."
|
in Vim the object members are consistently referred to with the "this."
|
||||||
prefix. This is different from languages like Java and TypeScript. The
|
prefix. This is different from languages like Java and TypeScript. The
|
||||||
naming convention makes the object members easy to spot. Also, when a
|
naming convention makes the object members easy to spot. Also, when a
|
||||||
variable does not have the "this." prefix you know it is not an object member.
|
variable does not have the "this." prefix you know it is not an object
|
||||||
|
variable.
|
||||||
|
|
||||||
|
|
||||||
Member write access ~
|
Object variable write access ~
|
||||||
|
|
||||||
Now try to change an object member directly: >
|
Now try to change an object variable directly: >
|
||||||
|
|
||||||
pos.lnum = 9
|
pos.lnum = 9
|
||||||
< *E1335*
|
< *E1335*
|
||||||
This will give you an error! That is because by default object members can be
|
This will give you an error! That is because by default object variables can
|
||||||
read but not set. That's why the TextPosition class provides a method for it: >
|
be read but not set. That's why the TextPosition class provides a method for
|
||||||
|
it: >
|
||||||
|
|
||||||
pos.SetLnum(9)
|
pos.SetLnum(9)
|
||||||
|
|
||||||
Allowing to read but not set an object member is the most common and safest
|
Allowing to read but not set an object variable is the most common and safest
|
||||||
way. Most often there is no problem using a value, while setting a value may
|
way. Most often there is no problem using a value, while setting a value may
|
||||||
have side effects that need to be taken care of. In this case, the SetLnum()
|
have side effects that need to be taken care of. In this case, the SetLnum()
|
||||||
method could check if the line number is valid and either give an error or use
|
method could check if the line number is valid and either give an error or use
|
||||||
the closest valid value.
|
the closest valid value.
|
||||||
*:public* *E1331*
|
*:public* *E1331*
|
||||||
If you don't care about side effects and want to allow the object member to be
|
If you don't care about side effects and want to allow the object variable to
|
||||||
changed at any time, you can make it public: >
|
be changed at any time, you can make it public: >
|
||||||
|
|
||||||
public this.lnum: number
|
public this.lnum: number
|
||||||
public this.col: number
|
public this.col: number
|
||||||
@ -140,23 +142,23 @@ changed at any time, you can make it public: >
|
|||||||
Now you don't need the SetLnum(), SetCol() and SetPosition() methods, setting
|
Now you don't need the SetLnum(), SetCol() and SetPosition() methods, setting
|
||||||
"pos.lnum" directly above will no longer give an error.
|
"pos.lnum" directly above will no longer give an error.
|
||||||
*E1326*
|
*E1326*
|
||||||
If you try to set an object member that doesn't exist you get an error: >
|
If you try to set an object variable that doesn't exist you get an error: >
|
||||||
pos.other = 9
|
pos.other = 9
|
||||||
< E1326: Member not found on object "TextPosition": other ~
|
< E1326: Member not found on object "TextPosition": other ~
|
||||||
|
|
||||||
*E1376*
|
*E1376*
|
||||||
A object member cannot be accessed using the class name.
|
A object variable cannot be accessed using the class name.
|
||||||
|
|
||||||
Private members ~
|
Private variables ~
|
||||||
*E1332* *E1333*
|
*E1332* *E1333*
|
||||||
On the other hand, if you do not want the object members to be read directly,
|
On the other hand, if you do not want the object variables to be read directly,
|
||||||
you can make them private. This is done by prefixing an underscore to the
|
you can make them private. This is done by prefixing an underscore to the
|
||||||
name: >
|
name: >
|
||||||
|
|
||||||
this._lnum: number
|
this._lnum: number
|
||||||
this._col number
|
this._col number
|
||||||
|
|
||||||
Now you need to provide methods to get the value of the private members.
|
Now you need to provide methods to get the value of the private 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
|
||||||
"Get": >
|
"Get": >
|
||||||
|
|
||||||
@ -168,7 +170,7 @@ These are commonly called getters. We recommend using a name that starts with
|
|||||||
return this._col
|
return this._col
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
This example isn't very useful, the members might as well have been public.
|
This example isn't very useful, the variables might as well have been public.
|
||||||
It does become useful if you check the value. For example, restrict the line
|
It does become useful if you check the value. For example, restrict the line
|
||||||
number to the total number of lines: >
|
number to the total number of lines: >
|
||||||
|
|
||||||
@ -202,8 +204,8 @@ the above class): >
|
|||||||
<
|
<
|
||||||
Simplifying the new() method ~
|
Simplifying the new() method ~
|
||||||
|
|
||||||
Many constructors take values for the object members. Thus you very often see
|
Many constructors take values for the object variables. Thus you very often
|
||||||
this pattern: >
|
see this pattern: >
|
||||||
|
|
||||||
class SomeClass
|
class SomeClass
|
||||||
this.lnum: number
|
this.lnum: number
|
||||||
@ -215,19 +217,20 @@ this pattern: >
|
|||||||
enddef
|
enddef
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
Not only is this text you need to write, it also has the type of each member
|
Not only is this text you need to write, it also has the type of each
|
||||||
twice. Since this is so common a shorter way to write new() is provided: >
|
variables twice. Since this is so common a shorter way to write new() is
|
||||||
|
provided: >
|
||||||
|
|
||||||
def new(this.lnum, this.col)
|
def new(this.lnum, this.col)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
The semantics are easy to understand: Providing the object member name,
|
The semantics are easy to understand: Providing the object variable name,
|
||||||
including "this.", as the argument to new() means the value provided in the
|
including "this.", as the argument to new() means the value provided in the
|
||||||
new() call is assigned to that object member. This mechanism comes from the
|
new() call is assigned to that object variable. This mechanism comes from the
|
||||||
Dart language.
|
Dart language.
|
||||||
|
|
||||||
Putting together this way of using new() and making the members public results
|
Putting together this way of using new() and making the variables public
|
||||||
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 this.lnum: number
|
||||||
@ -244,15 +247,15 @@ in a much shorter class definition than what we started with: >
|
|||||||
|
|
||||||
The sequence of constructing a new object is:
|
The sequence of constructing a new object is:
|
||||||
1. Memory is allocated and cleared. All values are zero/false/empty.
|
1. Memory is allocated and cleared. All values are zero/false/empty.
|
||||||
2. For each declared member that has an initializer, the expression is
|
2. For each declared object variable that has an initializer, the expression
|
||||||
evaluated and assigned to the member. This happens in the sequence the
|
is evaluated and assigned to the variable. This happens in the sequence
|
||||||
members are declared in the class.
|
the variables are declared in the class.
|
||||||
3. Arguments in the new() method in the "this.name" form are assigned.
|
3. Arguments in the new() method in the "this.name" form are assigned.
|
||||||
4. The body of the new() method is executed.
|
4. The body of the new() method is executed.
|
||||||
|
|
||||||
If the class extends a parent class, the same thing happens. In the second
|
If the class extends a parent class, the same thing happens. In the second
|
||||||
step the members of the parent class are done first. There is no need to call
|
step the object variables of the parent class are initialized first. There is
|
||||||
"super()" or "new()" on the parent.
|
no need to call "super()" or "new()" on the parent.
|
||||||
|
|
||||||
*E1365*
|
*E1365*
|
||||||
When defining the new() method the return type should not be specified. It
|
When defining the new() method the return type should not be specified. It
|
||||||
@ -275,7 +278,7 @@ prefix in the class where they are defined: >
|
|||||||
enddef
|
enddef
|
||||||
endclass
|
endclass
|
||||||
< *E1340* *E1341*
|
< *E1340* *E1341*
|
||||||
Since the name is used as-is, shadowing the name by a function argument name
|
Since the name is used as-is, shadowing the name by a method argument name
|
||||||
or local variable name is not allowed.
|
or local variable name is not allowed.
|
||||||
|
|
||||||
*E1374* *E1375*
|
*E1374* *E1375*
|
||||||
@ -394,7 +397,7 @@ does not have any new() method. *E1359*
|
|||||||
|
|
||||||
*abstract-method* *E1371* *E1372*
|
*abstract-method* *E1371* *E1372*
|
||||||
An abstract method can be defined in an abstract class by using the "abstract"
|
An abstract method can be defined in an abstract class by using the "abstract"
|
||||||
prefix when defining the function: >
|
prefix when defining the method: >
|
||||||
|
|
||||||
abstract class Shape
|
abstract class Shape
|
||||||
abstract def Draw()
|
abstract def Draw()
|
||||||
@ -510,17 +513,16 @@ once. They can appear in any order, although this order is recommended: >
|
|||||||
implements InterfaceName, OtherInterface
|
implements InterfaceName, OtherInterface
|
||||||
specifies SomeInterface
|
specifies SomeInterface
|
||||||
< *E1355* *E1369*
|
< *E1355* *E1369*
|
||||||
Each member and function name can be used only once. It is not possible to
|
Each variable and method name can be used only once. It is not possible to
|
||||||
define a function with the same name and different type of arguments. It is
|
define a method with the same name and different type of arguments. It is not
|
||||||
not possible to use a public and private member variable with the same name.
|
possible to use a public and private member variable with the same name. A
|
||||||
A object variable name used in a super class cannot be reused in a child
|
object variable name used in a super class cannot be reused in a child class.
|
||||||
class.
|
|
||||||
|
|
||||||
|
|
||||||
Member Initialization ~
|
Object Variable Initialization ~
|
||||||
If the type of a member is not explicitly specified in a class, then it is set
|
If the type of a variable is not explicitly specified in a class, then it is
|
||||||
to "any" during class definition. When an object is instantiated from the
|
set to "any" during class definition. When an object is instantiated from the
|
||||||
class, then the type of the member is set.
|
class, then the type of the variable is set.
|
||||||
|
|
||||||
|
|
||||||
Extending a class ~
|
Extending a class ~
|
||||||
@ -531,7 +533,7 @@ The basic idea is to build on top of an existing class, add properties to it.
|
|||||||
The extended class is called the "base class" or "super class". The new class
|
The extended class is called the "base class" or "super class". The new class
|
||||||
is called the "child class".
|
is called the "child class".
|
||||||
|
|
||||||
Object members from the base class are all taken over by the child class. It
|
Object variables from the base class are all taken over by the child class. It
|
||||||
is not possible to override them (unlike some other languages).
|
is not possible to override them (unlike some other languages).
|
||||||
|
|
||||||
*E1356* *E1357* *E1358*
|
*E1356* *E1357* *E1358*
|
||||||
@ -545,19 +547,19 @@ the same as the super class.
|
|||||||
|
|
||||||
Other object methods of the base class are taken over by the child class.
|
Other object methods of the base class are taken over by the child class.
|
||||||
|
|
||||||
Class functions, including functions starting with "new", can be overruled,
|
Class methods, including methods starting with "new", can be overruled, like
|
||||||
like with object methods. The function on the base class can be called by
|
with object methods. The method on the base class can be called by prefixing
|
||||||
prefixing the name of the class (for class functions) or "super.".
|
the name of the class (for class methods) or "super.".
|
||||||
|
|
||||||
Unlike other languages, the constructor of the base class does not need to be
|
Unlike other languages, the constructor of the base class does not need to be
|
||||||
invoked. In fact, it cannot be invoked. If some initialization from the base
|
invoked. In fact, it cannot be invoked. If some initialization from the base
|
||||||
class also needs to be done in a child class, put it in an object method and
|
class also needs to be done in a child class, put it in an object method and
|
||||||
call that method from every constructor().
|
call that method from every constructor().
|
||||||
|
|
||||||
If the base class did not specify a new() function then one was automatically
|
If the base class did not specify a new() method then one was automatically
|
||||||
created. This function will not be taken over by the child class. The child
|
created. This method will not be taken over by the child class. The child
|
||||||
class can define its own new() function, or, if there isn't one, a new()
|
class can define its own new() method, or, if there isn't one, a new() method
|
||||||
function will be added automatically.
|
will be added automatically.
|
||||||
|
|
||||||
|
|
||||||
A class implementing an interface ~
|
A class implementing an interface ~
|
||||||
@ -569,7 +571,7 @@ commas. Each interface name can appear only once. *E1351*
|
|||||||
|
|
||||||
A class defining an interface ~
|
A class defining an interface ~
|
||||||
*specifies*
|
*specifies*
|
||||||
A class can declare its interface, the object members and methods, with a
|
A class can declare its interface, the object variables and methods, with a
|
||||||
named interface. This avoids the need for separately specifying the
|
named interface. This avoids the need for separately specifying the
|
||||||
interface, which is often done in many languages, especially Java.
|
interface, which is often done in many languages, especially Java.
|
||||||
|
|
||||||
@ -577,14 +579,14 @@ interface, which is often done in many languages, especially Java.
|
|||||||
Items in a class ~
|
Items in a class ~
|
||||||
*E1318* *E1325*
|
*E1318* *E1325*
|
||||||
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 member declaration: >
|
- An object variable declaration: >
|
||||||
this._privateMemberName: memberType
|
this._privateVariableName: memberType
|
||||||
this.readonlyMemberName: memberType
|
this.readonlyVariableName: memberType
|
||||||
public this.readwriteMemberName: memberType
|
public this.readwriteVariableName: memberType
|
||||||
- A class member declaration: >
|
- A class variable declaration: >
|
||||||
static this._privateMemberName: memberType
|
static _privateClassVariableName: memberType
|
||||||
static this.readonlyMemberName: memberType
|
static readonlyClassVariableName: memberType
|
||||||
static public this.readwriteMemberName: memberType
|
static public readwriteClassVariableName: memberType
|
||||||
- A constructor method: >
|
- A constructor method: >
|
||||||
def new(arguments)
|
def new(arguments)
|
||||||
def newName(arguments)
|
def newName(arguments)
|
||||||
@ -595,10 +597,11 @@ Inside a class, in between `:class` and `:endclass`, these items can appear:
|
|||||||
def SomeMethod(arguments)
|
def SomeMethod(arguments)
|
||||||
def _PrivateMethod(arguments)
|
def _PrivateMethod(arguments)
|
||||||
|
|
||||||
For the object member the type must be specified. The best way is to do this
|
For the object variable the type must be specified. The best way is to do
|
||||||
explicitly with ": {type}". For simple types you can also use an initializer,
|
this explicitly with ": {type}". For simple types you can also use an
|
||||||
such as "= 123", and Vim will see that the type is a number. Avoid doing this
|
initializer, such as "= 123", and Vim will see that the type is a number.
|
||||||
for more complex types and when the type will be incomplete. For example: >
|
Avoid doing this for more complex types and when the type will be incomplete.
|
||||||
|
For example: >
|
||||||
this.nameList = []
|
this.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>
|
this.nameList: list<string>
|
||||||
@ -618,8 +621,8 @@ prefixed with `:export`: >
|
|||||||
export interface InterfaceName
|
export interface InterfaceName
|
||||||
endinterface
|
endinterface
|
||||||
< *E1344*
|
< *E1344*
|
||||||
An interface can declare object members, just like in a class but without any
|
An interface can declare object variables, just like in a class but without
|
||||||
initializer.
|
any initializer.
|
||||||
*E1345*
|
*E1345*
|
||||||
An interface can declare methods with `:def`, including the arguments and
|
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: >
|
||||||
@ -642,15 +645,15 @@ null object ~
|
|||||||
When a variable is declared to have the type of an object, but it is not
|
When a variable is declared to have the type of an object, but it is not
|
||||||
initialized, the value is null. When trying to use this null object Vim often
|
initialized, the value is null. When trying to use this null object Vim often
|
||||||
does not know what class was supposed to be used. Vim then cannot check if
|
does not know what class was supposed to be used. Vim then cannot check if
|
||||||
a member name is correct and you will get an "Using a null object" error,
|
a variable name is correct and you will get an "Using a null object" error,
|
||||||
even when the member name is invalid. *E1360* *E1362* *E1363*
|
even when the variable name is invalid. *E1360* *E1362* *E1363*
|
||||||
|
|
||||||
|
|
||||||
Default constructor ~
|
Default constructor ~
|
||||||
|
|
||||||
In case you define a class without a new() method, one will be automatically
|
In case you define a class without a new() method, one will be automatically
|
||||||
defined. This default constructor will have arguments for all the object
|
defined. This default constructor will have arguments for all the object
|
||||||
members, 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
|
this.name: string
|
||||||
@ -658,14 +661,14 @@ members, in the order they were specified. Thus if your class looks like: >
|
|||||||
this.gender: Gender
|
this.gender: Gender
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
Then The default constructor will be: >
|
Then the default constructor will be: >
|
||||||
|
|
||||||
def new(this.name = v:none, this.age = v:none, this.gender = v:none)
|
def new(this.name = v:none, this.age = v:none, this.gender = v:none)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
The "= v:none" default values make the arguments optional. Thus you can also
|
The "= v:none" default values make the arguments optional. Thus you can also
|
||||||
call `new()` without any arguments. No assignment will happen and the default
|
call `new()` without any arguments. No assignment will happen and the default
|
||||||
value for the object members will be used. This is a more useful example,
|
value for the object variables will be used. This is a more useful example,
|
||||||
with default values: >
|
with default values: >
|
||||||
|
|
||||||
class TextPosition
|
class TextPosition
|
||||||
@ -681,13 +684,13 @@ the name, you can define the constructor like this: >
|
|||||||
enddef
|
enddef
|
||||||
< *E1328*
|
< *E1328*
|
||||||
Note that you cannot use another default value than "v:none" here. If you
|
Note that you cannot use another default value than "v:none" here. If you
|
||||||
want to initialize the object members, do it where they are declared. This
|
want to initialize the object variables, do it where they are declared. This
|
||||||
way you only need to look in one place for the default values.
|
way you only need to look in one place for the default values.
|
||||||
|
|
||||||
All object members will be used in the default constructor, also private
|
All object variables will be used in the default constructor, also private
|
||||||
access ones.
|
access ones.
|
||||||
|
|
||||||
If the class extends another one, the object members of that class will come
|
If the class extends another one, the object variables of that class will come
|
||||||
first.
|
first.
|
||||||
|
|
||||||
|
|
||||||
@ -801,7 +804,7 @@ the method being called is obvious.
|
|||||||
No overloading of the constructor ~
|
No overloading of the constructor ~
|
||||||
|
|
||||||
In Vim script, both legacy and |Vim9| script, there is no overloading of
|
In Vim script, both legacy and |Vim9| script, there is no overloading of
|
||||||
functions. That means it is not possible to use the same function name with
|
methods. That means it is not possible to use the same method name with
|
||||||
different types of arguments. Therefore there also is only one new()
|
different types of arguments. Therefore there also is only one new()
|
||||||
constructor.
|
constructor.
|
||||||
|
|
||||||
@ -844,39 +847,40 @@ class implements an interface just because the methods happen to match is
|
|||||||
brittle and leads to obscure problems, let's not do that.
|
brittle and leads to obscure problems, let's not do that.
|
||||||
|
|
||||||
|
|
||||||
Using "this.member" everywhere ~
|
Using "this.variable" everywhere ~
|
||||||
|
|
||||||
The object members in various programming languages can often be accessed in
|
The object variables in various programming languages can often be accessed in
|
||||||
different ways, depending on the location. Sometimes "this." has to be
|
different ways, depending on the location. Sometimes "this." has to be
|
||||||
prepended to avoid ambiguity. They are usually declared without "this.".
|
prepended to avoid ambiguity. They are usually declared without "this.".
|
||||||
That is quite inconsistent and sometimes confusing.
|
That is quite inconsistent and sometimes confusing.
|
||||||
|
|
||||||
A very common issue is that in the constructor the arguments use the same name
|
A very common issue is that in the constructor the arguments use the same name
|
||||||
as the object member. Then for these members "this." needs to be prefixed in
|
as the object variable. Then for these variables "this." needs to be prefixed
|
||||||
the body, while for other members this is not needed and often omitted. This
|
in the body, while for other variables this is not needed and often omitted.
|
||||||
leads to a mix of members with and without "this.", which is inconsistent.
|
This leads to a mix of variables with and without "this.", which is
|
||||||
|
inconsistent.
|
||||||
|
|
||||||
For |Vim9| classes the "this." prefix is always used. Also for declaring the
|
For |Vim9| classes the "this." prefix is always used. Also for declaring the
|
||||||
members. Simple and consistent. When looking at the code inside a class it's
|
variables. Simple and consistent. When looking at the code inside a class
|
||||||
also directly clear which variable references are object members and which
|
it's also directly clear which variable references are object variables and
|
||||||
aren't.
|
which aren't.
|
||||||
|
|
||||||
|
|
||||||
Using class members ~
|
Using class variables ~
|
||||||
|
|
||||||
Using "static member" to declare a class member is very common, nothing new
|
Using "static variable" to declare a class variable is very common, nothing
|
||||||
here. In |Vim9| script these can be accessed directly by their name. Very
|
new here. In |Vim9| script these can be accessed directly by their name.
|
||||||
much like how a script-local variable can be used in a function. Since object
|
Very much like how a script-local variable can be used in a method. Since
|
||||||
members are always accessed with "this." prepended, it's also quickly clear
|
object variables are always accessed with "this." prepended, it's also quickly
|
||||||
what kind of member it is.
|
clear what kind of variable it is.
|
||||||
|
|
||||||
TypeScript prepends the class name before the class member, also inside the
|
TypeScript prepends the class name before the class variable name, also inside
|
||||||
class. This has two problems: The class name can be rather long, taking up
|
the class. This has two problems: The class name can be rather long, taking
|
||||||
quite a bit of space, and when the class is renamed all these places need to
|
up quite a bit of space, and when the class is renamed all these places need
|
||||||
be changed too.
|
to be changed too.
|
||||||
|
|
||||||
|
|
||||||
Declaring object and class members ~
|
Declaring object and class variables ~
|
||||||
|
|
||||||
The main choice is whether to use "var" as with variable declarations.
|
The main choice is whether to use "var" as with variable declarations.
|
||||||
TypeScript does not use it: >
|
TypeScript does not use it: >
|
||||||
@ -885,7 +889,7 @@ TypeScript does not use it: >
|
|||||||
y = 0;
|
y = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Following that Vim object members could be declared like this: >
|
Following that Vim object variables could be declared like this: >
|
||||||
class Point
|
class Point
|
||||||
this.x: number
|
this.x: number
|
||||||
this.y = 0
|
this.y = 0
|
||||||
@ -898,7 +902,7 @@ declaration. Adding "var" changes that: >
|
|||||||
var this.y = 0
|
var this.y = 0
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
We also need to be able to declare class members 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 this.x: number
|
||||||
@ -938,50 +942,50 @@ while there is no ClassName() method, it's a method by another name in the
|
|||||||
class called ClassName. Quite confusing.
|
class called ClassName. Quite confusing.
|
||||||
|
|
||||||
|
|
||||||
Default read access to object members ~
|
Default read access to object variables ~
|
||||||
|
|
||||||
Some users will remark that the access rules for object members are
|
Some users will remark that the access rules for object variables are
|
||||||
asymmetric. Well, that is intentional. Changing a value is a very different
|
asymmetric. Well, that is intentional. Changing a value is a very different
|
||||||
action than reading a value. The read operation has no side effects, it can
|
action than reading a value. The read operation has no side effects, it can
|
||||||
be done any number of times without affecting the object. Changing the value
|
be done any number of times without affecting the object. Changing the value
|
||||||
can have many side effects, and even have a ripple effect, affecting other
|
can have many side effects, and even have a ripple effect, affecting other
|
||||||
objects.
|
objects.
|
||||||
|
|
||||||
When adding object members one usually doesn't think much about this, just get
|
When adding object variables one usually doesn't think much about this, just
|
||||||
the type right. And normally the values are set in the new() method.
|
get the type right. And normally the values are set in the new() method.
|
||||||
Therefore defaulting to read access only "just works" in most cases. And when
|
Therefore defaulting to read access only "just works" in most cases. And when
|
||||||
directly writing you get an error, which makes you wonder if you actually want
|
directly writing you get an error, which makes you wonder if you actually want
|
||||||
to allow that. This helps writing code with fewer mistakes.
|
to allow that. This helps writing code with fewer mistakes.
|
||||||
|
|
||||||
|
|
||||||
Making object members private with an underscore ~
|
Making object variables private with an underscore ~
|
||||||
|
|
||||||
When an object member is private, it can only be read and changed inside the
|
When an object variable is private, it can only be read and changed inside the
|
||||||
class (and in sub-classes), then it cannot be used outside of the class.
|
class (and in sub-classes), then it cannot be used outside of the class.
|
||||||
Prepending an underscore is a simple way to make that visible. Various
|
Prepending an underscore is a simple way to make that visible. Various
|
||||||
programming languages have this as a recommendation.
|
programming languages have this as a recommendation.
|
||||||
|
|
||||||
In case you change your mind and want to make the object member accessible
|
In case you change your mind and want to make the object variable accessible
|
||||||
outside of the class, you will have to remove the underscore everywhere.
|
outside of the class, you will have to remove the underscore everywhere.
|
||||||
Since the name only appears in the class (and sub-classes) they will be easy
|
Since the name only appears in the class (and sub-classes) they will be easy
|
||||||
to find and change.
|
to find and change.
|
||||||
|
|
||||||
The other way around is much harder: you can easily prepend an underscore to
|
The other way around is much harder: you can easily prepend an underscore to
|
||||||
the object member inside the class to make it private, but any usage elsewhere
|
the object variable inside the class to make it private, but any usage
|
||||||
you will have to track down and change. You may have to make it a "set"
|
elsewhere you will have to track down and change. You may have to make it a
|
||||||
method call. This reflects the real world problem that taking away access
|
"set" method call. This reflects the real world problem that taking away
|
||||||
requires work to be done for all places where that access exists.
|
access requires work to be done for all places where that access exists.
|
||||||
|
|
||||||
An alternative would have been using the "private" keyword, just like "public"
|
An alternative would have been using the "private" keyword, just like "public"
|
||||||
changes the access in the other direction. Well, that's just to reduce the
|
changes the access in the other direction. Well, that's just to reduce the
|
||||||
number of keywords.
|
number of keywords.
|
||||||
|
|
||||||
|
|
||||||
No protected object members ~
|
No protected object variables ~
|
||||||
|
|
||||||
Some languages provide several ways to control access to object members. The
|
Some languages provide several ways to control access to object variables.
|
||||||
most known is "protected", and the meaning varies from language to language.
|
The most known is "protected", and the meaning varies from language to
|
||||||
Others are "shared", "private" and even "friend".
|
language. Others are "shared", "private" and even "friend".
|
||||||
|
|
||||||
These rules make life more difficult. That can be justified in projects where
|
These rules make life more difficult. That can be justified in projects where
|
||||||
many people work on the same, complex code where it is easy to make mistakes.
|
many people work on the same, complex code where it is easy to make mistakes.
|
||||||
|
|||||||
Reference in New Issue
Block a user