Class implementation

107 views
Skip to first unread message

Bram Moolenaar

unread,
Jan 14, 2023, 10:34:06 AM1/14/23
to vim...@googlegroups.com

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.

One thing that I had to make a choice for is how to deal with limiting
access, especially to object members. Different languages have
different ways of doing this. And very different granularity,
especially when it comes to access by parent or child classes.

Currently I decided to keep it relatively simple and only provide three
ways:

- public: read and write access, using the "public" keyword
- default: read access only, no keyword used
- private: name prefixed with an underscore

Within the inheritance tree there are no limits, a child class can
access all members of a parent class and vice versa. There is no
"protected".

Making the read-only access the default has two reasons.

First of all, it is the most useful and recommended way to declare
object members. It avoids having to define "getters" while disallowing
anybody changing the values.

Secondly, using "public" and "private" keywords is very common, but
there is no widely used keyword for read-only.

One thing could still be changed: Instead of using the underscore prefix
to indicate "private" we could use the "private" keyword. Both are used
by popular languages. Although using "private" is more common, more
recently developed languages use the underscore prefix. Thus I would say
both are acceptable choices.

# currently:
this._member

# alternatively:
private this.member

The main advantage of using the underscore prefix is that the "private"
property can also be seen where the member is used. The main
disadvantage is that it's a bit obscure for those users who haven't seen
this syntax used this way before.

Opinions?

--
hundred-and-one symptoms of being an internet addict:
10. And even your night dreams are in HTML.

/// 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 ///

Yegappan Lakshmanan

unread,
Jan 14, 2023, 11:02:57 AM1/14/23
to vim...@googlegroups.com
On Sat, Jan 14, 2023 at 7:34 AM Bram Moolenaar <Br...@moolenaar.net> wrote:
>
>
> 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.
>

Thanks Bram for adding the support for classes.
I prefer the first approach as it is much easier to spot the private variables
in the code.

Regards,
Yegappan

> Opinions?
>

Christopher Plewright

unread,
Jan 15, 2023, 6:24:33 PM1/15/23
to vim_dev
Oh, I created https://github.com/vim/vim/issues/11827  but wanted to reply to this thread.

In my opinion, this could all be simplified a lot, if all variables are public by default, and are private if they start with an underscore.
So, there would only be two visibility scopes, not three to think about.
Also, using an underscore prefix is simple, and Yegappan brings up a good point, because it means you can just look at the variable name and see that it's private, without needing to go back to the declaration.

If you can make the default be public, and you use underscore for private, then you don't need any private or public keywords at all.

One final thought, if it is not too late to suggest this - maybe the horse has already bolted...   I started learning ruby last week, and noticed that they use @variable_name for member variables.     

So, instead of using the "this." prefix, vim9 could specify that member variable names must either use the @ prefix for public, or use the _ prefix for private.   ie., all member variable names must have one of these two prefixes.   I think this is worth considering, because it's simple, clear and explicit.  You no longer need the following keywords;  "this", "public" and "private".

Christopher Plewright

unread,
Jan 15, 2023, 8:02:52 PM1/15/23
to vim_dev

So, instead of using the "this." prefix, vim9 could specify that member variable names must either use the @ prefix for public, or use the _ prefix for private.   ie., all member variable names must have one of these two prefixes.   I think this is worth considering, because it's simple, clear and explicit.  You no longer need the following keywords;  "this", "public" and "private".



Sorry, one more idea to float...  I was thinking that the "@" prefix looks a bit odd, so, is there any reason we couldn't simply prefix public member variable names with just period "."?  So, instead of writing "this.xyz" everywhere, just write ".xyz"

And just use the underscore "_" prefix for private member variables.

To show what I'm thinking, at the moment you have this;

        class TextPosition
           this._lnum: number
           this._col: number
           public this.depth: number

           def new(lnum: number, col: number, depth: number)
              this._lnum = lnum
              this._col = col
              this.depth = depth
           enddef

           def SetLnum(lnum: number)
              this._lnum = lnum
           enddef

           def GetLnum()
              return this._lnum
           enddef

           def SetCol(col: number)
              this._col = col
           enddef

           def GetCol()
              return this._col
           enddef

           def GetVolume()
              return this._lnum * this._col * this.depth
           enddef

           def SetPosition(lnum: number, col: number, depth: number)
              this._lnum = lnum
              this._col = col
              this.depth = depth
           enddef
         endclass


