www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Formal request to remove "put(OutRange, RangeOfElements)"

reply "monarch_dodra" <monarchdodra gmail.com> writes:
I'm really very sorry that this is such a long post, but I'd like 
to make request for a serious change to Phobos, so I think it 
should be as complete as possible.

Thank you to those who have the patience to read it and consider 
it.


**************************************************
Abstract:

   This is a formal request for the deprecation of the the support 
for accepting ranges of elements for the function "put" ie 
(put(OutRange, RangeOfElements)).

   As convenient as this functionality may be is, it undermines 
the very definition of what constitutes an output range, and 
creates some fundamental problems when trying to deal with them.

   put(Range, RangeOfElements) doesn't actually bring anything to 
the table that would be missed.

**************************************************
Explanation:

   The problem is not "put" in and out of itself, but rather that 
it is the fundamental definition of what constitutes an output 
range. In particular, because you cannot extract elements from 
output ranges, and because an output range can potentially 
support multiple types, you cannot write:
   "ElementType!OutputRange" => this will yield "void" on a 'true' 
output range. Rather, you have to individually query if the range 
is an output for specific types:
   "isOutputRange!(OutputRange, SomeElement)"

   The catch is that the definition of "isOutputRange" is just 
"does "put(range, element)" compile". This means that 
essentially, as soon as a range is an output for elements, it 
becomes an output for ranges of elements, for ranges of ranges of 
elements, for ranges of ranges of ranges of elements, for ...

For example: int[] is an outputRange of int (obviously), but it 
is also defined as an output range of int[], int[2], and 
int[][]...
This is clearly not right.

**************************************************
Problems put creates for template restrictions:

   At it simplest, it prevents any algorithm from properly working 
with outputRanges. This is the definition of "copy":

Range2 copy(Range1, Range2)(Range1 source, Range2 target)
   if (isInputRange!Range1 && isOutputRange!(Range2, 
ElementType!Range1))

See the trap? This is perfectly legal code:
   int a[][][][];
   int b[];
   copy(a, b);

   Look bad? it gets worse. Imagine the function fill. It works 
the same as "copy", but it can also take an "element" as an 
argument. One would be tempted to write this pair of signatures:

void fill(Range1, Range2)(Range1 target, Element filler)
   if(isOutputRange(Range1, Element))

void fill(Range1, Range2)(Range1 target, Range2  filler)
   if(isInputRange!Range2 && isOutputRange(Range1, 
ElementType!Range2))

You can try to write this, but if you do, the code will never 
work. ANYTHING that matches the range fill, will also match the 
element based fill, since the target range supports "put" from a 
range... For example:
int[2] a = [1, 2];
int[] b = new int[](8);
fill(b, a); //ambiguous call...
//Are you copying a "range" or an "element"?
//Answer: Who know! Honestly: if b is an output range of a, WHICH 
IS THE RIGHT CALL?

   The only way to really avoid this problem (as is currently done 
in algorithm.d) is to add: "is(typeof(range.front = filler))", 
but this defeats the very requirement of outputRange (outputRange 
does not have front), and bumps the algorithm's requirements up 
to "inputRange".

   Long story short, it is not currently possible to write 
templates that reliably support an outputRange restriction.

**************************************************
Problems put creates for implementation:

   The big problem about put is that it makes outputRanges _lie_ 
about what they support. Here is an example at its simplest:

alias int[] A; alias int[] B;
A a = new int[](2);
B b = new int[](1);
assert(isOutputRange!(typeof(a), typeof(b)));
if(!b.empty)
   b.put(a);

   In this code:
*b is an output range of A.
*b is not empty.
*putting an A inside b creates a empty range exception !?

   While this example might look "cute", it is also unacceptable 
behavior. if b is a non-empty range that supports "elements A", 
then it _HAS_ to be able to support a put. In this case, b 
clearly does not support elements of type A.

   I'm sure you can imagine the kinds of problems this can caue 
for a template developer.

**************************************************
Why we don't need put(Range):

   Quite simply: because we have the higher order function. The 
convenience "put(Range)" is nothing more than a glorified 
algorithm. Instead of using put, the user should make a call to 
copy. "copy" is designed specifically for copying an input range 
into an output range. Why duplicate this functionality into put? 
Calling copy is much more honest and accurate about what is 
actually happening.

**************************************************
Problems regarding removing put(Range):

   In theory, the only problem this would create is breaking code 
which can be legitimately replaced by “copy” without any 
change.

   It *could* also break some templates, as some ranges would 
seize reporting themselves as outputRanges of Ranges, but, quite 
frankly, I think those algorithms are unsafe to begin with, and 
are operating on incompatible types.

**************************************************
Conclusion:

   I think I've shown the problems that put(Range) creates. 
Problems that are simply insurmountable. On the other hand, 
"e.put(range)" brings nothing that can't be rewritten as "copy(e, 
range)". For all these reasons, I think it would be best to get 
rid of it.
Jul 18 2012
next sibling parent travert phare.normalesup.org (Christophe Travert) writes:
That sounds reasonable and justified. Let's wait to know if people 
maintaining legacy code will not strongly oppose to this.
Jul 18 2012
prev sibling next sibling parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
Maybe I should put this request elsewhere? I'm not sure if there 
is a place where I should put this?

I know this is not a very exciting issue, but I think it is a 
very important to resolve, preferably sooner than later.

Maybe I'll try to help kick start this by listing all the modules 
that would need to be changed?
Jul 23 2012
parent travert phare.normalesup.org (Christophe Travert) writes:
"monarch_dodra" , dans le message (digitalmars.D:173005), a crit:
 Maybe I should put this request elsewhere? I'm not sure if there 
 is a place where I should put this?
 
 I know this is not a very exciting issue, but I think it is a 
 very important to resolve, preferably sooner than later.
 
 Maybe I'll try to help kick start this by listing all the modules 
 that would need to be changed?

You can fill a bug report. assert(isOutputRange!typeof(r), typeof(e) && !output.r); output.put(e); failing on the second line is worthy of attention. And it makes fill fail IIRC. -- Christophe
Jul 23 2012
prev sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Monday, July 23, 2012 17:33:07 monarch_dodra wrote:
 Maybe I should put this request elsewhere? I'm not sure if there
 is a place where I should put this?
 
 I know this is not a very exciting issue, but I think it is a
 very important to resolve, preferably sooner than later.
 
 Maybe I'll try to help kick start this by listing all the modules
 that would need to be changed?

If you've found a bug, then report it bugzilla. If you have an issue that needs discussion, then this is the right place. It's just that you don't always get people responding, especially if it's a complicated topic (and the fact that it's summer right now probably doesn't help due to an increased number of people on vacation). Personally, I intend to read through this and respond, but it's the sort of thing that obviously needs to be read through and thought through carefully before discussing, and I haven't had the chance to do that yet. - Jonathan M Davis
Jul 23 2012