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


in reply to Re^4: Conditional array initialisation? (Question expanded)
in thread Conditional array initialisation?

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        

Replies are listed 'Best First'.
Re^6: Conditional array initialisation? (scalar, !defined)
by Athanasius (Archbishop) on Jul 13, 2013 at 03:49 UTC

    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,

      Yes, there are some subtle points that I didn't go into.

      First, making @a ||= ... the same as @a = @a || ... would just be leaving a trap. So it is actually a good thing (IMHO) that @a ||= ... is fatal rather than just being identical to @a = @a || .... (And I'm pretty sure that this fatalness was more just a result of implementation details than of extra work to not leave a non-fatal trap.)

      I don't recall the details, but I do recall that there are some subtle differences even between $a = $a || ... vs. $a ||= .... The differences boil down to subtle differences in how $a ||= ... is implemented, and these boil down (IMHO) mostly to matters of efficiency of implementation.

      $a = $a || ... actually deals with $a twice while $a ||= ... deals with $a once.

      So one way to think about why @a ||= ... is fatal is to realize that it isn't just @a = @a || ... but that both of the "@a"s in that expression are dealt with in a single go. So, rather than being like @a = 0+@a || ..., it ends up more like 0+@a = 0+@a || ....

      $ perl -e '@a ||= 1..3' Can't modify array dereference in logical or assignment (||=) ... $ perl -e '0+@a = 0+@a || 1..3' Can't modify addition (+) in scalar assignment ...

      Or you can think of it more like scalar @a = scalar @a || ..., like you guessed.

      If so, it seems strange that perlop#Assignment-Operators doesn’t highlight this important semantic difference

      But it isn't an important semantic difference. It is a subtle difference that mostly doesn't matter. The case where it easily matters is when you try to assign to an array. But that difference isn't "important" because the difference is between something that fails loudly and something that does something you didn't intend.

      op= is only useful on scalars. So there are some subtle details of implementation that are quite difficult to even intentionally arrange for them to matter when using a scalar. And those details are basically due to optimizations, which makes them much more likely to change in future versions of Perl. So these are not the types of things to try to document.

      The thing to document about using op= on an array would be to simply note that it doesn't work. Trying to document inaccurate explanations about subtle implementation details related to that isn't particularly useful.

      - tye        

Re^6: Conditional array initialisation? (scalar, !defined)
by BrowserUk (Patriarch) on Jul 13, 2013 at 03:28 UTC
    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.
      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?

      Meh. I see little advantage to providing a second, more verbose, less clear way of getting the exact same answer. I much prefer a compile-time notification of "you put 'defined' in there, but that doesn't do a dang bit of good; maybe you should double check that code or reread some documentation". This author may have been trying for some other meaning, even if such is not the majority case. Why leave a bunch of people scratching their heads about why some places use 'defined' and some don't?

      But, even if such were the chosen design decision, it still would have required that first, the old meaning be deprecated. So the current state is required no matter what.

      - tye