On Thursday, September 20, 2012 08:51:28 monarch_dodra wrote: > On Tuesday, 18 September 2012 at 17:59:04 UTC, Jonathan M Davis > > wrote: > > On Tuesday, September 18, 2012 17:05:26 monarch_dodra wrote: > >> This is issue #1: I'd propose that all objects in std.random be > >> migrated to classes (or be made reference structs), sooner than > >> later. This might break some code, so I do not know how this is > >> usually done, but I think it is necessary. I do not, however, > >> propose that they should all derive from a base class. > > > > Moving to classes would definitely break code, but it should be > > possible to > > make them reference types simply by making it so that their > > internal state is > > in a separate object held by a pointer. > > I was thinking of doing that. The problem with this (as I've run > into and stated in another thread), is a problem of > initialization: The simpler PRNGs are init'ed seeded, and are > ready for use immediately. Changing to this approach would break > the initialization, as shown in this post: > > http://forum.dlang.org/thread/bvuquzwfykiytdwsq...@forum.dlang.org#post-yvts > ivozyhqzscgddbrl:40forum.dlang.org > > A "used to be valid" PRNG has now become an un-initialized PRNG". > This is extremely insidious, as the code still compiles, but will > crash.
There's always the check that the internals have been initialized on every call and initialize it if it hasn't been solution. It's not pretty, but it won't break code. It's actually a use case that makes me wish that we had something like the invariant which ran before every public function call except that it was always there (even in -release) and let you do anything you want. In any case, while it's a bit ugly, I believe that simply adding checks for initialization in every function call is the cleanest solution from the standpoint of backwards compatibility, and the ugliness is all self-contained. As far as performance goes, it's only an issue if you're iterating over it in a tight loop, but the actual random number generation is so much more expensive than a check for a null pointer that it probably doesn't matter. > #2 > Change to class, but leave behind some "opCall"s for each old > constructor, plus an extra one for default: > Is this second solution something you think I should look into? Since A a; will just blow up in your face if you switch it to a class, it's not a non- breaking change even as a migration path, so I don't see that as really being viable. Even if you've found a way to minimize the immediate code breakage, you didn't eliminate it. If you're going to break code immediately, you might as well just break it all at once and get people to fix their stuff rather than mostly fix it but not quite, especially when you're asking them to change their code later anyway as part of a migration path. Regardless, when this came up previously, I believe that the conclusion was that if we were going to switch to classes, we needed to do something like create std.random2 and schedule std.random for deprecation rather than changing the current structs to classes (either that or rename _every_ type in there and schedule them for deprecation individually, but then you have to come up for new names for everything, and it's more of a pain to migrate, since all the names changed rather than just the import). So, I believe that the idea of switching to classes was pretty much rejected previously unless entirely new types were used so that no code would be broken. I think that we have two options at this point: 1. Switch the internals so that they're in a separate struct pointed to by the outer struct and check for initialization on every function call to avoid the problem where init was used. 2. Create a new module to replace std.random and make them final classes in there, scheduling the old module for deprecation. Honestly, I'd just go with #1 at this point, because it avoids breaking code, and there's increasing resistance to breaking code. Even Andrei, who was fairly willing to break code for improvements before, is almost paranoid about it now, and Walter was _always_ against it. So, if we have a viable solution that avoids breaking code (especially if any ugliness that comes with it is internal to the implementation), we should probably go with that. - Jonathan M Davis