http://www.perlmonks.org?node_id=1044071


in reply to Re^2: Conditional array initialisation?
in thread Conditional array initialisation?

The old use of defined @arr is deprecated, cause the logic was broken.

For me undefined means "not initialized" (yet), like with  my $a. But this state doesn't exist for array and hashes, they are initialized empty.

And if it existed it would be different from (defined and) empty.

Nevertheless undef @a is allowed, adding even more confusion:

DB<153> @a => (1, 2, 3, 4, 5, 6) DB<154> undef @a => undef DB<155> \@a => []

Cheers Rolf

( addicted to the Perl Programming Language)

Replies are listed 'Best First'.
Re^4: Conditional array initialisation? (Question expanded)
by BrowserUk (Patriarch) on Jul 12, 2013 at 21:24 UTC
    Nevertheless undef @a is allowed, adding even more confusion:

    I don't see any confusion nor potential for it.

    If I have a scalar and at some point in my code I wish to check if it currently has a value, and if it does not, set it, I might write:

    my $x; ... $x = getValue() unless defined $x;

    More recently, I'd write that as: $x //= getValue();. Clear concise semantics.

    If have an array, and at some point in my code I want to check if it contains anything, and populate it if it does not, I might write:

    my @a; ... @a = getValues() unless @a;

    Thus using the value of the array in a scalar context to decide if the array is empty or not.

    It seems a natural, semantically clear, easily implemented extension of the scalar case above to write that as:

    @a //= getValues();

    Test the scalar context value of the array, and if it is false, assign the list on the right hand side to the array on the left.

    Indeed, it seemed so logically analogous, and semantically clear, that I wrote it and expected it to work, and I was taken by considerable surprise that it didn't.

    Hence my OP.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      If have an array, and at some point in my code I want to check if it contains anything,

      I'm not sure why you are throwing in "defined" in this scenario. Your scenario makes perfect sense for a Boolean test but, indeed, there was often confusion with "defined" related to your stated purpose:

      $ perl -del > x defined @a '' > @a = (1..3) > x defined @a 1 > @a = () > x defined @a 1

      That is, people were often asking "defined @a" when they meant "is @a empty". The mistake was so common (you appear to have just made that mistake yourself) that "defined @a" was made to complain.

      But that seems mostly a distraction from your original question, which should be restricted to ||= (since //= doesn't mean what you thought it did).

      So why doesn't @a ||= (1..3); work? Well, the definition of ||= implies that such should be the same as @a = @a || (1..3). But you never wrote that as an alternative... because it doesn't work, either.

      @a = @a || (1..3); doesn't "work" because the left side of || is in a scalar context so it is the same as @a = 0+@a || (1..3);. Which means it changes @a when @a isn't empty. (FYI, I'm sure BrowserUk knew this, so I'm just explaining that for other readers.)

      I'm certainly sympathetic to the argument that it makes sense to special-case @a ||= ... so that it will DWYM. I can see somebody arguing against it because they worry it will make it more likely for people to mistakenly write @a || .... Or because it breaks the rules about how ||= was defined.

      I find both sides of that argument roughly equally persuasive.

      My response as to why @a ||= ... doesn't work is simply that nobody has taken the time to special-case it to make it DWYM instead of making it match @a = @a || ...

      I'll suggest the following alternative idiom:

      @a or @a = (1..3);

      Maybe that will lead to somebody adding an or= operator so you can then write @a or= (1..3);?

      - tye        

        Hello tye,

        Thanks for this explanation. When I first read the OP, I completely overlooked the fact that || puts its LHS into scalar context.

        However:

        ... instead of making it match @a = @a || ...

        But it doesn’t match!

        13:08 >perl -MData::Dump -wE "@a = @a || (1 .. 3); dd \@a;" [1, 2, 3] 13:08 >perl -MData::Dump -wE "@a ||= (1 .. 3); dd \@a;" Can't modify array dereference in logical or assignment (||=) at -e li +ne 1, near ");" Execution of -e aborted due to compilation errors. 13:09 >perl -v This is perl 5, version 18, subversion 0 (v5.18.0) built for MSWin32-x +86-multi-thread-64int

        From the error message, it appears that the ||= operator is putting its LHS into scalar context. Am I correct in reading it this way? If so, it seems strange that perlop#Assignment-Operators doesn’t highlight this important semantic difference between X = X op Y and X op= Y?

        Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

        That is, people were often asking "defined @a" when they meant "is @a empty". The mistake was so common (you appear to have just made that mistake yourself) that "defined @a" was made to complain.

        If the use of defined on aggregates doesn't match the common expectation; and the actual meaning is non-useful; doesn't it make sense to make it useful by making it match the common expectation?

        That's the question. And I think you've supplied the answer, albeit unknowingly.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.