Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Inconsistent for the sake of convenience

by ELISHEVA (Prior)
on Feb 17, 2009 at 03:22 UTC ( [id://744280]=perlmeditation: print w/replies, xml ) Need Help??

In the past few weeks, thanks to the wonderful Monks, I've discovered at least two examples where Perl parsing seems to be inconsistent for the sake of convenience:
  • regexes: normally $ in a regular expression matches only the end of the string unless the m modifier is used. BUT if the string just happens to end in a new line, $ also matches the just before the terminal newline. jethro explained this as a convenience. (see here for the gory details).
  • while clauses: normally while(expr) terminates when expr is false, but as ikegami informed me here, that is not the case for while($somevar = <...>) and while($somevar = readline(...)). The parser silently converts these to while(defined($somevar = <...>)) and while(defined($somevar = readline(...))). I presume this is also for convenience.

Convenience has been an important part of design of Perl from what I understand. Default variables abound. Typing is implicit. Context affects parsing. There is usually more than one way to do things. But generally, it seems, there is order in the chaos. There are, for example, clear rules for determining when something is list or scalar context and mechanisms for forcing a context if you wish. The same goes for implicit typing. Even the flexibility is consistent.

Arguably, even the two examples above are "consistent". A clearly defined contextual rule exists to predict the behavior of $ and while(...). But in another sense, they are not. The context itself, however clearly defined, is a very narrow context, amounting to a special case.

Inconsistencies are not necessarily bad for a language. Natural language abounds in them, and one of the things I have always admired in Perl is the way it tries to emulate the convenience and flexibility of natural language. And yet they also pose problems for teaching. Languages, even natural languages, that contain lots of special case constructions are much harder to learn well than fairly regular languages.

I'm sure the two examples above are old hat to everyone here, but they were new to me. So now I am wondering what other such "inconsistencies for the sake of convenience" exist in Perl? Would the kind monks care to share additional ones that they have come across? And what are your thoughts on the merits or dismerits of "inconsistency for the sake of convenience?"

Best, beth

Replies are listed 'Best First'.
Re: Inconsistent for the sake of convenience
by ysth (Canon) on Feb 17, 2009 at 05:15 UTC
      So totally awful, I'll have to clean it first.
      $ perl -MO=Deparse blurp.pl # normalize Code with B::Deparse $x[12] = $x[123] = $x = $_ = ''; print "match one\n" if /${x}[123]/; # array fail, characterclass win print "match two\n" if /$x[12]/; blurp.pl syntax OK

      print+qq(\L@{[ref\&@]}@{['@'x7^'!#2/"!4']});
Re: Inconsistent for the sake of convenience
by tilly (Archbishop) on Feb 17, 2009 at 08:34 UTC
    The regular expression behavior is not specific to Perl. Everyone does it that way, and it is done so that $ in regular expressions will behave the way it does in the grep utility.

    If you want a better convenient inconsistent regular expression behavior, ask yourself why the following are not endless loops:

    @matches = ("foo" =~ /o?/g); my @chars = split //, "foo";
    In both cases shouldn't the pattern match before f, then before f, then before f...? See perlre for an explanation. You probably understood the explanation there if you see why pos($string) = pos($string) is not a no-op.

    An inconsistency that I like is the (now useless) feature that the line "nose hairs"; generates a warning but "ignore my nose hairs, please"; does not. See How to make warnings disappear for further discussion and an explanation. It also explains why the feature has been useless since before I learned Perl.

    If you want a lot more inconsistency for the sake of convenience though, consider how context works in Perl and look how core parts of the language such as localtime, grep, and @array behave depending on context.

    And one general thought for this thread. As you review these examples, ask yourself whether it is a coincidence that Larry Wall was a repeat winner of the International Obfuscated C Contest? Or that his 1986 win was in the category Useful Obfuscation?

      Your split example is, of course, inconsistent in a way you didn't mention: but for the magic of split (or lack of magic, as perlre puts it), that // would probably mean /o?/.
Re: Inconsistent for the sake of convenience
by moritz (Cardinal) on Feb 17, 2009 at 08:47 UTC
    when you need inconsistency to achieve convenience, it might mean that you could have a better model.

    For example the while clause could better be written as

    for (<$filehandle>) { ... }

    And it would work without any special magic. People don't do this, because it slurps the while file into memory. But that could be changed. For example by making <$filehandle> return a lazy list, or an iterator that for knows how to iterate.

Re: Inconsistent for the sake of convenience
by Narveson (Chaplain) on Feb 17, 2009 at 15:38 UTC

    The while statement modifier works differently with do than with other statements.

    print "This doesn't print.\n" while 2 + 2 == 5; do {print "But this prints once.\n"} while 2 + 2 == 5;
Re: Inconsistent for the sake of convenience
by blokhead (Monsignor) on Feb 17, 2009 at 18:30 UTC
    My favorite (or least favorite) is when Perl tries to be a functional language and treat the name of a function as a first-order value. In normal circumstances, if foo is a function name, and it's followed by a comma, the meaning is to call foo with no args and return the result. For example:
    print lc, $/; ## ^^ ## call lc with no args, return the result:
    But in places like map EXPR and grep EXPR, it can mean something very different. This is especially bizarre when foo is a built-in that modifies $_ when it is called with no args:
    map chop, @items; ## ^^^^ ## calls map with first argument = sub{ chop; } ## doesn't change current value of $_ anyotherfunc chop, @items; ## ^^^^ ## calls anyotherfunc with first argument = result of chop($_) ## changes current value of $_ !!

    blokhead

      That doesn't actually have anything to do really with function names -- map and grep take an expression, up to the comma, and lambda it, for instance map $_ * $_, 1 .. 10 or grep exists $stuff{$_}, @things. It's syntactic sugar for map BLOCK LIST and grep BLOCK LIST, which are already kind of sugary themselves... but it's consistent if you understand what it does.
Re: Inconsistent for the sake of convenience
by repellent (Priest) on Feb 26, 2009 at 08:27 UTC
    I consider the magic-diamond <> behavior an "inconsistency for the sake of convenience" that is just a horrid inconvenience. This has got to be one of the worst, and it stings with a "What if?" during day-to-day practical use.

    Read more to find out about this feature.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://744280]
Approved by kyle
Front-paged by Arunbear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (2)
As of 2024-04-26 04:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found