Variadic parameters vs parameter defaults

Started by Tom Laneabout 17 years ago25 messages
#1Tom Lane
tgl@sss.pgh.pa.us

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

#2Gregory Stark
stark@enterprisedb.com
In reply to: Tom Lane (#1)
Re: Variadic parameters vs parameter defaults

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!

#3Josh Berkus
josh@agliodbs.com
In reply to: Tom Lane (#1)
Re: Variadic parameters vs parameter defaults

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

#4Tom Lane
tgl@sss.pgh.pa.us
In reply to: Gregory Stark (#2)
Re: Variadic parameters vs parameter defaults

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

#5Brendan Jurd
direvus@gmail.com
In reply to: Tom Lane (#1)
Re: Variadic parameters vs parameter defaults

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

#6Tom Lane
tgl@sss.pgh.pa.us
In reply to: Brendan Jurd (#5)
Re: Variadic parameters vs parameter defaults

"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

#7Brendan Jurd
direvus@gmail.com
In reply to: Tom Lane (#6)
Re: Variadic parameters vs parameter defaults

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

#8Tom Lane
tgl@sss.pgh.pa.us
In reply to: Brendan Jurd (#7)
Re: Variadic parameters vs parameter defaults

"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

#9Peter Eisentraut
peter_e@gmx.net
In reply to: Tom Lane (#1)
Re: Variadic parameters vs parameter defaults

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.

#10Peter Eisentraut
peter_e@gmx.net
In reply to: Tom Lane (#8)
Re: Variadic parameters vs parameter defaults

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.

#11Peter Eisentraut
peter_e@gmx.net
In reply to: Tom Lane (#8)
Re: Variadic parameters vs parameter defaults

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?

#12Pavel Stehule
pavel.stehule@gmail.com
In reply to: Peter Eisentraut (#9)
Re: Variadic parameters vs parameter defaults

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

Show quoted text

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

#13Tom Lane
tgl@sss.pgh.pa.us
In reply to: Pavel Stehule (#12)
Re: Variadic parameters vs parameter defaults

"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

#14Jeff Davis
pgsql@j-davis.com
In reply to: Peter Eisentraut (#9)
Re: Variadic parameters vs parameter defaults

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

#15Jeff Davis
pgsql@j-davis.com
In reply to: Tom Lane (#1)
Re: Variadic parameters vs parameter defaults

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

#16Tom Lane
tgl@sss.pgh.pa.us
In reply to: Jeff Davis (#14)
Re: Variadic parameters vs parameter defaults

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

#17Peter Eisentraut
peter_e@gmx.net
In reply to: Tom Lane (#8)
Re: Variadic parameters vs parameter defaults

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.

#18Tom Lane
tgl@sss.pgh.pa.us
In reply to: Jeff Davis (#15)
Re: Variadic parameters vs parameter defaults

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

#19Tom Lane
tgl@sss.pgh.pa.us
In reply to: Peter Eisentraut (#17)
Re: Variadic parameters vs parameter defaults

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

#20Peter Eisentraut
peter_e@gmx.net
In reply to: Tom Lane (#19)
Re: Variadic parameters vs parameter defaults

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.

#21Tom Lane
tgl@sss.pgh.pa.us
In reply to: Peter Eisentraut (#20)
Re: Variadic parameters vs parameter defaults

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

#22Gregory Stark
stark@enterprisedb.com
In reply to: Tom Lane (#21)
Re: Variadic parameters vs parameter defaults

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!

#23Pavel Stehule
pavel.stehule@gmail.com
In reply to: Gregory Stark (#22)
Re: Variadic parameters vs parameter defaults

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

Show quoted text

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

#24Tom Lane
tgl@sss.pgh.pa.us
In reply to: Pavel Stehule (#23)
Re: Variadic parameters vs parameter defaults

"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

#25Peter Eisentraut
peter_e@gmx.net
In reply to: Tom Lane (#24)
Re: Variadic parameters vs parameter defaults

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.