May 04, 2012
On 2012-05-04 01:11, Stewart Gordon wrote:

> To sum it up, it can't be done in the general case. The range API
> doesn't know or care about the underlying data structure. That's half
> the point of it. The underlying data structure might not even exist. An
> example is a range used as a file stream, a random number generator or
> to lazily generate a mathematical sequence.

Yeah, I know, I know. It's all good in theory but I never found a use for it in practice and in most cases it's just annoying.

> Moreover, what would you want such a function to return if the range is:
> - a file stream with a cache
> - an array wrapper to loop infinitely through it?
> - a concatenation of ranges that may be of different types?

I was mostly thinking when the range originated from a collection. Where it's actually possible to transfer the range back to the original collection type.

> Moreover, even if there were some "range with an underlying container"
> classification, it would be an extra burden on the writer of the range
> wrapper to implement this.

No, I was thinking that the developer of the collection would provide that. I mean, it's already possible to transform a range to an array, I'm sure it's possible to transform it to a list of some kind as well. Then we could have this for example:

collA.range.toArray();
collB.range.toList();

What I was asking for was if there is, or could be, a generic interface for this. Something like:

collA.range.toCollection();
collA.range.toCollection();

If "collA" is an array "toCollection" would transform the range to an array, just as std.array.array does. If "collB" is a list the range would be transformed back in to a list.

> If you want to generate a range that views a container in a certain way,
> and then construct a container of the original type (or indeed any type)
> from that range, then create the container and then use a foreach loop
> on the range (or a .save of it, if you want to keep the range
> afterwards) to put the data into the container.
>
> Stewart.


-- 
/Jacob Carlborg
May 04, 2012
On 2012-05-03 00:34, bearophile wrote:

> The newly redesigned containers in Scala language are often able to do
> this, but this has required the use of a very advanced static type
> system, that is currently not in D (maybe there are ways to implement it
> with D templates, but it will require work to implement).

I've heard of that. I've started to read a paper about how the collection API is implemented.

-- 
/Jacob Carlborg
May 04, 2012
On Friday, May 04, 2012 08:32:09 Jacob Carlborg wrote:
> On 2012-05-04 01:11, Stewart Gordon wrote:
> > To sum it up, it can't be done in the general case. The range API doesn't know or care about the underlying data structure. That's half the point of it. The underlying data structure might not even exist. An example is a range used as a file stream, a random number generator or to lazily generate a mathematical sequence.
> 
> Yeah, I know, I know. It's all good in theory but I never found a use for it in practice and in most cases it's just annoying.
> 
> > Moreover, what would you want such a function to return if the range is:
> > - a file stream with a cache
> > - an array wrapper to loop infinitely through it?
> > - a concatenation of ranges that may be of different types?
> 
> I was mostly thinking when the range originated from a collection. Where it's actually possible to transfer the range back to the original collection type.
> 
> > Moreover, even if there were some "range with an underlying container" classification, it would be an extra burden on the writer of the range wrapper to implement this.
> 
> No, I was thinking that the developer of the collection would provide that. I mean, it's already possible to transform a range to an array, I'm sure it's possible to transform it to a list of some kind as well. Then we could have this for example:
> 
> collA.range.toArray();
> collB.range.toList();
> 
> What I was asking for was if there is, or could be, a generic interface for this. Something like:
> 
> collA.range.toCollection();
> collA.range.toCollection();
> 
> If "collA" is an array "toCollection" would transform the range to an array, just as std.array.array does. If "collB" is a list the range would be transformed back in to a list.

Something like that could probably only be done if every range in the potentially large chain of wrapped ranges provided a means of getting at what type the previous one in the chain was, and very few ranges - if any - do that.

However, I'm not quite sure what toCollection would buy you. Why does it really matter what type of container the range comes from originally given that you have to create a new container to put the elements of the range into such a container? And if you're putting the elements of a range in a new container, you can pick whatever container type you'd like, and since it has no real connection to the original container, I don't see why it would matter whether it was the same type of container. All you really need is the equivalent of std.array.array for whatever container you want to construct, and the container's constructor should provide that.

- Jonathan M Davis
May 04, 2012
On 2012-05-04 09:01, Jonathan M Davis wrote:

> Something like that could probably only be done if every range in the
> potentially large chain of wrapped ranges provided a means of getting at what
> type the previous one in the chain was, and very few ranges - if any - do
> that.
>
> However, I'm not quite sure what toCollection would buy you. Why does it
> really matter what type of container the range comes from originally given
> that you have to create a new container to put the elements of the range into
> such a container? And if you're putting the elements of a range in a new
> container, you can pick whatever container type you'd like, and since it has
> no real connection to the original container, I don't see why it would matter
> whether it was the same type of container. All you really need is the
> equivalent of std.array.array for whatever container you want to construct,
> and the container's constructor should provide that.

It's just like with the whole range idea, providing a common interface for iterating over a collection (and some other stuff). Here the idea is to have a common interface to transform the range back to a collection.

-- 
/Jacob Carlborg
May 04, 2012
On Friday, May 04, 2012 11:20:58 Jacob Carlborg wrote:
> On 2012-05-04 09:01, Jonathan M Davis wrote:
> > Something like that could probably only be done if every range in the potentially large chain of wrapped ranges provided a means of getting at what type the previous one in the chain was, and very few ranges - if any - do that.
> > 
> > However, I'm not quite sure what toCollection would buy you. Why does it really matter what type of container the range comes from originally given that you have to create a new container to put the elements of the range into such a container? And if you're putting the elements of a range in a new container, you can pick whatever container type you'd like, and since it has no real connection to the original container, I don't see why it would matter whether it was the same type of container. All you really need is the equivalent of std.array.array for whatever container you want to construct, and the container's constructor should provide that.
> 
> It's just like with the whole range idea, providing a common interface for iterating over a collection (and some other stuff). Here the idea is to have a common interface to transform the range back to a collection.

