Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

Perl oddities

by brian_d_foy (Abbot)
on Mar 01, 2005 at 09:58 UTC ( [id://435338]=perlmeditation: print w/replies, xml ) Need Help??

Do you have a list of things that you find odd about Perl? I'm not talking about what you don't like, but things that just don't seem to fit in, as if they were exceptions to normal Perl thinking.

Since Perl draws from so many other things, it's going to be a mish-mash of things. Perl can't very well help that libc functions do things a certain ways, or that it wanted to bridge a couple of languages. Still, there are things that make we wonder. What makes you think "Huh?" Here's three of mine:

-M, -A, and -C units

The -M, -A, and -C file test operators return the file modification, access, and creation times in days since the start of the program. Why? Why why why? Does anyone actually use the values for anything other than to compare them to each other?

mkdir() and rmdir()

The libc mkdir(), chmod(), chown(), rmdir(), and unlink() functions take the file name first, and so do Perl's mkdir() and rmdir(). However, the Perl versions of the other functions take lists of files to affect. Perl's mkdir() and rmdir() doesn't. I always want to put the directory names second in mkdir().

int mkdir(const char *path, mode_t mode); int rmdir(const char *path); int chmod(const char *path, mode_t mode); int chown(const char *path, uid_t owner, gid_t group); int unlink(const char *path);

The Perl chown() and chmod() functions take the file names last, which is a good thing so they can affect a lot of files. To me, mkdir() breaks the rule because it's the only thing that doesn't take a list of names.

print FH @list

You don't put a comma between the filehandle name and the list you give to print. I've just always thought that was odd, and I go out of my way to point it out to people in Perl classes. I don't have a problem with this while I code, but I still think it's an odd corner of syntax.

--
brian d foy <bdfoy@cpan.org>

Replies are listed 'Best First'.
Re: Perl oddities
by jmcnamara (Monsignor) on Mar 01, 2005 at 10:40 UTC

    I find the return value of a hash in a scalar context odd.
    $ perl -le '%h = (a =>1, b => 2); print scalar %h' 2/8
    From perldata:
    If you evaluate a hash in scalar context ... the value returned is a string consisting of the number of used buckets and the number of allocated buckets ...

    Buckets!

    I can't imagine that this is useful to anyone except the implementor of the hashing function and the occasional person with pathological data.

    It would be much more useful, or sensible, if hash in a scalar context returned the number of keys:

    $ perl -le '%h = (a =>1, b => 2); print scalar keys %h' 2

    And before anyone leaps to the defense of this artifact I'm just stating that I find it odd. I can live with it.

    I think that there were a lot of things that I used to find odd but since I can't remember what they are I guess that I've just come to accept them. :-)

    --
    John.

      In Perl 6, a hash in scalar context will return a reference to the hash, which will behave appropriately in boolean, numeric, or string contexts. (You'll have to call a special method to get the bucket filling information.) I'd like to note for the record, however, that the main reason hashes did not return the number of keys by default in numeric context in Perl 5 was that it was potentially a very expensive operation on DBM files and the like. But Perl 6 will gladly let you hang yourself by the foot there...
      I also find this artifact useless, but a saving grace is that you can at least say:
      if (%hash) { # it's not empty }
      even though the string "0/8" evaluates to true.
      Update: Nonsense below, I misread the post.

      It would be much more useful, or sensible, if hash in a scalar context returned the number of keys:
      As soon as you try to use it as a number, "2/8" will be numified to 2 so actually it does effectively return the number keys.
      perl -le '%h = (a =>1, b => 2); print %h+0' 2
      The number of buckets is some bonus info for free.

        In the above case yes but as the number of keys is increased the buckets will get reused and the result won't be correct:
        $ perl -le '%h = (1 .. 10); print scalar %h' 5/8 $ perl -le '%h = (1 .. 12); print scalar %h' 5/8 $ perl -le '%h = (1 .. 100); print scalar %h' 33/64
        :-)

        Actually, I searched for a genuine use for this feature for a long time and I almost found one: Power Twool.

        --
        John.

Re: Perl oddities
by Anonymous Monk on Mar 01, 2005 at 12:10 UTC
    • system returning true on failure, false on success. I know why it's doing that, I know where it's coming from (and that's why), but it still makes me gag each and every time I use it.
    • open not returning a file handle, but modifying its first argument. There are other functions modifying their first argument (push and friends, 4-arg substr, chomp/chop), but you kind of expect those. open doing so seems to do it for no other reason of mimicing the underlaying C functionality.
    • Perl has every important flow control keyword used by other important languages, and then some. But it doesn't have a (native) switch. Or rather, it still doesn't have one. While it was on the wishlist of perl 1.0.0.
    • Ok, so Perl has this IO system that used to be a thin layer over your systems IO system, and now (with PerlIO) mimics it, but still looks the same. And while I can easily lock entire files, why can't I easily lock file regions on systems that support it?
    • perl -wce 'chomp ($_)' -e syntax OK perl -wce '$_ = log ($_)' -e syntax OK perl -wce 'print ($_)' print (...) interpreted as function at -e line 1. -e syntax OK perl -wce 'print ($_)' -e syntax OK
      Warn (wrongly) for one particular function, if you have exactly one space between the function name and the opening paren?
      Now that Perl 6 has interesting values of undef, it's easy to fix system, though we will probably rename it just to avoid confusion. Make it sysrun, or maybe just run.

      open returns a filehandle object in Perl 6.

      Perl 6 will have a switch statement because we finally figured out how it relates to smart matching and topicalization and exception handlers.

      The IO system for Perl 6 will be truly OO and not just made to look that way like Perl 5 did. So it'll be fairly easy to have whatever odd methods you like on derived IO classes, including regional locking.

      The parsing rules for function parentheses have been regularized in Perl 6, though not necessarily to everyone's delight. ;-)

      system returning true on failure, false on success. I know why it's doing that, I know where it's coming from (and that's why), but it still makes me gag each and every time I use it.

      I think Larry realises this. I'm hoping that Perl6's system function knows to do something like return $rc but ! $rc. Then 0 would be true and non-zero would be false, when checked in boolean context, but the return code would still be available:

      my $rc = system(...); unless ($rc) { print "system failed with rc = $rc!\n"; }
      (Or something like that - my perl6 isn't rusty, it's just not there yet ;->)

      But it doesn't have a (native) switch.

      No fair, picking on explicit design decisions. :-)

      Warn (wrongly) for one particular function

      What's wrong about the warning? It's there to prevent the common pitfall of expecting things like this to work right:

      print (stat)[9];

      And seems like a perfectly reasonable warning. Many other warnings are special-cased and very specific, so I don't know why you chose this one.

      Update: I didn't realize the warning would trigger with one and only one space. That does seem kind of peculiar. But if that was the crux of what the OP was talking about, it wasn't exactly clear.

        What's wrong about the warning? It's there to prevent the common pitfall of expecting things like this to work right:
        print (stat)[9];
        His point was the warning cares about exactly one space. Why it shouldn't it give the same warning for these also?
        print(stat)[9] print (stat)[9]
        is obtuse. I'm sure there are a hundred root nodes on this site alone about abuse of white space, so I'll defer to them.

        -QM
        --
        Quantum Mechanics: The dreams stuff is made of

        As noted, I find the oddity in that it warns about exactly one space - althought it doesn't do that always:
        perl -wle 'print ("foo")' # Warning perl -wle 'print ("foo");' # No warning perl -wle 'print (")");' # Warning perl -wle 'print ("\x29");' # No warning
        Now, I know why it's happening (I've studied the source), and I also know what the intent is, but that's beside the point. brian asked about oddities, and I do find this an oddity.

        But the single space is not the only thing that I find an oddity. I also find it odd (as in, irregular, different that you would expect based on how similar constructs are handled - you know, what brian was asking for - so spare me the explainations on why it is this way - I know already) that is only has these warnings for print and I think one other function. For other functions, it doesn't warn.

        $ perl -wle 'print ("foo") . "bar"' print (...) interpreted as function at -e line 1. Useless use of concatenation (.) or string in void context at -e line +1. foo $ perl -wle 'my $s = length ("foo") . "bar"'
        Why warn only with print and a single space, but not with length or other functions? Or other amounts of whitespace? That I find an oddity.

      Re the last one, it should simply be gotten rid of. The reason it's there is to keep you from accidentally saying print (1+2)/3;. That now gives /both/ a useless use of division in void context and a print interpreted as function. The "print interpreted as function" was there long before the "... in void context"; the later is more useful, but was harder for perl to notice.


      Warning: Unless otherwise stated, code is untested. Do not use without understanding. Code is posted in the hopes it is useful, but without warranty. All copyrights are relinquished into the public domain unless otherwise stated. I am not an angel. I am capable of error, and err on a fairly regular basis. If I made a mistake, please let me know (such as by replying to this node).

Re: Perl oddities
by Joost (Canon) on Mar 01, 2005 at 11:03 UTC
    I think the filehandle functions are generally messy: Bareword file handles, indirect object syntax for print() and close(), open() modifies it's $fh argument, and my least favorite "feature": defaulting to ignoring errors, which just means you end up having to type open FH,"<","file" or die "Can't open file: $!"; every time you use open, print and close.

    I would prefer something like this:

    my $fh = open "<","filename"; $fh->print "stuff"; $fh->close;

    Which would also make it easier to replace a filehandle with some other object.

      Change your arrows to dots and that's almost exactly how it looks in Perl 6.

      See Fatal, which does exactly that, override open (or whatever else you want) to die if it fails. The scheme falls down for system, as system returns a false value on success ...

        Fatal will be a built-in pragma in Perl 6, and any code which uses the fail keyword will fail in the way specified by the caller, which might be to throw a fatal exception, or to return an unthrown exception that is behaves like undef, or to cause some form of backtracking, in the case of the pattern matching engine.

        I'll talk about system elsewhere.

Re: Perl oddities
by TimToady (Parson) on Mar 01, 2005 at 18:18 UTC
    This is a great thread, if only because it lets me point out that most of this stuff is fixed in Perl 6. :-)

    It's going to take me a while, but I think it would be valuable if I responded to most of these. First, the OP...

    The behavior of -M, -A, and -C is intentionally differentiated from the bare values returned by stat(), so that's probably not going to change.

    The mkdir problem will be solved by making the mode an optional named parameter that goes before the list of directories if you do specify it.

    And finally, print FH @list is illegal several ways in Perl 6. First, there are no bareword filehandles in Perl 6--they're just regular variables. Second, indirect objects are no longer differentiated by the absence of a comma, but by the insertion of a colon. (The reason it doesn't work with comma in Perl 5 is that print wouldn't know whether it's supposed to treat its first arg as an object to print to or a value to be printed to STDOUT.)

      Perl 6 will have its very own oddities list. :)

      --
      brian d foy <bdfoy@cpan.org>
        Sure, but we're trying to pick a more useful set of oddities. And nobody's paying me enough to remove all the oddities. :-)
