July 10, 2012
"Christophe Travert" <travert@phare.normalesup.org> wrote in message news:jthmu8$2s5b$1@digitalmars.com...
> "Daniel Murphy" , dans le message (digitalmars.D:171720), a écrit :
>> Could it be extended to accept multiple values? (sort of like chain)
>> eg.
>> foreach(x; makeRange(23, 7, 1990)) // NO allocations!
>> {
>>     ....
>> }
>> I would use this in a lot of places I currently jump through hoops to get
>> a
>> static array without allocating.
>
> That's a good idea. IMHO, the real solution would be to make an easy way to create static arrays, and slice them when you want a range.
>

It's not quite the same thing, static arrays are not ranges and once you slice them you no longer have a value type, and might be referring to stack allocated data.  With... this thing, the length/progress is not encoded in the type (making it rangeable) but the data _is_ contained in the type, making it safe to pass around.  The best of both worlds, in some situations.

An easy way to get static arrays would be great too.

>
> I it were just me, array litterals would be static, and people should use .dup when they want a a surviving slice.
>

It used to be like that.  Most of the time you don't really want a static array.


July 10, 2012
Jacob Carlborg , dans le message (digitalmars.D:171739), a écrit :
> On 2012-07-10 18:42, Daniel Murphy wrote:
>> "Jacob Carlborg" <doob@me.com> wrote in message news:jthlpf$2pnb$1@digitalmars.com...
>>>
>>> Can't "map" and "filter" return a random-access range if that's what they receive?
>>>
>> map can, and does.
> 
> It doesn't seem to:
> 
> auto a = [3, 4].map!(x => x);
> auto b = a.sort;
> 
> Result in one of the original errors I started this thread with.

here, map is random-access. But random access is not enough to call sort: you need to have assignable (well, swapable) elements in the range, if you want to be able to sort it. values accessed via a map are not always assignable, since they are the result of a function.

It seems the map resulting from (x => x) is not assignable. This is debatable, but since (x => x) is just a stupid function to test. Otherwise, you could try the folowing:

auto a = [3, 4].map!(ref int (ref int x) { return x; })();
a.sort;

July 10, 2012
"Jacob Carlborg" <doob@me.com> wrote in message news:jthnlo$2tjg$1@digitalmars.com...
> On 2012-07-10 18:42, Daniel Murphy wrote:
>> "Jacob Carlborg" <doob@me.com> wrote in message news:jthlpf$2pnb$1@digitalmars.com...
>>>
>>> Can't "map" and "filter" return a random-access range if that's what
>>> they
>>> receive?
>>>
>> map can, and does.
>
> It doesn't seem to:
>
> auto a = [3, 4].map!(x => x);
> auto b = a.sort;
>
> Result in one of the original errors I started this thread with.
>
> -- 
> /Jacob Carlborg
>
>

writeln([1, 2, 3].map!"a"()[2]);

Sort is in place, and therefore requires more than random access, you need to be able to modify the data you're operating on.

Something like [3, 4].map!func().selectionSort() could work lazily without needing to modify the original range, but urrgh.


July 10, 2012
On Tuesday, July 10, 2012 18:57:25 Jacob Carlborg wrote:
> On 2012-07-10 16:36, Dmitry Olshansky wrote:
> > typeof to the rescue. In fact I'm not so proud of voldemort types. As when you need to sotre range somewhere they stand in your way for no benefit.
> 
> I'm not exactly sure how you mean but this is what I came up with:
> 
> import std.algorithm;
> import std.traits;
> import std.conv;
> 
> class Foo
> {
> auto bar ()
> {
> return [3, 4].map!(x => x.to!(string));
> }
> 
> ReturnType!(bar) x;
> }


typeof(bar()) x;

works. But regardless, given that you're dealing with a return type which is auto, there's really no other choice. Even if we weren't using voldemort types for stuff like map, the return type would still be templated and depend on the actual arguments to map, making writing the type a pain - especially if it's complicated; until (which _doesn't_ use a voldemort type) is a prime example of this. You end up with something like Until!("a == b",int[],int) for a basic call to until, and it gets really nasty if you start chaining function calls so that the range passed to Until is far more complicated than int[]. Using ReturnType and typeof becames the sane thing to do (and much more maintainable too, since you don't have to change it if/when you change the call to map enough that it's return type changes). It does take some getting used to, but it works very well. You just have to realize that if you're operating on ranges, you're generally _not_ caring what they exact type is, and you use auto and templates a lot. Sometimes converting the result to an array is exactly what you want to do, but the less you do that, the more efficient your code will be.

- Jonathan M Davis
July 10, 2012
On Tuesday, July 10, 2012 12:22:30 Andrei Alexandrescu wrote:
> On 7/10/12 12:01 PM, Christophe Travert wrote:
> > Andrei Alexandrescu , dans le message (digitalmars.D:171717), a écrit :
> >> auto singletonRange(E)(E value)
> >> {
> >> 
> >> return repeat(value).takeExactly(1);
> >> 
> >> }
> > 
> > It would be much better to use:
> > 
> > auto singletonRange(E)(E value)
> > {
> > 
> > return repeat(value).takeOne;
> > 
> > }
> > 
> > as well as:
> > 
> > auto emptyRange(E)(E value)
> > {
> > 
> > return repeat(value).takeNone;
> > 
> > }
> > 
> > to have the advantages of takeOne and takeNone over takeExactly.
> 
> Ah, such as them being random access. Cool!
> 
> That also seems to answer Jonathan's quest about defining emptyRange.
> Just use takeNone(R.init).

Actually, it doesn't, because find needs the ability to get an empty range of the exact same type as the original. It's a nice idea for cases where the resultant range doesn't matter though.

- Jonathan M Davis
July 10, 2012
On Tuesday, July 10, 2012 14:27:14 Simen Kjaeraas wrote:
> On Tue, 10 Jul 2012 09:04:31 +0200, Jonathan M Davis <jmdavisProg@gmx.com>
> 
> wrote:
> > The problem is that map is lazy, so it can't be a random access range,
> 
> Sure it can. If the underlying range is random-access or bidirectional, so can map be. What can't be (as easily) done is caching of elements.

Ah, you're right. I'm too used to thinking about filter, but map doesn't change the number of elements, so it works just fine as random access (though it risks being an efficient way of doing things if the function using it accessing its elements multiple times, since it's going to have to call the predicate every time that the element is accessed, whereas if you just iterate over the range, then odds are that you only access the element once).

- Jonathan M Davis
July 10, 2012
"Daniel Murphy" , dans le message (digitalmars.D:171741), a écrit :
> "Christophe Travert" <travert@phare.normalesup.org> wrote in message news:jthmu8$2s5b$1@digitalmars.com...
>> "Daniel Murphy" , dans le message (digitalmars.D:171720), a écrit :
>>> Could it be extended to accept multiple values? (sort of like chain)
>>> eg.
>>> foreach(x; makeRange(23, 7, 1990)) // NO allocations!
>>> {
>>>     ....
>>> }
>>> I would use this in a lot of places I currently jump through hoops to get
>>> a
>>> static array without allocating.
>>
>> That's a good idea. IMHO, the real solution would be to make an easy way to create static arrays, and slice them when you want a range.
> 
> It's not quite the same thing, static arrays are not ranges and once you slice them you no longer have a value type, and might be referring to stack allocated data.  With... this thing, the length/progress is not encoded in the type (making it rangeable) but the data _is_ contained in the type, making it safe to pass around.  The best of both worlds, in some situations.

OK, I see. This goes against the principle that ranges are small and easy to copy arround, but it can be useful when you know what you are doing, or when the number of items is small.

I don't like makeRange much. Would you have a better name? smallRange? rangeOf?


July 10, 2012
"Christophe Travert" <travert@phare.normalesup.org> wrote in message news:jthp14$30em$1@digitalmars.com...
> "Daniel Murphy" , dans le message (digitalmars.D:171741), a écrit :
>> "Christophe Travert" <travert@phare.normalesup.org> wrote in message news:jthmu8$2s5b$1@digitalmars.com...
>>> "Daniel Murphy" , dans le message (digitalmars.D:171720), a écrit :
>>>> Could it be extended to accept multiple values? (sort of like chain)
>>>> eg.
>>>> foreach(x; makeRange(23, 7, 1990)) // NO allocations!
>>>> {
>>>>     ....
>>>> }
>>>> I would use this in a lot of places I currently jump through hoops to
>>>> get
>>>> a
>>>> static array without allocating.
>>>
>>> That's a good idea. IMHO, the real solution would be to make an easy way to create static arrays, and slice them when you want a range.
>>
>> It's not quite the same thing, static arrays are not ranges and once you
>> slice them you no longer have a value type, and might be referring to
>> stack
>> allocated data.  With... this thing, the length/progress is not encoded
>> in
>> the type (making it rangeable) but the data _is_ contained in the type,
>> making it safe to pass around.  The best of both worlds, in some
>> situations.
>
> OK, I see. This goes against the principle that ranges are small and easy to copy arround, but it can be useful when you know what you are doing, or when the number of items is small.
>

Yeah, it works where you'd pass a tuple of elements of the same type, but want to iterate over it.

> I don't like makeRange much. Would you have a better name? smallRange? rangeOf?
>
>
rangeit


July 10, 2012
On Tue, 10 Jul 2012 16:15:09 +0200, Jacob Carlborg <doob@me.com> wrote:

> On 2012-07-10 14:53, Dmitry Olshansky wrote:
>
>> Too bad, as there is no need to make an array when you map something.
>
> How do you store your ranges in a struct or class? Most of them are voldemort types.

Well, there is std.range.inputRangeObject, but as the name indicates, it's
only an input range.


>> "
>> Iterates unique consecutive elements of the given range (functionality
>> akin to the uniq system utility). Equivalence of elements is assessed by
>> using the predicate pred, by default "a == b". If the given range is
>> bidirectional, uniq also yields a bidirectional range.
>> "
>> Though it doesn't explicitly mentions it, the example is:
>
> Yes, exactly.
>
>> int[] arr = [ 1, 2, 2, 2, 2, 3, 4, 4, 4, 5 ];
>> assert(equal(uniq(arr), [ 1, 2, 3, 4, 5 ][]));
>
> How should I know that from the example?

You shouldn't. The description however, says 'unique consecutive elements',
which *does* explain it.

-- 
Simen
July 10, 2012
On 7/10/12 12:38 PM, Jacob Carlborg wrote:
> Can't "map" and "filter" return a random-access range if that's what
> they receive?

(replied to by others)

>> Now I understand if you come from a place where there's no concern over
>> hidden allocations and extra work for the benefit of convenience, you
>> may find std.algorithm less easy to work with. But drawing the
>> conclusion that std.algorithm is badly designed or gratuitously
>> difficult to use would be a mistake. I opine I can recognize a good vs.
>> bad design even when it's mine, and in my opinion std.algorithm is a
>> good design and that most of your opposing impressions derive from a
>> misunderstanding of its charter.
>
> I don't think I've struggled as much with any other API I've used. In
> many cases I had to resort to foreach-loops because that was more
> convenient than using std.algorithm.

That's fine. I don't see std.algorithm as a competitor against simple loops, but instead of work that would be very verbose and difficult to do with loops. I mean I clearly recall at a point I wanted to define a forAll algorithm, but then I was like, "people can use foreach for that".

Andrei