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

inward goto deprecation has no removal date #16275

Closed
p5pRT opened this issue Nov 23, 2017 · 20 comments · Fixed by #21601
Closed

inward goto deprecation has no removal date #16275

p5pRT opened this issue Nov 23, 2017 · 20 comments · Fixed by #21601

Comments

@p5pRT
Copy link

p5pRT commented Nov 23, 2017

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

Searchable as RT132492$

@p5pRT
Copy link
Author

p5pRT commented Nov 23, 2017

From zefram@fysh.org

Created by zefram@fysh.org

Jumping into a block with goto is rightly deprecated​:

$ perl -lwe 'goto FOO; while(rand(1) > 2) { FOO​: print 22; }'
Use of "goto" to jump into a construct is deprecated at -e line 1.
22

But that warning message is missing a bit​: when will this deprecated
feature be removed? perldeprecation.pod also doesn't list this
deprecation.

Perl Info

Flags:
    category=core
    severity=low

Site configuration information for perl 5.27.6:

Configured by zefram at Tue Nov 21 05:42:59 GMT 2017.

Summary of my perl5 (revision 5 version 27 subversion 6) configuration:
   
  Platform:
    osname=linux
    osvers=3.16.0-4-amd64
    archname=x86_64-linux-thread-multi
    uname='linux barba.rous.org 3.16.0-4-amd64 #1 smp debian 3.16.43-2+deb8u2 (2017-06-26) x86_64 gnulinux '
    config_args='-des -Dprefix=/home/zefram/usr/perl/perl_install/perl-5.27.6-i64-f52 -Duselargefiles -Dusethreads -Uafs -Ud_csh -Uusesfio -Uusenm -Duseshrplib -Dusedevel -Uversiononly -Ui_db'
    hint=recommended
    useposix=true
    d_sigaction=define
    useithreads=define
    usemultiplicity=define
    use64bitint=define
    use64bitall=define
    uselongdouble=undef
    usemymalloc=n
    default_inc_excludes_dot=define
    bincompat5005=undef
  Compiler:
    cc='cc'
    ccflags ='-D_REENTRANT -D_GNU_SOURCE -fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_FORTIFY_SOURCE=2'
    optimize='-O2'
    cppflags='-D_REENTRANT -D_GNU_SOURCE -fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include'
    ccversion=''
    gccversion='4.9.2'
    gccosandvers=''
    intsize=4
    longsize=8
    ptrsize=8
    doublesize=8
    byteorder=12345678
    doublekind=3
    d_longlong=define
    longlongsize=8
    d_longdbl=define
    longdblsize=16
    longdblkind=3
    ivtype='long'
    ivsize=8
    nvtype='double'
    nvsize=8
    Off_t='off_t'
    lseeksize=8
    alignbytes=8
    prototype=define
  Linker and Libraries:
    ld='cc'
    ldflags =' -fstack-protector-strong -L/usr/local/lib'
    libpth=/usr/local/lib /usr/lib/gcc/x86_64-linux-gnu/4.9/include-fixed /usr/include/x86_64-linux-gnu /usr/lib /lib/x86_64-linux-gnu /lib/../lib /usr/lib/x86_64-linux-gnu /usr/lib/../lib /lib
    libs=-lpthread -lnsl -ldb -ldl -lm -lcrypt -lutil -lc
    perllibs=-lpthread -lnsl -ldl -lm -lcrypt -lutil -lc
    libc=libc-2.19.so
    so=so
    useshrplib=true
    libperl=libperl.so
    gnulibc_version='2.19'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs
    dlext=so
    d_dlsymun=undef
    ccdlflags='-Wl,-E -Wl,-rpath,/home/zefram/usr/perl/perl_install/perl-5.27.6-i64-f52/lib/5.27.6/x86_64-linux-thread-multi/CORE'
    cccdlflags='-fPIC'
    lddlflags='-shared -O2 -L/usr/local/lib -fstack-protector-strong'



