Thread: Variadic parameters vs parameter defaults
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
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!
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
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
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
"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
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
"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
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.
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.
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?
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 >
"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
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
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
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
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.
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
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
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.
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
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!
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 >
"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
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.