On 04/01/2020 22:40, Mike Schinkel wrote:
Add in the "initialise on first read", and you end up with 4 lines per
pseudo-constant vs 5 per method:
But then you give an example which exaggerates in the other direction.
No, I gave an example of exactly what it would like if I wrote it: one
line methods with one line docblocks, or one line constants with one
line docblocks. The only difference in your example below is that you've
omitted the docblocks from both versions, saving one line on each.
class Environments {
const PRODUCTION = 'master';
const STAGING = 'stage';
const TESTING = 'test';
const DEVELOPMENT = 'dev';
}
vs.
class Environments {
static function PRODUCTION() {
return 'master';
}
static function STAGING() {
return 'stage';
}
static function TESTING() {
return 'test';
}
static function DEVELOPMENT() {
return 'dev';
}
}
This is a really terrible example, because it's basically an enum, and
would never be anything other than a set of true constants. In a sense,
that's nitpicking at the example, but I think it's teling: the kinds of
constants that are "scannable" are generally not the kind that would be
replaced by configuration in the way you're suggesting.
That is, if you have:
class API {
const TEST_URL = 'https://testing.api.example.com';
const LIVE_URL = 'https://production.api.example.com';
}
...then these are nicely "scannable", but already capture the fact that
there are different options to choose from.
If instead you have:
class API {
const URL = 'https://production.api.example.com';
const VERSION = 1.5;
}
...then being "scannable" isn't particularly relevant, because these are
completely separate values.
What I am asking for is the ability to _evolve_ code over time and not force
code to forever retain its technical debt simply because of initial choices.
And not just for constants, but for evolvability of all code. To me that seems
like such a no-brainer best practice for programming language design that I am
struggling to understand the fundamental objections to it.
I suppose it would be possible to design a language which maximised
"evolvability" by using interchangeable syntax for different concepts.
For instance, properties and constants could all just be special method
calls; perhaps "const FOO=42" would be sugar for "static function FOO()
{ return 42; }" and "SomeClass::FOO" would always be the same as
"SomeClass::FOO()".
However, there will always be new requirements that require a breaking
change. For instance, maybe you need to send some API calls to one URL
and some to another, so everywhere that fetches the URL needs to choose
between two constants, or pass a parameter to the method. Or maybe you
write something as static and later wish you'd required an instance to
be constructed.
So it's not enough to say "everything should be evolvable", we need to
ask whether this specific scenario is common enough to design the
language around, and what the possible downsides of the feature might be.
The fact constants are limited to literal code is merely a limitation
of the opcode compiler, not a conceptual difference. In both cases
they are initialized before use, and then never changed. If they are
immutable once initialized, then they are conceptually constants.
I disagree, I think constants being a literal value is a design
decision, not an implementation one. Off the top of my head, I can think
of three types of things that you might call "constants":
1. A value that will never change, and you just want to give a name to.
For instance, MINUTES_IN_HOUR=60
2. A value set at compile-time, to hard-code a particular condition. For
instance, DEBUG=false
3. A value which is set at run-time, but happens not to change during
the course of the application, so should not be over-written.
PHP's constants are designed primarily to be type 1 - they are literal
values, hard-coded in the source. Unlike C, there is no standard
pre-processor for PHP, so type 2 is rarer, but it's possible to
implement by manipulating the source file before deployment, or even
when running the autoloader.
Your proposed feature changes constants to instead be type 3, which I
think is a fundamentally different concept - much more like a property
with extra restrictions. I think it would be very confusing for the
syntax which everyone is used to meaning "hard-coded or at most
compile-time value" could now actually mean "global value different on
every request":
const USER_ID {
return $_GET['user_id'];
}
Yet another approach would be for me to ask for would be for a shortened
function declaration syntax. But again that would also not empower existing
constants to evolve:
class Environments {
function PRODUCTION = 'master';
function STAGING = 'stage';
function TESTING = 'test';
function DEVELOPMENT = 'dev';
}
During the discussion of short closures a suggestion came up that the
syntax could be reused for single-expression methods, so you'd write this:
class Environments {
public static fn getUrl() => 'https://api.example.com';
}
As you say, that still requires callers to know that they're calling a
method, not referencing a constant; we evidently disagree on whether
that's a good thing.
Both you and Larry have redefined my use-case to an idealogically
convenient use-case. Can we please address the use-case as I am
defining it: existing code that already uses constants and future code
where developers use constants because of lack of skill, awareness of
"best practices", or too-tight timelines?
For my part, I tried to look at the bigger picture, because I think
major changes to the language should address as many use cases as
possible, not introduce special syntax for narrow scenarios.
As Larry mentions, the proposal is also limited by "globalness". Since
constants are always static, the initialisation code can only access
global and static state, so you can't inject a configuration object into
your constructor then use it to initialise constants. And since they're
write-once, you can't use them for Laravel-style "facades", where the
access is static, but can be swapped out at run-time.
Perhaps a better angle to look at is something like the C Pre-Processor
- manipulating the code at compile-time so that multiple different
versions of the code can be created from the same source, but constants
are still constant at run-time. I know there are tools out there already
to do this, but have never used one.
Regards,
--
Rowan Tommins (né Collins)
[IMSoP]
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php