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

Prototypes defined too late - warning for recursive subroutines #1511

Closed
p5pRT opened this issue Mar 27, 2000 · 19 comments
Closed

Prototypes defined too late - warning for recursive subroutines #1511

p5pRT opened this issue Mar 27, 2000 · 19 comments

Comments

@p5pRT
Copy link

p5pRT commented Mar 27, 2000

Migrated from rt.perl.org#2726 (status was 'resolved')

Searchable as RT2726$

@p5pRT
Copy link
Author

p5pRT commented Mar 27, 2000

From ht.000@foa.dk

Created by ht000@foa.dk

When running with -w flag you get a warning if a function with a
prototype is used recursively before the end of the function.

Eg​:
  $ cat fail.pl
  sub fail($) {
  return 1 unless $_[0] == 1;
  fail(4);
  }

  fail (1);
  $ perl5.6.0 -wc fail.pl
  main​::fail() called too early to check prototype at fail.pl line 3.
  fail.pl syntax OK

Perl5.005_03 does not exhibit this behaviour (possibly because the
prototype tests were not so restrictive - the warning is new anyway).
  $ perl5.00503 -wc fail.pl
  fail.pl syntax OK

The warning can be avoided by prototyping the subroutine just before
its definition - which does look a bit silly​:
  $ cat ok.pl
  sub fail($);
  sub fail($) {
  return 1 unless $_[0] == 1;
  fail(4);
  }

  fail (1);
  $ perl5.6.0 -wc ok.pl
  ok.pl syntax OK

A more intuitive behaviour would be that the prototype is known at the
start of the subroutine block, not at the end.

At the least a warning/note should be added in perlfunc.pod
documenting this not too intuitively clear behaviour.

---
Henrik Tougaard ht000@​foa.dk
FOA Trade Union for Public employees Denmark.
#include <disclaim.std>

Perl Info

Flags:
    category=core
    severity=low

Site configuration information for perl v5.6.0:

Configured by ht000 at Thu Mar 23 07:46:36 MET 2000.

Summary of my perl5 (revision 5.0 version 6 subversion 0) configuration:
  Platform:
    osname=dec_osf, osvers=4.0, archname=alpha-dec_osf
    uname='osf1 panama2.foa.dk v4.0 1091 alpha '
    config_args=''
    hint=recommended, useposix=true, d_sigaction=define
    usethreads=undef use5005threads=undef useithreads=undef usemultiplicity=undef
    useperlio=undef d_sfio=undef uselargefiles=define 
    use64bitint=define use64bitall=define uselongdouble=undef usesocks=undef
  Compiler:
    cc='cc', optimize='-O4', gccversion=
    cppflags='-std -ieee -D_INTRINSICS -I/usr/local/include -DLANGUAGE_C'
    ccflags ='-std -fprm d -ieee -D_INTRINSICS -I/usr/local/include -DLANGUAGE_C'
    stdchar='unsigned char', d_stdstdio=define, usevfork=false
    intsize=4, longsize=8, ptrsize=8, doublesize=8
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=8
    ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
    alignbytes=8, usemymalloc=y, prototype=define
  Linker and Libraries:
    ld='ld', ldflags =' -L/usr/local/lib'
    libpth=/usr/local/lib /usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /var/shlib
    libs=-ldbm -ldb -lm -liconv
    libc=/usr/shlib/libc.so, so=so, useshrplib=true, libperl=libperl.so
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='  -Wl,-rpath,/tools/perl/lib/5.6.0/alpha-dec_osf/CORE'
    cccdlflags=' ', lddlflags='-shared -expect_unresolved "*" -O4 -msym -std -s -L/usr/local/lib'

Locally applied patches:
    


@INC for perl v5.6.0:
    /usr/local/lib/perlmod
    /tools/perl/lib/5.6.0/alpha-dec_osf
    /tools/perl/lib/5.6.0
    /tools/perl/lib/site_perl/5.6.0/alpha-dec_osf
    /tools/perl/lib/site_perl/5.6.0
    /tools/perl/lib/site_perl/5.005/alpha-dec_osf
    /tools/perl/lib/site_perl/5.005
    /tools/perl/lib/site_perl
    .


Environment for perl v5.6.0:
    HOME=/usr/users/ht
    LANG=da_DK.ISO8859-1
    LANGUAGE (unset)
    LD_LIBRARY_PATH=/ingres_oa/ingres/lib:/usr/shlib
    LOGDIR (unset)
    PATH=/tools/perl/bin:/usr/local/scripts:/usr/local/bin:/usr/local:/sbin:/usr/sbin:/usr/bin:/usr/bin/X11:/usr/opt/networker/bin:/progs/CVS/cvs-1.10/bin:/usr/users/ht/bin:/ingres_oa/ingres/utility:/ingres_oa/ingres/bin
    PERL5LIB=/usr/local/lib/perlmod
    PERL_BADLANG (unset)
    SHELL=/usr/bin/ksh



@p5pRT
Copy link
Author

p5pRT commented Apr 5, 2000

From mrcoraza@an.intel.com

We're trying out the new 5.6 release. This version has introduced
a new "feature" with respect to using recursion. Try the following
script.

  eval 'exec perl -w -S $0 "$@​"'
  if 0;
 
  use strict;
 
  sub fact ($) {
  my $n = shift;
 
  if($n < 2) { return 1; }
  else { return $n*fact($n-1); }
  }
 
  print fact(4), "\n";

Note that I am using the -w option. I get the following.

  main​::fact() called too early to check prototype at rec line 12.
  24

I can work around the problem easily by explicitly pre-declaring the
prototype but, in principle, I shouldn't have to.

Thanks.

- Miguel

P.S. I think this has always been sort of a problem since I've noticed
that Perl never seems to check prototypes in recursion. I think the
extra check that was added simply hilighted the problem.

P.P.S. FYI we're also noting some seg faults in certain apps using Tk.
We've yet to isolate what specifically is failing.

Perl Info

Flags:
    category=core
    severity=low

Site configuration information for perl v5.6.0:

Configured by mthooks at Fri Mar 31 13:52:57 CST 2000.

Summary of my perl5 (revision 5.0 version 6 subversion 0) configuration:
  Platform:
    osname=hpux, osvers=10.20, archname=PA-RISC2.0
    uname='hp-ux anhp96 b.10.20 a 9000785 2015349244 two-user license '
    config_args='-des -Dprefix=/an/dm/work/mthooks/perl -Dcc=gcc -Doptimize=-O3 -N -Dlocincpth=/an/dm/work/mthooks/perl/include -Dloclibpth=/an/dm/work/mthooks/perl/lib'
    hint=recommended, useposix=true, d_sigaction=define
    usethreads=undef use5005threads=undef useithreads=undef usemultiplicity=undef
    useperlio=undef d_sfio=undef uselargefiles=undef 
    use64bitint=undef use64bitall=undef uselongdouble=undef usesocks=undef
  Compiler:
    cc='gcc', optimize='-O3 -N', gccversion=2.8.1
    cppflags='-D_HPUX_SOURCE -L/lib/pa1.1 -DUINT32_MAX_BROKEN'
    ccflags ='-D_HPUX_SOURCE -L/lib/pa1.1 -DUINT32_MAX_BROKEN'
    stdchar='unsigned char', d_stdstdio=define, usevfork=false
    intsize=4, longsize=4, ptrsize=4, doublesize=8
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=8
    ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=4
    alignbytes=8, usemymalloc=y, prototype=define
  Linker and Libraries:
    ld='ld', ldflags =''
    libpth=/lib /usr/lib /usr/ccs/lib /usr/local/lib
    libs=-lnsl_s -lndbm -ldld -lm -lc -lndir -lcrypt -lsec
    libc=/lib/libc.sl, so=sl, useshrplib=false, libperl=libperl.a
  Dynamic Linking:
    dlsrc=dl_hpux.xs, dlext=sl, d_dlsymun=undef, ccdlflags='-Wl,-E -Wl,-B,deferred '
    cccdlflags='-fpic', lddlflags='-b'

Locally applied patches:
    


@INC for perl v5.6.0:
    ../../ITk/src
    /an/ec/beta/hp9000.10.20/lib/perl5/site_perl/5.005/PA-RISC2.0
    .
    /home/mrcoraza/lib/perl
    /an/dm/dist/common/latest/lib/perl
    /an/dm/dist/catsgen/latest/lib/perl
    /an/dm/work/mthooks/perl/lib/5.6.0/PA-RISC2.0
    /an/dm/work/mthooks/perl/lib/5.6.0
    /an/dm/work/mthooks/perl/lib/site_perl/5.6.0/PA-RISC2.0
    /an/dm/work/mthooks/perl/lib/site_perl/5.6.0
    /an/dm/work/mthooks/perl/lib/site_perl
    .


Environment for perl v5.6.0:
    HOME=/home/mrcoraza
    LANG=C
    LANGUAGE (unset)
    LD_LIBRARY_PATH=/usr/lib:/usr/intel/CURRENT/lib:/an/dm/dist/commmon/latest/lib/hp9000.10.20
    LOGDIR (unset)
    PATH=/an/dm/dist/catsgen/latest/bin/scripts:.:/an/dm/work/mthooks/perl/bin:/home/mrcoraza/bin:/an/ec/beta/hp9000.10.20/bin:/usr/intel/bin:/usr/bin:/etc:/usr/etc:/usr/ccs/bin:/usr/afsws/bin:/usr/afsws/etc:/usr/local/bin:/an/tools/bin:/usr/dt/bin:/usr/vue/bin:/usr/bin/X11:/usr/contrib/bin:/usr/contrib/bin/X11:/an/ec/FrameMaker/bin:/home/mrcoraza/bin:/opt/aCC/bin:/an/dm/dist/common/latest/bin/scripts:/an/dm/dist/common/latest/bin/hp9000.10.20:/an/dm/local/bin
    PERLLIB=../../ITk/src:/an/ec/beta/hp9000.10.20/lib/perl5/site_perl/5.005/PA-RISC2.0:.:/home/mrcoraza/lib/perl:/an/dm/dist/common/latest/lib/perl:/an/dm/dist/catsgen/latest/lib/perl
    PERL_BADLANG (unset)
    SHELL=/usr/intel/bin/tcsh
    SHLIB_PATH=/an/dm/vendor/sycon/latest/mw/lib-ux10:/an/dm/vendor/sycon/latest/mw/lib-ux10_optimized:.

@p5pRT
Copy link
Author

p5pRT commented Apr 10, 2000

From ht.000@foa.dk

Created by ht000@foa.dk

When running with -w flag you get a warning if a function with a
prototype is used recursively before the end of the function.

Eg​:
  $ cat fail.pl
  sub fail($) {
  return 1 unless $_[0] == 1;
  fail(4);
  }

  fail (1);
  $ perl5.6.0 -wc fail.pl
  main​::fail() called too early to check prototype at fail.pl line 3.
  fail.pl syntax OK

Perl5.005_03 does not exhibit this behaviour (possibly because the
prototype tests were not so restrictive - the warning is new anyway).
  $ perl5.00503 -wc fail.pl
  fail.pl syntax OK

The warning can be avoided by prototyping the subroutine just before
its definition - which does look a bit silly​:
  $ cat ok.pl
  sub fail($);
  sub fail($) {
  return 1 unless $_[0] == 1;
  fail(4);
  }

  fail (1);
  $ perl5.6.0 -wc ok.pl
  ok.pl syntax OK

A more intuitive behaviour would be that the prototype is known at the
start of the subroutine block, not at the end.

At the least a warning/note should be added in perlfunc.pod
documenting this not too intuitively clear behaviour.

---
Henrik Tougaard ht000@​foa.dk
FOA Trade Union for Public employees Denmark.
#include <disclaim.std>

Perl Info

Flags:
    category=core
    severity=low

Site configuration information for perl v5.6.0:

Configured by ht000 at Thu Mar 23 07:46:36 MET 2000.

Summary of my perl5 (revision 5.0 version 6 subversion 0) configuration:
  Platform:
    osname=dec_osf, osvers=4.0, archname=alpha-dec_osf
    uname='osf1 panama2.foa.dk v4.0 1091 alpha '
    config_args=''
    hint=recommended, useposix=true, d_sigaction=define
    usethreads=undef use5005threads=undef useithreads=undef usemultiplicity=undef
    useperlio=undef d_sfio=undef uselargefiles=define 
    use64bitint=define use64bitall=define uselongdouble=undef usesocks=undef
  Compiler:
    cc='cc', optimize='-O4', gccversion=
    cppflags='-std -ieee -D_INTRINSICS -I/usr/local/include -DLANGUAGE_C'
    ccflags ='-std -fprm d -ieee -D_INTRINSICS -I/usr/local/include -DLANGUAGE_C'
    stdchar='unsigned char', d_stdstdio=define, usevfork=false
    intsize=4, longsize=8, ptrsize=8, doublesize=8
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=8
    ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
    alignbytes=8, usemymalloc=y, prototype=define
  Linker and Libraries:
    ld='ld', ldflags =' -L/usr/local/lib'
    libpth=/usr/local/lib /usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /var/shlib
    libs=-ldbm -ldb -lm -liconv
    libc=/usr/shlib/libc.so, so=so, useshrplib=true, libperl=libperl.so
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='  -Wl,-rpath,/tools/perl/lib/5.6.0/alpha-dec_osf/CORE'
    cccdlflags=' ', lddlflags='-shared -expect_unresolved "*" -O4 -msym -std -s -L/usr/local/lib'

Locally applied patches:
    


@INC for perl v5.6.0:
    /usr/local/lib/perlmod
    /tools/perl/lib/5.6.0/alpha-dec_osf
    /tools/perl/lib/5.6.0
    /tools/perl/lib/site_perl/5.6.0/alpha-dec_osf
    /tools/perl/lib/site_perl/5.6.0
    /tools/perl/lib/site_perl/5.005/alpha-dec_osf
    /tools/perl/lib/site_perl/5.005
    /tools/perl/lib/site_perl
    .


Environment for perl v5.6.0:
    HOME=/usr/users/ht
    LANG=da_DK.ISO8859-1
    LANGUAGE (unset)
    LD_LIBRARY_PATH=/ingres_oa/ingres/lib:/usr/shlib
    LOGDIR (unset)
    PATH=/tools/perl/bin:/usr/local/scripts:/usr/local/bin:/usr/local:/sbin:/usr/sbin:/usr/bin:/usr/bin/X11:/usr/opt/networker/bin:/progs/CVS/cvs-1.10/bin:/usr/users/ht/bin:/ingres_oa/ingres/utility:/ingres_oa/ingres/bin
    PERL5LIB=/usr/local/lib/perlmod
    PERL_BADLANG (unset)
    SHELL=/usr/bin/ksh



@p5pRT
Copy link
Author

p5pRT commented Apr 10, 2000

From @ysth

In article <Pine.OSF.3.95.1000410145750.22120C-100000@​sula1.foa.dk>,
Henrik Tougaard <ht.000@​foa.dk> wrote​:

When running with -w flag you get a warning if a function with a
prototype is used recursively before the end of the function.
<snip>
A more intuitive behaviour would be that the prototype is known at the
start of the subroutine block, not at the end.

That could cause some serious backward compatibility problems.

Given Booboo.pm​:

package Booboo;
use strict;
use Exporter ();
@​Booboo​::ISA='Exporter';
@​Booboo​::EXPORT='Booboo';
sub new { shift; bless [@​_], 'Booboo' }
#sub Booboo(@​);
sub Booboo(@​) { Booboo->new(@​_) }
1;

Try​:

perl -MBooboo -e 'Booboo(1,2,3)'

Then try it again with the declaration uncommented.

At the least a warning/note should be added in perlfunc.pod
documenting this not too intuitively clear behaviour.

Perhaps perlsub?

@p5pRT
Copy link
Author

p5pRT commented Jul 28, 2000

From [Unknown Contact. See original ticket]

patchit

@p5pRT
Copy link
Author

p5pRT commented Jul 7, 2003

From ziggy@panix.com

Executive summary​: prototypes exist but cannot be checked inside a recursive function.

@p5pRT
Copy link
Author

p5pRT commented Jul 27, 2006

@smpeters - Status changed from 'resolved' to 'open'

1 similar comment
@p5pRT
Copy link
Author

p5pRT commented Jul 27, 2006

@smpeters - Status changed from 'resolved' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Nov 25, 2012

From @wolfsage

On Mon Apr 10 08​:31​:35 2000, RT_System wrote​:

In article <Pine.OSF.3.95.1000410145750.22120C-100000@​sula1.foa.dk>,
Henrik Tougaard <ht.000@​foa.dk> wrote​:

When running with -w flag you get a warning if a function with a
prototype is used recursively before the end of the function.
<snip>
A more intuitive behaviour would be that the prototype is known at the
start of the subroutine block, not at the end.

That could cause some serious backward compatibility problems.

Given Booboo.pm​:

package Booboo;
use strict;
use Exporter ();
@​Booboo​::ISA='Exporter';
@​Booboo​::EXPORT='Booboo';
sub new { shift; bless [@​_], 'Booboo' }
#sub Booboo(@​);
sub Booboo(@​) { Booboo->new(@​_) }
1;

Try​:

perl -MBooboo -e 'Booboo(1,2,3)'

Then try it again with the declaration uncommented.

Hmm, isn't that wrong and broken?

Shouldn't sub Booboo(@​); sub Booboo(@​) { ... } behave the same as the
single declaration sub Booboo(@​) { ... } ?

Having it behave differently when it's predeclared seems very surprising.

The above can be fixed by​:

sub Booboo(@​) { Booboo​::->new(@​_) }

Is back-compat preventing this from being fixed? If so, how do we go
about fixing it while following the policy for incompatible changes?

@p5pRT
Copy link
Author

p5pRT commented Nov 25, 2012

From @cpansprout

On Sun Nov 25 05​:08​:34 2012, alh wrote​:

On Mon Apr 10 08​:31​:35 2000, RT_System wrote​:

In article <Pine.OSF.3.95.1000410145750.22120C-100000@​sula1.foa.dk>,
Henrik Tougaard <ht.000@​foa.dk> wrote​:

When running with -w flag you get a warning if a function with a
prototype is used recursively before the end of the function.
<snip>
A more intuitive behaviour would be that the prototype is known at the
start of the subroutine block, not at the end.

That could cause some serious backward compatibility problems.

Given Booboo.pm​:

package Booboo;
use strict;
use Exporter ();
@​Booboo​::ISA='Exporter';
@​Booboo​::EXPORT='Booboo';
sub new { shift; bless [@​_], 'Booboo' }
#sub Booboo(@​);
sub Booboo(@​) { Booboo->new(@​_) }
1;

Try​:

perl -MBooboo -e 'Booboo(1,2,3)'

Then try it again with the declaration uncommented.

Hmm, isn't that wrong and broken?

Shouldn't sub Booboo(@​); sub Booboo(@​) { ... } behave the same as the
single declaration sub Booboo(@​) { ... } ?

Having it behave differently when it's predeclared seems very surprising.

The above can be fixed by​:

sub Booboo(@​) { Booboo​::->new(@​_) }

Is back-compat preventing this from being fixed? If so, how do we go
about fixing it while following the policy for incompatible changes?

Well, the current behaviour *is* consistent with how my-scoping works.

Also, what happens when the subroutine contains a syntax error and there
was already a sub defined there? Currently the existing sub stays.
Applying the new prototype to calls inside the new sub would require
installing a stub (or some evil hackery I don’t want to think about),
which every syntax error would magically have to undo somehow.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Nov 25, 2012

From PeterCMartini@GMail.com

On Sun, Nov 25, 2012 at 10​:12 AM, Father Chrysostomos via RT <
perlbug-followup@​perl.org> wrote​:

On Sun Nov 25 05​:08​:34 2012, alh wrote​:

On Mon Apr 10 08​:31​:35 2000, RT_System wrote​:

In article <Pine.OSF.3.95.1000410145750.22120C-100000@​sula1.foa.dk>,
Henrik Tougaard <ht.000@​foa.dk> wrote​:

When running with -w flag you get a warning if a function with a
prototype is used recursively before the end of the function.
<snip>
A more intuitive behaviour would be that the prototype is known at
the
start of the subroutine block, not at the end.

That could cause some serious backward compatibility problems.

Given Booboo.pm​:

package Booboo;
use strict;
use Exporter ();
@​Booboo​::ISA='Exporter';
@​Booboo​::EXPORT='Booboo';
sub new { shift; bless [@​_], 'Booboo' }
#sub Booboo(@​);
sub Booboo(@​) { Booboo->new(@​_) }
1;

Try​:

perl -MBooboo -e 'Booboo(1,2,3)'

Then try it again with the declaration uncommented.

Hmm, isn't that wrong and broken?

Shouldn't sub Booboo(@​); sub Booboo(@​) { ... } behave the same as the
single declaration sub Booboo(@​) { ... } ?

Having it behave differently when it's predeclared seems very surprising.

The above can be fixed by​:

sub Booboo(@​) { Booboo​::->new(@​_) }

Is back-compat preventing this from being fixed? If so, how do we go
about fixing it while following the policy for incompatible changes?

Well, the current behaviour *is* consistent with how my-scoping works.

Also, what happens when the subroutine contains a syntax error and there
was already a sub defined there? Currently the existing sub stays.
Applying the new prototype to calls inside the new sub would require
installing a stub (or some evil hackery I don’t want to think about),
which every syntax error would magically have to undo somehow.

The natural change would be from​:

sub foo($$); -- sets $​::{foo} to '$$'
sub foo($$){ CODE } -- sets $​::{foo} to *​::foo after the closing brace

to

sub foo($$); -- sets $​::{foo} to '$$'
sub foo($$){ -- sets $​::{foo} to '$$', warns about changes, etc
  CODE
} -- sets $​::{foo} to *​::foo with a '$$' prototype after
the closing brace

So, 'sub foo($); sub foo($$){ SYNTAX ERROR}' or 'sub foo($); sub foo {
SYNTAX ERROR}' will change the prototype and warn about the change, even in
the event of a syntax error. I'd consider that a better state of affairs.

On the other hand, 'sub foo; sub foo($$){ SYNTAX ERROR }' would change the
prototype from undefined to a specific prototype, $$.

Do you have a use case in mind where that would matter?

And does anyone know if there is any documentation to suggest that the
current state of affairs is intentional, rather than an undefined
implementation detail?

--

Father Chrysostomos

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

@p5pRT
Copy link
Author

p5pRT commented Nov 25, 2012

From @cpansprout

On Sun Nov 25 10​:05​:06 2012, pcm wrote​:

On Sun, Nov 25, 2012 at 10​:12 AM, Father Chrysostomos via RT <
perlbug-followup@​perl.org> wrote​:

On Sun Nov 25 05​:08​:34 2012, alh wrote​:

On Mon Apr 10 08​:31​:35 2000, RT_System wrote​:

In article <Pine.OSF.3.95.1000410145750.22120C-
100000@​sula1.foa.dk>,
Henrik Tougaard <ht.000@​foa.dk> wrote​:

When running with -w flag you get a warning if a function with
a
prototype is used recursively before the end of the function.
<snip>
A more intuitive behaviour would be that the prototype is
known at
the
start of the subroutine block, not at the end.

That could cause some serious backward compatibility problems.

Given Booboo.pm​:

package Booboo;
use strict;
use Exporter ();
@​Booboo​::ISA='Exporter';
@​Booboo​::EXPORT='Booboo';
sub new { shift; bless [@​_], 'Booboo' }
#sub Booboo(@​);
sub Booboo(@​) { Booboo->new(@​_) }
1;

Try​:

perl -MBooboo -e 'Booboo(1,2,3)'

Then try it again with the declaration uncommented.

Hmm, isn't that wrong and broken?

Shouldn't sub Booboo(@​); sub Booboo(@​) { ... } behave the same as
the
single declaration sub Booboo(@​) { ... } ?

Having it behave differently when it's predeclared seems very
surprising.

The above can be fixed by​:

sub Booboo(@​) { Booboo​::->new(@​_) }

Is back-compat preventing this from being fixed? If so, how do we
go
about fixing it while following the policy for incompatible
changes?

