Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

delete function error with ternary operator #15771

Open
p5pRT opened this issue Dec 13, 2016 · 7 comments
Open

delete function error with ternary operator #15771

p5pRT opened this issue Dec 13, 2016 · 7 comments

Comments

@p5pRT
Copy link

p5pRT commented Dec 13, 2016

Migrated from rt.perl.org#130343 (status was 'open')

Searchable as RT130343$

@p5pRT
Copy link
Author

p5pRT commented Dec 13, 2016

From gomesbascoy@gmail.com

perldoc for the delete function indicates the following form​: delete EXPR
It also says that EXPR can be "arbitrarily complicated provided its final
operation is an element".

Here is an example of the issue I have found​:

my %a = (a=>123, b=>321); delete (1 ? $a{a} : $a{b}); # OK

my %a = (a=>123, b=>321); my $n = 1; delete ($n ? $a{a} : $a{b}); # FAIL

More specifically, the error message is​: "delete argument is not a HASH or
ARRAY element or slice"

Some folks on #perl @​freenode mentioned that my first example only works
because perl optimize the ternary operator, which makes sense, but I don't
think that this ambiguity is on purpose.

Thanks!

@p5pRT
Copy link
Author

p5pRT commented Dec 13, 2016

From @jkeenan

On Tue, 13 Dec 2016 21​:16​:52 GMT, gomesbascoy@​gmail.com wrote​:

perldoc for the delete function indicates the following form​: delete EXPR
It also says that EXPR can be "arbitrarily complicated provided its final
operation is an element".

Here is an example of the issue I have found​:

my %a = (a=>123, b=>321); delete (1 ? $a{a} : $a{b}); # OK

my %a = (a=>123, b=>321); my $n = 1; delete ($n ? $a{a} : $a{b}); # FAIL

More specifically, the error message is​: "delete argument is not a HASH or
ARRAY element or slice"

Confirmed.

Some folks on #perl @​freenode mentioned that my first example only works
because perl optimize the ternary operator, which makes sense, but I don't
think that this ambiguity is on purpose.

Agreed.

--
James E Keenan (jkeenan@​cpan.org)

@p5pRT
Copy link
Author

p5pRT commented Dec 13, 2016

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Dec 14, 2016

From zefram@fysh.org

Brian Gomes Bascoy wrote​:

It also says that EXPR can be "arbitrarily complicated provided its final
operation is an element".

That wording seems to have misled you. The arbitrary complexity
to which it refers lies in the subexpressions determining the hash
and key; for example, "delete ${$a->()}{$b->()}" is entirely legal.
It is not permitted to have any complexity in how the delete operand
resolves to a hash element operation, as is the case in your example.
What the documentation refers to as the "final operation" is really
the *topmost* construct within the operand expression, not merely the
last-executed operation. We could improve that.

my %a = (a=>123, b=>321); my $n = 1; delete ($n ? $a{a} : $a{b}); # FAIL

"delete $a{$n ? 'a' : 'b'}" would be legal.

Some folks on #perl @​freenode mentioned that my first example only works
because perl optimize the ternary operator,

Yes. The early constant folding of the conditional means that the
compilation of the delete op only sees the hash element operation as its
operand. It doesn't realise that it was syntactically a conditional.
This is arguably a bug, but also arguably not​: that kind of behaviour
can be deliberately invoked with respect to compile-time conditionals.

-zefram

@p5pRT
Copy link
Author

p5pRT commented Dec 15, 2016

From gomesbascoy@gmail.com

On Wed, 14 Dec 2016 15​:26​:48 -0800, zefram@​fysh.org wrote​:

Brian Gomes Bascoy wrote​:

It also says that EXPR can be "arbitrarily complicated provided its final
operation is an element".

That wording seems to have misled you. The arbitrary complexity
to which it refers lies in the subexpressions determining the hash
and key; for example, "delete ${$a->()}{$b->()}" is entirely legal.
It is not permitted to have any complexity in how the delete operand
resolves to a hash element operation, as is the case in your example.
What the documentation refers to as the "final operation" is really
the *topmost* construct within the operand expression, not merely the
last-executed operation. We could improve that.

my %a = (a=>123, b=>321); my $n = 1; delete ($n ? $a{a} : $a{b}); # FAIL

"delete $a{$n ? 'a' : 'b'}" would be legal.

Some folks on #perl @​freenode mentioned that my first example only works
because perl optimize the ternary operator,

Yes. The early constant folding of the conditional means that the
compilation of the delete op only sees the hash element operation as its
operand. It doesn't realise that it was syntactically a conditional.
This is arguably a bug, but also arguably not​: that kind of behaviour
can be deliberately invoked with respect to compile-time conditionals.

-zefram

I can totally see people using this kind of conditional compilation, probably with constants instead of plain numeric literals. At the same time I think that the optimization phase shouldn't change the semantics of the code being interpreted. Using compile-time conditionals as a sort of macro language is just a hack, not something that it's part of the Perl language itself but just a casual result of it's current implementation, or at least that's my point of view :)

Consider the following example​:
my %a = (a=>123, b=>321); delete (foo==9 ? $a{a} : $a{b}); # ?

That piece of code is ambiguous because foo was not defined. If foo is a numeric constant (e.g. "use constant foo => 9;") that code evaluates just fine. On the other hand, if foo is a subroutine that returns a number (e.g. "sub foo { 9 }") it fails because it requires run-time evaluation. IIRC constants are inlined subroutines so I can see how someone could go from a constant foo to a more complex subroutine foo.

