July 09, 2012
On 07/09/2012 09:52 PM, Timon Gehr wrote:
> On 07/09/2012 09:46 PM, Mehrdad wrote:
>> On Monday, 9 July 2012 at 19:30:25 UTC, Jonathan M Davis wrote:
>>> Except that how output ranges are written to and an input range with
>>> assignable elements are fundamentally different. Output ranges use
>>> put, which _might_ write to each individual element, or it may just
>>> append to the output range (it all depends on the implementation of
>>> put). You're essentially generating a range when you use an output
>>> range. But with an input range with assignable elements, you're
>>> specifically setting each element in an existing range rather than
>>> generating a new one. You can think of an output range like an output
>>> stream, whereas an input range with assignable elements is like an
>>> array where you're assigning values to each of its elements.
>>
>> Oh!! So they're _exactly_ emulating C++ here, with insert_iterators
>> trying to mimic regular iterators and all. I _never_ got that impression
>> from the docs.
>> The impression the docs give is that the only time when you "add"
>> instead of "overwrite" is when it either doesn't make sense to overwrite
>> (e.g. into hash set, at the end of an array, etc.).
>> They never implied that you you might also be inserting into somewhere
>> where overwriting is possible, so clearly I misunderstood what was
>> intended.
>>
>>
>> Btw, I just realized:
>>
>> With that explanation, hasAssignableElements doesn't make sense for some
>> things that it should make sense for.
>>
>> How do you "assign" to e.g. a range of a BST? It _certainly_ makes sense
>> to do a transform() on it, but assigning to any particular element
>> doesn't make sense. So I think that confirms that what we really want IS
>> an I/O range -- a range that supports delete-modify-add, but not
>> (necessarily) read-modify-write (which is what hasAssignableElements
>> implies).
>>
>> Makes sense?
>
> struct BST(K){
>      struct Node{ ... }
>      Node root;
>      auto opSlice(){
>          struct Range{
>              ...
>              @property front(){ return ...; }
>              @property front(K k){
>                  deleteFront();
>                  root.add(k);
>              }
>          }
>      }
> }

