Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:126455 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 qa.php.net (Postfix) with ESMTPS id ABD3D1A00BC for ; Tue, 18 Feb 2025 19:29:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1739906807; bh=J7yoSuuyE5BLk9IGbWH9y0+eIKtx/LbvLln/68O1zeI=; h=Date:From:To:Cc:Subject:In-Reply-To:References:From; b=WCt0CJJ5XFbNjAYnfVdfHNU+UOqGv6zcqHdJpo0CItVUIGT32pMC8F+T1G34xSq+5 vw9T4Ibx5K2IQz61ZTmh7i9wcNdlT6J9AA+qpTiCq/YZbINrivsXeodtEbwWyvxB0s /5MgagVj7vaA4F2nmED+esYfOUCIY0qq0zaPOeVawoHLJZRqVHx8JeTww6UidfugK+ Nz46gpjuZqLAQvhfx6IZqAtPK6T8m+5F6suGH7hccWAQHZH7g3DjlK16G8gVyVUDbL jkwenLt7m5UD1lHE7H6I9JBdSkDLyg5odxWCAujK+qo80Z9K+cJoTEh54cub8kNMny QjjAICHCx8Kiw== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 069B018020B for ; Tue, 18 Feb 2025 19:26:46 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-0.2 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_20, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_MISSING, HTML_MESSAGE,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL, SPF_HELO_NONE,SPF_PASS,T_PDS_PRO_TLD autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from giraffe.ash.relay.mailchannels.net (giraffe.ash.relay.mailchannels.net [23.83.222.69]) (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 ; Tue, 18 Feb 2025 19:26:45 +0000 (UTC) X-Sender-Id: yszpovajlk|x-authuser|juris@glaive.pro Received: from relay.mailchannels.net (localhost [127.0.0.1]) by relay.mailchannels.net (Postfix) with ESMTP id 2D1761A61A7; Tue, 18 Feb 2025 19:29:25 +0000 (UTC) Received: from server42.areait.lv (trex-9.trex.outbound.svc.cluster.local [100.104.238.197]) (Authenticated sender: yszpovajlk) by relay.mailchannels.net (Postfix) with ESMTPA id 5707F1A615B; Tue, 18 Feb 2025 19:29:24 +0000 (UTC) ARC-Seal: i=1; s=arc-2022; d=mailchannels.net; t=1739906964; a=rsa-sha256; cv=none; b=oXLbLxoRRK61t4ijCO5AnjmoygzH2ZYcefKUXztxSA/oB+Yr+jG4rdKMLIukyEQqXs1iWF cT4YfYMeqx+L5cf8ATQI1UaJk0AK9A8VYt9LsvPrroQEmtcJLiV6CeqHsmx78Nr/soznZI 6zZE2TjdHXatVOmq4t7OlheLtKBohR2pSV2YxwI47JD2Oj7ztaHnCpCrmH/Zb3gO3Nm2sd Y5CR2IgiUGuMNI77w/vx5VFBAAp4aKFZ9Yq7gJf1iePQ0EbfkrvFm2BVws31ymxWzBuTTn b3pPhsBMEAPN/c7XhykDDBSEBidfmHLynoeALjuPMtiYxVWtAT1rFq/tjn8ZFA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=mailchannels.net; s=arc-2022; t=1739906964; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references:dkim-signature; bh=k4GysWJ/Ax4BBywQP3KHMLOr/oTltqE92UYicRejskk=; b=LJeCco36OKaaLrsmBSBsYMZUApjY5s3vJ4Dr/287VXlDj0mGdIXI4E2Acbr1EawweNtWBu f848yJl1dVEJTtVqr3xaLgvoFvXg0fU4/ZQwjedzho3nLlwGMQ0sb5z1YCjbpzqFvKyM5C Wdev1cPVyK+W4OUCmmL2aoV+xSPVhrb7/5gRo+RwMa5gYnM+Gg6nU3t7mBjIx2ONTTZX2e aNBzy1gDwMbztIGczv9fEmMheaeNqgEtOb7ucKvzopNCQ/auF6fvyns+5uCjcbPBE/6heP 0lGifTAAuSiErVf91ECWee3Im4umLqae25kYlyQoxA8qDtKGiEU317OXhW85mw== ARC-Authentication-Results: i=1; rspamd-78ddd997cc-w4bsg; auth=pass smtp.auth=yszpovajlk smtp.mailfrom=juris@glaive.pro X-Sender-Id: yszpovajlk|x-authuser|juris@glaive.pro X-MC-Relay: Neutral X-MailChannels-SenderId: yszpovajlk|x-authuser|juris@glaive.pro X-MailChannels-Auth-Id: yszpovajlk X-Towering-Callous: 3c312a50149a9967_1739906965027_1162631566 X-MC-Loop-Signature: 1739906965027:2460969386 X-MC-Ingress-Time: 1739906965026 Received: from server42.areait.lv (server42.areait.lv [212.7.207.88]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384) by 100.104.238.197 (trex/7.0.2); Tue, 18 Feb 2025 19:29:25 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=glaive.pro; s=default; h=Content-Type:Message-ID:References:In-Reply-To:Subject:Cc:To: From:Date:MIME-Version:Sender:Reply-To:Content-Transfer-Encoding:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=k4GysWJ/Ax4BBywQP3KHMLOr/oTltqE92UYicRejskk=; b=VK5PYaTwL8thpFhXWFSVu+ImCY N9mf4iZtN4JyijgWEEhhHLiqOfnG+syp9VtT6m5pAA0mVIiMtASxMuYU/uMEVLQgF7YKJcmTStFHN aSyE2nr9tz82w0Sqm7JMb6Brc14vq67SsxPsYmIaTO4V/s72rGUvto/dM4mgaTcQuqIxyE+qgcec4 S6eMTBR1c9ms3CeoExQpOG/8YD6HYC4g9CPhyz1irWEtQHC9rJ4vg9UeyjWgY1VjNXr5GzDIwY4Bu K9DnLQoEQAKWlMBCwOm094DCIJVbL/20tIWQwx3CVFqRjzgIi49xCR6cmBeuqaDbEhMZeabMCmSE3 nV5dmfpQ==; Received: from [::1] (port=45044 helo=glaive.pro) by server42.areait.lv with esmtpa (Exim 4.96.2) (envelope-from ) id 1tkTHU-00AVRe-2D; Tue, 18 Feb 2025 21:29:22 +0200 Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 Date: Tue, 18 Feb 2025 21:29:20 +0200 To: Rob Landers Cc: internals@lists.php.net Subject: Re: [PHP-DEV] Fully overridable factory methods In-Reply-To: References: <04b901db8225$788d5250$69a7f6f0$@glaive.pro> User-Agent: Roundcube Webmail/1.4.8 Message-ID: <2d86d841d82344bd5aa48053771e6294@glaive.pro> X-Sender: juris@glaive.pro Organization: SIA "Glaive.pro" Content-Type: multipart/alternative; boundary="=_fbb740e3c0832487af07d092400103c6" X-AuthUser: juris@glaive.pro From: juris@glaive.pro (Juris Evertovskis) --=_fbb740e3c0832487af07d092400103c6 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII; format=flowed On 2025-02-18 19:31, Rob Landers wrote: > On Tue, Feb 18, 2025, at 17:52, Juris Evertovskis wrote: > >> Hi, >> >> A recent discussion brought up the need for multiple constructors for >> the same class. >> >> https://externals.io/message/126428 >> >> The need was mostly answered by suggestions to use factory methods. >> >> However on an earlier discussion it was discussed how it's fine and >> even useful for constructor methods to violate the LSP. >> >> https://externals.io/message/121789 >> >> I've felt a similar need on some projects. To have a named factory >> method that would have an overridable signature. >> >> Maybe a new keyword like `factory`that would make the method only >> callable statically? I'm thinking of something like >> >> class Triangle extends Polygon >> >> { >> >> public factory method fromPoints(Point $p1, Point $p2, Point $p3): >> static >> { >> >> // ... >> >> } >> >> public factory method wrap(static|string $triangle): static >> { >> >> return $triangle instanceof static ? $triangle : >> static::fromWkt($triangle); >> >> } >> >> } >> >> Sure, I'm not saying this API is currently impossible. I can do the >> more narrow checks within the methods and throw from there. But >> sometimes it's useful to precisely describe the acceptable arguments >> in the method signature. >> >> What do you think? Would such a feature be useless and/or harmful? >> >> BR, >> >> Juris > > Hey Juris: > > You may be interested in a super-draft RFC that I'll propose in the > next few days... (just fixing a couple of edge cases in the > implementation) it allows for nested classes and can support what you > are thinking. I will add this use case to the RFC. > > Adapting your example: > > class Triangle extends Polygon { > public final class fromPoints extends Triangle { > public function __construct(Point $p1, Point $p2, Point $p3) {} > } > > public final class wrap extends Triangle { > public function __construct(Triangle $triangle) {} > } > } > > $triange = new Triangle::fromPoints(...$points); > > I don't know if this is what you are thinking of, but it basically > allows the expression you are suggesting. If we were to implement your > idea though, then nested classes would probably be impossible (and > vice-versa). > > -- Rob Hi Rob, I'm a bit confused about the use of `final` in your example. Would it allow defining Polygon::fromPoints such that it accepts variable number of arguments and Triangle::fromPoints such that it only accepts exactly 3 args? Or having a hierarchy like `Square extends Rectangle extends Polygon` while having a wrap with the following covariant behaviour? - Polygon::wrap(Polygon $poly) -- accepts any Polygons - Rectangle::wrap(Rectangle $poly) -- accepts Rectangles and Squares, but not other Polygons - Square::wrap(Square $poly) -- only accepts Square arguments Juris --=_fbb740e3c0832487af07d092400103c6 Content-Transfer-Encoding: quoted-printable Content-Type: text/html; charset=UTF-8

On 2025-02-18 19:31, Rob Landers wrote:

 
 
On Tue, Feb 18, 2025, at 17:52, Juris Evertovskis wrote:

Hi,

 

A recent discussion brought up the need for mul= tiple constructors for the same class.

https://externals.io/message= /126428

 

The need was mostly answered by suggestions to = use factory methods.

However on an earlier discussion it was discuss= ed how it's fine and even useful for constructor methods to violate the LSP= =2E

https://externals.io/message= /121789

 

I've felt a similar need on some projects. To h= ave a named factory method that would have an overridable signature.

 

Maybe a new keyword like `factory`that would ma= ke the method only callable statically? I'm thinking of something like

 

    class Triangle extends Polyg= on

    {

 

        public factory method fromP= oints(Point $p1, Point $p2, Point $p3): static
        {


        = ;    // ...

        }

 

 

        public factory method wrap(= static|string $triangle): static
        {


        = ;    return $triangle instanceof static ? $triangle : static= ::fromWkt($triangle);

        }

    }

 

Sure, I'm not saying this API is currently impo= ssible. I can do the more narrow checks within the methods and throw from t= here. But sometimes it's useful to precisely describe the acceptable argume= nts in the method signature.

 

What do you think? Would such a feature be usel= ess and/or harmful?

 

BR,

Juris

 
Hey Juris:
 
You may be interested in a super-draft RFC that I'll propose in the ne= xt few days... (just fixing a couple of edge cases in the implementation) i= t allows for nested classes and can support what you are thinking. I will a= dd this use case to the RFC.
 
Adapting your example:
 
class Triangle extends Polygon {
  public final class fromPoints extends Triangle {
    public function __construct(Point $p1, Point $p2, Point = $p3) {}
  }
 
  public final class wrap extends Triangle {
    public function __construct(Triangle $triangle) {}
  }
}
 
$triange =3D new Triangle::fromPoints(...$points);
 
I don't know if this is what you are thinking of, but it basically all= ows the expression you are suggesting. If we were to implement your idea th= ough, then nested classes would probably be impossible (and vice-versa).
 
— Rob

Hi Rob,

I'm a bit confused about the use of `final` in your example.

Would it allow defining Polygon::fromPoints such that it accepts variabl= e number of arguments and Triangle::fromPoints such that it only accepts ex= actly 3 args?

Or having a hierarchy like `Square extends Rectangle extends Polygon` wh= ile having a wrap with the following covariant behaviour?
- Polygon::w= rap(Polygon $poly) -- accepts any Polygons
- Rectangle::wrap(Rectangle= $poly) -- accepts Rectangles and Squares, but not other Polygons
- Sq= uare::wrap(Square $poly) -- only accepts Square arguments

Juris

--=_fbb740e3c0832487af07d092400103c6--