The idea I'm floating for consideration, is that we could simplify it to something like this;

        class TextPosition
           _lnum: number
           _col: number
           .depth: number

           def new(lnum: number, col: number, depth: number)
              _lnum = lnum
              _col = col
              .depth = depth
           enddef

           def SetLnum(lnum: number)
              _lnum = lnum
           enddef

           def GetLnum()
              return _lnum
           enddef

           def SetCol(col: number)
              _col = col
           enddef

           def GetCol()
              return _col
           enddef

           def GetVolume()
              return _lnum * _col * .depth
           enddef

           def SetPosition(lnum: number, col: number, depth: number)
              _lnum = lnum
              _col = col
              .depth = depth
           enddef
      endclass


The advantages of this are;
1.  It removes the need for "this." everywhere.
2.  It's obvious when the member variable is public or private, wherever you read it,
3.  The dot prefix looks a bit more natural than "this." prefix everywhere, and 
4.  The dot prefix nicely reflects similar to how it is accessed outside the class

The usage from outside the class hierarchy would be the same;

    var text_pos = TextPosition.new(3, 5, 8)

    var text_pos_l = text_pos.GetLnum()
    assert(text_pos_l, 3)
    text_pos.SetLnum(text_pos_l + 1)
    text_pos_l = text_pos.GetLnum()
    assert(text_pos_l, 4)

    var text_pos_c = text_pos.GetCol()
    assert(text_pos_c , 5)
    text_pos.SetCol(text_pos_c + 1)
    text_pos_c = text_pos.GetCol()
    assert(text_pos_c, 6)

    var text_pos_d = text_pos.depth
    assert(text_pos_d , 8)
    text_pos.depth += 1
    text_pos_d = text_pos.depth
    assert(text_pos_d, 9)

    var volume = text_pos.GetVolume()
    assert(volume, (text_pos_l * text_pos_c * text_pos_d))





Bram Moolenaar

unread,
Jan 16, 2023, 9:24:07 AM1/16/23
to vim...@googlegroups.com, Christopher Plewright

> So, instead of using the "this." prefix, vim9 could specify that member
> variable names must either use the @ prefix for public, or use the _ prefix
> for private. ie., all member variable names must have one of these two
> prefixes. I think this is worth considering, because it's simple, clear
> and explicit. You no longer need the following keywords; "this", "public"
> and "private".

[...]

One of the goals of Vim9 script was to make it more similar to popular
languages. So that switching between Vim script and another language
isn't too difficult.

A language I have been experimenting with used "$" instead of "this.".
That works quite well, it's short and easy to recognize. But it's
different from every other language.

I think most users will immediately understand what "this." means.
Anything else will take some time getting used to and probably lead to
mistakes. Using the underscore prefix for "private" is already a bit
obscure, but other languages do it too, hopefully that means it's easy
to get used to.

Just using a dot prefix instead of "this." seems practical, but again is
different from any other language. It's a bit hard to spot, with a
dirty monitor all variables appear to be members :-).

I think using "this." everywhere is simple and similar to what other
languages do. It is a bit more verbose, but that's a small price to
pay. It helps making members stand out from function arguments, local
variables, etc.


About public/private/read-only: Making the default public is certainly
possible. I think most languages have it that way, even though it's not
a safe choice.

I do like the read-only access. Quite often you want to disallow any
code outside of the class to change a member, so that you can make sure
the value is valid. But making it private means you have add a
"getter" and call it. Unfortunately I don't know a good keyword to use.
C# has the "readonly" keyword, but it means something else.

Nevertheless, if we give priority to keeping it simple, making members
public by default and using the underscore for private is the way to go.


--
Q: What is the difference between open-source and commercial software?
A: If you have a problem with commercial software you can call a phone
number and they will tell you it might be solved in a future version.
For open-source software there isn't a phone number to call, but you
get the solution within a day.

Bram Moolenaar

unread,
Jan 23, 2023, 7:53:56 AM1/23/23
to vim...@googlegroups.com, Christopher Plewright

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.

--
Nothing is fool-proof to a sufficiently talented fool.

Doug Kearns

unread,
Jan 24, 2023, 10:18:31 AM1/24/23
to vim...@googlegroups.com
On Mon, 23 Jan 2023 at 23:53, Bram Moolenaar <Br...@moolenaar.net> wrote:
>
> I expected a lively discussion about alternatives for the class
> implementation, but nothing much happened.

