Proposal for User methods

32 views
Skip to first unread message

Bram Moolenaar

unread,
Aug 10, 2019, 6:11:43 PM8/10/19
to vim...@googlegroups.com

Currently user functions can be used both without a context and as a
method, it is not possible to restrict them to be used as one or the
other. Very often this doesn't matter, the method is the same as the
function, passing the base as the first argument. But questions arise:

- What if the function doesn't take an argument, should it not be able
to be used as a method? Or always result in an error? Or should we
be able to define a function FooBar() without an argument to be used
as a function and a function FooBar() with an argument to be used as a
method:
func Report()
echo "nothing to report"
endfunc
func Report(msg)
echo "this happened: " .. a:msg
endfunc

- What if I want to define a similar but different method depending on
the type of the first argument:
GetList()->Total()
GetDict()->Total()
Generally, define a method that gets used only if the context type
matches.
We already do this for internal functions: len() works differently
depending on the argument type.

All can be done in some other way, but rather clumsy. We could try
supporting this better.

I was first thinking of adding a property to the function command:
function Total(arg) method=list
function Total(arg) method=dict

Many languages now support an optional type, using that we could do:
function Total(arg: list) method
function Total(arg: dict) method

Instead of the property we might as well use a new command:
method Total(arg: list)
method Total(arg: dict)
That means the first Total() can be used as mylist->Total() and the
second one as mydict->Total(), but you cannot do "call Total(list)".

That a function which was not written intentionally to be called as a
method CAN be called as a method, passing the base as the first
argument, is probably a good thing. That way a function written by
anyone, without any special annotation, can be used as a method. I
don't see a reason to disallow that.

So if you intentionally want to define a function to both be used
without a context and as a method, but still want to specify the type,
we should allow for:
function Total(arg: list)
function Total(arg: dict)

This basically means we have function overloading based on argument
types.

Opinions?

--
Don't read everything you believe.

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

Justin M. Keyes

unread,
Aug 11, 2019, 10:30:04 AM8/11/19
to vim...@googlegroups.com
What problem is being solved by adding these various OOP cosmetics to
Vimscript, other than ticking a "I have this feature" checkbox?

Historically, something that I strongly appreciated about Vim was its
(now obviously accidental) culture of backwards-compatibility in the
*plugin community*. This happened (accidentally) because Vimscript
evolved so slowly, it was usually worth the effort for plugins to
support 10-year-old versions of Vim. Contrast to Emacs, where I found
most plugins required the latest version.

With meaningless syntax-sugar being added into Vimscript, that
accident will become much less frequent. Plugin authors can add
wrappers for e.g. missing *library* functions. But they cannot add
wrappers for syntax sugar. They could adopt a "subset" (like C++...
does that sound familiar?) of VimL, but the general effect will be
pollution of community knowledge as the discussion becomes more
complicated, with code samples only working in recent Vim versions
simply because someone writes foo->bar() instead of bar(foo).

Why in the world is foo->bar() worth sacrificing even a small amount
of backwards compatibility, or worth complicating
tutorials/documentation/discussions even a small amount? It is pure
vanity. The same applies for these other meaningless OOP cosmetics
(including "dict functions" which are harder to debug).

It is strange that these "fake OOP" features are being *amplified* in
Vim now. What's the point?

> I was first thinking of adding a property to the function command:
> function Total(arg) method=list
> function Total(arg) method=dict
>
> Many languages now support an optional type, using that we could do:
> function Total(arg: list) method
> function Total(arg: dict) method

Type-parameterized methods are usable in languages with IDEs. But I do
not think it makes sense to change Vimscript into a language that
requires an IDE: that is a regression, not an improvement.

--
Justin M. Keyes

Andy Wokula

unread,
Aug 11, 2019, 11:41:11 AM8/11/19
to vim...@googlegroups.com
Am 11.08.2019 um 00:11 schrieb Bram Moolenaar:
> Currently user functions can be used both without a context and as a
> method, it is not possible to restrict them to be used as one or the
> other. Very often this doesn't matter, the method is the same as the
> function, passing the base as the first argument. But questions arise:
>
> - What if the function doesn't take an argument, should it not be able
> to be used as a method? Or always result in an error? Or should we
> be able to define a function FooBar() without an argument to be used
> as a function and a function FooBar() with an argument to be used as a
> method:
> func Report()
> echo "nothing to report"
> endfunc
> func Report(msg)
> echo "this happened: " .. a:msg
> endfunc

