Обсуждение: Calling variadic function with default value in named notation

Поиск
Список
Период
Сортировка

Calling variadic function with default value in named notation

От
Wolfgang Walther
Дата:
Hi,

I tried the following on PG 12.4 and PG 13.0:


create function a(x int, y int[] default '{}')
returns void language sql as '';

create function b(x int, variadic y int[] default '{}')
returns void language sql as '';

-- 1
select a(1, '{2}');
-- 2
select b(1, 2);
-- 3
select a(x=>1, y=>'{2}');
-- 4
select b(x=>1, variadic y=>'{2}');
-- 5
select a(1);
-- 6
select b(1);
-- 7
select a(x=>1);
-- 8
select b(x=>1);


The first 7 calls succeed, but the last one is failing with:


ERROR: function b(x => integer) does not exist
LINE 1: select b(x=>1);
                ^
HINT: No function matches the given name and argument types. You might 
need to add explicit type casts.


So while I am able to call the variadic function in named notation (call 
4) or with the default value (call 6) - I am not able to put both 
together in call 8.

I could not find anything in the documentation that points this out as a 
limitation, so I expected this to work. Did I miss anything?

Thanks

Wolfgang



Re: Calling variadic function with default value in named notation

От
Tom Lane
Дата:
Wolfgang Walther <walther@technowledgy.de> writes:
> create function b(x int, variadic y int[] default '{}')
> returns void language sql as '';

> select b(x=>1, variadic y=>'{2}');
> [ ok ]

> select b(x=>1);
> ERROR: function b(x => integer) does not exist

> I could not find anything in the documentation that points this out as a 
> limitation, so I expected this to work. Did I miss anything?

You can't write positional arguments after named arguments, so the
failure to match isn't all that surprising; that is, to accept this
call we'd have to interpret it as a named argument and then an empty
list of things to match positionally to the variadic parameter.
Perhaps a better error message could be wished for, but given the
current rules this can't succeed.

One could imagine saying that if the function has a variadic last
parameter, then we can match that to zero or more positional arguments
after the last named argument.  Not sure that that would be a good
idea though, or how hard it'd be to implement.  It'd be a pretty
radical departure from the rules for non-variadic functions.

            regards, tom lane



Re: Calling variadic function with default value in named notation

От
"David G. Johnston"
Дата:
On Wed, Oct 28, 2020 at 2:18 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
One could imagine saying that if the function has a variadic last
parameter, then we can match that to zero or more positional arguments
after the last named argument.  Not sure that that would be a good
idea though, or how hard it'd be to implement.  It'd be a pretty
radical departure from the rules for non-variadic functions.
 
I too failed to realize that there was an implied, required, positional, parameter, of cardinality zero, following the named parameter.  I see no reason to make that case work.  I'm doubtful additional words in the documentation, examples or otherwise, would have helped people commit this edge case to memory.  The error message would be of benefit but IMO it isn't worth the effort given the sparsity of complaints and the assumed rarity that all three of these dynamics come into play in order to have an obscure doesn't work scenario.

David J.


Re: Calling variadic function with default value in named notation

От
Wolfgang Walther
Дата:
Tom Lane:
> You can't write positional arguments after named arguments, so the
> failure to match isn't all that surprising; that is, to accept this
> call we'd have to interpret it as a named argument and then an empty
> list of things to match positionally to the variadic parameter.

It's not possible to have positional after named arguments and variadic 
arguments always come last. Therefore, once any other argument is named 
(so the call is made with either named or mixed notation) any variadic 
argument will always have to be named. In this case it could be 
interpreted as a named argument, even if absent, so the default value 
should be given.

The information about the call being in named or mixed notation should 
be available well in advance, when the statement is parsed. Do you think 
it would be possible to "expect a named variadic argument" and then 
fallback to the default in this case?


David G. Johnston:

> I too failed to realize that there was an implied, required, 
> positional, parameter, of cardinality zero, following the named parameter.
IMHO it's neither required nor positional. Not required, because it has 
a default value and not positional because it can never be in this case 
(see above).


