Thread: Calling variadic function with default value in named notation
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
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
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.
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
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.
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
"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
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.
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
ú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