Newsgroups: php.internals
Path: news.php.net
Xref: news.php.net php.internals:107998
Return-Path: <mike@newclarity.net>
Delivered-To: mailing list internals@lists.php.net
Received: (qmail 23636 invoked from network); 5 Jan 2020 23:48:45 -0000
Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5)
  by pb1.pair.com with SMTP; 5 Jan 2020 23:48:45 -0000
Received: from php-smtp4.php.net (localhost [127.0.0.1])
	by php-smtp4.php.net (Postfix) with ESMTP id AC386180511
	for <internals@lists.php.net>; Sun,  5 Jan 2020 13:53:28 -0800 (PST)
X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on php-smtp4.php.net
X-Spam-Level: 
X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED,
	DKIM_VALID,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL,
	SPF_HELO_NONE,SPF_NONE autolearn=no autolearn_force=no version=3.4.2
X-Spam-ASN: AS15169 209.85.128.0/17
X-Spam-Virus: No
X-Envelope-From: <mike@newclarity.net>
Received: from mail-yw1-f44.google.com (mail-yw1-f44.google.com [209.85.161.44])
	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
	 key-exchange ECDHE (P-256) server-signature RSA-PSS (4096 bits) server-digest SHA256)
	(No client certificate requested)
	by php-smtp4.php.net (Postfix) with ESMTPS
	for <internals@lists.php.net>; Sun,  5 Jan 2020 13:53:27 -0800 (PST)
Received: by mail-yw1-f44.google.com with SMTP id u139so21124930ywf.13
        for <internals@lists.php.net>; Sun, 05 Jan 2020 13:53:27 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=newclarity-net.20150623.gappssmtp.com; s=20150623;
        h=mime-version:subject:from:in-reply-to:date:cc
         :content-transfer-encoding:message-id:references:to;
        bh=LrDx2BTX9TOMqNnSwAnX+MacJRUg6j4D8VBU+IsP5og=;
        b=MhFMwwEV3WmI/RlUbe6mnvxNqo4vBYcgG/wkqKNVYRJNWuTQa4P/HKL80b5CEzGw/+
         0laZDdWMcE5aUp0l+8UJM6V2/uYb3w/gAxCaKVipsBME/YwxJH95GBnNoC3egp/7Oi+m
         iKomRzQ7cMhYChd5/HD6hP0Q2hjIatxr+AlC5ZSu9E9aAkgaVxFnn1/x37cjlVd52DaJ
         IU6xVmpeNbbKZPZ15CdoZmIueehcpkEKL6eAq/cU3itSt3rD59BsmqGeFKvkyBvu3NWV
         fMsXPBVcyeCyzuRpU3RnOKlmVBYIlTQtCLIXpJoQxk5PAgUA3YiZtVWB0g97/27lnUTF
         u7gg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=1e100.net; s=20161025;
        h=x-gm-message-state:mime-version:subject:from:in-reply-to:date:cc
         :content-transfer-encoding:message-id:references:to;
        bh=LrDx2BTX9TOMqNnSwAnX+MacJRUg6j4D8VBU+IsP5og=;
        b=D6rLjBPyMlQxKQbcN+7iM36BUbD2mBAuk310IKHvZr3Ar6uS7c4ijRqWS1pp0f2gau
         w59HbZgesKxSSSAoKKXEg1IKNJprIb180n2QL9Wo1QhALZUZWDU017g4gnGh8IrAAein
         SFQfHIiF9N1YnE6/SLJVroOf0dmX/MIHhkMQCNjwh4wxUl8fXsK/dr4HrvQ5XldoC8Dt
         9JODgn+/F2Jq3a5ruOyn7/ak27Oty4jdFliGkhXG2rJyEtJcFdnUXadSWOVJY/nVXiQ+
         hEf5EZoTCMoraA96CeudVc3Vebw0mVeIk1Cy/Z62cHx3RXBMmoKdsYE8mx0NRofd0MMy
         3oig==
