Sergey Gromov wrote:
Mon, 26 Jan 2009 08:06:05 -0800, Andrei Alexandrescu wrote:

Anyhow, here's a simple D example. Consider we define a BigInt type as a value-type struct: when you copy a BigInt to another, the latter becomes an independent copy:

BigInt a = 100;
BigInt b = a;
++b;
assert(a == 100);

BigInt's copy constructor would allocate memory dynamically, which means it may throw and also that it is inefficient to copy BigInt objects unwittingly.

So far, so good. Now say we define some range that iterates over BigInts. If that range chooses to implement head() as a property, then a copy is created whenever you ask for head. The small problem is that that's inefficient. The larger problem is that there is no way to correctly e.g. sort such a range. Sorting hinges on swap, and with properties you can't ever swap without risking to throw. Sort would end up throwing, and not only throwing, but losing state irretrievably while at it. Well that's not a foundation we want to build D on, do we?

This will happen in C++, too, if operator*() decides to throw.
Algorithms are correct only if objects they manipulate obey the rules.

Of course. The problem with get and set is not that they make it possible to write incorrect code. They make it impossible to write correct code.

It seems like your rule is, 'forward ranges are nothrow.'  Any senior
ranges included.  Or maybe throwing next() or empty() are less
dangerous?

Yes, because even if they throw, net loss of state is still avoidable.


Andrei

Reply via email to