Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:114833 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 4723 invoked from network); 12 Jun 2021 10:14:47 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 12 Jun 2021 10:14:47 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id B1A42180539 for ; Sat, 12 Jun 2021 03:30:30 -0700 (PDT) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM,HTML_MESSAGE, RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_PASS autolearn=no autolearn_force=no version=3.4.2 X-Spam-Virus: No X-Envelope-From: Received: from mail-ed1-f49.google.com (mail-ed1-f49.google.com [209.85.208.49]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Sat, 12 Jun 2021 03:30:30 -0700 (PDT) Received: by mail-ed1-f49.google.com with SMTP id cb9so40087067edb.1 for ; Sat, 12 Jun 2021 03:30:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to; bh=ulJVq9KmbgLH8bK7oluCgm0fh8gz2ulBCy58Ikn9B2s=; b=mBcFMsFPonNFrtOzMRvfOC35wqkc5Zk3YZx8uigkpTNskttIOqHILuEnACg9ePpYXa 1b2YT7kN+npsKJZz0M8rgkO7cSY8zrjjjS/QHRKNPcs/50LEreOlDkTNzID9kQhX8HTb 1lZ0nWUhUakMqOiABApFgYTEFwUdHxwStkYkbHKaeJzVo/uPh4s5RDVgv6XurEqoLnpK oneH2VkEHBV485fxIklnQ9vrfRk5IpDEdVzkqfeHzcKhCjT3IDJtCI5MowahFAXBlZ2w Fwcml5OylKJZCLuD9hO+1Z+v4Cp4G1P9p/4i8AcHY4QDdFuuvLFNF/oE4EnZ8OcO7R4Q KzbA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to; bh=ulJVq9KmbgLH8bK7oluCgm0fh8gz2ulBCy58Ikn9B2s=; b=YRWzIgE2yZHhY75YTcbWK+AsydzxPf5P2u64ZdNKGJRBIJu8afITL+32WQQeVrkdpE pKDJbfW9uRfhvvr1q4AE0AKEf5n7oL1RFS07RuHO2i8GzSpY4avvDNQV7+Rd7Lptvu1H IulyLgqFP8BAMd34shcI1iSWJEQ7eevrzizr9V1HDkdSjMBp8Lw4/czxod8jiWBrAym0 /9xB6UkOWL0KnAdGew9WP9uaiFAiANgEqk5zglq8GyjGKIFtN9rKBDIau72bMSdOMfzf I3uLNTMDwFObtHHJ0aiwQggsISUJOsJubPiPDHg4gL7kEjdhqgAbdP3uelRMJrisMV3t u9lg== X-Gm-Message-State: AOAM53185eScKCNNVu6t7kyeTZSRR8/Ap2mUuzNh5OU9IV/dgPJuyETc VfKZo4/nxkyxcA0tCY0sZlJ9Z8Ciu6d+/oAwDsM7Tpul/fB5hQ== X-Google-Smtp-Source: ABdhPJxNBicxPnqJOLTf7tGFfF6gRAd4Xqycj1G4c3wfOsKyXhnrb29mWzhaZ+2vJPgPMHtmygJf6pUNl/c2LesMzdo= X-Received: by 2002:a05:6402:344:: with SMTP id r4mr7880321edw.226.1623493828944; Sat, 12 Jun 2021 03:30:28 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: Date: Sat, 12 Jun 2021 19:30:17 +0900 Message-ID: To: Guilliam Xavier , Nikita Popov , PHP internals Content-Type: multipart/alternative; boundary="000000000000f8259305c48f1ccf" Subject: Re: [PHP-DEV] Re: [RFC] Under Discussion: Add Random class and RandomNumberGenerator interface From: zeriyoshi@gmail.com (Go Kudo) --000000000000f8259305c48f1ccf Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Sorry, I'm late to reply. > How much more "costly" would it be to define a class (implementing RandomNumberGenerator) and use its (full) name as the algo identifier? If the Random class always accepts an instance of the RandomNumberGenerator, it will be necessary to provide a class that implements the RandomNumberGenerator whenever you try to implement a new RNG. The current approach of specifying the algorithm by string does not require the implementation of a class and is more developer friendly. However, I may be the only one who writes an extension that adds RNG in the first place, so the additional cost is well worth it. > (already pointed out by Jordi) new Random(new CustomRNG(/*custom args*/), $seed) is "illogical" (the passed $seed won't be used) but "possible" (even if your current implementation throws a ValueError when $seed is non-null); I thought about it carefully after that, and this is indeed a problem. It is difficult to find the problem easily by static analysis or other methods. > 64-bit problems I feel like I'm making too big a deal out of this. This kind of incompatibility happens some time in userland. In conclusion, I see no problem with the implicit truncation behavior. Indeed, the current implementation appears to have several problems. So, how about the following implementation? ```php interface RandomNumberGenerator { public function generate(): int; } final class Random { private RandomNumberGenerator $rng; public function __construct(?RandomNumberGenerator $rng =3D null) { $this->rng =3D $rng ?? new XorShift128Plus(random_int(PHP_INT_MIN, PHP_INT_MAX)); } public function nextInt(): int {} public function getInt(int $min, int $max): int {} public function getBytes(int $length): string {} public function shuffleArray(array $array): array {} public function shuffleString(string $string): string {} public function __serialize(): array {} public function __unserialize(array $data): void {} } class XorShift128PlusNumberGenerator implements RandomNumberGenerator { public function generate(): int {} public function __serialize(): array {} public function __unserialize(array $data): void {} } class MT19937NumberGenerator implements RandomNumberGenerator { public function generate(): int {} public function __serialize(): array {} public function __unserialize(array $data): void {} } class SecureNumberGenerator implements RandomNumberGenerator { public function generate(): int {} } ``` This is an approach similar to Nikita's `createDefault`. If the constructor has a null argument, it uses the default, XorShift128+, internally. Also, whether the Random class is serializable or clonable depends on the instance of RandomNumberGenerator being used. This means that when the Random class clone is called, the `$rng` member will be implicitly cloned. How about this? Regards, Go Kudo 2021=E5=B9=B46=E6=9C=8810=E6=97=A5(=E6=9C=A8) 1:11 Guilliam Xavier : > > On Wed, Jun 9, 2021 at 3:16 PM Go Kudo wrote: > >> Thanks Guilliam. >> >> > I'm not sure you really addressed >> https://externals.io/message/114561#114680 ? >> >> I thought I had solved this problem by implementing the >> `RandomNumberGenerator` interface. >> >> Accepting strings and objects as arguments is certainly complicated, but >> I thought it met the necessary requirements. >> From the aspect of static analysis, there seems to be no problem. >> >> Reverting to a full object-based approach would increase the cost of >> providing new RNGs from extensions. I think the string approach is super= ior >> in this respect. >> > > How much more "costly" would it be to define a class (implementing > RandomNumberGenerator) and use its (full) name as the algo identifier? > > >> Nikita's `createDefault()` approach is certainly good, but I think it is >> still difficult for beginners to understand. >> >> I also thought about it for a while after that, and I think that the >> current implementation is the most appropriate for now. What do you thin= k? >> > > I still agree with Nikita that there's a discrepancy between e.g. `new > Random(RANDOM_XXX, $seed)` and `new Random(new CustomRNG(/*custom > args*/))`, which also poses additional questions, e.g.: > > - (already pointed out by Jordi) `new Random(new CustomRNG(/*custom > args*/), $seed)` is "illogical" (the passed $seed won't be used) but > "possible" (even if your current implementation throws a ValueError when > $seed is non-null); > > - This opens the possibility of "leaking" the RNG "source" (even if no > `public function getRNG()`), e.g.: > > ``` > $rng =3D new CustomRNG(/*custom args*/); > $r1 =3D new Random($rng); > $r2 =3D new Random($rng); > var_dump($r1->nextInt() =3D=3D=3D $r2->nextInt()); // false (not true), I > suppose? > ``` > > or: > > ``` > $rng =3D new CustomRNG(/*custom args*/); > $r =3D new Random($rng); > var_dump($r->nextInt()); // 1st of sequence > $rng->generate(); > var_dump($r->nextInt()); // 3rd of sequence (not 2nd), I suppose? > ``` > > (possibly in less obvious ways), which may be considered bad or not (but > still a discrepancy vs extension-provided algos). > > Again, taking a class name and optional extra args (or an $options array, > like password_hash(), maybe even including 'seed' only for the algos that > need one) to construct, rather than an already constructed object, might = be > better? > > But that would also "split" the constructor args from the class > (increasing the risk of "mismatch"), and make using anonymous classes les= s > easy, and maybe we haven't considered all the uses cases (e.g. what about > `Random::getAlgoInfo(CustomRNG::class)`?)... So that might also be worse = :/ > > It would be great to have more insights! (if nobody else speaks up then > let's keep it as is of course) > > >> > Couldn't the Random class simply implement `public function __clone(): >> void` (that would internally do like `$this->rng =3D clone $this->rng;`)= ? >> >> Implicitly cloning in areas where the user cannot interfere may cause >> problems when using objects that cannot be cloned. >> However, this may be overthinking it. The reason is that a >> `RandomNumberGenerator` that cannot be cloned should be implemented as a= lgo >> in the first place. >> If there are no objections, I will change the implementation. >> > > Ah, true, I hadn't thought about non-clonable implementations... But > that's already the case for `__serialize()` and non-serializable > implementations, right? (But let's wait a bit for possible objections, > indeed) > > >> > Indeed, a decision has to be made. If you throw an exception, we >> wouldn't have the "issue" of different results on 32- vs 64-bit machines= , >> but XorShift128+ and Secure would be unusable on a 32-bit machine, right= ? >> >> I don't see any problem with the current implicit truncation behavior fo= r >> this. Even if a user switches to a 64-bit environment, compatibility can= be >> maintained by explicitly truncating the generated values. In addition, m= ost >> of the other methods only use 32bit internally. >> If you are concerned about this, you should probably be concerned about >> the incompatibility with MT_RAND_PHP. >> That problem can also be compensated for with an extension that adds alg= o. >> > > I thought you were "struggling with [this implicit truncation] behavior > when calling nextInt() in a 32-bit environment using a 64-bit RNG [...] > which means that the code loses compatibility with the result of running = on > a 64-bit machine"? And you asked if throwing an exception would be > preferable? > Anyway, I personally don't care about 32-bit (but other people may). > > >> Regards, >> Go Kudo >> > > Regards, > > -- > Guilliam Xavier > --000000000000f8259305c48f1ccf--