> I see no reason to make that case work. I'm doubtful additional words 
> in the documentation, examples or otherwise, would have helped people 
> commit this edge case to memory.  The error message would be of 
> benefit but IMO it isn't worth the effort given the sparsity of 
> complaints and the assumed rarity that all three of these dynamics 
> come into play in order to have an obscure doesn't work scenario.
One reason for the lack of complaints so far could also be, that people 
don't realize it's actually possible to call variadic arguments in named 
notation at all. This fact is not at all obvious from the documentation, 
it's spread across different places.


In general, although PG doesn't implement it that way, variadic 
arguments don't have to be unnamed by nature. Something like the 
following could be very much imaginable:

SELECT func(a => 1, b => 2, a => 3, a => 4)

PG chooses to implement calling variadic arguments in named notation 
with array syntax + variadic keyword. PG also implements DEFAULT values 
for variadic arguments (something that could have been done differently 
as well!). It would just make sense to support both together as well.


Best regards

Wolfgang




Re: Calling variadic function with default value in named notation

От
"David G. Johnston"
Дата:
On Wed, Oct 28, 2020 at 11:46 PM Wolfgang Walther <walther@technowledgy.de> wrote:
One reason for the lack of complaints so far could also be, that people
don't realize it's actually possible to call variadic arguments in named
notation at all. This fact is not at all obvious from the documentation,
it's spread across different places.


As I look at this more I'm definitely agreeing that the documentation here is problematic.  Specifically, the fact that the only place about this syntax is in a chapter under Extending SQ - SQL Functions, is not good.  It really needs to be in the Syntax chapter.

That said the one place this syntax is explicitly defined says:

"The array element parameters generated from a variadic parameter are treated as not having any names of their own. This means it is not possible to call a variadic function using named arguments (Section 4.3), except when you specify VARIADIC."

And proceeds to give examples.

Given the volume of precautions listed in 10.3, Function Type Resolution, it definitely seems like an imposing challenge to evaluate and change behavior in this area.

In short, I agree that there is a need for a documentation patch, and may even write one at some point in the future.  As for making the last case work, the concept has merit but my expectations are low.

David J.

Re: Calling variadic function with default value in named notation

От
Tom Lane
Дата:
Wolfgang Walther <walther@technowledgy.de> writes:
> Tom Lane:
>> You can't write positional arguments after named arguments, so the
>> failure to match isn't all that surprising; that is, to accept this
>> call we'd have to interpret it as a named argument and then an empty
>> list of things to match positionally to the variadic parameter.

> It's not possible to have positional after named arguments and variadic 
> arguments always come last. Therefore, once any other argument is named 
> (so the call is made with either named or mixed notation) any variadic 
> argument will always have to be named. In this case it could be 
> interpreted as a named argument, even if absent, so the default value 
> should be given.

> The information about the call being in named or mixed notation should 
> be available well in advance, when the statement is parsed. Do you think 
> it would be possible to "expect a named variadic argument" and then 
> fallback to the default in this case?

Looking back at the original discussion about named arguments,

https://www.postgresql.org/message-id/flat/15635.1249842629%40sss.pgh.pa.us

there was quite extensive discussion about how they should interact
with VARIADIC, and we ended up settling on the current behavior,
which is that you must explicitly say VARIADIC if you want a
named-arguments call to match a variadic function.  The argument
for requiring that was basically to avoid confusion, which I think
is reasonable.

Now what I don't see in that thread is any mention of the possibility of
allowing the variadic parameter to be defaulted --- which is problematic
with this rule mostly because then there's noplace to write VARIADIC.

Still, the fact that this hasn't come up in ten-plus years says
that it's a pretty niche use case.  I'm not sure that it's worth
doing anything about.

I did poke at the code a little bit, and the fact that the function isn't
matched just comes down to these two lines in FuncnameGetCandidates:

             if (OidIsValid(procform->provariadic) && expand_variadic)
                 continue;

If you delete them then all these cases work, but so would some other
ones that I doubt we should allow.  I'd be inclined to insist that
the only two cases we should allow are (1) the variadic parameter
isn't listed in the call (so it's defaulted), or (2) it is listed
with an explicit VARIADIC marker (which is the case we allow now).

            regards, tom lane



Re: Calling variadic function with default value in named notation

