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.)

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to