Choices for Vim9 class implementation

302 views
Skip to first unread message

Bram Moolenaar

unread,
Dec 18, 2022, 8:33:24 AM12/18/22
to vim...@googlegroups.com

You may have noticed I started implementing classes for Vim9 script.
There are quite a few detailed choices to make. I have already written
the documentation with the current ideas: ":help vim9class". But
nothing is set in stone yet, we can discuss improvements.

One thing where different languages have a different way of doing things
is how object and class members are declared. Some are very verbose and
offer detailed options for access, others are so concise it's hard to
spot declarations and some have hardly any access control. For Vim9 the
goal is to keep it simple, only support the features we really need, use
a simple syntax.

For object members most languages use the "this." prefix. But not
everywhere, which makes it inconsistent. A good example is a
constructor where object members that are also an argument need to be
prefixed with "this." to avoid a name collision, while other object
members are used without "this.". I find that very confusing. Example:

SomeObject(String name)
{
this.name = name;
gender = Gender.unknown;
}

Here both "name and "gender" are object members, but used differently,
because "name" is also an argument.

I looked into using the "this." prefix for object members everywhere,
and that turns out to work very well. It's not really different from
what other languages are doing, it's not a new mechanism. But instead
of using it optionally, require using it everywhere makes it consistent.

One thing I'm not yet sure about is the declaration. Currently it works
like this:

this.name: string
this.gender: Gender

Notice that there is no "var" keyword. It's not needed to recognize the
declaration. I can't think of a good reason to add "var" here, other
than that a declaration would be expected to always have "var". Well, I
don't have that expectation.

For class members most languages use the "static" keyword. It's a bit
of a weird word, but I suppose most people are used to it, and I can't
find a popular language that has a good alternative.

If we leave out "var" for object members, I suppose we should also leave
it out for class members. We then get:

static oneClassMember: number
static twoClassMember: string

I think this looks fine. Any objections?


--
MORTICIAN: Bring out your dead!
[clang]
Bring out your dead!
[clang]
Bring out your dead!
CUSTOMER: Here's one -- nine pence.
DEAD PERSON: I'm not dead!
The Quest for the Holy Grail (Monty Python)

/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///

N i c o l a s

unread,
Dec 18, 2022, 12:12:53 PM12/18/22
to vim_dev
Hi Bram, 

Just to remember static meaning in C/C++ :
'' 
A static variable inside a function keeps its value between invocations ''. 

In C++ static class purpose is helper class and don't need to be instantiated. Furthermore, direct access to static member can be easily done as this :   MyHelper::myStaticMember


Will it be same meaning  in vim9 class ? 
I think it should. 

N i c o l a s

Bram Moolenaar

unread,
Dec 18, 2022, 4:55:13 PM12/18/22
to vim...@googlegroups.com, N i c o l a s

> Just to remember static meaning in C/C++ :
> ''
> A static variable inside a function keeps its value between invocations ''.
> https://stackoverflow.com/questions/572547/what-does-static-mean-in-c/572550#572550

We don't have static variables inside a function. Perhaps some day.
In a class you can use the class member variables in a function, thus
you could do:

static someCount
def SomeFunc()
someCount += 1
echo 'count is now' someCount

> In C++ static class purpose is helper class and don't need to be
> instantiated.

There are no plans for that.

> Furthermore, direct access to static member can be easily
> done as this : MyHelper::myStaticMember
>
> https://stackoverflow.com/questions/10442404/invoke-a-c-class-method-without-a-class-instance/10442432#10442432
>
> Will it be same meaning in vim9 class ?
> I think it should.

C++ has lots of features that we won't get in Vim9 script. C++ is too
complicated and the syntax is hard to understand, it's not a good
example of a "nice" object oriented language.

--
DEAD PERSON: I'm getting better!
CUSTOMER: No, you're not -- you'll be stone dead in a moment.
MORTICIAN: Oh, I can't take him like that -- it's against regulations.

Maxim Kim

unread,
Dec 18, 2022, 6:00:22 PM12/18/22
to vim_dev


понедельник, 19 декабря 2022 г. в 00:33:24 UTC+11, Bram Moolenaar:




For object members most languages use the "this." prefix. But not
everywhere, which makes it inconsistent. A good example is a
constructor where object members that are also an argument need to be
prefixed with "this." to avoid a name collision, while other object
members are used without "this.". I find that very confusing. Example:

SomeObject(String name)
{
this.name = name;
gender = Gender.unknown;
}

 
I would go with this.name and this.gender while accessing the variables.
 

One thing I'm not yet sure about is the declaration. Currently it works
like this:

this.name: string
this.gender: Gender

and

var name: string
var gender: Gender

to declare them.

Christopher Plewright

unread,
Dec 19, 2022, 3:52:34 AM12/19/22
to vim_dev
I'm not a big fan of the "this" keyword.   I agree if going to use it, ensure to use it everywhere.  Consistency is good.  I like simplicity, and dislike redundancy.

So, about "this", alternatively,  don't use it anywhere, but maybe you could throw an error if a function argument name is also member variable name.  Not sure what static analysis is available - given that its a scripting language.  There's not really a compilation step is there?

OR, perhaps another option, just thinking outside the box, if a function argument does actually happen to match a member variable name - then automatically force it to actually set that variable.  When (if) this becomes the expected behavior, I think it would enable simplifying some things a lot.

Explaining with an example.  Often, when I'm coding and the arg name is the same as a member variable name,  then I usually find myself setting that early-ish in the code.  (just using a pseudo code to explain, obviously not real code;)

class Blahh
this.toX: TYPE_A
this.toX: TYPE_B
fn SetXandY(toX: TPYE_A, toY: TYPE_B )
  this.toX = toX
  this.toY = toY
enfunc
endclass

So, I find that pattern happens a lot.  And it gets real tedious.    I think this could be simplified to the following;

class Blahh
toX: TYPE_A
toX: TYPE_B
fn  SetXandY(toX, toY)
enfunc
endclass

ie. This would set the member variables, toX and toY automatically.

Now, we might want to do some sanity check on the argument before clobbering whatever was in there previously.  The developer could very easily use another temporary name, for example prefixed with p_ as they wish, and check it is in range for example, before setting it.  Like so;

class Blahh
toX: TYPE_A
toX: TYPE_B
fn  SetXandY(p_toX, toY)
if p_toX in range
    toX = p_toX
else
  ignore, or throw, or set some default, whatever for toX 
endif
enfunc
endclass

In this last example, any matching names could be automatically set, so here, the toY would be automatically set.

This is inspired by your idea from the constructor idea you had here;
def new(this.lnum, this.col)
enddef

I like that one :)

Cheers,

Chris Plewright

Christopher Plewright

unread,
Dec 19, 2022, 4:13:37 AM12/19/22
to vim_dev
On Monday, 19 December 2022 at 19:52:34 UTC+11 Christopher Plewright wrote:
I'm not a big fan of the "this" keyword.   I agree if going to use it, ensure to use it everywhere.  Consistency is good.  I like simplicity, and dislike redundancy.

So, about "this", alternatively,  don't use it anywhere, but maybe you could throw an error if a function argument name is also member variable name.  Not sure what static analysis is available - given that its a scripting language.  There's not really a compilation step is there?

OR, perhaps another option, just thinking outside the box, if a function argument does actually happen to match a member variable name - then automatically force it to actually set that variable.  When (if) this becomes the expected behavior, I think it would enable simplifying some things a lot.

Explaining with an example.  Often, when I'm coding and the arg name is the same as a member variable name,  then I usually find myself setting that early-ish in the code.  (just using a pseudo code to explain, obviously not real code;)

class Blahh
this.toX: TYPE_A
this.toY: TYPE_B
fn SetXandY(toX: TPYE_A, toY: TYPE_B )
  this.toX = toX
  this.toY = toY
enfunc
endclass

So, I find that pattern happens a lot.  And it gets real tedious.    I think this could be simplified to the following;

class Blahh
toX: TYPE_A
toY: TYPE_B
fn  SetXandY(toX, toY)
enfunc
endclass

ie. This would set the member variables, toX and toY automatically.

Now, we might want to do some sanity check on the argument before clobbering whatever was in there previously.  The developer could very easily use another temporary name, for example prefixed with p_ as they wish, and check it is in range for example, before setting it.  Like so;

class Blahh
toX: TYPE_A
toY: TYPE_B
fn  SetXandY(p_toX, toY)
if p_toX in range
    toX = p_toX
else
  ignore, or throw, or set some default, whatever for toX 
endif
enfunc
endclass

In this last example, any matching names could be automatically set, so here, the toY would be automatically set.

 
This is inspired by your idea from the constructor idea you had here;
def new(this.lnum, this.col)
enddef

I like that one :)

Cheers,

Chris Plewright



1. Sorry for top posting.  I'm still learning to navigate the google groups platform.
2. typo:  toX: TYPE_B  was meant to be  toY: TYPE_B   Hope my idea is still readable.  Have fixed that in this reply anyway.
 

Bram Moolenaar

unread,
Dec 19, 2022, 9:26:15 AM12/19/22
to vim...@googlegroups.com, Christopher Plewright

> I'm not a big fan of the "this" keyword. I agree if going to use it,
> ensure to use it everywhere. Consistency is good. I like simplicity, and
> dislike redundancy.

What do you mean, do you prefer "self"?

> So, about "this", alternatively, don't use it anywhere, but maybe you
> could throw an error if a function argument name is also member variable
> name.

That is actually very common. It is very likely that methods pass
arguments to set or modify the object members, thus using the same name
is very likely to happen.

> Not sure what static analysis is available - given that its a
> scripting language. There's not really a compilation step is there?

Some minimal checks can be done, but static analysis is too complicated
and time consuming to build in.

> OR, perhaps another option, just thinking outside the box, if a function
> argument does actually happen to match a member variable name - then
> automatically force it to actually set that variable. When (if) this
> becomes the expected behavior, I think it would enable simplifying some
> things a lot.

Boundary checks are often done on arguments, assuming that the argument
is always assigned to an object member is too limiting.

I also want to avoid doing things very differently from what existing
languages are doing. Some different syntax and rules can be acceptable,
but introducing new mechanisms that are hard to understand are to be
avoided.

> Explaining with an example. Often, when I'm coding and the arg name is the
> same as a member variable name, then I usually find myself setting that
> early-ish in the code. (just using a pseudo code to explain, obviously not
> real code;)
>
> class Blahh
> this.toX: TYPE_A
> this.toY: TYPE_B
> fn SetXandY(toX: TPYE_A, toY: TYPE_B )
> this.toX = toX
> this.toY = toY
> enfunc
> endclass
>
> So, I find that pattern happens a lot. And it gets real tedious. I
> think this could be simplified to the following;
>
> class Blahh
> toX: TYPE_A
> toY: TYPE_B
> fn SetXandY(toX, toY)
> enfunc
> endclass
>
> ie. This would set the member variables, toX and toY automatically.

I don't know any language that does this and I find it very obscure and
confusing. Also, it makes giving useful errors difficult. Using an
argument name that happens to be a member name would not result in any
error but silently turned into an assignment.

[...]

--
A computer programmer is a device for turning requirements into
undocumented features. It runs on cola, pizza and Dilbert cartoons.
Bram Moolenaar

Bram Moolenaar

unread,
Dec 19, 2022, 9:26:17 AM12/19/22
to vim...@googlegroups.com, Maxim Kim

> > One thing I'm not yet sure about is the declaration. Currently it works
> > like this:
> >
> > this.name: string
> > this.gender: Gender
> >
> > and
>
> var name: string
> var gender: Gender
>
> to declare them.

That is indeed an alternative, and more like a normal declaration.
Although in Typescript, which syntax has been mostly used for
declarations, it would be:

name: string;
gender: Gender;

Unfortunately, this doesn't stand out and easily gets lost in a long
class. It would require the habit of putting all the members at the
start of the class.

Other languages, like Java, put the type before the name and also don't
have a keyword, e.g.:

String name;
Gender gender;

There are advantages and disadvantages of using the normal "var" style
declarations. But it appears that most language don't declare object
members with a keyword.

I still like the consistency of always prefixing the object members with
"this.", instead of having it depend on the context.


--
A mathematician is a device for turning coffee into theorems.
Paul Erdos
A computer programmer is a device for turning coffee into bugs.

Christopher Plewright

unread,
Dec 19, 2022, 10:12:37 AM12/19/22
to vim_dev
On Tuesday, 20 December 2022 at 01:26:15 UTC+11 Bram Moolenaar wrote:

> I'm not a big fan of the "this" keyword. I agree if going to use it,
> ensure to use it everywhere. Consistency is good. I like simplicity, and
> dislike redundancy.

What do you mean, do you prefer "self"?

No, I prefer 'this' over 'self'.   I was considering if its possible to go without any keyword for it.   For example, these days we also have syntax highlighting which can give a different color for member variables and arguments.
 
> So, about "this", alternatively, don't use it anywhere, but maybe you
> could throw an error if a function argument name is also member variable
> name.

That is actually very common. It is very likely that methods pass
arguments to set or modify the object members, thus using the same name
is very likely to happen.

Yes, it is common, and it is a source of confusion & errors - especially when its not referring to the same thing.  Thats my point.  It seems like it would be better practice to use different names for different context, especially when those contexts overlap in scope.
 
> OR, perhaps another option, just thinking outside the box, if a function
> argument does actually happen to match a member variable name - then
> automatically force it to actually set that variable. When (if) this
> becomes the expected behavior, I think it would enable simplifying some
> things a lot.

Boundary checks are often done on arguments, assuming that the argument
is always assigned to an object member is too limiting.

To be clear, I didn't mean that every argument is always assigned to an object member, I only meant assign it when it has the same name...  I think you understood anyay, but just in case I was ambiguous.

But, yes, I see that it could be restrictive.  Still, really, if you are using the same name to mean something different, then that is also a potential pitfall.
 
 
I also want to avoid doing things very differently from what existing
languages are doing. Some different syntax and rules can be acceptable,
but introducing new mechanisms that are hard to understand are to be
avoided.

It is unusual, I agree.  I've never seen it done like that in any modern major language.  It reminds me of some languages that don't really use scope very well, where ALL of the variable names were pretty much scoped to the whole class, no matter where they were declared in that class.  I can't recall what language I saw that in, that was over 20 years ago.  
 
> class Blahh
> this.toX: TYPE_A
> this.toY: TYPE_B
> fn SetXandY(toX: TPYE_A, toY: TYPE_B )
> this.toX = toX
> this.toY = toY
> enfunc
> endclass
>
> So, I find that pattern happens a lot. And it gets real tedious. I
> think this could be simplified to the following;
>
> class Blahh
> toX: TYPE_A
> toY: TYPE_B
> fn SetXandY(toX, toY)
> enfunc
> endclass
>
> ie. This would set the member variables, toX and toY automatically.

I don't know any language that does this and I find it very obscure and
confusing. Also, it makes giving useful errors difficult. Using an
argument name that happens to be a member name would not result in any
error but silently turned into an assignment.

Yeah, it could be confusing to get used to it.  But, there would not need to be any error messages, because it wouldn't be an error. It would be a feature.  And, once you got used to it, you'd realise it solves a number of problems.

I take your point though.  Considering it would behave different to current paradigm of most popular languages, then users would get surprised that they didn't get an error - because they were expecting something different to happen.

But, at the end of the day, "this" is a pragmatic choice, and I like your idea of enforcing it everywhere such member variables are used. 



Christopher Plewright

unread,
Dec 19, 2022, 10:27:48 AM12/19/22
to vim_dev


> class Blahh
> toX: TYPE_A
> toY: TYPE_B
> fn SetXandY(toX, toY)
> enfunc
> endclass

So... like you said, that was confusing.

But, I just realised that prefixing member variables with "this" everywhere consistently could perhaps allow us to do something in between, along these lines?

class Blahh
this.toX: TYPE_A
this.toY: TYPE_B
fn SetXandY(this.toX, this.toY, Z : TYPE_C)
   blahh blah..
enfunc
endclass


Could we make this signature pattern auto assign this.toX and this.toY, for any function?   I'm just exploring other possibilities inspired by the idea you presented with respect to the new() constructor.

> Simplifying the new() method ~

> Many constructors take values for the object members.  Thus you very often see
> this pattern: >

>            this.lnum: number
>            this.col: number

>            def new(lnum: number, col: number)
>               this.lnum = lnum
>               this.col = col
>            enddef

> Not only is this text you need to write, it also has the type of each member
> twice.  Since this is so common a shorter way to write new() is provided: >

>            def new(this.lnum, this.col)
>            enddef

> The semantics are easy to understand: Providing the object member name,
> including "this.", as the argument to new() means the value provided in the
> new() call is assigned to that object member.  This mechanism is coming from
> the Dart language.

Why limit this idea to only the new constructor?

Bram Moolenaar

unread,
Dec 19, 2022, 11:50:10 AM12/19/22
to vim...@googlegroups.com, Christopher Plewright

> > class Blahh
> > toX: TYPE_A
> > toY: TYPE_B
> > fn SetXandY(toX, toY)
> > enfunc
> > endclass
>
> So... like you said, that was confusing.
>
> But, I just realised that prefixing member variables with "this" everywhere
> consistently could perhaps allow us to do something in between, along these
> lines?
>
> class Blahh
> this.toX: TYPE_A
> this.toY: TYPE_B
> fn SetXandY(this.toX, this.toY, Z : TYPE_C)
> blahh blah..
> enfunc
> endclass
>
>
> Could we make this signature pattern auto assign this.toX and this.toY, for
> any function? I'm just exploring other possibilities inspired by the idea
> you presented with respect to the new() constructor.

I do not see much use for it. Without supporting using "this.member" as
an argument name the code for the assignment would need to be given
explicitly, which isn't that bad.

> > Simplifying the new() method ~
> >
> > Many constructors take values for the object members. Thus you very
> often see
> > this pattern: >
> >
> > this.lnum: number
> > this.col: number
> >
> > def new(lnum: number, col: number)
> > this.lnum = lnum
> > this.col = col
> > enddef
> >
> > Not only is this text you need to write, it also has the type of each
> member
> > twice. Since this is so common a shorter way to write new() is provided:
> >
> >
> > def new(this.lnum, this.col)
> > enddef
> >
> > The semantics are easy to understand: Providing the object member name,
> > including "this.", as the argument to new() means the value provided in
> the
> > new() call is assigned to that object member. This mechanism is coming
> from
> > the Dart language.
>
> Why limit this idea to only the new constructor?

The difference between a regular method and a constructor is that for a
constructor it is very common to assign the argument to an object
member.

The idea comes from Dart, and I don't think Dart supports this for
anything but constructors.


--
Q: Is selling software the same as selling hardware?
A: No, good hardware is sold new, good software has already been used by many.

Christopher Plewright

unread,
Dec 19, 2022, 7:30:50 PM12/19/22
to vim_dev

The difference between a regular method and a constructor is that for a
constructor it is very common to assign the argument to an object
member.

The idea comes from Dart, and I don't think Dart supports this for
anything but constructors.

That's a good point, it is usually constructors where it get tedious.
I really appreciate your considered replies.  
Thanks
 

puremo...@gmail.com

unread,
Dec 20, 2022, 4:49:10 AM12/20/22
to vim_dev
For what it's worth, I feel that the formal "var memberVariable : Type" syntax for member is (while more verbose) more likely to stand out. The `var` keyword is a signpost and so is likely to be syntax highlighted. Simple `memberVariable : Type` doesn't stand out anywhere and contains mostly identifiers without keywords.

Additionally, I personally prefer the symmetry with local variables. If all declarations look the same, then it's one less rule to remember.

You can then also use const: `const memberVarConstant : Type` maybe?

Message has been deleted

skywind3000

unread,
Dec 23, 2022, 10:02:18 AM12/23/22
to vim_dev
Hi Bram,

Before everything becomes unchangeable, can I suggest to use
"new ClassName" instead of "ClassName.new" to create an instance ?

According to the description in `vim9class.txt`:

> An object can only be created by a class.  A class provides:
> - A new() method, the constructor, which returns an object for the class.
>   This method is invoked on the class name: MyClass.new().

An object can be created by:

    var pos = TextPosition.new(1, 1)

Is it possible to change it to:

    var pos = new TextPosition(1, 1)

this makes me feel more nature/familiar.

Since the vim9-class is built from scratch without any backward-compatible problems,
why not choose some intuitive grammars ?

Bram Moolenaar

unread,
Dec 23, 2022, 11:15:30 AM12/23/22
to vim...@googlegroups.com, Wei Zhang

> Before everything becomes unchangeable, can I suggest to use
> "new ClassName" instead of "ClassName.new" to create an instance ?
>
> According to the description in vim9class.txt:
>
>
> > An object can only be created by a class. A class provides:
> > - A new() method, the constructor, which returns an object for the class.
> > This method is invoked on the class name: MyClass.new().
>
> An object can be created by:
> var pos = TextPosition.new(1, 1)
>
> Is it possible to change it to:
> var pos = new TextPosition(1, 1)
>
> this makes me feel more nature/familiar.
>
> Since the vim9-class is built from scratch without any backward-compatible
> problems, why not choose some intuitive grammars ?

I would not call it intuitive at all. This syntax with the "new"
keyword comes from the first object-oriented languages. More recent
languages have moved away from it, because it is a very strange
construct.

The best example is Dart, which started out using "new" like other
languages, but dropped it in Dart 2. Unfortunately completely dropping
it has backwards compatibility problems, thus now "new" is optional and
it's recommended to leave it out. As an indication it's important to
make the right choice from the start.

I'm sure the proposed syntax is simple and straightforward, it will be
easy to get used to.


--
-rwxr-xr-x 1 root 24 Oct 29 1929 /bin/ed
-rwxr-xr-t 4 root 131720 Jan 1 1970 /usr/ucb/vi
-rwxr-xr-x 1 root 5.89824e37 Oct 22 1990 /usr/bin/emacs

bfrg

unread,
Dec 23, 2022, 12:40:15 PM12/23/22
to vim_dev
> No, I prefer 'this' over 'self'.   I was considering if its possible to go without any keyword for it.   For example, these days we also have syntax highlighting which can give a different color for member variables and arguments.

In order to give different colors for member variables and function arguments you need a very sophisticated parser. Otherwise you cannot distinguish the two in code. For the same reason C++ developers often prefix member variables with `m_`, like `m_age`, others use a postfix underscore like `age_` etc. I don't like it because it's not consistent.

Personally, I would prefer `this` (or `self` etc.) for member variables. It makes the syntax script a lot simpler and the syntax highlighting will work 100%. It will also be easier to `:grep` for all usages of a member variable since every reference of a member variable will contain `this`.

N i c o l a s

unread,
Dec 23, 2022, 1:46:31 PM12/23/22
to vim_dev

Sometimes quantity is quality.

self
----
. Python
. Smalltalk
. Lua
. Ruby
. Rust
. Legacy vimscript dict obj

this
----
. Dart
. C++
. Java
. C#
. Php use $this->

Neither this or self, but instance.member
----
.Julia
.Actionscript 3
. Fortran 90, 2003



Instance  created by new ClassName/Object
---------
. C++
. Dart
. C#
. Php
. R
. Actionscript 3 var obj:Object = new Object();

Instance:MyClass = MyClass
-----
. Python
. Julia
... Etc..

Doug Kearns

unread,
Dec 24, 2022, 10:34:35 AM12/24/22
to vim...@googlegroups.com
On Mon, 19 Dec 2022 at 00:33, Bram Moolenaar <Br...@moolenaar.net> wrote:

One thing I'm not yet sure about is the declaration.  Currently it works
like this:

        this.name: string
        this.gender: Gender

Notice that there is no "var" keyword.  It's not needed to recognize the
declaration.  I can't think of a good reason to add "var" here, other
than that a declaration would be expected to always have "var".  Well, I
don't have that expectation.

This following currently defines a field and is, without context, indistinguishable from any other assignment.  Is that intended?

this.name = "Somebody"

As methods still require :def I think it would be more consistent to not special case field declarations and still require the :var.

For class members most languages use the "static" keyword.  It's a bit
of a weird word, but I suppose most people are used to it, and I can't
find a popular language that has a good alternative.

If we leave out "var" for object members, I suppose we should also leave
it out for class members.  We then get:

        static oneClassMember: number
        static twoClassMember: string

I think this looks fine.  Any objections?

It seems from the documentation that static fields can be referenced as bare identifiers?  This feels a bit unexpected to me given that instance fields are always qualified.

Regards,
Doug

Christopher Plewright

unread,
Dec 24, 2022, 8:53:56 PM12/24/22
to vim_dev
On Saturday, 24 December 2022 at 04:40:15 UTC+11 bfrg wrote:
> No, I prefer 'this' over 'self'.   I was considering if its possible to go without any keyword for it.   For example, these days we also have syntax highlighting which can give a different color for member variables and arguments.

In order to give different colors for member variables and function arguments you need a very sophisticated parser. Otherwise you cannot distinguish the two in code. For the same reason C++ developers often prefix member variables with `m_`, like `m_age`, others use a postfix underscore like `age_` etc. I don't like it because it's not consistent

All good points.  After exploring the idea from different angles, I now think "this." prefix is the best choice.    Interesting, it effectively acts the same as the "m_" prefix  but enforced to be consistent - and I do like that.
 
Personally, I would prefer `this` (or `self` etc.) for member variables. It makes the syntax script a lot simpler and the syntax highlighting will work 100%. It will also be easier to `:grep` for all usages of a member variable since every reference of a member variable will contain `this`

Yes, indeed consistency, clarity, readability, simplicity, maintainability...  These are all more desirable than saving a few keystrokes.

Christopher Plewright

unread,
Dec 24, 2022, 9:29:29 PM12/24/22
to vim_dev
On Sunday, 25 December 2022 at 02:34:35 UTC+11 Doug Kearns wrote:
On Mon, 19 Dec 2022 at 00:33, Bram Moolenaar <Br...@moolenaar.net> wrote:

One thing I'm not yet sure about is the declaration.  Currently it works
like this:

        this.name: string
        this.gender: Gender

Notice that there is no "var" keyword.  It's not needed to recognize the
declaration.  I can't think of a good reason to add "var" here, other
than that a declaration would be expected to always have "var".  Well, I
don't have that expectation.

This following currently defines a field and is, without context, indistinguishable from any other assignment.  Is that intended?

this.name = "Somebody"

Is that right?  if that's a declaration as well, shouldn't that include the type?
I thought that the declaration would be like this;

this.name : string = "Somebody" 

Or is auto-type detection at play here too? 

 
As methods still require :def I think it would be more consistent to not special case field declarations and still require the :var.

For class members most languages use the "static" keyword.  It's a bit
of a weird word, but I suppose most people are used to it, and I can't
find a popular language that has a good alternative.

If we leave out "var" for object members, I suppose we should also leave
it out for class members.  We then get:

        static oneClassMember: number
        static twoClassMember: string

I think this looks fine.  Any objections?

It seems from the documentation that static fields can be referenced as bare identifiers?  This feels a bit unexpected to me given that instance fields are always qualified.

Just sharing another idea - perhaps also require "static." as the class scope prefix, and enforce it - for all the same reasons that "this." would be enforced as the object scope prefix. 
Alternatively, perhaps we could use the actual class name as the enforced prefix for static class scoped variables.   Either option would avoid confusion with inner function variables.

Either way, it seems consistency is important here.

The following is all over the place;

        var static    oneClassMember: number
        var static    twoClassMember: string
        this.threeObjectMember: number
        this.fourObjectMember: string

I think that the following also looks inconsistent;

        static   oneClassMember: number
        static   twoClassMember: string
        this.threeObjectMember: number
        this.fourObjectMember: string

I think the following is better, more consistent, and this would be my preference;

        static.oneClassMember: number
        static.twoClassMember: string
        this.threeObjectMember: number
        this.fourObjectMember: string

I don't mind var, but I don't see a real need for it either, because the declarations will have the type name included.  Anyway, if going to use var, please keep it consistent, eg like this;

        var static.oneClassMember: number
        var static.twoClassMember: string
        var this.threeObjectMember: number
        var this.fourObjectMember: string







Bram Moolenaar

unread,
Dec 25, 2022, 10:02:15 AM12/25/22
to vim...@googlegroups.com, Doug Kearns

> > One thing I'm not yet sure about is the declaration. Currently it works
> > like this:
> >
> > this.name: string
> > this.gender: Gender
> >
> > Notice that there is no "var" keyword. It's not needed to recognize the
> > declaration. I can't think of a good reason to add "var" here, other
> > than that a declaration would be expected to always have "var". Well, I
> > don't have that expectation.
>
> This following currently defines a field and is, without context,
> indistinguishable from any other assignment. Is that intended?

With "var" it's indistinguishable from another declaration, I don't
think it matters much that it looks like an assignment otherwise.

> this.name = "Somebody"
>
> As methods still require :def I think it would be more consistent to not
> special case field declarations and still require the :var.

True, for methods ":def" is used like elsewhere. I'm not sure if using
":var" for variables should be considered more consistent.

> For class members most languages use the "static" keyword. It's a bit
> > of a weird word, but I suppose most people are used to it, and I can't
> > find a popular language that has a good alternative.
> >
> > If we leave out "var" for object members, I suppose we should also leave
> > it out for class members. We then get:
> >
> > static oneClassMember: number
> > static twoClassMember: string
> >
> > I think this looks fine. Any objections?
>
> It seems from the documentation that static fields can be referenced as
> bare identifiers? This feels a bit unexpected to me given that instance
> fields are always qualified.

Static fields (class members) are totally different from object members.
I have always found it confusing, in many languages it's hard to tell
them apart, especially if the declaration is further away. Always using
"this" for object members helps a lot for this. I would not know what
to use for class members. The only thing I have seen is using the class
name, which can be long (and gets tricky when using inheritance).
I believe most languages access class members directly, without a
prefix.

We have already dropped the "s:" prefix for using script-local
variables. Using class members is a bit similar to that.

--
We learn from our mistakes. Politicians don't make mistakes.

Bram Moolenaar

unread,
Dec 25, 2022, 10:41:16 AM12/25/22
to vim...@googlegroups.com, Christopher Plewright

> On Sunday, 25 December 2022 at 02:34:35 UTC+11 Doug Kearns wrote:
>
> > On Mon, 19 Dec 2022 at 00:33, Bram Moolenaar <Br...@moolenaar.net> wrote:
> >
> >>
> >> One thing I'm not yet sure about is the declaration. Currently it works
> >> like this:
> >>
> >> this.name: string
> >> this.gender: Gender
> >>
> >> Notice that there is no "var" keyword. It's not needed to recognize the
> >> declaration. I can't think of a good reason to add "var" here, other
> >> than that a declaration would be expected to always have "var". Well, I
> >> don't have that expectation.
> >
> >
> > This following currently defines a field and is, without context,
> > indistinguishable from any other assignment. Is that intended?
> >
> > this.name = "Somebody"
> >
>
> Is that right? if that's a declaration as well, shouldn't that include the
> type?
> I thought that the declaration would be like this;
>
> this.name : *string *= "Somebody"
>
> Or is auto-type detection at play here too?

It's called type inference. The type of the expression is used as the
type of the variable. In most cases this works very well, keeps it
short and it's obvious what the variable is used for. What it does not
work well for is when using an empty list or dictionary.

> >>> For class members most languages use the "static" keyword. It's a bit
> >> of a weird word, but I suppose most people are used to it, and I can't
> >> find a popular language that has a good alternative.
> >>
> >> If we leave out "var" for object members, I suppose we should also leave
> >> it out for class members. We then get:
> >>
> >> static oneClassMember: number
> >> static twoClassMember: string
> >>
> >> I think this looks fine. Any objections?
> >>
> >
> > It seems from the documentation that static fields can be referenced as
> > bare identifiers? This feels a bit unexpected to me given that instance
> > fields are always qualified.
>
> Just sharing another idea - perhaps also require "*static.*" as the class
> scope prefix, and enforce it - for all the same reasons that "*this.*"
> would be enforced as the object scope prefix.

I don't know a language that does this. As I mentioned, the word
"static" is a bit strange anyway, using it in more places makes that
worse.

> Alternatively, perhaps we could use the actual class name as the enforced
> prefix for static class scoped variables. Either option would avoid
> confusion with inner function variables.

Some languages use the class name as a prefix for class members.
Outside of the class this makes sense, it's like a scope name. Inside
the class, however, using the class name is more duplicating what you
already know. With inheritance the question comes up if the current
class name or the parent class name need to be used (maybe both work?).
And class names have a tendency to be quite long.

There is also some similarity of using a script-local variable in code
and functions inside that script. We currently don't use a prefix, and
that works fine. I can predict that using class members inside the
class can work without a prefix without a problem, just like using
script-local variables.

> Either way, it seems consistency is important here.
>
> The following is all over the place;
>
> var static oneClassMember: number
> var static twoClassMember: string
> this.threeObjectMember: number
> this.fourObjectMember: string

Using "var" is either for both or none, this mix is not making sense.

> I think that the following also looks inconsistent;
>
> static oneClassMember: number
> static twoClassMember: string
> this.threeObjectMember: number
> this.fourObjectMember: string

Class and object members *are* different, thus I don't think consistency
is important here, or even a goal.

> I think the following is better, more consistent, and this would be my
> preference;
>
> static.oneClassMember: number
> static.twoClassMember: string
> this.threeObjectMember: number
> this.fourObjectMember: string

This goes against the syntax we know from any other language. Using
"static" as a prefix looks weird to me.

> I don't mind var, but I don't see a real need for it either, because the
> declarations will have the type name included. Anyway, if going to use
> var, please keep it consistent, eg like this;
>
> var static.oneClassMember: number
> var static.twoClassMember: string
> var this.threeObjectMember: number
> var this.fourObjectMember: string

Whether to use "var" or not was also part of the discussion. It does
make it clearer that we're looking at a declaraction. But otherwise the
"var" keyword is not actually needed.

I also wonder if it should be "var static oneClassMember" or
"static var oneClassMember". Just using "static oneClassMember" avoids
that. That still leaves open the possibility to use:

static oneClassMember: number
var this.oneObjectMember: number

Or:

static oneClassMember: number
this.oneObjectMember: number

--
Mental Floss prevents moral decay!

Ernie Rael

unread,
Dec 25, 2022, 2:49:06 PM12/25/22
to vim...@googlegroups.com
With 9.0.1094, in the script that follows, attempting to read a
classMember through  an instance fails;
echomsg c.classMember
should it? I suppose requiring the class name makes it most clear, but I recall
mention that classnames can get long. I suppose a getter could be added.

Can a class method (or should it be called class function?) be static?
For example, a method accessed like
MyClass.SomeStaticFunction()

Amusingly, I added a getter for the classMember; I guess accessing a static
member from inside the class definition is not handled yet. Different errors
depending on how it's accessed by the instance method

-ernie

vim9script

class MyClass
  public this.instanceMember: string
  public static classMember = 'foo'

  def new(instanceMember: string)
      this.instanceMember = instanceMember
  enddef

  def GetCM(): string
    return 'foobar'

    # following gets: Variable not found: classMember
    #return classMember

    # following gets: compile_class_object_index: not handled
    #return MyClass.classMember
  enddef

endclass

var c = MyClass.new("abc")
echomsg c.instanceMember
echomsg MyClass.classMember

echomsg c.GetCM()

# fails
echomsg c.classMember

Bram Moolenaar

unread,
Dec 25, 2022, 4:07:38 PM12/25/22
to vim...@googlegroups.com, Ernie Rael

> With 9.0.1094, in the script that follows, attempting to read a
> classMember through  an instance fails;
>
> echomsg c.classMember
>
> should it?

No, an object does not provide a class member.

> I suppose requiring the class name makes it most clear, but I recall
> mention that classnames can get long. I suppose a getter could be added.

How can you access the getter without referring to the class?

> Can a class method (or should it be called class function?) be static?

Nothing *is* static, the "static" keyword is used to change the meaning
of items.

> For example, a method accessed like
>
> MyClass.SomeStaticFunction()
>
>
> Amusingly, I added a getter for the classMember; I guess accessing a static
> member from inside the class definition is not handled yet. Different
> errors depending on how it's accessed by the instance method

Lots of things are not implemented yet...

--
Time flies like an arrow.
Fruit flies like a banana.

Ernie Rael

unread,
Dec 25, 2022, 5:08:22 PM12/25/22
to vim...@googlegroups.com
On 22/12/25 1:07 PM, Bram Moolenaar wrote:

      
With 9.0.1094, in the script that follows, attempting to read a
classMember through  an instance fails;

    echomsg c.classMember

should it?
No, an object does not provide a class member.

I suppose requiring the class name makes it most clear, but I recall
mention that classnames can get long. I suppose a getter could be added.
How can you access the getter without referring to the class?


Assuming c is an object

c.GetClassMember()

where the method GetClassMember() returns the classMember that was declared static.

Can a class method (or should it be called class function?) be static?
Nothing *is* static, the "static" keyword is used to change the meaning
of items.

I should have said "can a method/function defined in a class be declared static?"

One way to look at it: is it the case that any method can be invoked as

MyClass.SomeMethod()

and as long as "SomeMethod()" doesn't reference a variable like "this.someVar" then it's OK?

-ernie

Christopher Plewright

unread,
Dec 25, 2022, 5:54:39 PM12/25/22
to vim_dev
On Monday, 26 December 2022 at 09:08:22 UTC+11 err...@raelity.com wrote:
On 22/12/25 1:07 PM, Bram Moolenaar wrote:

      
With 9.0.1094, in the script that follows, attempting to read a
classMember through  an instance fails;

    echomsg c.classMember

should it?
No, an object does not provide a class member.

I suppose requiring the class name makes it most clear, but I recall
mention that classnames can get long. I suppose a getter could be added.
How can you access the getter without referring to the class?


Assuming c is an object

c.GetClassMember()

where the method GetClassMember() returns the classMember that was declared static.

Can a class method (or should it be called class function?) be static?
Nothing *is* static, the "static" keyword is used to change the meaning
of items.

I should have said "can a method/function defined in a class be declared static?"

I don't think it's a good idea to access static class function from an object instance of that class.   Also, I would not name that function with "Member" if it is a static function, because member implies that it is a member method of an object instance.  I think that could lead to confusion for someone else trying to read your code.
 
The difference between a function and a method is important - with regard to this topic of classes vs objects of the class.   According to Bram's preliminary doco.  Yes, class "method" can be declared static.  But then, I think that makes it a static class "function", and not a class "method".  

Bram, I think that the doco here is referring to a class "function", not a class "method".  It might be worth distinguishing between method and function in the doco?

Ref:


One way to look at it: is it the case that any method can be invoked as

MyClass.SomeMethod()

and as long as "SomeMethod()" doesn't reference a variable like "this.someVar" then it's OK?

-ernie

How would Vim know when that is an error or not, if you didn't specify the static keyword when declaring the static class function.   You want Vim to treat it as if it was a static class function, but wouldn't Vim need to analyse deeper to see if it uses any object members, to be able to allow that?



Ernie Rael

unread,
Dec 25, 2022, 6:26:50 PM12/25/22
to vim...@googlegroups.com
On 22/12/25 2:54 PM, Christopher Plewright wrote:


On Monday, 26 December 2022 at 09:08:22 UTC+11 err...@raelity.com wrote:
On 22/12/25 1:07 PM, Bram Moolenaar wrote:
With 9.0.1094, in the script that follows, attempting to read a
classMember through  an instance fails;

    echomsg c.classMember

should it?
No, an object does not provide a class member.

I suppose requiring the class name makes it most clear, but I recall
mention that classnames can get long. I suppose a getter could be added.
How can you access the getter without referring to the class?


Assuming c is an object

c.GetClassMember()

where the method GetClassMember() returns the classMember that was declared static.

Can a class method (or should it be called class function?) be static?
Nothing *is* static, the "static" keyword is used to change the meaning
of items.

I should have said "can a method/function defined in a class be declared static?"

I don't think it's a good idea to access static class function from an object instance of that class.

I was not suggesting that. I've botched the question. I was saying that to get a class member (something declared static) from an object, there could be an instance method that returns the class member.

And I didn't know that it was documented that a function could be declared static; missed that, my bad.

   Also, I would not name that function with "Member" if it is a static function, because member implies that it is a member method of an object instance.  I think that could lead to confusion for someone else trying to read your code.
 
The difference between a function and a method is important - with regard to this topic of classes vs objects of the class.   According to Bram's preliminary doco.  Yes, class "method" can be declared static.  But then, I think that makes it a static class "function", and not a class "method".  

Bram, I think that the doco here is referring to a class "function", not a class "method".  It might be worth distinguishing between method and function in the doco?
I should have studied the docs better, but yes, method for instance and function for class works for me.


Ref:


One way to look at it: is it the case that any method can be invoked as

MyClass.SomeMethod()

and as long as "SomeMethod()" doesn't reference a variable like "this.someVar" then it's OK?

-ernie

How would Vim know when that is an error or not, if you didn't specify the static keyword when declaring the static class function.

I didn't know it was documented that there could be a static class function. The whole point of the question was to determine if there could be a static class function.

Sorry for the noise and confusion,
-ernie

 You want Vim to treat it as if it was a static class function, but wouldn't Vim need to analyse deeper to see if it uses any object members, to be able to allow that?



--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

---
You received this message because you are subscribed to the Google Groups "vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to vim_dev+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/vim_dev/656faf72-e6a1-452c-bd25-59c22a071115n%40googlegroups.com.


Christopher Plewright

unread,
Dec 25, 2022, 8:30:59 PM12/25/22
to vim_dev

> I thought that the declaration would be like this;
>
> this.name : *string *= "Somebody"
>
> Or is auto-type detection at play here too?

It's called type inference. The type of the expression is used as the
type of the variable. In most cases this works very well, keeps it
short and it's obvious what the variable is used for. What it does not
work well for is when using an empty list or dictionary.

Thanks, that's good to know. I think type inference is generally useful.  
Similar to how typescript does it.  
So, I see how "var" could be helpful in distinguishing declarations from assignments. 
 
> >>> For class members most languages use the "static" keyword. It's a bit
> >> of a weird word, but I suppose most people are used to it, and I can't
> >> find a popular language that has a good alternative.
> >>
> >> If we leave out "var" for object members, I suppose we should also leave
> >> it out for class members. We then get:
> >>
> >> static oneClassMember: number
> >> static twoClassMember: string
> >>
> >> I think this looks fine. Any objections?
> >>
> >
> > It seems from the documentation that static fields can be referenced as
> > bare identifiers? This feels a bit unexpected to me given that instance
> > fields are always qualified.
>
> Just sharing another idea - perhaps also require "*static.*" as the class
> scope prefix, and enforce it - for all the same reasons that "*this.*"
> would be enforced as the object scope prefix.

I don't know a language that does this. As I mentioned, the word
"static" is a bit strange anyway, using it in more places makes that
worse.

Yeah, that thought crossed my mind too.  
 
> Alternatively, perhaps we could use the actual class name as the enforced
> prefix for static class scoped variables. Either option would avoid
> confusion with inner function variables.

Some languages use the class name as a prefix for class members.
Outside of the class this makes sense, it's like a scope name. Inside
the class, however, using the class name is more duplicating what you
already know. With inheritance the question comes up if the current
class name or the parent class name need to be used (maybe both work?).
And class names have a tendency to be quite long.

Good question about inheritance.  My initial thought is that either should work.   Now, hmm, if they aren't actually referring to the same thing?  Not sure.  It seems odd for a static member to be shadowed by a child static member variable.   I think you could treat as with the standard inheritance rules, ie, the child may specialize the parent's members.  Doesn't matter if they are static, ie, be consistent with inheritance for static class functions as well as inheritance for static class variables.

That reminds me, in java, the compiler makes child default constructor automatically call the super() default constructor, in cases where you forget to write super() in the child constructor.  The compiled bytecode looks the same as if you had written super() in the code.

In java, the default constructor always refers to the zero-arg constructor.  But, I think you referred to the default constructor to be able to initialise all the member variables.  I do really like your idea for that.  So, for inheritance, if you have an existing parent default constructor perhaps it should get called automatically when constructing the child?  I think maintaining that could be tricky if your child constructor doesn't implement at least sufficient arguments to match the parent's default constructor. 

 
There is also some similarity of using a script-local variable in code
and functions inside that script. We currently don't use a prefix, and
that works fine. I can predict that using class members inside the
class can work without a prefix without a problem, just like using
script-local variables.

> Either way, it seems consistency is important here.
>
> The following is all over the place;
>
> var static oneClassMember: number
> var static twoClassMember: string
> this.threeObjectMember: number
> this.fourObjectMember: string

Using "var" is either for both or none, this mix is not making sense.

> I think that the following also looks inconsistent;
>
> static oneClassMember: number
> static twoClassMember: string
> this.threeObjectMember: number
> this.fourObjectMember: string

Class and object members *are* different, thus I don't think consistency
is important here, or even a goal.

Oh, OK.  In my mind, the only difference is their scope and lifetime, which is what that prefix declares.

Effectively, "this." has become like an enforced "m_" prefix on object member variable names.
Likewise, I was thinking that "static." could effectively become like an enforced "s_" for static class variable names.
 
> I think the following is better, more consistent, and this would be my
> preference;
>
> static.oneClassMember: number
> static.twoClassMember: string
> this.threeObjectMember: number
> this.fourObjectMember: string

This goes against the syntax we know from any other language. Using
"static" as a prefix looks weird to me.

Sure, it is weird, but this is a new programming language, anything new might look weird.  I also liked the s: prefix
 
> I don't mind var, but I don't see a real need for it either, because the
> declarations will have the type name included. Anyway, if going to use
> var, please keep it consistent, eg like this;
>
> var static.oneClassMember: number
> var static.twoClassMember: string
> var this.threeObjectMember: number
> var this.fourObjectMember: string

Whether to use "var" or not was also part of the discussion. It does
make it clearer that we're looking at a declaraction. But otherwise the
"var" keyword is not actually needed.

I also wonder if it should be "var static oneClassMember" or
"static var oneClassMember". Just using "static oneClassMember" avoids
that. That still leaves open the possibility to use:

static oneClassMember: number
var this.oneObjectMember: number

Or:

static oneClassMember: number
this.oneObjectMember: number



So, have you ruled out the following?

var static oneClassMember: number
var this.oneObjectMember: number

If you have ruled that out, then I think the following is the better choice from the two you presented.

static oneClassMember: number
this.oneObjectMember: number

