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."

Reply via email to