On 01/09/2014 01:27, Timothy Wilkens wrote:
I had initially placed HashIterator inside Hash.c but after some discussion
with Marvin I decided to move it, even though it caused the implementation
to be complicated. I believe that having it outside of Hash.c highlights
the fact that hash iteration is done through a separate object now.
Well, right now, users have to look into the .cfh files for documentation. So
the decision whether classes are implemented in a single file or not might
have a small impact on how the role of a class is perceived. But once we start
generating docs for the C API, it won't make a difference.
The main argument not to implement multiple classes in the same file is to
have a better separation of concerns. But Hash and HashIterator are so tightly
coupled that I don't see any benefits from splitting up the implementation.
I don't feel strongly either way with respect to calling Get_Key or
Get_Value before Next has been called, though I'm leaning towards agreeing
with you and throwing an error. After iteration is finished I believe that
returning false from Next and NULL from Get_Key and Get_Value is the
desired behavior. It seems more natural to me to continue iteration until
Next returns false, rather than checking the state of iteration before
calling Next to avoid throwing an error.
I don't want to change the way the end of iteration is detected. Next should
still return false after the iterator is finished. I only propose that once
Next has returned false, calls to Get_Key and Get_Value shouldn't be allowed.
This wouldn't affect the standard idiom:
// Works like before.
HashIterator *iter = HashIter_new(hash);
while (HashIter_Next(iter)) {
Obj *key = HashIter_Get_Key(iter);
Obj *value = HashIter_Get_Value(iter);
}
// Calling Get_Key or Get_Value now would throw an exception.
If someone calls Get_Key or Get_Value after the end of iteration, it's most
likely a programming error, and throwing an exception helps to detect this.
Nick