On Mon, Nov 05, 2012 at 01:42:47PM -0500, Jonathan M Davis wrote: > On Monday, November 05, 2012 15:48:41 deadalnix wrote: > > HS Teoh explained it nicely. > > > > The responsibility of using .transient or not belong to the consumer. > > Only the consumer can know if a transient range is suitable. > > > > So you don't wrap a transient range. You wrap a non transient range, > > and, if the consumer is able to handle the transcient version, it call > > .transient on its source, that call it on its source, etc . . . up to > > the real source. > > > > If one transformer is unable to handle transient range, the it don't > > pass .transient to its source. > > You still need to wrap it in every wrapper range which could possibly > support transience. So, this affects every single range which could > possibly support transience.
You *can* wrap it if the wrapper range can support transience. It doesn't *have* to be wrapped. That's what I like about deadalnix's proposal -- do nothing, and you get *correct* behaviour. Do something, and you make it faster. Sounds like a good deal to me. Besides, almost *all* of those wrapper ranges are currently _broken_ for transient ranges. You get undefined behaviour when you inadvertently pass a transient range to them. No matter what you do, this has to be fixed, one way or another. By fixing *all* ranges to be non-transient by default (and, as you say, there are only a scant few of them -- byLine is the only Phobos example I can think of), we fix all of this broken behaviour instantly. The rest is optional optimization. > At least with Andrei's proposal, transience is explicitly restricted > to input ranges, which seriously reduces the problems caused by them, > particularly since so few functions can really function with just an > input range. [...] With Andrei's proposal, all code that assumes transient .front with input ranges are broken by definition. I've looked over std.algorithm -- there are a *lot* of places with this assumption. Instead of getting correct default behaviour, you get a whole bunch of broken code with buggy behaviour, unless you first rewrite a lot of code in std.algorithm (and probably std.range as well). Furthermore, afterwards there is still no safety net: accidentally create a transient forward range? You're screwed, std.algorithm breaks all over the place. You said that ranges are supposed to be easy for users to create. Well, with Andrei's scheme, all the user has to do is to write a .save method in his input range, and all of a sudden everything breaks. The problem is that input ranges allow transient .front to begin with. Now users have to remember, once I add .save, I have to make .front non-transient. This is very counterintuitive to me. I'm extending a range to make it usable as a forward range, and now suddenly I can't reuse my buffers anymore? In my mind, forward ranges should be a refinement of input ranges. So I should be able to just add more stuff to my input range, and it should become a valid forward range. But now this is not true anymore, and the reason? We arbitrarily decided to make forward ranges non-transient. By making *all* ranges non-transient by default, we avoid this problem. Users don't have to remember the strange interaction between .front and .save. You only get transient ranges when you explicitly ask for it. So code is safe by default, and if you know what you're doing, you can make it faster. And std.array.array actually works correctly 100% of the time with no further changes. The current situation is, code is *not* safe by default. Pass a transient range to std.algorithm, and sometimes it works, sometimes it breaks. Passing it to std.array.array sometimes works, sometimes doesn't. Subtle bugs arise everywhere. With Andrei's proposal, you still have the same problem: forget to update a Phobos algorithm that expects an input range, and it breaks. You have to pretty much rewrite every single algorithm in Phobos that expects an input range, AND complete this rewrite BEFORE code starts working correctly. Then after that, every time you write code that takes an input range, you have to watch out for transient ranges, otherwise things will break. And std.array.array can no longer take an input range because it can't copy .front correctly. IOW, input ranges become almost completely useless. How is this any better than deadalnix's solution? From what I can tell, it's a lot worse, for all of the above reasons. T -- "Hi." "'Lo."