От
Tom Lane
Дата:
"David G. Johnston" <david.g.johnston@gmail.com> writes:
> As I look at this more I'm definitely agreeing that the documentation here
> is problematic.  Specifically, the fact that the only place about this
> syntax is in a chapter under Extending SQ - SQL Functions, is not good.  It
> really needs to be in the Syntax chapter.

The documentation situation was complained of in the 2009 thread I just
cited :-(.  Doesn't look like anybody did anything about it.

I am not, however, persuaded that you can just move a bunch of that
material to the syntax chapter.  I don't think it's very practical
to describe variadic functions when the user doesn't know how to
create one.  And we definitely should not push all the docs about
creating functions into the syntax chapter.

            regards, tom lane



Re: Calling variadic function with default value in named notation

От
"David G. Johnston"
Дата:
On Thu, Oct 29, 2020 at 8:51 AM Tom Lane <tgl@sss.pgh.pa.us> wrote:
"David G. Johnston" <david.g.johnston@gmail.com> writes:
> As I look at this more I'm definitely agreeing that the documentation here
> is problematic.  Specifically, the fact that the only place about this
> syntax is in a chapter under Extending SQ - SQL Functions, is not good.  It
> really needs to be in the Syntax chapter.

The documentation situation was complained of in the 2009 thread I just
cited :-(.  Doesn't look like anybody did anything about it.

I am not, however, persuaded that you can just move a bunch of that
material to the syntax chapter.

That wasn't the intent, but the exact solution will take time to come up with so I was just being vague.

  I don't think it's very practical
to describe variadic functions when the user doesn't know how to
create one.

Plenty of users are able to execute built-in functions without knowing how to create them.  This doesn't seem any different.

David J.


Re: Calling variadic function with default value in named notation

От
Wolfgang Walther
Дата:
Tom Lane:
> I did poke at the code a little bit, and the fact that the function isn't
> matched just comes down to these two lines in FuncnameGetCandidates:
> 
>               if (OidIsValid(procform->provariadic) && expand_variadic)
>                   continue;
> 
> If you delete them then all these cases work, but so would some other
> ones that I doubt we should allow.

I looked at this a lot longer than on my latest endeavor in boolean 
algebra [somewhere else] and came to the conclusion that the only other 
case that would be allowed by this change is in the following:


create function f(x int, variadic y int[] default '{}')
returns void language sql as '';

-- was ok before
select f(x=>1, variadic y=>'{2}');

-- ability to default is the goal
select f(x=>1);

-- omitting the variadic keyword is now also possible
select f(x=>1, y=>'{2}');


So for mixed/named notation the variadic keyword would now be optional. 
I realize that this has been discussed intensively in the thread you 
mentioned - but did I miss any other cases that are now allowed as well?


 > Looking back at the original discussion about named arguments,
 >
 > 
https://www.postgresql.org/message-id/flat/15635.1249842629%40sss.pgh.pa.us
 >
 > there was quite extensive discussion about how they should interact
 > with VARIADIC, and we ended up settling on the current behavior,
 > which is that you must explicitly say VARIADIC if you want a
 > named-arguments call to match a variadic function.  The argument
 > for requiring that was basically to avoid confusion, which I think
 > is reasonable.

Thanks for the link! I read through the whole thread and this is what I 
took from it:
The reasons for making the variadic keyword required in named notation 
calls are (1) to keep backwards compatibility for future extensions - 
the only one that comes to mind is repeating named arguments for the 
variadic elements as mentioned by me somwhere upthread - and (2) to 
avoid confusion.

There were no extensions in that regard in the last ten-plus years, so I 
would assume it was safe to make this keyword optional now. I don't see 
repeated named arguments coming up anytime. I didn't hear of any 
language allowing this, yet, and tried googling for it but didn't come 
up with any as well. I'm most likely wrong here, but it doesn't seem 
widespread at least.

As for the confusion... I'm very much convinced that any confusion on 
this topic is from lack of documentation. I guess we agree on that. If 
making named calls with a variadic keyword was documented more, it 
should be easily possible to state it as optional as well. That should 
avoid any confusion.


 > Still, the fact that this hasn't come up in ten-plus years says
 > that it's a pretty niche use case.  I'm not sure that it's worth
 > doing anything about.

Well, I tried to use it that way, so my opinion is different ;)

Since the question of how to call functions in positional/mixed/named 
notations seems to be pretty much settled, it would make sense to just 
"finish" this and allow defaulting the variadic named keyword. It's 
strange to be allowed to set a default and not be able to use it once 
you name any argument.

If the optional variadic keyword is indeed the only thing that changes 
when removing those two lines, I think this would fix the default case 
without much effort. The documentation improvement seems neccessary in 
any case.

Of course the next thing you tell me will be that I missed 10 other 
cases that are implied by this change as well and everything I wrote is 
rendered void... ;)

Best

Wolfgang



Re: Calling variadic function with default value in named notation

От
Pavel Stehule
Дата:


út 3. 11. 2020 v 21:04 odesílatel Wolfgang Walther <walther@technowledgy.de> napsal:
Tom Lane:
> I did poke at the code a little bit, and the fact that the function isn't
> matched just comes down to these two lines in FuncnameGetCandidates:
>
>               if (OidIsValid(procform->provariadic) && expand_variadic)
>                   continue;
>
> If you delete them then all these cases work, but so would some other
> ones that I doubt we should allow.

I looked at this a lot longer than on my latest endeavor in boolean
algebra [somewhere else] and came to the conclusion that the only other
case that would be allowed by this change is in the following:


create function f(x int, variadic y int[] default '{}')
returns void language sql as '';

-- was ok before
select f(x=>1, variadic y=>'{2}');

-- ability to default is the goal
select f(x=>1);

-- omitting the variadic keyword is now also possible
select f(x=>1, y=>'{2}');


So for mixed/named notation the variadic keyword would now be optional.
I realize that this has been discussed intensively in the thread you
mentioned - but did I miss any other cases that are now allowed as well?


 > Looking back at the original discussion about named arguments,
 >
 >
https://www.postgresql.org/message-id/flat/15635.1249842629%40sss.pgh.pa.us
 >
 > there was quite extensive discussion about how they should interact
 > with VARIADIC, and we ended up settling on the current behavior,
 > which is that you must explicitly say VARIADIC if you want a
 > named-arguments call to match a variadic function.  The argument
 > for requiring that was basically to avoid confusion, which I think
 > is reasonable.

Thanks for the link! I read through the whole thread and this is what I
took from it:
The reasons for making the variadic keyword required in named notation
calls are (1) to keep backwards compatibility for future extensions -
the only one that comes to mind is repeating named arguments for the
variadic elements as mentioned by me somwhere upthread - and (2) to
avoid confusion.

There were no extensions in that regard in the last ten-plus years, so I
would assume it was safe to make this keyword optional now. I don't see
repeated named arguments coming up anytime. I didn't hear of any
language allowing this, yet, and tried googling for it but didn't come
up with any as well. I'm most likely wrong here, but it doesn't seem
widespread at least.

As for the confusion... I'm very much convinced that any confusion on
this topic is from lack of documentation. I guess we agree on that. If
making named calls with a variadic keyword was documented more, it
should be easily possible to state it as optional as well. That should
avoid any confusion.


 > Still, the fact that this hasn't come up in ten-plus years says
 > that it's a pretty niche use case.  I'm not sure that it's worth
 > doing anything about.

Well, I tried to use it that way, so my opinion is different ;)

Since the question of how to call functions in positional/mixed/named
notations seems to be pretty much settled, it would make sense to just
"finish" this and allow defaulting the variadic named keyword. It's
strange to be allowed to set a default and not be able to use it once
you name any argument.

If the optional variadic keyword is indeed the only thing that changes
when removing those two lines, I think this would fix the default case
without much effort. The documentation improvement seems neccessary in
any case.

Of course the next thing you tell me will be that I missed 10 other
cases that are implied by this change as well and everything I wrote is
rendered void... ;)

I dislike the proposed change. The using VARIADIC keyword is signal so arguments are used in different than usual format. More, it introduces other inconsistency between named and unnamed notation. So it may remove one issue, but introduces another issue. 

Regards

Pavel


Best

Wolfgang