But what's special about the original container type? Once the range has been wrapped, it doesn't really have any connection to the container - particuarly when elements are likely to have been transformed and/or skipped or added such that they're no longer strongly linked with the original elements. As far as I can tell, the original container type becomes pretty much meaningless at that point.

You should be able to put the elements that are in the range in whatever container type you want (which you can currently do very easily with arrays thanks to std.array.array and should be able to do with std.container's containers with their constructors), so you can put them in whatever container type is appropriate for whatever you're going to do with the elements. But I don't see how the _original_ container type matters for any of that.

And when you consider that it's quite possible for a range to have no connection to a container whatsoever (e.g. anything in std.random), I just don't see how you could generically get at the type of the original container anyway (since there may not be one). Best case, you could create variable or alias which a range type _could_ have but doesn't necessarily have (similar to save or back) which could then hold the original container type (effectively creating yet another genre of range). But again, I don't see why that would actually be useful.

- Jonathan M Davis
May 04, 2012
On 2012-05-04 11:38, Jonathan M Davis wrote:
> On Friday, May 04, 2012 11:20:58 Jacob Carlborg wrote:
>> On 2012-05-04 09:01, Jonathan M Davis wrote:
>>> Something like that could probably only be done if every range in the
>>> potentially large chain of wrapped ranges provided a means of getting at
>>> what type the previous one in the chain was, and very few ranges - if any
>>> - do that.
>>>
>>> However, I'm not quite sure what toCollection would buy you. Why does it
>>> really matter what type of container the range comes from originally given
>>> that you have to create a new container to put the elements of the range
>>> into such a container? And if you're putting the elements of a range in a
>>> new container, you can pick whatever container type you'd like, and since
>>> it has no real connection to the original container, I don't see why it
>>> would matter whether it was the same type of container. All you really
>>> need is the equivalent of std.array.array for whatever container you want
>>> to construct, and the container's constructor should provide that.
>>
>> It's just like with the whole range idea, providing a common interface
>> for iterating over a collection (and some other stuff). Here the idea is
>> to have a common interface to transform the range back to a collection.
>
> But what's special about the original container type? Once the range has been
> wrapped, it doesn't really have any connection to the container - particuarly
> when elements are likely to have been transformed and/or skipped or added such
> that they're no longer strongly linked with the original elements. As far as I
> can tell, the original container type becomes pretty much meaningless at that
> point.

I give up. Apparently you don't think it's useful.

-- 
/Jacob Carlborg
May 04, 2012
On Friday, 4 May 2012 at 11:46:34 UTC, Jacob Carlborg wrote:
> I give up. Apparently you don't think it's useful.

I'm not seeing it either, but it might help if you gave a concrete example of where it could/should be used and what benefits it might have. I think it'll be rather hard to come up with an example where the programmer wouldn't know what the original type was and have it actually matter.
May 04, 2012
On Thu, 03 May 2012 04:41:50 -0400, Jacob Carlborg <doob@me.com> wrote:

> On 2012-05-02 23:40, Jonathan M Davis wrote:
>> On Wednesday, May 02, 2012 23:01:21 Jacob Carlborg wrote:
>>> Is there a general function for transforming a range back to the
>>> original type? If not, would it be possible to create one?
>>
>> You mean that if you have something like
>>
>> auto range = getRangeFromSomewhere();
>> auto newRange = find(filter!func(range), value);
>>
>> you want to transform newRange back to the same type as range?
>
> No, I want to transform newRange back to a collection, the same type as the original collection. I was thinking something like this:
>
> Collection c = new Collection();
> c = c.filter!(x => x < 3).toCollection();

Why can't the last line be:

c = new Collection(c.filter!(x => x < 3));

or more generically:

c = new typeof(c)(c.filter!(x => x < 3));

?

-Steve
May 04, 2012
On Friday, 4 May 2012 at 12:49:35 UTC, Steven Schveighoffer wrote:
> or more generically:
>
> c = new typeof(c)(c.filter!(x => x < 3));
>
> ?

That doesn't do the right thing when 'c' isn't a class type, so it's not really that generic.

Struct types (the type of `new typeof(c)` is not `typeof(c)`!) and array types simply fail with your suggestion.

I personally haven't decided whether I think a generic convention is useful here, but that code doesn't fit the bill.

May 04, 2012
On Fri, 04 May 2012 09:06:31 -0400, Jakob Ovrum <jakobovrum@gmail.com> wrote:

> On Friday, 4 May 2012 at 12:49:35 UTC, Steven Schveighoffer wrote:
>> or more generically:
>>
>> c = new typeof(c)(c.filter!(x => x < 3));
>>
>> ?
>
> That doesn't do the right thing when 'c' isn't a class type, so it's not really that generic.
>
> Struct types (the type of `new typeof(c)` is not `typeof(c)`!) and array types simply fail with your suggestion.

Structs don't make very good containers.  A slice is not really a container.

But in any case, someone can make a function that's generic with a couple static ifs.

> I personally haven't decided whether I think a generic convention is useful here, but that code doesn't fit the bill.

What exactly are you looking for?  I mean, you want the original type back, so you can reassign, is that all?  Something like this should work for that:

c = makeContainer!typeof(c)(c.filter!(x => x < 3));

Implementation left as an exercise.

-Steve