@INC for perl 5.27.6:
    /home/zefram/usr/perl/perl_install/perl-5.27.6-i64-f52/lib/site_perl/5.27.6/x86_64-linux-thread-multi
    /home/zefram/usr/perl/perl_install/perl-5.27.6-i64-f52/lib/site_perl/5.27.6
    /home/zefram/usr/perl/perl_install/perl-5.27.6-i64-f52/lib/5.27.6/x86_64-linux-thread-multi
    /home/zefram/usr/perl/perl_install/perl-5.27.6-i64-f52/lib/5.27.6


Environment for perl 5.27.6:
    HOME=/home/zefram
    LANG (unset)
    LANGUAGE (unset)
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PATH=/home/zefram/usr/perl/perl_install/perl-5.27.6-i64-f52/bin:/home/zefram/usr/perl/util:/home/zefram/pub/x86_64-unknown-linux-gnu/bin:/home/zefram/pub/common/bin:/usr/bin:/bin:/usr/local/bin:/usr/games
    PERL_BADLANG (unset)
    SHELL=/usr/bin/zsh

@p5pRT
Copy link
Author

p5pRT commented Nov 23, 2017

From @cpansprout

On Thu, 23 Nov 2017 10​:11​:23 -0800, zefram@​fysh.org wrote​:

This is a bug report for perl from zefram@​fysh.org,
generated with the help of perlbug 1.41 running under perl 5.27.6.

-----------------------------------------------------------------
[Please describe your issue here]

Jumping into a block with goto is rightly deprecated​:

$ perl -lwe 'goto FOO; while(rand(1) > 2) { FOO​: print 22; }'
Use of "goto" to jump into a construct is deprecated at -e line 1.
22

But that warning message is missing a bit​: when will this deprecated
feature be removed? perldeprecation.pod also doesn't list this
deprecation.

In <20170111060624.1223.qmail@​lists-nntp.develooper.com> I wrote​:

Sawyer X wrote​:

* Use of "goto" to jump into a construct is deprecated​: Deprecated in
5.12.0, remove in 5.28.0.

I have a strong objection to this one. (I have code relying on it
that would likely get slower if I had to rewrite it to avoid the con-
struct. Also, some instances of this do not get the warning.)

The two reasons that were given when this deprecation was proposed
were (1) that it would not work with the 'code generation' patch
that later was rejected as not providing any more efficiency, while
increasing memory usage, and (2) that this kind of goto did not work
with 'given' blocks.

The former reason no longer applies. The latter reason applies to an
experimental feature.

I propose we undeprecate this feature instead.

Sawyer responded, in <096e5596-a40c-0615-c5af-0e3718e2c7b0@​gmail.com>​:

I suggest we discuss it in a separate thread.

The policy I have in mind for these are​: If you have a use-case for
this, which is reasonable, and to which there is no alternative, then we
should either create one or undeprecate.

In response, Abigail made this commit​:

commit dc6e8de
Author​: Abigail <abigail@​abigail.be>
Date​: Mon Jan 16 11​:44​:30 2017 +0100

  There's an objection to fatalizing jumping into a construct.
 
  This reverts commit 84b32f5.
  This reverts commit d30393a.
 
  We need more debate on this one; either we should undeprecate it,
  or settle on an end-of-life version.

I never got around to starting a new thread, but that is what you have done. Can someone respond to my words above?

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Nov 23, 2017

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

@p5pRT
Copy link
Author

p5pRT commented Nov 24, 2017

From zefram@fysh.org

The problems with inward gotos are bigger than you indicated. That it
doesn't work with "given" [perl #74764] is not really specific to
"given", but symptomatic of the general problem that arises from mixing
inward gotos with Perl's heavy use of dynamic scoping. For example,
it also doesn't work with "foreach", though at least this is detected
and signalled cleanly​:

$ perl -lwe 'goto FOO; foreach(1,2) { FOO​: print $_; }'
Use of "goto" to jump into a construct is deprecated at -e line 1.
Can't "goto" into the middle of a foreach loop at -e line 1.

