Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:107179 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 34866 invoked from network); 16 Sep 2019 22:09:18 -0000 Received: from unknown (HELO php-smtp3.php.net) (208.43.231.12) by pb1.pair.com with SMTP; 16 Sep 2019 22:09:18 -0000 Received: from php-smtp3.php.net (localhost [127.0.0.1]) by php-smtp3.php.net (Postfix) with ESMTP id 1A2B62C2CA1 for ; Mon, 16 Sep 2019 12:46:16 -0700 (PDT) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on php-smtp3.php.net X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,HTML_MESSAGE,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS3215 2.6.0.0/16 X-Spam-Virus: No Received: from mail-yb1-xb32.google.com (mail-yb1-xb32.google.com [IPv6:2607:f8b0:4864:20::b32]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by php-smtp3.php.net (Postfix) with ESMTPS for ; Mon, 16 Sep 2019 12:46:15 -0700 (PDT) Received: by mail-yb1-xb32.google.com with SMTP id m9so497217ybm.3 for ; Mon, 16 Sep 2019 12:46:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=newclarity-net.20150623.gappssmtp.com; s=20150623; h=from:message-id:mime-version:subject:date:in-reply-to:cc:to :references; bh=Wz+32DnMJd8n/QE4bR5h0BzuhdFoPsAyPTR1HhSxFvo=; b=j3u6XNvBGYu28zHIVLC1/Ldc+tnL+zaDEwHcNXoSIS1w+Sa3DQhNiI3xiDYZ5y2fGh p7xBTNyqv1wOBAA+Zy9aorrKajnNixQWJ9Dm6ubd9sneIzcZLsX+AEw+mo72Au8DNogC I95R2n2NGy4eCy8N1oKs51Z+F+rXQHsZeDEruKx9/ki1vYiFLidEd99/sm7WjEkdIbKG NQU/+a9SGBX6Fz9xI1uk3hR/dyOxTMPlBL9asuRdpiwaSRqFSKA1I7PZAWnEJ68Aa213 5VYXJEWnbHN+hgYc/pMhZUj2bL4bALIu83bYSg6WuuA58rAom9gq063+pFv5Tjj+MUkF ejBQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:message-id:mime-version:subject:date :in-reply-to:cc:to:references; bh=Wz+32DnMJd8n/QE4bR5h0BzuhdFoPsAyPTR1HhSxFvo=; b=VtOazTcWO0g4MD8FZNxjmILIh1FsW7eCgMFPN27s/CnB5DZ2Uj7dAgLmnZDgaNDKdP OlncQJR/e78BTjGZs/4PhT01usguvsyyZ3NJ2apbiKRtlmDru3mPKmNtSyAsQpmR/+/u uc5JIrHiXmkCoBOoDps2nHcRzFJU3BFBibVKZAoiBaGwn6sBQ9GTjTQxJFW8RzenmtoO gz3OmGYY2rQCI5SZsiDGQD9fWgDro+uTYn2Xj6zPPmmtCzGYJvQoEdb/53EMp3u27vn0 NYXMUpYQFui/k2Gyd2lY5JW7rEV1thlAaL6kKRi2tKqDqTeXIFSLCUhQnMGbUY6fKaJG /TkA== X-Gm-Message-State: APjAAAUnkhU8X0ZafuBH+MfjYpL31ETdB8pNYGhfjk9M5k6DuPVY9ROL 98QgLFb3kY+x+pa5iA5Lgmx65Q== X-Google-Smtp-Source: APXvYqzwW2ZEO8t3T8Isg173zsHnROwI7v+QgE36B/VQsmnsmpwDSYZaT1guPkQUyckS6lkYP/yB+Q== X-Received: by 2002:a25:ab42:: with SMTP id u60mr791815ybi.190.1568663175190; Mon, 16 Sep 2019 12:46:15 -0700 (PDT) Received: from ?IPv6:2601:c0:c67f:e34e:f4e5:82c9:8e75:5377? ([2601:c0:c67f:e34e:f4e5:82c9:8e75:5377]) by smtp.gmail.com with ESMTPSA id u69sm9375365ywu.93.2019.09.16.12.46.14 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 16 Sep 2019 12:46:14 -0700 (PDT) Message-ID: <6EE5ADE4-68B7-4EC0-A16C-E7FE8DA5BCF5@newclarity.net> Content-Type: multipart/alternative; boundary="Apple-Mail=_A556E506-D3B3-492D-A4D7-350173555949" Mime-Version: 1.0 (Mac OS X Mail 12.4 \(3445.104.11\)) Date: Mon, 16 Sep 2019 15:46:13 -0400 In-Reply-To: <6743794A-82B7-4E1E-8E74-0546B7569728@newclarity.net> Cc: PHP Internals List To: Rowan Tommins References: <472D3E22-18D9-4C25-8961-C1DDEF482981@newclarity.net> <58673C6E-6632-42D9-BCBF-0294A62EB001@newclarity.net> <0ED2C80B-7A61-4F27-BA3D-945A288F52B6@newclarity.net> <6743794A-82B7-4E1E-8E74-0546B7569728@newclarity.net> X-Mailer: Apple Mail (2.3445.104.11) X-Envelope-From: Subject: Re: [PHP-DEV] Features related to Object Initializers From: mike@newclarity.net (Mike Schinkel) --Apple-Mail=_A556E506-D3B3-492D-A4D7-350173555949 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=utf-8 2 of 2 > On Sep 16, 2019, at 6:22 AM, Rowan Tommins = wrote: >=20 > I don't particularly see them as a "group". If I write foo($a, 42), I = don't > think of $a and 42 being bound together in any way; each is passed as = a > value to one variable in the function. So that's my answer to "why = not"; > they just don't feel like related ideas to me. I think I see why we are seeing these as different. I have been thinking of named parameters using braces to enclose them = like I have seen some people on the list to discuss. So looking at it = like this: foo($a, { $mol =3D> 42 }); $a is the normal *required* parameter and `$mol` is the *optional* named = parameter. Using this syntax I envision the 2nd parameter could be = satisfied with _either_ of the following function declarations, = depending on use-case and developer preference: public function foo( $a, int $mol ) { ... } public function foo( $a, object $args=3D{}) { ... } I personally would (almost?) always use the latter syntax; this is the = use-case for which object initializers would be a killer feature (for = me?). This approach can almost guarantee that function signatures = never need break in the future, and when we use a declared named class = with type hints instead of `object` we cab guarantee that optional = parameters can be type checked when called. This is why simply improving the object constructor does not really = address the use-case. Ideally a developer would be able to start out = with a stdClass initializer unless or until the need to use a declared = named class became obvious and clear. (And I know stdClass properties = would not be type-checked. But later when we move to a declared named = class we would not have to refactor calling code like we do with = arrays.) BTW, this is how I code the same use-case today, because ensuring my = function signatures don't need to change is one of my highest = programming priorities, even more than type checking (but I want object = initializers so I can eventually get type checking): public function foo( $a, array $args=3D[]) {=20 $defaults =3D array( 'mol' =3D> null, ); $args =3D array_merge($defaults,$args); ... } foo($a, array( 'mol' =3D> 42 )); > Even if they use the same syntax, those are not the same piece of > functionality, or equivalent. The first two are certainly related, but = the > last one I just don't see the connection. See my explanation above. > This feels like a straw man to me: "if we don't unify named parameters = with > object initializers, everyone will use arrays".=20 My evident lack of clarity had you conflating two different arguments. = Here are the arguments delineated: Argument #1: If we can add one new concept with a single syntax that = can address many different use-cases it will probably be better than = adding multiple new concepts each with their own new syntax. Argument #2: If we don't offer a simplified object initializer many of = the less-zealous programmers will just use arrays. IMO perfection-minded programmers are the majority; they are those who = just want to get their job done and not have to think about it too much = because they would rather think about family, friends, sports, and = extra-curricular activities. So these people take the easy road, not = necessarily the best road. I work with several of them at a client right = now.=20 Few developers are as zealous as people on this list. Remember, this = list is self-selecting, so it attracts those who are most passionate = about developing in PHP to exacting levels of perfection. > I would definitely be happy > seeing objects being passed around more; but this syntax isn't the = only way > to encourage that, and I think its costs outweigh its gains. What are the costs? I don't see any costs? But I do see costs to segregate them, i.e. two different = syntaxes/concepts for people to learn rather than one. BTW, I am actually not super passionate about this one issues, but I do = want to make sure we are comparing apples to apples. > Consider this code: >=20 > class Customer { > public string $name; > public ?int $age=3Dnull; > } > function doSomething(?Customer $customer=3Dnull, ?string $name=3Dnull) = { > // ... > } > doSomething({name =3D> 'John Smith'}); > Is this equivalent to: > doSomething(new Customer{name=3D'John Smith'}, null); > or: > doSomething(null, 'John Smith'); Ok, I see why you are confused.=20 I was making the assumption =E2=80=94 which I should have stated = explicitly =E2=80=94 that the object that can collect named parameters = would always have to be the last parameter =E2=80=94 no different than = variadics =E2=80=94 which means the answer to your question would = unambiguously be a parameter error. (It also means either named = parameters or variadics but not both.) If instead you had this: function doSomething(?string $name=3Dnull, ?Customer $customer=3Dnull) { // ... } Then this: doSomething({name =3D> 'John Smith'}); Would unambiguously be:=20 doSomething(null, new Customer{name=3D'John Smith'}); And this: doSomething('John Smith'); Would unambiguously be:=20 doSomething('John Smith',null); > If I change the public properties of the Customer class, does that = change > the result?=20 Generally no, but yes, in one case it would throw an error. In what I am proposing/envisioning properties in the case would only = apply to the last passed object. So this would error if you remove the = `name` property: doSomething({name =3D> 'John Smith'}); But then if I was calling a function using a hypothetical named = parameter and we renamed that parameter in the function declaration we = would get an error too.=20 > If the parameter was mandatory, would that be different?=20 No.=20 > If it wasn't type-hinted, would I get an anonymous object?=20 Yes, definitely. > It's all too ambiguous and context-dependent. No, not according to the requirements I outlined above. However, one thing we could do to make it even clearer is to require all = named parameters to also be grouped in the declaration using braces, = e.g.: function doSomething(?string $name=3Dnull, { ?string $email, ?string = $phone, ?string address } ) { // ... } function doSomething(?string $name=3Dnull, { ?Customer $customer=3Dnull = } ) { // ... } > Compare that to separate syntax for the separate features: >=20 > doSomething(new class extends Customer { string $name=3D'John Smith'; = }); > doSomething(new Customer{ name=3D'John Smith' }); > doSomething(name =3D> 'John Smith'); >=20 > All are nice and short, but there's no ambiguity; I don't need to read = the > rest of the code to understand what each line is doing. Given the requirement to have the object as the last parameter, all your = examples except the last would work, assuming you used these = declarations (note I am assuming the braces are required in the = declaration for clarity): function doSomething({ ?Customer $customer=3Dnull }) { // ... } However, if you changed the last call to the following then they would = all work, having the same effect as your first two examples: doSomething( { name =3D> 'John Smith' } ); > There's definitely some interesting ideas here, but they're not all = part > of one feature, How the features parse out =E2=80=94 as one or as many =E2=80=94 are all = the same to me, assuming the resultant capabilities can still address = all the same use-cases. -Mike --Apple-Mail=_A556E506-D3B3-492D-A4D7-350173555949--