Naturally lazy
D:\>6e "my @bar = 'a', 'b', 'c'; sub foo( @b ) { my $bar = 0; gather loop { print "*"; take ($bar, @b[$bar]); $bar++; last if $bar > 2; } }; .print for foo( @bar )"
*(0 a)*(1 b)*(2 c)
So far, so expected. Now, let's be eager.
D:\>6e "my @bar = 'a', 'b', 'c'; sub foo( @b ) { my $bar = 0; eager gather loop { print "*"; take ($bar, @b[$bar]); $bar++; last if $bar > 2; } }; .print for foo( @bar )"
***(3 a)(3 b)(3 c)
Why on earth are the numeric values all "3"? As if, I don't know, the closure vanished in a puff of illogic. take-rw
doesn't cut it, either.
D:\>6e "my @bar = 'a', 'b', 'c'; sub foo( @b ) { my $bar = 0; eager gather loop { print "*"; take-rw ($bar, @b[$bar]); $bar++; last if $bar > 2; } }; .print for foo( @bar )"
***(3 a)(3 b)(3 c)
I can mitigate
D:\>6e "my @bar = 'a', 'b', 'c'; sub foo( @b ) { my $bar = 0; eager gather loop { print "*"; take-rw ($bar + 0, @b[$bar]); $bar++; last if $bar > 2; } }; .print for foo( @bar )"
***(0 a)(1 b)(2 c)
But why do I have to?
Edit: So, questions boils down to,
>6e "my $bar = 0; .say for gather { take ($bar,); $bar++; take ($bar,) }"
(0)
(1)
>6e "my $bar = 0; .say for eager gather { take ($bar,); $bar++; take ($bar,) }"
(1)
(1)
It is still unexplained, why there is a difference in behaviour in eager
vs. lazy
case.
Eager fetching is the ability to efficiently load subclass data and related objects along with the base instances being queried.
LAZY: It fetches the child entities lazily i.e at the time of fetching parent entity it just fetches proxy(created by cglib or any other utility) of the child entities and when you access any property of child entity then it is actually fetched by hibernate. EAGER: it fetches the child entities along with parent.
The FetchType. LAZY tells Hibernate to only fetch the related entities from the database when you use the relationship. This is a good idea in general because there's no reason to select entities you don't need for your uses case. You can see an example of a lazily fetched relationship in the following code snippets.
Eager Loading is a design pattern in which data initialization occurs on the spot. Lazy Loading is a design pattern that we use to defer initialization of an object as long as it's possible.
Holli has accepted the answer that quoted two of Brad's comments. I deliberately kept that one terse.
But you're reading this.1 So I'll go in the opposite direction with this answer.
($bar,...)
is a list containing $bar
, not $bar
's valueThe behavior shown in the question really is all about containers vs values, and how list literals store containers, not their values1:
my $bar = 0;
my $list = ($bar,);
say $list[0]; # 0
$bar = 1;
say $list[0]; # 1
The laziness vs eager aspect is just things doing what they're all supposed to do. Emphasizing this first point may be enough to inspire you to focus on containers vs values. And maybe that'll lead you to quickly understand what went wrong in Holli's code. But maybe not.1 So I'll continue.
A lazy list waits until a value is demanded before attempting to produce it. Then, it just does the necessary work and pauses, yielding control, until it's asked to produce another value at some later time.
In Holli's code the for
loop demands values.
The first time around the for
loop, it demands a value from the lazy
expression. This turns around and demands a value from the gather
'd expression. The latter then computes until the take
, by which time it's created a list whose first element is the container $bar
. This list is the result of the take
.
Then the .print
prints that first list. At the moment of printing, $bar
still contains 0
. (The first increment of $bar
hasn't yet happened.)
The second time around the for
loop, the inner control structure enclosing the take
(the loop
) is re-entered. The first thing that happens is that $bar
gets incremented for the first time. Then the loop exit condition is checked (and fails), so the second time around the loop starts. Another list is created. Then it's take
d.
When the second list is printed, its first element, which is the $bar
container, prints as 1
, not 0
, because at that point, having been incremented, $bar
now contains 1
.
(If Holli had written code that held onto the first list, and printed that first list again now, after having just printed the second list, they'd have discovered that the first list also now printed with a 1
, no longer a 0
. Because all the take
d lists have the same $bar
container as their first element.)
And likewise the third list.
After the third list has been printed, the for
loop demands a fourth go at the gather
. This re-enters the loop
at the statement after the take
statement. $bar
gets incremented for the third time, to 3
, and then the last if $bar > 2;
condition triggers, exiting the loop (and thus the expression being gather
'd and ultimately the whole .print for ...
statement).
All the gather
ing is completed before any of the print
ing.
At the end of this, the for
construct has a sequence of three lists. It has not yet called any .print
calls. The third time around the loop
in the gather
has left $bar
containing 3
.
Next, .print
is called on each of the three lists. $bar
contains 3
so they all print with 3
as their first element.
I think the idiomatic way to deal with this would be to switch from a list literal to an array literal:
[$bar, @bar[$bar]]
# instead of
($bar, @bar[$bar])
This works because, unlike a list literal, an array literal treats an element that's a container as an r-value2, i.e. it copies the value contained in the container out of that container, rather than storing the container itself.
It just so happens that the value is copied into another new Scalar
container. (That's because all elements of new non-native arrays are fresh Scalar
containers; this one of the main things that makes an array different from a list.) But the effect in this context is the same as if the value were copied directly into the array because it no longer matters that the value contained in $bar
is changing as things proceed.
The upshot is that the first element of the three arrays ends up containing, respectively, 0
, 1
, and 2
, the three values that were contained in $bar
at the time each array was instantiated.
As Holli noted, writing $bar + 0
also worked.
In fact any expression will do, so long as it isn't just $bar
on its own.
Of course, the expression needs to work, and return the right value. I think $bar.self
should work and return the right value no matter what value $bar
is bound to or assigned.
(Though it does read a little strangely; $bar.self
is not $bar
itself if $bar
is bound to a Scalar
container! Indeed, in an even more counter-intuitive twist, even $bar.VAR
, which uses .VAR
, a method which "Returns the underlying Scalar
object, if there is one.", still ends up being treated as an r-value instead!)
The above is an entirely logical consequence of:
What Scalar
s are;
What list literals do with Scalar
s;
What lazy vs eager processing means.
If the doc is weak, it's presumably in its explanation of one of the last two aspects. It looks like it's primarily the list literal aspect.
The doc's Syntax page has a section on various literals, including Array literals, but not list literals. The doc's Lists, sequences, and arrays does have a List literals section (and not one on Arrays) but it doesn't mention what they do with Scalar
s.
Presumably that warrants attention.
The Lists, sequences, and arrays page also has a Lazy lists section that could perhaps be updated.
Putting the above together it looks like the simplest doc fix might be to update the Lists, sequences, and arrays page.
1 In my first couple versions of this answer (1, 2, I tried to get Holli to reflect on the impact of containers vs values. But that failed for them and maybe hasn't worked for you either. If you're not familiar with Raku's containers, consider reading:
Containers, the official doc's "low-level explanation of Raku containers".
Containers in Perl 6, the third of Elizabeth Mattijsen's series of articles about Raku fundamentals for those familiar with Perl.
2 Some of the details in Wikipedia's discussion of "l-values and r-values" don't fit Raku but the general principle is the same.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With