Some of us are old soldiers with too many scars. :)

I'm a bit short on time today but I have a few thoughts, some of which may be partially reiterated from the previous related thread, to keep the ball rolling.

= Field and Method Declaration Syntax =

I still find the difference between field and method declaration styles quite jarring after playing with them for a while.  In my experience most languages reuse their variable and function declaration syntax, with some additions, for this.  TypeScript and JavaScript are exceptions that spring to mind.

I think it's reasonable, though unnecessary, to introduce new syntax for member declarations but we're currently only doing so for fields.

So my preference would be to use one of the following.

# Syntax-1
class Foo
  this.bar: number = 42
  this.Baz(qux: number): number {
     return this.bar + qux
  }
endclass

# Syntax-2
class Foo
  var bar: number = 42
  def Baz(qux: number): number
    return this.bar + qux
  enddef
endclass

I think we could get away with curly braces in the Syntax-1 version as they're already used for lambda blocks and others.

Using Syntax-2, fields are declared as variables would be in other contexts and then qualification with "this" could be required to access them.  Then, the only new syntax rule is the qualification requirement.  This was also proposed in the earlier thread by Maxim but didn't seem to garner any comment.

var this.bar: number = 42 has been proposed but that is also jarring as declarations of qualified identifiers aren't allowed in any other context and the qualification is redundant.

Syntax-2 is what I would have guessed the class declaration syntax would look like after having previously worked with Vim9 script.  I think anything else is an unnecessary complication so it would be my strong preference.

= Underscore for Private Access =

The current implementation's asymmetry with regard to the private underscore prefix and public modifier keyword isn't particularly elegant.  I note that it largely disappears with your newly proposed change of defaulting to public access.

Irrespective, I'd prefer keywords were used for access modification.  A leading underscore is used for many ad-hoc purposes such as reserved words, member fields, pseudo private fields and generally to work around perceived deficiencies in a language.  It has a lot of baggage and I wouldn't like to see it become semantically significant.

Dart uses this scheme for library level access but they later introduced a @protected annotation.  Keyword modifiers are more flexible and future proof.

JavaScript uses the even uglier # sigil but IIRC that was largely done for JavaScript specific reasons that aren't pertinent.

Leading underscores are also ugly, to my eye, and I'd consider it an unfortunate addition after the identifier prefix requirements were cleaned up for Vim 9.

For example, when it's paired with required this qualification we get the following from the help section on private members:

def GetLnum(): number
  if this._lnum > this._lineCount
    return this._lineCount
  endif
  return this._lnum
enddef

rather than the infinitely more readable:

def GetLnum(): number
  if lnum > lineCount
    return lineCount
  endif
  return lnum
enddef

The "this" qualification and "_" prefix are both useless to me when reading or writing this so some of those lines are almost 50% noise.  That's a simple method, I think it can only get worse.

= Miscellaneous =

A few other questions that occurred to me:

- Is it intended that public fields can have the same name (ignoring the underscore) as private fields?
- Are private methods planned?  I don't think I noticed any reference to these one way or the other in the help.
- Are final fields planned?

Regards,
Doug

Bram Moolenaar

unread,
Jan 24, 2023, 12:03:28 PM1/24/23
to vim...@googlegroups.com, Doug Kearns

Doub Kearns wrote:

> I'm a bit short on time today but I have a few thoughts, some of which may
> be partially reiterated from the previous related thread, to keep the ball
> rolling.

Thanks for your opinions. I'll take them into account.

> = Underscore for Private Access =
>
> The current implementation's asymmetry with regard to the private
> underscore prefix and public modifier keyword isn't particularly elegant.
> I note that it largely disappears with your newly proposed change of
> defaulting to public access.
>
> Irrespective, I'd prefer keywords were used for access modification. A
> leading underscore is used for many ad-hoc purposes such as reserved words,
> member fields, pseudo private fields and generally to work around perceived
> deficiencies in a language. It has a lot of baggage and I wouldn't like to
> see it become semantically significant.