I have a mechanism in place which loads global functions via
FuncUndefined (similar to DrChip's AsNeeded).

Now I wonder how to find the right script when the function name alone
is no longer enough for the lookup.

--
Andy

Bram Moolenaar

unread,
Aug 11, 2019, 12:28:03 PM8/11/19
to vim...@googlegroups.com
If you define a normal user function, both available globally and as a
method, then nothing changes.

If you specifically target a method, thus used after -> and not
available without it, we should probably add a MethodUndefined
autocommand. It would be used first, and only when no results then
FuncUndefined is triggered to find/load any user function.

I'm not sure about methods for a specific type, e.g. only defined for a
list or dict. I suppose in many cases you have very similar
functionality in both, and might as well define both.

It would be possible to make the type available to the autocommand. But
it feels like this is getting more complicated than needed. That is
also the main reason I asked: Do we want/need to select the function
based on the type? Perhaps we should just keep it simple and have a
function/method always handle all types.

I want to start adding internal functions that are only available as a
method, to avoid "polluting" the global function namespace. But for the
script writer it doesn't matter if this is one function for all types,
or different functions for each type, the same will happen. For user
functions it does matter.

--
Well, you come from nothing, you go back to nothing... What have you
lost? Nothing!
-- Monty Python: The life of Brian

Andy Wokula

unread,
Aug 11, 2019, 12:51:21 PM8/11/19
to vim...@googlegroups.com
Am 11.08.2019 um 18:27 schrieb Bram Moolenaar:
> I'm not sure about methods for a specific type, e.g. only defined for a
> list or dict. I suppose in many cases you have very similar
> functionality in both, and might as well define both.
>
> It would be possible to make the type available to the autocommand. But
> it feels like this is getting more complicated than needed. That is
> also the main reason I asked: Do we want/need to select the function
> based on the type?

If you ask me: no.
I want to be able to build these things using Vim script
because then it's backwards compatible.

I wish there was a *small* Vim script core (already too late).

I'm with JM Keyes there: we don't need more syntactic
(or syntoxic!!) sugar.


My Vim script experiments (just for the record):

CallOverloaded()
https://gist.github.com/Houl/d28f6b05f14956296fd9328e149d8751

Usage example: HasPatchExpr()
https://gist.github.com/Houl/151594d0089fee91e33ba6d676f5092c

--
Andy

Ingo Karkat

unread,
Aug 11, 2019, 1:21:09 PM8/11/19
to vim...@googlegroups.com
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

On 11-Aug-2019 18:51 +0200, 'Andy Wokula' via vim_dev wrote:
> Am 11.08.2019 um 18:27 schrieb Bram Moolenaar:
>> I'm not sure about methods for a specific type, e.g. only defined
>> for a list or dict. I suppose in many cases you have very
>> similar functionality in both, and might as well define both.
>>
>> It would be possible to make the type available to the
>> autocommand. But it feels like this is getting more complicated
>> than needed. That is also the main reason I asked: Do we
>> want/need to select the function based on the type?
>
> If you ask me: no. I want to be able to build these things using
> Vim script because then it's backwards compatible.
>
> I wish there was a *small* Vim script core (already too late).
>
> I'm with JM Keyes there: we don't need more syntactic (or
> syntoxic!!) sugar.

I agree with Andy and Justin. The vast majority of plugins are small
enough to be written in a procedural style, and any desire to do some
simple object orientation can be satisfied via Dictionary functions
alread. For anything larger or complex, I would use another embedded
language, of which Vim supports many (depending on the build, but both
Python and Perl have very fine and powerful object-orientation and are
commonly available).

The discussion about type annotation and how FuncUndefined would be
affected already shows how hard it is to retrofit these features into
the existing language. (Java did this with generics and closures - but
both still left many unsatisfied with the chosen design, and it took
several committees a long time.) I'd rather have the effort spent on
adding more low-level functions (like the recent chdir() and sign_*()
additions), and to work on the huge todo list; there are still so many
outstanding patches and bugs.

The addition of Lists, Dictionaries and many other things in Vim 7.0
was a good thing - it enabled effective plugin development, and people
desperate for these features were already emulating these poorly on
their own. With the recent addition of closures (which I still
hesitate to use - I still encounter Vim 7.4 on some Ubuntu 16.04 LTS
systems), I think we're now firmly in the area of diminishing returns
when it comes to language features.

- -- regards, ingo
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2

iQEcBAEBCAAGBQJdUE56AAoJEA7ziXlAzQ/vgBgH/1GX7m7J+NFn56vVrIkiFy/e
hirGIQMdMDk9FiJeqx/EZsCwX61KlVJX5PVp+Kcsw7WL04xKKzEqa1wKIQZTWKPi
iXb2oUyWOtkDMaJG7SRLFXkFmLldVdZjLUaUl5HFoLJ5W+0gSSUNUTwa62NB5OlC
P63waSB0yVwCvhmaeKOl0BS0bLsvhHjUbOgj+kuCDJHiR7aikOL/39EJwfaWrkdx
VwJ7naTth9ZnzsLSG7HvUhrZAn+ozJkh6R94b/7PVOtdBL0VrFi+c9A+wQP/cykB
J55T7D7BaCQLnS12m63c5nSA6GQ7qSEp1NpUZ1jkSBGec2EMbjPLdXXWIs8A15w=
=puBU
-----END PGP SIGNATURE-----

Andy Wokula

unread,
Aug 11, 2019, 3:38:11 PM8/11/19
to vim...@googlegroups.com
Am 11.08.2019 um 00:11 schrieb Bram Moolenaar:
> So if you intentionally want to define a function to both be used
> without a context and as a method, but still want to specify the type,
> we should allow for:
> function Total(arg: list)
> function Total(arg: dict)
>
> This basically means we have function overloading based on argument
> types.
>
> Opinions?

I'd prefer when a Vim expression in "chained notation" has an equivalent
representation as "ordinary" Vim expression.

--
Andy

Bram Moolenaar

unread,
Aug 11, 2019, 4:04:43 PM8/11/19
to vim...@googlegroups.com, Justin M. Keyes

Justin M. Keyes wrote:

> Am So., 11. Aug. 2019 um 00:11 Uhr schrieb Bram Moolenaar <Br...@moolenaar.net>:
> > Currently user functions can be used both without a context and as a
> > method, it is not possible to restrict them to be used as one or the
> > other. Very often this doesn't matter, the method is the same as the
> > function, passing the base as the first argument. But questions arise:

[...]

> What problem is being solved by adding these various OOP cosmetics to
> Vimscript, other than ticking a "I have this feature" checkbox?

That is not at all we are doing. Function chaining has nothing to do
with OOP.

> Historically, something that I strongly appreciated about Vim was its
> (now obviously accidental) culture of backwards-compatibility in the
> *plugin community*. This happened (accidentally) because Vimscript
> evolved so slowly, it was usually worth the effort for plugins to
> support 10-year-old versions of Vim. Contrast to Emacs, where I found
> most plugins required the latest version.

That is not true, over time new functionality was added and quite often
plugins soon popped up which used this functionality, thus depended on
that new version. And old plugins keep working, that is what backwards
compatibility is about. If you see an old plugin break because of new
functionality, then please report it soon, that's not what we want.

> With meaningless syntax-sugar being added into Vimscript, that
> accident will become much less frequent. Plugin authors can add
> wrappers for e.g. missing *library* functions. But they cannot add
> wrappers for syntax sugar. They could adopt a "subset" (like C++...
> does that sound familiar?) of VimL, but the general effect will be
> pollution of community knowledge as the discussion becomes more
> complicated, with code samples only working in recent Vim versions
> simply because someone writes foo->bar() instead of bar(foo).

And don't see what wrappers are needed for new syntax. Just keep using
the old syntax.

Every plugin writer will have to aim for a certain minimal Vim version.
If the plugin uses the new popup window feature, then older versions
will just not work. This is nothing new. Except perhaps I'm now adding
functionality requested by plugin writers about a year ago, thus it's
likely plugins will appear that use these new features. There is
nothing wrong with that.

Today's version of Vim is new and not widely spread, but in a few years
it is, and then we'll be glad there is a better way to write Vim script.

> Why in the world is foo->bar() worth sacrificing even a small amount
> of backwards compatibility,

If you think this breaks backwards compatibility, please give an
example.

> or worth complicating tutorials/documentation/discussions even a small
> amount? It is pure vanity. The same applies for these other
> meaningless OOP cosmetics (including "dict functions" which are harder
> to debug).

I found myself writing Vim code this way, because it's very natural.
All modern languages use and recommend this, including Java and
Typescript, which are both very popular.

> It is strange that these "fake OOP" features are being *amplified* in
> Vim now. What's the point?

Again, this has nothing to do with OOP.

> > I was first thinking of adding a property to the function command:
> > function Total(arg) method=list
> > function Total(arg) method=dict
> >
> > Many languages now support an optional type, using that we could do:
> > function Total(arg: list) method
> > function Total(arg: dict) method
>
> Type-parameterized methods are usable in languages with IDEs. But I do
> not think it makes sense to change Vimscript into a language that
> requires an IDE: that is a regression, not an improvement.

I hardly ever use an IDE for any language, including Java and
Typescript. True, someone who is familiar with a good IDE can do
certain things faster, but these IDEs are lacking a good editor...

Anyway, the real question I'm asking is if selecting a function/method
based on the type is actually useful or will just make things more
complicated?

--
hundred-and-one symptoms of being an internet addict:
39. You move into a new house and decide to Netscape before you landscape.

FUJIWARA Takuya

unread,
Aug 11, 2019, 5:47:20 PM8/11/19
to vim...@googlegroups.com
Bram says the same in some parts, but I'm one of users who appreciate
-> operator was included.

> Justin
What backward compatibility does this syntax sugars (type annotation
and -> operator) break?
I don't think this breaks backward compatibility.

I understand if you think it's just unnecessary, but I don't think so.
As Bram said, you can choose using -> operator or not.
It is difficult to discuss about a syntax sugar is useful or not.
Someone thinks it is useful, but the other may not.

> Type-parameterized methods are usable in languages with IDEs. But I do
> not think it makes sense to change Vimscript into a language that
> requires an IDE: that is a regression, not an improvement.

I write TypeScript in Vim.
You might think about auto-completion by variable's type when typing "->".
But it helps to avoid a lot of bugs of various errors.

---

I see this operator (->) as pipeline operators in other languages (not
method invocation),
so maybe I see slightly the different point of view from Bram.
and pipeline operator I was thinking is not related to type annotation
(just passing lhs of -> to the function of rhs).
Yes I proposed `var: type` syntax here...
https://github.com/vim/vim/issues/4768#issuecomment-518021861

Because I supposed Bram sees -> operator as method invocation and
wants to limit the type of value.
I agree it should be discussed more carefully before the first commit.
but there are no objections in the above issue.

2019年8月12日(月) 5:04 Bram Moolenaar <Br...@moolenaar.net>:
> --
> --
> 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/201908112004.x7BK4ZBt021173%40masaka.moolenaar.net.



--
FUJIWARA Takuya

Justin M. Keyes

unread,
Aug 11, 2019, 6:44:28 PM8/11/19
to Bram Moolenaar, vim...@googlegroups.com
Am So., 11. Aug. 2019 um 22:04 Uhr schrieb Bram Moolenaar <Br...@moolenaar.net>:
> That is not at all we are doing. Function chaining has nothing to do
> with OOP.

Definition of OOP is uninteresting/irrelevant here.

> > Historically, something that I strongly appreciated about Vim was its
> > (now obviously accidental) culture of backwards-compatibility in the
> > *plugin community*. This happened (accidentally) because Vimscript
> > evolved so slowly, it was usually worth the effort for plugins to
> > support 10-year-old versions of Vim. Contrast to Emacs, where I found
> > most plugins required the latest version.
>
> That is not true, over time new functionality was added and quite often
> plugins soon popped up which used this functionality, thus depended on

Vacuously true. *Functionality* is useful. *Features* often are
useless noise, and only add entropy. Language-level features in
particular.

I reported my experience based on deep familiarity with Vim and Emacs
plugin ecosystems.

> that new version. And old plugins keep working, that is what backwards
> compatibility is about. If you see an old plugin break because of new
> functionality, then please report it soon, that's not what we want.

Back-compat is easier *for plugin authors* if they don't have to
carefully select a subset of Vimscript.

> > Why in the world is foo->bar() worth sacrificing even a small amount
> > of backwards compatibility,
>
> If you think this breaks backwards compatibility, please give an
> example.

It increases the cognitive burden (to plugin authors) of finding a
backwards-compatible subset, and thereby makes back-compat a less
common, higher-cost endeavor.

> > > I was first thinking of adding a property to the function command:
> > > function Total(arg) method=list
> > > function Total(arg) method=dict
> > >
> > > Many languages now support an optional type, using that we could do:
> > > function Total(arg: list) method
> > > function Total(arg: dict) method
> >
> > Type-parameterized methods are usable in languages with IDEs. But I do
> > not think it makes sense to change Vimscript into a language that
> > requires an IDE: that is a regression, not an improvement.
>
> I hardly ever use an IDE for any language, including Java and
> Typescript. True, someone who is familiar with a good IDE can do
> certain things faster, but these IDEs are lacking a good editor...
>
> Anyway, the real question I'm asking is if selecting a function/method
> based on the type is actually useful or will just make things more
> complicated?

You can suggest *any* language feature and you'll find people who want
it. That's why C++ has all of them. So this survey is a formality.

--
Justin M. Keyes
Reply all
Reply to author
Forward
0 new messages