Re: Perl oddities
by BrowserUk (Patriarch) on Mar 01, 2005 at 11:34 UTC
    The -M, -A, and -C file test operators return the file modification, access, and creation times in days since the start of the program. Why? Why why why? Does anyone actually use the values for anything other than to compare them to each other?

    The relativity of the dates produced by -M, -C and -A are useful for things like "delete all *.tmp files more than 5 days old" etc.

    For example, this lists all the .pl file in the current directory that have been modified in the last 24 hours.

    perl -le "-M() < 1 and print for map glob, @ARGV" *.pl 435230.pl junk.pl junk2.pl junk3.pl

    My least favorite oddity is the need to use /g option on a regex in order for pos to be set.


    Examine what is said, not who speaks.
    Silence betokens consent.
    Love the truth but pardon error.
      My vote for weirdest feature of Perl is reset.

      dates produced by -M, -C and -A are useful for things like "delete all *.tmp files more than 5 days old" etc.

      And for command line utilities you are making your decision at the time of invocation, $^T, so that is the important time. These op's must have been a grand convenience for find2perl. I agree these are a strange and odd convenience feature but given the early mission of Perl to be a better shell/awk/sed I don't find it weird.

      Be well,
      rir

        reset will be demoted to a method on a package or hash object. It will no longer be a keyword. We can't get rid of the functionality entirely if we want to be able to translate Perl 5 to Perl 6 though. But it can definitely stand to be de-Huffmanized, or more accurately, Huffmanized to be longer. Funny how we associate Huffman with making easy things easier but not harder things harder...
      and having it be relative to the start of the program (actually, $^T, which you can change to suit) saves having to call time() for each -M, -A, or -C (in addition to making the results equal for different files with the same timestamp).
        saves having to call time() for each -M, -A, or -C (in addition to making the results equal for different files with the same timestamp).

        I'm not quite sure I follow that. If they just returned the timestamp from the files as absolute values, you wouldn't have to call time() at all? And the results of different files with the same timestamps would be the same anyway?


        Examine what is said, not who speaks.
        Silence betokens consent.
        Love the truth but pardon error.
