MoveNext()
JavaのhasNext()
モデルに対するC#/。NETのモデルの利点は、前者はいくつかの作業が行われる可能性があることを意味することです。このhasNext()
メソッドは、単純な状態チェックを意味します。しかし、遅延ストリームを反復していて、データベースにアクセスして結果があるかどうかを判断する必要がある場合はどうでしょうか。その場合、への最初の呼び出しhasNext()
は、長いブロッキング操作になる可能性があります。hasNext()
メソッドの命名は、実際に何が行われているのかについて非常に誤解を招く可能性があります。
実際の例では、この設計の問題は、JavaでMicrosoftのReactive Extensions(Rx)APIを実装するときに私に噛み付きました。具体的には、によって作成されたイテレータがIObservable.asIterable()
適切に機能するために、hasNext()
メソッドはブロックし、次のアイテム/エラー/完了通知が到着するのを待つ必要があります。それはほとんど直感的ではありません。名前は単純な状態チェックを意味します。MoveNext()
遅延評価されたストリームを処理している場合は、ブロックする必要があるC#の設計とは対照的に、まったく予期しない結果にはなりません。
私のポイントはこれです。「this-iterator」モデルは嘘であることが多いため、「next-iterator」モデルは「this-iterator」モデルよりも望ましいです。チェックするために次の要素をプリフェッチする必要がある場合があります。イテレータの状態。私の意見では、その可能性を明確に伝えるデザインが望ましいと思います。はい、Javaの命名規則は「次の」モデルに従いますが、動作の影響は「this-iterator」モデルのそれに似ています。
明確化: Javaのモデルは欺瞞的であるため、おそらくJavaとC#の対比は不適切な選択でした。OPによって提示されたモデルの最も重要な違いは、「thisイテレータ」モデルが「is is valid」ロジックを「retrieve current / next element」ロジックから切り離し、理想的な「next-iterator」実装であると考えていますこれらの操作を組み合わせます。場合によっては、イテレータの状態が有効かどうかを判断するには次の要素をプリフェッチする必要があるため、それらを組み合わせることが適切であると考えています。
以下の間に設計上の大きな違いは見られません。
while (i.isValid()) { // do we have an element? (implied as fast, non-blocking)
doSomething(i.current()); // retrieve the element (may be slow!)
i.next();
}
// ...and:
while (i.hasNext()) { // do we have an element? (implied as fast, non-blocking)
doSomething(i.next()); // retrieve the element (may be slow!)
}
しかし、私はここに意味のある違いを見ています:
while (i.hasNext()) { // do we have an element? (implied as fast, non-blocking)
doSomething(i.next()); // retrieve the element (may be slow!)
}
// ...and:
while (i.moveNext()) { // fetch the next element if it exists (may be slow!)
doSomething(i.current()); // get the element (implied as fast, non-blocking)
}
isValid()
とのhasNext()
例の両方で、高速かつ非ブロッキング状態のチェックであると暗黙的に示されている操作は、実際には低速のブロック操作である可能性があります。このmoveNext()
例では、熱心に評価されたストリームと遅延評価されたストリームのどちらを処理しているかに関係なく、ほとんどの作業は期待どおりの方法で行われます。