www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 9339] New: std.random.uniform!Enum should return random enum member

reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9339

           Summary: std.random.uniform!Enum should return random enum
                    member
           Product: D
           Version: D2
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: enhancement
          Priority: P2
         Component: Phobos
        AssignedTo: nobody puremagic.com
        ReportedBy: hsteoh quickfur.ath.cx


--- Comment #0 from hsteoh quickfur.ath.cx 2013-01-17 14:33:56 PST ---
Currently, std.random.uniform does not respect enum bounds:

import std.random;
import std.stdio;

enum Fruit {
        Apple = 14,
        Orange = 27,
        Pear = 36,
        Mango = 47
}

void main() {
        writefln("%d", Fruit.min);
        writefln("%d", Fruit.max);

        writeln(uniform!Fruit());
}


Typical output:

14
47
cast(Fruit)-2046817621


It should at the very least respect the enum range defined by the enum's .min
and .max properties (which in this case are 14 and 47, respectively).

Ideally, it should only return one of the four possible values of Fruit, not
anything outside the range of .min and .max, and not anything in between the
four possible values.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jan 17 2013
next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9339


Andrej Mitrovic <andrej.mitrovich gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |andrej.mitrovich gmail.com


--- Comment #1 from Andrej Mitrovic <andrej.mitrovich gmail.com> 2013-01-17
16:31:49 PST ---
Would this suffice?

auto uniform(T)()
if (is(T == enum) && isIntegral!T || isSomeChar!T)
{
    enum arr = [EnumMembers!T];
    return randomSample(arr, 1);
}

(You would have to add a !is(T == enum) in the other template).

Example:

import std.random;
import std.stdio;
import std.traits;

enum Fruit
{
    Apple  = 14,
    Orange = 27,
    Pear   = 36,
    Mango  = 47
}

auto uniform(T)()
if (is(T == enum) && isIntegral!T || isSomeChar!T)
{
    enum arr = [EnumMembers!T];
    return randomSample(arr, 1);
}

void main()
{
    foreach (i; 0 .. 10)
        writeln(uniform!Fruit());
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jan 17 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9339



--- Comment #2 from hsteoh quickfur.ath.cx 2013-01-17 16:40:15 PST ---
Yeah, that will do. Except that the "enum arr = [EnumMembers!E];" line may run
into issue 6057. :)

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jan 17 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9339


bearophile_hugs eml.cc changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |bearophile_hugs eml.cc


--- Comment #3 from bearophile_hugs eml.cc 2013-01-17 16:47:21 PST ---
(In reply to comment #1)

 auto uniform(T)()
 if (is(T == enum) && isIntegral!T || isSomeChar!T)
 {
     enum arr = [EnumMembers!T];
     return randomSample(arr, 1);
 }

I think this is more efficient: T uniform(T)() if (is(T == enum) && isIntegral!T || isSomeChar!T) { static immutable T[EnumMembers!T.length] members = [EnumMembers!T]; return members[std.random.uniform(0, members.length)]; } -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Jan 17 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9339



--- Comment #4 from bearophile_hugs eml.cc 2013-01-17 16:48:48 PST ---
(In reply to comment #1)

     enum arr = [EnumMembers!T];

Be very careful with enum arrays. They are very inefficient. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Jan 17 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9339



--- Comment #5 from hsteoh quickfur.ath.cx 2013-01-17 16:52:13 PST ---
(In reply to comment #3)
[...]
 I think this is more efficient:
 
 
 T uniform(T)()
 if (is(T == enum) && isIntegral!T || isSomeChar!T)
 {
     static immutable T[EnumMembers!T.length] members = [EnumMembers!T];
     return members[std.random.uniform(0, members.length)];
 }

You're right, we want the array to be statically initialized. Does enum arr = [...] cause the code to create the array every time the function is called? -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Jan 17 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9339



--- Comment #6 from Andrej Mitrovic <andrej.mitrovich gmail.com> 2013-01-17
17:01:43 PST ---
(In reply to comment #4)
 (In reply to comment #1)
 
     enum arr = [EnumMembers!T];

Be very careful with enum arrays. They are very inefficient.

Well, the compiler is very inefficient, static will do.
 T uniform(T)()
 if (is(T == enum) && isIntegral!T || isSomeChar!T)
 {
     static immutable T[EnumMembers!T.length] members = [EnumMembers!T];
     return members[std.random.uniform(0, members.length)];
 }

That's not doing what was requested. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Jan 17 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9339



--- Comment #7 from Andrej Mitrovic <andrej.mitrovich gmail.com> 2013-01-17
17:08:20 PST ---
As much as I'd love to make a pull for this I already know I'm going to run
into Issue 6057 (which has a pull but needs a review).

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jan 17 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9339



--- Comment #8 from Andrej Mitrovic <andrej.mitrovich gmail.com> 2013-01-17
17:29:52 PST ---
(In reply to comment #7)
 As much as I'd love to make a pull for this I already know I'm going to run
 into Issue 6057 (which has a pull but needs a review).

Looks like I said the same thing as Comment #2. :p -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Jan 17 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9339



--- Comment #9 from hsteoh quickfur.ath.cx 2013-01-17 17:36:18 PST ---
If you write "static arr = [EnumMembers!T];", you should be able to evade issue
6057.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jan 17 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9339



--- Comment #10 from Andrej Mitrovic <andrej.mitrovich gmail.com> 2013-01-17
17:43:00 PST ---
(In reply to comment #9)
 If you write "static arr = [EnumMembers!T];", you should be able to evade issue
 6057.

The issue is with unittests. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Jan 17 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9339



--- Comment #11 from hsteoh quickfur.ath.cx 2013-01-17 21:15:26 PST ---
I don't understand. If you use that line in uniform(), and it works, then
unittests shouldn't have any problems either, no?

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jan 17 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9339



--- Comment #12 from Andrej Mitrovic <andrej.mitrovich gmail.com> 2013-01-17
21:21:50 PST ---
(In reply to comment #11)
 I don't understand. If you use that line in uniform(), and it works, then
 unittests shouldn't have any problems either, no?

The problem is the enum has to be hidden in a unittest block like so: version(unittest) { enum TestEnum { ... } } unittest { foreach (_; 0 .. 100) assert(uniform!TestEnum() == ...); } And this causes linking problems due to Issue 6057. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Jan 17 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9339



--- Comment #13 from hsteoh quickfur.ath.cx 2013-01-17 21:35:46 PST ---
Oh? This code compiles & links just fine:

import std.random;
import std.traits;

E randomPick(E)() if (is(E == enum)) {
        static members = [ EnumMembers!E ];
        return members[uniform(0, EnumMembers!E.length)];
}

void main() {
}

unittest {
        enum Fruit { Apple = 12, Mango = 29, Pear = 72 };
        foreach (_; 0 .. 100) {
                auto f = randomPick!Fruit();
                assert(f == Fruit.Apple || f == Fruit.Mango || f ==
Fruit.Pear);
        }
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jan 17 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9339



--- Comment #14 from bearophile_hugs eml.cc 2013-01-18 10:20:09 PST ---
(In reply to comment #6)

 T uniform(T)()
 if (is(T == enum) && isIntegral!T || isSomeChar!T)
 {
     static immutable T[EnumMembers!T.length] members = [EnumMembers!T];
     return members[std.random.uniform(0, members.length)];
 }

That's not doing what was requested.

Then I don't understand. This ER asks for that function overload to return a "random enum member". Isn't members[std.random.uniform(0, members.length)] a random enum member? And beside what the OP is asking, uniform() returns single random values of a type. Isn't this what I am doing there? -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Jan 18 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9339



--- Comment #15 from Andrej Mitrovic <andrej.mitrovich gmail.com> 2013-01-18
10:30:47 PST ---
(In reply to comment #14)
 (In reply to comment #6)
 
 T uniform(T)()
 if (is(T == enum) && isIntegral!T || isSomeChar!T)
 {
     static immutable T[EnumMembers!T.length] members = [EnumMembers!T];
     return members[std.random.uniform(0, members.length)];
 }

That's not doing what was requested.

Then I don't understand.

I've misread the last statement (it was late) as: return std.random.uniform(0, members.length); instead of: return members[std.random.uniform(0, members.length)]; Apologies. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Jan 18 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9339



--- Comment #16 from Andrej Mitrovic <andrej.mitrovich gmail.com> 2013-01-21
17:01:19 PST ---
https://github.com/D-Programming-Language/phobos/pull/1086

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jan 21 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9339



--- Comment #17 from bearophile_hugs eml.cc 2013-01-21 17:10:03 PST ---
(In reply to comment #16)
 https://github.com/D-Programming-Language/phobos/pull/1086

I have seen that of this line you have dropped both the immutable and fixed sized array, can you explain why a dynamic array is better than a fixed array in the static segment? static immutable T[EnumMembers!T.length] members = [EnumMembers!T]; -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Jan 21 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9339



--- Comment #18 from Andrej Mitrovic <andrej.mitrovich gmail.com> 2013-01-21
17:21:07 PST ---
(In reply to comment #17)
 (In reply to comment #16)
 https://github.com/D-Programming-Language/phobos/pull/1086

I have seen that of this line you have dropped both the immutable and fixed sized array, can you explain why a dynamic array is better than a fixed array in the static segment? static immutable T[EnumMembers!T.length] members = [EnumMembers!T];

It was a mistake, I've updated the code now. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Jan 21 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9339



--- Comment #19 from github-bugzilla puremagic.com 2013-02-12 17:25:07 PST ---
Commits pushed to master at https://github.com/D-Programming-Language/phobos

https://github.com/D-Programming-Language/phobos/commit/c95100ba78cc137ee4af37d59e3b3dfb704a4832
Fixes Issue 9339 - Uniform for enums.

https://github.com/D-Programming-Language/phobos/commit/6a3ffa5e136d22b31529e6a3688cb8ce3a5508a0
Merge pull request #1086 from AndrejMitrovic/Fix9339

Issue 9339 - std.random.uniform for enums

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Feb 12 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9339


Andrej Mitrovic <andrej.mitrovich gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|                            |FIXED


-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Feb 12 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9339



--- Comment #20 from bearophile_hugs eml.cc 2013-02-12 17:33:09 PST ---
One test case to try:


import std.bigint, std.random;

enum Foo : BigInt {
    zero = BigInt(0),
    one =  BigInt(1)
}

void main() {
    auto x = uniform!Foo();
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Feb 12 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9339



--- Comment #21 from Andrej Mitrovic <andrej.mitrovich gmail.com> 2013-02-12
17:38:45 PST ---
(In reply to comment #20)
 One test case to try:
 
 
 import std.bigint, std.random;
 
 enum Foo : BigInt {
     zero = BigInt(0),
     one =  BigInt(1)
 }
 
 void main() {
     auto x = uniform!Foo();
 }

It works. It should actually work with any enum base types, since the only requirement is that the type is an enum. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Feb 12 2013
prev sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9339



--- Comment #22 from github-bugzilla puremagic.com 2013-02-13 00:13:44 PST ---
Commit pushed to staging at https://github.com/D-Programming-Language/phobos

https://github.com/D-Programming-Language/phobos/commit/128eaa901ccc0b011773e269e7f2adcd8e0d03b8
Fixes Issue 9339 - Uniform for enums.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Feb 13 2013