Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:108849 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 6330 invoked from network); 4 Mar 2020 19:52:47 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 4 Mar 2020 19:52:47 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id E2ADB18050A for ; Wed, 4 Mar 2020 10:12:14 -0800 (PST) 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-ASN: AS15169 209.85.128.0/17 X-Spam-Virus: No X-Envelope-From: Received: from mail-lj1-f171.google.com (mail-lj1-f171.google.com [209.85.208.171]) (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 ; Wed, 4 Mar 2020 10:12:14 -0800 (PST) Received: by mail-lj1-f171.google.com with SMTP id e18so3072838ljn.12 for ; Wed, 04 Mar 2020 10:12:14 -0800 (PST) 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 :cc; bh=YGjQM97LCbBqkunE+2rRV9GwupDIfWfF8WshGX88850=; b=eNQr9GzsFRf0qjq2SrLqbgLw9qtv2YOtV9S7XOWN+8pyPLfitOcw3QNTcJ5Xrh07wJ h/UN3l8lQ8lgLB9pI4WgoPcVXOYCjQoC6f3a9Z11Gou63ZjCxuWVhY1QLuajtxuxzA/e fCPDA2UCatdxOKHHjs++gy4bqRebXuaVXYcmFPavzRyWMggnj0emzBj9JnLdWU96EbkD Tt0A0Z3yNMMKYibKItoWH8bNuXyRdUAmogBcSE8F7LdHG8Cta5mjwfnQkVLllIzSZU8c Qi07efsJ23KjFUaZlWe2F1EGntBsYI7zq1ADYtIRAR9ZTkT5iJAATeRmuojvmGkSVXvS co6A== 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:cc; bh=YGjQM97LCbBqkunE+2rRV9GwupDIfWfF8WshGX88850=; b=hEhtE7pq1UjQNW4resin5ngJje3iEA6qRQtyy3zh84XSYdC0oK7QdDCWDgSUvPpZOL 9BGHlBYmkvYOv94gBJGsEKuWX1ibvKiUU68/zGTxqd2Jv0iLDQyCuwbgolMPO99aZ15z 1rfVwdwJVWwc1agsIiW7X9TDammW9fa6M4G8odx/1OYvJZLGtvsqPvfmaD8q+eE4HHvP yVSDKlWUINhEEdMxFjqV0Vrv1mSQ4bFtgvaCJLnnjvkeeC11cKuk8OhuTcQ6itqbjKDG mARsbME/AeDDZzgXaZegBNtW/WpHjWV+Gf61uRxNlvKVqf1q8oVZjzmuP1XYY2XG/aST +9bw== X-Gm-Message-State: ANhLgQ13+Za+/ZeNlpHvTKUUPkLRFGghHqttHLLv3ZIRYUOVbYDSg8g6 YxM1sgvNTyfTkFpk88hSomyUep0zHGQgPtbw8+M= X-Google-Smtp-Source: ADFU+vuD0JDz2nC9I/qJeB0DFSmdVq+Jwg+CXi090qpkACxuyOjIr9IVuWhf48Zh++o73+m4feYKBIqKU3xX8JOYorw= X-Received: by 2002:a2e:b554:: with SMTP id a20mr1469639ljn.34.1583345532094; Wed, 04 Mar 2020 10:12:12 -0800 (PST) MIME-Version: 1.0 References: In-Reply-To: Date: Wed, 4 Mar 2020 19:11:56 +0100 Message-ID: To: Sara Golemon Cc: PHP internals Content-Type: multipart/alternative; boundary="000000000000ff4c2505a00b5bc7" Subject: Re: [PHP-DEV] Make sorting stable From: nikita.ppv@gmail.com (Nikita Popov) --000000000000ff4c2505a00b5bc7 Content-Type: text/plain; charset="UTF-8" On Wed, Mar 4, 2020 at 6:17 PM Sara Golemon wrote: > On Wed, Mar 4, 2020 at 10:42 AM Nikita Popov wrote: > >> The only issue I ran into is that this change has a negative impact on >> code >> using illegal comparison callbacks like this: >> >> usort($array, function($a, $b) { >> return $a > $b; >> }); >> >> Let's define what "negative impact" means in this regard. Is it that one > still winds up with an essentially sorted array, but hitherto "stable > appering" output is now stable in a different way? Or is the result > actually just NOT sorted in a way that a reasonable user would consider > correct (e.g. 5 sorted before "3")? > "Negative impact" is PR speak for "completely broken" ;) Yes, it could sort 5 before 3. The comparison function becomes completely ill-defined and you get Garbage-In-Garbage-Out. If we are concerned about this (I'm not sure we should be, but I've at least seen people be interested about this peculiar behavior: https://stackoverflow.com/questions/59908195/how-come-usort-php-works-even-when-not-returning-integers), there's two things we can do: 1. As Tyson suggests, we can throw a warning if a boolean is returned from the comparison callback (probably with a check to only throw it once per sort), to make it obvious what the cause is. 2. We can fix this transparently by doing something like this internally: $result = $compare($a, $b); if ($result !== false) { return (int) $result; // Normal behavior } // Bad comparison function, try the reverse order as well return -$compare($b, $a); That is, we will recover the full three-way comparison result from the "greater than" result, by checking for both $a > $b and $b > $a. > If it's the former, then I'm generally disinclined to be concerned about > the breakage. We never made a promise about comparison equality > resolution, so moving to making a promise about it isn't violating anything. > > > >> This kind of incorrect code will break under the proposed implementation, >> because we will now compare by original position if the comparison >> function >> reports equality. Because the comparator reports equality inconsistently >> (it says that $a == $b, but $b != $a), the sort results are also >> inconsistent. >> >> I read this user-space comparator as saying that values are never equal. > Sometimes $a > $b and $b > $a are both true, which is terrible. But if > they never report equality, then position sorting should never come into > play. > That's not what this comparator does: The result gets interpreted as the usual -1/0/1 three-way comparison result, so "return $a > $b" will report true == 1 == greater-than if $a is greater than $b (this is correct!) and will report false == 0 == equals if $a equals $b (this is also correct) or if $a is smaller than $b (this is wrong). This ends up working, because the sort implementation happened to never make a distinction between 0 and -1 return value. Now it does, and thus results in an incorrect result. Nikita --000000000000ff4c2505a00b5bc7--