Now, wondering about the need for static in the first place.   Just stepping back to clarify some assumptions here.
Given that "static" has the same lifetime as a global variable, it only differs in how you access it, is it really valuable.   
Why implement it, if it is only an edge case - and global variables work well already.

Another thought, vimscript had a great thing using letter-colon prefixes to scope the variables.  That looked really weird to me at first, but I really like it now.
I assume you are still maintaining much of this list?

g:           Global variable
{nothing}    Global variable
b:           Buffer-local variable
w:           Window-local variable
t:           Tab-local variable
s:           Sourced Vimscript variable
l:           Function local variable
a:           Function formal parameter variable
v:           Built-in Vim variable


Why not just add "c:" instead of "static" for Class variables,  
or perhaps even extend "s:" if it is declared inside a class definition?
Or, even extend "g:" here, to specify the lifetime as global, but whenever g: is declared inside a class definition, then need to access it externally via class-name prefix.

And why not use "o:" instead of "this." for object member variables?

Are you going to have a mixture of scope specifier patterns?  Some from good-Ol' vimscript and some common keywords from other languages?


Christopher Plewright

unread,
Dec 25, 2022, 8:36:07 PM12/25/22
to vim_dev
On Monday, 26 December 2022 at 10:26:50 UTC+11 err...@raelity.com wrote:
On 22/12/25 2:54 PM, Christopher Plewright wrote:

I didn't know it was documented that there could be a static class function. The whole point of the question was to determine if there could be a static class function.

Sorry for the noise and confusion,
-ernie

Sorry that I misunderstood your question.  Look, no worries on my part, I'm interested in the language design as well.  Also, feeling a bit cautious of adding noise myself :)   This discussion could go anywhere, I guess we follow Brams lead on that.

Bram Moolenaar

unread,
Dec 26, 2022, 6:59:19 AM12/26/22
to vim...@googlegroups.com, Ernie Rael

> On 22/12/25 1:07 PM, Bram Moolenaar wrote:
> >> With 9.0.1094, in the script that follows, attempting to read a
> >> classMember through  an instance fails;
> >>
> >> echomsg c.classMember
> >>
> >> should it?
> > No, an object does not provide a class member.
> >
> >> I suppose requiring the class name makes it most clear, but I recall
> >> mention that classnames can get long. I suppose a getter could be added.
> > How can you access the getter without referring to the class?
>
>
> Assuming c is an object
>
> c.GetClassMember()
>
> where the method GetClassMember() returns the classMember that was
> declared static.

Well, you can add such a method if you like, but it would not be added
automatically.

> >> Can a class method (or should it be called class function?) be static?
> > Nothing *is* static, the "static" keyword is used to change the meaning
> > of items.
>
> I should have said "can a method/function defined in a class be declared
> static?"
>
> One way to look at it: is it the case that any method can be invoked as
>
> MyClass.SomeMethod()
>
> and as long as "SomeMethod()" doesn't reference a variable like
> "this.someVar" then it's OK?

You need to explicitly declare a method as a class method or object
method. A class method is declared with "static". AFAIK all languages
do it this way.

--
TALL KNIGHT: We are now no longer the Knights Who Say Ni!
ONE KNIGHT: Ni!
OTHERS: Sh!
ONE KNIGHT: (whispers) Sorry.
"Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD

Bram Moolenaar

unread,
Dec 26, 2022, 6:59:19 AM12/26/22
to vim...@googlegroups.com, Christopher Plewright

> > I don't think it's a good idea to access static class function from
> > an object instance of that class. Also, I would not name that
> > function with "Member" if it is a static function, because member
> > implies that it is a member method of an object instance. I think
> > that could lead to confusion for someone else trying to read your
> > code.
>
> The difference between a function and a method is important - with regard
> to this topic of classes vs objects of the class. According to Bram's
> preliminary doco. Yes, class "method" can be declared static. But then, I
> think that makes it a static class "function", and not a class "method".

That depends on how you define this. A method usually implicitily gets
an extra argument or is aware of its context. It does not necessarily
alwayw need to be an object.

> Bram, I think that the doco here is referring to a class "function", not a
> class "method". It might be worth distinguishing between method and
> function in the doco?

If that makes it easier to understand.


--
TALL KNIGHT: Firstly. You must get us another shrubbery!
OTHER KNIGHTS: More shrubberies! More shrubberies for the ex-Knights of Ni!
ARTHUR: Not another shrubbery -

Christopher Plewright

unread,
Dec 26, 2022, 7:14:33 PM12/26/22
to vim_dev
On Monday, 26 December 2022 at 22:59:19 UTC+11 Bram Moolenaar wrote: 

> I think that makes it a static class "function", and not a class "method".

That depends on how you define this. A method usually implicitily gets
an extra argument or is aware of its context. It does not necessarily
alwayw need to be an object.

Ahh OK, I see now.

> Bram, I think that the doco here is referring to a class "function", not a
> class "method". It might be worth distinguishing between method and
> function in the doco?

If that makes it easier to understand.

The doco already uses both words, "method" and "function", in various places.  I know this topic is annoyingly semantic, but I wondered if there was meant to be a specific meaning for each word as they are used now, or are they used interchangeably?   Because... now seems like a good chance to define what these words should mean for vim9class -  I think it would help avoid confusion going forward.

In normal English, at least in the way I think anyway, is that "method" refers to details of the process, the steps how you do something, and "function" is more about the outcome or goal, or purpose of a thing, it is bigger picture.   So, my general English understanding of those terms doesn't seem very helpful for this discussion.!

While its true that I have heard both terms used interchangeably in computing, in all sorts of weird ways.  I also remember when learning OO in the 90's  being taught by "authority figures" that a "method" is a special type of "function" that is an object member.   So, in that sense, not all functions are methods, but all methods are functions.   But since I've just done some research now, I think that this might be more of an academic idea, and doesn't seem to be used consistently in official OO language specs, like Java and C++ etc.   Then the terminology seems to get re-mixed again with functional programming anyway.

Just food for thought, I got no sacred cows here :)

Another possibility occurred to me, that you could keep;  function and endfunction
That could still be used to always mean static functions - as that essentially does now already - I mean, because there was no such thing as object member methods in vimscript before classes were added. 
So, if you say function and endfunction, when defined inside a class, means a static function of that class.   You wouldn't need the word static for that.

Because... you now have the opportunity to add;  method and endmethod to define object member methods.   ie. instead of def and enddef.   I find def and enddef a bit too generic,  but that is just my opinion.   Again, this is relying on a certain meaning of the word method, which I dont think is uncommon, but as you said it doesn't necessarily always have that meaning either.  

If you did this then static wouldn't need to be used for functions or methods.   That would just leave static for variables.  And, I think "s:" is very close in meaning already to how I understand static, (it implies certain lifetime and accessibility), and so you could say that an s: variable, when declared inside a class definition, is a static variable.   

If you did these couple of things, then you wouldn't need to use the word "static" anywhere.




Christopher Plewright

unread,
Dec 26, 2022, 8:29:22 PM12/26/22
to vim_dev
On Tuesday, 27 December 2022 at 11:14:33 UTC+11 Christopher Plewright wrote:


Another possibility occurred to me, that you could keep;  function and endfunction
That could still be used to always mean static functions - as that essentially does now already - I mean, because there was no such thing as object member methods in vimscript before classes were added. 
So, if you say function and endfunction, when defined inside a class, means a static function of that class.   You wouldn't need the word static for that.

Because... you now have the opportunity to add;  method and endmethod to define object member methods.   ie. instead of def and enddef.   I find def and enddef a bit too generic,  but that is just my opinion.   Again, this is relying on a certain meaning of the word method, which I dont think is uncommon, but as you said it doesn't necessarily always have that meaning either.  

If you did this then static wouldn't need to be used for functions or methods.   That would just leave static for variables.  And, I think "s:" is very close in meaning already to how I understand static, (it implies certain lifetime and accessibility), and so you could say that an s: variable, when declared inside a class definition, is a static variable.   

