# [RFC] Alternative typehinting syntax for accessors

- Thread: https://externals.io/message/64520
- Original archive: https://news-web.php.net/php.internals/64520
- Started by Nikita Popov on 2013-01-04T14:41:07+00:00
- Messages: 46
- Page 1 of 2: messages 1 to 25 (25 per page, add `?page=N` to the URL)
- Next page: https://externals.io/message/64520.md?page=2
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #64520 — Nikita Popov — 2013-01-04T14:41:07+00:00

URL: https://externals.io/message/64520#64520

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

---

## #64522 — Levi Morrison — 2013-01-04T15:15:55+00:00

URL: https://externals.io/message/64520#64522 · In reply to: #64520

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.

---

## #64523 — Clint Priest — 2013-01-04T15:19:07+00:00

URL: https://externals.io/message/64520#64523 · In reply to: #64522

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

---

## #64533 — Stas Malyshev — 2013-01-04T22:29:53+00:00

URL: https://externals.io/message/64520#64533 · In reply to: #64523

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

---

## #64534 — Steve Clay — 2013-01-04T23:31:15+00:00

URL: https://externals.io/message/64520#64534 · In reply to: #64520

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/



> 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

---

## #64535 — Levi Morrison — 2013-01-04T23:34:28+00:00

URL: https://externals.io/message/64520#64535 · In reply to: #64534

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

---

## #64536 — Levi Morrison — 2013-01-04T23:44:48+00:00

URL: https://externals.io/message/64520#64536 · In reply to: #64535

> > […]
>
> 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.

---

## #64537 — Nikita Popov — 2013-01-05T00:48:14+00:00

URL: https://externals.io/message/64520#64537 · In reply to: #64534

> 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

---

## #64539 — Clint Priest — 2013-01-05T03:31:36+00:00

URL: https://externals.io/message/64520#64539 · In reply to: #64533

> Hi!
>
> > […]
> 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

---

## #64544 — Bernhard Schussek — 2013-01-05T10:38:28+00:00

URL: https://externals.io/message/64520#64544 · In reply to: #64537

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

---

## #64555 — Jonathan Wage — 2013-01-05T18:06:55+00:00

URL: https://externals.io/message/64520#64555 · In reply to: #64520

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

---

## #64558 — Clint Priest — 2013-01-05T21:00:36+00:00

URL: https://externals.io/message/64520#64558 · In reply to: #64520

+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

---

## #64562 — Steve Clay — 2013-01-05T22:27:20+00:00

URL: https://externals.io/message/64520#64562 · In reply to: #64520

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

---

## #64564 — Stas Malyshev — 2013-01-05T22:33:49+00:00

URL: https://externals.io/message/64520#64564 · In reply to: #64544

Hi!

> > […]

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

---

## #64580 — Anthony Ferrara — 2013-01-06T00:06:32+00:00

URL: https://externals.io/message/64520#64580 · In reply to: #64564

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

---

## #64582 — Stas Malyshev — 2013-01-06T00:18:02+00:00

URL: https://externals.io/message/64520#64582 · In reply to: #64580

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

---

## #64584 — Anthony Ferrara — 2013-01-06T00:25:50+00:00

URL: https://externals.io/message/64520#64584 · In reply to: #64582

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


> > […]
>
> 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

---

## #64585 — Nikita Popov — 2013-01-06T00:41:34+00:00

URL: https://externals.io/message/64520#64585 · In reply to: #64582

On Sun, Jan 6, 2013 at 1:18 AM, Stas Malyshev <smalyshev@sugarcrm.com>wrote:

> Hi!
>
> > […]
>
> 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.
>
> > […]
>
> 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.

---

## #64586 — Stas Malyshev — 2013-01-06T00:56:52+00:00

URL: https://externals.io/message/64520#64586 · In reply to: #64584

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

---

## #64587 — Stas Malyshev — 2013-01-06T01:05:12+00:00

URL: https://externals.io/message/64520#64587 · In reply to: #64585

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

---

## #64590 — Nikita Popov — 2013-01-06T01:39:22+00:00

URL: https://externals.io/message/64520#64590 · In reply to: #64587

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.

> > […]
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

---

## #64591 — Steve Clay — 2013-01-06T01:43:44+00:00

URL: https://externals.io/message/64520#64591 · In reply to: #64584

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

---

## #64592 — Stas Malyshev — 2013-01-06T01:59:53+00:00

URL: https://externals.io/message/64520#64592 · In reply to: #64590

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.

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

> 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

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.

> 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

"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

---

## #64593 — Anthony Ferrara — 2013-01-06T02:32:33+00:00

URL: https://externals.io/message/64520#64593 · In reply to: #64586

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


> > […]
>
> 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;


> > […]
>
> 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...


> > […]
>
> 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

---

## #64594 — Anthony Ferrara — 2013-01-06T02:51:12+00:00

URL: https://externals.io/message/64520#64594 · In reply to: #64592

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


> > […]
>
> 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...


> > […]
>
> 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.


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


> > […]
>
> 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.


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.


> > […]
>
> "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)...


> > […]
>
> 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

---

Next page: https://externals.io/message/64520.md?page=2