We could `fix' [perl #74764] by making jumps into "given" fail this
cleanly. That inward goto wouldn't work is pretty understandable with
"foreach" and "given", with their high-level concept of aliasing the topic
variable in a dynamic scope. To jump into a "foreach" successfully we'd
have to alias the loop variable on the way in, but without evaluating
the list how do we know what to alias it to? Jumping in without aliasing
it would have some logic to it, but it's a logic quite alien to the more
structured view of code that these constructs provide.

No, inward goto only makes sense where the "inward" part is a sham.
That is, where all control constructs amount to conditional jumps within
a flat sequence of instructions. That is, in C, and by extension in
parts of Perl that imitate it. C-style "for" is fine​: omitting the init
portion has well-defined behaviour (provided that the loop variable was
declared and initialised earlier. "while" is fine​: omitting to check
the condition doesn't in itself cause any problem. And "if" is fine​:
again, you're just bypassing a conditional jump. So this perfectly good
C construct can of course be used in Perl​:

$ perl -lwe 'my $i = 0; if(0) { RESTART​: print "restarted"; } print "beginning process with i=$i"; goto RESTART unless $i++; print "done";'
beginning process with i=0
Can't find label RESTART at -e line 1.

Say what? The label's right there! Inside the block for that "if" that
you optimised away! Oops. This construct works if the conditional is
changed (as in the example I started this thread with) to one that Perl
isn't clever enough to optimise out, such as "rand(1) > 2". So *the
cleverness of the compiler* changes the legality of this construct.
There is a major clash of coding worldviews here​: between the C world,
where blocks are just for show and so inward jumps are unremarkable,
and the truly-structured world that the Perl compiler lives in, where it
optimises in the sure and certain knowledge that a block being unenterable
at the top makes the entire block unreachable.

I actually reported this as a bug, way back in 2000 in the pre-RT
bugtracker. I'd innocently used the "if(0) { RESTART​:" construct in a
genuine program, and hit this problem. I argued that it should work,
in order to make "goto" behave as advertised. I commented

  Unreachable code elimination is a good thing. But if code has a label
  in front of it then there's a fair chance that it's not unreachable.

Unfortunately I don't have a copy of any substantive reply to this, and
RT doesn't have the ticket. The p5p archive has the original report,
but no reply. IIRC I did get a reply, rejecting the bug report, on
grounds amounting to "too much trouble to make it work". (The lack of a
record of such reply is making me doubt my recollection.) Anyway, that
this wasn't considered worth fixing was clearly a rejection of "goto"
as a first-class control construct. It doesn't count for reachability.

Fixing this would indeed be troublesome. The easy bit would be to
search for labels inside blocks about to be dropped due to constant
folding, and decline to fold them to such an extent as to discard
the ops. More difficult would be the peephole optimiser, which traces
the execution-order links between ops, and, quelle surprise, doesn't
consider gotos to be such links.

A lot of this comes down to the very dynamic way in which perl handles
gotos. It doesn't treat the link between a goto and its target label
in the first-class way that the an if-else conditional links to its
two branches. Instead the string label name is the thing, with a
dynamic search for a label having the same name. This is very unlike C.
It has some advantage, in that the target label doesn't have to be in
the same subroutine​: perl can go on unwinding dynamic scopes (something
it's pretty good at) looking for a surrounding scope in which there's a
matching label. But doing that gives up any possibility of compile-time
detection of unmatched labels, and it generally makes it difficult to
pay any attention to goto-based control transfers in compilation.

I have periodically had thoughts of implementing a "true goto" as a
CPAN module. This goto would be an op with its op_next pointing at
its target label, all fixed up during sub compilation, with missing
targets constituting errors. Simple cases (neither inward nor outward)
would be null ops that the peephole optimiser eventually threads out.
But the utility seemed too low for the tuits.

It's also worth comparing goto against our treatment of C's "switch"
statement. Yes, it's experimental, but the general approach is settled
and it's instructive. "given"/"when" are described by the documentation
as resembling C's "switch"/"case". But the resemblance is a lot looser
than the resemblance of "while" et al. C's "switch" is, like almost all
its control constructs, a glorified goto. But the Perl incarnation isn't
at all like that​: it builds up two significant layers of dynamic scoping,
just so that all the distant jumps in it have the well-supported form of
unwinding to a defined type of scope. Indeed, it gives up some of the
lexical scoping of the C feature, in order to be more purely dynamic.
This would seem a step backward, but it's certainly more coherent with
the rest of Perl, and can be justified as a pragmatic way to design a
feature inspired by "switch". (Perl 5 is also not purely imitating C
here, it's more directly imitating Perl 6, but it's still notable that
it takes the dynamic approach to this kind of feature.)

All in all, inward gotos don't fit into the language. They don't
play nicely with the dynamic scoping that Perl uses so heavily.
They don't work with the structured approach to code that Perl takes
most of the time. They're an orphaned feature, copied from C but not
actually workable in the Perl context. Copying goto and adapting it to
the dynamic control flow was a very Perlish design decision in itself,
but to make goto work in the inward case was overstretching it. It should
be regarded as a failed experiment and excised from the language.

Inward goto has been deprecated for long enough that it should be fine to
just remove it in 5.28. Specifically, we should remove the cases that
yield a deprecation warning. If there are other kinds of troublesome
goto, we should consider deprecating them.

-zefram

@p5pRT
Copy link
Author

p5pRT commented Nov 24, 2017

From @arc

Father Chrysostomos via RT <perlbug-followup@​perl.org> wrote​:

The two reasons that were given when this deprecation was proposed
were (1) that it would not work with the 'code generation' patch
that later was rejected as not providing any more efficiency, while
increasing memory usage, and (2) that this kind of goto did not work
with 'given' blocks.

The former reason no longer applies. The latter reason applies to an
experimental feature.

I propose we undeprecate this feature instead.

Sawyer responded, in <096e5596-a40c-0615-c5af-0e3718e2c7b0@​gmail.com>​:

I suggest we discuss it in a separate thread.

The policy I have in mind for these are​: If you have a use-case for
this, which is reasonable, and to which there is no alternative, then we
should either create one or undeprecate.

I never got around to starting a new thread, but that is what you have done. Can someone respond to my words above?

I didn't realise this at the time the deprecation was reprieved, but
we still have some crash bugs around goto-in-construct. All of these
fail noisily under ASAN​:

perl -e 'goto X; meth { X​: }'
perl -e 'goto X; map { X​: } ()'
perl -e 'sub f {} goto X; f(do { X​: })'

See https://rt.perl.org/Public/Bug/Display.html?id=130936 for details
(including some notes from Dave M).

If we can't find a reasonable way to fix cases like those, I think we
should reinstate the deprecation of goto-into-construct.

--
Aaron Crane ** http​://aaroncrane.co.uk/

@p5pRT
Copy link
Author

p5pRT commented Nov 24, 2017

From @cpansprout

On Fri, 24 Nov 2017 02​:56​:04 -0800, zefram@​fysh.org wrote​:

The problems with inward gotos are bigger than you indicated. That it
doesn't work with "given" [perl #74764] is not really specific to
"given", but symptomatic of the general problem that arises from
mixing
inward gotos with Perl's heavy use of dynamic scoping. For example,
it also doesn't work with "foreach", though at least this is detected
and signalled cleanly​:

$ perl -lwe 'goto FOO; foreach(1,2) { FOO​: print $_; }'
Use of "goto" to jump into a construct is deprecated at -e line 1.
Can't "goto" into the middle of a foreach loop at -e line 1.

We could `fix' [perl #74764] by making jumps into "given" fail this
cleanly.

