On Mon, Dec 1, 2025, at 9:38 AM, Rowan Tommins [IMSoP] wrote:
> On 01/12/2025 14:26, Tim Düsterhus wrote:
>> You are wrong here. Manually interacting with an Iterator is not just
>> safe, it is also necessary for some use cases. The simplest example
>> would be iterating two Iterators in lock-step (i.e. doing a `zip()`
>> operation / array_combine()).
>
>
> It is certainly *possible* to use the Iterator methods safely without a
> foreach() construct or built-in aggregate; but it's also easy to miss
> the implications, and cause very confusing behaviour. For instance, you
> could call next() in two different pieces of code, and each would miss
> half the items; or you could call rewind() on an iterator that was
> already in use elsewhere.
>
> The same is true of the ContextManager interface: you could certainly
> call enterContext() and exitContext() manually with no problems at all.
> It might even be necessary, for much the same reasons as iterators: you
> might want to write code that aggregates two context managers in a
> specific arrangement.
>
>
> As I understand it, your concern is that someone will call
> enterContext() without exitContext(). You could do exactly the same
> thing if you manually handle an Iterator.
>
> Consider this method:
>
> function getDataIterator(): Generator {
> $this->acquireLock();
> while ( $this->hasMoreResults() ) {
> yield $this->getNextResult();
> }
> $this->releaseLock();
> }
>
> If the user calls $it = $foo->getDataIterator(), they can call
> $it->current() and get a result, but never call $it->next(). They could
> even use it in a foreach() loop but `break` out before consuming all the
> results. In such cases, the lock would never be released, unless there's
> an extra safety check in the destructor.
Excellent example, thank you.
> I think the currently proposed names actually make that *less* likely
> for a ContextManager: if you enter something, you probably want to exit
> it later.
>
> We could reinforce that further by also prefixing the method names with
> "__", but we don't have any precedent for that, and misuse would still
> be possible.
Python uses magic methods here, and we considered it, but given that you will
basically always want both methods we felt an interface was easier and provided
better type checks. If there were multiple callbacks (say, a different one for
a success exit and a fail exit), then magic methods might make more sense.
If you're suggesting having interface methods that begin with __, I agree that
would be novel for no particular value. You can't screw up ContextManagers
through misuse any more than you can screw up Iterator or ArrayAccess, and
we've survived just fine with those for literally decades.
--Larry Garfield