Re: Perl oddities (s/// doesn't DWIM in map)
by grinder (Bishop) on Mar 01, 2005 at 13:55 UTC

    I still find myself being tripped up from time to time by the following, even though I should know better:

    my @w= qw/ per coercer berserker / ; print "$_\n" for map { s/er/aler/g } @w;

    The above produces the output "1 2 3". To make it DWIM, one must say:

    my @w = qw/ per coercer berserker / ; print "$_\n" for map { s/er/aler/g; $_ } @w;

    I've always found that odd. (Yes, I know why it works that way).

    - another intruder with the mooring in the heart of the Perl

      This can be solved much more generically in Perl 6 with mutator methods and topics:
      print "$_\n" for map { .=subst(/er/, 'aler', :global) } @w;
      But what you're really asking for is something other than map here, I think...

        True. I'd like to see a switch:

        my $modified = s/$pattern/$change_to/gr;

        Where /r stands for 'replaced', or somesuch.

      A related oddity is that map can modify its input, in addition to generating output. That leads to the pitfall of
      my @new = map { s/foo/bar/; $_ } @old; # @old is modified along with @new! # should be my @new = map { s/foo/bar/; $_ } map {$_} @old;
      If map couldn't modify its input, the whole "map in a void context" debate might never have happened. for would be used for modifying input, map would be used for generating new output. Of course, it's a tradeoff, giving up some liberty for safety.

      Caution: Contents may have been coded under pressure.
        my @new = map { local $_ = $_; s/foo/bar/; $_ } @old; also avoids the problem. Probably faster than using two maps, too. Still ugly, unfortunately.

        I write that as

        s/foo/bar/ for my @new = @old;

        Makeshifts last the longest.

      I understand that you were just giving an example, but it looks like gratuitous chaining to me. Why not just
      for (@w) { s/er/aler/g; print "$_\n"; }
      You might also be interested in Algorithm::Loops 'filter'.

      Caution: Contents may have been coded under pressure.
        Because that might be part of a much larger chain.

        Additionally, what's gratuitous in one set of eyes is natural in another's. For example, I find Java to be a gratuitous (mis)use of classes, but others, like Smalltalkers, find it to be gratuitously procedural. :-)

        Being right, does not endow the right to be rude; politeness costs nothing.
        Being unknowing, is not the same as being stupid.
        Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
        Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

Re: Perl oddities
by hv (Prior) on Mar 01, 2005 at 12:46 UTC

    I find the behaviour of int() odd: I want it to be like floor(), since then I can easily make ceil() and other useful functions for myself without loading the expensive POSIX module:

    sub ceil { -int(-shift) }
    I've never been able to see a good reason for the existing "truncate towards zero" behaviour.

    Hugo

      It seems pretty sensible to me to say that the integer portion of -3.5 is -3.

      It's still pretty easy to write ceil and floor:

      sub ceil { my $n = shift; int($n) + ($n > int($n)); } sub floor { my $n = shift; int($n) - ($n < int($n)); }

      Caution: Contents may have been coded under pressure.
Re: Perl oddities
by dragonchild (Archbishop) on Mar 01, 2005 at 14:09 UTC
    Disambiguation messes with me. Once you have found something wonky, you put a + somewhere and Perl gets what you mean. Why a plus-sign?? I'm not adding a left-squiggly to shift when I do
    sub foo { my $self = shift; $self->{+shift} = 3; return $self; }

    Also, while we're talking about prototypes, why do some internals prototype and others don't? Can't the prototype for vec() look at how many elements there are in the array before bitching at me? And, I have to override CORE::GLOBAL::vec to eliminate the prototype. Overriding CORE::vec, even in a BEGIN block, isn't good enough. (Can you tell I don't like Perl's prototypes in any form?)

    Being right, does not endow the right to be rude; politeness costs nothing.
    Being unknowing, is not the same as being stupid.
    Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
    Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

      There are several things wrong there that are fixed in Perl 6. You won't need the plus because you'll disambiguate autoquotes differently, so that a shift in curlies is always a real shift. And plus is always numeric in Perl 6--it's not a no-op as it is in Perl 5. But mostly, methods just look different. Your code might look more like this in Perl 6:
      method foo ($self: $key) { .{$key} = 3; return $self; }

      As for vec, that interface is a total kludge. You'll be much happier with real bit arrays, I expect.

      You aren't subtracting from a left squiggly when you put a minus in front of it either. It's not that + in this expression is special cased. Unary + in Perl is a noop. (Just like unary plus is a noop when doing arithmetic). In the example you give, putting a plus there is just one of the ways to do disambiguations. Putting parenthesis after shift works as well, as well as something else that's essentially a noop (adding an empty string for instance).

      I wouldn't call an idiom a Perl oddity - it's not part of the language itself, just an often used construct.

Re: Perl oddities
by trammell (Priest) on Mar 01, 2005 at 17:41 UTC
    Unary - on strings always struck me as weird:
    my $foo = '-bar'; print $foo; print -$foo;
      Yeah, I'm not sure anyone has ever used that feature. It snuck in there because certain linguists love to write their linguistic booleans as +feature and -feature, plus there was some resonance with Tk's -foo syntax. But we're probably breaking that too in favor of something more natively Perlish.
Re: Perl oddities
by Anonymous Monk on Mar 01, 2005 at 13:23 UTC
    Perl has sin and cos, but no tan. I know you can make your own tan function, but that's not the point. It's not convenient (hence, unPerlish) for the programmer to make his/her own (or load a module to do so). Besides, calling sub in Perl is expensive. Even many calculators have a button for the tan function.
      sin, cos, and atan2 are "primitive" functions. From those, all other forward and reverse functions can be trivially derived.

      The overhead of calling a subroutine is tiny compared to the overhead of computing the sin or cos, I would imagine.

      -- Randal L. Schwartz, Perl hacker
      Be sure to read my standard disclaimer if this is a reply.

          sin, cos, and atan2 are "primitive" functions.

        Well, once you have a routine for sin, then cos is the same thing, but pi/2 sooner. And I'm fairly sure that's the way it's implemented in the libraries.

        Using atan2 to do an inverse sin or cos is a bit of a walk in the park, but essentially I guess you have to find the 'Y' value once you have the 'X', then submit both to atan2, and that will give you the angle you're looking for.

        That's a nice brain exercise right after lunch.

        Alex / talexb / Toronto

        "Groklaw is the open-source mentality applied to legal research" ~ Linus Torvalds

        I know. But you can do away with either sin or cos as well - they are the same primitive, just shifted a quarter of a phase. That of course doesn't mean tan couldn't be present. After all, Perl gives us push, pop, shift and unshift, when they can all be trivially implemented using splice. Perl is a rich language, and any minimal approach is, to quote brian, what I consider exceptions to normal Perl thinking. Normal Perl thinking is "programmer convenience". A minimalistic approach isn't programmer convenience.
      Note that I've seen the pattern of providing sin, cos and atan (but not other trig functions) in other libraries and programming languages. And the reason for this (that so far as I can tell no one has yet said) is simple: those functions are defined for all values of their argument. tan isn't. arcsin and arccos aren't.

      Not that it's necessarily a very good reason, mind you.

      -- @/=map{[/./g]}qw/.h_nJ Xapou cets krht ele_ r_ra/; map{y/X_/\n /;print}map{pop@$_}@/for@/
        And the reason for this (that so far as I can tell no one has yet said) is simple: those functions are defined for all values of their argument. tan isn't. arcsin and arccos aren't. Well, division isn't defined for all values of its arguments either, and neither are log and sqrt. So, I agree it's not much of a reason at all.
Re: Perl oddities
by Anonymous Monk on Mar 01, 2005 at 13:33 UTC
    Perl doesn't DWIM in:
    sub add ($$) {$_[0] + $_[1]} my @arr = (3, 4); print add(@arry);
    It issues a warning and prints 2, not the 7 I'd expect.

    Perl doesn't DWIM in:

    sleep 2.5;

    You can tie some magical variables, and get the expected effects, but with other magical variables, no subroutines tied to them are ever called.

    $ perl -wle 'print+(localtime())[5]' 105
    C all over again.

    brian, are you going to collect the results here, and give them to Larry before Perl6 comes out? ;-)

      Perl 6's flattening rules are completely revised so that hashes and arrays don't actually have to care whether they're in scalar or list context until they're bound to parameters. Nevertheless, what you're saying there still won't work. If you want to treat an array as a list of parameters where Perl 6 is expecting a scalar, you have to use an explicit unary * to tell it that's what you want.

      Fractional seconds weren't supported by most versions of Unix when Perl was invented, but that has changed for the better over the years. In Perl 6 most times will be represented in floating-point seconds, so a fractional sleep should do what you expect.

      Tying and magic are done entirely differently in Perl 6 (through mixins and such), though you can never get entirely away from the fact that some semantics are going to hide other semantics unless you construct a class that specifically knows about both sets of inherited or composed semantics. However, it should work more like you expect, insofar as the latest layer of semantics should hide the built-in magic, and not vice versa.

      As for localtime, it was always intended to be a thin interface over C. But Perl 6 will give an OO interface to most of the list-returning functions, and you'll get at the values with methods on the returned object. So we can fix the year+1900 problem at least for the method call.

      I'm not brian, but I can probably pass these on to Larry before Perl 6 comes out... :-)

      Perl doesn't DWIM in:
      sleep 2.5;
      But see:
      use Time::HiRes qw(sleep); ... sleep 2.5;
      You can't make core Perl do this, because the number of systems on which this worked was once miniscule compared to the number of systems on which it could never work.

      -- Randal L. Schwartz, Perl hacker
      Be sure to read my standard disclaimer if this is a reply.

        merlyn,
        You can't make core Perl do this

        To the letter of the law, that's true. In spirit though, select(undef, undef, undef, 2.5); is usually close enough. It would be nice if you didn't have to use something so ugly with core Perl though.

        Cheers - L~R

        You can't make core Perl do this

        Did I say we should change Perl to allow this? No. Do you understand the premises of this thread? brian was asking for what people consider oddities of Perl thinking. Now I'm sure any oddity has its reason for being odd (after all, it's there the way it is because someone put it there, and not because Larry has a piece of radioactive material next to his computer and he's just watching how the rays mutate Perl) - but that's not the point.

        I expect Perl to DWIM (just like it does in many other things), and if on my system select undef, undef, undef, 2.5 waits for about 2500 milliseconds, then there's no reason to assume sleep 2.5 can't.

      Just avoid prototypes and you will be happier. 99.9% of the time they aren't needed and often they hurt, like in this case.
      sleep 2.5;
      works if you
      use Time::HiRes qw/sleep/;

      The alternative

      select(undef, undef, undef, 2.5);
      looks too much like a hack and isn't very clear.

      /J

      Update: I can't believe I didn't scroll down to see the existing answers to this question :)

Re: Perl oddities
by hardburn (Abbot) on Mar 01, 2005 at 14:27 UTC

    The fact that a comma after a map block is a syntax error:

    $ perl -e 'map { $_ }, qw/foo bar/' syntax error at -e line 1, near "}," Execution of -e aborted due to compilation errors.

    I'm fine with it not being required, but it shouldn't yell at you if you happen to include it.

    "There is no shame in being self-taught, only in not trying to learn in the first place." -- Atrus, Myst: The Book of D'ni.

      The comma after the block is optional in Perl 6. On the other hand, you have to use a block there. The expression form is not supported in Perl 6. Or more precisely, the first arguments will be expected to be an expression that returns a closure to be executed.
      And if you're trying to map your inputs into hashrefs with a comma, you can't. :-/

      Being right, does not endow the right to be rude; politeness costs nothing.
      Being unknowing, is not the same as being stupid.
      Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
      Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

Re: Perl oddities
by sh1tn (Priest) on Mar 01, 2005 at 23:35 UTC
    Oddity ... I think there is one – Perl made me love programming!


      I don't think we've quite got around to fixing that one in Perl 6 yet, but we're working on it. :-)
Re: Perl oddities
by bart (Canon) on Mar 01, 2005 at 22:40 UTC
    First of all, I'd like open and opendir to have returned an open handle, or undef on failure, instead of changing a passed argument on the side. But Joost already mentioned that.

    And second, I find it not just odd but also extremely annoying how the -X operators ignore parens as a hint for parsing precedence. Take this example:

    print -M($0) + 1;
    This yields:
    Argument "test.pl" isn't numeric in addition (+) at test.pl line 2.
    Use of uninitialized value in print at test.pl line 2.

    Perl treats this the same as

    print -M ($0 + 1);

    Not exactly what I had in mind. You have to wrap the parens around both operator and argument, to make it behave like I want. Just like Applescript.

    print +(-M $0)+1;
Re: Perl oddities
by bluto (Curate) on Mar 01, 2005 at 16:46 UTC
    print FH @list

    Normally this doesn't bother me unless I have to use parens (due to a parsing or emacs alignment issue)...

    print(FH <list>);

    ... looks even worse.

    The other thing I think is odd is how split() removes null fields at the end of a line if you don't give a LIMIT argument. Normally when I process a delimited file I expect each line to have the same number of fields, though some may be empty. For short scripts I tend to write quick sanity checks like this...

    my @values = split /:/, $line; die "invalid line: '$line'" unless @values == 7;

    It looks nice, but I have to remember to go back and set LIMIT to a negative (or large) number.

      In Perl 6 it's probably one of
      print($fh: @list); $fh.print(@list);
      instead, or maybe you'll use pipes:
      @list ==> $fh.print; $fh.print <== @list;

      As for split, we haven't decided yet whether to change the default. I can argue it both ways.

      Normally this doesn't bother me unless I have to use parens

      It's also kind of odd when your filehandle is not a simple scalar or bareword:

      open $hash{foo}, ">", "foobar"; print { $hash{foo} } "Test\n";

      Makes me shudder every time.

      I do it this way:
      print FH ('test', 'ing', 1, 2, 3);

      Actually, I lied. I simply don't use barewords filehandles.

Re: Perl oddities
by YuckFoo (Abbot) on Mar 01, 2005 at 18:53 UTC
    It is odd that regex capture variables are not put in an array somewhere and I have to explicitly list them:

    # too much work... my ($this, $that, $some, $other) = ($1, $2, $3, $4); # would rather: my ($this, $that, $some, $other) = @_;

    YuckFoo

      This also is fixed in Perl 6. You can get at the captures as an array if you like, or you can even bind the variables directly within the pattern and bypass the assignment altogether (though you'd still have to declare the variables in that case). Alternately, you can name the captures within the pattern and then get at them as a hash. With some syntactic sugar, $1 is also called $<this>, $2 is also called $<that>, etc., and it's just pulling captures out of the result object without you having to declare anything (except the name bindings within the pattern).

      A few other pattern matching things have changed too. :-)

      Often you can just assign the results of the match. Make sure you are in list context if you have only one capture.

      my ($this, $that, $some, $other) = /(this)(that).*(some)....(other)$/; my ($cap) = /hello(there)/; # OK my $cap = /hello(there)/; # BUG
        Often you can just assign the results of the match.

        But not if you use /g, as /g acts quite differently in scalar and in list context.

      I generally do as gaal suggests. However, if this were impossible, and if you had a long list of regex capture variables, you could always do:

         my ( $this, $that, $some, $other, $foo, $bar, $baz ) = ( $1 .. $+ );

      dave

        I am aware of the method suggested by gaal. I usually do not use it because I almost always wrap the regex up with an 'if'. Throw in a my function and it starts to get messy.
        # Ugly to me... if (my ($this, $that, $some, $other) = $line =~ /(this).*(that).*(some +).*(other)/) { do_it(); }; # Better, I think... if ($line =~ /(this).*(that).*(some).*(other)/) { my ($this, $that, $some, $other) = ($1, $2, $3, $4); do_it(); }
        This business doesn't DWYM:

        my ( $this, $that, $some, $other, $foo, $bar, $baz ) = ( $1 .. $+ );
        The magical string incrementer is summoned to build a list of strings starting with the first capture, ending with the last.

        YuckFoo

        That doesn't work:
        #!/usr/bin/perl use strict; use warnings; $_ = "this that some other foo bar baz"; if (/(this)\s*(that)\s*(some)\s*(other)\s*(foo)\s*(bar)\s*(baz)/) { my ($this, $that, $some, $other, $foo, $bar, $baz) = ($1 .. $+); print "$this, $that, $some, $other, $foo, $bar, $baz\n"; } __END__ Use of uninitialized value in concatenation (.) or string at Use of uninitialized value in concatenation (.) or string at Use of uninitialized value in concatenation (.) or string at Use of uninitialized value in concatenation (.) or string at Use of uninitialized value in concatenation (.) or string at Use of uninitialized value in concatenation (.) or string at Use of uninitialized value in concatenation (.) or string at , , , , , ,
        What does work is:
        #!/usr/bin/perl use strict; use warnings; $_ = "this that some other foo bar baz"; if (/(this)\s*(that)\s*(some)\s*(other)\s*(foo)\s*(bar)\s*(baz)/) { my ($this, $that, $some, $other, $foo, $bar, $baz) = map {;no strict 'refs'; $$_} 1 .. $#-; print "$this, $that, $some, $other, $foo, $bar, $baz\n"; } __END__ this, that, some, other, foo, bar, baz
        A trick I've been using for quite a long time. ($#+ instead of $#- works as well).