I personally think that the delete syntax may be inherently inconsistent; in JavaScript, for instance, there is a similar delete operator that deletes a property from a given object, but the syntax is more restrictive because you really have to give obj.prop... if you try a ternary operator there the interpreter will reduce obj.prop to its value before it reaches delete (maybe because of its evaluation strategy, or by ECMAScript's specification, I don't know). In my opinion other scripting languages like Perl6, Lua or even Python have much better approaches. Maybe extending delete's syntax to something like "delete hash, key"? but it's too late for that.

Thanks

@p5pRT
Copy link
Author

p5pRT commented Dec 16, 2016

From @demerphq

On 15 December 2016 at 19​:57, Brian Gomes Bascoy via RT
<perlbug-followup@​perl.org> wrote​:

On Wed, 14 Dec 2016 15​:26​:48 -0800, zefram@​fysh.org wrote​:

Brian Gomes Bascoy wrote​:

It also says that EXPR can be "arbitrarily complicated provided its final
operation is an element".

That wording seems to have misled you. The arbitrary complexity
to which it refers lies in the subexpressions determining the hash
and key; for example, "delete ${$a->()}{$b->()}" is entirely legal.
It is not permitted to have any complexity in how the delete operand
resolves to a hash element operation, as is the case in your example.
What the documentation refers to as the "final operation" is really
the *topmost* construct within the operand expression, not merely the
last-executed operation. We could improve that.

my %a = (a=>123, b=>321); my $n = 1; delete ($n ? $a{a} : $a{b}); # FAIL

"delete $a{$n ? 'a' : 'b'}" would be legal.

Some folks on #perl @​freenode mentioned that my first example only works
because perl optimize the ternary operator,

Yes. The early constant folding of the conditional means that the
compilation of the delete op only sees the hash element operation as its
operand. It doesn't realise that it was syntactically a conditional.
This is arguably a bug, but also arguably not​: that kind of behaviour
can be deliberately invoked with respect to compile-time conditionals.

-zefram

I can totally see people using this kind of conditional compilation, probably with constants instead of plain numeric literals. At the same time I think that the optimization phase shouldn't change the semantics of the code being interpreted. Using compile-time conditionals as a sort of macro language is just a hack, not something that it's part of the Perl language itself but just a casual result of it's current implementation, or at least that's my point of view :)

Consider the following example​:
my %a = (a=>123, b=>321); delete (foo==9 ? $a{a} : $a{b}); # ?

That piece of code is ambiguous because foo was not defined. If foo is a numeric constant (e.g. "use constant foo => 9;") that code evaluates just fine. On the other hand, if foo is a subroutine that returns a number (e.g. "sub foo { 9 }") it fails because it requires run-time evaluation. IIRC constants are inlined subroutines so I can see how someone could go from a constant foo to a more complex subroutine foo.

FWIW, we used to have similar issues with ternaries and split,
although IIRC it was a bit different. But the basic point remains,
sometimes perl does things with expressions which don't work when the
argument is a ternary.

Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Dec 27, 2016

From @jkeenan

On Fri, 16 Dec 2016 07​:24​:43 GMT, demerphq wrote​:

On 15 December 2016 at 19​:57, Brian Gomes Bascoy via RT
<perlbug-followup@​perl.org> wrote​:

On Wed, 14 Dec 2016 15​:26​:48 -0800, zefram@​fysh.org wrote​:

Brian Gomes Bascoy wrote​:

It also says that EXPR can be "arbitrarily complicated provided
its final
operation is an element".

That wording seems to have misled you. The arbitrary complexity
to which it refers lies in the subexpressions determining the hash
and key; for example, "delete ${$a->()}{$b->()}" is entirely legal.
It is not permitted to have any complexity in how the delete operand
resolves to a hash element operation, as is the case in your
example.
What the documentation refers to as the "final operation" is really
the *topmost* construct within the operand expression, not merely
the
last-executed operation. We could improve that.

my %a = (a=>123, b=>321); my $n = 1; delete ($n ? $a{a} : $a{b});
# FAIL

"delete $a{$n ? 'a' : 'b'}" would be legal.

Some folks on #perl @​freenode mentioned that my first example only
works
because perl optimize the ternary operator,

Yes. The early constant folding of the conditional means that the
compilation of the delete op only sees the hash element operation as
its
operand. It doesn't realise that it was syntactically a
conditional.
This is arguably a bug, but also arguably not​: that kind of
behaviour
can be deliberately invoked with respect to compile-time
conditionals.

-zefram

I can totally see people using this kind of conditional compilation,
probably with constants instead of plain numeric literals. At the
same time I think that the optimization phase shouldn't change the
semantics of the code being interpreted. Using compile-time
conditionals as a sort of macro language is just a hack, not
something that it's part of the Perl language itself but just a
casual result of it's current implementation, or at least that's my
point of view :)

Consider the following example​:
my %a = (a=>123, b=>321); delete (foo==9 ? $a{a} : $a{b}); # ?

That piece of code is ambiguous because foo was not defined. If foo
is a numeric constant (e.g. "use constant foo => 9;") that code
evaluates just fine. On the other hand, if foo is a subroutine that
returns a number (e.g. "sub foo { 9 }") it fails because it requires
run-time evaluation. IIRC constants are inlined subroutines so I can
see how someone could go from a constant foo to a more complex
subroutine foo.

FWIW, we used to have similar issues with ternaries and split,
although IIRC it was a bit different. But the basic point remains,
sometimes perl does things with expressions which don't work when the
argument is a ternary.

Yves

Is this a problem about which, in the short run, we should write some cautionary documentation?

--
James E Keenan (jkeenan@​cpan.org)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants