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

when() as a statement modifier outside a topicalizer both works and fails #10589

Closed
p5pRT opened this issue Aug 30, 2010 · 9 comments
Closed

Comments

@p5pRT
Copy link

p5pRT commented Aug 30, 2010

Migrated from rt.perl.org#77510 (status was 'rejected')

Searchable as RT77510$

@p5pRT
Copy link
Author

p5pRT commented Aug 30, 2010

From @briandfoy

Created by @briandfoy

Perl 5.12 allows when() as a statement modifier. I think this
is only intended inside a topicalizer, but it parses just
fine outside a topicalizer.

This script compiles just fine​:

  use 5.012;
 
  my %microchips = (
  'Mimi' => 123,
  'Buster' => undef,
  'Roscoe' => 345,
  );
 
  say "Known cats are @​{[keys %microchips]}\n";
  {
  print "Enter a cat name> ";
  chomp( $_ = <STDIN> );
  say "Found cat with id $microchips{$_}" when %microchips;
  redo;
  }

Now, when I run this and respond to a prompt with a cat's name
that is in the hash, the say() outputs its message and Perl
dies​:

  Buster
  Found cat with id
  Can't use when() outside a topicalizer at test line 11, <STDIN> line

That's fine, but I don't get the same error when I respond with
a cat's name that is not in the hash​:

  Enter a cat name> Ella
  Enter a cat name> Buster
  Found cat with id
  Can't use when() outside a topicalizer at test line 12, <STDIN> line 2.

That is, the when() always works. If its condition is true, it also dies. If
its condition is false, it does not die.

I verified this with all released versions of 5.12 and 5.13.

I figure this should be a compile-time error, or, if we're really lazy, just
never die.

Perl Info

Flags:
    category=core
    severity=medium

Site configuration information for perl 5.12.1:

Configured by brian at Wed Jun 16 15:54:54 PDT 2010.

Summary of my perl5 (revision 5 version 12 subversion 1) configuration:

  Platform:
    osname=darwin, osvers=9.8.0, archname=darwin-2level
    uname='darwin mimibean.local 9.8.0 darwin kernel version 9.8.0:
wed jul 15 16:55:01 pdt 2009; root:xnu-1228.15.4~1release_i386 i386
i386 '
    config_args='-des -Dprefix=/usr/local/perls/perl-5.12.1'
    hint=recommended, useposix=true, d_sigaction=define
    useithreads=undef, usemultiplicity=undef
    useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef
    use64bitint=undef, use64bitall=undef, uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='cc', ccflags ='-fno-common -DPERL_DARWIN -no-cpp-precomp
-fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include',
    optimize='-O3',
    cppflags='-no-cpp-precomp -fno-common -DPERL_DARWIN
-no-cpp-precomp -fno-strict-aliasing -pipe -fstack-protector
-I/usr/local/include'
    ccversion='', gccversion='4.0.1 (Apple Inc. build 5490)', gccosandvers=''
    intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16
    ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t',
lseeksize=8
    alignbytes=8, prototype=define
  Linker and Libraries:
    ld='env MACOSX_DEPLOYMENT_TARGET=10.3 cc', ldflags ='
-fstack-protector -L/usr/local/lib'
    libpth=/usr/local/lib /usr/lib
    libs=-ldbm -ldl -lm -lutil -lc
    perllibs=-ldl -lm -lutil -lc
    libc=/usr/lib/libc.dylib, so=dylib, useshrplib=false, libperl=libperl.a
    gnulibc_version=''
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=bundle, d_dlsymun=undef, ccdlflags=' '
    cccdlflags=' ', lddlflags=' -bundle -undefined dynamic_lookup
-L/usr/local/lib -fstack-protector'

Locally applied patches:



@INC for perl 5.12.1:
    /usr/local/perls/perl-5.12.1/lib/site_perl/5.12.1/darwin-2level
    /usr/local/perls/perl-5.12.1/lib/site_perl/5.12.1
    /usr/local/perls/perl-5.12.1/lib/5.12.1/darwin-2level
    /usr/local/perls/perl-5.12.1/lib/5.12.1
    .


Environment for perl 5.12.1:
    DYLD_LIBRARY_PATH (unset)
    HOME=/Users/brian
    LANG=en_US
    LANGUAGE (unset)
    LC_ALL=C
    LC_COLLATE=en_US.UTF-8
    LC_CTYPE=en_US.UTF-8
    LC_MESSAGES=en_US.UTF-8
    LC_MONETARY=en_US.UTF-8
    LC_NUMERIC=en_US.UTF-8
    LC_TIME=en_US.UTF-8
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PATH=/Users/brian/bin:/usr/local/bin:/opt/local/bin:/Users/brian/TPR/scripts:/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/mysql/bin:/usr/X11R6/bin:/usr/local/teTeX/bin/powerpc-apple-darwin-current:/usr/local/pgsql/bin:/usr/local/gcj/bin:/Library/Frameworks/Python.framework/Versions/Current/bin
    PERL_BADLANG (unset)
    SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Aug 30, 2010

From perl@profvince.com

Perl 5.12 allows when() as a statement modifier. I think this
is only intended inside a topicalizer, but it parses just
fine outside a topicalizer.

...

That is, the when() always works. If its condition is true, it also dies. If
its condition is false, it does not die.
Thanks for your report. The same behaviour happens if "when" isn't a
statement modifier :

  $ perl -wE '$_ = "abc"; { when (/x/) { say "contains x" }; when
(/b/) { say "contains b" }; say "end" }'
  contains b
  Can't use when() outside a topicalizer at -e line 1.

  $ perl -wE '$_ = "abc"; { say "contains x" when /x/; say "contains