I would be all in favour of that.

No, inward goto only makes sense where the "inward" part is a sham.
That is, where all control constructs amount to conditional jumps
within
a flat sequence of instructions. That is, in C, and by extension in
parts of Perl that imitate it. C-style "for" is fine​: omitting the
init
portion has well-defined behaviour (provided that the loop variable
was
declared and initialised earlier. "while" is fine​: omitting to check
the condition doesn't in itself cause any problem. And "if" is fine​:
again, you're just bypassing a conditional jump. So this perfectly
good
C construct can of course be used in Perl​:

$ perl -lwe 'my $i = 0; if(0) { RESTART​: print "restarted"; } print
"beginning process with i=$i"; goto RESTART unless $i++; print
"done";'
beginning process with i=0
Can't find label RESTART at -e line 1.

Say what? The label's right there! Inside the block for that "if"
that
you optimised away! Oops. This construct works if the conditional is
changed (as in the example I started this thread with) to one that
Perl
isn't clever enough to optimise out, such as "rand(1) > 2". So *the
cleverness of the compiler* changes the legality of this construct.

That is all documented behaviour. If it helps, we could change the wording of the documentation (in perlfunc) from​:

  It also can't be used to go
  into a construct that is optimized away.

to​:

  Using C<goto> to jump into a construct that is otherwise unreachable is not
  guaranteed to work.

There is a major clash of coding worldviews here​: between the C world,
where blocks are just for show and so inward jumps are unremarkable,
and the truly-structured world that the Perl compiler lives in, where
it
optimises in the sure and certain knowledge that a block being
unenterable
at the top makes the entire block unreachable.

But in those few cases where it does work (if/when), it causes no harm, and allows some code to be written more straightforwardly.

My particular case is a long if/else chain. Sometimes, in a block preceding that if/else chain, it is determined ahead of time which if-block we will end up in, so a ‘goto’ allows for a (relatively) quick short-circuit. Yes, it’s true that I could rewrite the code some other way (skip the goto, use a hash of subs, etc.), but then it would be slower. (I could also write in my module’s documentation​: ‘Perl 5.26.0 and lower recommended, as later versions are slower’, but I don’t think anybody wants that.)

I actually reported this as a bug, way back in 2000 in the pre-RT
bugtracker. I'd innocently used the "if(0) { RESTART​:" construct in a
genuine program, and hit this problem. I argued that it should work,
in order to make "goto" behave as advertised. I commented

Unreachable code elimination is a good thing. But if code has a label
in front of it then there's a fair chance that it's not unreachable.

Unfortunately I don't have a copy of any substantive reply to this,
and
RT doesn't have the ticket. The p5p archive has the original report,
but no reply. IIRC I did get a reply, rejecting the bug report, on
grounds amounting to "too much trouble to make it work". (The lack of
a
record of such reply is making me doubt my recollection.) Anyway,
that
this wasn't considered worth fixing was clearly a rejection of "goto"
as a first-class control construct. It doesn't count for
reachability.

Fixing this would indeed be troublesome. The easy bit would be to
search for labels inside blocks about to be dropped due to constant
folding, and decline to fold them to such an extent as to discard
the ops. More difficult would be the peephole optimiser, which traces
the execution-order links between ops, and, quelle surprise, doesn't
consider gotos to be such links.

I don’t think this would be at all unreasonable. But I think that having a goto-LABEL that can jump into simple blocks and dies for other constructs is a reasonable compromise.

It's also worth comparing goto against our treatment of C's "switch"
statement. Yes, it's experimental, but the general approach is
settled
and it's instructive. "given"/"when" are described by the
documentation
as resembling C's "switch"/"case". But the resemblance is a lot
looser
than the resemblance of "while" et al. C's "switch" is, like almost
all
its control constructs, a glorified goto. But the Perl incarnation
isn't
at all like that​: it builds up two significant layers of dynamic
scoping,
just so that all the distant jumps in it have the well-supported form
of
unwinding to a defined type of scope. Indeed, it gives up some of the
lexical scoping of the C feature, in order to be more purely dynamic.
This would seem a step backward, but it's certainly more coherent with
the rest of Perl, and can be justified as a pragmatic way to design a
feature inspired by "switch". (Perl 5 is also not purely imitating C
here, it's more directly imitating Perl 6, but it's still notable that
it takes the dynamic approach to this kind of feature.)

For this reason, I’ve never really seen the point of Perl’s ‘given’. It offers no new features and saves typing a few characters. But this is actually quite irrelevant to goto.

All in all, inward gotos don't fit into the language. They don't
play nicely with the dynamic scoping that Perl uses so heavily.
They don't work with the structured approach to code that Perl takes
most of the time. They're an orphaned feature, copied from C but not
actually workable in the Perl context. Copying goto and adapting it
to
the dynamic control flow was a very Perlish design decision in itself,
but to make goto work in the inward case was overstretching it. It
should
be regarded as a failed experiment and excised from the language.

I fail to see how inward goto is all that different from goto-&sub and list assignment to state().

eval { goto &sub } used to crash. Since it wasn’t easy to implement properly, it was made an error. Still, goto &sub is useful.

state assignment was made an error in those cases where its behaviour hadn’t been decided. The few cases in which it will work are still useful, even without the full-blown state() feature that we could have.

Similarly, using goto-LABEL to jump into if/when blocks is useful, if even the more weird constructs don’t work, or even crash. Let’s just forbid the crashing cases.

I realize you will probably reject my reasoning. But I hope you will appreciate that yours is not the only reasonable viewpoint.

Inward goto has been deprecated for long enough that it should be fine
to
just remove it in 5.28. Specifically, we should remove the cases that
yield a deprecation warning. If there are other kinds of troublesome
goto, we should consider deprecating them.

There’s this, which doesn’t warn​:

$ perl -le 'if (do { goto foo }) { foo​: }'

But if you remove the ‘do{’ and ‘}’ surrounding the goto, it warns.

What’s unfortunate about this is the timing. I never bothered arguing for keeping inward goto, because until a year ago the policy (even stated by a former pumpking) was that we would remove deprecated features when they got in the way of fixing bugs (e.g., do sub()), adding new features (<<), or just basic maintenance (use encoding, which was pervasive); otherwise the feature would be left alone. goto-LABEL fits into none of those categories, so I felt ‘safe’, as it were. The policy changed sharply a year ago, so I felt it was time to say something in defence of the construct.

All this is a long-winded way of saying why I reject the reasoning, ‘it’s been deprecated long enough’. It’s hasn’t been ‘deprecated and in danger of being deleted’ long enough.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Nov 28, 2017

From @xsawyerx

On 11/24/2017 01​:12 PM, Aaron Crane wrote​:

Father Chrysostomos via RT <perlbug-followup@​perl.org> wrote​:

The two reasons that were given when this deprecation was proposed
were (1) that it would not work with the 'code generation' patch
that later was rejected as not providing any more efficiency, while
increasing memory usage, and (2) that this kind of goto did not work
with 'given' blocks.

The former reason no longer applies. The latter reason applies to an
experimental feature.

I propose we undeprecate this feature instead.
Sawyer responded, in <096e5596-a40c-0615-c5af-0e3718e2c7b0@​gmail.com>​:
I suggest we discuss it in a separate thread.

The policy I have in mind for these are​: If you have a use-case for
this, which is reasonable, and to which there is no alternative, then we
should either create one or undeprecate.
I never got around to starting a new thread, but that is what you have done. Can someone respond to my words above?
I didn't realise this at the time the deprecation was reprieved, but
we still have some crash bugs around goto-in-construct. All of these
fail noisily under ASAN​:

perl -e 'goto X; meth { X​: }'
perl -e 'goto X; map { X​: } ()'
perl -e 'sub f {} goto X; f(do { X​: })'

See https://rt.perl.org/Public/Bug/Display.html?id=130936 for details
(including some notes from Dave M).

If we can't find a reasonable way to fix cases like those, I think we
should reinstate the deprecation of goto-into-construct.

Which brings us back to FC providing his use-case and seeing if there's
a reasonable way to provide *that* need without the additional cases
which give us headaches.

@p5pRT
Copy link
Author

p5pRT commented Nov 28, 2017

From @cpansprout

On Tue, 28 Nov 2017 04​:08​:59 -0800, xsawyerx@​gmail.com wrote​:

On 11/24/2017 01​:12 PM, Aaron Crane wrote​:

perl -e 'goto X; meth { X​: }'
perl -e 'goto X; map { X​: } ()'
perl -e 'sub f {} goto X; f(do { X​: })'
...
If we can't find a reasonable way to fix cases like those, I think we
should reinstate the deprecation of goto-into-construct.

Which brings us back to FC providing his use-case and seeing if
there's
a reasonable way to provide *that* need without the additional cases
which give us headaches.

All the cases above involve a pushmark, which is easy enough to check for.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Nov 29, 2017

From @davidnicol

with 5.10, the visibility or invisibility of labels is curious. Label
becomes visible from inside other subroutine when called from inside block
containing label, not visible when invoked from outside.

$ perl -le 'goto X; map { print 22; X​: print 55 } (1 .. 3)'
55
$ perl -le 'goto X; sub sb{map { print 22; X​: print 55 } (1 .. 3)}'
Can't find label X at -e line 1.
$ perl -le 'sub x{goto X}; sub sb{map { print 22; X​: print 55 } (1 .. 3)}'
$ perl -le 'sub x{goto X}; sub sb{ x(); map { print 22; X​: print 55 } (1 ..
3)}; sb()'
55
$ perl -le 'sub x{goto X}; sub sb{ map { print 22; X​: print 55 } (1 ..
3)}; sb()'
22
55
22
55
22
55
$ perl -le 'sub x{goto X}; sub sb{ map { print 22; X​: print 55 } (1 ..
3)}; x()'
Can't find label X at -e line 1.

