Thread: Variadic parameters vs parameter defaults

Variadic parameters vs parameter defaults

From
Tom Lane
Date:
Oh, and another thing --- should variadic parameters be defaultable?
The current patch doesn't allow it but it looks more like an oversight
than anything that was thought through.  The boundary case for variadic
parameters is a bit weird already:

regression=# create function fv (f1 int, f2 variadic int[]) returns int
regression-# as 'select $1' language sql;
CREATE FUNCTION
regression=# select fv(1,2);fv 
---- 1
(1 row)

regression=# select fv(1,2,3);fv 
---- 1
(1 row)

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

ISTM one could make a pretty good argument that this last case should
succeed, producing an empty-array argument.  If you buy that, then it
is sensible to forbid defaults for variadics, because a default would
conflict with this behavior (ie, there would be sort of a
system-supplied default of an empty array).  On the other hand, if we
don't want to change this behavior, then I'd like to be able to specify
"array[]::int[]" as the variadic's default so that I can make the corner
case go away when I want to.  Either way the current behavior seems
unsatisfactory.

A related point is that, because the current code forbids a default
for a variadic, you can't do something like

create function foo (f1 int, f2 int default = 42, f3 variadic int[] = array[]::int[])

ie there's no way to have defaults on the preceding parameters either.
I don't know how useful that is, but maybe it's an argument for adopting
the second solution where you can explicitly specify a default for a
variadic.

Comments?
        regards, tom lane


Re: Variadic parameters vs parameter defaults

From
Gregory Stark
Date:
Tom Lane <tgl@sss.pgh.pa.us> writes:

> A related point is that, because the current code forbids a default
> for a variadic, you can't do something like
>
> create function foo (f1 int, f2 int default = 42, f3 variadic int[] = array[]::int[])
>
> ie there's no way to have defaults on the preceding parameters either.
> I don't know how useful that is, but maybe it's an argument for adopting
> the second solution where you can explicitly specify a default for a
> variadic.
>
> Comments?

Well if you adopt the implicit empty array argument for missing variadic
parameters then you can just allow defaults for trailing parameters before the
final parameter.

I'm inclined to think an implicit empty array makes the most sense. If a
function-writer wants to enforce a minimum number of arguments they can check
and throw an error.

The question arises though whether it's useful to have any default other than
an empty array. I don't see a compelling reason.

--  Gregory Stark EnterpriseDB          http://www.enterprisedb.com Ask me about EnterpriseDB's 24x7 Postgres support!


Re: Variadic parameters vs parameter defaults

From
Josh Berkus
Date:
Tom Lane wrote:
> Oh, and another thing --- should variadic parameters be defaultable?
> The current patch doesn't allow it but it looks more like an oversight
> than anything that was thought through.  The boundary case for variadic
> parameters is a bit weird already:
From a user perspective, if we just told people "polymorphic and 
variadic parameters do not accept defaults", and give people an error 
message, I can't imagine anyone caring.    Then we can support them 
later if someone wants to troubleshoot the corner cases.

--Josh


Re: Variadic parameters vs parameter defaults

From
Tom Lane
Date:
Gregory Stark <stark@enterprisedb.com> writes:
> I'm inclined to think an implicit empty array makes the most sense. If a
> function-writer wants to enforce a minimum number of arguments they can check
> and throw an error.

> The question arises though whether it's useful to have any default other than
> an empty array. I don't see a compelling reason.

I'm not sure if that's useful either.  However, I think there are
probably quite a lot of cases where an empty array *isn't* desirable,
and so letting the current behavior alone seems okay, so long as there's
a way to override that and specify default = empty array when you do
want it to be possible.

The other way seems to boil down to "a variadic parameter has an
implicit default that you're not allowed to override", which doesn't
seem tremendously attractive.
        regards, tom lane


Re: Variadic parameters vs parameter defaults

From
"Brendan Jurd"
Date:
On Wed, Dec 17, 2008 at 11:07 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> ISTM one could make a pretty good argument that this last case should
> succeed, producing an empty-array argument.  If you buy that, then it
> is sensible to forbid defaults for variadics,

Yep, +1 for this approach.  I would intuitively expect that, if I omit
variadic argument(s) when calling a function, that the function ends
up getting an empty array of the appropriate type.

And when writing a variadic function, I wouldn't find it all
surprising or annoying if I was not allowed to override this default.
In the unlikely case I want my function to do something special when
it gets an empty array, I can write that behaviour into the function
body.

Cheers,
BJ


Re: Variadic parameters vs parameter defaults

From
Tom Lane
Date:
"Brendan Jurd" <direvus@gmail.com> writes:
> On Wed, Dec 17, 2008 at 11:07 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> ISTM one could make a pretty good argument that this last case should
>> succeed, producing an empty-array argument.  If you buy that, then it
>> is sensible to forbid defaults for variadics,

> Yep, +1 for this approach.  I would intuitively expect that, if I omit
> variadic argument(s) when calling a function, that the function ends
> up getting an empty array of the appropriate type.

Actually, I just realized that there's another fly in the ointment:
the current variadic code allows "variadic anyarray", which is
equivalent to an appropriate number of anyelement arguments.  If we
allow defaulting then there's a big problem: no principled way to
decide what type the empty array is.

The explicit-default solution would work around that, by making the
user say what type he wants.  However it puts us right back into the
situation of having a default for a polymorphic argument, which I
was hoping to avoid.
        regards, tom lane


Re: Variadic parameters vs parameter defaults

From
"Brendan Jurd"
Date:
On Wed, Dec 17, 2008 at 12:23 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> Actually, I just realized that there's another fly in the ointment:
> the current variadic code allows "variadic anyarray", which is
> equivalent to an appropriate number of anyelement arguments.  If we
> allow defaulting then there's a big problem: no principled way to
> decide what type the empty array is.

I see your point.  Polymorphic + variadic is tricky.

Because Postgres cannot determine the "default" type for the empty
variadic anyarray argument, I think it makes sense to throw an error
in this case.

So if I had these two functions ...

var1(a int, b variadic int[])
var2(a int, b variadic anyarray)

... it would be okay to write var1(8), which resolves as var1(8,
array[]::int[]).  But if I tried to write var2(8) I'd get an error.
Maybe something like "cannot determine type of missing variadic
arguments".

NB I have no idea whether such an approach would be practical to
implement, but I think it's the least astonishing set of behaviours.

Cheers,
BJ


Re: Variadic parameters vs parameter defaults

From
Tom Lane
Date:
"Brendan Jurd" <direvus@gmail.com> writes:
> So if I had these two functions ...

> var1(a int, b variadic int[])
> var2(a int, b variadic anyarray)

> ... it would be okay to write var1(8), which resolves as var1(8,
> array[]::int[]).  But if I tried to write var2(8) I'd get an error.
> Maybe something like "cannot determine type of missing variadic
> arguments".

Well, we could unify these behaviors if we insisted on an explicit
default to omit the argument in both cases.
var1(a int, b variadic int[] default '{}'::int[])var2(a int, b variadic anyarray default '{}'::text[]) -- perhaps

In both cases, supplying a single argument would be legal if and only
if you provided a default for the variadic parameter.  As soon as you
give two arguments, the default isn't relevant anymore.  This method
eliminates the discrepancy between anyarray and other types of variadic
parameters, and it leaves the door open for someone to use something
besides an empty array as the default.  (Who are we to say that such a
thing is never useful?  NULL seems like a possibly useful default for
instance.)  I think it also makes the variadic and default features
a bit more orthogonal.

This still leaves us with the annoyance of having to prevent changes in
the actual datatype of a default associated with a polymorphic parameter;
but that's just some implementation tedium, and I'm beginning to find
it more attractive than the alternatives.
        regards, tom lane


Re: Variadic parameters vs parameter defaults

From
Peter Eisentraut
Date:
On Wednesday 17 December 2008 02:07:35 Tom Lane wrote:
> Oh, and another thing --- should variadic parameters be defaultable?
> The current patch doesn't allow it but it looks more like an oversight
> than anything that was thought through.  The boundary case for variadic
> parameters is a bit weird already:
>
> regression=# create function fv (f1 int, f2 variadic int[]) returns int
> regression-# as 'select $1' language sql;
> CREATE FUNCTION

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

That looks like a bug to me.  Anything that you can do with 1 to N items 
should also work for zero.

Also, in C, variadic functions are quite commonly called with zero arguments 
in the variadic position.


Re: Variadic parameters vs parameter defaults

From
Peter Eisentraut
Date:
On Wednesday 17 December 2008 06:03:06 Tom Lane wrote:
> "Brendan Jurd" <direvus@gmail.com> writes:
> > So if I had these two functions ...
> >
> > var1(a int, b variadic int[])
> > var2(a int, b variadic anyarray)
> >
> > ... it would be okay to write var1(8), which resolves as var1(8,
> > array[]::int[]).  But if I tried to write var2(8) I'd get an error.
> > Maybe something like "cannot determine type of missing variadic
> > arguments".
>
> Well, we could unify these behaviors if we insisted on an explicit
> default to omit the argument in both cases.
>
>     var1(a int, b variadic int[] default '{}'::int[])
>     var2(a int, b variadic anyarray default '{}'::text[]) -- perhaps

I would just pass an empty array if the type is clear and error out otherwise.  
Mixing these things up makes things a lot more complicated for even normal 
uses.


Re: Variadic parameters vs parameter defaults

From
Peter Eisentraut
Date:
On Wednesday 17 December 2008 06:03:06 Tom Lane wrote:
> This method
> eliminates the discrepancy between anyarray and other types of variadic
> parameters, and it leaves the door open for someone to use something
> besides an empty array as the default.  (Who are we to say that such a
> thing is never useful?

I think it is a mistake to consider this a default value issue at all.  If you
pass zero arguments to a function, the function should get zero.

Or why would you pass <> N arguments when N are provided for any N?


Re: Variadic parameters vs parameter defaults

From
"Pavel Stehule"
Date:
2008/12/17 Peter Eisentraut <peter_e@gmx.net>:
> On Wednesday 17 December 2008 02:07:35 Tom Lane wrote:
>> Oh, and another thing --- should variadic parameters be defaultable?
>> The current patch doesn't allow it but it looks more like an oversight
>> than anything that was thought through.  The boundary case for variadic
>> parameters is a bit weird already:
>>
>> regression=# create function fv (f1 int, f2 variadic int[]) returns int
>> regression-# as 'select $1' language sql;
>> CREATE FUNCTION
>
>> regression=# select fv(1);
>> ERROR:  function fv(integer) does not exist
>> LINE 1: select fv(1);
>>                ^
>> HINT:  No function matches the given name and argument types. You might
>> need to add explicit type casts.
>
> That looks like a bug to me.  Anything that you can do with 1 to N items
> should also work for zero.
>

no, when we discused about variadic functions we defined, so variadic
parameter should not be empty Please, look to archive.

Pavel

> Also, in C, variadic functions are quite commonly called with zero arguments
> in the variadic position.
>
> --
> Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
> To make changes to your subscription:
> http://www.postgresql.org/mailpref/pgsql-hackers
>


Re: Variadic parameters vs parameter defaults

From
Tom Lane
Date:
"Pavel Stehule" <pavel.stehule@gmail.com> writes:
> 2008/12/17 Peter Eisentraut <peter_e@gmx.net>:
>> That looks like a bug to me.  Anything that you can do with 1 to N items
>> should also work for zero.

> no, when we discused about variadic functions we defined, so variadic
> parameter should not be empty Please, look to archive.

Yeah, the problem is to infer a datatype when there are no actual
arguments to look at.  If we wanted to drop "variadic anyarray" then
the corner case wouldn't be a problem, but that cure is worse than
the disease.
        regards, tom lane


Re: Variadic parameters vs parameter defaults

From
Jeff Davis
Date:
On Wed, 2008-12-17 at 19:43 +0200, Peter Eisentraut wrote:
> That looks like a bug to me.  Anything that you can do with 1 to N items 
> should also work for zero.
> 

Previous discussion link:

http://archives.postgresql.org/pgsql-patches/2008-07/msg00149.php

You can make either mechanism do what you want by defining the right set
of functions. If a minimum of one argument per variadic parameter is
required, you can work around it by defining an extra function with no
variadic parameter to handle the zero-argument case.

So, although I agree with you, I don't have a strong opinion, and I'm
happy with either.

Regards,Jeff Davis





Re: Variadic parameters vs parameter defaults

From
Jeff Davis
Date:
On Tue, 2008-12-16 at 19:07 -0500, Tom Lane wrote:
> regression=# select fv(1);
> ERROR:  function fv(integer) does not exist
> LINE 1: select fv(1);
>                ^
> HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
> 
> ISTM one could make a pretty good argument that this last case should
> succeed, producing an empty-array argument.

We had a similar discussion before, and you replied here:

http://archives.postgresql.org/pgsql-patches/2008-07/msg00150.php

Are you now in favor of allowing zero arguments for a variadic
parameter?

Regards,Jeff Davis



Re: Variadic parameters vs parameter defaults

From
Tom Lane
Date:
Jeff Davis <pgsql@j-davis.com> writes:
> Previous discussion link:
> http://archives.postgresql.org/pgsql-patches/2008-07/msg00149.php

> You can make either mechanism do what you want by defining the right set
> of functions. If a minimum of one argument per variadic parameter is
> required, you can work around it by defining an extra function with no
> variadic parameter to handle the zero-argument case.

I think the bottom line here is that we need to make it possible for the
user to define what happens in the corner case.  One of the problems
mentioned in the prior thread was that foo(variadic int[]) and
foo(variadic text[]) would conflict if it were possible to match both
to a zero-argument call.  There's no principled solution to that if the
system insists on defining the behavior for zero args.  However, with
the behavior I propose now, the user could determine which one is used
by giving a default to it and not the other one.  That is,
foo(variadic int[] = array[]::int[])foo(variadic text[])

causes the int[] one to get used for "foo()", and if you want the other
choice you hang the default on that one instead.
        regards, tom lane


Re: Variadic parameters vs parameter defaults

From
Peter Eisentraut
Date:
On Wednesday 17 December 2008 06:03:06 Tom Lane wrote:
> and it leaves the door open for someone to use something
> besides an empty array as the default.  (Who are we to say that such a
> thing is never useful?  NULL seems like a possibly useful default for
> instance.)

Another point against that: If you wanted something else besides an empty
array as "default", you can handle that inside the function body by just
looking at how many arguments were passed.  Using the default mechanism
provides no added functionality.


Re: Variadic parameters vs parameter defaults

From
Tom Lane
Date:
Jeff Davis <pgsql@j-davis.com> writes:
> On Tue, 2008-12-16 at 19:07 -0500, Tom Lane wrote:
>> ISTM one could make a pretty good argument that this last case should
>> succeed, producing an empty-array argument.

> We had a similar discussion before, and you replied here:
> http://archives.postgresql.org/pgsql-patches/2008-07/msg00150.php

> Are you now in favor of allowing zero arguments for a variadic
> parameter?

No, not as such (at least not now that I've had a chance to digest the
alternatives).  The default-parameter mechanism gives us another
solution tool, but if you don't use a default then the same ambiguities
as before still exist.
        regards, tom lane


Re: Variadic parameters vs parameter defaults

From
Tom Lane
Date:
Peter Eisentraut <peter_e@gmx.net> writes:
> Another point against that: If you wanted something else besides an empty 
> array as "default", you can handle that inside the function body by just 
> looking at how many arguments were passed.  Using the default mechanism 
> provides no added functionality.

Well, the entire default mechanism provides "no additional
functionality", since you can always emulate it with a nest of functions
(or a single function that is able to accept a varying argument list and
look at how many arguments were passed; which, please note, is not
allowed in any of the existing PLs).  What we're looking for here is a
convenient notational tradeoff.  The behavior at zero arguments is
certainly a judgment call, but it seems to me that we'll wind up with
more warts and less flexibility if we try to make the system install a
default behavior for that case.
        regards, tom lane


Re: Variadic parameters vs parameter defaults

From
Peter Eisentraut
Date:
On Wednesday 17 December 2008 20:50:22 Tom Lane wrote:
> The behavior at zero arguments is
> certainly a judgment call, but it seems to me that we'll wind up with
> more warts and less flexibility if we try to make the system install a
> default behavior for that case.

Maybe we'll just let it be for now and see what kind of user demands we get.


Re: Variadic parameters vs parameter defaults

From
Tom Lane
Date:
Peter Eisentraut <peter_e@gmx.net> writes:
> On Wednesday 17 December 2008 20:50:22 Tom Lane wrote:
>> The behavior at zero arguments is
>> certainly a judgment call, but it seems to me that we'll wind up with
>> more warts and less flexibility if we try to make the system install a
>> default behavior for that case.

> Maybe we'll just let it be for now and see what kind of user demands we get.

Fair enough.  We could possibly have the system install a "default
default" for variadic arguments, but I'd rather add that later
on the basis of demand than stick it in now.
        regards, tom lane


Re: Variadic parameters vs parameter defaults

From
Gregory Stark
Date:
Tom Lane <tgl@sss.pgh.pa.us> writes:

> Peter Eisentraut <peter_e@gmx.net> writes:
>> On Wednesday 17 December 2008 20:50:22 Tom Lane wrote:
>>> The behavior at zero arguments is
>>> certainly a judgment call, but it seems to me that we'll wind up with
>>> more warts and less flexibility if we try to make the system install a
>>> default behavior for that case.
>
>> Maybe we'll just let it be for now and see what kind of user demands we get.
>
> Fair enough.  We could possibly have the system install a "default
> default" for variadic arguments, but I'd rather add that later
> on the basis of demand than stick it in now.

My inclination would be to say zero arguments is zero arguments and you get a
zero-length array. We could eliminate the problem with anyelement by saying
the variadic argument can't be the only polymorphic argument.

I think there are going to be more users using non-polymorphic arguments who
are surprised that no arguments is a special case than people using
polymorphic arguments who are annoyed by restrictions at the intersection.

Actually I think my vote would be for whatever requires the least code now. If
you've already committed something then let's just go with that.

--  Gregory Stark EnterpriseDB          http://www.enterprisedb.com Ask me about EnterpriseDB's Slony Replication
support!


Re: Variadic parameters vs parameter defaults

From
"Pavel Stehule"
Date:
2008/12/17 Gregory Stark <stark@enterprisedb.com>:
> Tom Lane <tgl@sss.pgh.pa.us> writes:
>
>> Peter Eisentraut <peter_e@gmx.net> writes:
>>> On Wednesday 17 December 2008 20:50:22 Tom Lane wrote:
>>>> The behavior at zero arguments is
>>>> certainly a judgment call, but it seems to me that we'll wind up with
>>>> more warts and less flexibility if we try to make the system install a
>>>> default behavior for that case.
>>
>>> Maybe we'll just let it be for now and see what kind of user demands we get.
>>
>> Fair enough.  We could possibly have the system install a "default
>> default" for variadic arguments, but I'd rather add that later
>> on the basis of demand than stick it in now.
>
> My inclination would be to say zero arguments is zero arguments and you get a
> zero-length array. We could eliminate the problem with anyelement by saying
> the variadic argument can't be the only polymorphic argument.
>

I disagree. Polymorphism is strong feature and without it, you have to
repeat code. Or maybe divide this problem to two cases: zero typed
variadic arguments, and nnempty polymorphic variadic argument.

Regards
Pavel Stehule

> I think there are going to be more users using non-polymorphic arguments who
> are surprised that no arguments is a special case than people using
> polymorphic arguments who are annoyed by restrictions at the intersection.
>
> Actually I think my vote would be for whatever requires the least code now. If
> you've already committed something then let's just go with that.
>
> --
>  Gregory Stark
>  EnterpriseDB          http://www.enterprisedb.com
>  Ask me about EnterpriseDB's Slony Replication support!
>
> --
> Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
> To make changes to your subscription:
> http://www.postgresql.org/mailpref/pgsql-hackers
>


Re: Variadic parameters vs parameter defaults

From
Tom Lane
Date:
"Pavel Stehule" <pavel.stehule@gmail.com> writes:
> 2008/12/17 Gregory Stark <stark@enterprisedb.com>:
>> My inclination would be to say zero arguments is zero arguments and you get a
>> zero-length array. We could eliminate the problem with anyelement by saying
>> the variadic argument can't be the only polymorphic argument.

> I disagree. Polymorphism is strong feature and without it, you have to
> repeat code. Or maybe divide this problem to two cases: zero typed
> variadic arguments, and nnempty polymorphic variadic argument.

Yeah, I don't like putting extra restrictions on the polymorphic case
either.  Also, see my nearby note about how letting fewer defaults win
over more defaults might be unsafe.  Consider
foo (f1 int)foo (f1 int, f2 variadic int[])

If the system allows f2 to be defaulted to zero elements, then these two
functions would have to be considered ambiguous under the stricter rule.
This would make it *impossible* for the user to override the default
zero-argument behavior, even with the trick of using an additional
function.  Under the rules that I'm pushing, the above two declarations
are not ambiguous because you need at least two actual arguments to
match the second one.  They would be ambiguous if you explicitly
specified a default for f2, but there's no reason to do so if you want
this type of combination.
        regards, tom lane


Re: Variadic parameters vs parameter defaults

From
Peter Eisentraut
Date:
Tom Lane wrote:
> Yeah, I don't like putting extra restrictions on the polymorphic case
> either.  Also, see my nearby note about how letting fewer defaults win
> over more defaults might be unsafe.  Consider
> 
>     foo (f1 int)
>     foo (f1 int, f2 variadic int[])
> 
> If the system allows f2 to be defaulted to zero elements, then these two
> functions would have to be considered ambiguous under the stricter rule.
> This would make it *impossible* for the user to override the default
> zero-argument behavior, even with the trick of using an additional
> function.

Hmm, that use case might best be addressed by allowing the variadic 
argument to be omitted (or defaulted) if all previous arguments are 
omittable.