Mostly a matter of taste, but also it has a history, using an underscore
for private members has been used in many style guides (even if the
language doesn't do anything with it).

Considering:

> - Are private methods planned? I don't think I noticed any reference to
> these one way or the other in the help.

Yes, we should support private methods. The question then is how to
specify that. Using the same mechanism as for members would be
expected. With an underscore:

this._privateMember = 'text'
def _PrivateFunc()

With a keyword:

private this.privateMember = 'text'
private def PrivateFunc()

To me this doesn't appear to change the preference for how to mark
members as private.

> - Is it intended that public fields can have the same name (ignoring the
> underscore) as private fields?

No, we should not allow that, it is not only confusing, it also makes it
difficult to change a member from private to public later.

> - Are final fields planned?

Not sure. "final" is an extra mechanism and it doesn't add
functionality. It is mainly useful in larger, multi-person projects
where you don't want others to overrule your class/method/etc.
It can make writing tests more difficult.

--
George: "I just got a new set of golf clubs for my wife!"
John: "Great trade!"

Ernie Rael

unread,
Jan 24, 2023, 1:23:54 PM1/24/23
to vim...@googlegroups.com
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.

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

Dominique Pellé

unread,
Jan 24, 2023, 3:15:14 PM1/24/23
to vim...@googlegroups.com
Bram Moolenaar wrote:

> Currently I decided to keep it relatively simple and only provide three
> ways:
>
> - public: read and write access, using the "public" keyword
> - default: read access only, no keyword used
> - private: name prefixed with an underscore

It can be fine, but:
- it's not symmetric to have a keyword for 'public' members
only. Symmetry is nice when possible.
- what if the developer changes his mind (changing
a member from private to public for example). It
requires renaming all occurrences.

I'd slightly prefer the 'private' (default) and 'public' keywords
and use 'const' or 'final' instead of implicit constness.
Later you may decide to add 'protected' if deemed useful enough.
I would have preferred 'const' by default and use the explicit 'mutable'
or 'mut' to make things changeable as in 'rust', but that would be
inconsistent with the regular variables in vim9 unfortunately.

Dominique

Ernie Rael

unread,
Jan 25, 2023, 2:41:43 PM1/25/23
to vim...@googlegroups.com
On 23/01/24 10:23 AM, Ernie Rael wrote:
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

Doug Kearns

unread,
Feb 2, 2023, 11:22:28 AM2/2/23
to vim...@googlegroups.com
On Sun, 15 Jan 2023 at 02:34, Bram Moolenaar <Br...@moolenaar.net> wrote:

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.
 
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.

Regards,
Doug

Bram Moolenaar

unread,
Feb 2, 2023, 12:28:11 PM2/2/23
to vim...@googlegroups.com, Doug Kearns

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.


--
From "know your smileys":
:-O>-o Smiley American tourist (note big mouth and camera)

Ernie Rael

unread,
Feb 2, 2023, 3:19:55 PM2/2/23
to vim...@googlegroups.com
On 23/02/02 9:28 AM, Bram Moolenaar wrote:
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

Marius Gedminas

unread,
Feb 3, 2023, 6:58:47 AM2/3/23
to vim...@googlegroups.com
On Thu, Feb 02, 2023 at 05:28:03PM +0000, Bram Moolenaar wrote:
> 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.

Python lets you declare that a function will not accept positional
arguments:

def fn(*, line, column, also_arg_with_a_default_value=42):
...

fn(line=5, column=0)
fn(column=0, line=5)
fn(0, 5) # <-- error, positional arguments not allowed
fn(line=5) # <-- error, 'column' argument is required

Marius Gedminas
--
I can barely exit nano.
-- Christian Neukirchen
signature.asc

Bram Moolenaar

unread,
Feb 3, 2023, 7:55:37 AM2/3/23
to vim...@googlegroups.com, Marius Gedminas
I have been using Python but didn't know about this mechanism.

Apparently the "*" can also appear later, e.g.

def fn(line, *, column, also_arg_with_a_default_value=42):

Now you can use:
fn(5, column=0)

Although this works, I find it rather obscure.

--
You can't have everything. Where would you put it?
-- Steven Wright

Doug Kearns

unread,
Feb 4, 2023, 8:14:11 AM2/4/23
to Bram Moolenaar, vim...@googlegroups.com
On Fri, 3 Feb 2023 at 04:28, Bram Moolenaar <Br...@moolenaar.net> wrote:

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

This is probably the 'standard' approach.
 
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.

Swift does this for structs and calls them memberwise initializers.  It creates a default initializer (constructor) with named fields if no initializer is otherwise specified.

struct Foo {
  var x: Int
  var y: Int
}
let bar = Foo(x: 1, y: 2)

Classes don't currently create the default memberwise initializer (there's a proposal for this) but named parameters are either specified or created automatically for declared initializers.

Swift actually defaults to named parameters and the mechanism is a little more elaborate than usual as argument labels can be specified that differ from the parameter names.   Unnamed parameters are allowed but these must be explicitly specified with an argument label of "_".

I've never used Swift in anger; it was just the first search result of interest.  Here are the details - https://docs.swift.org/swift-book/LanguageGuide/Initialization.html

Regards,
Doug

Marius Gedminas

unread,
Feb 4, 2023, 8:54:02 AM2/4/23
to Bram Moolenaar, vim...@googlegroups.com
On Fri, Feb 03, 2023 at 12:55:30PM +0000, Bram Moolenaar wrote:
> > On Thu, Feb 02, 2023 at 05:28:03PM +0000, Bram Moolenaar wrote:
> > > 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.
> >
> > Python lets you declare that a function will not accept positional
> > arguments:
> >
> > def fn(*, line, column, also_arg_with_a_default_value=42):
> > ...
> >
> > fn(line=5, column=0)
> > fn(column=0, line=5)
> > fn(0, 5) # <-- error, positional arguments not allowed
> > fn(line=5) # <-- error, 'column' argument is required
>
> I have been using Python but didn't know about this mechanism.

This syntax was added in Python 3.0. Since I started with Python 2.1, I
still think of it as "the new keyword-only argument syntax". I'm old.

> Apparently the "*" can also appear later, e.g.
>
> def fn(line, *, column, also_arg_with_a_default_value=42):
>
> Now you can use:
> fn(5, column=0)
>
> Although this works, I find it rather obscure.

It is a consequence of allowing variable number of arguments with *args:

def fn(regular, args, *the_rest):

the Python designers decided to allow additional arguments after the
all-consuming varargs argument

def fn(regular, args, *the_rest, keyword_only=None):

and then if you don't actually want the varargs you can omit the name
for it

def fn(regular, args, *, keyword_only=None):

Anyway, I wasn't proposing this syntax for Vimscript, merely mentioning
that there are languages that have this functionality.

Marius Gedminas
--
Initially, there were few or no postal regulations governing packages mailed
parcel post. To construct a bank in Vernal, Utah in 1916, a Salt Lake City
Company figured out that the cheapest way to send 40 tons of bricks to the
building was by Parcel Post. Each brick was individually wrapped & mailed.
Postal rules were promptly rewritten.
-- http://en.wikipedia.org/wiki/United_States_Postal_Service
signature.asc

Doug Kearns

unread,
Feb 5, 2023, 11:40:40 AM2/5/23
to vim...@googlegroups.com
On Sun, 15 Jan 2023 at 02:34, Bram Moolenaar <Br...@moolenaar.net> wrote:

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.

I notice that it's planned to allow classes to "specify" an interface.  Does this not make interfaces themselves redundant?  I can't see any utility to them over abstract classes that specify an interface.

Regards,
Doug

Bram Moolenaar

unread,
Feb 5, 2023, 12:54:43 PM2/5/23
to vim...@googlegroups.com, Doug Kearns

> I notice that it's planned to allow classes to "specify" an interface.
> Does this not make interfaces themselves redundant? I can't see any
> utility to them over abstract classes that specify an interface.

An abstract class and an interface have several similarities. Some
languages do not even have interfaces and then you use an abstract class
instead.

An important difference is the intention. For an abstract class this is
not always clear, some people suggest to not have them at all for that
reason. For an interface the intention is very clear.

The idea to have a class (not abstract) specify an interface comes from
the life cycle of code. Also for testing purposes. Very often someone
creates a class, and only later there is a desire to have an interface,
which the class implements. Since this then requires quite a bit of
refactoring, some have suggested to always define an interface and a
separate class that implements that interface. Unfortunately that
causes a lot of duplication.

The mechanism that a class can function as an interface at the same time
solves these problems elegantly. It avoids defining an interface
separately, and it's easy to add the interface to the class later.
It is almost like having a tool that generates the interface from the
class.

Only a few languages have this mechanism, but I like it. We can
probably do without it for quite a while, thus implementing this has a
low priority.

--
From "know your smileys":
@:-() Elvis Presley
Reply all
Reply to author
Forward
0 new messages