http://qs321.pair.com?node_id=11124122


in reply to Re: A short whishlist of Perl5 improvements leaping to Perl7
in thread A short whishlist of Perl5 improvements leaping to Perl7

Yes, simple lexical scoping (a variable is known from its point of declaration to end of scope) and deterministic destructors are two things I find enjoyable when using both Perl and C++ ... and I feel confused and frustrated when forced to use the ugly and complex Python scoping workarounds introduced with the global and nonlocal (sic) keywords.

To give an illustrative example, Python happily compiles and runs the typo-riddled program below, printing vanilla:

icecream_flavour = 'vanilla' # ... if 1: icecream_flavor = 'chocolate' print(icecream_flavour)
while Perl detects the typo at compile-time:
use strict; my $icecream_flavour = 'vanilla'; # ... if (1) { $icecream_flavor = 'chocolate'; } print $icecream_flavour;
with the error message:

Global symbol "$icecream_flavor" requires explicit package name (did you forget to declare "my $icecream_flavor"?) at t1.pl line 5.
Execution of t1.pl aborted due to compilation errors.

Update: As pointed out by LanX below, this is an unfortunate example of Python violating the Zen of Python, specifically "Explicit is better than implicit". I feel it further violates "Beautiful is better than ugly" and "Simple is better than complex" and "Errors should never pass silently" and "If the implementation is hard to explain, it's a bad idea".

See also (further update):

Replies are listed 'Best First'.
Re^3: A short whishlist of Perl5 improvements leaping to Perl7
by Eily (Monsignor) on Nov 24, 2020 at 12:26 UTC

    It took me ages to understand why and how to use the with keyword in python, until I realized it was an at attempt at recreating block-scoped variables.

    I think I already had a similar discussion where LanX pointed out that python variables are lexically scoped as well, but the scope they are lexically bound to is the function, not the block. (perl decided to do block-scoped variables, but you could also imagine limitting the scope to a single expression. For example in push @out, {A => $one, b => $two} while my ($one, undef, $two) = some_function())

      Yes, Python doesn't have block scopes.

      It has 4 scope levels° - it took me a while to understand them - and function scope is the smallest.

      To mimic something similar to blocks you'll need again a named function in Python, since "lambdas" (aka anonymous subs in Perl) are limited to one statement only. Python compensates it by allowing nested named functions, leading to enclosed scope. *

      > push @out, {A => $one, b => $two} while my ($one, undef, $two) = some_function())

      This is certainly not doing what you expect, those $one and $two variables are different.

      DB<17> @out=() DB<18> $x=2; push @out, { A =>$one } while my $one = $x-- DB<19> x @out 0 HASH(0x31f07b8) 'A' => undef 1 HASH(0x31f0410) 'A' => undef DB<20> @out=() DB<21> $x=2; push @out, { A =>$one } while $one = $x-- DB<22> x @out 0 HASH(0x32023b0) 'A' => 2 1 HASH(0x3202428) 'A' => 1 DB<23>

      Please keep in mind that declarations are only effective for following statements.

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery

      °) Local, Global, Built-in, Enclosed

      UPDATE

      *) remember Py's mantra about "explicit is better than implicit"? Perl's scoping rules are explicit ones here (and easier to understand)

        remember Py's mantra about "explicit is better than implicit"? Perl's scoping rules are explicit ones here (and easier to understand)
        Good point. After reading Zen of Python, I suggest Python's scoping rules violate four more principles:
        • Beautiful is better than ugly
        • Simple is better than complex
        • Errors should never pass silently
        • If the implementation is hard to explain, it's a bad idea

        Just remembered I did a Rosetta code node, implementing the same PGA-TRAM algorithm in Perl, Python, Haskell and C++. In Perl I chose simple lexical scoping to data-hide the rtoa hash:

        { my %rtoa = ( M=>1000, D=>500, C=>100, L=>50, X=>10, V=>5, I=>1 ); sub roman_to_dec { reduce { $a+$b-$a%$b*2 } map { $rtoa{$_} } split//, uc(shift) } }

        Not wanting to get a headache from understanding Python scoping, I chose to data-hide the rtoa hash by making it a default function argument instead:

        def roman_to_dec(r, __rtoa = dict(M=1000, D=500, C=100, L=50, X=10, V= +5, I=1) ): return reduce( lambda t,n: t+n-t%n*2, (__rtoa[c] for c in r.upper()) + )

        Suggestions for alternative/better ways to implement this algorithm in Perl and Python are still welcome (11 years later! :).