On 05/01/2020 21:53, Mike Schinkel wrote:
Yet you called my list of URLs enums, and they are not at all arbitrary and 
absolutely want to change.


I apologise - I took a guess without context for how those constants would be used, but apparently they're something rather different.


I take it you have never used Pantheon hosting then?  You create a named 
environment to match a Git branch.


I'm still struggling to understand why you need multiple constants, all mutable based on some other dimension. If the ultimate goal is to know the name and branch of the *current* environment, how do the constants help?

It seems on the face of it like the constants have outlived their usefulness, and need to be replaced by a lookup table of some kind.


What is "better" in this context is one's opinion. You might not find it beneficial, but I would.


Agreed. I actually said the same in one draft reply, but maybe deleted it while editing down.


"Constants are defined at compile-time" is a status quo in the same sense as 
"variables can be assigned to" is a status quo - you could certainly design a language 
differently, but it's not just something that happened by accident, it's a design decision.
It was a design decision in that maybe it did not occur to them that it would 
be useful; IOW a design by omission.


We'll just have to agree to disagree here. I stand by the assertion that "compile-time constants" are a well-defined feature, whose restrictions are part of their definition and purpose.


Ruby has the .replace method for constants and can thus assign at runtime:
=========
https://stackoverflow.com/a/6712438/102699


That method is not actually a feature of constants, its abusing the fact that everything is an object, so the *value* of a constant might still be a mutable object. It's an interesting "cheat", but it's not really a deliberate language feature.


C++ has const member functions (not exactly the same, but similar):
=========
https://www.linuxtopia.org/online_books/programming_books/thinking_in_c++/Chapter08_014.html


Unless I'm missing something, this isn't really related to anything we've been discussing, it just happens to use the keyword "const".


Python adds a final qualifier to turn variables into constants. Thus is 
supports initializing constants:
=========
https://stackoverflow.com/a/47821212/102699
http://code.activestate.com/recipes/65207-constants-in-python/


Those links seem to say that Python doesn't have constants *at all*, but you can emulate them in various ways. As such, you can give them pretty much whatever behaviour you like, since you're defining the language feature from scratch.


Javascript can assign constants at runtime:
=========
fn = function() { return "World"; };
const who = fn();
alert( "Hello " + who );

This is a more interesting case; some properties to ponder:

- implemented as a special kind of variable (e.g. they have the same scope rules and syntax as "let" variables)
- can be global or block-scoped, but not a property of an object
- cannot be pre-declared before they are assigned, or automatically initialised on first reference
- can contain any value, including mutable objects


Java creates class constants with `public static final` which can be 
initialized with code:
=========
https://www.javaworld.com/article/2076481/use-constant-types-for-safer-and-cleaner-code.html


Another interesting case:

- implemented as a special kind of variable
- can contain any value, including mutable objects
- will raise an error if the compiler cannot prove there is exactly one assignment; i.e. these are not purely run-time constructs like PHP's define() constants
- can be static members of a class, and include an inline initializer
- can be static members of a class and have no inline initializer, in which case they *must* be initialized using a "static initializer block" which will be run the first time *the class* is referenced at run time (a bit like substituting the value during autoloading in PHP) - can be instance fields, and must be initialised inline, or in every possible constructor
- can be block-scoped variables, and must be initialised before first use

The interesting thing here is that the constants are initialised the same way as any other variable, not using any special on-demand code. Because of the language's design, the compiler is able to prove that they are assigned exactly once. That proof is probably a lot harder in PHP, and the check would probably be punted to run-time.


The biggest sticking point in my mind is your insistence that they share syntax with constants, rather than variables. This means they can only be used in static class or namespace context, not against an instance.

It also means *widening* the meaning of a construct, rather than *narrowing* it: the "final" keyword in Java doesn't let variables do anything new, it just restricts them; your proposed constant initialization would allow constants to act in new ways, including holding complex, mutable types. That's likely to cause confusion for both humans and tools written based on the current concept that a constant can always be computed at compile-time.



It's a limitation in the very basic sense that it limits what you can do. You 
can't write this, for instance:

class API {
     private $config;
     public function __construct($config) {
         $this->config = $config;
     }

     const URL {
          return $this->config->getValue('API_URL');
     }
}
But you could do this:

class Api {
    const URL:string {
          return Config::get()->api_url;
     }
}


The difference is that a Java-style "final variable" can have a single value *per instance*, so this is valid:

class API {
    private final $URL;
    public function __construct($config) {
        $this->URL = $this->config->getValue('API_URL');
    }
}



I'm just looking for solutions to your use case, which as I understand it is 
values which change rarely based on configuration.
I honestly do appreciate it.  You are generally very good about that kind of 
thing.


I would be interested to hear more about why you think pre-processing doesn't suit your use case. It seems like a good fit to me:

- naturally fits with code expecting compile-time constants
- no run-time overhead if done as part of deployment
- can be implemented using succinct syntax, rather than run-time initialisation code


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