(but BSTs do not actually support a range that implements transform.
Some elements might get transformed twice.)
July 09, 2012
On Monday, 9 July 2012 at 19:52:04 UTC, Andrei Alexandrescu wrote:
> On 7/9/12 3:30 PM, Mehrdad wrote:
>> I agree. My alternative would be to abandon similar 'hasXYZ' stuff
>> (which doesn't convey the picture and looks hacky), and instead formally
>> define what those are, like I/O range. Sounds good/bad?
>
> You may want to just spell it clearly.
>
> So right now we have the notions:
>
> input range (well one-pass range)
> forward range
> bidirectional range
> random-access range
> output range
>
> coupled with the capability queries
>
> isInfinite
> hasAssignableElements
> hasLength
> ...
>
> The small set of ranges coupled with the capability queries reflect the orthogonal or near-orthogonal nature of such.
>
> As far as I understand the above, you propose the notions:
>
> input range
> input range with assignable elements
> infinite input range
> infinite input range with assignable elements
> forward range
> forward range with assignable elements
> ...
>
> That seems pretty onerous, but then I can't derive other meaning from your post.
>
>
> Andrei

that's not what I meant, but I think another solution is better anyway:

Why isn't transform taking in both an input and an output range in the first place? Of course they might be the same, but they don't have to be.
July 09, 2012
On Monday, 9 July 2012 at 20:21:18 UTC, Mehrdad wrote:
> that's not what I meant, but I think another solution is better anyway:
>
> Why isn't transform taking in both an input and an output range in the first place? Of course they might be the same, but they don't have to be.

Could you make a detailed proposal? I still completely don't understand neither the problem you're trying to solve, nor the solution you have in mind.

I was reading all your posts in this thread very carefully.
July 09, 2012
On Monday, July 09, 2012 22:25:57 Roman D. Boiko wrote:
> On Monday, 9 July 2012 at 20:21:18 UTC, Mehrdad wrote:
> > that's not what I meant, but I think another solution is better anyway:
> > 
> > Why isn't transform taking in both an input and an output range in the first place? Of course they might be the same, but they don't have to be.
> 
> Could you make a detailed proposal? I still completely don't understand neither the problem you're trying to solve, nor the solution you have in mind.
> 
> I was reading all your posts in this thread very carefully.

What we really need is a solid article on ranges on the site (maybe even several, with each one going into more detail on specific stuff - e.g. issues with strings being ranges of dchar). Then it will be much easier for programmers to gain a solid understanding of ranges. The API documentation will never be good enough for that, because it's not the right place to go into that level of detail. I keep meaning to write up such an article (and even started one a while back), but I never get around to getting it done...

In the meantime, there's alway's Ali's book:

http://ddili.org/ders/d.en/ranges.html

It may be that there are things that can and should be improved about how ranges currently work, but I think that it's clear that any proposal made to improve them needs to be made with a solid understanding of how they currently work.

- Jonathan M Davis
July 09, 2012
On Monday, 9 July 2012 at 20:25:58 UTC, Roman D. Boiko wrote:
> On Monday, 9 July 2012 at 20:21:18 UTC, Mehrdad wrote:
>> Why isn't transform taking in both an input and an output range in the first place? Of course they might be the same, but they don't have to be.
>
> Could you make a detailed proposal? I still completely don't understand neither the problem you're trying to solve, nor the solution you have in mind.


Well, I'm not even sure if the proposal is necessary yet, since it would be solved another way -- I'm not sure if transform should be taking 1 range as input or 2.

I mean like, why isn't it defined this way instead?

void transform(alias f, RI, RO)(RI r, RO output)
    if(isInputRange!RI && isOutputRange!RO)
{
    for(; !r.empty; r.popFront())
        output.put(unaryFun!f(r.front));
}



If that works, then I still think we don't need assignable front()s after all.
July 09, 2012
By the way, this thread is quite old.

getNext looks similar to what I wanted when first dealt with ranges, but now it looks too heavyweight.

What happened to this proposal anyway? Was it deferred, discarded, or what?
July 09, 2012
On 7/9/12 4:47 PM, Mehrdad wrote:
> I mean like, why isn't it defined this way instead?
>
> void transform(alias f, RI, RO)(RI r, RO output)
> if(isInputRange!RI && isOutputRange!RO)
> {
> for(; !r.empty; r.popFront())
> output.put(unaryFun!f(r.front));
> }

Instead of what? There is not transform() function in std.algorithm.

Andrei
July 09, 2012
On 07/09/2012 11:04 PM, Andrei Alexandrescu wrote:
> On 7/9/12 4:47 PM, Mehrdad wrote:
>> I mean like, why isn't it defined this way instead?
>>
>> void transform(alias f, RI, RO)(RI r, RO output)
>>     if(isInputRange!RI && isOutputRange!RO)
>> {
>>     for(; !r.empty; r.popFront())
>>     output.put(unaryFun!f(r.front));
>> }
>
> Instead of what? There is not transform() function in std.algorithm.
>
> Andrei

His post was related to this one, burried in another branch of the
thread:

On 07/09/2012 08:33 PM, jerro wrote:
> It is useful to be able to write an algorithm that both reads
> and writes range elements. There are plenty of use cases for
> that, but if you really need an example, here's a simple one:
>
> void transform(alias f, R)(R r)
>      if(isInputRange!R && hasAssignableElements!R)
> {
>      for(; !r.empty; r.popFront())
>          r.front = unaryFun!f(r.front);
> }

July 09, 2012
On Monday, 9 July 2012 at 21:04:31 UTC, Andrei Alexandrescu wrote:
> Instead of what? There is not transform() function in std.algorithm.
>
> Andrei

I was talking about this:

http://forum.dlang.org/thread/i1gnlo$18g0$1@digitalmars.com?page=5#post-tdgxpwegpwaczardhvpx:40forum.dlang.org


If you had a different use-case in mind for 'ref' front()'s, would you mind posting it?
July 16, 2012
On Mon, 09 Jul 2012 12:17:49 -0400, Mehrdad <wfunction@hotmail.com> wrote:

> On Monday, 9 July 2012 at 16:06:57 UTC, Timon Gehr wrote:
>>
>> Consider the possibility that this electrical engineer might be a plumber as well.
>
> Yes, so if you expect him to be, then you should ask him "are you a plumber?" (i.e. output range?)
>
>
> But what you're asking him right now is, "hey, can you do clear this pipe for me with copper wires??" which is downright silly. Being able to write to an output range does NOT require you to have 'ref' members. The only thing 'ref' ever buys you is performance, not any new capabilities. Depending on it doesn't make sense.

import std.range;

struct inputrange
{
    int x;
    @property ref int front() { return x;}
    void popFront() {}
    enum empty = false;
}

static assert(isOutputRange!(inputrange, int));

-Steve