Hi internals!
I already brought this up before, but I think the discussion at that time
was not very constructive and largely off-topic, so I'm bringing it up
again. To make sure everything is clear I wrote an RFC document:
https://wiki.php.net/rfc/propertygetsetsyntax-alternative-typehinting-syntax
This RFC proposes an alternative syntax for typehinting accessors, which
will in particular also allow to typehint properties directly, even if no
accessors are used (public DateTime $date).
What are your opinions on this?
Thanks,
Nikita
This proposal looks really good to me. It cuts out a lot of syntax and
boilerplate for a commonly used case. However, there is one issue that
I know somebody is going to raise:
Argument: If you change the value of the property without using the
setter then get
could return something that has a type mismatch with
the type-hint.
If I understand the current RFC for properties correctly, the only
place that a property can be directly written to without the accessor
is inside of the __setProperty
method. This almost nullifies the
argument completely.
The only other place for possible error would be assigning a value in
the constructor that does not match the type-hint. However, because
we adding a new syntax we could disallow assigning a value if it
really was that problematic. I do not personally feel that would be
necessary.
I feel that this argument is not weighty enough to stop the proposal
for this improved syntax.
This shouldn't be an issue because it is not possible to set the
property without going through the setter, which would be a type hinted
accessor function.
Ergo, an attempt to set the value to an invalid value would cause a
fatal error and thus the setter would not be able to then set it to the
invalid value.
This proposal looks really good to me. It cuts out a lot of syntax and
boilerplate for a commonly used case. However, there is one issue that
I know somebody is going to raise:Argument: If you change the value of the property without using the
setter thenget
could return something that has a type mismatch with
the type-hint.If I understand the current RFC for properties correctly, the only
place that a property can be directly written to without the accessor
is inside of the__setProperty
method. This almost nullifies the
argument completely.The only other place for possible error would be assigning a value in
the constructor that does not match the type-hint. However, because
we adding a new syntax we could disallow assigning a value if it
really was that problematic. I do not personally feel that would be
necessary.I feel that this argument is not weighty enough to stop the proposal
for this improved syntax.
--
-Clint
Hi!
This shouldn't be an issue because it is not possible to set the
property without going through the setter, which would be a type hinted
accessor function.
It is possible, if this property's guard is set. Since guard works for
all code called from inside the setter, if setter is doing something not
trivial (meaning, calls any functions, explicitly or implicitly) it is
possible to set the property directly. Since the value you are getting
is defined by the getter, there are no guarantees there too. So
effectively, unless both getter and setter are implicit, this does not
give you anything compared to the typed setter.
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
Hi!
This shouldn't be an issue because it is not possible to set the
property without going through the setter, which would be a type hinted
accessor function.
It is possible, if this property's guard is set. Since guard works for
all code called from inside the setter, if setter is doing something not
trivial (meaning, calls any functions, explicitly or implicitly) it is
possible to set the property directly. Since the value you are getting
is defined by the getter, there are no guarantees there too. So
effectively, unless both getter and setter are implicit, this does not
give you anything compared to the typed setter.
I think I was referring to the possibility I mentioned in another email
about a second call to a getter which was already guarded would return
NULL
and likewise a second call to a setter which was already being
guarded would do whatever __set() does...? Ignored?
--
-Clint
Would the following two be exactly functionally equivalent?
public Foo $foo;
public $foo {
get;
set(Foo $value) { $this->foo = $value; }
}
We should also consider how an author would allow type-hinted properties to accept NULL
as a new value, in both proposals.
Steve
Hi internals!
I already brought this up before, but I think the discussion at that time
was not very constructive and largely off-topic, so I'm bringing it up
again. To make sure everything is clear I wrote an RFC document:https://wiki.php.net/rfc/propertygetsetsyntax-alternative-typehinting-syntax
This RFC proposes an alternative syntax for typehinting accessors, which
will in particular also allow to typehint properties directly, even if no
accessors are used (public DateTime $date).What are your opinions on this?
Thanks,
Nikita
We should also consider how an author would allow type-hinted properties to accept
NULL
as a new value, in both proposals.
public $foo {
get;
set(Foo $value = NULL) { $this->foo = $value; }
}
Would work for traditional type-hints.
We should also consider how an author would allow type-hinted properties to accept
NULL
as a new value, in both proposals.public $foo {
get;
set(Foo $value = NULL) { $this->foo = $value; }
}Would work for traditional type-hints.
I just realized that unset
would actually have a use here. Rather
than setting something to null
you would unset
it.
Would the following two be exactly functionally equivalent?
public Foo $foo;
public $foo {
get;
set(Foo $value) { $this->foo = $value; }
}We should also consider how an author would allow type-hinted properties
to acceptNULL
as a new value, in both proposals.
I think that's a very interesting question, thanks for bringing it up. I
think a good approach here would be the same one used for function argument
typehints, i.e. allow NULL
when NULL
is specified as the default value. So
public DateTime $date;
would not allow an explicit NULL
assignment,
whereas public DateTime $date = NULL;
would.
Nikita
2013/1/5 Nikita Popov nikita.ppv@gmail.com
I think that's a very interesting question, thanks for bringing it up. I
think a good approach here would be the same one used for function argument
typehints, i.e. allowNULL
whenNULL
is specified as the default value. So
public DateTime $date;
would not allow an explicitNULL
assignment,
whereaspublic DateTime $date = NULL;
would.
I was wondering about this question too. I really like that solution.
Bernhard
Hi!
typehints, i.e. allow
NULL
whenNULL
is specified as the default value. So
public DateTime $date;
would not allow an explicitNULL
assignment,
whereaspublic DateTime $date = NULL;
would.
I think this is way too much magic. This means default is no longer a
default, but instead some obscure flag that somehow is carried over to
the setter. I do not think redefining initialization as permitting nulls
is a good idea, initialization and value set are two different things.
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
Stas,
I think this is way too much magic. This means default is no longer a
default, but instead some obscure flag that somehow is carried over to
the setter. I do not think redefining initialization as permitting nulls
is a good idea, initialization and value set are two different things.
"Too much magic"? It's completely consistent with how method parameters
work now. In fact, I'd argue that introducing a new syntax for this would
be inconsistent with the current paradigm.
This becomes especially true if initializers are added, where the property
would be initialized to a non-null value. Hence adding the ability for it
to never actually be null in the first place...
Anthony
Hi!
"Too much magic"? It's completely consistent with how method parameters
work now. In fact, I'd argue that introducing a new syntax for this
would be inconsistent with the current paradigm.
But this in for methods, and you are putting it into entirely different
place - property initializer. That's what I call magic - somehow
property initializer magically becomes method parameter's default value.
This becomes especially true if initializers are added, where the
property would be initialized to a non-null value. Hence adding the
ability for it to never actually be null in the first place...
I think property initializers won't work well, especially combined with
this syntax. What should public DateTime $foo = 42; produce?
Essentially it looks like the only initializer useful here would be
NULL. In this case, why not just make it simple and always allow NULL
there and get rid of the confusing syntax? You'd have to allow NULL
anyway since otherwise you'd be unable to implement unset() and won't
have any useful isset(). In fact, initial value of any object property
will always be NULL, so not allowing NULL
is pointless as there's always
NULL
there when you start.
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
Stas,
But this in for methods, and you are putting it into entirely different
place - property initializer. That's what I call magic - somehow
property initializer magically becomes method parameter's default value.
The same could be used to justify the param order difference between
strings and arrays "But these are arrays, they are entirely different"...
This becomes especially true if initializers are added, where the
property would be initialized to a non-null value. Hence adding the
ability for it to never actually be null in the first place...I think property initializers won't work well, especially combined with
this syntax. What should public DateTime $foo = 42; produce?
A compile time fatal error. If it's typed, the only values allowed are the
type and null (in the initializer)
Essentially it looks like the only initializer useful here would be
NULL. In this case, why not just make it simple and always allowNULL
there and get rid of the confusing syntax? You'd have to allowNULL
anyway since otherwise you'd be unable to implement unset() and won't
have any useful isset(). In fact, initial value of any object property
will always be NULL, so not allowingNULL
is pointless as there's always
NULL
there when you start.
No, the other initializer that would be useful is new Foo
. Assigning a
default value is not an initializer. An initializer is something that's run
on object construction (and has been discussed in other threads):
class Foo {
public DateTime $bar {
init: { $bar = new DateTime(); }
}
}
As far as "why not just make it always allow null" is that it half defeats
the point of typed accessors in the first place. Java has huge issues with
null pointers. And if you set the property in the constructor (and it's
typed), you should never have the chance for it to be non-null, unless you
explicitly define it that way. Otherwise, you'd have to litter your code
with is_null checks... Which defeats the point of the syntax in the first
place. Sure, there are going to be use-cases for supporting null. But there
are also plenty of use-cases for explicitly Not allowing null. In fact, I'd
argue that the "not allow null" use-cases are the most frequent and most
critical ones...
Anthony
Hi!
No, the other initializer that would be useful is
new Foo
. Assigning a
You really put it in the same answer as telling me it's the same as
parameter defaults? Here you introduce completely new concept, not
existing in PHP at all - non-constant initializers. And this is a whole
new can of worms - when it should be run, what should happen when it's
run, what is the order, etc. And we already have a perfectly good place
to do this - constructors. We don't really need this whole new level of
complications with dynamic initializers, just do it in the constructor.
As far as "why not just make it always allow null" is that it half
defeats the point of typed accessors in the first place. Java has huge
Of course it does not. It would be really useless addition if the whole
point of it was not allowing nulls in variables, and pointless too,
since there's no way do to it. Even with initializers, how you guarantee
that no code is run before your initializer? Like another initializer?
You can not. So you always have a possibility of having null. It is true
in any language, not just Java - pretty much any language that has
object types also has "empty" value.
issues with null pointers. And if you set the property in the
constructor (and it's typed), you should never have the chance for it to
be non-null, unless you explicitly define it that way. Otherwise, you'd
And you will have to ensure constructor never accesses this property,
constructor can never be extended with a code that uses this property,
constructor never calls any outside method that may use this property,
etc., etc. The complexity of this "solution" quickly gets out of hand
and does not guarantee anything in fact. And now you also have to deal
with unset() failing with a fatal error, too.
explicitly Not allowing null. In fact, I'd argue that the "not allow
null" use-cases are the most frequent and most critical ones...
If the whole point of this feature is to save is_null check, I do not
think we need it in PHP, since it can not guarantee it, and it does much
more and changes much more in the language than simple is_null check.
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
Stas,
You really put it in the same answer as telling me it's the same as
parameter defaults? Here you introduce completely new concept, not
existing in PHP at all - non-constant initializers. And this is a whole
new can of worms - when it should be run, what should happen when it's
run, what is the order, etc. And we already have a perfectly good place
to do this - constructors. We don't really need this whole new level of
complications with dynamic initializers, just do it in the constructor.
I didn't introduce it. It was introduced in another thread about this very
same RFC.
As far as "introduce completely new concept, not existing in PHP at all",
that's the entire purpose of an RFC. That's what we're doing right here.
We're talking about introducing new functionality and features that may
make people's lives easier. So to discuss the feature, yet limit it to not
including new functionality, is rather odd...
As far as "why not just make it always allow null" is that it half
defeats the point of typed accessors in the first place. Java has hugeOf course it does not. It would be really useless addition if the whole
point of it was not allowing nulls in variables, and pointless too,
since there's no way do to it. Even with initializers, how you guarantee
that no code is run before your initializer? Like another initializer?
You can not. So you always have a possibility of having null. It is true
in any language, not just Java - pretty much any language that has
object types also has "empty" value.
You always have the possibility of having null before the object is
constructed. That's given.
But after the constructor finishes, you can actually guarantee that the
property is never null. For example:
class Foo {
private $other;
final public function __construct() {
$this->other = new Other;
}
}
What case, other than reflection abuse, is $this->other ever null after
construction? The only case is when the class itself sets it to null. Which
is quite easy to check for when looking at the class.
Having an empty type, and having it be able to be set on anything are two
very different concepts. Take for example method type hinting:
function foo(Bar $bar) {}
In PHP, inside foo(), $bar will never be anything except an instance of
Bar. It's not possible. Trying to pass Null would generate a catchable
fatal: http://codepad.viper-7.com/Le3jC1
This concept is just an exception of that. After construction, if the
property is not declared with = NULL, it's never allowed to be set to it.
Simple as that. It's the same thing as setting the setter to a function
which type hints against Bar $bar instead of Bar $bar = NULL;
issues with null pointers. And if you set the property in the
constructor (and it's typed), you should never have the chance for it to
be non-null, unless you explicitly define it that way. Otherwise, you'dAnd you will have to ensure constructor never accesses this property,
constructor can never be extended with a code that uses this property,
constructor never calls any outside method that may use this property,
etc., etc. The complexity of this "solution" quickly gets out of hand
and does not guarantee anything in fact. And now you also have to deal
with unset() failing with a fatal error, too.
No language can protect you from yourself. If you do something inside the
class that screws everything up, then you're SOL. That's not what this
concept is about. It's about me as the class writer knowing that nobody
outside my class can screw it up. I know that if I write my code correctly,
that nobody can set it to null and screw me up.
As far as unset failing, we already have the ability to do that right now
with __unset(). All this is doing is applying it to the implicit
declaration when providing a type-hinted property variable...
explicitly Not allowing null. In fact, I'd argue that the "not allow
null" use-cases are the most frequent and most critical ones...If the whole point of this feature is to save is_null check, I do not
think we need it in PHP, since it can not guarantee it, and it does much
more and changes much more in the language than simple is_null check.
No. The whole point of this is to make defensive coding easier. We can do
it today with a combination of __get, __set, __unset. But that's dirty as
hell, and leads to LOTS of code doing the same thing over and over again.
Instead, we're looking at techniques that make peoples lives easier by
reducing the boilerplate that they need to write. Just like the generators
RFC... Generators don't provide anything that isn't already possible with
iterators. They just make the amount of boilerplate required a LOT lower.
And this concept does the same. And that doesn't even make mention of the
performance gains by having the getter/setter be written in C instead of
PHP...
Anthony
Hi!
As far as "introduce completely new concept, not existing in PHP at
all", that's the entire purpose of an RFC. That's what we're doing right
here. We're talking about introducing new functionality and features
that may make people's lives easier. So to discuss the feature, yet
limit it to not including new functionality, is rather odd...
You can not both say "it works just like method parameters" and in the
same breath say it needs the concept of dynamic initializers which never
existed in PHP and which BTW was not introduced in the RFC either (and
which won't solve the problem you're trying to solve anyway).
You always have the possibility of having null before the object is
constructed. That's given.
Not before. While initialization is running. Which can be quite a
complex process. E.g. look at SoapClient class - it parses whole WSDL in
the constructor. Imagine you implemented something like this - there
would be a bunch of things happening while object is being constructed.
But after the constructor finishes, you can actually guarantee that the
property is never null. For example:
You can only guarantee it if you know ctor actually assigned the
variable, but there's no way to check it in the code. I.e. if you
manually reviewed the code, you can know it, but declaration itself in
no way guarantees it, even though you were thinking it does.
So for it to be actually useful, you need to know that ctor has already
finished working and that that ctor actually assigned value to this
property. And if you are third-party library using this class as an API,
it's not very useful for you unless you code-review all third-party
libraries you use. Declaration itself does not guarantee it, even if it
looks and is promoted as if it did.
In PHP, inside foo(), $bar will never be anything except an instance
of Bar. It's not possible. Trying to pass Null would generate a
catchable fatal: http://codepad.viper-7.com/Le3jC1
Again, for parameters you MUST provide parameter to call a function,
otherwise function would not be called. So there's no way the control
can enter the function and $bar not be assigned to instance of Bar,
whatever the code around it is doing, however crazy it is. On the
contrary, it is very easy to find scenario where property is declared as
"public Bar $bar;" and still contains null. Unlike parameters, again,
the declaration itself DOES NOT guarantee the property is not null.
This concept is just an exception of that. After construction, if the
property is not declared with = NULL, it's never allowed to be set to
it. Simple as that. It's the same thing as setting the setter to a
function which type hints against Bar $bar instead of Bar $bar = NULL;
But that's not very useful. Who cares if it can't be set to null if it
can still be null? You'll have to check it anyway. Or, even worse,
you'll rely on your own insistence that it can not be null and get fatal
error in production code.
As far as unset failing, we already have the ability to do that right
now with __unset(). All this is doing is applying it to the implicit
declaration when providing a type-hinted property variable...
With __unset, you will have to specifically write code to do that. Here,
it is a side effect of a declaration that has nothing to do with unset
and it is completely unobvious to 99.999% of the users that this is what
will happen.
No. The whole point of this is to make defensive coding easier. We can
But you don't make it easier if you're making promises you can not keep,
such as "this value will never be null".
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
Stas,
You can not both say "it works just like method parameters" and in the
same breath say it needs the concept of dynamic initializers which never
existed in PHP and which BTW was not introduced in the RFC either (and
which won't solve the problem you're trying to solve anyway).
I never said it needed dynamic initializers. I said it would be cool if
it had them, but the concept stands on its own without them.
You always have the possibility of having null before the object is
constructed. That's given.Not before. While initialization is running. Which can be quite a
complex process. E.g. look at SoapClient class - it parses whole WSDL in
the constructor. Imagine you implemented something like this - there
would be a bunch of things happening while object is being constructed.
You miss the key point here. It's not that it can't happen, it's that
nothing outside your code can interfere. If you set it in your
constructor, it's set. If you don't, it's not. But it's on your shoulders...
But after the constructor finishes, you can actually guarantee that the
property is never null. For example:You can only guarantee it if you know ctor actually assigned the
variable, but there's no way to check it in the code. I.e. if you
manually reviewed the code, you can know it, but declaration itself in
no way guarantees it, even though you were thinking it does.
So for it to be actually useful, you need to know that ctor has already
finished working and that that ctor actually assigned value to this
property. And if you are third-party library using this class as an API,
it's not very useful for you unless you code-review all third-party
libraries you use. Declaration itself does not guarantee it, even if it
looks and is promoted as if it did.
There's no way to check lots of things unless you look at the code. In
fact, there's tons of more pressing issues then this. What if the code
calls shell_exec("rm -rf /");... OMG!!!
The point I'm trying to get at here, is this is not about trying to defend
yourself from yourself. It's about trying to let you write code easily that
defends yourself from others. Simple as that...
And as far as revewing 3pd libraries, if they fatal, that's on them. I'm
talking about preventing my class from fataling. That's all that I can
ever hope to do anyway...
In PHP, inside foo(), $bar will never be anything except an instance
of Bar. It's not possible. Trying to pass Null would generate a
catchable fatal: http://codepad.viper-7.com/Le3jC1Again, for parameters you MUST provide parameter to call a function,
otherwise function would not be called. So there's no way the control
can enter the function and $bar not be assigned to instance of Bar,
whatever the code around it is doing, however crazy it is. On the
contrary, it is very easy to find scenario where property is declared as
"public Bar $bar;" and still contains null. Unlike parameters, again,
the declaration itself DOES NOT guarantee the property is not null.
You're mincing words here. The point I was making in the email you replied
to wasn't that the variable couldn't contain NULL, but that it could never
be assigned null. A very different concept...
This concept is just an exception of that. After construction, if the
property is not declared with = NULL, it's never allowed to be set to
it. Simple as that. It's the same thing as setting the setter to a
function which type hints against Bar $bar instead of Bar $bar = NULL;But that's not very useful. Who cares if it can't be set to null if it
can still be null? You'll have to check it anyway. Or, even worse,
you'll rely on your own insistence that it can not be null and get fatal
error in production code.
I don't need to check it if I know that it was set before I get to that
point (such as in the constructor).
As far as unset failing, we already have the ability to do that right
now with __unset(). All this is doing is applying it to the implicit
declaration when providing a type-hinted property variable...With __unset, you will have to specifically write code to do that. Here,
it is a side effect of a declaration that has nothing to do with unset
and it is completely unobvious to 99.999% of the users that this is what
will happen.
It's completely unobvious because it's not documented. Simple as that...
And if you have a better alternative to signify the ability to pass null or
not, I'm all ears. Would public nullable Foo $foo; be better? Or public
not-nullable Foo $foo be better?
What we're trying to do here is make life easier for the 99% use case. Not
the far edge-cases that you've presented so far...
No. The whole point of this is to make defensive coding easier. We can
But you don't make it easier if you're making promises you can not keep,
such as "this value will never be null".
Again, nobody promised "this value will never be null". What we're talking
about is the promise that it can never be assigned null. A big difference...
Please, stop grasping at straws. If you can come up with a non-edge case
scenario where this breaks down, by all means let's discuss this. But red
herrings like you have proposed so far do no good but dilute the
discussions...
Anthony
No, the other initializer that would be useful is
new Foo
. Assigning a
default value is not an initializer. An initializer is something that's run
on object construction (and has been discussed in other threads):class Foo {
public DateTime $bar {
init: { $bar = new DateTime(); }
}
}
I think property init() would enable two bad practices:
- putting too much logic in a property (SRP)
- building dependencies within the object instead of injecting them (the better way is
what we already do: receive dependencies in the constructor and assign them to the properties)
null pointers. And if you set the property in the constructor (and it's
typed), you should never have the chance for it to be non-null, unless you
explicitly define it that way. Otherwise, you'd have to litter your code
with is_null checks... Which defeats the point of the syntax in the first
Which is why I think the default setting signature should not have "= null". If someone
wants to allow setting the property back to null, they could easily:
public Foo $foo {
get;
set($value = null);
}
I agree with you that, in an ideal world, a property with a declared type would never not
have that type, but I think a property init() would be a bad tradeoff to make that a reality.
The class constructor is the best place to do this, and maybe this is why C# forces
property storage to be in fields; you can set fields directly from the constructor without
going through property setters.
Steve Clay
On Sun, Jan 6, 2013 at 1:18 AM, Stas Malyshev smalyshev@sugarcrm.comwrote:
Hi!
"Too much magic"? It's completely consistent with how method parameters
work now. In fact, I'd argue that introducing a new syntax for this
would be inconsistent with the current paradigm.But this in for methods, and you are putting it into entirely different
place - property initializer. That's what I call magic - somehow
property initializer magically becomes method parameter's default value.This becomes especially true if initializers are added, where the
property would be initialized to a non-null value. Hence adding the
ability for it to never actually be null in the first place...I think property initializers won't work well, especially combined with
this syntax. What should public DateTime $foo = 42; produce?
Consider the normal function typehints: function foo(DateTime $foo = 42)
.
Same problem, same solution. You can only assign "compatible" types. For
object typehints NULL
is the only compatible compile-time value. For array
typehints arrays can be used as initializers.
Essentially it looks like the only initializer useful here would be
NULL. In this case, why not just make it simple and always allowNULL
there and get rid of the confusing syntax?
Again, same for function typehints. NULL
is the only possible initializer
there, too. But still we don't take that as a reason to always allow NULL
for them.
You'd have to allow NULL
anyway since otherwise you'd be unable to
implement unset() and won't
have any useful isset().
Not every property needs the ability to be unset(). Not being able to unset
it is a feature actually. It guarantees that it will always be available
(after the initial set) and does not have to be checked.
In fact, initial value of any object property
will always be NULL, so not allowing
NULL
is pointless as there's always
NULL
there when you start.
The timeframe in which it is NULL
is usually contained to the constructor.
Hi!
Again, same for function typehints.
NULL
is the only possible
initializer there, too. But still we don't take that as a reason to
always allowNULL
for them.
For function, non-optional parameters are always mandatory provided. For
properties, it is not true - there are no "mandatory properties". I'm
surprised how you do not see the different between function parameters
explicitly provided and object properties which are never provided when
object is constructed and always have to be set manually or use default.
They work pretty much in opposite ways here - you can not call function
without parameters, and you can not directly assign parameters when
creating an object.
Not every property needs the ability to be unset(). Not being able to
unset it is a feature actually. It guarantees that it will always be
available (after the initial set) and does not have to be checked.
You convinced me that this feature is actually harmful to PHP - dealing
with unset() throwing fatal errors is much worse than occasional empty()
check. This is a huge landmine - now any code that unsets object
property can return fatal error, and there's, unlike is_null, not even
any way to check it.
The timeframe in which it is
NULL
is usually contained to the constructor.
So what? Objects are constructed all the time, and constructors can call
any other code. Also, nothing really guarantees the constructor actually
has initialized the variable - the constructor author could have
forgotten it just as you could have forgotten to initialize it without
"no NULL" requirement - so when you are using the API of the object, you
can not know if the constructor initialized it or not. And if you're
sure your code is right - you don't need null checks anyway, as you know
your code never assigns null there.
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
On Sun, Jan 6, 2013 at 2:05 AM, Stas Malyshev smalyshev@sugarcrm.comwrote:
You convinced me that this feature is actually harmful to PHP - dealing
with unset() throwing fatal errors is much worse than occasional empty()
check. This is a huge landmine - now any code that unsets object
property can return fatal error, and there's, unlike is_null, not even
any way to check it.
Wait, what are you talking about here? About this particular proposal or
the accessors RFC in general? The fact that unset() can throw a (catchable)
fatal error is just the same without this particular syntax. If you define
a property with an object-typehinted set accessor, then unset() will not be
possible (throwing a catchable fatal). And I really don't see what's wrong
with this. Unset() does not and should not work silently on anything you
pass it. Some things just can't be unset() and we shouldn't pretend like
they can just by silently ignoring. On this topic, a tangentially related
note: The current accessors RFC will make an unset() call on a property
without setter just do nothing without an error. I don't know why you
would think this is a good idea. I honestly can't see how just silently
ignoring instructions is any good. If something can't be unset PHP should
tell you so, rather than leaving you with an (incorrect!) sense of the
operation being performed successfully.
The timeframe in which it is
NULL
is usually contained to the
constructor.
So what? Objects are constructed all the time, and constructors can call
any other code. Also, nothing really guarantees the constructor actually
has initialized the variable - the constructor author could have
forgotten it just as you could have forgotten to initialize it without
"no NULL" requirement - so when you are using the API of the object, you
can not know if the constructor initialized it or not. And if you're
sure your code is right - you don't need null checks anyway, as you know
your code never assigns null there.
There are some things one should address here:
-
First of all, there never is a guarantee for everything. All kinds of
typing mechanism can only go so far. They are supposed to help you find
mistakes and prevent issues, but they can't do everything. If you know
some magic method to prevent all possible bugs in software, please let me
know. Typehinting is just another defense mechanism preventing many common
faults, but it can't prevent everything. -
Secondly, the main purpose of typehints is to prevent people setting
incorrect values. If you know that only a "DateTime" instance is valid and
thatNULL
is not valid, then you should allow only that, only the DateTime.
AllowingNULL
absolutely doesn't make sense (as it's not a valid value for
your application), so I'm not sure why you insist on allowing it.
unset()ing it doesn't make sense, so we shouldn't allow it. Your
argumentation goes along the lines of "It's possible that this property
could maybe end up being NULL, so it does not make sense to prevent people
from assigning NULL". The second part of that sentence does not follow from
the first part. The fact that it can beNULL
before initialization does not
mean that we shouldn't prevent API users from doing aNULL
assignment. -
The constructor is typically (or at least that's how it should be)
small and doesn't do work, so there isn't much to do wrong. But sure, it
can still happen that you forget to initialize something, no arguing that.
The typehint on the property will not prevent this, absolutely. Still it
will prevent all other incorrect assignments to the property, which is
exactly its goal.
I'd summarize this as follows: The typehint prevents all incorrectly-typed
assignments, but it does not prevent missing initialization. Your
argumentation is that because it can't prevent missing initialization, we
shouldn't bother with preventing incorrect assignments either. I hope you
realize that this makes no sense.
Nikita
Hi!
Wait, what are you talking about here? About this particular proposal or
the accessors RFC in general? The fact that unset() can throw a
(catchable) fatal error is just the same without this particular syntax.
This is pretty bad by itself. But the fact that everybody would be using
this feature in this way - since they would think "I don't need null
default, null is always the default and I'd initialize it in the ctor
anyway", not realizing that declaring "public DateTime $foo" blocks
unset - is even worse. At least with setter you need to explicitly
define typehinted setter - and there you have a place to think about it.
With "public DateTime $foo" 99% of people would never even remember to
think about it - until they'd start getting mysterious fatal errors on
unsets. That's why I think it makes it worse.
- First of all, there never is a guarantee for everything. All kinds of
This is a useless platitude. I've outlines specific scenarios where it
fails to do what it seemingly promises to do.
- Secondly, the main purpose of typehints is to prevent people setting
incorrect values. If you know that only a "DateTime" instance is valid
and thatNULL
is not valid, then you should allow only that, only the
DateTime. AllowingNULL
absolutely doesn't make sense (as it's not a
Allowing NULL
is inevitable, that's the whole point, since that's what
the value is when the object is created, and you can not guarantee this
value was initialized. The only thing you can do is to pretend it can
not be null, even though you know it can be, and ignore the cases where
it is null, because you're sure your code is correct.
Your argumentation goes along the lines of "It's possible that this
property could maybe end up being NULL, so it does not make sense to
prevent people from assigning NULL". The second part of that sentence
You can easily prevent people from assigning NULL, what you can not do
is guarantee the property never returns NULL
(at least not with the
short syntax, the explicit accessor is a different thing, there you can
do it just fine). That's what is wrong with this thing. This shortcut
doesn't actually do what people would think it does. It is misleading.
- The constructor is typically (or at least that's how it should be)
small and doesn't do work, so there isn't much to do wrong. But sure, it
"Small" and "work" have wildly different definitions. In real life,
constructors frequently call out to other methods when initializing.
E.g. somehing like:
public function __construct() { $this->log = Logger::getInstance();
$this->db = DBFactory::getInstance(); }
or something like that, happens all the time. Now imagine Logger somehow
tries to use something that uses $this->db and assumes it's not null -
since it can never be null, we declared it not null!
I'd summarize this as follows: The typehint prevents all
incorrectly-typed assignments, but it does not prevent missing
initialization. Your argumentation is that because it can't prevent
missing initialization, we shouldn't bother with preventing incorrect
assignments either. I hope you realize that this makes no sense.
It's not my argument. My argument is this syntax makes promise of the
value never be null and it is specifically proposed with this sole
purpose (and argument is unless it is the promise this syntax has no
value at all). And it does not do that. In addition, it breaks unset()
which would be completely unexpected by 99% of users. I think in this
way it will do more harm than good as it would lead people to write code
which behaves worse than if this syntax did not exist.
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
Stas,
This is pretty bad by itself. But the fact that everybody would be using
this feature in this way - since they would think "I don't need null
default, null is always the default and I'd initialize it in the ctor
anyway", not realizing that declaring "public DateTime $foo" blocks
unset - is even worse. At least with setter you need to explicitly
define typehinted setter - and there you have a place to think about it.
With "public DateTime $foo" 99% of people would never even remember to
think about it - until they'd start getting mysterious fatal errors on
unsets. That's why I think it makes it worse.
So your argument is that people who don't take the time to understand how
something works will somehow be worse off then they would be today? They
can currently write all sorts of bastardized code that raises fatal errors.
Should we try to stop them doing that as well? Should we implement BASIC
style syntax where each line that generates an error just goes to the next
line like nothing even happend (oh, right, we already do that, we should be
ashamed of ourselves).
Show me a public (real life) code base that calls unset on a parameter
that's type hinted by a setter. Where you have either __set or a setBar()
setter, and then somewhere else in the class you call unset() on the
property. While I do understand that it's a possibility, I can't help but
feel that you're completely grasping at straws here...
- First of all, there never is a guarantee for everything. All kinds of
This is a useless platitude. I've outlines specific scenarios where it
fails to do what it seemingly promises to do.
Yes, and all those scenarios are complete far edge-cases. Not one that I've
seen yet is something that I've sen in production code more than once in my
career...
- Secondly, the main purpose of typehints is to prevent people setting
incorrect values. If you know that only a "DateTime" instance is valid
and thatNULL
is not valid, then you should allow only that, only the
DateTime. AllowingNULL
absolutely doesn't make sense (as it's not aAllowing
NULL
is inevitable, that's the whole point, since that's what
the value is when the object is created, and you can not guarantee this
value was initialized. The only thing you can do is to pretend it can
not be null, even though you know it can be, and ignore the cases where
it is null, because you're sure your code is correct.
Again, before initialization (__construct is completed) all bets are off.
You can screw yourself up as much as you want. But if I provide a final
constructor, after initialization, the property should never be null unless
I explicitly make it so INSIDE MY CLASS. If you, outside my class, want to
screw with that, I want you to get a fatal error. That's the entire point
of defensive programming. I can do what I'd like, but I don't want you to
screw something up in a way that I don't expect. And that's what this RFC
is talking about adding...
Your argumentation goes along the lines of "It's possible that this
property could maybe end up being NULL, so it does not make sense to
prevent people from assigning NULL". The second part of that sentenceYou can easily prevent people from assigning NULL, what you can not do
is guarantee the property never returnsNULL
(at least not with the
short syntax, the explicit accessor is a different thing, there you can
do it just fine). That's what is wrong with this thing. This shortcut
doesn't actually do what people would think it does. It is misleading.
Yet again, post construct, if I can guarantee that nobody outside my class
can assign null, I can guarantee that the property will never return null.
Simple as that. It reduces the exposure area to the class itself.
- The constructor is typically (or at least that's how it should be)
small and doesn't do work, so there isn't much to do wrong. But sure, it"Small" and "work" have wildly different definitions. In real life,
constructors frequently call out to other methods when initializing.
E.g. somehing like:
public function __construct() { $this->log = Logger::getInstance();
$this->db = DBFactory::getInstance(); }
or something like that, happens all the time. Now imagine Logger somehow
tries to use something that uses $this->db and assumes it's not null -
since it can never be null, we declared it not null!
Funny you bring that up. Because it's literally not possible in the code
that you wrote to throw the error case you describe. That's because in the
constructor there's literally no other reference to the active class other
than $this. So the only possible way for that to happen would be to
explicitly pass $this to the logger call. Otherwise, as the code you wrote
would always, 100% of the time, work...
And that's the point here. Not that it's not possible to break the
system, but that they are such extreme edge-cases that throwing an error
isn't a big deal. And they are such extreme edge-cases that throwing away
an entire concept is down right irresponsible (it'd be like throwing away
OOP as a concept because an object might not quack like a duck if you
choose to use duck-typing)...
I'd summarize this as follows: The typehint prevents all
incorrectly-typed assignments, but it does not prevent missing
initialization. Your argumentation is that because it can't prevent
missing initialization, we shouldn't bother with preventing incorrect
assignments either. I hope you realize that this makes no sense.It's not my argument. My argument is this syntax makes promise of the
value never be null and it is specifically proposed with this sole
purpose (and argument is unless it is the promise this syntax has no
value at all). And it does not do that. In addition, it breaks unset()
which would be completely unexpected by 99% of users. I think in this
way it will do more harm than good as it would lead people to write code
which behaves worse than if this syntax did not exist.
No. The syntax promises that the value will never be assigned a value of
null. That's very different from "never will be null". One I can control
(by assigning it a value, I know it can never be null again), and the other
I cannot (with initialization race-conditions as you specify)...
Let's not handicap the language because there may be some code that someone
might write in the next 20 years that might cause something that results in
a fatal error that wouldn't be obvious. Except that if that person
understood the documented language, it would be obvious. So it's not really
possible (running into an unexpected error) unless that person also didn't
read the documentation..
So if we're now designing language features that need to behave 100%
intuitively for every single programmer without the requirement of reading
documentation, let's stop making all changes to the language. Because all
changes are going to be unintuitive to someone...
Let's be realistic here...
Anthony
On Sun, Jan 6, 2013 at 2:59 AM, Stas Malyshev smalyshev@sugarcrm.comwrote:
This is pretty bad by itself. But the fact that everybody would be using
this feature in this way - since they would think "I don't need null
default, null is always the default and I'd initialize it in the ctor
anyway", not realizing that declaring "public DateTime $foo" blocks
unset - is even worse. At least with setter you need to explicitly
define typehinted setter - and there you have a place to think about it.
With "public DateTime $foo" 99% of people would never even remember to
think about it - until they'd start getting mysterious fatal errors on
unsets. That's why I think it makes it worse.
In this mail I'm only going to address the unset() concern.
First of all it should be made clear that contrary to the impression that
you conveyed unset() is a fallible operation. It absolutely is fallible,
even when overloaded properties and offset (__unset/offsetUnset) are not
involved. If I write unset($foo[0])
then this is an operation that can
throw a fatal error, for example when $foo is a string. Why does this throw
a fatal error? Because a string offset can not be unset. It's an operation
that does not make sense and so PHP throws an error. PHP could also just do
nothing, leave the string intact and pretend the unset() was successful.
But it doesn't do so and it's good that it doesn't do so.
What we are talking about here is a similar situation. We are talking about
a property where it does not make sense to unset it. The unset operation is
not meaningful and as such shouldn't be allowed. It's as easy as that.
That's the first point. The second point is that even if an issue existed
here (which it does not) then you are presenting it in a totally
disproportional matter. You make it seem like unset()ing properties is this
super important operation that we do all the time and the world would
collapse if it failed. That's not true. Unset() on object properties is
only used very rarely. Symfony Standard (including Symfony, Doctrine,
Twig, ...) has a total of !! 4 !! property unsets (compare this to their
~3800 accessor methods). The ZF2 has 8 property unsets of which only !! 3
!! are targeted at specific properties (the remaining 5 are on
stdClass-like objects). Again, compare this to their ~4k accessor methods.
In summary: a) Unset() is a fallible operation, it's okay if it throws an
error if the unset is not reasonably possible. b) Even if you don't agree
with this assessment it's quasi a non-issue as property unsets are
incredibly rare. Dismissing a feature based on something like this is
absolutely implausible. c) You can always allow unset() and NULL
assignment
by specifying it as the default value. Not hard to do should you once run
into issues of this kind.
Thanks,
Nikita
Hi. I like the proposal of this RFC very much ;-)
But the way 'nullable' properties are defined is not very intuitive and unclean, in my opinion. Stas has already mentioned that.
public DateTime $date = NULL;
// this looks like the property is initialized with null, but it does not show that the property is 'nullable'
If type hinted properties are not allowed to be set to null, I would propose this way to make a property nullable:
public DateTime? $date;
In C# the question mark after a type is a short hand for a generic Nullable type.
-----Original Message-----
From: Nikita Popov [mailto:nikita.ppv@gmail.com]
Sent: Saturday, January 05, 2013 1:48 AM
To: Steve Clay
Cc: PHP internals
Subject: Re: [PHP-DEV] [RFC] Alternative typehinting syntax for accessors
Would the following two be exactly functionally equivalent?
public Foo $foo;
public $foo {
get;
set(Foo $value) { $this->foo = $value; }
}We should also consider how an author would allow type-hinted properties
to acceptNULL
as a new value, in both proposals.
I think that's a very interesting question, thanks for bringing it up. I
think a good approach here would be the same one used for function argument
typehints, i.e. allow NULL
when NULL
is specified as the default value. So
public DateTime $date;
would not allow an explicit NULL
assignment,
whereas public DateTime $date = NULL;
would.
Nikita
Am 08.01.2013 08:56, schrieb Christian Stoller:
But the way 'nullable' properties are defined is not very intuitive and unclean, in my opinion. Stas has already mentioned that.
public DateTime $date = NULL;
// this looks like the property is initialized with null, but it does not show that the property is 'nullable'
To me this makes perfect sense. It takes up the syntax php has been
using for method-definitions. A syntax we would be using to create a
classic setter method if there wasn't a fancy new one.
public function setDate(DateTime $date = NULL) {
$this->date = $date;
}
Anything other than this would result in an inconsistency. Having
accepted that syntax previously and now introducing yet another one,
would be confusing and unnecessary.
Although, as Stas has pointed out, not allowing NULL
for a property
will not prevent it from being NULL...depending on wether it has been
initalized.
It takes up the syntax php has been using for method-definitions.
The fact is that the existing syntax for nullable type hinting has its own
problems. For example, this is not possible:
function foo( Bar $bar = null , $mandatory ) { ... }
I would love to have the question mark syntax for both properties and
argument type hinting.
Although, as Stas has pointed out, not allowing
NULL
for a property
will not prevent it from being NULL...depending on wether it has been
initalized.
This does not apply in all cases. Here is an example of a property that is
guaranteed not to be null:
class Foo {
private $_date;
public DateTime $date {
get {
return is_null($date) ? new DateTime() : $this->date;
}
set {
$this->date = $value;
}
}
}
Lazare INEPOLOGLOU
Ingénieur Logiciel
2013/1/8 Lars Schultz lars.schultz@toolpark.com
Am 08.01.2013 08:56, schrieb Christian Stoller:
But the way 'nullable' properties are defined is not very intuitive and
unclean, in my opinion. Stas has already mentioned that.
public DateTime $date = NULL;
// this looks like the property is
initialized with null, but it does not show that the property is 'nullable'To me this makes perfect sense. It takes up the syntax php has been using
for method-definitions. A syntax we would be using to create a classic
setter method if there wasn't a fancy new one.public function setDate(DateTime $date = NULL) {
$this->date = $date;
}Anything other than this would result in an inconsistency. Having accepted
that syntax previously and now introducing yet another one, would be
confusing and unnecessary.Although, as Stas has pointed out, not allowing
NULL
for a property will
not prevent it from being NULL...depending on wether it has been initalized.
Am 08.01.2013 10:03, schrieb Lazare Inepologlou:
The fact is that the existing syntax for nullable type hinting has its own
problems. For example, this is not possible:
function foo( Bar $bar = null , $mandatory ) { ... }
Sure it's possible;) I did not get a syntax error for that...I even use
that case many times in my code exactly for that purpose, to allow $bar
to be null but require $mandatory to be defined explicitly.
I would love to have the question mark syntax for both properties and
argument type hinting.
Introducing a BC-Break and/or yet another syntax? Is that worth it?
This does not apply in all cases. Here is an example of a property that is
guaranteed not to be null:class Foo {
private $_date;
public DateTime $date {
get {
return is_null($date) ? new DateTime() : $this->date;
}
set {
$this->date = $value;
}
}
}
The property is still null;) Only the return value of the getter will
not be null. But that's not the issue, is it? I am not arguing the case
of NOT allowing null, Stas wanted to always allow null because of this
reason and not have a special syntax to declare this.
2013/1/8 Lars Schultz lars.schultz@toolpark.com
Am 08.01.2013 10:03, schrieb Lazare Inepologlou:
The fact is that the existing syntax for nullable type hinting has its own
problems. For example, this is not possible:
function foo( Bar $bar = null , $mandatory ) { ... }Sure it's possible;) I did not get a syntax error for that...I even use
that case many times in my code exactly for that purpose, to allow $bar to
be null but require $mandatory to be defined explicitly.
Seems you are right. Sorry.
I would love to have the question mark syntax for both properties and
argument type hinting.
Introducing a BC-Break and/or yet another syntax? Is that worth it?
This does not apply in all cases. Here is an example of a property that is
guaranteed not to be null:
class Foo {
private $_date;
public DateTime $date {
get {
return is_null($date) ? new DateTime() : $this->date;
}
set {
$this->date = $value;
}
}
}The property is still null;) Only the return value of the getter will not
be null. But that's not the issue, is it? I am not arguing the case of NOT
allowing null, Stas wanted to always allow null because of this reason and
not have a special syntax to declare this.
No, the field $_date can be null. The property $date is not null, cannot be
set to null and cannot return null. Furthermore, it cannot be unset (should
fail with an error) and isset always returns true.
Lazare INEPOLOGLOU
Ingénieur Logiciel
But the way 'nullable' properties are defined is not very intuitive and unclean, in my opinion. Stas has already mentioned that.
public DateTime $date = NULL;
// this looks like the property is initialized with null, but it does not show that the property is 'nullable'
Much agreed. After instantiation, these shouldn't behave differently:
public $foo = null;
public Foo $foo = null;
Sure, method signatures have special behavior based on a default value, but IMO:
- those semantics aren't entirely intuitive to begin with
- property initializers aren't method sigs
- the semantics would apply only to some properties
public DateTime? $date;
In C# the question mark after a type is a short hand for a generic Nullable type.
I like that it's an established practice of doing exactly what we're trying to do.
Could we not just make it obvious?:
public Foo|null $foo;
Steve Clay
But the way 'nullable' properties are defined is not very intuitive and
unclean, in my opinion. Stas has already mentioned that.
public DateTime $date = NULL;
// this looks like the property is
initialized with null, but it does not show that the property is 'nullable'Much agreed. After instantiation, these shouldn't behave differently:
public $foo = null;
public Foo $foo = null;Sure, method signatures have special behavior based on a default value,
but IMO:
those semantics aren't entirely intuitive to begin with
property initializers aren't method sigs
the semantics would apply only to some properties
public DateTime? $date;
In C# the question mark after a type is a short hand for a generic
Nullable type.I like that it's an established practice of doing exactly what we're
trying to do.Could we not just make it obvious?:
public Foo|null $foo;
I'm not going to argue whether or not determining nullability via = null is
a good or bad idea, but it's the way things currently work in PHP. Adding
other mechanisms for nullability (or multiple typehints, like it is your
suggestion) is something that may be considered, but it is outside the
scope of this RFC. Those things apply to typehints in general, not just to
property typehints. If you want pursue this further, then I would ask you
to create a separate RFC (or just a separate internals discussion maybe).
Thanks,
Nikita
But the way 'nullable' properties are defined is not very intuitive and
unclean, in my opinion. Stas has already mentioned that.
public DateTime $date = NULL;
// this looks like the property is
initialized with null, but it does not show that the property is 'nullable'Much agreed. After instantiation, these shouldn't behave differently:
public $foo = null;
public Foo $foo = null;Sure, method signatures have special behavior based on a default value,
but IMO:
- those semantics aren't entirely intuitive to begin with
- property initializers aren't method sigs
- the semantics would apply only to some properties
public DateTime? $date;
In C# the question mark after a type is a short hand for a generic
Nullable type.I like that it's an established practice of doing exactly what we're
trying to do.Could we not just make it obvious?:
public Foo|null $foo;
I updated the RFC to include the current state regarding default value and
nullability:
https://wiki.php.net/rfc/propertygetsetsyntax-alternative-typehinting-syntax
One question that still needs to be discussed is what syntax regarding
parentheses we want to use if this makes it. Currently both set { } and
set($foo) { } style accessors are supported. Do we want to keep those two
with the new syntax?
Nikita
PS: I hope I'm not interrupting all those heated annotations discussion too
much ^^
Hi!
The proposal is pretty clear, but could you explain this part:
The current accessors proposal will need special handling of the
typehint in any case (it can't be handled as a normal method typehint).
What special handling is required?
One question that still needs to be discussed is what syntax regarding
parentheses we want to use if this makes it. Currently both set { } and
set($foo) { } style accessors are supported. Do we want to keep those two
with the new syntax?
Within this context, I'd prefer getting rid of set {} and only have
set($param) {}. You don't save that much typing and you do it at the
cost of additional obscurity and complexity - now every developer and
every tool that deals with it needs to remember there's hidden $value
parameter. IMHO not worth it. I can see what "get;" gives you - you can
say "just do the natural thing". But if you start writing code anyway -
i.e. if you do {} - then I think it should look like a real function.
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
On Thu, Jan 10, 2013 at 11:11 PM, Stas Malyshev smalyshev@sugarcrm.comwrote:
Hi!
The proposal is pretty clear, but could you explain this part:
The current accessors proposal will need special handling of the
typehint in any case (it can't be handled as a normal method typehint).What special handling is required?
I have written that in anticipation of a rewrite of the current automatic
accessor implementation. Currently it creates a string of PHP code and
compiles it as the method body. We were planning to replace this with
handling directly in the object handlers (because automatic accessors just
need to use the "normal" property code rather than the accessor one). In
this case we'd have to handle the typehint explicitly. But I'm not sure
whether we will still do this, so I'm not sure whether that statement in
the RFC is still true. On this subject, are you (personally) okay with the
current approach for creating automatic accessors (i.e. create PHP code
string and compile)?
One question that still needs to be discussed is what syntax regarding
parentheses we want to use if this makes it. Currently both set { } and
set($foo) { } style accessors are supported. Do we want to keep those two
with the new syntax?Within this context, I'd prefer getting rid of set {} and only have
set($param) {}. You don't save that much typing and you do it at the
cost of additional obscurity and complexity - now every developer and
every tool that deals with it needs to remember there's hidden $value
parameter. IMHO not worth it. I can see what "get;" gives you - you can
say "just do the natural thing". But if you start writing code anyway -
i.e. if you do {} - then I think it should look like a real function.
Just to make sure I got it all right, you are suggesting:
- Parentheses must be used on all accessors, so it's set($value) {} and
get() {} and isset() {} and unset() {} and something like get {} is not
possible? - Automatic accessors don't have parentheses so they are just set; get;
isset; unset;
Is that right? If so, then I think it's a reasonable approach.
Nikita
Hi!
that statement in the RFC is still true. On this subject, are you
(personally) okay with the current approach for creating automatic
accessors (i.e. create PHP code string and compile)?
It might be more efficient to generate the opcodes directly, since they
are always the same and you'd really need to only plug the string into
one place (or in case of typehints, two places), but I don't have
preference one way or another, depending on which is easier. If we won't
have reentrancy, line numbers, etc. issues then generating a string may
be easier and also more robust if opcodes ever change.
Just to make sure I got it all right, you are suggesting:
- Parentheses must be used on all accessors, so it's set($value) {} and
get() {} and isset() {} and unset() {} and something like get {} is not
possible?- Automatic accessors don't have parentheses so they are just set; get;
isset; unset;Is that right? If so, then I think it's a reasonable approach.
Yes, I think this makes it look consistent - albeit at the price of some
added verbosity.
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
On Thu, Jan 10, 2013 at 11:11 PM, Stas Malyshev smalyshev@sugarcrm.comwrote:
Hi!
The proposal is pretty clear, but could you explain this part:
The current accessors proposal will need special handling of the
typehint in any case (it can't be handled as a normal method typehint).What special handling is required?
I now added a patch for this proposal: https://gist.github.com/4579298 (For
more detailed individual commits see here:
https://github.com/nikic/php-src/commits/alternativeSyntax)
If there are no more issues I'll start the vote on this.
Nikita
I now added a patch for this proposal: https://gist.github.com/4579298 (For
more detailed individual commits see here:
https://github.com/nikic/php-src/commits/alternativeSyntax)
One thing I hadn't noticed is that the proposal was to move the
typehint, what happens in this case then:
public DateTime $date {
get;
set(stdClass $value);
}
Would the above produce a compilation error on the stdClass part?
--
-Clint
I now added a patch for this proposal: https://gist.github.com/**4579298https://gist.github.com/4579298(For
more detailed individual commits see here:
https://github.com/nikic/php-**src/commits/alternativeSyntaxhttps://github.com/nikic/php-src/commits/alternativeSyntax
)One thing I hadn't noticed is that the proposal was to move the typehint,
what happens in this case then:public DateTime $date {
get;
set(stdClass $value);
}Would the above produce a compilation error on the stdClass part?
Yes, that's an error. And I'm not sure what that is supposed to mean in the
first place (it has two different typehints at two different places...)
This proposal will allow a typehint before the property name and only
there. Allowing one in both places doesn't make much sense to me.
Nikita
Nikita,
2013/1/10 Nikita Popov nikita.ppv@gmail.com
But the way 'nullable' properties are defined is not very intuitive and
unclean, in my opinion. Stas has already mentioned that.
public DateTime $date = NULL;
// this looks like the property is
initialized with null, but it does not show that the property is
'nullable'Much agreed. After instantiation, these shouldn't behave differently:
public $foo = null;
public Foo $foo = null;Sure, method signatures have special behavior based on a default value,
but IMO:
- those semantics aren't entirely intuitive to begin with
- property initializers aren't method sigs
- the semantics would apply only to some properties
public DateTime? $date;
In C# the question mark after a type is a short hand for a generic
Nullable type.I like that it's an established practice of doing exactly what we're
trying to do.Could we not just make it obvious?:
public Foo|null $foo;
I updated the RFC to include the current state regarding default value and
nullability:https://wiki.php.net/rfc/propertygetsetsyntax-alternative-typehinting-syntax
One question that still needs to be discussed is what syntax regarding
parentheses we want to use if this makes it. Currently both set { } and
set($foo) { } style accessors are supported. Do we want to keep those two
with the new syntax?Nikita
PS: I hope I'm not interrupting all those heated annotations discussion too
much ^^
In the RFC, one thing is not clear: How to provide typehints for nullable
properties that actually have accessors.
Will it be like this?
public DateTime $date = null {
get { ... }
set { ... }
}
Lazare INEPOLOGLOU
Ingénieur Logiciel
We all agree that nullable properties need to be addressed.
Now why just don't discuss a possible syntax and move on?
Initializers, parenthesis around unsetters, etc can all be detailed and
discussed later.
Here are the proposed syntaxes:
public DateTime? $date {
get { ... }
set { ... }
}
public DateTime $date = null {
get { ... }
set { ... }
}
public DateTime $date {
get { ... }
set($value = null) { ... }
}
public $date {
get { ... }
set(DateTime $value = null) { ... }
}
Now choose your options from 1-4 and move on...
Sometimes you truly love to discuss instead of act. Tsc, tsc, tsc...
Cheers,
On Thu, Jan 10, 2013 at 7:24 PM, Lazare Inepologlou linepogl@gmail.comwrote:
Nikita,
2013/1/10 Nikita Popov nikita.ppv@gmail.com
But the way 'nullable' properties are defined is not very intuitive
and
unclean, in my opinion. Stas has already mentioned that.
public DateTime $date = NULL;
// this looks like the property is
initialized with null, but it does not show that the property is
'nullable'Much agreed. After instantiation, these shouldn't behave differently:
public $foo = null;
public Foo $foo = null;Sure, method signatures have special behavior based on a default value,
but IMO:
- those semantics aren't entirely intuitive to begin with
- property initializers aren't method sigs
- the semantics would apply only to some properties
public DateTime? $date;
In C# the question mark after a type is a short hand for a generic
Nullable type.I like that it's an established practice of doing exactly what we're
trying to do.Could we not just make it obvious?:
public Foo|null $foo;
I updated the RFC to include the current state regarding default value
and
nullability:https://wiki.php.net/rfc/propertygetsetsyntax-alternative-typehinting-syntax
One question that still needs to be discussed is what syntax regarding
parentheses we want to use if this makes it. Currently both set { } and
set($foo) { } style accessors are supported. Do we want to keep those two
with the new syntax?Nikita
PS: I hope I'm not interrupting all those heated annotations discussion
too
much ^^In the RFC, one thing is not clear: How to provide typehints for nullable
properties that actually have accessors.Will it be like this?
public DateTime $date = null {
get { ... }
set { ... }
}Lazare INEPOLOGLOU
Ingénieur Logiciel
--
Guilherme Blanco
MSN: guilhermeblanco@hotmail.com
GTalk: guilhermeblanco
Toronto - ON/Canada
This looks really nice. I would love to see this in PHP +1
- Jon
Hi internals!
I already brought this up before, but I think the discussion at that time
was not very constructive and largely off-topic, so I'm bringing it up
again. To make sure everything is clear I wrote an RFC document:https://wiki.php.net/rfc/propertygetsetsyntax-alternative-typehinting-syntax
This RFC proposes an alternative syntax for typehinting accessors, which
will in particular also allow to typehint properties directly, even if no
accessors are used (public DateTime $date).What are your opinions on this?
Thanks,
Nikita
--
Connect with me on http://twitter.com/jwage http://twitter.com/jwage
and http://about.me/jwage to keep in touch.
Join OpenSky today: http://osky.co/l6a75g
+1 from me as well.
Hi internals!
I already brought this up before, but I think the discussion at that time
was not very constructive and largely off-topic, so I'm bringing it up
again. To make sure everything is clear I wrote an RFC document:https://wiki.php.net/rfc/propertygetsetsyntax-alternative-typehinting-syntax
This RFC proposes an alternative syntax for typehinting accessors, which
will in particular also allow to typehint properties directly, even if no
accessors are used (public DateTime $date).What are your opinions on this?
Thanks,
Nikita
--
-Clint
https://wiki.php.net/rfc/propertygetsetsyntax-alternative-typehinting-syntax
I like the proposal so far.
I'm still a little hesitant about syntax for allowing the setting of NULL
values. Since
properties are NULL
by default (I wish this were explicit in the docs), these are
completely equivalent:
public $f;
public $f = null;
So it bothers me that these would result in different behavior:
public Foo $f;
public Foo $f = null;
Now, all properties with an object type must be NULL
initially, so really we're deciding
whether a property can be set back to NULL
(outside the setter).