Reference semantic ranges and algorithms (and std.random)
monarch_dodra
monarchdodra at gmail.com
Thu Sep 20 02:18:27 PDT 2012
On Thursday, 20 September 2012 at 07:26:01 UTC, Jonathan M Davis
wrote:
> 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/bvuquzwfykiytdwsqkky@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
TY for your insight. Good points. I'll try to do your "#1": It is
simple and non breaking. *IF* we ever do decide to break, and
rather it be done after a very thourough discussion of
requirements, specifications, migration path, etc...
More information about the Digitalmars-d
mailing list