X-Gm-Message-State: APjAAAXchNQ3jhcHKao42f9zNDWPN9WcW8gQaEBBXOtKSzNu1Dd08nfR
	vpP38qtGKq5d8OQl62EUPVA3GQ==
X-Google-Smtp-Source: APXvYqwbg4Q8HS0x0iGu8sgC3G7Robmv1fyhzPPktSeoco1js0hObq/BGKhKlcgGKE2K4NGiGqZFbw==
X-Received: by 2002:a81:5206:: with SMTP id g6mr77449407ywb.216.1578261206461;
        Sun, 05 Jan 2020 13:53:26 -0800 (PST)
Received: from ?IPv6:2601:c0:c680:5cc0:64a1:dd94:3e49:c5e1? ([2601:c0:c680:5cc0:64a1:dd94:3e49:c5e1])
        by smtp.gmail.com with ESMTPSA id b192sm27077646ywe.2.2020.01.05.13.53.24
        (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);
        Sun, 05 Jan 2020 13:53:25 -0800 (PST)
Content-Type: text/plain;
	charset=utf-8
Mime-Version: 1.0 (Mac OS X Mail 12.4 \(3445.104.11\))
In-Reply-To: <f9e2f739-4964-b259-d9e5-4aeec938c54b@gmail.com>
Date: Sun, 5 Jan 2020 16:53:24 -0500
Cc: internals@lists.php.net
Content-Transfer-Encoding: quoted-printable
Message-ID: <F48FF1DC-5DE9-4C30-8BCF-C17A1877AF37@newclarity.net>
References: <5e0d723f.1c69fb81.e2ae8.24e2SMTPIN_ADDED_MISSING@mx.google.com>
 <74F2DBFC-E63C-428C-A37F-2D0CEE15AD0F@newclarity.net>
 <DM5PR07MB30676FC66DA036895D5E3554F9200@DM5PR07MB3067.namprd07.prod.outlook.com>
 <CD014984-715D-49C5-9A90-66C0A11F9818@newclarity.net>
 <c40a96fe-8929-4b44-98bd-3370a12ec516@www.fastmail.com>
 <D56361F6-8B11-4363-908D-962F683936BF@newclarity.net>
 <b32edf0c-451d-2281-8036-0b631a3c7a6f@gmail.com>
 <CD3AFCD7-EF2F-46C7-90D3-3A83A1D8836C@newclarity.net>
 <53556dfb-44ce-f902-204c-9a7da9484a61@gmail.com>
 <65567C7C-CF0F-4562-8943-F1F302134B07@newclarity.net>
 <f9e2f739-4964-b259-d9e5-4aeec938c54b@gmail.com>
To: Rowan Tommins <rowan.collins@gmail.com>
X-Mailer: Apple Mail (2.3445.104.11)
Subject: Re: [PHP-DEV] Initializing constants once, with code?
From: mike@newclarity.net (Mike Schinkel)

> On Jan 5, 2020, at 3:17 PM, Rowan Tommins <rowan.collins@gmail.com> =
wrote:
>=20
> They seem a poor example of something that you would later want to =
"evolve" using the proposed new feature. An enum is, by definition, a =
set of values that covers all possibilities, often with completely =
arbitrary values.

Yet you called my list of URLs enums, and they are not at all arbitrary =
and absolutely want to change.

We can both agree that enums for 0, 1, 2 etc. are not in use-case I am =
discussing.

Maybe you misspoke when you called my list of URLs enums?  Or I misread?

> I'm struggling to imagine how this would work. I've seen plenty of =
code that needs to know "the current environment", but "the name of the =
current development environment" seems an odd thing to have a constant =
for.

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

"dev" is not "local" in this content.  "dev" is the place developers =
push code to test remotely.  Then they push to "test" for QA to =
evaluate.  At least for this client.