Well, the current behaviour *is* consistent with how my-scoping
works.

Also, what happens when the subroutine contains a syntax error and
there
was already a sub defined there? Currently the existing sub stays.
Applying the new prototype to calls inside the new sub would require
installing a stub (or some evil hackery I don’t want to think
about),
which every syntax error would magically have to undo somehow.

The natural change would be from​:

sub foo($$); -- sets $​::{foo} to '$$'
sub foo($$){ CODE } -- sets $​::{foo} to *​::foo after the closing brace

to

sub foo($$); -- sets $​::{foo} to '$$'
sub foo($$){ -- sets $​::{foo} to '$$', warns about changes, etc
CODE
} -- sets $​::{foo} to *​::foo with a '$$' prototype
after
the closing brace

So, 'sub foo($); sub foo($$){ SYNTAX ERROR}' or 'sub foo($); sub foo {
SYNTAX ERROR}' will change the prototype and warn about the change,
even in
the event of a syntax error. I'd consider that a better state of
affairs.

On the other hand, 'sub foo; sub foo($$){ SYNTAX ERROR }' would change
the
prototype from undefined to a specific prototype, $$.

Do you have a use case in mind where that would matter?

No. But I want to point out that this would break compatibility in four
ways, which need to be considered (even if they are ultimately rejected)​:

• Barewords
• Whether subs with syntax errors can clobber existing subs
• What BEGIN blocks within the subroutine see
• Whether BEGIN blocks can use glob assignment to make the sub get
inserted elsewhere.

And does anyone know if there is any documentation to suggest that the
current state of affairs is intentional, rather than an undefined
implementation detail?

I think the general consensus in the past has been that this is not a
bug. I don’t believe there is any documentation to support that.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Nov 25, 2012

From PeterCMartini@GMail.com

On Sun, Nov 25, 2012 at 3​:46 PM, Father Chrysostomos via RT <
perlbug-followup@​perl.org> wrote​:

No. But I want to point out that this would break compatibility in four
ways, which need to be considered (even if they are ultimately rejected)​:

• Barewords

Ah, barewords make a strong argument​:

sub STDOUT {
  # Do something - log the output?
  print STDOUT @​_;
  undef;
}
print STDOUT "Test\n";

That's persuasive enough for me to drop the argument, much as I wish it
could be changed.

--

Father Chrysostomos

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

@p5pRT
Copy link
Author

p5pRT commented Nov 25, 2012

From @cpansprout

On Sun Nov 25 13​:06​:36 2012, pcm wrote​:

On Sun, Nov 25, 2012 at 3​:46 PM, Father Chrysostomos via RT <
perlbug-followup@​perl.org> wrote​:

No. But I want to point out that this would break compatibility in four
ways, which need to be considered (even if they are ultimately
rejected)​:

• Barewords

Ah, barewords make a strong argument​:

sub STDOUT {
# Do something - log the output?
print STDOUT @​_;
undef;
}
print STDOUT "Test\n";

That's persuasive enough for me to drop the argument, much as I wish it
could be changed.

I think this is the appropriate place to bring up the joke about the
Irishman giving directions. :-)

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Dec 3, 2012

From @nwc10

On Sun, Nov 25, 2012 at 01​:33​:33PM -0800, Father Chrysostomos via RT wrote​:

Ah, barewords make a strong argument​:

sub STDOUT {
# Do something - log the output?
print STDOUT @​_;
undef;
}
print STDOUT "Test\n";

That's persuasive enough for me to drop the argument, much as I wish it
could be changed.

I think this is the appropriate place to bring up the joke about the
Irishman giving directions. :-)

Yes. :-(

Given that where we are right now is that bareword parsing behaves as above,
do we have any tests for it? It strikes me as something obscure we should
test, just to be sure that we don't change it without realising.

I'm not sure where such tests should go.

Nicholas Clark

@p5pRT
Copy link
Author

p5pRT commented Aug 6, 2013

From PeterCMartini@GMail.com

On Mon Dec 03 05​:02​:36 2012, nicholas wrote​:

On Sun, Nov 25, 2012 at 01​:33​:33PM -0800, Father Chrysostomos via RT
wrote​:

Ah, barewords make a strong argument​:

sub STDOUT {
# Do something - log the output?
print STDOUT @​_;
undef;
}
print STDOUT "Test\n";

That's persuasive enough for me to drop the argument, much as I
wish it
could be changed.

I think this is the appropriate place to bring up the joke about the
Irishman giving directions. :-)

