This must be a common code conversion, so I am surprised that I cannot easily find what it is called nor info on how best to do it.
Original code (pseudo):
sub generate_array {
for(i=0,n=0;i<X;++i)
for(j=0;j<Y;++j)
for(k=0;k<p[i][j];++k,++n)
a[n] = calculation(i,j,k,n,p);
return a;
}
m=generate_array();
for(i=0;i<size(m);++i)
if (some_cond(m[i]) break;
work_with(m[i]);
For time-efficiency reasons, I want to lazy-eval the array instead thus:
sub array_start() {...}
sub array_next() {... return val}
array_start();
while (m = array_next())
if some_cond(m) break;
work_with(m);
Yes, it's called "lazy evaluation" generally (design pattern), but isn't this specific and basic type of code conversion called something more specific? I've also looked up "iterator" and "factory" design patterns, and "loop unrolling", but nothing is a good conceptual fit to what I'm talking about. Any ideas? What am I missing? Guidance appreciated.
Update
The answer is "generator" as given below. As for the "conversion" of code, the core change from above would be a[n] =
--> yield
, and of course using whatever syntax defines a generator rather than a subroutine. But it's also possible to implement the idea "by hand" (at least for this simple case), if your language doesn't support it and/or you don't want to use a 3rd-party package to implement it, by "unnesting" all the loops:
sub array_next {
if (++k >= p[i][j])
k = 0;
if (++j >= Y)
j = 0;
if (++i >= X)
return false
return calculation(i,j,k,p)
}
sub array_start {
i = j = k = 0;
}
Note a difference that needs to be handled correctly though: the variables (i
, j
, k
) have become global, or at least exposed.
What you are doing here is not exactly lazy evaluation because it usually refers to the delayed evaluation of a certain expression, which is common in functional programming. From the Wikipedia article on Lazy Evaluation:
[...] lazy evaluation, or call-by-need is an evaluation strategy which delays the evaluation of an expression until its value is needed [...]
What you are building here fits very well the term generator. From the Wikipedia article on Generators:
[...] a generator is a special routine that can be used to control the iteration behaviour of a loop. In fact, all generators are iterators. A generator is very similar to a function that returns an array, in that a generator has parameters, can be called, and generates a sequence of values. However, instead of building an array containing all the values and returning them all at once, a generator yields the values one at a time, which requires less memory and allows the caller to get started processing the first few values immediately.
If the sequence being generated is infinite, the generator is often referred to as a stream. However, the term stream is also used for finite sequences that are computed on demand.