On Tue, Nov 28, 2017 at 11​:54 AM, Father Chrysostomos via RT <
perlbug-followup@​perl.org> wrote​:

On Tue, 28 Nov 2017 04​:08​:59 -0800, xsawyerx@​gmail.com wrote​:

On 11/24/2017 01​:12 PM, Aaron Crane wrote​:

perl -e 'goto X; meth { X​: }'
perl -e 'goto X; map { X​: } ()'
perl -e 'sub f {} goto X; f(do { X​: })'
...
If we can't find a reasonable way to fix cases like those, I think we
should reinstate the deprecation of goto-into-construct.

Which brings us back to FC providing his use-case and seeing if
there's
a reasonable way to provide *that* need without the additional cases
which give us headaches.

All the cases above involve a pushmark, which is easy enough to check for.

--

Father Chrysostomos

---
via perlbug​: queue​: perl5 status​: open
https://rt-archive.perl.org/perl5/Ticket/Display.html?id=132492

--
Hi-jinks ensue.

@p5pRT
Copy link
Author

p5pRT commented Nov 29, 2017

From @cpansprout

On Wed, 29 Nov 2017 06​:46​:28 -0800, davidnicol@​gmail.com wrote​:

with 5.10, the visibility or invisibility of labels is curious. Label
becomes visible from inside other subroutine when called from inside block
containing label, not visible when invoked from outside.

