lucenenet-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Andy Pook (JIRA)" <>
Subject [jira] [Commented] (LUCENENET-469) Convert Java Iterator classes to implement IEnumerable<T>
Date Thu, 10 Aug 2017 08:46:00 GMT


Andy Pook commented on LUCENENET-469:

bq. Wow, do I sound so closed minded?
Ha. No not at all :) more worried I just not seeing the whole picture.

bq. not sure if the state is actually being "iterated over" ... 
Well, in so far as {{Next}} moves a set of values one step forward, it can certainly be thought
of that way. I think of these like a cursor over a sql table. You can foreach over the rows.
How the data is actually retrieved is abstracted. It could be one at a time, batches, all
of them, cached... At the foreach level you just call Next to inspect the values of the next

bq. {{IEnumerable<T>}} is just an interface - it doesn't actually define any behavior.
Right, this is one of those language syntax enabling things. You actually don't need to specify
the interface. As long as the class implements {{GetEnumerator()}} then foreach will work.

bq. So then we end up with some behavior that doesn't fit the mold.
True. But that's completely normal.
Imagine an enumerator over a Stream that pulls a line of text at a time. What would happen
if you called {{myStream.Seek(...)}} inside the loop? Or a foreach over a Dictionary and call
{{myDictionary.Add(...)}}? The behavior is to either throw (because the Dictionary.Enumerator
protects against this) or some undefined behavior depending on which Stream/Reader or underlying
storage is being used. Having overridden implementations with different behaviors is also
to be expected. Many hours of fun to be had following Stream/TextReader etc. There's no guarantee
that descendant classes will have similar behavior at he edges.

My theory was to enable foreach that would produce items representing the values of the Enum
that change when its Next is called. This would be entirely an overlay/facade. All the existing
members would remain presenting a dual api.
This way copy/pasting code from Java is still possible (modulo c# style properties). But the
while style can be refactored to foreach. Or green field dev can be done in whichever style
the dev likes.

All linq style stuff will work. I don't think the "extra" (Seek etc) are a problem. Most of
them aren't composable as they return a single item or perfrom some op over the "collection".
I mean for example you probably wouldn't call {{SeekExact}} from inside a foreach, in the
same way you would use a dictionary indexer if you were foreach'ing over it. Or call {{Sort}}
inside a foreach over a List.
Those that are composable (ie the various {{Docs}} methods) will work (assuming the {{DocsEnum}}
is converted. So you could image {{terms.Docs(...).Where(d=>...).Select(...)}} working.
But I would expect them to be at the beginning of the chain.
I guess you could image a few extra linq style extensions for special cases. But once you're
into enumerable land it does cause some restrictions. Unless you want to get into rewriting
expressions trees (runs away screaming).

You are quite right, trying to fit this in such that it's consistent across the class hierarchies
is going to be a challenge for sure :)

I'm away this weekend but I'll try to put together a PR with a few examples/tests new week
to see if it'll work out.

> Convert Java Iterator classes to implement IEnumerable<T>
> ---------------------------------------------------------
>                 Key: LUCENENET-469
>                 URL:
>             Project: Lucene.Net
>          Issue Type: Sub-task
>          Components: Lucene.Net Contrib, Lucene.Net Core
>    Affects Versions: Lucene.Net 2.9.4, Lucene.Net 2.9.4g, Lucene.Net 3.0.3, Lucene.Net
>         Environment: all
>            Reporter: Christopher Currens
>             Fix For: Lucene.Net 4.8.0
> The Iterator pattern in Java is equivalent to IEnumerable in .NET.  Classes that were
directly ported in Java using the Iterator pattern, cannot be used with Linq or foreach blocks
in .NET.
> {{Next()}} would be equivalent to .NET's {{MoveNext()}}, and in the below case, {{Term()}}
would be as .NET's {{Current}} property.  In cases as below, it will require {{TermEnum}}
to become an abstract class with {{Term}} and {{DocFreq}} properties, which would be returned
from another class or method that implemented {{IEnumerable<TermEnum>}}.
> {noformat} 
> 	public abstract class TermEnum : IDisposable
> 	{
> 		public abstract bool Next();
> 		public abstract Term Term();
> 		public abstract int DocFreq();
> 		public abstract void  Close();
> 	        public abstract void Dispose();
> 	}
> {noformat} 
> would instead look something like:
> {noformat} 
> 	public class TermFreq
> 	{
> 		public abstract Term { get; }
> 		public abstract int { get; }
> 	}
>         public abstract class TermEnum : IEnumerable<TermFreq>, IDisposable
>         {
>                 // ...
>         }
> {noformat}
> Keep in mind that it is important that if the class being converted implements {{IDisposable}},
the class that is enumerating the terms (in this case {{TermEnum}}) should inherit from both
{{IEnumerable<T>}} *and* {{IDisposable}}.  This won't be any change to the user, as
the compiler automatically calls {{IDisposable}} when used in a {{foreach}} loop.

This message was sent by Atlassian JIRA

View raw message