Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:108008 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 46400 invoked from network); 6 Jan 2020 20:02:57 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 6 Jan 2020 20:02:57 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 71DB9180564 for ; Mon, 6 Jan 2020 10:07:54 -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=0.1 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_LOW,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL, SPF_HELO_PASS,SPF_NONE autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS11403 66.111.4.0/24 X-Spam-Virus: No X-Envelope-From: Received: from out1-smtp.messagingengine.com (out1-smtp.messagingengine.com [66.111.4.25]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Mon, 6 Jan 2020 10:07:53 -0800 (PST) Received: from compute7.internal (compute7.nyi.internal [10.202.2.47]) by mailout.nyi.internal (Postfix) with ESMTP id 3DC0B21AB4 for ; Mon, 6 Jan 2020 13:07:53 -0500 (EST) Received: from imap26 ([10.202.2.76]) by compute7.internal (MEProxy); Mon, 06 Jan 2020 13:07:53 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm1; bh=h9INlr nRXLDoVuNrdqMYCAv2tO5YrXEf8OTX8JErWtU=; b=Mg/jWN9lKnCk/uN+CvqaTo gpSbfoWhUPG1qoTi2vfFGUG0+rHiUMunPakUmlNkCzAftLHfUxkA5NMCApYUVvTm CO5aBq2EKe6kVyUSgiBqMprsVN6B4zNbWZSyiYtDi7PmWGqXkpmYaFoEORXof+bF 1WFS9eZPWpZRvmzz0DWZSOzydnPD0dwOQggp+9CPB0QUl5bInTpqeesSuQ8H8L0D BEJMGcM637bYrOH/T5h8Z2mJY76Oxz16j0PZZyxaJkitPz6uUfupFnIvlQtNR8uP K64h9VWNzvl2jEXwpUDmRa4xtopOgzSXyWdnyk5pxDZQ+J7dMl5UlvZeTdTVq10g == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedufedrvdehtddguddutdcutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfgh necuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd enucfjughrpefofgggkfgjfhffhffvufgtsehttdertderredtnecuhfhrohhmpedfnfgr rhhrhicuifgrrhhfihgvlhgufdcuoehlrghrrhihsehgrghrfhhivghlughtvggthhdrtg homheqnecuffhomhgrihhnpeifihhkihhpvgguihgrrdhorhhgpdgvgigrmhhplhgvrdgt ohhmnecurfgrrhgrmhepmhgrihhlfhhrohhmpehlrghrrhihsehgrghrfhhivghlughtvg gthhdrtghomhenucevlhhushhtvghrufhiiigvpedt X-ME-Proxy: Received: by mailuser.nyi.internal (Postfix, from userid 501) id E486B14200A2; Mon, 6 Jan 2020 13:07:52 -0500 (EST) X-Mailer: MessagingEngine.com Webmail Interface User-Agent: Cyrus-JMAP/3.1.7-731-g1812a7f-fmstable-20200106v2 Mime-Version: 1.0 Message-ID: In-Reply-To: References: <5e0d723f.1c69fb81.e2ae8.24e2SMTPIN_ADDED_MISSING@mx.google.com> <74F2DBFC-E63C-428C-A37F-2D0CEE15AD0F@newclarity.net> Date: Mon, 06 Jan 2020 12:07:32 -0600 To: "php internals" Content-Type: text/plain Subject: Re: [PHP-DEV] Initializing constants once, with code? From: larry@garfieldtech.com ("Larry Garfield") Lots to reply to here, so I'm going to munge it into a single response. Mike Schinkel said: > Let's consider the fact that is PHP had never had the define() and instead implemented the `const` keyword from the start, and only allowed compile time values. If PHP had done that, you would be arguing from a status quo bias the same thing about making that dynamic. And it currently is dynamic which IMO invalidates your argument that constants must be defined at compile time. Do not put words in my mouth and presume to know what I would think in some hypothetical situation. That is rude and inappropriate. You also repeatedly are accusing Rowan and I of "status quo bias" as though it were a bad thing. Let me be clear: I entirely agree with Zeev that in a language used by millions of people a "status quo bias" is a *very good thing*. The potential benefit of any improvement needs to substantially outweight any downsides, and the burden of proof is on the person/people proposing a change. There's a long list of things I'd like to see added to the language myself, but I'm well aware that the burden of proof is always on the proposer (in this case, you), as it should be. Also Mike: >> Many people would say the kind of global state you're talking about is an anti-pattern. > Well, Larry did, which is reality is an appeal-to-authority argument and not an argument on the merits. So you call something an anti-pattern, then get on my case for "appeal to authority" for calling something an anti-pattern? Your argument style needs work, dude. Global data is well-recognized across the industry as dangerous, and the larger the system the more dangerous it is. It violates pure functions, and pure functions are how you get any semblance of predictability in your code. I do not have the time or inclination to go through all the details of that here; you can find ample resources for that yourself. (And for the record, "appeal to authority" is only a logical fallacy if the authority being appealed to is not a qualified authority on the topic at hand. Appealing to Tiger Woods's authority on golf clubs is not a logical fallacy because he really would have more knowledge and experience than most; appealing to his authority on baseball gloves would be a logical fallacy.) > I take it you have never used Pantheon hosting then? You create a named environment to match a Git branch. Full disclosure: I work for Platform.sh, which has been doing environment-per-bit-branch longer than Pantheon has. I'm responsible for maintaining our public utility libraries for bridging environment variables into application configuration for environment-sensitive things like DB credentials and route names. So I am very intimately familiar with this problem space, probably moreso than most people. :-) In my experience, systems that configure themselves via constants are the worst. I know some do, but it's the most annoying option to work with. It makes any sort of dynamic override (which you *must* do in a cloud hosting enviroment) a PITA. The best option are systems that are configured by env vars, and have a very clearly set of documented env vars to populate. Env vars are also globally readable but you're not tricked into thinking they're compiled out at compilation time (as things with `const` are.) They're also by far the easiest for me to work with as the person writing that glue code. Adding language features that make it easier for people to take the approach that is in my experience the most painful option is something I am not going to support. :-) To the use cases, "I'm changing the API but don't want to change the API" (what you're calling evolving here) is not an argument that's going to carry weight with me. It's not a use case I feel is worth the confusion that comes with "Sometimes a constant is not a constant". The links you offer offer some other potential use cases that are worth considering, but "I made something a const when I shouldn't have" is not going to be convincing to me. Enums are also not constants. They're sum types. They can be implemented using a collection of constants, but that's a mediocre implementation of them (even if a popular one). To the list of links Mike offered, let me add Wikipedia: https://en.wikipedia.org/wiki/Constant_(computer_programming) So, to examine the full problem space using Wikipedia's terminology: 1) Macro constants. These are handled at compile time and do not exist at runtime. This is what PHP's const is currently, both global and class-based. 2) Dynamically valued constants. This is what Java and C++ have, and essentially what Javascript's const does. This supports dynamic code that runs a computation to produce a value, once. That value's scope is based on whatever that variable's scope would be otherwise. (Could be global, could be class static, could be local to a function.) It's unclear when that code is actually run, and likely varies by language; also, it's unclear if it's legal to have the computing code depend on runtime information. That may also vary by language; I'm not sure. PHP's `declare` statement is more akin to the latter, albeit hoisted to global scope. It's not computed on-demand but whenever the `declare` line happens to be reached. There is no class-level equivalent. Unlike the other languages listed, PHP also has a syntactic split between variables and constants. Variables have a $, constants do not. Whether that's good or bad is an academic question as it's clearly not going to change. That's in contrast to most other languages where there is no syntactic distinction, just the convention of capitalizing not-gonna-change things. Dynamically valued constants are... I'll say similar to but not quite the same as an auto-memoized function. For one there's the () vs not; for another, an auto-memoized function may take parameters and thus memoize different return values. From one perspective one could look at dynamically valued constants as a zero parameter self-memoizing function with some syntactic sugar. I can see a use for const variables, especially const class variables. The example in the Java link Mike provided is actually something I ran into just last week and it would have been very nice to have that ability. However, class constants in PHP right now are limited to Macro constants. So the more general request here is for dynamically valued constants beyond the current `declare` support. Which... I could potentially get behind. Self-memoizing functions is one way they could be implemented, if you don't mind (). (I don't.) That would also have a lot of other benefits. The caveat in both cases is dependencies. Memoizing an impure function can lead to all sorts of time-dependent silliness. The same concern applies to dynamically valued constants. If their generation code is a pure function (however expressed), then cool, that's a safe and nice feature. If it has unpredictable dependencies, though, the behavior can be equally unpredicatable. That includes depending on $_GET or env vars. (Remember, PHP has plenty of users outside of shred-nothing requests, and with FFI and preloading hopefully more of them wil get used more often.) So I could get behind dynamically valued constants and/or auto-memoizing functions. That would probably mean they still have a $ on them, which doesn't bother me. That clearly separates them visually from macro constants, which I like. The concern is when you use impure functions to generate them, the results are unpredicatable and, depending on the circumstances, may be non-deterministic. The potential for hard to find bugs here is high; although the counter point is that using a function/method to emulate them today, which you can absolutely do, offers the exact same risk. So I am nervous here but not quite agahst, since... "status quo bias". ;-) There's a lot of ways that could be done syntactically. One option is Tyson's proposal, although I would prefer to not pollute `const` with it and use a declare, like so: // This line already works. declare('API_URL', $_ENV['EXAMPLE_API_URL'] ?? 'https://api.example.com'); // The change would just be allowing the const to lazy-populate here. class Api { const URL = API_URL; } Another option is to allow `declare` in classes: class Api { declare string $URL = $_ENV['EXAMPLE_API_URL'] ?? 'https://api.example.com'); } (Or something like that.) The trick is when exactly these run, because they're impure functions so whether they run at code compile time or first-access could mean a dramatic difference in their resulting value. And that is precisely why I am very, very nervous about allowing impure functions to be cached, whatever the syntax on top of them. (Constant-like or not.)