$ perl -le 'goto X; map { print 22; X​: print 55 } (1 .. 3)'
55
$ perl -le 'goto X; sub sb{map { print 22; X​: print 55 } (1 .. 3)}'
Can't find label X at -e line 1.
$ perl -le 'sub x{goto X}; sub sb{map { print 22; X​: print 55 } (1 .. 3)}'
$ perl -le 'sub x{goto X}; sub sb{ x(); map { print 22; X​: print 55 } (1 ..
3)}; sb()'
55
$ perl -le 'sub x{goto X}; sub sb{ map { print 22; X​: print 55 } (1 ..
3)}; sb()'
22
55
22
55
22
55
$ perl -le 'sub x{goto X}; sub sb{ map { print 22; X​: print 55 } (1 ..
3)}; x()'
Can't find label X at -e line 1.

I see nothing curious in the output of those examples. (The examples themselves are another matter.) You can goto out of a subroutine, but you cannot goto into a subroutine, for an obvious reason​:

  sub foo { BONK​: }
  sub bar { BONK​: }
  goto BONK

Which one wins? And how do you even find the label to begin with? The label has to be accessible via the context stack for sanity’s sake.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Jan 8, 2018

From @cpansprout

On Tue, 28 Nov 2017 09​:54​:46 -0800, sprout wrote​:

On Tue, 28 Nov 2017 04​:08​:59 -0800, xsawyerx@​gmail.com wrote​:

On 11/24/2017 01​:12 PM, Aaron Crane wrote​:

perl -e 'goto X; meth { X​: }'
perl -e 'goto X; map { X​: } ()'
perl -e 'sub f {} goto X; f(do { X​: })'
...
If we can't find a reasonable way to fix cases like those, I think we
should reinstate the deprecation of goto-into-construct.

Which brings us back to FC providing his use-case and seeing if
there's
a reasonable way to provide *that* need without the additional cases
which give us headaches.

All the cases above involve a pushmark, which is easy enough to check for.

And I’ve now forbidden the crashing cases in commit 6d90e98.

--

Father Chrysostomos

@khwilliamson
Copy link
Contributor

What to do about this ticket?

@khwilliamson khwilliamson added the Closable? We might be able to close this ticket, but we need to check with the reporter label Apr 19, 2022
@hvds
Copy link
Contributor

hvds commented Apr 19, 2022

What to do about this ticket?

There are well argued cases for and against, I think this is one for the PSC to make a decision on.

@jkeenan
Copy link
Contributor

jkeenan commented Jul 1, 2022

What to do about this ticket?

There are well argued cases for and against, I think this is one for the PSC to make a decision on.

PSC: can you put discussion of this ticket on your agenda? Thanks.

@leonerd
Copy link
Contributor

leonerd commented Jul 1, 2022

I've added a note for next week's agenda

@rjbs
Copy link
Member

rjbs commented Jul 15, 2022

Our question as of last week was: "Why not immediately?"

@hvds
Copy link
Contributor

hvds commented Jul 15, 2022

Our question as of last week was: "Why not immediately?"

@rjbs: Does that mean PSC has decided on removal? It would be worth stating that. :)

It is not clear to me from reading the ticket that all forms of inward goto currently have a deprecation warning. For ones that warn, I think it might be acceptable to remove them immediately. If there are any that still don't warn it would be rude to make them immediate errors without a user-visible deprecation period.

I don't know what the full list of distinguishable forms looks like, or I'd be able to check this for myself - @arc's examples already include cases I would not have thought of.

@jkeenan
Copy link
Contributor

jkeenan commented Oct 26, 2023

Our question as of last week was: "Why not immediately?"

@rjbs: Does that mean PSC has decided on removal? It would be worth stating that. :)

It is not clear to me from reading the ticket that all forms of inward goto currently have a deprecation warning. For ones that warn, I think it might be acceptable to remove them immediately. If there are any that still don't warn it would be rude to make them immediate errors without a user-visible deprecation period.

I don't know what the full list of distinguishable forms looks like, or I'd be able to check this for myself - @arc's examples already include cases I would not have thought of.

Perl Steering Council: Can you respond to @hvds's concerns raised last year? Thank you very much.

@leonerd
Copy link
Contributor

leonerd commented Oct 26, 2023

We've just discussed this in PSC. Thoughts are that things that currently already warn should immediately set a removal date of 5.42 so we can set a timeline. If there are other remaining cases that don't even warn, such warnings could be added but those cases would probably need the usual two-release-cycles of warning lifetime before they were removed.

@hvds
Copy link
Contributor

hvds commented Oct 26, 2023

We've just discussed this in PSC. Thoughts are that things that currently already warn should immediately set a removal date of 5.42 so we can set a timeline. If there are other remaining cases that don't even warn, such warnings could be added but those cases would probably need the usual two-release-cycles of warning lifetime before they were removed.

Works for me. I hope that the changes will turn out to be very close to the code that currently raises warnings - maybe even doing nothing but elevate those warnings to errors - so that it will be clear that only the warning paths are affected.

@jkeenan jkeenan removed the Closable? We might be able to close this ticket, but we need to check with the reporter label Oct 28, 2023
jkeenan added a commit that referenced this issue Nov 5, 2023
perlfunc: clarify documentation per suggestion from Hugo van der Sanden in
#21601.

Fixes #16275
jkeenan added a commit that referenced this issue Nov 5, 2023
perlfunc: clarify documentation per suggestion from Hugo van der Sanden in
#21601.

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

Successfully merging a pull request may close this issue.

7 participants