Re: Perl oddities
by ikegami (Patriarch) on Mar 02, 2005 at 06:49 UTC
    What's with the 1; at the end of every module. Are there any modules that don't return true? Couldn't they just die instead?
      Modules should be made to return their name (or Class maybe if that is a type.)
Re: Perl oddities
by PreferredUserName (Pilgrim) on Mar 01, 2005 at 15:09 UTC
    I've always been annoyed that you can't say:
    if ($condition) do_something();
    The lame "Perl is saving you from nested elses" rationale for this doesn't wash. Since when is Perl a bondage and discipline language?

    I often have written:

    do_something() if $condition;
    , which is less clear to me, to avoid taking up four lines of screen/brain space with:
    if ($condition) { do_something(); }
      Actually, I think C made the wrong choice here. It's not the braces that are being redundant, but the parentheses! The parens are there only to avoid syntactic ambiguity if the following statement isn't a block. So the parens are what Perl 6 lets you get rid of:
      if $condition { do_something() }
      In fact, the braces are much more important in Perl 6 because they almost always indicate a closure, or at least a potential closure. That's important because the braces indicate delayed evaluation. A closure is treated as an argument to the control construct, so you could also write the above as:
      statement:<if>($condition, { do_something() });
      But the converse is also true, that if you define your own statement:<foo> with the same signature, you can call it as:
      foo $condition { do_something() }
      just as if it were a built-in control construct. To do this in Perl 5 requires chewing gum and bailing wire, plus assorted smoke and mirrors.

        I'm not going to argue the logic of this. Being able to create a brand new language without making my jaw tired, running out of wire and having to go back to the store to get more, and in a non-smoking city ... that is great.

        The fact is that most of the more popular languages use those parens. Whether your history is C/C++, Java, Perl5, or others which I've probably forgotten (I don't remember enough Pascal or Fortran to print out "hello world" - whether they do or not, I can't recall, but I'm not sure they quite qualify among the more popular languages, at least not from the perspective of those who would use Perl6), you're used to it. While it may not be intuitively natural for a human being to put parens around their conditional, it has been trained into a large majority of programmers to do it, even if that is against our nature.

        Sometimes, bad choices are propogated to get over the inertia of the results of those choices. Rather than spending time retraining in the revolutionary new pattern of behaviour (I'd use the word "paradigm", but I think that word has lost all meaning), we stick to the tried-and-true-more-or-less. It helps languages, such as Java or C#, take off, because there is less retraining involved.

        The trade-off here is that this may indeed be a revolution in language design. But it will delay the adoption of Perl6 (I think I've read something in the Apocalypses where this has been conceded already), possibly (although hopefully not) to the point where it just cannot acheive critical mass.

        Another problem is for those of us who have to deal with multiple languages. I'm doing mostly perl5 right now, but I am still responsible for some C++ code (a couple KLOC), some shell scripts (probably about a dozen KLOC - ugh!), and have input into some Java code design issues. Yet another pattern will mess me up for a while - I can imagine that a number of people will just be too busy to pick up another language, especially one that has not (yet) hit critical mass, making it just a bit more difficult to acheive that critical mass. I'm not sure if I'll fall into this group or not yet.

        I'm not saying that perl6 in general (or making parens optional in specific) is a bad idea. Someone has to come up with the revolutions every once in a while if we're ever going to get to that AI which just does what we ask it, without having to do all the drudgery of actually coding. It's just a risk. Whether good or bad, only time will tell.

        Perl6 has, from what little I've read, so many time savers here and there - taken one at a time, most are pretty minor. Taken all together, it's pretty daunting. In some ways, renaming it away from "perl" may have been a good idea, so that no one thinks about it like perl. ;-) I think that perl6 shares less in common with perl5 than C++ shares with C ;-)

      Another alternative:
      if ($condition) { do_something(); }
      A couple of things:

      1. I've found that the braceless if can slow me down when reading C code. I have to remember that the next command is the thing that's done.
      2. Cuddling the braces around their control statements saves a lot of whitespace without much loss of readability. Consider the following extension of my suggestion above:

      if ($condition) { do_something(); } else { if ($another_condition) { do_something_else(); } else { do_yet_a_third_thing(); } }
      Just my $0.02
      ----
      My mission: To boldy split infinitives that have never been split before!
      Which is more important - do_something() or $condition? The important bit should be left-most in indentation. I have often found
      if (really_long_and_boring_condition) do_something_useful()

      to be much harder to read in C. Plus, people seem to feel that just cause you don't have braces means you don't have to follow proper indentation practices. (Not that braces always help, but it allows me to bounce on % in (g)vi(m).)

      Personally, I prefer the following alternatives:

      do_something_useful() if really_long_and_boring_condition; # Or ... really_long_and_boring_condition && do_something_useful();

      Depending on which is more important to understanding the program's flow.

      Being right, does not endow the right to be rude; politeness costs nothing.
      Being unknowing, is not the same as being stupid.
      Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
      Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

        I would argue that if the condition is "really long and boring", then it is *more* important to have braces and whitespace so it is easier to see where the actual action being taken is at a glance. The only one you mention that could work for me is:
        do_something_useful() if really_long_and_boring_condition;
        Unfortunately, that's at the expense of putting the cart before the horse IMHO. The action doesn't matter if the condition is not satisfied.
        ----
        My mission: To boldy split infinitives that have never been split before!
       if ($condition) { do_something(); }

      Not the same, but its not four lines! ;)


      ___________
      Eric Hodges
