Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:128543 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by lists.php.net (Postfix) with ESMTPS id A3FB81A00BC for ; Sun, 24 Aug 2025 14:42:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1756046432; bh=YQa4/ELgwqKcVxRtOUk+sagBMEp4Cmhs8K4ZOvGSmY0=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=O+9SI7CUZ/lBSuwNlxwqpiFw3S5LzGkfR2nZJK67o/7dev56tFC4tyBMgUJm/dWx4 2YXLBFno8xvgDO2zwg6hCNGwu0OKH3Gr9ndwqD142kJctSWSOciEI/e/vgY5sslKNj YTpaML8oxrtP9YPn0bLHJ23jwxrpSGRQfRoVjiNerza0bLPd3VKKLQy+Gxh9PP3SQu TVBYGXPiKqncGUlEiL9IgaCG1miT3f+hGdrDVZw+XqkvshY4//s6yxhK523N0qLVlH Hk1aiXYrDMBPRiSgvS1iukrNcG2Dmg3+ZGR+/R3BgcpM0tix+GOGjhXo7sOC6zyU0m OoqOlsYHnYaJA== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 08840180059 for ; Sun, 24 Aug 2025 14:40:31 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) 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,DMARC_PASS,FREEMAIL_FROM, HTML_MESSAGE,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE, SPF_PASS autolearn=no autolearn_force=no version=4.0.1 X-Spam-Virus: No X-Envelope-From: Received: from mail-pg1-f176.google.com (mail-pg1-f176.google.com [209.85.215.176]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Sun, 24 Aug 2025 14:40:30 +0000 (UTC) Received: by mail-pg1-f176.google.com with SMTP id 41be03b00d2f7-b47175d02dcso2953964a12.3 for ; Sun, 24 Aug 2025 07:42:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1756046523; x=1756651323; darn=lists.php.net; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=dgVoXTOmsi3omV/20QXGqdmOQfR5CNAXQ1gFyDJky3A=; b=JoeZ/63K3VmorkvuD/cG1TyQ/2V2OfQVpT6np3SKBuzT5iTI6IUDsTsTGwc2GCLf6I GEFrxnYjTfgqsCYuZbdWnWvtiqq1I1f8fl5SqE+a48FPz+WERBi1ph7c43tzSqy2k9kw COeRQPd2syGMCwZVrMWpYkNqrDhYCrfs9L6iPT3NNi5cYGkayHb/XOKp2j2uwIPFR7/K Kii6duJs1onrwqp65ZnKhlpriyPVl/juPVpmfgkmA13QeSjcePzcGajic7ZH9THqJ7xJ 2rkJfewC21kRMPUpOHjjevQSR4UK4sg3BU/Fw5zKqxn1WzrVaSm2Xq2BO32Kingl7qV2 NWCw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1756046523; x=1756651323; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=dgVoXTOmsi3omV/20QXGqdmOQfR5CNAXQ1gFyDJky3A=; b=t6mYRBCiWaA6qyKFxPwORyY/e2M7sCB2/ONPFui4cqn5mEagrH4jw7f4YUWU6kmeHE /KyJ64pPSowgYviWc3VvpqWS8cG+YRhu1/+UwUYJsjJ5P6d5yuvB86I3Pw+vjocBQy/8 iLO8vHM68uznfDqCZW2D9dCyi3pQCdgnucaIjXTPhJQdGxNAaieGSHRGaFcU7zMdflxM 8yfhuu5c8r66j8W9qHkDtBicF3m01m/fiw8EVKRWRdpsZk/MJUdi02rs4FgrRWJE6Ic6 O0i5Qh2Kw/d1YdzZBqCBiKr6+LOqOoBS1Ewf2I6TPudbUL3SJBnorN/D0+4aCmx2Nw56 zEgQ== X-Gm-Message-State: AOJu0YxOH9kmOUMlESiwWc+kWmUvBE80ph9YZ8R7I05+O+ciPgVQ7Jrx JYwB4iAGEWH/tqwZd30MiZU4kR3dfP/TPC1IeTcTUnH3BTaFNE8ANChT8RSf+2QPMqceiGjAQXu TInQFPDHS+e5zNDg6CzPH0NmHsBX7s732a44Wxhc= X-Gm-Gg: ASbGncvab2nq2XUjAZ4UO2G94tXCDjs4epmCecT/7pqEhZ+uecfVhDwPVIiajOWDQC5 LQA4yi3PyKHac0pFwdysjuQZooTULOGIp+l9ZcwAOrq1RO8tv2iCBqvbTpevOglggv/NEx+/iRy r/3kVke7hTBHhUBuaLrgJcPLa42VjCaOYhnS6LRmVMM1xYA7WGDWEQO6+/eGWutWy1dgEJ/l/UA fks+dr/nxma9XDQPGUb X-Google-Smtp-Source: AGHT+IHcuy7Rk622yUJJGeXgdk3YtVA/8RPR7FZZ6mTsm8mxoneGlD9AzlSHbbxHgvJGxSyytIv322Sk1SHCuWFSPUY= X-Received: by 2002:a17:903:1a24:b0:246:4d93:78a8 with SMTP id d9443c01a7336-2464d937c89mr116301515ad.6.1756046522704; Sun, 24 Aug 2025 07:42:02 -0700 (PDT) Precedence: list list-help: list-post: List-Id: x-ms-reactions: disallow MIME-Version: 1.0 References: <0027ab13-89fb-40b4-991b-2f88a35c2f31@gmx.de> <272c241b-3145-4069-8a6a-9ea877f936c0@app.fastmail.com> In-Reply-To: Date: Sun, 24 Aug 2025 16:41:52 +0200 X-Gm-Features: Ac12FXxR0Fo-ebgryS9j3BBUsmyKlMgBUe1ONgZiykHr4FkWEmQh3bLK6mYQpsM Message-ID: Subject: Re: [PHP-DEV] [RFC] Add clamp function To: Rob Landers Cc: internals@lists.php.net Content-Type: multipart/alternative; boundary="00000000000031e897063d1d713d" From: kylekatarnls@gmail.com (Kyle Katarn) --00000000000031e897063d1d713d Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable 2025-08-23 at 12:06, Rob Landers wrote: > > On Fri, Aug 22, 2025, at 22:09, Larry Garfield wrote: > > On Fri, Aug 22, 2025, at 12:45 PM, Kyle Katarn wrote: > > > About "What determines comparability", it follows the usual rules of > > PHP: https://www.php.net/manual/en/language.operators.comparison.php > > > > So it's equivalent to ($value < $min) ? $min : (($value > $max) ? $max > > : $value) and also equivalent to min($max, max($min, $value)) > > > > About clamp(new Point(1, 2), new Point(0, 0), new Point(5, 5)); > > > > If Point is a comparable value (simple DTO for example), it should > > return $value, like when doing ($value < $min) ? $min : (($value > > > $max) ? $max : $value) we could add a test for such case, but I think > > that for consistency, whatever currently works in min() should work in > > clamp() > > > > Following the link of the implementation, there is also a link to the > > documentation where I already explained the comparison rules following > > the example of what was done in the documentation for min() and max(): > > https://github.com/php/doc-en/pull/4814 > > Please make sure the above is captured in the RFC. > > Though apparently what PHP currently does with Point comparisons in > min/max is... weird. I don't even know what the logic here is. :) > > https://3v4l.org/pTmiV > > (No need to change it in this RFC, just note explicitly that the expected > behavior is identical to that min(max()) construct, regardless of type.) > > --Larry Garfield > > > It only compares the first property, and if there is a conflict, it moves > on to the next property. That is why some of us have been advocating for > operator overrides: because this default isn=E2=80=99t always appropriate= , as your > Point example illustrates. In some cases, you would want to compare > magnitude or something else entirely, not just the x value. > > What is even trickier is that this process completely ignores computed > hooks. So, if you add a hook as the first property (for example, returnin= g > the magnitude), it is simply ignored. As a weird side note: if you cast t= he > object to an array, the computed hook disappears, but if you use > json_encode(), the computed value is included. > > To complicate things further, the current behaviour for objects is > actually =E2=80=9Cundefined=E2=80=9D and it isn=E2=80=99t documented. The= re are examples that show > how objects are compared, but they don=E2=80=99t explicitly mention that = the object > is being cast to an array (see the above paragraph on why that matters). > Because this relies on implementation details rather than documented > behaviour, it could change between PHP versions without an RFC. That make= s > relying on it a bit risky. > > Adding operator overrides would help by making this behaviour explicit an= d > consistent across versions, or just defining it in general. But whenever > someone tries to define this more clearly (as I started to do with > Records), it tends to run into resistance on this list for reasons I=E2= =80=99ve > never quite understood. > > =E2=80=94 Rob > I would not be against operator overrides, though it starts becoming quite complex when dealing with comparing 2 objects of different classes. Anyway I will add a note on the RFC about objects to warn about unexpected behavior, but this is probably out of scope, the same concerns apply to min() and max() and that's why I added the same warning in the documentation: "Be careful when passing arguments of different types because clamp can produce unpredictable results." Adding a specific note about objects in the documentation could make sense. Then it would probably be nice if it were also added to min() and max(). --00000000000031e897063d1d713d Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
2025-08-23 at 12:06, Rob Landers <rob@= bottled.codes> wrote:

<= div>On Fri, Aug 22, 2025, at 22:09, Larry Garfield wrote:
On Fri, Aug 22, 2025, at= 12:45 PM, Kyle Katarn wrote:

> About "Wha= t determines comparability", it follows the usual rules of=C2=A0
=
>
> So it's e= quivalent to ($value < $min) ? $min : (($value > $max) ? $max=C2=A0
> : $value) and also equivalent to min($max, max($min, $value))=
>
> About clamp(new Point(1, 2), new Point(0, 0)= , new Point(5, 5));
>
> If Point is a comparable = value (simple DTO for example), it should=C2=A0
> return $valu= e, like when doing ($value < $min) ? $min : (($value >=C2=A0
> $max) ? $max : $value) we could add a test for such case, but I thin= k=C2=A0
> that for consistency, whatever currently works in mi= n() should work in=C2=A0
> clamp()
>
&g= t; Following the link of the implementation, there is also a link to the=C2= =A0
> documentation where I already explained the comparison r= ules following=C2=A0
> the example of what was done in the doc= umentation for min() and max():=C2=A0

Please make sure the above i= s captured in the RFC.

Though apparently what PHP = currently does with Point comparisons in min/max is... weird.=C2=A0 I don&#= 39;t even know what the logic here is. :)

https://3v4l.org/pTmiV

