How to get an empty generator?

I have a method that takes a generator plus some additional parameters and gives a new generator:

function merge(\Generator $carry, array $additional) { foreach ( $carry as $item ) { yield $item; } foreach ( $additional as $item ) { yield $item; } } 

A typical usage example for this function is similar to this:

 function source() { for ( $i = 0; $i < 3; $i++ ) { yield $i; } } foreach ( merge(source(), [4, 5]) as $item ) { var_dump($item); } 

But the problem is that sometimes I need to pass an empty source to the merge method. Ideally, I would like to do something like this:

 merge(\Generator::getEmpty(), [4, 5]); 

That is exactly what I would do in C # (there is the IEnumerable<T>.Empty ). But I do not see the empty generator in the manual .

I managed to get around this (for now) with this function:

 function sourceEmpty() { if ( false ) { yield; } } 

And it works. The code:

 foreach ( merge(sourceEmpty(), [4, 5]) as $item ) { var_dump($item); } 

correctly displays:

 int(4) int(5) 

But this is obviously not an ideal solution. What would be the correct way to pass an empty generator to the merge method?

+11
source share
4 answers

I found a solution:

Since \Generator extends \Iterator , I can simply change the method signature to this:

 function merge(\Iterator $carry, array $additional) { // ... 

This is covariance of input, so it will break backward compatibility, but only if someone has expanded the merge method. Any calls will still work.

Now I can call the method with the native PHP EmtpyIterator :

 merge(new \EmptyIterator, [4, 5]); 

And a regular generator also works:

 merge(source(), [4, 5]) 
+4
source

The bit was late, but I needed an empty generator, and it is actually quite simple to implement it ...

 function empty_generator(): Generator { yield from []; } 

I don’t know if this is better with EmptyIterator , but this way you get exactly the same type as non-empty generators.

+13
source

As explained in the white papers , you can create an instance of Generator in a string using yield in an expression:

 $empty = (yield); 

This should work, but when I tried to use it, I got a fatal error (the yield expression can only be used in a function). Using null did not help:

 $empty = (yield null); //error 

So, I think you are stuck in the sourceEmpty function ... this is the only thing I found that works ... notice that it will create a null value in the array that you are repeating. <w> All code has been tested on PHP 5.5.9, BTW

The best fix I can come up with (since the compatibility issue is the issue) would be for both arguments to be optional:

 function merge(\Generator $carry = null, array $additional = array()) { if ($carry) foreach ($carry as $item) yield $item; foreach ($additional as $item) yield $item; } foreach(merge(null, [1,2]) as $item) var_dump($item); 

Thus, the existing code will not slow down, and instead of building an empty generator, passing null will also be very good.

+1
source

Just for completeness, perhaps the least detailed answer so far:

 function generator() { return; yield; } 

I just wondered about the same question and recalled the earlier description in the documents (which should be at least semantically by today) that a generator function is any function with the yield keyword.

Now that the function returns before it exits, the generator should be empty.

And so it is.

Example at 3v4l.org: https://3v4l.org/iqaIY

0
source

Source: https://habr.com/ru/post/1200841/


All Articles