Re: Perl oddities
by dragonchild (Archbishop) on Mar 01, 2005 at 17:27 UTC

    It's also kind of odd when your filehandle is not a simple scalar or bareword:

    That's something that also bugs me - why is a filehandle a bareword, but every other bareword gets smacked down by strict?

    Being right, does not endow the right to be rude; politeness costs nothing.
    Being unknowing, is not the same as being stupid.
    Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
    Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

      Don't forget that labels escape strictures too. If Perl can tell what it is, strict doesn't care. With filehandles it knows by position. With labels, it's the colon. You can forward define subs too, and get away with it.

      --
      brian d foy <bdfoy@cpan.org>
        Perl 6 has no barewords at all. If Perl 6 can't tell what it is from context, it's an error. Classes must be predeclared or use the :: prefix, for instance. They aren't just bareword strings anymore.
Re: Perl oddities
by Anonymous Monk on Mar 01, 2005 at 21:28 UTC
    $::foo refers to the global variable called foo in the main package, not in the current package.

    This works out the same for package main, but it just doesn't DWIM for other packages. The first three times I read through the documentation, I assumed it was just refering to this similarity: clearly, the writers of the Perl parser could tell what package they were in, so they could expand $::foo appropriately. After all, they need to figure out packages for function calls. Instead, it means the same as $main::foo, something that a simple regexp could do for me, if I wanted it to.

    Since I thought the point of the package notation was to let the globals stand out with the double colon sigil syntax, I was disappointed to learn that I'd have to hard-code the package name in multiple places: first, in the the package, and second, for all the global variables within that package.

    "our" variables solve the hard-coded package name issue, but don't have a special sigil to make them stand out as globals anymore...*sigh*
    --
    Ytrew

      In Perl 6, :: behaves more like you expect, and is no longer automatically associated with either package main or any other top-level package. Class names are searched for starting in the current package, so $::foo would be a variable in the current package if declared there.

      I just made package variable names start with a capital letter. That way I could remind myself I might be ruining someone else's day by playing with it.

      --
      brian d foy <bdfoy@cpan.org>
Re: Perl oddities
by ikegami (Patriarch) on Mar 01, 2005 at 20:47 UTC

    print FH @list is not unique. It's called the "indirect object" method invocation syntax. The example in perlobj is new Critter ('Barney', 1.5, 70). True, FH is not (necessarily) an object here, but it behaves just like one.

      I had never really thought of it like that: maybe because we teach it in the second day of Learning Perl and I don't talk about objects and such then. This has also been around a bit longer than

      Too bad this doesn't seem to work.

      #!/usr/bin/perl STDOUT->print( "Hello World!\n" );

      I get this error:

      Can't locate object method "print" via package "IO::Handle" at io.pl l +ine 3.

      If I change it slightly, though, I get the expected output. I'm surprised I didn't get the "perhaps you forgot to load ..." message that usually comes with this sort of error.

      #!/usr/bin/perl use IO::Handle; STDOUT->print( "Hello World!\n" );
      --
      brian d foy <bdfoy@cpan.org>
        I'm surprised I didn't get the "perhaps you forgot to load ..." message that usually comes with this sort of error.

        Odd, I get the message...

        >perl -e "bless({}, 'Cow')->moo();" Can't locate object method "moo" via package "Cow" (perhaps you forgot + to load "Cow"?) at -e line 1. >perl -e "STDOUT->print();" Can't locate object method "print" via package "IO::Handle" (perhaps y +ou forgot to load "IO::Handle"?) at -e line 1. >perl -v This is perl, v5.6.1 built for MSWin32-x86-multi-thread (with 1 registered patch, see perl -V for more detail) Copyright 1987-2001, Larry Wall Binary build 633 provided by ActiveState Corp. http://www.ActiveState. +com Built 21:33:05 Jun 17 2002
Re: Perl oddities
by BrowserUk (Patriarch) on Mar 02, 2005 at 08:41 UTC

    My other "love to hate" oddity of Perl 5 is lvalue subs. To quote me:

    As they are, the only thing that can be done with the assigned value is ... well, to assign it to something. Sure, you can decide what to assign it to using the values past via the normal @_ mechanism to make the determination, but there is absolutely no way to inspect the value of the assign value either before you assign it nor after is was assigned. That means it is impossible to perform any verification on the assigned value. This may work for things like substr and splice, that simply don't care what is assigned, but it makes using lvaue subs for any other purpose pretty much useless. I note that vec can and does inspect the value assigned in that it will reject non-numerical assignments as it has to process them in order to use them. This is exactly the facility I would like to use.

    I'd really like to see lvalue subs made useful:(


    Examine what is said, not who speaks.
    Silence betokens consent.
    Love the truth but pardon error.

      lvalue subs will be useful, but only with a lot of ugly syntax. I hope that macros and attributes will be powerful enough to fix this, and suspect that they will be, though it still jars me that I'll need to depend on the module that has the macros in it.


      Warning: Unless otherwise stated, code is untested. Do not use without understanding. Code is posted in the hopes it is useful, but without warranty. All copyrights are relinquished into the public domain unless otherwise stated. I am not an angel. I am capable of error, and err on a fairly regular basis. If I made a mistake, please let me know (such as by replying to this node).

Re: Perl oddities
by PhilHibbs (Hermit) on Mar 21, 2005 at 13:46 UTC
    I thought that ctime was the change time of the inode, rather than creation time. chmod a file and see it change.
      You're correct. You'll even see this referenced in perldoc -f -C.

      thor

      Feel the white light, the light within
      Be your own disciple, fan the sparks of will
      For all of us waiting, your kingdom will come

Re: Perl oddities
by marinersk (Priest) on Mar 01, 2005 at 22:44 UTC
    File timestamp relative to start of program is also useful when writing file utilities; on some operating systems you can actually get a filename twice, once before you modified it and once after -- checking its timestamp relative to program start eliminates the need to track which files you've already processed.
Re: Perl oddities
by blazar (Canon) on Mar 02, 2005 at 10:18 UTC
    print FH @list

    You don't put a comma between the filehandle name and the list you give to print. I've just always thought that was odd, and I go out of my way to point it out to people in Perl classes. I don't have a problem with this while I code, but I still think it's an odd corner of syntax.

    Well, it's more of a coincidence than a real fact, but that looks much like indirect object dereferentiation, a la
    FH->print(@list)
    and (BTW) it won't be a coincidence any more in Perl6...
Re: Perl oddities
by Limbic~Region (Chancellor) on Mar 02, 2005 at 19:22 UTC
    brian_d_foy,
    I find the way Perl handles mixed tied interfaces odd.
    use Tie::Hash::Sorted; tie my %s_hash, 'Tie::Hash::Sorted'; print tied( %sorted_data )->Count, "\n";
    The alternative is to split the functionality into two pieces.
    my $s_href = tie my %s_hash, 'Tie::Hash::Sorted'; print "$_\n" for keys %s_hash; print $s_href->Count, "\n";

    Cheers - L~R

Re: Perl oddities
by fraktalisman (Hermit) on Mar 05, 2005 at 13:30 UTC

    Looking at TimToady's answers, this thread looks a bit like a Perl 6 wishlist. And a chance to get a better idea of what Perl 6 is going to be like, without following the developers' discussions about it.

    But I don't think Perl will stop to have oddities, just because it has so many influences (or compatibilities?) of other languages and tools.

      I'm a little disappointed in all the comments about perl6. This thread could have been a nice discussion providing insights into how people think, and all the noise about "But we've fixed that in perl6 and boy will it be neat!" is getting irritating.

        I'll disagree. I think that this list of oddities is a perfect place to vent, to reflect on where we are, how we got here, and, just as importantly, if not moreso, where we are going. Many of these oddities seem to have been made into RFCs for perl 6 - which is why perl 6 seems to solve so many of them. But, don't worry, a year or two after perl 6 comes out, we can have this thread all over again with perl 6's own oddities, as brian_d_foy points out ;-}

        (I'm not disagreeing with it "getting irritating" - that's your feelings, and you're entitled to them. Just disagreeing with the implication that this is not a nice discussion providing insights into how people think, which I think it has done, and more: whether those oddities will be addressed or not in future versions of perl.)

Re: Perl oddities
by Dedalus (Scribe) on Mar 01, 2005 at 21:37 UTC
    pipe A=>B
    does rather the opposite to what it looks like it should.

      So does push(@a => $b);. Why are you using => instead of ,?

      By the way, your code is equivalent to pipe('A', B); and not pipe(A, B).

        Why should not I? It is perfectly valid, and would seem to make visual sense, pipe one thing into an other. Arrows are pretty, but not DWIM, it is a shame.

        I've taken to using =>, having been inspired by Abigail-II's tendancy tward the fact comma. I put it in whenever the expressions on each side are somehow related.

        "There is no shame in being self-taught, only in not trying to learn in the first place." -- Atrus, Myst: The Book of D'ni.

Re: Perl oddities
by Anonymous Monk on Mar 02, 2005 at 00:59 UTC
    While I agree with your observations about the odities of -M, -A, and -C, print FH @list makes perfect sense to me. If one was to put a comma between the two, I would expect the filehandle and list to be printed (ie. the glob and the list); especially with the possibility of Filehandles now being assigned to variables ( open my $fh => ''), I'd find it counterintuitive to see perl differentiate between:
    print $fh,@list; # ref($fh) = GLOB
    and
    print $fh,@list
    That'd be some cooky DWIMery, considering, then, that _if_ we wanted to print something like GLOB<0x...>, we'd have to do this:  print "$fh",@list, which would function in a significantly different manner than print $fh,@list. Thus, to me it's a perfectly rational and well thought out syntax.

    I still prefer, however,  $fh->print();. In addition, the workaround to this oddity would be to force the explicit declaring of the filehandle to write to, or the like.
Re: Perl oddities
by mattk (Pilgrim) on Mar 04, 2005 at 19:01 UTC
    I'd like to know why POSIX.pm doesn't include an interface to strptime(3). Time::Piece has it, but it's broken (you can't get proper epoch values out of it when you use it as your constructor). I'm looking forward to Perl6's OO-based time functions already.
substr oddity
by Ytrew (Pilgrim) on Mar 04, 2005 at 05:14 UTC
    I'm not sure if this one counts as an oddity, or a bug. I think it's defined behaviour, but I'm not sure.

    substr() is implemented as an Lvalue subroutine, and it's a fatal error when assigned to incorrectly. I think means that when substr() is passed as a parameter, it gets treated like an Lvalue, since it can be assigned back to by modifying @_.

    This code crashes on the subroutine call:

    use strict; use warnings; my $x=""; foo( substr($x,2,1) ); # crashes here print "Alive!\n"; # not reached sub foo {}

    This code doesn't:

    use strict; use warnings; my $x=""; my $y=substr($x,2,1); # warns, doesn't crash foo($y); # no-op print "Alive\n"; # we get here just fine sub foo {}

    I maintain that this is an odd behaviour, one way or the other. My hunch is that it counts as an "oddity" as opposed to a "bug": can the experts confirm or deny this?
    --
    Ytrew

      This doesn't seem to happen on Win32 5.8.4 (AS 810). Which version are you using?

      P:\test>perl -wle"sub foo{}; my $s =''; foo( substr $s, 2, 1 );" substr outside of string at -e line 1.

      Examine what is said, not who speaks.
      Silence betokens consent.
      Love the truth but pardon error.
        This doesn't seem to happen on Win32 5.8.4 (AS 810). Which version are you using?

        Well, I'm running version "5.8.6 built for PA-RISC2.0-thread-multi-LP64", running on HP/UX. I also get the same behaviour for 5.6.1.

        But your snippet doesn't actually demonstrate the problem: you get the warning message, but can't actually detect whether the code crashed. Here's what I get when I add a trace statement after the call to substr().

        $ perl -wle 'sub foo{}; my $s=""; foo( substr($s,2,1) );print "Not rea +ched\n"' substr outside of string at -e line 1. $
        Note that "not reached" is never reached, and is not printed, because the code crashes on the substr() call.
        --
        Ytrew

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (6)
As of 2024-03-28 16:14 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found