[RFC] Alternative typehinting syntax for accessors

php.internals

Nikita Popov

13 years ago
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

Levi Morrison

13 years ago
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.

Clint M Priest

13 years ago
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. On 1/4/2013 9:15 AM, Levi Morrison wrote:
> 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. >
-- -Clint

Stas Malyshev

13 years ago
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

Clint M Priest

13 years ago
On 1/4/2013 4:29 PM, Stas Malyshev wrote:
> 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

Steve Clay

13 years ago
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
-- http://www.mrclay.org/ On Jan 4, 2013, at 9:41 AM, Nikita Popov <nikita.ppv@gmail.com> wrote:

Levi Morrison

13 years ago
>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.

Levi Morrison

13 years ago
On Fri, Jan 4, 2013 at 4:34 PM, Levi Morrison <levim@php.net> wrote:
>>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.

Nikita Popov

13 years ago
On Sat, Jan 5, 2013 at 12:31 AM, Steve Clay <steve@mrclay.org> wrote:
> 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. >
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

Bernhard Schussek

13 years ago
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. 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.
I was wondering about this question too. I really like that solution. Bernhard

Stas Malyshev

13 years ago
Hi!
>> 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.
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

Anthony Ferrara

13 years ago
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

Stas Malyshev

13 years ago
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

Anthony Ferrara

13 years ago
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 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. >
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

Stas Malyshev

13 years ago
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

Anthony Ferrara

13 years ago
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 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.
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'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.
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

Steve Clay

13 years ago
On 1/5/13 7:25 PM, Anthony Ferrara wrote:
> 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: 1. putting too much logic in a property (SRP) 2. 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
-- http://www.mrclay.org/

Nikita Popov

13 years ago
On Sun, Jan 6, 2013 at 1:18 AM, Stas Malyshev <smalyshev@sugarcrm.com>wrote:
> 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 allow NULL > 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.

Stas Malyshev

13 years ago
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 allow NULL 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

Nikita Popov

13 years ago
On Sun, Jan 6, 2013 at 2:05 AM, Stas Malyshev <smalyshev@sugarcrm.com>wrote:
> 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: 1. 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. 2. Secondly, the main purpose of typehints is to prevent people setting incorrect values. If you know that only a "DateTime" instance is valid and that NULL is not valid, then you should allow only that, only the DateTime. Allowing NULL 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 be NULL before initialization does not mean that we shouldn't prevent API users from doing a NULL assignment. 3. 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

Christian Stoller

13 years ago
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 On Sat, Jan 5, 2013 at 12:31 AM, Steve Clay <steve@mrclay.org> wrote:
> 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. >
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

Lars Schultz

13 years ago
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.

Lazare Inepologlou

13 years ago
> 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>

Lars Schultz

13 years ago
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.

Lazare Inepologlou

13 years ago
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

Steve Clay

13 years ago
On 1/8/13 2:56 AM, Christian Stoller wrote:
> 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: 1. those semantics aren't entirely intuitive to begin with 2. property initializers aren't method sigs 3. 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
-- http://www.mrclay.org/

Nikita Popov

13 years ago
On Tue, Jan 8, 2013 at 7:03 PM, Steve Clay <steve@mrclay.org> wrote:
> On 1/8/13 2:56 AM, Christian Stoller wrote: > >> 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: > 1. those semantics aren't entirely intuitive to begin with > 2. property initializers aren't method sigs > 3. 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

Nikita Popov

13 years ago
On Tue, Jan 8, 2013 at 7:03 PM, Steve Clay <steve@mrclay.org> wrote:
> On 1/8/13 2:56 AM, Christian Stoller wrote: > >> 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: > 1. those semantics aren't entirely intuitive to begin with > 2. property initializers aren't method sigs > 3. 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 ^^

Stas Malyshev

13 years ago
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

Nikita Popov

13 years ago
On Thu, Jan 10, 2013 at 11:11 PM, Stas Malyshev <smalyshev@sugarcrm.com>wrote:
> 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

Stas Malyshev

13 years ago
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

Nikita Popov

13 years ago
On Thu, Jan 10, 2013 at 11:11 PM, Stas Malyshev <smalyshev@sugarcrm.com>wrote:
> 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

Clint M Priest

13 years ago
On 1/20/2013 9:26 AM, Nikita Popov wrote:
> 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

Nikita Popov

13 years ago
On Sun, Jan 20, 2013 at 4:47 PM, Clint Priest <cpriest@zerocue.com> wrote:
> > On 1/20/2013 9:26 AM, Nikita Popov wrote: > >> I now added a patch for this proposal: https://gist.github.com/**4579298<https://gist.github.com/4579298>(For >> more detailed individual commits see here: >> https://github.com/nikic/php-**src/commits/alternativeSyntax<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? >
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

Lazare Inepologlou

13 years ago
Nikita, 2013/1/10 Nikita Popov <nikita.ppv@gmail.com>
> On Tue, Jan 8, 2013 at 7:03 PM, Steve Clay <steve@mrclay.org> wrote: > > > On 1/8/13 2:56 AM, Christian Stoller wrote: > > > >> 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: > > 1. those semantics aren't entirely intuitive to begin with > > 2. property initializers aren't method sigs > > 3. 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

13 years ago
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.com>wrote:
> Nikita, > > > 2013/1/10 Nikita Popov <nikita.ppv@gmail.com> > > > On Tue, Jan 8, 2013 at 7:03 PM, Steve Clay <steve@mrclay.org> wrote: > > > > > On 1/8/13 2:56 AM, Christian Stoller wrote: > > > > > >> 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: > > > 1. those semantics aren't entirely intuitive to begin with > > > 2. property initializers aren't method sigs > > > 3. 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

Jonathan Wage

13 years ago
This looks really nice. I would love to see this in PHP +1 - Jon On Fri, Jan 4, 2013 at 8:41 AM, Nikita Popov <nikita.ppv@gmail.com> wrote:
> 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

Clint M Priest

13 years ago
+1 from me as well. On 1/4/2013 8:41 AM, Nikita Popov wrote:
> 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

Steve Clay

13 years ago
On 1/4/13 9:41 AM, Nikita Popov wrote:
> 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). We could just make the most common case the default behavior. Otherwise the author must provide the signature of the setter with/without "= null". Steve Clay
-- http://www.mrclay.org/