That said, my client wants to move to many "dev" and "test" =
environments, one for each JIRA epic, so we would like to be able to =
initialize the API urls based on the current subdomain.=20

> Well, it would be more "scannable" if every method in the class was =
written on one line - and indeed you can do so if you want - but that's =
not inherently better.

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

> If a class has a bunch of different functions and constants in, I'll =
generally use an IDE or editor plugin to navigate them, and rely on them =
being well-named, rather than minimising the whitespace between them.

I use and have used PhpStorm extensively, since prior to 1.0.   But =
PhpStorm does not make it easier to do code reviews on Github, or even =
read code in PhpStorm.  Yes, I can navigate them, but to still adds =
cognitive load.=20

Honestly, we are debating preferences here.  Can we focus on objective =
things?

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

Design decisions can be changed.  PHP 5 changed the design decisions of =
PHP objects and added the __set() method. Before then it could have =
easily been argued that variable accessed a memory location, but never =
called code. But then that design decision was changed. =20

So there is no reason I've heard thus far that this one could not be =
changed too.

> An interesting exercise is to ask if there are other languages that =
take a different decision - it's not decisive, either way, but it can be =
suggestive.
> "Can constants be evolved into something that is initialised =
on-demand?" is not something I'm aware of examples of elsewhere. That =
could be because nobody's thought of it before, or just that I haven't =
come across it, but it could be because there's a better solution to the =
underlying requirement.

Excellent point. =20

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

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

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

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

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

I think that is a fairly conclusive list of highly-used languages, all =
of which allow constants to be initialized with code. This list would =
imply any assertion that constants must be handled at compile time is =
not applicable for many other languages so I would argue to not a =
universal principle.

Also it would imply that allowing constants to be initialized via =
runtime code would not disrupt the time-space continuum, either.

> I think the syntax being the same when you *reference* the value =
bothers me more than how it is declared. If I see ClassName::USER_ID, I =
expect the value to be the same each time the code runs, and to be able =
to find the value directly in the source.

Again, I ask if that your unease has more to do with status quo bias vs. =
something fundamentally wrong with the concept?

> It's a limitation in the very basic sense that it limits what you can =
do. You can't write this, for instance:
>=20
> class API {
>     private $config;
>     public function __construct($config) {
>         $this->config =3D $config;
>     }
>=20
>     const URL {
>          return $this->config->getValue('API_URL');
>     }
> }

But you could do this:

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

class Config {
   public $api_url;
   private static $_current;
   function __construct($args =3D array()){
      $this->api_url =3D $args['api_url'];
   }
   static function get():Config{
      if ( ! isset( self::$_current ) ) {
         trigger_error('must call Config::set() before calling =
Config::get()');
         die();
      }
      return self::$_current;
   }
   static function set( Config $config ){
      self::$_current =3D $config;
   }
}

Config::set( new Config(['api_url' =3D> 'https://api.example.com']) );

//...
$api_url =3D Api::URL;

Any way, why again must perfect be the enemy of the good?

> Laravel's "facades" are global variables hidden behind static methods. =
So you write "DB::query($sql)" as a short-hand for =
"DB::$currentInstance->query($sql)". Most of the time, you just treat it =
as static, but if you want to write tests, for instance, you can inject =
a mock as the current instance.

Ah.=20

> An interesting thing is that you can evolve a class that really is =
static and replace it with one of these facades. Unfortunately, the same =
wouldn't be true with initialise-once constants, because once the =
constant had been read, you couldn't swap it out in another test.

Well, I am suggested one-time only because I assumed that one-time only =
_is_ the only thing that is fundamental to `const.`  But I can see uses =
for being able to redefine them =E2=80=94 when running unit tests =E2=80=94=
 but I was not planning to ask for that.

> 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. =20

But I used "anti-pattern" because I did not think I was trying to =
convince anyone against adding a pre-processor, so it was just easier to =
write!

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

-Mike=