I expected a lively discussion about alternatives for the class implementation, but nothing much happened. Does this mean that most people agree with making this changed: 1. Make object members public by default. They can be read and written from anywhere. 2. The only other possibility is making the object members private. This is done with the existing mechnism to prefix an underscore to the name. This simplifies things, there is no "read-only" access mode, which is currently the default. There is no need for a "plublic" keyword. This is a bit limited, but it's simple. And making things simple is part of the goals for the Vim9 script syntax. Unless there are relevant objections, I'll make this change.
This makes me uncomfortable at first consideration; allowing random actors, by default, to modify internal state of other plugins does not seem to support reliability. BUT... I have no experience with legacy vimscript, I've seen that a dict is used as an "object". So I guess the proposed access control, with "_" for private allows protection in vim9script. That said, by default having r/w access within the defining file would be nice (kinda like a java package with multiple classes in a single file), and default access private to other files. Use public for access outside the file. Guess I'm looking for a way that a trusted group of classes can have full access; but I'm not sure how important that really is (and I'm not sure how I feel about a bunch of classes in a single file). It seems some sort "package" access mechanism could be compatibly added if it turns out it's needed. One area where it might be particularly useful is vim9script libraries. But I enjoy and sometimes use python (and I occasionally do things I'd call cheating), I'm a fan of simplicity. I ported half of a vim/python hybrid plugin to vim9 leaving the primary class structure in python; I'm looking forward finishing it with vim9script classes, no matter what the rules are, and having a pure vim plugin.
-ernie
On 23/01/23 4:53 AM, Bram Moolenaar wrote:
I expected a lively discussion about alternatives for the class implementation, but nothing much happened. Does this mean that most people agree with making this changed: 1. Make object members public by default. They can be read and written from anywhere. 2. The only other possibility is making the object members private. This is done with the existing mechnism to prefix an underscore to the name. This simplifies things, there is no "read-only" access mode, which is currently the default. There is no need for a "plublic" keyword. This is a bit limited, but it's simple. And making things simple is part of the goals for the Vim9 script syntax. Unless there are relevant objections, I'll make this change.
In a previous comment on this, I said
Guess I'm looking for a way that a trusted group of classes can have full access; but I'm not sure how important that really is (and I'm not sure how I feel about a bunch of classes in a single file).
But while exploring porting some python code to vim9 I realized that I generally use lots of classes in a single file; but they are nested classes and that's one of the primary ways that private members are used from the outside (I'm talking about java, not python). I can probably achieve a lot of this by having a given object save functions/lambdas that access private stuff into function variables within the file and then use those functions from within the file. Sounds messy, but I don't like having stuff public outside of trusted code. I'm trying to experiment with this approach, but classes aren't ready for it yet. Here's what I'm thinking might work. It depends on a static class method being able to access private object members, something like the **private** method `StaticModX` in the following, and then the func `AccessXxxx` give stuff in the file access to private members. (Might want to have InitLocalAccessFunctions private and executed only the first time the constructor is called) var AccessXxxx: func class X this._xxx: string def new(this._xxx) enddef static def StaticModX(x: X, val: string) x._xxx = val enddef static def InitLocalAccessFunctions() AccessXxxx = X.StaticModX enddef endclass X.InitLocalAccessFunctions() o = X.new("some_string") AccessXxxx(o, "different_string") -ernie
Most of the implementation of classes has been done. Feel free to give
it a try. You might run into something that is still a todo item, or a
bug. Please report this in a reproducible way.
This is a good moment to evaluate the current choices. Although the
syntax and semantics are similar to popular languages, there are also
some differences. Hopefully they are easy to understand.
Doug Kearns wrote:I was just looking at the constructor documentation and noticed that the default constructor includes parameters for each field in the order they were declared. Having to change all the constructor call sites when reordering field declarations seems like a probable source of bugs, particularly when switching fields of the same type. This seems like a feature that really needs named-parameter support.Good point. Although I doubt it would happen often, it can be difficult to figure out what went wrong when it does happen. What we could do: 1. Do not change how it works, add remarks to the help warning for changing the member ordering.
BTW, it's easy to avoid the situation, add
def new()
enddef
to any class where you don't want the default constructor.
Without this, a lint could produce a warning about using default constructor.
-ernie
Doug Kearns wrote:
> I was just looking at the constructor documentation and noticed that the
> default constructor includes parameters for each field in the order they
> were declared. Having to change all the constructor call sites when
> reordering field declarations seems like a probable source of bugs,
> particularly when switching fields of the same type. This seems like a
> feature that really needs named-parameter support.
Good point. Although I doubt it would happen often, it can be difficult
to figure out what went wrong when it does happen.
What we could do:
1. Do not change how it works, add remarks to the help warning for
changing the member ordering.
2. Make the default new() method not accept arguments. The caller must
set the fields after calling new(). This is safe, but requires
several extra lines.
var obj = Class.new()
obj.line = 5
obj.column = 0
3. Add a mechanism to name the members in the call, e.g.
var obj = Class.new(line = 5, column = 0)
This is similar to 2. but puts it in one line.
It requires marking a method to not use positional arguments.a
Although 3. looks like a good solution, it requires implementing a new
mechanism. And disallowing positional arguments might be considered
weird, I cannot think of a language that has this functionality.
Most of the implementation of classes has been done. Feel free to give
it a try. You might run into something that is still a todo item, or a
bug. Please report this in a reproducible way.
This is a good moment to evaluate the current choices. Although the
syntax and semantics are similar to popular languages, there are also
some differences. Hopefully they are easy to understand.