If you did these couple of things, then you wouldn't need to use the word "static" anywhere.

Apologies all,  I've just re-read the vim9.txt doco, and now realise some of these suggestions don't fit.  There is already a rationalised delineation between function and def for vim9.    And, the idea of using s: for static, is overloading the meaning and could cause confusion for those expecting it to be accessible for the whole script, to suddenly find its only accessible within the class.   So, overloading s: not a good idea.  And, even though another prefix might work, for example c: to mean that it is static class scoped, but then people already know what static means anyway, so no need to introduce something brand new, unless its actually helpful.

  

Doug Kearns

unread,
Dec 27, 2022, 10:26:04 AM12/27/22
to Bram Moolenaar, vim...@googlegroups.com
On Mon, 26 Dec 2022 at 02:02, Bram Moolenaar <Br...@moolenaar.net> wrote:

[...]
 
> This following currently defines a field and is, without context,
> indistinguishable from any other assignment.  Is that intended?

With "var" it's indistinguishable from another declaration, I don't
think it matters much that it looks like an assignment otherwise.

There's only one declaration per class assuming either a qualified name is used in the declaration or normal shadowing rules apply.

So, ignoring subjective aesthetic issues, this would allow for tooling to more easily identify the declaration.

[...]
 
> It seems from the documentation that static fields can be referenced as
> bare identifiers?  This feels a bit unexpected to me given that instance
> fields are always qualified.

Static fields (class members) are totally different from object members.
I have always found it confusing, in many languages it's hard to tell
them apart, especially if the declaration is further away.  Always using
"this" for object members helps a lot for this.  I would not know what
to use for class members.  The only thing I have seen is using the class
name, which can be long (and gets tricky when using inheritance).
I believe most languages access class members directly, without a
prefix.

I think they're much the same in terms of the problems the required "this" qualifier is attempting to address.  Static fields also need disambiguation in shadowed contexts and could, arguably, also use better identification.

Are methods going to need to be qualified too?

Cards on the table, I'm not in favour of requiring qualified references.  I just found it surprising that only unqualified instance fields were considered a problem.

Regards,
Doug

Bram Moolenaar

unread,
Dec 27, 2022, 11:29:24 AM12/27/22
to vim...@googlegroups.com, Doug Kearns

> > > This following currently defines a field and is, without context,
> > > indistinguishable from any other assignment. Is that intended?
> >
> > With "var" it's indistinguishable from another declaration, I don't
> > think it matters much that it looks like an assignment otherwise.
> >
>
> There's only one declaration per class assuming either a qualified name is
> used in the declaration or normal shadowing rules apply.
>
> So, ignoring subjective aesthetic issues, this would allow for tooling to
> more easily identify the declaration.

Yes, there are some reasons to declare object members with "var".
It's hard to decide what matters most. Perhaps "making it look like a
declaration" is more important than other reasons. The space taken up
by the extra "var" keyword probably doesn't matter much.

> > > It seems from the documentation that static fields can be referenced as
> > > bare identifiers? This feels a bit unexpected to me given that instance
> > > fields are always qualified.
> >
> > Static fields (class members) are totally different from object members.
> > I have always found it confusing, in many languages it's hard to tell
> > them apart, especially if the declaration is further away. Always using
> > "this" for object members helps a lot for this. I would not know what
> > to use for class members. The only thing I have seen is using the class
> > name, which can be long (and gets tricky when using inheritance).
> > I believe most languages access class members directly, without a
> > prefix.
>
> I think they're much the same in terms of the problems the required "this"
> qualifier is attempting to address. Static fields also need disambiguation
> in shadowed contexts and could, arguably, also use better identification.

Assigning to a static class member in a constructor is unusual, thus the
common problem that an argument name matches a member name is unlikely
to happen for a class member. We could probably disallow shadowing a
class member. We can at least start with that and see if that doesn't
cause annoyance.

> Are methods going to need to be qualified too?

Object methods are always called on an object "obj.method()".
I suppose "this.method()" also works (don't see this very often).
Just using "method()" probably needs to be disallowed. Especially if we
require prefixing "this." for object members.

> Cards on the table, I'm not in favour of requiring qualified
> references. I just found it surprising that only unqualified instance
> fields were considered a problem.

That is the reality. All this is much more about what a developer
encounters on a regular basis than theory or philosophy. Especially
when it comes to what mistakes people tend to make and whether it's
possible to give a helpful error for them. Every time I have started
using a new language (usually advertised as being the best ever) I have
run into things that don't work well in practice.

--
ARTHUR: Charge!
[They all charge with swords drawn towards the RABBIT. A tremendous twenty
second fight with Peckinpahish shots and borrowing heavily also on the
Kung Fu and karate-type films ensues, in which some four KNIGHTS are
comprehensively killed.]
ARTHUR: Run away! Run away!

skywind3000

unread,
Jan 12, 2023, 1:01:46 PM1/12/23
to vim_dev
One more thing about vim9 class:

can we define a named or anonymous class inside a function ?
That can be used to simulate a closure,

And maybe, someday, we can translate javascript or lua to vim9script with this feature.

Bram Moolenaar

unread,
Jan 12, 2023, 3:05:46 PM1/12/23
to vim...@googlegroups.com, skywind3000

> One more thing about vim9 class:
>
> can we define a named or anonymous class inside a function ?
> That can be used to simulate a closure,

It can be made possible, but the usefulness might be minimal. Perhaps
you can give an example (possibliy in another language) of what you want
to do.

The idea of class support is to just implement the basics, what most
other languages also have. Not adding all kinds of "nice to have"
features.

> And maybe, someday, we can translate javascript or lua to vim9script with
> this feature.

Javascript is a bit of a weird language, it will be very hard to
translate into another language, because it has some constructs that
most other languages don't have.

Anyway, I don't see this as a goal.

--
I think that you'll agree that engineers are very effective in their social
interactions. It's the "normal" people who are nuts.
(Scott Adams - The Dilbert principle)

skywind3000

unread,
Jan 12, 2023, 3:30:18 PM1/12/23
to vim_dev
- declaring a class inside a function allows me put related code together
- can be used to simulate a closure function.

example for java:

    button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            AsyncTaskRunner runner = new AsyncTaskRunner();
            String sleepTime = time.getText().toString();
            runner.execute(sleepTime);
        }
    });

and python:

    def subscript(event_list):
        class MyListener(EventListener):
            def __init__ (self, id):
                self.id = id
            def on_enter (self):
                # do something
                return -1
            def on_leave (self):
                # done
        for event in event_list:
            x = MyListener(event)
            scheduler.add_listener(x)

Bram Moolenaar

unread,
Jan 13, 2023, 9:18:30 AM1/13/23
to vim...@googlegroups.com, skywind3000

> - declaring a class inside a function allows me put related code together
> - can be used to simulate a closure function.
>
> example for java:
>
> button.setOnClickListener(new View.OnClickListener() {
> @Override
> public void onClick(View v) {
> AsyncTaskRunner runner = new AsyncTaskRunner();
> String sleepTime = time.getText().toString();
> runner.execute(sleepTime);
> }
> });

This doesn't declare a class. This could be done by passing a lambda or
closure.

> and python:
>
> def subscript(event_list):
> class MyListener(EventListener):
> def __init__ (self, id):
> self.id = id
> def on_enter (self):
> # do something
> return -1
> def on_leave (self):
> # done
> for event in event_list:
> x = MyListener(event)
> scheduler.add_listener(x)

This would be more illustrative if the class has "implements Listener",
and the "add_listener()" function would accept a Listener. You then
create a class that implements Listener in a certain way.

It would work to declare the class outside of the function, but it's
nicer to keep it local to the function. This looks like something that
can be done later.

--
You have heard the saying that if you put a thousand monkeys in a room with a
thousand typewriters and waited long enough, eventually you would have a room
full of dead monkeys.
Reply all
Reply to author
Forward
0 new messages