New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Extra template on certain iterators #8053
Comments
I found these snippets: https://psalm.dev/r/17b32189e1<?php
/**
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
declare(strict_types=1);
namespace loophp\iterators;
use CachingIterator;
use Generator;
use Iterator;
use IteratorAggregate;
// phpcs:disable Generic.Files.LineLength.TooLong
/**
* @template TKey of array-key
* @template T
*
* @implements IteratorAggregate<array-key, T>
*/
final class SimpleCachingIteratorAggregate implements IteratorAggregate
{
/**
* @var CachingIterator<array-key, T>
*/
private CachingIterator $iterator;
/**
* @param Iterator<array-key, T> $iterator
*/
public function __construct(Iterator $iterator)
{
$this->iterator = new CachingIterator(
$iterator,
CachingIterator::FULL_CACHE
);
}
/**
* @return Generator<array-key, T>
*/
public function getIterator(): Generator
{
yield from $this->iterator->getCache();
while ($this->iterator->hasNext()) {
$this->iterator->next();
yield $this->iterator->key() => $this->iterator->current();
}
}
}
|
@drupol It's the type of the iterator it's wrapping, but afaict there seems to be a bug with template comparisons: https://psalm.dev/r/ffa90f6c5b (@orklah am I missing something?) You also have a You should also probably be using |
I found these snippets: https://psalm.dev/r/ffa90f6c5b<?php
/**
* @template TKey of array-key
* @template T
*
* @implements IteratorAggregate<array-key, T>
*/
final class SimpleCachingIteratorAggregate implements IteratorAggregate
{
/**
* @var CachingIterator<array-key, T, Iterator<array-key, T>>
*/
private CachingIterator $iterator;
/**
* @param Iterator<array-key, T> $iterator
*/
public function __construct(Iterator $iterator)
{
$this->iterator = new CachingIterator(
$iterator,
CachingIterator::FULL_CACHE
);
}
/**
* @return Generator<array-key, T>
*/
public function getIterator(): Generator
{
yield from $this->iterator->getCache();
while ($this->iterator->hasNext()) {
$this->iterator->next();
yield $this->iterator->key() => $this->iterator->current();
}
}
}
https://psalm.dev/r/2196c8e242<?php
/**
* @template-covariant TKey of array-key
* @template-covariant TValue
*
* @implements IteratorAggregate<TKey, TValue>
*/
final class SimpleCachingIteratorAggregate implements IteratorAggregate
{
/**
* @var CachingIterator<TKey, TValue, Iterator<TKey, TValue>>
*/
private CachingIterator $iterator;
/**
* @param Iterator<TKey, TValue> $iterator
*/
public function __construct(Iterator $iterator)
{
$this->iterator = new CachingIterator(
$iterator,
CachingIterator::FULL_CACHE
);
}
/**
* @return Generator<TKey, TValue>
*/
public function getIterator(): Generator
{
yield from $this->iterator->getCache();
while ($this->iterator->hasNext()) {
$this->iterator->next();
yield $this->iterator->key() => $this->iterator->current();
}
}
public function hasNext(): bool
{
return $this->iterator->hasNext();
}
}
|
Hi, Thanks for the suggestion. I'm not using If you could help me on this, I'll be glad to implement the necessary changes. Thanks! |
I found these snippets: https://psalm.dev/r/ffa90f6c5b<?php
/**
* @template TKey of array-key
* @template T
*
* @implements IteratorAggregate<array-key, T>
*/
final class SimpleCachingIteratorAggregate implements IteratorAggregate
{
/**
* @var CachingIterator<array-key, T, Iterator<array-key, T>>
*/
private CachingIterator $iterator;
/**
* @param Iterator<array-key, T> $iterator
*/
public function __construct(Iterator $iterator)
{
$this->iterator = new CachingIterator(
$iterator,
CachingIterator::FULL_CACHE
);
}
/**
* @return Generator<array-key, T>
*/
public function getIterator(): Generator
{
yield from $this->iterator->getCache();
while ($this->iterator->hasNext()) {
$this->iterator->next();
yield $this->iterator->key() => $this->iterator->current();
}
}
}
https://psalm.dev/r/2196c8e242<?php
/**
* @template-covariant TKey of array-key
* @template-covariant TValue
*
* @implements IteratorAggregate<TKey, TValue>
*/
final class SimpleCachingIteratorAggregate implements IteratorAggregate
{
/**
* @var CachingIterator<TKey, TValue, Iterator<TKey, TValue>>
*/
private CachingIterator $iterator;
/**
* @param Iterator<TKey, TValue> $iterator
*/
public function __construct(Iterator $iterator)
{
$this->iterator = new CachingIterator(
$iterator,
CachingIterator::FULL_CACHE
);
}
/**
* @return Generator<TKey, TValue>
*/
public function getIterator(): Generator
{
yield from $this->iterator->getCache();
while ($this->iterator->hasNext()) {
$this->iterator->next();
yield $this->iterator->key() => $this->iterator->current();
}
}
public function hasNext(): bool
{
return $this->iterator->hasNext();
}
}
|
Basically, by default Generally, if you have a templated class that doesn't need to take the template as an argument you should prefer to use covariant templates since they allow code using the class more freedom by imposing extra restrictions on the class itself. |
I found these snippets: https://psalm.dev/r/5565ec3b9f<?php
/**
* @template T
*/
class Collection
{
/** @param list<T> $items */
public function __construct(private array $items) {}
/** @param T $item */
public function add($item): void
{
$this->items[] = $item;
}
/** @return Iterator<int, T> */
public function iterate(): Iterator
{
return new ArrayIterator($this->items);
}
}
class Animal {}
class Cat extends Animal
{
public function meow(): void {}
}
class Dog extends Animal
{
public function bark(): void {}
}
$cats = new Collection([new Cat()]);
/** @param Collection<Animal> $animals */
function addDog($animals): void
{
$animals->add(new Dog());
}
addDog($cats); // Collection<Cat> is not a Collection<Animal>
foreach ($cats->iterate() as $cat) {
$cat->meow(); // Runtime error, Dog cannot meow
}
https://psalm.dev/r/18aca553c9<?php
/**
* @template-covariant T
*/
class Collection
{
/** @param list<T> $items */
public function __construct(private array $items) {}
/** @param T $item This is disallowed so that the collection type cannot be modified to include sibling types */
public function add($item): void
{
$this->items[] = $item;
}
/** @return Iterator<int, T> */
public function iterate(): Iterator
{
return new ArrayIterator($this->items);
}
}
class Animal {}
class Cat extends Animal
{
public function meow(): void {}
}
class Dog extends Animal
{
public function bark(): void {}
}
$cats = new Collection([new Cat()]);
/** @param Collection<Animal> $animals */
function addDog($animals): void
{
$animals->add(new Dog());
}
addDog($cats); // Collection<Cat> _is_ a Collection<Animal>
foreach ($cats->iterate() as $cat) {
$cat->meow(); // Runtime error, Dog cannot meow
}
|
Hey hi,
I'm testing Psalm 5b1 and I have this new issue:
This comes from there: https://github.com/loophp/iterators/blob/main/src/SimpleCachingIteratorAggregate.php#L28
I'm trying to understand why does
\CachingIterator
needs 3 template parameters ?Therefore, how to fix this then ? https://psalm.dev/r/17b32189e1
Originally posted by @drupol in #6970 (comment)
The text was updated successfully, but these errors were encountered: