Subject: Re: Why don't we support external input/output functions for the composite types

From: Robert Haas <[email-masked]>
Date: Fri, 26 Apr 2024 12:19:07 -0400

On Fri, Apr 26, 2024 at 11:55 AM Tom Lane <[email-masked]> wrote:
> Well, that would be one way of making the consistency problem be not
> our problem, but it would be a sad restriction.  It'd void a lot of
> the arguable use-case for this feature, if you ask me.  I realize
> that non-superusers couldn't create the C-language I/O functions that
> would be most at risk here, but you could imagine people building
> I/O functions in some other PL.

Huh, I hadn't considered that. I figured the performance would be too
bad to even think about it. I also wasn't even sure such a thing would
be supportable: I thought cstrings were generally limited to
C/internal functions.

> >> I take it that you also don't believe that "2 + 3 * 4" should yield
> >> different results from "(2 + 3) * 4"?
>
> > Isaac's rebuttal to this particular point was perfect; I have nothing to add.
>
> As far as I could tell, Isaac's rebuttal was completely off-point.

OK, I'm not sure why, but let me explain my position. In an expression
like (2 + 3) * 4, the parentheses change the order of evaluation,
which makes sense. That's what parentheses are for, or at least one
thing that parentheses are for. But in an expression like
(my_point).x, that's not the case. There's only one operator here, the
period, and so there's only one possible order of evaluation, so why
do parentheses make any difference? Having (my_point).x be different
from my_point.x is like having 2 + 3 give a different answer from (2 +
3), which would be bonkers.

But it's not at all like the difference between 2 + 3 * 4 and (2 + 3)
* 4. The comparable case there would be foo.bar.baz as against
(foo.bar).baz or alternatively foo.(bar.baz). Now there are two dot
operators, and one of them has to be applied first, and there's some
default based on associativity, and if you want it the other way you
stick parentheses in there to tell the parser what you meant.

And the reason I thought Isaac put it well is that he said, "In that
expression 2 + 3 is not a subexpression, although 3 * 4 is, thanks to
the operator precedence rules." Exactly so. 2 + 3 * 4 is going to be
parsed as something like OpExpr(+, 2, OpExpr(*, 3, 4)) -- and that
does not have OpExpr(+, 2, 3) anywhere inside of it, so my comment
that parenthesizing a subexpression shouldn't change its meaning is
not relevant here. I'm perfectly fine with parentheses changing which
things we parse as subexpressions. Users have no license to just stick
parentheses into your SQL expressions in random places and expect that
they don't do anything; if that were so, we'd have to make ((2 +)
3)()()() evaluate to 5, which is obviously nonsense. Rather, what I
don't like about the status quo is that putting parentheses around
something that we were already going to consider as a unit changes the
meaning of it. And that's exactly what happens when you write x.y vs.
(x).y. The parentheses around the x make us think that it's a
different kind of thing, somehow. That seems odd, and the practical
result is that you have to insert a bunch of parentheses into your
PostgreSQL code that look like they shouldn't be needed, but are.

-- 
Robert Haas
EDB: http://www.enterprisedb.com