Re: Initializing constants once, with code?
| From: | Larry Garfield | Date: | Sun, 05 Jan 2020 17:02:22 +0000 |
| Subject: | Re: Initializing constants once, with code? | ||
| References: | 1 2 3 4 5 6 7 8 9 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-107989@lists.php.net to get a copy of this message | ||
On Sat, Jan 4, 2020, at 3:25 PM, Mike Schinkel wrote:
> > On Jan 3, 2020, at 2:52 PM, Larry Garfield <larry@garfieldtech.com> wrote:
> >
> > There's two broad reasons I think this is a bad idea.
> >
> > 1) Constants are one thing. Function calls are another. They serve different purposes.
> > Trying to mutate them into one thing can only lead to confusion and lack of understanding about what
> > is actually going on.
> >
> > 2) The approach you describe (of starting with constants everywhere and refactoring to
> > method calls later)... I would never do and do not endorse. What you describe is basically
> > "make globals nicer to work with", whereas I am 100% firmly in the camp of "if I
> > could remove globals from the language entirely I would". Frankly, the use of constants for
> > configuration is an anti-pattern to begin with; they should be used only for things that are truly
> > constant. Honestly, I cannot recall the last time I used constants for anything other than giving
> > some other compile-time value a nicer name. (Eg, DEFAULT_THING_VALUE or giving nice names to bit
> > flags or something like that.)
> >
> > For configuration, my answer is frankly "put your configuration behind a nice
> > configuration object from the very beginning and then you won't have to refactor it later;
> > Problem solved." You can use env vars for configuration, and wrap those into a nice object,
> > possibly using one of the many DotEnv implementations that already exist to make them nicer to work
> > with in development. That is superior in basically every conceivable way to semi-mutable globals
> > passing themselves off as pseudo-constants.
> >
> > I *would* love to see property accessors come back, which would have a side effect of
> > making what you describe a little easier, but at no point is it pretending to be a compile time
> > value when it isn't.
> >
> > --Larry Garfield
>
> <sigh> So much to unpack here, but I will just hit the most important points.
*snip*
> Symfony — which many PHP developers hold in high regard including
> Drupal developers — uses constants:
Just an FYI: I assume you mention Drupal specifically here because of my history with the project.
What Drupal developers hold in high regard matters not even 0% for me at this point; "Drupal
does it" is not an argument that will carry any weight with me.
*snip*
> I think this analysis proves many PHP developers do use constants in
> ways you claim you would never. IOW, the use-cases I am trying to
> address exist to a significant degree in the wild.
>
> Further I believe I have made the case that there would be significant
> value in allowing developers who previously used constants because of
> prior lack of skill or too-tight timelines to be able to evolve their
> code to initialize their constants with code instead of forcing their
> users to change their code or worse.
>
> -Mike
I think you are overstating my case. I am not arguing that one should never use constants. In
fact, a majority of the examples you cite I would say are reasonable uses of constants, at least in
concept. (I cannot speak to the particulars of the individual code bases.)
I am saying that the behavior of a constant is that it is... constant. A proper constant is
evaluated at compile time and appears as a literal in the final runtime code, with no dereferencing.
AIUI,
const in PHP does exactly that, in contrast to define. That is
fundamentally conceptually incompatible with a value that is derived at runtime and happens to use
constant-style syntax. I am firmly opposed in principle to having a language construct that looks
like a constant and makes you think it's a constant but is actually a method call that does who
knows what.
There's really two different use cases here, I think, that we're conflating.
("We" meaning I think we're all doing it to an extent.)
1) I want an approximately global value that is auto-memoized on first usage, so I can access it
from anywhere without having to recompute it or do the work of memoizing it myself.
2) I have a code base with lots of constants, and I've changed my mind about the API (for
whatever reason) and want them to no longer be constant but runtime defined.
For point 1, I'd love it if we had some way to auto-memoize a result. That would be sweet.
There's a couple of ways we could go about it... but I firmly believe that sticking it behind a
const-like API is the wrong way to do it for the reasons above. (I wouldn't want to limit it
to global-ish things, either, because global-ish things are, as stated, bad in every way and should
be avoided whenever possible. Yes, I know there's a lot of bad code out there already with it;
that doesn't mean encouraging it.)
For point 2... if you want to change your API, then your API is going to change. That's what
it means to change an API. It's no different than deciding to rename a method or class. It
may or may not be hard depending on the API and the install base, but that it's a constant
doesn't change matters. Making code easier to refactor is all well and good, but not if it
violates all expectations around what a constant is.
For derive-once global constants, you may be looking for define. That's a runtime
operation and effectively boils down to a set-once global. It doesn't help with constants
defined in a class, but for an already-global constant define already gives you a
one-time set operation, just not on-demand. That's probably the better avenue to pursue for
option 2, though again it's not one that I find worth compromising the language design for.
--Larry Garfield