(No need to change it in this RFC, just note explici= tly that the expected behavior is identical to that min(max()) construct, r= egardless of type.)

--Larry Garfield

It only compares the first property= , and if there is a conflict, it moves on to the next property. That is why= some of us have been advocating for operator overrides: because this defau= lt isn=E2=80=99t always appropriate, as your Point example illustrates. In = some cases, you would want to compare magnitude or something else entirely,= not just the x value.

What is even trickier is th= at this process completely ignores computed hooks. So, if you add a hook as= the first property (for example, returning the magnitude), it is simply ig= nored. As a weird side note: if you cast the object to an array, the comput= ed hook disappears, but if you use json_encode()<= /code>, the computed value is included.

To complic= ate things further, the current behaviour for objects is actually =E2=80=9C= undefined=E2=80=9D and it isn=E2=80=99t documented. There are examples that= show how objects are compared, but they don=E2=80=99t explicitly mention t= hat the object is being cast to an array (see the above paragraph on why th= at matters). Because this relies on implementation details rather than docu= mented behaviour, it could change between PHP versions without an RFC. That= makes relying on it a bit risky.

Adding operator = overrides would help by making this behaviour explicit and consistent acros= s versions, or just defining it in general. But whenever someone tries to d= efine this more clearly (as I started to do with Records), it tends to run = into resistance on this list for reasons I=E2=80=99ve never quite understoo= d.

=E2=80=94 Rob
=
I would not be against operator overrides, though it starts becomi= ng quite complex when dealing with comparing 2 objects of different classes= . Anyway I will add a note on the RFC about objects to warn about unexpecte= d behavior, but this is probably out of scope, the same concerns apply to m= in() and max() and that's why I added the same warning in the documenta= tion: "Be careful when passing arguments of different types because cl= amp can produce unpredictable results." Adding a specific note about o= bjects in the documentation could make sense. Then it would probably be nic= e if it were also added to min() and max().
--00000000000031e897063d1d713d--