Calling PL functions with named parameters

Started by David Fetterover 21 years ago31 messageshackers
Jump to latest
#1David Fetter
david@fetter.org

Kind people,

I've brought this up before, and with Dennis Bj��rklund's help, would
like to bring it up again. Here's the idea:

I'd like to be able to create functions with named parameters that
could be called with the names in any order. For example,

CREATE OR REPLACE FUNCTION foo_func(name TEXT, val INTEGER) AS ...

SELECT foo_func(val AS 23, name AS 'Name goes here');

and have it Do The Right Thing.

Dennis has pointed out that mixing the call-with-named-parameter
interface with call-by-order-of-parameters one would cause confusion,
and I think it would be OK to disallow this type mixing, so

SELECT foo_func(name AS 'yet another name', 35);

would be disallowed.

A calling convention that names parameters makes it a lot easier to
track just exactly what parameter is set to which value, and lets
people not have to memorize what order those named parameters appear
in. On a related note, it would also be nice to have default
parameters and some way to say to use them.

Well, that's my thoughts so far. What are yours?

Cheers,
D
--
David Fetter david@fetter.org http://fetter.org/
phone: +1 510 893 6100 mobile: +1 415 235 3778

Remember to vote!

#2Oliver Jowett
oliver@opencloud.com
In reply to: David Fetter (#1)
Re: Calling PL functions with named parameters

David Fetter wrote:

Dennis has pointed out that mixing the call-with-named-parameter
interface with call-by-order-of-parameters one would cause confusion,
and I think it would be OK to disallow this type mixing, so

SELECT foo_func(name AS 'yet another name', 35);

would be disallowed.

Python's equivalent syntax allows you to mix the two forms so long as
all the by-position parameters come first:

def f(a,b,c,d):

... print a,b,c,d
...

f(1,2,3,4)

1 2 3 4

f(1,2,c=3,d=4)

1 2 3 4

f(1,2,d=4,c=3)

1 2 3 4

f(1,d=4,2,c=3)

SyntaxError: non-keyword arg after keyword arg

-O

#3Tom Lane
tgl@sss.pgh.pa.us
In reply to: David Fetter (#1)
Re: Calling PL functions with named parameters

David Fetter <david@fetter.org> writes:

CREATE OR REPLACE FUNCTION foo_func(name TEXT, val INTEGER) AS ...

SELECT foo_func(val AS 23, name AS 'Name goes here');

I don't think that syntax will work. You could possibly do it the other
way round:

SELECT foo_func(23 AS val, 'Name goes here' AS name);

which would have some commonality with SELECT's column-labeling syntax
but otherwise seems to have little to recommend it. Are there any other
vendors supporting such things in SQL, and if so how do they do it?

A bigger issue is how do you see this interacting with resolution of
ambiguous/overloaded function names.

On a related note, it would also be nice to have default
parameters and some way to say to use them.

That is fundamentally not ever going to happen, because it blows
overloaded-function resolution out of the water: there is no way to
choose whether "foo(42, 2.5)" matches foo(int, float) or
foo(int, float, something-with-a-default). Let's try to limit our
attention to something that might actually work.

regards, tom lane

#4Jim Nasby
Jim.Nasby@BlueTreble.com
In reply to: David Fetter (#1)
Re: Calling PL functions with named parameters

I would personally find this useful, but I would suggest using Oracle's
syntax of SELECT func(a=>2, b=>'b', ...);

Having said that, having the concept of DEFAULT for parameters wolud be
even more useful, ie:

CREATE FUNCTION blah (
a int
, b int DEFAULT 0
);

SELECT blah(1,0);
and
SELECT blah(1);
would do the same thing. (Yes, I know there's a work-around, but it's a
bit of a pain if you've got 10 parameters that could be omitted).

On Fri, Aug 13, 2004 at 02:41:48PM -0700, David Fetter wrote:

Kind people,

I've brought this up before, and with Dennis Bj��rklund's help, would
like to bring it up again. Here's the idea:

I'd like to be able to create functions with named parameters that
could be called with the names in any order. For example,

CREATE OR REPLACE FUNCTION foo_func(name TEXT, val INTEGER) AS ...

SELECT foo_func(val AS 23, name AS 'Name goes here');

and have it Do The Right Thing.

Dennis has pointed out that mixing the call-with-named-parameter
interface with call-by-order-of-parameters one would cause confusion,
and I think it would be OK to disallow this type mixing, so

SELECT foo_func(name AS 'yet another name', 35);

would be disallowed.

A calling convention that names parameters makes it a lot easier to
track just exactly what parameter is set to which value, and lets
people not have to memorize what order those named parameters appear
in. On a related note, it would also be nice to have default
parameters and some way to say to use them.

Well, that's my thoughts so far. What are yours?

Cheers,
D
--
David Fetter david@fetter.org http://fetter.org/
phone: +1 510 893 6100 mobile: +1 415 235 3778

Remember to vote!

---------------------------(end of broadcast)---------------------------
TIP 8: explain analyze is your friend

--
Jim C. Nasby, Database Consultant decibel@decibel.org
Give your computer some brain candy! www.distributed.net Team #1828

Windows: "Where do you want to go today?"
Linux: "Where do you want to go tomorrow?"
FreeBSD: "Are you guys coming, or what?"

#5Jim Nasby
Jim.Nasby@BlueTreble.com
In reply to: Tom Lane (#3)
Re: Calling PL functions with named parameters

On Fri, Aug 13, 2004 at 06:22:25PM -0400, Tom Lane wrote:

On a related note, it would also be nice to have default
parameters and some way to say to use them.

That is fundamentally not ever going to happen, because it blows
overloaded-function resolution out of the water: there is no way to
choose whether "foo(42, 2.5)" matches foo(int, float) or
foo(int, float, something-with-a-default). Let's try to limit our
attention to something that might actually work.

Actually, it is possible because Oracle does it. Presumably they treat a
function with defaults as being the equivalent number of overloaded
functions when functions are created, to ensure it can always resolve
what function to call.

IOW, their function resolution code treats a(int, int default 0) as
being equivalent to a(int) and a(int, int).
--
Jim C. Nasby, Database Consultant decibel@decibel.org
Give your computer some brain candy! www.distributed.net Team #1828

Windows: "Where do you want to go today?"
Linux: "Where do you want to go tomorrow?"
FreeBSD: "Are you guys coming, or what?"

#6Gaetano Mendola
mendola@bigfoot.com
In reply to: Oliver Jowett (#2)
Re: Calling PL functions with named parameters

Oliver Jowett wrote:

David Fetter wrote:

Dennis has pointed out that mixing the call-with-named-parameter
interface with call-by-order-of-parameters one would cause confusion,
and I think it would be OK to disallow this type mixing, so

SELECT foo_func(name AS 'yet another name', 35);

would be disallowed.

Python's equivalent syntax allows you to mix the two forms so long as
all the by-position parameters come first:

def f(a,b,c,d):

... print a,b,c,d
...

f(1,2,3,4)

1 2 3 4

f(1,2,c=3,d=4)

1 2 3 4

f(1,2,d=4,c=3)

1 2 3 4

f(1,d=4,2,c=3)

SyntaxError: non-keyword arg after keyword arg

python don't have overloaded function...

Regards
Gaetano Mendola

#7Tom Lane
tgl@sss.pgh.pa.us
In reply to: Jim Nasby (#5)
Re: Calling PL functions with named parameters

"Jim C. Nasby" <decibel@decibel.org> writes:

IOW, their function resolution code treats a(int, int default 0) as
being equivalent to a(int) and a(int, int).

So you are willing to prohibit a(int) from existing in parallel with
a(int, int-with-a-default) ?

I'll be interested to see the unique-index scheme for pg_proc to enforce
that ;-)

However this does point up the fact that there already *is* a way to
accomplish the task, which is just to create some helper function(s) to
supply the default(s). Perhaps we can leave it at that for the time
being, and concentrate on adding real new functionality.

regards, tom lane

#8Oliver Jowett
oliver@opencloud.com
In reply to: Tom Lane (#3)
Re: Calling PL functions with named parameters

Tom Lane wrote:

On a related note, it would also be nice to have default
parameters and some way to say to use them.

That is fundamentally not ever going to happen, because it blows
overloaded-function resolution out of the water: there is no way to
choose whether "foo(42, 2.5)" matches foo(int, float) or
foo(int, float, something-with-a-default). Let's try to limit our
attention to something that might actually work.

C++ manages to solve this problem, although I can't remember the exact
mechanics (and C++ is usually not a good example to follow anyway ;)

How about just disallowing function signatures that cause ambiguity?
i.e. make f(t1,t2,default t3,default t4,..) lay claim to f(t1,t2),
f(t1,t2,t3), f(t1,t2,t3,t4) etc, and creation fails if any of those
signatures are already claimed by another function.

-O

#9Oliver Jowett
oliver@opencloud.com
In reply to: David Fetter (#1)
Re: Calling PL functions with named parameters

Gaetano Mendola wrote:

Oliver Jowett wrote:

David Fetter wrote:

Dennis has pointed out that mixing the call-with-named-parameter
interface with call-by-order-of-parameters one would cause confusion,

Python's equivalent syntax allows you to mix the two forms so long as
all the by-position parameters come first:

python don't have overloaded functions...

It doesn't change how you'd handle overloaded functions; you still have
a type for every parameter available.

-O

#10Robert Treat
xzilla@users.sourceforge.net
In reply to: Jim Nasby (#4)
Re: Calling PL functions with named parameters

Would it be any better to allow

SELECT blah(1,DEFAULT);

?

Robert Treat

On Friday 13 August 2004 18:49, Jim C. Nasby wrote:

I would personally find this useful, but I would suggest using Oracle's
syntax of SELECT func(a=>2, b=>'b', ...);

Having said that, having the concept of DEFAULT for parameters wolud be
even more useful, ie:

CREATE FUNCTION blah (
a int
, b int DEFAULT 0
);

SELECT blah(1,0);
and
SELECT blah(1);
would do the same thing. (Yes, I know there's a work-around, but it's a
bit of a pain if you've got 10 parameters that could be omitted).

On Fri, Aug 13, 2004 at 02:41:48PM -0700, David Fetter wrote:

Kind people,

I've brought this up before, and with Dennis Bjőrklund's help, would
like to bring it up again. Here's the idea:

I'd like to be able to create functions with named parameters that
could be called with the names in any order. For example,

CREATE OR REPLACE FUNCTION foo_func(name TEXT, val INTEGER) AS ...

SELECT foo_func(val AS 23, name AS 'Name goes here');

and have it Do The Right Thing.

Dennis has pointed out that mixing the call-with-named-parameter
interface with call-by-order-of-parameters one would cause confusion,
and I think it would be OK to disallow this type mixing, so

SELECT foo_func(name AS 'yet another name', 35);

would be disallowed.

A calling convention that names parameters makes it a lot easier to
track just exactly what parameter is set to which value, and lets
people not have to memorize what order those named parameters appear
in. On a related note, it would also be nice to have default
parameters and some way to say to use them.

Well, that's my thoughts so far. What are yours?

Cheers,
D
--
David Fetter david@fetter.org http://fetter.org/
phone: +1 510 893 6100 mobile: +1 415 235 3778

Remember to vote!

---------------------------(end of broadcast)---------------------------
TIP 8: explain analyze is your friend

--
Robert Treat
Build A Better Lamp :: Linux Apache {middleware} PostgreSQL

#11Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert Treat (#10)
Re: Calling PL functions with named parameters

Robert Treat <xzilla@users.sourceforge.net> writes:

Would it be any better to allow
SELECT blah(1,DEFAULT);

Not a lot. If there is more than one 2-parameter blah(), how do you
pick? The DEFAULT gives you no clue at all about the type of the
second parameter...

I think if we wanted to do something like this, the right way would be
that "create function foo(f1 text, f2 int default 42)" implicitly
creates a second function "foo(f1 text)", and we make no change to the
matching rules. But managing this seems mighty messy --- for instance,
we don't presently have any concept of hidden or second-class-citizen
entries in pg_proc, but we'd have to create one to keep the implicitly
created functions out of your face in pg_dump, psql \df, etc. And
again, it's not really giving you anything you can't have today.

regards, tom lane

#12Gaetano Mendola
mendola@bigfoot.com
In reply to: Oliver Jowett (#8)
Re: Calling PL functions with named parameters

Oliver Jowett wrote:

Tom Lane wrote:

On a related note, it would also be nice to have default
parameters and some way to say to use them.

That is fundamentally not ever going to happen, because it blows
overloaded-function resolution out of the water: there is no way to
choose whether "foo(42, 2.5)" matches foo(int, float) or
foo(int, float, something-with-a-default). Let's try to limit our
attention to something that might actually work.

C++ manages to solve this problem, although I can't remember the exact
mechanics (and C++ is usually not a good example to follow anyway ;)

Your're wrong:

try to compile this:

void foo( int a, float b ) { }
void foo( int a, float b, int c=0 ) { }

int main(char argc, char **argv)
{
foo( 42, 2.5 );

return 0;
}

you'll get:

a.cpp:6: error: call of overloaded `foo(int, double)' is ambiguous
a.cpp:1: error: candidates are: void foo(int, float)
a.cpp:2: error: void foo(int, float, int)

usualy C++ is not a good example as SQL is not :-)

Regards
Gaetano Mendola

#13Gaetano Mendola
mendola@bigfoot.com
In reply to: Oliver Jowett (#9)
Re: Calling PL functions with named parameters

Oliver Jowett wrote:

Gaetano Mendola wrote:

Oliver Jowett wrote:

David Fetter wrote:

Dennis has pointed out that mixing the call-with-named-parameter
interface with call-by-order-of-parameters one would cause confusion,

Python's equivalent syntax allows you to mix the two forms so long as
all the by-position parameters come first:

python don't have overloaded functions...

It doesn't change how you'd handle overloaded functions; you still have
a type for every parameter available.

I think will be a mess that will break the "minor surprise" principle,
even the bad C++ stays away from this field ( se explicit constructors,
and automatic cast limited to only one level ).

I know I know the Koenig Lookup is there as a Damocle's sword...

Regards
Gaetano Mendola

#14Peter Eisentraut
peter_e@gmx.net
In reply to: David Fetter (#1)
Re: Calling PL functions with named parameters

David Fetter wrote:

I'd like to be able to create functions with named parameters that
could be called with the names in any order. For example,

CREATE OR REPLACE FUNCTION foo_func(name TEXT, val INTEGER) AS ...

SELECT foo_func(val AS 23, name AS 'Name goes here');

When that was brought up last time, I think the hard part was what
syntax to use. You can't use AS because SQL uses that for something
different. => might be OK, but then we'd need to disallow that as
operator name.

--
Peter Eisentraut
http://developer.postgresql.org/~petere/

#15Oliver Jowett
oliver@opencloud.com
In reply to: Gaetano Mendola (#12)
Re: Calling PL functions with named parameters

Gaetano Mendola wrote:

C++ manages to solve this problem, although I can't remember the exact
mechanics (and C++ is usually not a good example to follow anyway ;)

Your're wrong:

try to compile this: [...]

a.cpp:6: error: call of overloaded `foo(int, double)' is ambiguous
a.cpp:1: error: candidates are: void foo(int, float)
a.cpp:2: error: void foo(int, float, int)

usualy C++ is not a good example as SQL is not :-)

I think you just made my point for me. C++ allows default parameters and
resolves the ambiguity by disallowing ambiguous calls when they happen.

I'm not sure why C++ doesn't disallow it at declaration time off the top
of my head -- perhaps because you'd get inconsistent behaviour if the
candidates were split across compilation units. Since we don't have that
problem in the SQL function case, we can disallow ambiguity at the time
of creating the function.

-O

#16Oliver Jowett
oliver@opencloud.com
In reply to: Gaetano Mendola (#13)
Re: Calling PL functions with named parameters

Gaetano Mendola wrote:

Oliver Jowett wrote:

Gaetano Mendola wrote:

Oliver Jowett wrote:

David Fetter wrote:

Dennis has pointed out that mixing the call-with-named-parameter
interface with call-by-order-of-parameters one would cause confusion,

Python's equivalent syntax allows you to mix the two forms so long
as all the by-position parameters come first:

python don't have overloaded functions...

It doesn't change how you'd handle overloaded functions; you still
have a type for every parameter available.

I think will be a mess that will break the "minor surprise" principle,
even the bad C++ stays away from this field ( se explicit constructors,
and automatic cast limited to only one level ).

I don't understand your argument. What is the surprising behaviour you
are worried about?

-O

#17Harald Fuchs
hf0722x@protecting.net
In reply to: David Fetter (#1)
Re: Calling PL functions with named parameters

In article <411DFBE1.7060007@opencloud.com>,
Oliver Jowett <oliver@opencloud.com> writes:

I think you just made my point for me. C++ allows default parameters
and resolves the ambiguity by disallowing ambiguous calls when they
happen.

I'm not sure why C++ doesn't disallow it at declaration time off the
top of my head -- perhaps because you'd get inconsistent behaviour if
the candidates were split across compilation units.

IIRC this was due to multiple unheritance. You could inherit methods
with the same name and parameter list from two different base classes.
Disallowing that at declaration time would mean disallowing
inheritance (even indirectly) from these two base classes, even though
the derived class didn't use the ambiguous methods.

#18Gaetano Mendola
mendola@bigfoot.com
In reply to: Oliver Jowett (#16)
Re: Calling PL functions with named parameters

Oliver Jowett wrote:

Gaetano Mendola wrote:

Oliver Jowett wrote:

Gaetano Mendola wrote:

Oliver Jowett wrote:

David Fetter wrote:

Dennis has pointed out that mixing the call-with-named-parameter
interface with call-by-order-of-parameters one would cause confusion,

Python's equivalent syntax allows you to mix the two forms so long
as all the by-position parameters come first:

python don't have overloaded functions...

It doesn't change how you'd handle overloaded functions; you still
have a type for every parameter available.

I think will be a mess that will break the "minor surprise" principle,
even the bad C++ stays away from this field ( se explicit constructors,
and automatic cast limited to only one level ).

I don't understand your argument. What is the surprising behaviour you
are worried about?

I'm worried about:

(1) foo( integer, float);
(2) foo( integer, integer, float a = 3 );

which one is called with: foo( 2, 2 )?

the first one because have two parameters or the second one
that better match the arguments ?

Whatever policy we adopt someone could argue that the (2) have
a signature with 3 parameters so the (1) shall be called, and
someone can argue that (2) is equivalent to:

(2a) foo(integer, integer)
(2b) foo(integer, integer, float);

so the (2) have to be called.

BTW C++ adopt the latter.

Regards
Gaetano Mendola

#19Oliver Jowett
oliver@opencloud.com
In reply to: Gaetano Mendola (#18)
Re: Calling PL functions with named parameters

Gaetano Mendola wrote:

Oliver Jowett wrote:

David Fetter wrote:

Dennis has pointed out that mixing the call-with-named-parameter
interface with call-by-order-of-parameters one would cause

confusion,

Python's equivalent syntax allows you to mix the two forms so long
as all the by-position parameters come first:

I'm worried about:

(1) foo( integer, float);
(2) foo( integer, integer, float a = 3 );

which one is called with: foo( 2, 2 )?

This is a separate issue to the one I was discussing above. I am not
talking about default arguments at all here; I am talking about mixing
positional parameter syntax with named parameter syntax.

-O

#20Gaetano Mendola
mendola@bigfoot.com
In reply to: Harald Fuchs (#17)
Re: Calling PL functions with named parameters

Harald Fuchs wrote:

In article <411DFBE1.7060007@opencloud.com>,
Oliver Jowett <oliver@opencloud.com> writes:

I think you just made my point for me. C++ allows default parameters
and resolves the ambiguity by disallowing ambiguous calls when they
happen.

I'm not sure why C++ doesn't disallow it at declaration time off the
top of my head -- perhaps because you'd get inconsistent behaviour if
the candidates were split across compilation units.

IIRC this was due to multiple unheritance. You could inherit methods
with the same name and parameter list from two different base classes.
Disallowing that at declaration time would mean disallowing
inheritance (even indirectly) from these two base classes, even though
the derived class didn't use the ambiguous methods.

You get the point, and with a linear hierarchy the last function hide
the previous one:

struct A { void foo(int) { } };

struct B : A { void foo(int, int a = 3) { } };

B b;
b.foo(3);

will call the B::foo.

Regards
Gaetano Mendola

#21Gaetano Mendola
mendola@bigfoot.com
In reply to: Oliver Jowett (#19)
#22Andreas Pflug
pgadmin@pse-consulting.de
In reply to: Tom Lane (#3)
#23Josh Berkus
josh@agliodbs.com
In reply to: Andreas Pflug (#22)
#24Peter Eisentraut
peter_e@gmx.net
In reply to: Josh Berkus (#23)
#25Andrew Dunstan
andrew@dunslane.net
In reply to: Peter Eisentraut (#24)
#26Tom Lane
tgl@sss.pgh.pa.us
In reply to: Peter Eisentraut (#24)
#27David Fetter
david@fetter.org
In reply to: Tom Lane (#7)
#28Tom Lane
tgl@sss.pgh.pa.us
In reply to: David Fetter (#27)
#29Josh Berkus
josh@agliodbs.com
In reply to: Tom Lane (#26)
#30Tom Lane
tgl@sss.pgh.pa.us
In reply to: Josh Berkus (#29)
#31Josh Berkus
josh@agliodbs.com
In reply to: Tom Lane (#30)