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

Reply via email to