March 27, 2014 Re: protocol for using InputRanges | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | On 03/27/2014 05:17 AM, Walter Bright wrote:
>
> As with *any* API, if you look under the hood and make assumptions about
> the behavior based on a particular implementation, assumptions that are
> not part of the API, the risk of breakage inevitably follows.
>
> If you've identified Phobos code that uses ranges but does not follow
> the protocol, the Phobos code is broken - please file a bugzilla issue
> on it.
I feel uneasy about the assertion that code that assumes that 'empty' checks for an empty range is broken. If the API does not allow fast range implementations without arbitrarily restrictions on some 'protocol', then this is a problem with the API. Maybe empty/front/popFront should just be a single primitive, like:
Nullable!T get();
|
March 27, 2014 Re: protocol for using InputRanges | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timon Gehr | On 03/27/2014 11:48 PM, Timon Gehr wrote:
> arbitrarily restrictions on some 'protocol'
arbitrarily restricting interactions to some 'protocol'
|
March 27, 2014 Re: protocol for using InputRanges | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On 3/27/2014 2:46 PM, Steven Schveighoffer wrote: > In the cases where you know there is input, that's not true. The range doesn't know what you know. > What I am protesting is the idea that you *know* input exists, you must still call empty. > Front is enough in that case. You can't use that on generic code, because generic code cannot assume that front will not fail. >> What is wrong with following the protocol? Why must we introduce all these >> caveats for ranges, like streams not working, front that can fail, can't do C# >> style LINQ, etc.? For what gain? > > There is no gain to requiring empty on ranges where you logically prove they are > not empty. It's a wasted call. For things where you're not sure if they are > empty or not (e.g. an input file), of course empty is required to be called, and > of course it may do some processing to determine that. But I would only expect > that on the first call. Subsequent checks would already be done by popFront. I know that you want to get rid of empty. But getting rid of empty means that front may fail. This is why there is an empty, and any generic code MUST respect that. What you can do is, in your range: enum empty = true; and then it won't cost anything to call it. > I mean, if you are calling empty regularly, because you aren't sure whether the > elements are there. That's not always the case, sometimes you are sure the > elements are there. Then use an adapter range that has: enum empty = true; and forwards the front and popFront() calls to its parameter. You'll get the optimization you want, and won't violate protocol. > Requiring a call to empty to do anything other than to check > whether a range is empty, is just plain wrong. There are solid reasons to require it (i.e. streams), and you've responded that ranges needn't even support streams. If I have interpreted your position correctly, I cannot agree with it. |
March 28, 2014 Re: protocol for using InputRanges | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timon Gehr | On 3/27/2014 3:48 PM, Timon Gehr wrote:
> Maybe empty/front/popFront should just be a single primitive, like:
> Nullable!T get();
What if get() fails?
|
March 28, 2014 Re: protocol for using InputRanges | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On 3/27/2014 2:56 PM, Andrei Alexandrescu wrote: > On 3/27/14, 2:24 PM, Walter Bright wrote: >> The range protocol is designed to work with streams. > > It's designed to work with containers. I know we talked about streams when we designed it. >> It's a giant fail >> if they do not, or if you want to create a separate, non-range universe >> to deal with streams. > > It's not a giant fail, we just need to adjust the notion. Are you suggesting that ranges needn't support streams? Note also that I suggested a way Steven could create an adapter with the behavior he desired, yet still adhere to protocol. No notion adjustments required. |
March 28, 2014 Re: protocol for using InputRanges | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On 3/27/2014 2:31 PM, Steven Schveighoffer wrote:
> Adding range primitives on top of a stream does not make sense.
Are ready to implement a parallel universe of stream based algorithms to go alongside all the range based ones and be ready to constantly justify that to everyone?
I'm also curious what a generic read() should do when the stream is empty.
|
March 28, 2014 Re: protocol for using InputRanges | ||||
---|---|---|---|---|
| ||||
Posted in reply to QAston | On 3/27/2014 3:23 PM, QAston wrote:
> The protocol is not intuitive.
I find empty-front-popFront as perfectly intuitive. I don't find the counter proposals, which come with baggage like constructors that may fail, and front() that may fail in unspecified ways, or throwing entire paradigms out the window, as intuitive.
But I concede that other people think differently. Not everyone thinks the same. But consider this: floating point math is not intuitive. There has never been a shortage of proposals to make fp intuitive, but they've all failed because they are impractical.
Sometimes ya gotta go with what works.
|
March 28, 2014 Re: protocol for using InputRanges | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | On Thu, Mar 27, 2014 at 05:11:55PM -0700, Walter Bright wrote: > On 3/27/2014 3:48 PM, Timon Gehr wrote: > >Maybe empty/front/popFront should just be a single primitive, like: > >Nullable!T get(); > > What if get() fails? That's the whole point of Nullable!T: you can return null if get() fails. I can't say I like this, though. There are many cases in my code that need separation of .empty from .front from .popFront, such as recursive descent parsers or code that does if-match-then-consume algorithms. One of the *nice* things about the current range API is that that code works with arrays, streams, and lots of other stuff, without needing to care about implementation details. Changing it to get() will require lots of manual buffering and reintroduce lots of ugly boilerplate that I had to live with in C++. I'm with Walter on this one. Generic code should NOT assume anything about a range it was given, and therefore it should call .empty before calling .front or .popFront. If you "know" that a particular range doesn't require calling .empty beforehand, then by definition your code is no longer generic, and you just have to live with the consequences of that. Nothing stops you, for example, from exposing a .get function or whatever else, *in addition* to the standard range API. Then code that knows how to deal with .get will use it, and your range remains usable with other generic code. Nothing about the range API dictates that .empty cannot do useful work like initialize buffers. That should be an implementation detail that generic code shouldn't rely on. T -- The early bird gets the worm. Moral: ewww... |
March 28, 2014 Re: protocol for using InputRanges | ||||
---|---|---|---|---|
| ||||
Posted in reply to Chris | On 3/27/2014 3:21 AM, Chris wrote:
> I agree. I've been using ranges for a while now and have tried
> different implementations based on advice given on this forum and
> depending on each case. After reading this thread I looked at
> some of my ranges and I have to say I still have no clue as to
> what should and should _not_ be done (regardless of whether you
> _can_ do it). For a while I thought that it's my lack of
> understanding, but this thread shows that everyone has a
> different view of ranges. Guidelines with use cases would be
> great. I remember I mentioned this in another thread already. The
> thing is that experimenting without proper guidelines leaves your
> code in an inconsistent state where you have two or more ranges
> doing technically the same thing but each with a different logic.
Following the protocol empty-front-popFront always works.
Where the differences come in is when people skip calling empty.
|
March 28, 2014 Re: protocol for using InputRanges | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | On Friday, 28 March 2014 at 02:14:40 UTC, H. S. Teoh wrote: > I'm with Walter on this one. Generic code should NOT assume anything > about a range it was given, and therefore it should call .empty before > calling .front or .popFront. If you "know" that a particular range > doesn't require calling .empty beforehand, then by definition your code > is no longer generic, and you just have to live with the consequences of > that. Nothing stops you, for example, from exposing a .get function or > whatever else, *in addition* to the standard range API. Then code that > knows how to deal with .get will use it, and your range remains usable > with other generic code. It's not that *you* know a particular range doesn't need "empty" called, it's that the algorithm you are using has already previously validated there are elements in it. For example, the splitter algorithm will first save a copy of its range, and then walk it, searching for the "splitting" elements. It then realizes it has walked N elements. From there, it takes the original range, and packs it into a "takeExactly(N)" of the original range. Iterating that "takeExactly(N)" is faster than a raw "take", *because* "takeExactly" was already promised that the range holds N elements, and as such, *doesn't* check for empty. Ditto for "findSplit". And again, there are functions, such as "copy", then simply *require* that a certain range have at least a certain amount of elements. Why check for it, if not providing it is a violation of its interface. On Thursday, 27 March 2014 at 23:52:46 UTC, Walter Bright wrote: > I know that you want to get rid of empty. But getting rid of empty means that front may fail. This is why there is an empty, and any generic code MUST respect that. Front only fails *if* the range is empty. Not if you fail to call empty. Generic code respects that. > What you can do is, in your range: > > enum empty = true; That's not the same. That's making the assumption your range will *never* be empty, which is a whole other concept (infinite ranges). |
Copyright © 1999-2021 by the D Language Foundation