Perl misfeature?



  • This wasted a good half hour of my time (I needed to initialise some data if this was the first occurrence of the key and _not_ touch some of the data otherwise, in a complex application matching RDBMS held data with other configuration information held elsewhere). I knew there was a reason I like Python a lot more than Perl. A more reasonable implementation would do the defined() test starting at the top and fail if it couldn't follow the chain of references, not simply create the references as it progresses down the chain

     The perl man pages describe 'autovivification' in man perlref. What they say, however is

               This is one of the cases we mentioned earlier in which references
               could spring into existence when in an lvalue context.  Before this
               statement, $array[$x] may have been undefined.  If so, it's auto-
               matically defined with a hash reference so that we can look up
               "{"foo"}" in it.  Likewise "$array[$x]->{"foo"}" will automatically
               get defined with an array reference so that we can look up "[0]" in
               it.  This process is called autovivification.

    I don't think that the defined() function qualifies as an lvalue context and I don't think invoking defined() on a substructure where the higher level is not defined should create the higher level. As an extreme example, consider the following hash of hashes of hashes and a test if a low level hash has some key: 

    <pre>
    use strict;
    use Data::Dumper;

    my $ahash = {};
    if (!defined $ahash->{this}->{should}->{not}->{exist}->{key_not_defined}) {
        print "hash 'ahash' does not contain hash(hash(hash{key_not_defined})))\n";
    }
    print Dumper($ahash);
    exit 1;


    jes@jes.noc.nl.demon.net:/home/jes/maildns$ perl -w x.pl
    hash 'ahash' does not contain hash(hash(hash{key_not_defined})))
    $VAR1 = {
              'this' => {
                          'should' => {
                                        'not' => {
                                                   'exist' => {}
                                                 }
                                      }
                        }
            };
    </pre> 



  • Eww. No, that shouldn't happen in my perfect world either.



  • You have a fundamental failure to understand what is happening. This has got absolutely nothing to do with the defined() function. Furthermore, this behaviour is very clearly and explicitly documented on page 254 of the camel (3rd edition). It is considered a bug and has been fixed in perl 6. It is a very widely known problem that has no simple solution (all the easy alternatives, such as the ones used in python and ruby, are worse) and if you didn't know about it, you do not know perl well enough to be using it for anything that matters. You cannot learn perl from the manpages (much like every other language).

    Autovivification is a property of the arrow operator. If you say $foo->{bar}->{baz} in any context (or any similar shorthand, like $foo->{bar}{baz} or $foo{bar}{baz}) then the key 'bar' is created with a value of {}. It doesn't matter whether you say it in the context of defined() or assignment or anything else - autovivification is a property of dereferencing, period.

    Perl 6 does something extremely complicated in order to eliminate this behaviour - the language is fundamentally context-sensitive, so $foo{bar}{baz} means something different depending on whether you're reading or writing (it's approximately either ($foo{bar} && $foo{bar}{baz}) or ($foo{bar} ||= {}}{baz}, respectively). Most other languages, including python, would simply crash if you said something like that. The perl philosophy is "no unnecessary exceptions or strictures by default", so by default you do not get that behaviour. If you do want that behaviour, it is available in the form of restricted hashes (or pseudohashes in older perl versions), which raise an exception instead of autovivifying.

    Don't play with tools that you don't understand. That's how WTFs happen.

    I knew there was a reason I like Python a lot more than Perl. A more
    reasonable implementation would do the defined() test starting at the
    top and fail if it couldn't follow the chain of references, not simply
    create the references as it progresses down the chain

    Python does not do this. The only language I am aware of which does this is Perl 6.



  • The problem is that if that were to work the way you would want it to work, then the exists/defined operators would have to block the code parser from emitting hash traversal opcodes for the parameter.

    Because if it didn't autovivify in an lvalue sense, then by doing exists($a->{b}->{c}) would cause a warning or return undef if 'b' didn't exist in hash a.

    So that adds another special case to the perl interpreter... parameters to exists are not evaluated before passing. They would have to be evaluated implictly at runtime inside an eval and trap the undefined reference error.
     



  • If you're so hot on man pages, why didn't you read perlfunc, where "defined" is, er, defined? You would have found a warning not to use it on hash values. (At least, as of Perl 5.8.)



  • I think I understand what is happening quite well.

    It has to do with Perl's behaviour not matching the documentation, since the documentation describes autovivification in an lvalue context, which defined() is not. The fact that it may be in the camel book is not relevant.. As you noted, it is a bug. Since python has a different method of testing for definedness or not of items in dictionaries, which seem to work well, I don't really see what's 'worse' about them. Your conclusion that if I wasn't aware of this I don't know Perl well enough to be using it for serious applications is an indictment either of your attitude or the usefulness of Perl. If the language is only usable for people who are aware of what I can only consider to be counter-intuitive behaviour, then it is not fit for the purpose which it is most touted as serving.

    What, besides a rather snotty attitude, made you conclude that I was learning or would attempt to learn a language from the man pages? What I do expect is that the manpages match the language, which I maintain they do not in this case.

    In what sense would python or ruby 'crash' if you attempt an invalid operation? Either it won't byte compile, which is fine, because you know where the problem is, or it throws a run-time exception with a stack trace, and, surprise, you know where the problem is. Silently creating sub-structures does neither of these.

     
    A final note, "Don't play with tools that you don't understand" might be countered with, a) I understand the tool and b) I am glad I'm not your co-worker, your assumption about others and your attitude mark you as someone to avoid. And in this case no WTF's happened, because I was running extensive testing of my code.




     

     

     



  • I wouldn't complain if it raised a runtime exception - that's easy to track down. I did not expect to be testing for a subelement of a non-existing hash, an exception would have led immediately to the problem, a complicated code path that needed to be addressed. It was the silent creation of an empty hash which led to later, non-obvious problems. An exception would be fine. Undef would be fine, that's what I would have been looking for. It's the silent side-effect in a non-assignment context which I consider to be a WTF.

     



  • It's deprecated, with the warning that it may disappear in future versions. Since I have reason to know that this script will _never_ run after next August and that Perl will remain at 5.8.6 until that time, I have no concerns about future versions of Perl. The 5.8 perlfunc man page does not mention autovivification as a reason to avoid this operation.

     



  • @kirchhoff said:

    The problem is that if that were to work the way you would want it to work, then the exists/defined operators would have to block the code parser from emitting hash traversal opcodes for the parameter.

    Because if it didn't autovivify in an lvalue sense, then by doing exists($a->{b}->{c}) would cause a warning or return undef if 'b' didn't exist in hash a.

    So that adds another special case to the perl interpreter... parameters to exists are not evaluated before passing. They would have to be evaluated implictly at runtime inside an eval and trap the undefined reference error.
     

    I agree that exists() throwing a warning would propably not very DWIM-ish. Then again though I wonder if an exists() call that silently changes data is so much more intuitive.
     



  • @jes said:

    It's deprecated, with the warning that it may disappear in future versions. Since I have reason to know that this script will never run after next August and that Perl will remain at 5.8.6 until that time, I have no concerns about future versions of Perl. The 5.8 perlfunc man page does not mention autovivification as a reason to avoid this operation.

    To clarify (assuming I'm reading it correctly) the man page says that "defined(%hash)" is deprecated, but there's nothing to suggest that there's anything wrong with "defined($hash{$key})".  It does mention that sometimes it may be more appropriate to use exists() instead, but not because defined() is wrong - it's because they do two slightly different things, sometimes you want one and sometimes you want the other.



  • I agree that exists() throwing a warning would propably not very DWIM-ish. Then again though I wonder if an exists() call that silently changes data is so much more intuitive.

    I think the issue is that it's a necessity for exist to take an lvalue. Why?

    exists doesn't want to fully evaluate it's argument. It wants to do everything EXCEPT resolve the last reference to the data returned by that expression, which is exactly an lvalue. So like the left side of an = or += is lvalue, the parameter to exists is lvalue so it can "get at" what it wants to examine to return true/false.

    And whenever hashes are evaluated in lvalue context, they autovivify. Why? Because it would be really shitty if we couldn't easily construct hash trees/data structures with {} notation willy nilly in one liners. It's to valuable a feature to leave out.

    But we know that exists() is useless on checking transverse nodes in a hash lookup (for previously mentioned reasons, no matter if it has the autovivify behavior or not). We shouldn't be trying it in the first place. So you already have to implement a different kind of test function that does it if you need it... its best practices. If you don't understand how exists and operator expression evaluation works, well then you run into the pitfall, and you learn.

    Here's my replacement for exists() that walks:

    sub hash_path_exists () {
      my $ref = shift;
      if(ref $ref ne 'HASH') { return undef; }
      foreach my $inner @_[0..-2] {   #Don't include the last in the traversal list
        if(ref $inner ne 'SCALAR') { return undef; }
        if(!exists($ref->{$inner})) { return 0; }
        if(ref $ref->{$inner} eq 'HASH') {
          $ref = $ref->{$inner};
          next;
        }
        return undef;  #We encountered a non-hash ref in the traversal list
      }
      return defined($_[0]) && exists($ref->{$_[0]});  # The params array can only contain at most 1 element here.

     


     



  • Meant to add:

    Example usage:
    my $test = hash_path_walk($some_hash_ref => "level_1" => "level_2" => "leaf_element");
    I'm abusing the => notation instead of commas so it looks kinda like hash deferencing.

     



  • @jes said:

    I think I understand what is happening quite well.

    Which is precisely why you are likely to commit a WTF. See Alex's diatribe on "worse than failure", and how all of those people thought they understood and were doing the right thing.

    Most of the really great front-page WTFs included a guy who kept insisting "I know what I'm doing". 

     

    It has to do with Perl's behaviour not matching the documentation, since the documentation describes autovivification in an lvalue context, which defined() is not.

    See, that is what you are not understanding. The documentation is accurate and Perl's behaviour matches it. You just don't understand what it means, and you failed to even read my explanation of what was happening. This has got nothing to do with the defined() function. One last time, in case you still missed it:

    THIS HAS GOT NOTHING TO DO WITH THE defined FUNCTION.

    There is an lvalue context here. Your example includes an lvalue context which causes autovivification. The defined() function is not that context. You apparently don't know what an "lvalue context" means in perl.


    The fact that it may be in the camel book is not relevant.

    The camel is an example of a place where you could learn perl. The perl manpages are not such a place. The manpage text you quote is entirely correct, but since it's designed as a reference for people who already know perl, it doesn't take half a page to explain the meaning in detail and therefore is not a suitable place for you to learn how this works.

     

    Your conclusion that if I wasn't aware of this I don't know Perl well enough to be using it for serious applications is an indictment either of your attitude or the usefulness of Perl.

    Actually, it's an indictment of your knowledge of perl.

    Imagine an american tourist in france. He's lost his shoes. He says to the nearest frenchman: "avez vous seen mon shoes?". The frenchman stares at him like he's a moron, then walks off. The tourist goes off on a rant about how useless french is and how unhelpful french people are, despite his perfect understanding of the language.

    You are being that tourist. The problem here is not the language.

    (With apologies to Roald Dahl - I don't have a copy of the book, so I probably missed a few details in writing it from memory)

     

    If the language is only usable for people who are aware of what I can only consider to be counter-intuitive behaviour, then it is not fit for the purpose which it is most touted as serving.

    There's no such thing as intuitive behaviour in programming languages (or anything beyond "fight or flight", really). There is only "familiar" and "unfamiliar". Perl is only usable for people who are familiar with it, which you are obviously not. Everybody who is familiar with perl understands autovivification.

    Sadly, many people write things in perl without being familiar with it, resulting in a lot of really crappy code. 

     

    What, besides a rather snotty attitude, made you conclude that I was learning or would attempt to learn a language from the man pages?

    That would be your inability to find the explanation in the standard text, and instead relying on your misunderstanding of the manpage. I gave you the benefit of the doubt in assuming that you were trying to learn the language, rather than trying to use it without learning it (because that would be really stupid).

     

    What I do expect is that the manpages match the language, which I maintain they do not in this case.

    Well, you're just wrong, and the manpage is right.



  • @hk0 said:

    I agree that exists() throwing a warning would propably not very
    DWIM-ish. Then again though I wonder if an exists() call that silently
    changes data is so much more intuitive.

    I think the issue is that it's a necessity for exist to take an lvalue. Why?

    exists doesn't want to fully evaluate it's argument. It wants to do everything EXCEPT resolve the last reference to the data returned by that expression, which is exactly an lvalue. So like the left side of an = or += is lvalue, the parameter to exists is lvalue so it can "get at" what it wants to examine to return true/false.

    You're overcomplicating. It's nothing to do with the function. The exists function does not take an lvalue. It operates via an entirely different kind of evil.



  • <pre>

      Which is precisely why you are likely to commit a WTF. See Alex's
      diatribe on "worse than failure", and how all of those people
      thought they understood and were doing the right thing.
    </pre>


    Some of us test our software, which is what I was doing when I found this behaviour which I consider a misfeature. The autovivification came about owing to a error in my code which allowed a path to be taken which should only be taken under circumstances where the higher levels of the hash would exist. Later, the code processed each of the higher level items and was not prepared to find an empty hash for one of the keys. I tend to test my code and try to force it through the various execution paths, including error handling. But of course, I don't really know what I'm doing.

    <pre>
        Most of the really great front-page WTFs included a guy who kept
        insisting "I know what I'm doing".
    </pre>
    Not from those people who test their code and discover that there is un- or ill documented behaviour in the tools they are using.

    <pre>
            It has to do with Perl's behaviour not matching the
            documentation, since the documentation describes autovivification
            in an lvalue context, which defined() is not.


        See, that is what you are not understanding. The documentation is
        accurate and Perl's behaviour matches it. You just don't understand
        what it means, and you failed to even read my explanation of what
        was happening. This has got nothing to do with the defined()
        function. One last time, in case you still missed it:
    </pre>
    There you go again with your baseless assumptions. I read your explanation, I understood your explanation. I also understood what Perl was doing, otherwise I wouldn't have had the contrived example illustrating the issue.

    <pre>

        THIS HAS GOT NOTHING TO DO WITH THE defined FUNCTION.
    </pre>
    No, it has to do with autovivification in a non-lvalue context.
    <pre>
        There is an lvalue context here. Your example includes an lvalue
        context which causes autovivification. The defined() function is not
        that context. You apparently don't know what an "lvalue context"
        means in perl.
    </pre>
    I dispute that this function invocation is an lvalue context. Perl's own man pages suggest that it probably isn't an lvalue (see below). Perl's implementation treats it as _though_ it were an lvalue context. That doesn't make it one.
    <pre>
             The fact that it may be in the camel book is not relevant.

        The camel is an example of a place where you could learn perl. The
        perl manpages are not such a place. The manpage text you quote is
        entirely correct, but since it's designed as a reference for people
        who already know perl, it doesn't take half a page to explain the
        meaning in detail and therefore is not a suitable place for you to
        learn how this works.
    </pre>
    What a surprise, I've read the camel book, in more than one edition. I actually do know Perl, although unlike you, I don't claim to know every corner case. I didn't use the manpages to learn perl, or to see if I could legitimately write the code which caused me to stumble over this behaviour. I looked at the manpages when I found that autovivification takes place in a context where I would not expect it to and found that the manpages don't suggest anything different than my expectations. Why do you continue to assume I learned perl from the man pages? Your multiple WTFs which you made in your responses (this is not necessarily a complete list) are to leap to completely unwarranted conclusions, such as:
    <pre>
    1) that I'm trying to learn Perl
    2) that I'm trying to learn Perl from the manpages
    3) that I didn't understand your description of what Perl actually does in the case under discussion
    4) that I consider the example which illustrates the disputed behaviour as being a recommended coding practice since the perlfunc
        man page on 'defined' doesn't say not to do this
    5) that every Perl programmer should either be intimately familiar with every corner case of the language or should never write a Perl
        program for production use

            Your conclusion that if I wasn't aware of this I don't know Perl
            well enough to be using it for serious applications is an
            indictment either of your attitude or the usefulness of Perl.

        Actually, it's an indictment of your knowledge of perl.
    </pre>
    Given that Perl does not have anything similar to the ANSI C standards, the only language reference will either be the man pages and or books by the Perl developers. Since it's neither practical nor desireable to publish a new book per point release, it's important that the man pages be a complete and accurate description of the release which contains those  man pages, so a criticism that the man pages don't expressly point out that autovivification can occur when using 'defined' or that Perl will treat it as though it were an lvalue context is a legitimate point for criticism. It's also quite reasonable to question whether this behaviour is desireable. I'd be willing to bet that given a pool of experienced Perl programmers, a significant number of them would not be aware that testing defined($something{sub_level}->{sub_sub_level}) where  $something{sub_level}  does not exist would cause it to be created. Does that mean that all of those people should not be writing Perl programs? Even if, like me, they would never intentionally code such a test?

    <pre>
        Imagine an american tourist in france. He's lost his shoes. He says
        to the nearest frenchman: "avez vous seen mon shoes?". The frenchman
        stares at him like he's a moron, then walks off. The tourist goes
        off on a rant about how useless french is and how unhelpful french
        people are, despite his perfect understanding of the language.

        You are being that tourist. The problem here is not the language.

        (With apologies to Roald Dahl - I don't have a copy of the book, so
        I probably missed a few details in writing it from memory)
    </pre>
    A straw man argument of the first order. The closest you could get  with this rather poor analogy would be a tourist using a phrase book which had a mistranslation or failed to warn of local associations of a word; for example a British phrase book for visiting the US which included 'rubber' for eraser without pointing out the more common US usage of 'eraser' or the usual US meanings of the word 'rubber'. The tourist points out that the phrasebook is sub-optimal, which is hardly a rant, much less a rant against the populace of the US.

    The point I raised before was that if the documentation for Perl doesn't match the behaviour of Perl, for those with exposure to multiple languages and the concept of lvalues as it is usually used.

    Your attitude seems to be that only those who know both the documentation and the variances are fit to use the language is saying that Perl should not be used by anyone except those people who have explored all the darkest corners of the language. This doesn't match the description in the preface to the Camel book 'The Pursuit of Happiness', nor the
    real world.
    <pre>
            If the language is only usable for people who are aware of what I
            can only consider to be counter-intuitive behaviour, then it is not
            fit for the purpose which it is most touted as serving.

        There's no such thing as intuitive behaviour in programming
        languages (or anything beyond "fight or flight", really). There is
        only "familiar" and "unfamiliar". Perl is only usable for people who
        are familiar with it, which you are obviously not. Everybody who is
        familiar with perl understands autovivification.
    </pre>
    Nonsense of the first order. If a computer language has an underlying design, then the behaviour of parts not familiar to a programmer will not be surprisingly different to the behaviour already learned and will make sense as part of the overall design. Python's "everything is an object" and "variables are attached to objects, not the values of the objects" is a constant which carries through the language. A case where this were untrue would be counter-intuitive. Or imagine a language with integers, floats and complex types. You'd expect all 3 of those types to behave following the usual mathematical conventions and would find it counter-intuitive if addition, subtraction, multiplication and division of complex types followed the usual conventions but comparisions were done by saying 'complex X < complex  Y if  real(X)  <  real(Y)  or  (real(X) ==  real(Y)  and  imag(X) <  imag(Y)).
    Operations with surprising side effects are counter-intuitive.
    <pre>
        Sadly, many people write things in perl without being familiar with
        it, resulting in a lot of really crappy code.
    </pre>
    And the relevance of this is?
    <pre>
            What, besides a rather snotty attitude, made you conclude that I was
            learning or would attempt to learn a language from the man pages?

        That would be your inability to find the explanation in the standard
        text, and instead relying on your misunderstanding of the manpage. I
        gave you the benefit of the doubt in assuming that you were trying
        to learn the language, rather than trying to use it without learning
        it (because that would be really stupid).
    </pre>
    You truly are an arrogant ass and I pity anyone having the misfortune of sharing office space with you. The question wasn't whether Perl does this, it clearly does, but rather a) if it's well documented - I suggest not - and b) if it's a good feature - I suggest not and the 'exists' entry also suggest not.
    <pre>
            What I do expect is that the manpages match the language, which I maintain they do not in this case.

        Well, you're just wrong, and the manpage is right.
    </pre>
    Looking further, I find that perlfunc does mention this behaviour in perlfunc under 'exists', but not under 'defined'. And the text there suggests that it is a misfeature:
    <pre>
     This surprising autovivification in what does not at first--or even
     second--glance appear to be an lvalue context may be fixed in a
     future release.
    </pre>




  • If this behavior is so different from what happens throughout the rest of Perl, please find me an instance where you can have the code "$hash{KEY1}{KEY2}{KEY3}" anywhere and the first two levels of the hash (KEY1 and KEY2) don't spring into existence.  It would be counter-intuitive if the lower level hashed didn't spring into existence when used in exists or defined.



  • @jes said:


        See, that is what you are not understanding. The documentation is
        accurate and Perl's behaviour matches it. You just don't understand
        what it means, and you failed to even read my explanation of what
        was happening. This has got nothing to do with the defined()
        function. One last time, in case you still missed it:

    There you go again with your baseless assumptions.

    Your continuing failure to comprehend what is happening is all the basis needed.

    I dispute that this function invocation is an lvalue context.

    Which part of "THIS HAS GOT NOTHING TO DO WITH THE defined FUNCTION" are you having trouble understanding?

    This is normal autovivification in a normal lvalue context. It has got nothing to do with the function call that you happened to wrap around it.

    Until you start reading, you will remain ignorant.



  • @tster said:

    If this behavior is so different from what happens throughout the rest of Perl, please find me an instance where you can have the code "$hash{KEY1}{KEY2}{KEY3}" anywhere and the first two levels of the hash (KEY1 and KEY2) don't spring into existence.  It would be counter-intuitive if the lower level hashed didn't spring into existence when used in exists or defined.

    Not to mention impossible without radical changes to the language design (which have been made in Perl 6).



  • @asuffield said:

    @hk0 said:

    I agree that exists() throwing a warning would propably not very
    DWIM-ish. Then again though I wonder if an exists() call that silently
    changes data is so much more intuitive.

    I think the issue is that it's a necessity for exist to take an lvalue. Why?

    exists doesn't want to fully evaluate it's argument. It wants to do everything EXCEPT resolve the last reference to the data returned by that expression, which is exactly an lvalue. So like the left side of an = or += is lvalue, the parameter to exists is lvalue so it can "get at" what it wants to examine to return true/false.

    You're overcomplicating. It's nothing to do with the function. The exists function does not take an lvalue. It operates via an entirely different kind of evil.

     

    Whoops. You're right... speculative traversal is creation, whether or not you use the arrow operator.



  • @asuffield said:

    You have a fundamental failure to understand what is happening. (...) and if you didn't know about it, you do not know perl well enough to be using it for anything that matters. You cannot learn perl from the manpages (...)

    Don't play with tools that you don't understand. That's how WTFs happen. (...)

    Posts such as this is the definite proof that Perl is badly designed from the start. If it was a good design, the answer to a post like the OP would have been something along the lines of "Whoops, oh, I see how that could be confusing for a user. There have been discussions on this exact issue on (some mailinglist or other), and it will be fixed in the next release to do something more sane".

    If a language is to be successfull in the world, and have happy users, then it needs to be user friendly. Otherwise, the users will gladly switch to another language.

    I myself tried to learn Perl once. I sat down with it for a few days, but I got fed up with it and wrote my string-handling stuff in C instead (yup, thats true!). A few years later, I heard of this new language called Python, and in an afternoon, I had several working scripts. Score: Perl -1, Python +1.

    What I want to say with this is that if you are happy using Perl, and think it is a wonderful, great language, then you would automatically want to encourage people to use it, so that they too can see all the wonderfulness. Instead, Perl hackers more than often try to scare people away from the language, meaning that in a few years it will be a dead language, where no users are left to use it.

    Note that this whole post also applies in another forum here, but replace "Perl" with "Oracle"....



  • Very well said. What I think also applies is that some people are just mean-spirited / disgruntled by nature and need to be taken with a lot of salt. Maybe using perl/oracle for too long just changes them to be that way :-)



  • Gaah, let's see if I can clean up that formatting... 

     

    What part of the word context has escaped you?

    I stated that this function invocation - of the function 'defined', is not an lvalue context.
     

    If you wish to maintain that any mention of a hash element with more than a single level is an lvalue context, then I think you need to learn a bit more about computer langauges.

     

    You seem to be under the delusion that I don't know that Perl is doing autovivification here, and hence I am ignorant. You seem to think that telling me that Perl just does this and it has nothing to do with the function call is pointing out something I don't know, whereas my actual point was that autovivification in a rvalue context seems to me to be a bug, as it's undesireable behaviour and it's not well documented.

     

    Having just remembered that I had Programming Perl on-line on my home machine, I did a short scan for autovivification to see what it had to say, since it seems to be your Bible of the Perl world.

     

    =================
     

    Programming Perl, 3rd Edition:

    Section 8.3.3:

     

    This is one of those cases mentioned earlier in which references spring into existence (or "autovivify") when used as an lvalue (that is, when a value is being assigned to it). If $array[3] was undefined, it's automatically defined as a hash reference so that we can set a value for $array[3]->{"English"} in it. Once that's done, $array[3]->{"English"} is automatically defined as an array reference so that we can assign something to the first element in that array. Note that rvalues are a little different: print $array[3]->{"English"}->[0] only defines $array[3] and $array[3]->{"English"}, not $array[3]->{"English"}->[0], since the final element is not an lvalue. (The fact that it defines the first two at all in an rvalue context could be considered a bug. We may fix that someday.)

     

    =================

    Someone else who seems to think it's not an lvalue context, but an rvalue context.

     

    And if you consider anyone who hasn't read and remembered the last two lines of that one paragraph as being unequipped to program in Perl, then you simply confirm what an arrogant ass your are.

     

    Another and perhaps more interesting discussion would be whether the entire concept of autovivification is a good idea. It certainly removes the ability to catch a certain, probably not uncommon class of errors - misspelling a key name in a sub-hash:

     

    thing{$customer}->{separate_invoice}->{total_sales_tax} += $sales_tax;

    thing{$customer}->{seperate_invoice}->{total_amount} += $this_invoice_amount;

     

    Is unlikely to be what's wanted and won't raise an error or warning.

    The counter argment is that it prevents some one-liners being written doesn't exactly convince me of the wonderfulness of this functionality. Without autovivification, then the second line would require that the misspelt key had already been inserted in a separate operation, which is far less likely to occur.



  • Okay, all of you involved in these long, drawn-out exchanges are turning out to be complete prats.  Why not take this off-line into an e-mail exchange so you don't waste valuable server space with your vomit exchange?

    #1 Perl best practice: Don't Use Perl!



  • @boh said:

    If a language is to be successfull in the world, and have happy users, then it needs to be user friendly.

    That is the sort of dogmatic bigotry that leads to idiocracy.

    It is not the only way to be successful, fortunately. No matter how much you might want it to be.

    (And there is a surprisingly large number of new accounts here - probably more than the number of new users)

     

    What I want to say with this is that if you are happy using Perl, and think it is a wonderful, great language, then you would automatically want to encourage people to use it, so that they too can see all the wonderfulness. Instead, Perl hackers more than often try to scare people away from the language, meaning that in a few years it will be a dead language, where no users are left to use it.

    Perl hackers want people to learn perl. If it is obvious that a person has no interest in learning perl, we're all better off if they don't use it. It's usually quite easy to tell which group a person falls into - the ones who begin with a rant about "how much better python is" are not interested in learning perl, and it is a waste of time to try changing their mind on that point.

    Nobody sane wants to encourage programmers who suck. Someday you might have to use something that they wrote, and then you would regret it.



  • @jes said:

    I stated that this function invocation - of the function 'defined', is not an lvalue context.

    While strictly true, this statement is utterly irrelevant to the matter at hand, as I have told you repeatedly.


    If you wish to maintain that any mention of a hash element with more than a single level is an lvalue context, then I think you need to learn a bit more about computer langauges.

    And yet perl continues to work the way I say it does, and not the way you think it does. Funny how that happens.

     

    Someone else who seems to think it's not an lvalue context, but an rvalue context.

    There is an rvalue context here (notably the function call which you keep obsessing over). There is also an lvalue context, and that's the one which is causing autovivification, like every lvalue context does. In perl (like in most languages that aren't pure-functional) there is no rule against having both in a single expression.

     

    Another and perhaps more interesting discussion would be whether the entire concept of autovivification is a good idea. It certainly removes the ability to catch a certain, probably not uncommon class of errors - misspelling a key name in a sub-hash:

    I have already told you that perl provides this if you want it. The perl philosophy is to provide things like this *only* if you want them, so it's not the default.

    (Your examples will be caught under 'use warnings', and you can get exceptions by using restricted hashes or pseudohashes) 



  • @asuffield said:

    @jes said:

    Another and perhaps more interesting discussion would be whether the entire concept of autovivification is a good idea. It certainly removes the ability to catch a certain, probably not uncommon class of errors - misspelling a key name in a sub-hash:

    I have already told you that perl provides this if you want it. The perl philosophy is to provide things like this *only* if you want them, so it's not the default.

    (Your examples will be caught under 'use warnings', and you can get exceptions by using restricted hashes or pseudohashes) 

    Care to amplify on how 'use warnings;' will catch such a typo? It doesn't produce any warnings under Perl 5.86. Yes, using Hash::Util does allow trapping such errors, but at quite a cost for programs where hashes are used to collect and order data from a wide variety of sources. It's unlikely to be commonly adopted simply to eliminate the effects of typos. But use warnings by itself is insufficient:


    jes:/usr/home/jes$ cat x.pl
    use strict;
    use warnings;

    use Data::Dumper;

    my %thing;
    my ($customer, $sales_tax, $this_invoice_amount)  = ("fred", 1.75. 22.79);
    $thing{$customer}->{separate_invoice}->{total_sales_tax} += $sales_tax;
    $thing{$customer}->{seperate_invoice}->{total_amount} += $this_invoice_amount;

    print Dumper(%thing);

    jes:/usr/home/jes$ perl x.pl
    $VAR1 = 'fred';
    $VAR2 = {
              'seperate_invoice' => {
                                      'total_amount' => '22.79'
                                    },

              'separate_invoice' => {
                                      'total_sales_tax' => '1.75'
                                    }
            };
    jes:/usr/home/jes$

    And re. your other comments in your reply to boh:

    @asuffield said:

    Perl hackers want people to learn perl. If it is obvious that a person has no interest in learning perl, we're all better off if they don't use it. It's usually quite easy to tell which group a person falls into - the ones who begin with a rant about "how much better python is" are not interested in learning perl, and it is a waste of time to try changing their mind on that point.

    Nobody sane wants to encourage programmers who suck. Someday you might have to use something that they wrote, and then you would regret it.

     

    If you are directing these comments at me, I'd point out that I didn't say "how much better Python is". Perl has its uses and in some areas is far more convenient than Python. It also has its built in oddities and a distinct lack of an overall design - it's a lanuguage that has been around for a lot longer than Python and has grown by accretion, not always in what I would describe as an orderly way. That observation and my initial posting hardly constitutes a rant, nor have I seen anyone else in this thread 'ranting' about the relative merits of one language or another. I certainly find Perl's integration of regular expressions to be very convenient when programming when compared to many other languages.

    As to whether or not I suck as a programmer, or whether programs I've written are useful or maintainable, you have zero evidence to offer any opinion on that matter. You do seem unduly disturbed that I have pointed out that Perl's documentation doesn't match it's behaviour very well and that the effects of autovivification leave some nasty surprises for the unwary.

     


Log in to reply