Hello All,
In June 2020, Benas Seliuginas emailed this list (
https://externals.io/message/110755#110755) to gauge interest in typed
constants. An RFC (https://wiki.php.net/rfc/typed_class_constants) was
started and had an accompanying PR (https://github.com/php/php-src/pull/5815).
At the time, Nikita Popov supported it for overall language consistency,
and Sebastian Bergmann +1'd it for overall language consistency as well.
The PR has since been closed without being merged, and the idea hasn't
progressed since.
I'd like to revisit the concept, gauge current interest, and pick the
concept and work back up. Any more discussion items for or against the idea?
I'm willing to do the work to pick it up where it was left off and get an
RFC proposed through the normal process, and a working PR. This is my first
foray into the PHP RFC process, and C code is not my forte, but I'll take
it on. If anyone would be willing to pair/mentor/co-author with me, please
let me know. Either way, I'll plan to work on it.
This is the first of several concepts I have been tinkering with and seeing
practical uses for. The next phase of work with different RFC would take
this further with const inheritance, where const type must match.
- Mark
Hello All,
In June 2020, Benas Seliuginas emailed this list (
https://externals.io/message/110755#110755) to gauge interest in typed
constants. An RFC (https://wiki.php.net/rfc/typed_class_constants) was
started and had an accompanying PR (https://github.com/php/php-src/pull/5815).
At the time, Nikita Popov supported it for overall language consistency,
and Sebastian Bergmann +1'd it for overall language consistency as well.
The PR has since been closed without being merged, and the idea hasn't
progressed since.I'd like to revisit the concept, gauge current interest, and pick the
concept and work back up. Any more discussion items for or against the idea?I'm willing to do the work to pick it up where it was left off and get an
RFC proposed through the normal process, and a working PR. This is my first
foray into the PHP RFC process, and C code is not my forte, but I'll take
it on. If anyone would be willing to pair/mentor/co-author with me, please
let me know. Either way, I'll plan to work on it.This is the first of several concepts I have been tinkering with and seeing
practical uses for. The next phase of work with different RFC would take
this further with const inheritance, where const type must match.
- Mark
Is there a benefit to it other than "well everything else has types now, so..."? Even if it's esoteric, like in reflection-based meta programming? (I've been dabbling too much in that lately. :-) ) "Everything else does" isn't a compelling argument for me, but there may be others I'm not thinking of.
--Larry Garfield
On Wed, Mar 23, 2022 at 4:10 PM Larry Garfield larry@garfieldtech.com
wrote:
Hello All,
In June 2020, Benas Seliuginas emailed this list (
https://externals.io/message/110755#110755) to gauge interest in typed
constants. An RFC (https://wiki.php.net/rfc/typed_class_constants) was
started and had an accompanying PR (
https://github.com/php/php-src/pull/5815).
At the time, Nikita Popov supported it for overall language consistency,
and Sebastian Bergmann +1'd it for overall language consistency as well.
The PR has since been closed without being merged, and the idea hasn't
progressed since.I'd like to revisit the concept, gauge current interest, and pick the
concept and work back up. Any more discussion items for or against the
idea?I'm willing to do the work to pick it up where it was left off and get an
RFC proposed through the normal process, and a working PR. This is my
first
foray into the PHP RFC process, and C code is not my forte, but I'll take
it on. If anyone would be willing to pair/mentor/co-author with me,
please
let me know. Either way, I'll plan to work on it.This is the first of several concepts I have been tinkering with and
seeing
practical uses for. The next phase of work with different RFC would take
this further with const inheritance, where const type must match.
- Mark
Is there a benefit to it other than "well everything else has types now,
so..."? Even if it's esoteric, like in reflection-based meta programming?
(I've been dabbling too much in that lately. :-) ) "Everything else does"
isn't a compelling argument for me, but there may be others I'm not
thinking of.--Larry Garfield
Larry and Internals,
To the benefits!
On its own, typing class constants does help align them with other things
like typed class properties, typed arguments, and method return types.
There will come additional benefits though, and this would be phase 1.
Phase 2 would be to introduce typed constants to be set by extending or
implementing classes. Combining the two features would lead to better
defined and usable class constants.
For example, an interface could be:
interface DbTable
{
public const string TABLE_NAME;
}
Which would then be implemented as:
class UserTable implements DbTable
{
public const string TABLE_NAME = 'user';
}
Thus ensuring TABLE_NAME
is always set, and always returns a string
type. See https://docs.laminas.dev/laminas-db/table-gateway/ for a
real-world framework example where this feature could be used.
Another example I often see in my projects could be used with a similar
example:
abstract class Bird
{
public const bool CAN_FLY;
public const string FAMILY;
public function canFly(): bool
{
return self::CAN_FLY;
}
}
final class EmperorPenguin extends Bird
{
public const bool CAN_FLY = false;
public const string FAMILY = 'penguin';
}
In this case, one could instead use typed class properties, but it feels
improper since the values are static and unchanging. Immutability is a work
around to this when implemented properly. This would simplify the solution
while ensuring values remain unchanged.
- Mark
--
To unsubscribe, visit: https://www.php.net/unsub.php
Hi Mark,
On Wed, Mar 23, 2022 at 11:55 PM Mark Niebergall mbniebergall@gmail.com
wrote:
(...)
Another example I often see in my projects could be used with a similar
example:abstract class Bird { public const bool CAN_FLY; public const string FAMILY; public function canFly(): bool { return self::CAN_FLY; } } final class EmperorPenguin extends Bird { public const bool CAN_FLY = false; public const string FAMILY = 'penguin'; }
I had this "need" too (and used abstract static methods where the
implementations just return a literal value...).
Just 2 remarks: in abstract class Bird, shouldn't it be:
- "abstract public const bool CAN_FLY;" (and same for FAMILY)
- "return static::CAN_FLY;"
?
Regards,
--
Guilliam Xavier
Guilliam,
On Fri, Mar 25, 2022 at 6:35 AM Guilliam Xavier guilliam.xavier@gmail.com
wrote:
Hi Mark,
On Wed, Mar 23, 2022 at 11:55 PM Mark Niebergall mbniebergall@gmail.com
wrote:(...)
Another example I often see in my projects could be used with a similar
example:abstract class Bird { public const bool CAN_FLY; public const string FAMILY; public function canFly(): bool { return self::CAN_FLY; } } final class EmperorPenguin extends Bird { public const bool CAN_FLY = false; public const string FAMILY = 'penguin'; }
I had this "need" too (and used abstract static methods where the
implementations just return a literal value...).Just 2 remarks: in abstract class Bird, shouldn't it be:
- "abstract public const bool CAN_FLY;" (and same for FAMILY)
- "return static::CAN_FLY;"
?
I intentionally left abstract
out of public const bool CAN_FLY;
in the
abstract class
for consistency with the implementation with interface
,
which would also have to be public const bool CAN_FLY;
. Currently
abstract
is only used in front of methods abstract function doThing(): bool;
. Open to discussion - which way is ideal or preferred? That could be
included as a subset of an RFC vote if a consensus during discussion isn't
reached.
Good correction, yes, return static::CAN_FLY;
in that example in the
concrete child class.
Regards,
--
Guilliam Xavier
I intentionally left
abstract
out ofpublic const bool CAN_FLY;
in the
abstract class
for consistency with the implementation withinterface
,
which would also have to bepublic const bool CAN_FLY;
. Currently
abstract
is only used in front of methodsabstract function doThing(): bool;
. Open to discussion - which way is ideal or preferred? That could be
included as a subset of an RFC vote if a consensus during discussion isn't
reached.
I understand, but note that methods are implicitly abstract in an
interface, but it must be explicit in an abstract class; and since I see
the proposed feature mainly as a "replacement" for abstract static methods
[whose all implementations just return a literal value]... (anyway, not
super important)
On Fri, Mar 25, 2022 at 10:55 AM Guilliam Xavier guilliam.xavier@gmail.com
wrote:
I intentionally left
abstract
out ofpublic const bool CAN_FLY;
in the
abstract class
for consistency with the implementation withinterface
,
which would also have to bepublic const bool CAN_FLY;
. Currently
abstract
is only used in front of methodsabstract function doThing(): bool;
. Open to discussion - which way is ideal or preferred? That could be
included as a subset of an RFC vote if a consensus during discussion isn't
reached.I understand, but note that methods are implicitly abstract in an
interface, but it must be explicit in an abstract class; and since I see
the proposed feature mainly as a "replacement" for abstract static methods
[whose all implementations just return a literal value]... (anyway, not
super important)
Constants are not abstract in an interface - they must be assigned a value.
Only classes and methods can be abstract. Within an abstract class it is
not valid to have an abstract property. Properties can be defined
protected int $id;
and optionally assigned a value protected int $id = 5;
, but cannot be abstract protected int $id;
. So to me it makes more
sense to have constants follow the same syntax as properties public const bool CAN_FLY;
without the abstract
keyword.
An example:
abstract class Bird
{
public const bool CAN_FLY;
protected bool $isExtinct;
This allows for similar behavior, similar requirements, and similar syntax
- consistency ftw!
There seems to be interest and good use cases (thanks Sara for the good
practical example!). At this point I'm going to work on a new RFC with all
the details and feedback from this discussion.
Constants are not abstract in an interface - they must be assigned a
value. Only classes and methods can be abstract. Within an abstract class
it is not valid to have an abstract property. Properties can be defined
protected int $id;
and optionally assigned a valueprotected int $id = 5;
, but cannot beabstract protected int $id;
.
That's the current state of the language indeed, but to me, [part of]
your proposal looks like introducing "abstract constants"... Maybe I'm
misunderstanding?
So to me it makes more sense to have constants follow the same syntax as
propertiespublic const bool CAN_FLY;
without theabstract
keyword.An example:
abstract class Bird { public const bool CAN_FLY; protected bool $isExtinct;
This allows for similar behavior, similar requirements, and similar syntax
- consistency ftw!
For similarity/consistency, the $isExtinct
property should probably be
[public
and] static
(actually readonly
too, but cannot be both).
But, again, we can also see some similarity with static
methods, e.g.:
abstract class Bird
{
abstract public const bool CAN_FLY;
abstract public static function isExtinct(): bool;
}
class Dove extends Bird
{
// NOTE: the following two lines are required (in the class definition)
public const bool CAN_FLY = true;
public function static isExtinct(): bool { return false; }
}
// var_dump(Dove::CAN_FLY);
// var_dump(Dove::isExtinct());
Besides, an uninitialized property must be initialized before first read,
but is not required to be overridden/redefined (with a value) in a child
class; so in this example (still hypothetical):
abstract class Bird
{
public const bool CAN_FLY;
public static bool $isExtinct;
}
class Dodo extends Bird
{
// NOTE: the following two lines are commented out
// public const bool CAN_FLY = false;
// public static bool $isExtinct = true;
}
var_dump(Dodo::CAN_FLY);
var_dump(Dodo::$isExtinct);
where would the [missing value for constant] error be: on the definition of
class Dodo (like for an unimplemented abstract method), or only when trying
to access Dodo::CAN_FLY (like for an uninitialized property)?
There seems to be interest and good use cases (thanks Sara for the good
practical example!). At this point I'm going to work on a new RFC with all
the details and feedback from this discussion.
Thanks & good luck! =)
--
Guilliam Xavier
On Mon, Mar 28, 2022 at 6:54 AM Guilliam Xavier guilliam.xavier@gmail.com
wrote:
Constants are not abstract in an interface - they must be assigned a
value. Only classes and methods can be abstract. Within an abstract class
it is not valid to have an abstract property. Properties can be defined
protected int $id;
and optionally assigned a valueprotected int $id = 5;
, but cannot beabstract protected int $id;
.That's the current state of the language indeed, but to me, [part of]
your proposal looks like introducing "abstract constants"... Maybe I'm
misunderstanding?So to me it makes more sense to have constants follow the same syntax as
propertiespublic const bool CAN_FLY;
without theabstract
keyword.An example:
abstract class Bird { public const bool CAN_FLY; protected bool $isExtinct;
This allows for similar behavior, similar requirements, and similar
syntax - consistency ftw!For similarity/consistency, the
$isExtinct
property should probably be
[public
and]static
(actuallyreadonly
too, but cannot be both).But, again, we can also see some similarity with
static
methods, e.g.:abstract class Bird { abstract public const bool CAN_FLY; abstract public static function isExtinct(): bool; } class Dove extends Bird { // NOTE: the following two lines are required (in the class definition) public const bool CAN_FLY = true; public function static isExtinct(): bool { return false; } } // var_dump(Dove::CAN_FLY); // var_dump(Dove::isExtinct());
Besides, an uninitialized property must be initialized before first read,
but is not required to be overridden/redefined (with a value) in a child
class; so in this example (still hypothetical):abstract class Bird { public const bool CAN_FLY; public static bool $isExtinct; } class Dodo extends Bird { // NOTE: the following two lines are commented out // public const bool CAN_FLY = false; // public static bool $isExtinct = true; } var_dump(Dodo::CAN_FLY); var_dump(Dodo::$isExtinct);
where would the [missing value for constant] error be: on the definition
of class Dodo (like for an unimplemented abstract method), or only when
trying to access Dodo::CAN_FLY (like for an uninitialized property)?There seems to be interest and good use cases (thanks Sara for the good
practical example!). At this point I'm going to work on a new RFC with all
the details and feedback from this discussion.Thanks & good luck! =)
I have updated the RFC https://wiki.php.net/rfc/typed_class_constants with
more details and examples from this thread, and updated the RFC status to
Under Discussion. Hopefully the updated RFC helps answer questions and
clarifies what the proposal includes.
Of note is the "Inheritance and variance" section, which details uses with
abstracts and interfaces, plus the "Constant values" section which includes
details about errors.
--
Guilliam Xavier
Hey Mark,
On Wed, Mar 30, 2022 at 6:03 AM Mark Niebergall mbniebergall@gmail.com
wrote:
I have updated the RFC https://wiki.php.net/rfc/typed_class_constants with
more details and examples from this thread, and updated the RFC status to
Under Discussion. Hopefully the updated RFC helps answer questions and
clarifies what the proposal includes.
Thanks for the RFC and the drive here.
I personally see the benefit and I think it would be a nice addition.
I think you should also update the "Supported types" section.
Starting with enums, constants can also be objects. Once a good technical
solution is found, any object would be supported probably
https://wiki.php.net/rfc/new_in_initializers#future_scope
I think that only void, never and callable types should not be supported,
just like on properties.
Of note is the "Inheritance and variance" section, which details uses with
abstracts and interfaces, plus the "Constant values" section which includes
details about errors.--
Guilliam Xavier
Thanks,
Alex
Alex,
On Tue, Mar 29, 2022 at 10:35 PM Alexandru Pătrănescu drealecs@gmail.com
wrote:
Hey Mark,
On Wed, Mar 30, 2022 at 6:03 AM Mark Niebergall mbniebergall@gmail.com
wrote:I have updated the RFC https://wiki.php.net/rfc/typed_class_constants
with
more details and examples from this thread, and updated the RFC status to
Under Discussion. Hopefully the updated RFC helps answer questions and
clarifies what the proposal includes.Thanks for the RFC and the drive here.
I personally see the benefit and I think it would be a nice addition.I think you should also update the "Supported types" section.
Starting with enums, constants can also be objects. Once a good technical
solution is found, any object would be supported probably
https://wiki.php.net/rfc/new_in_initializers#future_scope
I think that only void, never and callable types should not be supported,
just like on properties.
I have updated the "Supported types" to list out all types that are
supported and which types are not supported.
Constants cannot be objects since objects are mutable, so typed constants
will not be allowed to be an enum (which is technically an object). A typed
constant may be an enum value though, so the following example will be
valid:
enum Fruit
{
case Apple;
case Banana;
}
class Colors
{
protected const string RED = Fruit::Apple;
protected const string YELLOW = Fruit::Banana;
}
Of note is the "Inheritance and variance" section, which details uses with
abstracts and interfaces, plus the "Constant values" section which
includes
details about errors.--
Guilliam XavierThanks,
Alex
Hey Mark,
On Wed, Mar 30, 2022 at 4:01 PM Mark Niebergall mbniebergall@gmail.com
wrote:
Alex,
On Tue, Mar 29, 2022 at 10:35 PM Alexandru Pătrănescu drealecs@gmail.com
wrote:Hey Mark,
On Wed, Mar 30, 2022 at 6:03 AM Mark Niebergall mbniebergall@gmail.com
wrote:I have updated the RFC https://wiki.php.net/rfc/typed_class_constants
with
more details and examples from this thread, and updated the RFC status to
Under Discussion. Hopefully the updated RFC helps answer questions and
clarifies what the proposal includes.Thanks for the RFC and the drive here.
I personally see the benefit and I think it would be a nice addition.I think you should also update the "Supported types" section.
Starting with enums, constants can also be objects. Once a good technical
solution is found, any object would be supported probably
https://wiki.php.net/rfc/new_in_initializers#future_scope
I think that only void, never and callable types should not be supported,
just like on properties.I have updated the "Supported types" to list out all types that are
supported and which types are not supported.Constants cannot be objects since objects are mutable, so typed constants
will not be allowed to be an enum (which is technically an object). A typed
constant may be an enum value though, so the following example will be
valid:enum Fruit { case Apple; case Banana; } class Colors { protected const string RED = Fruit::Apple; protected const string YELLOW = Fruit::Banana; }
Actually, Fruit::Apple is an enum instance and that is an object that is of
Fruit enum type (Fruit class).
You can check this as it's already possible in PHP 8.1, even if it's not
yet possible to have them with type: https://3v4l.org/f4WIC
What you are referring to as enum value is actually a backed value for an
enum instance.
If you would define the enum as
enum Fruit: string
{
case Apple = 'apple';
case Banana = 'banana';
}
You could obtain the value with Fruit::Apple->value. But I'm not
referring to this.
So going back to the topic I mentioned, a constant can right now be an
object.
It can be only an enum instance for now but I believe that in the near
future we will be able to have any object there.
Also, self and parent would make sense for valid typed constants, just like
they do work on properties.
Regards,
Alex
Of note is the "Inheritance and variance" section, which details uses
with
abstracts and interfaces, plus the "Constant values" section which
includes
details about errors.--
Guilliam XavierThanks,
Alex
Alex,
On Wed, Mar 30, 2022 at 7:47 AM Alexandru Pătrănescu drealecs@gmail.com
wrote:
Hey Mark,
On Wed, Mar 30, 2022 at 4:01 PM Mark Niebergall mbniebergall@gmail.com
wrote:Alex,
On Tue, Mar 29, 2022 at 10:35 PM Alexandru Pătrănescu drealecs@gmail.com
wrote:Hey Mark,
On Wed, Mar 30, 2022 at 6:03 AM Mark Niebergall mbniebergall@gmail.com
wrote:I have updated the RFC https://wiki.php.net/rfc/typed_class_constants
with
more details and examples from this thread, and updated the RFC status
to
Under Discussion. Hopefully the updated RFC helps answer questions and
clarifies what the proposal includes.Thanks for the RFC and the drive here.
I personally see the benefit and I think it would be a nice addition.I think you should also update the "Supported types" section.
Starting with enums, constants can also be objects. Once a good
technical solution is found, any object would be supported probably
https://wiki.php.net/rfc/new_in_initializers#future_scope
I think that only void, never and callable types should not be
supported, just like on properties.I have updated the "Supported types" to list out all types that are
supported and which types are not supported.Constants cannot be objects since objects are mutable, so typed constants
will not be allowed to be an enum (which is technically an object). A typed
constant may be an enum value though, so the following example will be
valid:enum Fruit { case Apple; case Banana; } class Colors { protected const string RED = Fruit::Apple; protected const string YELLOW = Fruit::Banana; }
Actually, Fruit::Apple is an enum instance and that is an object that is
of Fruit enum type (Fruit class).
You can check this as it's already possible in PHP 8.1, even if it's not
yet possible to have them with type: https://3v4l.org/f4WICWhat you are referring to as enum value is actually a backed value for an
enum instance.
If you would define the enum asenum Fruit: string { case Apple = 'apple'; case Banana = 'banana'; }
You could obtain the value with Fruit::Apple->value. But I'm not
referring to this.So going back to the topic I mentioned, a constant can right now be an
object.
It can be only an enum instance for now but I believe that in the near
future we will be able to have any object there.
Ah yes, you are correct, my mistake. I will need to make some more updates
to the RFC page to address that.
Also, self and parent would make sense for valid typed constants, just
like they do work on properties.
I'll add examples and an item about this as well.
Regards,
AlexOf note is the "Inheritance and variance" section, which details uses
with
abstracts and interfaces, plus the "Constant values" section which
includes
details about errors.--
Guilliam XavierThanks,
Alex
Hi Mark,
I have updated the RFC https://wiki.php.net/rfc/typed_class_constants with
more details and examples from this thread, and updated the RFC status to
Under Discussion. Hopefully the updated RFC helps answer questions and
clarifies what the proposal includes.
Thanks (I assume that you talked with the original author) -- not sure if
you should have started a new thread with the "[RFC]" tag in the subject?
I think you should also update the "Supported types" section.
Starting with enums, constants can also be objects. Once a good technical
solution is found, any object would be supported probably
https://wiki.php.net/rfc/new_in_initializers#future_scope
I think that only void, never and callable types should not be supported,
just like on properties.I have updated the "Supported types" to list out all types that are
supported and which types are not supported.
A few comments, by subsection:
-
Supported types: This corresponds to the types currently allowed
for const values (as well as unions thereof) except it [still] doesn't
mention enums (which internally are classes implementing theUnitEnum
interface, and whose values are ultimately ofobject
type) although
currently allowed. It also doesn't mentionmixed
(used later in examples). -
Strict and coercive typing modes: I didn't understand it on first
read; I had to read the later "Constant values" section and compare both
with
https://wiki.php.net/rfc/typed_properties_v2#strict_and_coercive_typing_modes
and https://wiki.php.net/rfc/typed_properties_v2#default_values -
Inheritance and variance: Several occurrences of "Class constants"
should probably be "Typed class constants". Also, I still think that
protected bool $isExtinct
is not a good parallel topublic const bool CAN_FLY
(see my previous message). -
Constant values: You should probably remove the
iterable
example
now [and maybe add anenum
one].
Constants cannot be objects since objects are mutable, so typed constants
will not be allowed to be an enum (which is technically an object). A typed
constant may be an enum value though, so the following example will be
valid:enum Fruit { case Apple; case Banana; } class Colors { protected const string RED = Fruit::Apple; protected const string YELLOW = Fruit::Banana; }
This is incorrect, Fruit::Apple
is of type Fruit
(ultimately object
),
not string
. But it is not mutable, and is allowed as a const value
currently.
Besides, I realized that the RFC is [only] for class constants; what
about namespaced (and global) constants?
Regards,
--
Guilliam Xavier
Guilliam,
On Wed, Mar 30, 2022 at 7:50 AM Guilliam Xavier guilliam.xavier@gmail.com
wrote:
Hi Mark,
I have updated the RFC https://wiki.php.net/rfc/typed_class_constants with
more details and examples from this thread, and updated the RFC status
to
Under Discussion. Hopefully the updated RFC helps answer questions and
clarifies what the proposal includes.Thanks (I assume that you talked with the original author) -- not sure if
you should have started a new thread with the "[RFC]" tag in the subject?
I will address the issues from you and Alex in the RFC page, then start a
new thread with "[RFC]" since you are correct this has moved past
initial testing-the-waters and is now into the discussion phase about the
RFC. I reached out multiple times to the original author but have not
received a response. I did leave Benas as an author to give him credit for
the work he did.
I think you should also update the "Supported types" section.
Starting with enums, constants can also be objects. Once a good
technical solution is found, any object would be supported probably
https://wiki.php.net/rfc/new_in_initializers#future_scope
I think that only void, never and callable types should not be
supported, just like on properties.I have updated the "Supported types" to list out all types that are
supported and which types are not supported.A few comments, by subsection:
- Supported types: This corresponds to the types currently allowed
for const values (as well as unions thereof) except it [still] doesn't
mention enums (which internally are classes implementing theUnitEnum
interface, and whose values are ultimately ofobject
type) although
currently allowed. It also doesn't mentionmixed
(used later in examples).- Strict and coercive typing modes: I didn't understand it on first
read; I had to read the later "Constant values" section and compare both
with
https://wiki.php.net/rfc/typed_properties_v2#strict_and_coercive_typing_modes
and https://wiki.php.net/rfc/typed_properties_v2#default_values- Inheritance and variance: Several occurrences of "Class constants"
should probably be "Typed class constants". Also, I still think that
protected bool $isExtinct
is not a good parallel topublic const bool CAN_FLY
(see my previous message).- Constant values: You should probably remove the
iterable
example
now [and maybe add anenum
one].
Thanks for the input, I'll work on addressing those.
Constants cannot be objects since objects are mutable, so typed constants
will not be allowed to be an enum (which is technically an object). A typed
constant may be an enum value though, so the following example will be
valid:enum Fruit { case Apple; case Banana; } class Colors { protected const string RED = Fruit::Apple; protected const string YELLOW = Fruit::Banana; }
This is incorrect,
Fruit::Apple
is of typeFruit
(ultimately
object
), notstring
. But it is not mutable, and is allowed as a
const value currently.
Yes, Alex also identified this issue in my examples, I will correct that
and include enum examples in an updated RFC. I will do that before starting
an "[RFC]" thread.
Besides, I realized that the RFC is [only] for class constants; what
about namespaced (and global) constants?
Ah yes, I hadn't considered expanding this RFC to namespaced and global
constants. Let me mull over implementation syntax for those and include
them in the RFC. My initial reaction is to not include those in this RFC,
keeping the scope to just class constants. If there is value in typing
namespaced and global constants, then another RFC could add those.
Once I have all these new issues figured out and the RFC updated, I'll
start that new thread.
Regards,
--
Guilliam Xavier
Ah yes, I hadn't considered expanding this RFC to namespaced and global
constants. Let me mull over implementation syntax for those and include
them in the RFC. My initial reaction is to not include those in this RFC,
keeping the scope to just class constants. If there is value in typing
namespaced and global constants, then another RFC could add those.
Yes, it could be simply a mention in a "Future scope" (or even "Unaffected
functionality") section
(and the syntax could indeed be a problem, like for typed local/global
variables...)
Once I have all these new issues figured out and the RFC updated, I'll
start that new thread.
Looking forward to it =)
Le 23/03/2022 à 23:10, Larry Garfield a écrit :
Is there a benefit to it other than "well everything else has types now, so..."? Even if it's esoteric, like in reflection-based meta programming? (I've been dabbling too much in that lately. :-) ) "Everything else does" isn't a compelling argument for me, but there may be others I'm not thinking of.
--Larry Garfield
Hello,
Well I was thinking myself that const being well... constant, and so
always defined, type could be determined at compile time without the
need to express it in a verbose way.
PHP doesn't do any static type inference, but in this case, it could be
done almost for free, am I wrong ? If it was determined at compile time,
then the type checking on overrides would only be trivial, using the
parent occurrence value inferred type. My point is that there's no need
to express the type of a value, the value has already has a type.
Regards,
--
Pierre
Pierre,
Le 23/03/2022 à 23:10, Larry Garfield a écrit :
Is there a benefit to it other than "well everything else has types now,
so..."? Even if it's esoteric, like in reflection-based meta programming?
(I've been dabbling too much in that lately. :-) ) "Everything else does"
isn't a compelling argument for me, but there may be others I'm not
thinking of.--Larry Garfield
Hello,
Well I was thinking myself that const being well... constant, and so
always defined, type could be determined at compile time without the
need to express it in a verbose way.PHP doesn't do any static type inference, but in this case, it could be
done almost for free, am I wrong ? If it was determined at compile time,
then the type checking on overrides would only be trivial, using the
parent occurrence value inferred type. My point is that there's no need
to express the type of a value, the value has already has a type.
As a developer, I don't always trust other developers implementing my
code. Referring back to the Bird and EmperorPenguin example, the expected
type for public const bool CAN_FLY;
example MUST be a bool. If it isn't
typed, another developer could incorrectly set CAN_FLY = 1;
or CAN_FLY = 'true';
or even CAN_FLY = 'Y';
. With class constants typed, they would
get an error if setting it to anything other than a bool CAN_FLY = true;
or CAN_FLY = false;
. This further proliferates into sending the value of
CAN_FLY
into a typed argument like protected function determineModeOfTransport(bool $canFly)
- if the constant is set
incorrectly as a string or integer then more errors can occur.
Typing class constants could also help static code analyzers more easily
determine if there are bugs with unexpected value types being used in code.
Instead of determining the value of the constant, the type of the constant
could be used instead, providing a cleaner tokenized parsing.
So you are correct, the const value does have a value that has a type, but
there is no way to enforce which type the value is or to use const with
inheritance, which is part of the bigger picture here.
Regards,
--
Pierre
--
To unsubscribe, visit: https://www.php.net/unsub.php
Le 24/03/2022 à 16:06, Mark Niebergall a écrit :
So you are correct, the const value does have a value that has a type, but
there is no way to enforce which type the value is or to use const with
inheritance, which is part of the bigger picture here.
That was exactly my point: the type could simply implicitely be the one
of the original value.
Then the engine just has to use the existing covariance/contravariance
rules for type checks based upon the guessed value type. This would fix
the type safety issue you are referring to.
--
Regards
Pierre,
Le 24/03/2022 à 16:06, Mark Niebergall a écrit :
So you are correct, the const value does have a value that has a type,
but
there is no way to enforce which type the value is or to use const with
inheritance, which is part of the bigger picture here.That was exactly my point: the type could simply implicitely be the one
of the original value.Then the engine just has to use the existing covariance/contravariance
rules for type checks based upon the guessed value type. This would fix
the type safety issue you are referring to.
I'd rather not use the "guessed value type" in code, that tends to lead to
bugs: guessing = bugs. Explicitly declaring the type avoids the pitfalls of
guessing and ensures code predictability. It also comes with added
benefits, including self-documenting code, defined inheritance requirements
(the way you describe would have BC breakage), and (for some IDEs) type
hinting.
Of note, many other languages already have typed constants. Yes this is the
"everyone else is doing it" argument, but they had their valid reasons.
Some are strong typed languages, others are not. See:
- Go: https://go.dev/blog/constants
- HVVM: https://docs.hhvm.com/hack/classes/type-constants
- C: https://fresh2refresh.com/c-programming/c-constants/
- C++: https://en.cppreference.com/w/c/language/const
- C#:
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/const
--
Regards
Pierre,
Le 24/03/2022 à 16:06, Mark Niebergall a écrit :
So you are correct, the const value does have a value that has a type,
but
there is no way to enforce which type the value is or to use const with
inheritance, which is part of the bigger picture here.That was exactly my point: the type could simply implicitely be the one
of the original value.Then the engine just has to use the existing covariance/contravariance
rules for type checks based upon the guessed value type. This would fix
the type safety issue you are referring to.I'd rather not use the "guessed value type" in code, that tends to lead to
bugs: guessing = bugs. Explicitly declaring the type avoids the pitfalls of
guessing and ensures code predictability. It also comes with added
benefits, including self-documenting code, defined inheritance requirements
(the way you describe would have BC breakage), and (for some IDEs) type
hinting.Of note, many other languages already have typed constants. Yes this is the
"everyone else is doing it" argument, but they had their valid reasons.
Some are strong typed languages, others are not. See:
The addition of union types put the kibosh on successfully type guessing, I think. If you have a const that you'll allow a float or int in, and the default is 0, the guesser will guess int, not float, and then you can't allow a float.
So "constant inheritance" is a use case for typed constants, even if constant inheritance is a rather edge-case situation to begin with.
--Larry Garfield
That was exactly my point: the type could simply implicitely be the one
of the original value.
That works when the initial value is a literal, but what about when it's
another cost?
class Foo {
const BAR = Baz::BAR;
const BLING = MY_QUX;
}
What type are Foo::BAR and Foo::BLING? Suddenly these constants have
dependent type and resolving it becomes less trivial.
Also, what happens when this code is originally written when MY_QUX is a
string, but then gets redefined (because it lives in another library we
don't control).
Allowing the author to put an explicit type removes all that uncertainty.
-Sara
The next phase of work with different RFC would take
this further with const inheritance, where const type must match.
I'm not sure it makes much sense to split this into two RFCs, and as far
as I can see, the previous RFC included both features:
Class constants are covariant. This means that the type of a class
constant is not allowed to be widen during inheritance.
Or is there something more you mean by "const inheritance", which isn't
covered by the RFC's examples?
Regards,
--
Rowan Tommins
[IMSoP]
On Thu, Mar 24, 2022 at 1:00 PM Rowan Tommins rowan.collins@gmail.com
wrote:
The next phase of work with different RFC would take
this further with const inheritance, where const type must match.I'm not sure it makes much sense to split this into two RFCs, and as far
as I can see, the previous RFC included both features:Class constants are covariant. This means that the type of a class
constant is not allowed to be widen during inheritance.Or is there something more you mean by "const inheritance", which isn't
covered by the RFC's examples?
Agreed, the more discussion that is going on, the more I'm leaning towards
to see this implemented in a single RFC. The true value comes with the full
feature set.
Correct the original RFC discusses some inheritance, but didn't expand it
out the way I'm thinking. It only details ensuring the concrete class has a
matching type. I'm proposing additionally allowing blank values to be set
by the concrete class.
Existing draft RFC (https://wiki.php.net/rfc/typed_class_constants):
class Test {
private const int A = 1;
public const mixed B = 1;
public const int C = 1;
}
class Test2 extends Test {
// this is legal (because Test::A is private)
public const string A = 'a';
// this is legal
public const int B = 0;
// this is illegal
public const mixed C = 0;
}
What I'm proposing would further allow const without values in abstracts
and interfaces, which require concrete classes to have a value:
abstract class Test
{
private const int A = 1;
public const mixed B = 1;
public const int C = 1;
// no value set, this is legal, concrete classes must set value
public const int D;
}
interface TestInterface
{
// no value set, this is legal
public const string NAME;
}
class Test2 extends Test implements TestInterface
{
// this is legal (because Test::A is private)
public const string A = 'a';
// this is legal
public const int B = 0;
// these are required due to inheritance
public const int D = 5;
public const string NAME = 'EmperorPenguin';
// this is illegal
public const mixed C = 0;
}
Regards,
--
Rowan Tommins
[IMSoP]--
To unsubscribe, visit: https://www.php.net/unsub.php