b" when /b/; say "end" }'
  contains b
  Can't use when() outside a topicalizer at -e line 1.

I verified this with all released versions of 5.12 and 5.13.

I figure this should be a compile-time error, or, if we're really lazy, just
never die.
I don't think we can make it a compile time error, because you don't
always know at compile time if "when" is inside a for or a given block :

  $ perl -wE 'sub check { my $x = shift; say "contains $x" when /$x/ }
$_ = "abc"; { check("x"); check("b"); say "end" }'
  contains b
  Can't use when() outside a topicalizer at -e line 1.

  $ perl -wE 'sub check { my $x = shift; when (/$x/) { say "contains
$x" } } $_ = "abc"; { check("x"); check("b"); say "end" }'
  contains b
  Can't use when() outside a topicalizer at -e line 1.

Vincent.

@p5pRT
Copy link
Author

p5pRT commented Aug 30, 2010

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

@p5pRT
Copy link
Author

p5pRT commented Aug 30, 2010

From @briandfoy

In article <4C7B6AF4.7000207@​profvince.com>, Vincent Pit
<perl@​profvince.com> wrote​:

I verified this with all released versions of 5.12 and 5.13.

I figure this should be a compile-time error, or, if we're really lazy, just
never die.

I don't think we can make it a compile time error, because you don't
always know at compile time if "when" is inside a for or a given block :

I don't see how your examples illustrate that, but I don't think that
calling a subroutine that contains a when() should qualify as "inside a
topicalizer" because you call the subroutine inside a topicalizer. I'm
not sure why you'd even try to do that since the topic shouldn't be
visible in the subroutine.

@p5pRT
Copy link
Author

p5pRT commented Aug 30, 2010

From perl@profvince.com

I don't think we can make it a compile time error, because you don't
always know at compile time if "when" is inside a for or a given block :
I don't see how your examples illustrate that,
Because at the moment the sub is compiled, it is of course apparently
not inside any for/given block. Yet it can be called at run-time while
inside one of these and this is prefectly correct.

but I don't think that
calling a subroutine that contains a when() should qualify as "inside a
topicalizer" because you call the subroutine inside a topicalizer. I'm
not sure why you'd even try to do that since the topic shouldn't be
visible in the subroutine
Not with given, as it lexicalises $_, but for loops only localises the
global $_. This is what allows for example the nifty syntax of using
when() inside Try​::Tiny's catch blocks.

Although it is valid, I'll agree that it is kind of misleading of
calling when() inside given() but not in the same lexical scope, because
when() picks up the global $_ :

  $ perl -wE 'sub check { say "fail" when /x/ } $_ = "xyz"; for
("abc") { check(); } say "end"'
  end

  $ perl -wE 'sub check { say "fail" when /x/ } $_ = "xyz"; given
("abc") { check(); } say "end"'
  fail
  end

Vincent.

@p5pRT
Copy link
Author

p5pRT commented Aug 19, 2012

From @cpansprout

On Sun Aug 29 22​:29​:58 2010, comdog wrote​:

This is a bug report for perl from brian.d.foy@​gmail.com,
generated with the help of perlbug 1.39 running under perl 5.12.1.

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

Perl 5.12 allows when() as a statement modifier. I think this
is only intended inside a topicalizer, but it parses just
fine outside a topicalizer.

This script compiles just fine​:

use 5\.012;

my %microchips = \(
      'Mimi'   => 123\,
      'Buster' => undef\,
      'Roscoe' => 345\,
    \);

say "Known cats are @&#8203;\{\[keys %microchips\]\}\\n";
\{
print "Enter a cat name> ";
chomp\( $\_ = \<STDIN> \);
say "Found cat with id $microchips\{$\_\}" when %microchips;
redo;
\}

Now, when I run this and respond to a prompt with a cat's name
that is in the hash, the say() outputs its message and Perl
dies​:

Buster
Found cat with id
Can't use when\(\) outside a topicalizer at test line 11\, \<STDIN> line

That's fine, but I don't get the same error when I respond with
a cat's name that is not in the hash​:

Enter a cat name> Ella
Enter a cat name> Buster
Found cat with id
Can't use when\(\) outside a topicalizer at test line 12\, \<STDIN> line

2.

That is, the when() always works. If its condition is true, it also
dies. If
its condition is false, it does not die.

I verified this with all released versions of 5.12 and 5.13.

I figure this should be a compile-time error, or, if we're really
lazy, just
never die.

Clarifying the error message might help. If we make it clear that
‘when’ is having trouble *exiting* a topicalizer, I think that would be
good enough. But I can’t find a good way of wording it.

We currently have​:

Can't "when" outside a topicalizer

But it should be more like​:

"when" can't break outside a topicalizer

But ‘break outside’ could be misconstrued as ‘break out of’. Maybe​:

"when" can't break without a topicalizer

(The archaistic could make the same argument about that one.)

"when" can't find a topicalizer to exit
"when" can't break except from inside a topicalizer

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Jul 21, 2013

From @rjbs

* Father Chrysostomos via RT <perlbug-followup@​perl.org> [2012-08-19T15​:07​:16]

"when" can't find a topicalizer to exit

FWIW, I like this one.

--
rjbs

@p5pRT
Copy link
Author

p5pRT commented Dec 11, 2017

From zefram@fysh.org

It's a deliberate design choice that topicalisers are dynamically scoped.
We no longer have the lexical $_ confusing things, so the topic itself
is now always dynamically scoped too. There is no bug here. (This is
also unaffected by the present proposed revision of smartmatch et al.)
This ticket should be closed.

-zefram

@p5pRT
Copy link
Author

p5pRT commented Dec 11, 2017

@iabyn - Status changed from 'open' to 'rejected'

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