November 23, 2016
On 11/23/16 11:10 AM, Kagamin wrote:
> On Wednesday, 23 November 2016 at 14:30:53 UTC, Andrei Alexandrescu wrote:
>> That seems to be a minor matter. Of course at best some measurements
>> would be in order.
>>> Yes, it's just Joseph worries about microoptimizations.
>
> Though we saw that the compiler can't optimize some simple operations
> like division by 2.

[Details needed]

I just took a look https://godbolt.org/g/EMy6X4, it's happening.


Andrei

November 23, 2016
On 11/23/16 3:05 PM, Ilya Yaroshenko wrote:
> On Wednesday, 23 November 2016 at 19:51:50 UTC, Andrei Alexandrescu wrote:
>> On 11/23/16 2:40 PM, Ilya Yaroshenko wrote:
>>> On Wednesday, 23 November 2016 at 19:16:29 UTC, Andrei Alexandrescu
>>> wrote:
>>>>
>>>> A tip for the range adaptor: have it allocate and own the generator
>>>> internally. That way it's easy to make it reference counted
>>>> economically.
>>>
>>> Current adaptor should be used in a function scope. (Would be great to
>>> have a DIP for that kind of semantic check). An RC adaptor can be added
>>> too. First we need to find a real world use case where we need to store
>>> a random range outside of a function. -- Ilya
>>
>> Yah, problem here is we can't make that @safe. -- Andrei
>
> Can we improve D to make it safe?

It's difficult in the general case for objective reasons (modular analysis). For this, we may be able to take an argument by ref, save its address inside, add some scope attributes. It's a project. -- Andrei
November 23, 2016
On Wednesday, November 23, 2016 14:02:36 Joseph Rushton Wakeling via Digitalmars-d wrote:
> On Wednesday, 23 November 2016 at 13:56:27 UTC, Andrei
>
> Alexandrescu wrote:
> > Well I do see another small problem with https://github.com/libmir/mir-random/blob/master/source/random/algorithm .d#L19. It creates the first value eagerly upon construction. That's just a bit awkward. It's not the first time I'm seeing this issue, and to be honest am a bit bummed about it. It's a consequence of all ranges needing to buffer at least one element. -- Andrei
> Yea, this touches on one of my more general concerns related to ranges, randomness and laziness.  Part of the trouble is we don't have a really good general design for how to implement _truly_ lazy ranges, where the value of `front` is not determined until the point where you first access it.
>
> This has particular relevance to e.g. RandomSample and RandomCover.

It's quite feasible if you don't calculate front until it's called or popFront is called, and then you cache the result so that subsequent calls to front prior to the call to popFront return the same result, but it creates additional overhead, because then every call to front and popFront has to check whether the value has been calculated yet. And if every range in the chain of ranges has to do that, then that additional overhead is going to add up.

In general, it's just cleaner to either calculate front on every call to front (which doesn't make sense in the case of random number generators) or to calculate the first front upon construction and be done with it. And I think that the general consensus has been that calculating front in the constructor and popFront and caching works better than calculating it on every call to front, but that doesn't always work (e.g. map), and that caching does cause issues occasionally.

- Jonathan M Davis

November 23, 2016
On Wednesday, November 23, 2016 08:54:30 Andrei Alexandrescu via Digitalmars-d wrote:
> On 11/23/2016 06:14 AM, Ilya Yaroshenko wrote:
> > I think that Range API is bad and useless overengineering for RNGs.
>
> So it either "takes 1 minute" to change the interface from opCall to ranges (i.e. they're virtually the same thing), or it's the above. There's precious little overengineering that can be done in 1 minute
>
> :o). I see you did that in a dozen lines in RandomRangeAdaptor.
>
> I understand you believe the range interface is unnecessary or overkill for random number generators. I may even agree for certain cases. However, there are a few arguments you may want to consider:
>
> * By virtue of working with D, everybody know what a range is. Presenting the RNGs that way instantly evokes a host of knowledge, understanding, and idioms.
>
> * D users (or at least a fraction) and several algorithms understand the notion of an infinite range and make salient decisions based on that. A range interface automatically taps into that.

I've frequently found that in cases where I'm not operating on a range of values, I really just want a way to get a random number, and having to call both popFront and front to get it is a bit annoying (it's actually one of the few places that I've ever used the comma operator). That being said, I think that the correct solution to that is to add a function to std.random that takes a range, calls popFront on it, and then returns front so that it can work with any of the random number generators and avoids problems with whether or not popFront was called prior to calling front. I have to agree that creating a different API that uses opCall or whatever instead of a the range API is a bad idea, particularly when a simple helper function would make it possible to use a random number generator in a fashion more like rand() for the cases where that's preferable, and for a lot of cases, having the range API is _extremely_ useful.

- Jonathan M Davis

November 23, 2016
On Wednesday, November 23, 2016 15:29:14 Kagamin via Digitalmars-d wrote:
> On Wednesday, 23 November 2016 at 14:30:53 UTC, Andrei
>
> Alexandrescu wrote:
> > This claim would apply to all ranges. There seems to be evidence it is unfounded.
> >
> > The main argument for using the range interface for RNGs is reuse of abstraction. Minute implementation matters are much less important. The main counter-argument is that the abstraction is not fitting well and another abstraction (such as opCall) is more advantageous.
>
> Consider this okayish looking code:
> consume(rng());
> consume(rng.take(2)); //reuses previous value
> consume(rng()); //discards unused value

In the cases where I don't really need a range of random numbers, I've typically ended up doing stuff like

auto nextNum = rndGen().popFront(), rndGen().front;

though I think that using the comma operator like that is deprecated now. Adding a helper function such as

auto getNext(R)(ref R range)
    if(isInputRange!R)
{
    range.popFront();
    return range.front;
}

would solve that problem. And there are plenty of cases where having a range of random numbers is extremely useful. After having dealt with, std.random, it would really suck to have to deal with a random number generator that was not range-based. std.random has problems such as not using reference types for its ranges, but using the range API in the way it does is extremely useful.

- Jonathan M Davis

November 24, 2016
> I have to agree that creating a different API that uses opCall or whatever instead of a the range API is a bad idea, particularly when a simple helper function would make it possible to use a random number generator in a fashion more like rand() for the cases where that's preferable, and for a lot of cases, having the range API is _extremely_ useful.
>
> - Jonathan M Davis

Would, assuming the OpCall() interface, generate!(() => rng()) make an input range out of it easily? Or am I missing something?

November 24, 2016
On Wednesday, 23 November 2016 at 17:31:58 UTC, Kagamin wrote:
> On Wednesday, 23 November 2016 at 01:28:11 UTC, Andrei Alexandrescu wrote:
>> Interesting. Could you please add a couple of links about that? -- Andrei
>
> http://xoroshiro.di.unimi.it/

Very short public domain implementation:
http://xoroshiro.di.unimi.it/xoroshiro128plus.c

November 24, 2016
On Wednesday, 23 November 2016 at 21:18:27 UTC, Andrei Alexandrescu wrote:
> [Details needed]
>
> I just took a look https://godbolt.org/g/EMy6X4, it's happening.

That's three instructions instead of one shr eax,1
November 24, 2016
On Wednesday, 23 November 2016 at 19:40:47 UTC, Ilya Yaroshenko wrote:
> Current adaptor should be used in a function scope. (Would be great to have a DIP for that kind of semantic check). An RC adaptor can be added too. First we need to find a real world use case where we need to store a random range outside of a function. -- Ilya

You want to instantiate and seed Mt every time you call a function that may need random numbers?
November 24, 2016
On Wednesday, 23 November 2016 at 21:33:53 UTC, Jonathan M Davis wrote:
> though I think that using the comma operator like that is deprecated now. Adding a helper function such as
>
> auto getNext(R)(ref R range)
>     if(isInputRange!R)
> {
>     range.popFront();
>     return range.front;
> }
>
> would solve that problem.

It's the same behavior and suffers from the same problem of reuse of RNG output.