Yes. :-(

Given that where we are right now is that bareword parsing behaves as
above,
do we have any tests for it? It strikes me as something obscure we
should
test, just to be sure that we don't change it without realising.

I'm not sure where such tests should go.

Nicholas Clark

For the sake of argument, and to clean up an old RT that's ultimately
just a doc fix, how about the attached patch?

I'm more than happy to see an alternate patch with better wording, or in
a better spot in perlsub, if it knocks this ticket off of the RT queue
:-)

@p5pRT
Copy link
Author

p5pRT commented Aug 6, 2013

From PeterCMartini@GMail.com

0001-perl-2726-Prototype-is-not-applied-until-BLOCK-is-de.patch
From 48597a2adb2b6a01e9bfdb94d1598ea3c6d91bbf Mon Sep 17 00:00:00 2001
From: Peter Martini <PeterCMartini@GMail.com>
Date: Tue, 6 Aug 2013 03:16:35 -0400
Subject: [PATCH] [perl #2726] Prototype is not applied until BLOCK is defined

In the case of a sub definition with a prototype, the prototype
is not attached to the sub until after the body is completely
defined.  This means that any sub which calls itself will
not honor its prototype unless the prototype was declared prior to
the sub's definition.  Whether or not this behavior is desirable is
debatable, but its far too late to do anything about it other than
document it and test to make sure it doesn't change.
---
 pod/perlsub.pod |   10 ++++++++++
 t/comp/proto.t  |    9 ++++++++-
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/pod/perlsub.pod b/pod/perlsub.pod
index ff5feb5..455fa23 100644
--- a/pod/perlsub.pod
+++ b/pod/perlsub.pod
@@ -1338,6 +1338,16 @@ C<func()> now gets passed in a C<1>; that is, the number of elements
 in C<@foo>.  And the C<split> gets called in scalar context so it
 starts scribbling on your C<@_> parameter list.  Ouch!
 
+If a sub has both a PROTO and a BLOCK, the prototype is not applied
+until after the BLOCK is completely defined.  This means that a recursive
+function with a prototype has to be predeclared for the prototype to take
+effect, like so:
+
+	sub foo($$);
+	sub foo($$) {
+		foo 1, 2;
+	}
+
 This is all very powerful, of course, and should be used only in moderation
 to make the world a better place.
 
diff --git a/t/comp/proto.t b/t/comp/proto.t
index 947a232..47ebf74 100644
--- a/t/comp/proto.t
+++ b/t/comp/proto.t
@@ -18,7 +18,7 @@ BEGIN {
 # strict
 use strict;
 
-print "1..199\n";
+print "1..201\n";
 
 my $i = 1;
 
@@ -559,6 +559,13 @@ print "ok ", $i++, " star3 STDERR\n";
 print "not " unless eval 'star4 STDERR; 1';
 print "ok ", $i++, " star4 STDERR\n";
 
+# [perl #2726]
+# Test that prototype binding is late
+print "not " unless eval 'sub l564($){ l564(); } 1';
+print "ok ", $i++, " prototype checking not done within initial definition\n";
+print "not " if eval 'sub l566($); sub l566($){ l566(); } 1';
+print "ok ", $i++, " prototype checking done if sub pre-declared\n";
+
 # test scalarref prototype
 sub sreftest (\$$) {
     print "not " unless ref $_[0];
-- 
1.7.9.5

@p5pRT
Copy link
Author

p5pRT commented Aug 6, 2013

From @cpansprout

On Tue Aug 06 00​:36​:02 2013, pcm wrote​:

it knocks this ticket off of the RT queue
:-)

Thank you. Applied as 1cd19e1.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Aug 6, 2013

@cpansprout - Status changed from 'open' to 'resolved'

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

No branches or pull requests

1 participant