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
'no formats' #16135
Comments
From @epaCreated by @epaIt would be useful to have no formats; to turn off, at compile time, features related to formats This is useful because of the fair number of format-only special Perl Info
|
From zefram@fysh.orgEd Avis wrote:
I don't think this justifies a core feature, at least not yet. Thinking in terms of a stricture that disables magic variables, use strict::punctuation qw(except -zefram |
The RT System itself - Status changed from 'new' to 'open' |
From @petdance
Perl::Critic already has a policy that forbids using formats. https://metacpan.org/pod/Perl::Critic::Policy::Miscellanea::ProhibitFormats I could see expanding that to include any format-only variables. |
From @petdance
I wasn’t arguing against the idea. I’d love to see it. I was just pointing out an alternative solution if the original idea doesn’t get implemented. Here’s the ticket I filed: https://github.com/Perl-Critic/Perl-Critic/issues/785 <https://github.com/Perl-Critic/Perl-Critic/issues/785> |
From @AbigailOn Fri, Sep 01, 2017 at 10:32:55PM +0200, Sam Kington wrote:
I don't see the win of requiring people to use "use feature 'foo'" for a There isn't less functionality to support (after all, we're keeping said Abigail |
From @LeontOn Sat, Sep 2, 2017 at 1:58 AM, Abigail <abigail@abigail.be> wrote:
Agreed Leon |
From @TuxOn Fri, 1 Sep 2017 22:32:55 +0200, Sam Kington <sam@illuminated.co.uk>
Where the heroic effort is done by volunteers that care for that Choosing to have that option on or of is easy in your ~/.perlcriticrc $ grep -i format ~/.perlcriticrc So, I have this module installed, but - being a user of formats - I
Interesting question, but what would be the gain. As Abigail already
you assume formats will be deprecated? Why?
You don't know DarkPAN. What is "commonly used"? I *never* used threads in any of my perl scripts. Is that a reason to
-- |
From sam@illuminated.co.uk
Perl::Critic requires a heroic amount of tweaking even to be useful at the minimal level, though. Something that says “I don’t even understand formats, let alone use them” might be useful to people who don’t have the patience to wrangle Perl::Critic. An interesting related question would be: what other parts of Perl are there that could be potentially made optional? Is e.g. dbmopen still core? There’s no reason why “use feature ‘foo’” should be reserved for something that’s new to that particular version of Perl; we could easily say “if you still want to use formats, which aren’t deprecated but aren’t that commonly-used, say use feature ‘formats’” in one version of Perl, and emit warnings if people don’t explicitly use the feature. Sam |
From @xsawyerx On 09/01/2017 09:07 PM, Zefram wrote: Thinking in terms of a stricture that disables magic variables, use strict::punctuation qw(except I actually like this idea.
use punctuation qw( no punctuation qw( $- );
|
From @epaThanks to everyone who has replied. First to say something about formats. I haven't used them, and in my personal and subjective experience, they seem like a relic from another age; one of fixed-width terminal output and monospaced hard copy. If I wanted something fancier than plain text output with the occasional tab, I would generate HTML; for printed documentation I'd use a toolchain that makes PDFs. And what I said here was equally true twenty years ago. However, that is not by any means a reason to remove formats or even to provide a way to disable them. As Abigail notes, it doesn't improve maintainability of the core because now you have two modes to support, with and without formats. And who knows, there may be programmers who make regular use of them. So this bug is not intended as "I do not like formats; please get rid of them". The particular issue is the punctuation variables associated with formats. There are six and some of these two-character sequences can often appear as typos. The common typing mistakes vary by programmer; I often type So it's not really the same as threads or dbmopen(), or even dump(), which may not be much used, but don't affect the language syntax. Perlcritic is a great tool and I use it regularly, but it isn't a replacement for error and warning checking in the language itself. For me at least, it's something to look at as a regular report but not every single time you edit and run the program. If the normal edit-test cycle is to be replaced by edit-perlcritic-test, development becomes a lot slower. As others have noted, perlcritic tends to need a lot of customization and adaptation. It's certainly worth it in the long term, but the more guru-ish issues raised by perlcritic are in a different class from a mistyped variable name. I see it as analogous to "use strict". Why should perl check for mistyped variable names when it's perfectly legal to have both $transformed and $tansformed in your code, and perfectly legal to call &{"hello"}()? You can always have a perlcritic policy for that. And it means that the perl core now has to support running both with 'strict' and without. Yet checking for these typos saves so much development time, and doing it in the core is much faster than as an external linter, that it's worth having (and in my opinion, is one of the big plus points for Perl compared with other scripting languages). Zefram's idea of disabling particular punctuation variables may be the way to go. As noted, the bug is not really about formats but just about Or if you forget the emphasis on formats and just cover magic variables in general, it could be used to address what I feel is another of the "paper cuts" in the language, the special behaviour of $a and $b. The crystal chamber could be used to change these to ordinary variable names. -- |
From @tonycozOn Mon, 04 Sep 2017 02:01:24 -0700, ed wrote:
Something like the attached? Tony |
From @tonycoz0001-perl-132013-implement-strict-punctuation.patchFrom cc93575397fe3016d970743ca9727aa19a83bb49 Mon Sep 17 00:00:00 2001
From: Tony Cook <tony@develop-help.com>
Date: Thu, 19 Oct 2017 16:43:51 +1100
Subject: (perl #132013) implement strict::punctuation
---
MANIFEST | 2 +
Porting/Maintainers.pl | 1 +
gv.c | 52 +++++++++++
lib/strict/punctuation.pm | 214 ++++++++++++++++++++++++++++++++++++++++++++++
lib/strict/punctuation.t | 155 +++++++++++++++++++++++++++++++++
pod/perldiag.pod | 5 ++
6 files changed, 429 insertions(+)
create mode 100644 lib/strict/punctuation.pm
create mode 100644 lib/strict/punctuation.t
diff --git a/MANIFEST b/MANIFEST
index 124812b..52413f1 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -4683,6 +4683,8 @@ lib/sort.pm For "use sort"
lib/sort.t See if "use sort" works
lib/strict.pm For "use strict"
lib/strict.t See if strictures work
+lib/strict/punctuation.pm Enable or disable punctuation variables
+lib/strict/punctuation.t See if strict::punctuation works
lib/subs.pm Declare overriding subs
lib/subs.t See if subroutine pseudo-importation works
lib/Symbol.pm Symbol table manipulation routines
diff --git a/Porting/Maintainers.pl b/Porting/Maintainers.pl
index 9c8c128..68e95b4 100755
--- a/Porting/Maintainers.pl
+++ b/Porting/Maintainers.pl
@@ -1437,6 +1437,7 @@ use File::Glob qw(:case);
lib/sigtrap.{pm,t}
lib/sort.{pm,t}
lib/strict.{pm,t}
+ lib/strict/punctuation.{pm,t}
lib/subs.{pm,t}
lib/unicore/
lib/utf8.{pm,t}
diff --git a/gv.c b/gv.c
index fed5b7c..9d2b0b8 100644
--- a/gv.c
+++ b/gv.c
@@ -1766,6 +1766,36 @@ S_gv_is_in_main(pTHX_ const char *name, STRLEN len, const U32 is_utf8)
return FALSE;
}
+static int
+punct_bit_number(svtype sv_type, U8 ch) {
+ /* This needs to match _punct_bit() in strict::punctation */
+ int base = sv_type == SVt_PV ? 0 :
+ sv_type == SVt_PVAV ? 1 :
+ sv_type == SVt_PVHV ? 2 : -1;
+ ch = NATIVE_TO_LATIN1(ch);
+
+ assert(sv_type == SVt_PV || sv_type == SVt_PVAV || sv_type == SVt_PVHV);
+ if (ch == 95) { /* _ */
+ return base;
+ }
+ else if (ch >= 33 && ch < 48) { /* ! .. / */
+ return base + 3 * (ch - 32);
+ }
+ else if (ch >= 58 && ch < 65) { /* : .. @ */
+ return base + 3 * (ch - 42);
+ }
+ else if (ch >= 91 && ch < 97) { /* [ .. ^ */
+ /* yes, this leaves an unused bit for _ */
+ return base + 3 * (ch - 68);
+ }
+ else if (ch == 126) { /* ~ */
+ return base + 3 * (ch - 97);
+ }
+ else {
+ return -1;
+ }
+}
+
/* This function is called if parse_gv_stash_name() failed to
* find a stash, or if GV_NOTQUAL or an empty name was passed
@@ -1784,7 +1814,29 @@ S_find_default_stash(pTHX_ HV **stash, const char *name, STRLEN len,
/* No stash in name, so see how we can default */
if ( gv_is_in_main(name, len, is_utf8) ) {
+ int bit;
+ SV *punct_bits;
+
*stash = PL_defstash;
+ if (IN_PERL_COMPILETIME && add &&
+ (PL_hints & HINT_LOCALIZE_HH) != 0 &&
+ (sv_type == SVt_PV || sv_type == SVt_PVAV || sv_type == SVt_PVHV) &&
+ len == 1 &&
+ (bit = punct_bit_number(sv_type, (U8)*name)) != -1 &&
+ (punct_bits = cop_hints_fetch_pvs(PL_curcop, "strict::punctuation", 0)) != &PL_sv_placeholder
+ ) {
+ STRLEN len;
+ U8 *bits = (U8*)SvPV(punct_bits, len);
+ if (Off((unsigned)bit) >= len || !IsSet(bits, (unsigned)bit)) {
+ qerror(Perl_mess(aTHX_
+ "Punctuation variable '%s%s' disabled by strict::punctuation",
+ (sv_type == SVt_PV ? "$"
+ : sv_type == SVt_PVAV ? "@"
+ : sv_type == SVt_PVHV ? "%"
+ : ""), name));
+ }
+ }
+
}
else {
if (IN_PERL_COMPILETIME) {
diff --git a/lib/strict/punctuation.pm b/lib/strict/punctuation.pm
new file mode 100644
index 0000000..170b8c9
--- /dev/null
+++ b/lib/strict/punctuation.pm
@@ -0,0 +1,214 @@
+package strict::punctuation;
+use strict;
+use warnings;
+use v5.26.0;
+
+our $VERSION = '1.000';
+
+our @CARP_NOT = __PACKAGE__;
+
+sub _croak {
+ require Carp;
+ goto &Carp::croak;
+}
+
+sub _punct_bit {
+ # we want ASCII-ish numbering here
+ my $o = ord(utf8::native_to_unicode(substr($_[0], 1)));
+ my $sigil = substr($_[0], 0, 1);
+ my $base =
+ $sigil eq '$' ? 0 :
+ $sigil eq '@' ? 1 :
+ $sigil eq '%' ? 2 :
+ return;
+ if ($o == 95) { # _
+ return $base;
+ }
+ elsif ($o >= 33 && $o < 48) {
+ return $base + 3 * ($o - 32);
+ }
+ elsif ($o >= 58 && $o < 65) {
+ return $base + 3 * ($o - 42);
+ }
+ elsif ($o >= 91 && $o < 97) {
+ # yes, this leaves an unused bit for _
+ return $base + 3 * ($o - 68);
+ }
+ elsif ($o == 126) {
+ return $base + 3 * ($o - 97);
+ }
+ else {
+ return;
+ }
+}
+
+my $def_bits;
+my $all_bits;
+my $key = "strict::punctuation";
+{
+ vec($def_bits, _punct_bit('$_'), 1) = 1;
+ vec($def_bits, _punct_bit('@_'), 1) = 1;
+ $all_bits = "\xFF" x ((_punct_bit('%~') + 7) / 8);
+}
+
+my %groups =
+ (
+ regex => [ qw($& $` $' $+ @+ %+ @- %-) ],
+ formats => [ qw($% $: $= $^ $~) ],
+ users => [ qw($< $>) ],
+ groups => [ qw[$( $)] ],
+ files => [ qw($. $/ $\ $|), '$,' ],
+ errors => [ qw($! $@ $? %!) ],
+ );
+
+sub _do_bits {
+ my $value = shift;
+
+ my $bits = $^H{$key} || $def_bits;
+ if (@_) {
+ if ($_[0] eq ':none') {
+ shift;
+ $bits = $value ? '' : $all_bits;
+ }
+ elsif ($_[0] eq ':all') {
+ shift;
+ $bits = $value ? $all_bits : '';
+ }
+ }
+ while (defined(my $var = shift)) {
+ if ($var =~ s/^://) {
+ $groups{$var}
+ or _croak("Unknown punctuation variable group :$var");
+ unshift @_, @{$groups{$var}};
+ }
+ elsif ($var =~ s/^-://) {
+ $groups{$var}
+ or _croak("Unknown punctuation variable group :$var");
+ unshift @_, map "-$_", @{$groups{$var}};
+ }
+ else {
+ my $set = $value;
+ $set = !$set if $var =~ s/^-//;
+ my $bit = _punct_bit($var);
+ defined $bit
+ or _croak("Unknown punctuation variable $var");
+ vec($bits, $bit, 1) = $set;
+ }
+ }
+ $bits =~ s/\0+\z//g;
+ if ($bits eq $all_bits) {
+ delete $^H{$key};
+ }
+ else {
+ $^H{$key} = $bits;
+ }
+}
+
+sub import {
+ shift;
+ _do_bits(1, @_);
+}
+
+sub unimport {
+ shift;
+ _do_bits(0, @_);
+}
+
+1;
+
+=head1 NAME
+
+strict::punctuation - disable/enable punctuation variables lexically
+
+=head1 SYNOPSIS
+
+ use strict::punctuation;
+ # only $_ and @_ enabled
+ use strict::punctuation '$!';
+ # can now use $!
+ use strict::punctuation ':errors';
+ # can now use $!, $@, $? and %!
+ no strict::punctuation ':errors';
+ # can't use $! etc
+
+=head1 DESCRIPTION
+
+The C<strict::punctuation> pragma disables most punctuation variables
+to prevent accidental use of the wrong variables.
+
+By default the C<$_> and C<@_> variables remain enabled, but they can
+also be disabled by explicitly disabling them, or with the C<:none>
+group:
+
+ use strict::punctuation qw(-$_ -@_);
+ no strict::punctuation qw($_ @_);
+ use strict::punctuation ':none';
+
+You can enable or disable punctuation variables either individually or
+in groups:
+
+ use strict::punctuation qw($! $@ $? %!);
+ use strict::punctuation ':errors';
+
+You can prefix a variable name or most groups to reverse the
+operation:
+
+ use strict::punctuation '-$!'; # disable $!
+ no strict::punctuation '-$!'; # enable $!
+
+This is most useful when combining elements:
+
+ # enable all error variables except for $?
+ use strict::punctuation ':errors', '-$?';
+
+=head2 Variable Groups
+
+=over
+
+=item *
+
+C<:all> - all punctuation variables. This can only be at the
+beginning of the import list and cannot be negated.
+
+ # enable all but $!
+ use strict::punctuation ':all', '-$!';
+
+=item *
+
+C<:none> - no variables. This can only be at the beginning of the
+import list and cannot be negated.
+
+ # only $! is enabled
+ use strict::punctuation ':none', '$!';
+
+=item *
+
+C<:regex> - enable regular expression punctuation variables. C<$&>,
+C<$`>, C<$'>, C<$+>, C<@+>, C<%+>, C<@-> and C<%->.
+
+=item *
+
+C<:formats:> - enable punctuation variables associated with formats.
+C<$%>, C<$:>, C<$=>, C<$^> and C<$~>.
+
+=item *
+
+C<:users> - the C<< $< >> and C<< $> >> variables.
+
+=item *
+
+C<:groups> - the C<$(> and C<$)> variables.
+
+=item *
+
+C<:files> - punctuation variables associated with file handling.
+C<$.>, C<$/>, C<$\>, C<$|> and C<$,>.
+
+=item *
+
+C<:errors> - punctuation variables associated with errors. C<$!>,
+C<$@>, C<$?> and C<%!>.
+
+=back
+
+=cut
diff --git a/lib/strict/punctuation.t b/lib/strict/punctuation.t
new file mode 100644
index 0000000..afe815c
--- /dev/null
+++ b/lib/strict/punctuation.t
@@ -0,0 +1,155 @@
+#!perl
+
+BEGIN {
+ chdir 't' if -d 't';
+ require "./test.pl";
+ set_up_inc(".", "../lib");
+}
+
+run_multiple_progs('', \*DATA);
+
+done_testing();
+
+__END__
+# NAME strict::punctuation defaults
+use strict::punctuation;
+my $x = $_;
+my @x = @_;
+my %x = %_;
+$x = $!;
+@x = @!;
+%x = %!;
+print "Fail\n";
+EXPECT
+OPTIONS fatal
+Punctuation variable '%_' disabled by strict::punctuation at - line 4.
+Punctuation variable '$!' disabled by strict::punctuation at - line 5.
+Punctuation variable '@!' disabled by strict::punctuation at - line 6.
+Punctuation variable '%!' disabled by strict::punctuation at - line 7.
+BEGIN not safe after errors--compilation aborted at - line 7.
+########
+# NAME strict::punctuation disable $_
+no strict::punctuation '$_';
+my $x = $_;
+use strict::punctuation '$_';
+my $y = $_;
+EXPECT
+OPTIONS fatal
+Punctuation variable '$_' disabled by strict::punctuation at - line 2.
+BEGIN not safe after errors--compilation aborted at - line 3.
+########
+# NAME strict::punctuation disable $_
+my $z = $_;
+no strict::punctuation '$_';
+my $x = $_;
+use strict::punctuation '$_';
+my $y = $_;
+EXPECT
+OPTIONS fatal
+Punctuation variable '$_' disabled by strict::punctuation at - line 3.
+BEGIN not safe after errors--compilation aborted at - line 4.
+########
+# NAME test - prefix
+my $x = $_;
+use strict::punctuation '-$_', '$!';
+die $!;
+my $y = $_;
+EXPECT
+OPTIONS fatal
+Punctuation variable '$_' disabled by strict::punctuation at - line 4.
+Execution of - aborted due to compilation errors.
+########
+# NAME strict::punctuation disable @_
+sub foo {
+ my @x = @_;
+ use strict::punctuation '@_';
+ my @y = @_;
+ no strict::punctuation '@_';
+ my @z = @_;
+}
+EXPECT
+OPTIONS fatal
+Punctuation variable '@_' disabled by strict::punctuation at - line 6.
+Execution of - aborted due to compilation errors.
+########
+# NAME regex group (and - on groups)
+"a" =~ /(1)/;
+my $x = $';
+my $y = $&;
+my $z = $`;
+my $w = $+;
+my @x = @-;
+my @y = @+;
+my %x = %-;
+my %y = %+;
+use strict::punctuation ':regex';
+$x = $';
+$y = $&;
+$z = $`;
+$w = $+;
+@x = @-;
+@y = @+;
+%x = %-;
+%y = %+;
+use strict::punctuation '-:regex';
+$x = $';
+$y = $&;
+$z = $`;
+$w = $+;
+@x = @-;
+@y = @+;
+%x = %-;
+%y = %+;
+EXPECT
+OPTIONS fatal
+Punctuation variable '$'' disabled by strict::punctuation at - line 20.
+Punctuation variable '$&' disabled by strict::punctuation at - line 21.
+Punctuation variable '$`' disabled by strict::punctuation at - line 22.
+Punctuation variable '$+' disabled by strict::punctuation at - line 23.
+Punctuation variable '@-' disabled by strict::punctuation at - line 24.
+Punctuation variable '@+' disabled by strict::punctuation at - line 25.
+Punctuation variable '%-' disabled by strict::punctuation at - line 26.
+Punctuation variable '%+' disabled by strict::punctuation at - line 27.
+Execution of - aborted due to compilation errors.
+########
+# NAME errors group
+$! = 0;
+$@ = '';
+$? = 0;
+my @x = keys %!;
+use strict::punctuation ':errors';
+$! = 0;
+$@ = '';
+$? = 0;
+@x = keys %!;
+no strict::punctuation ':errors';
+$! = 0;
+$@ = '';
+$? = 0;
+my @x = keys %!;
+EXPECT
+OPTIONS fatal
+Punctuation variable '$!' disabled by strict::punctuation at - line 11.
+Punctuation variable '$@' disabled by strict::punctuation at - line 12.
+Punctuation variable '$?' disabled by strict::punctuation at - line 13.
+Punctuation variable '%!' disabled by strict::punctuation at - line 14.
+Execution of - aborted due to compilation errors.
+########
+# NAME all group
+use strict::punctuation ':all';
+my $x = $_;
+no strict::punctuation ':all';
+my $x = $_;
+EXPECT
+OPTIONS fatal
+Punctuation variable '$_' disabled by strict::punctuation at - line 4.
+Execution of - aborted due to compilation errors.
+########
+# NAME none group
+use strict::punctuation ':none', '$!';
+my $x = $_;
+$! = 0;
+EXPECT
+OPTIONS fatal
+Punctuation variable '$_' disabled by strict::punctuation at - line 2.
+Execution of - aborted due to compilation errors.
diff --git a/pod/perldiag.pod b/pod/perldiag.pod
index d417fb2..43c3cde 100644
--- a/pod/perldiag.pod
+++ b/pod/perldiag.pod
@@ -5079,6 +5079,11 @@ the sub name and via the prototype attribute. The prototype in
parentheses is useless, since it will be replaced by the prototype
from the attribute before it's ever used.
+=item Punctuation variable '%s' disabled by strict::punctuation
+
+(F) You've attemptted to use a punctuation variable that you've
+disabled with the L<strict::punctuation> pragma.
+
=item Quantifier follows nothing in regex; marked by S<<-- HERE> in m/%s/
(F) You started a regular expression with a quantifier. Backslash it if
--
2.1.4
|
From @epaOn Mon, 23 Oct 2017 22:10:46 -0700, tonyc wrote:
Yes, that looks great (based on reading the documentation). Although you have provided a few canned presets, I envisage that the exact selection would often be done in a 'style' module like Modern::Perl. Personally, I would set it to a small change at first, only disabling those punctuation variables which are truly obscure and obsolete, like $[. (I do still like the idea of 'no formats', with 'use formats' enabling both the format keywords and the associated punctuation variables, but I understand that it's kind of unrelated to the key issue in this bug, which is to get more useful diagnostics out of the parser for typing errors.) |
From @epaAnd thank you! |
Migrated from rt.perl.org#132013 (status was 'open')
Searchable as RT132013$
The text was updated successfully, but these errors were encountered: