# [RFC Discussion] Typed Properties

- Thread: https://externals.io/message/91692
- Original archive: https://news-web.php.net/php.internals/91692
- Started by Phil Sturgeon on 2016-03-16T16:36:45+00:00
- Messages: 118
- Page 1 of 5: messages 1 to 25 (25 per page, add `?page=N` to the URL)
- Next page: https://externals.io/message/91692.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

---

## #91692 — Phil Sturgeon — 2016-03-16T16:36:45+00:00

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

Hello everyone,

I have completed the draft for an RFC, to add Typed Properties. The
patch has been written by the one and only Joe Watkins.

https://wiki.php.net/rfc/typed-properties

I would really appreciate constructive feedback on this RFC, with a
few areas especially:

1. How scared are we that integers can be expanded to floats on runtime?

2. This whole temporary nullability situation, where unset properties
will error on attempted usage if not set. Should they instead error
after the constructor has been called if they are still not holding a
value?

3. Weak vs Strict. Right now this is entirely strict, with no
declare() to change mode. Reasons for this vary, from various sources,
but include "Not sure how to implement it" and "Well people should not
be using properties as part of their public API".

Help on 3 would be appreciated.

Also let's please avoid "PHP IS TURNING INTO JAVA" and the other
rather common rhetoric. Strict Type Hinting might have been seen as a
battleground for fans of strict and fans of weak to fight through a
keyboard, but this RFC will not be the repeat.

We'll have a nice, orderly, constructive conversation about this RFC,
and improve the patch as you all provide feedback.

Let me know what you think folks!

---

## #91693 — Will Fitch — 2016-03-16T16:49:49+00:00

URL: https://externals.io/message/91692#91693 · In reply to: #91692

> Hello everyone,
> 
> I have completed the draft for an RFC, to add Typed Properties. The
> patch has been written by the one and only Joe Watkins.
> 
> https://wiki.php.net/rfc/typed-properties
> 
> I would really appreciate constructive feedback on this RFC, with a
> few areas especially:
> 
> 1. How scared are we that integers can be expanded to floats on runtime?

First, this looks awesome, Phil!  

After reading through it, I think we can consult with function return
types:

function blah() : int {
    return 55.5;
}

var_dump(blah());

Will return 55.  It's a little different with properties, but what are
your thoughts on this runtime conversion?

> 
> 2. This whole temporary nullability situation, where unset properties
> will error on attempted usage if not set. Should they instead error
> after the constructor has been called if they are still not holding a
> value?
> 
> 3. Weak vs Strict. Right now this is entirely strict, with no
> declare() to change mode. Reasons for this vary, from various sources,
> but include "Not sure how to implement it" and "Well people should not
> be using properties as part of their public API".
> 
> Help on 3 would be appreciated.
> 
> Also let's please avoid "PHP IS TURNING INTO JAVA" and the other
> rather common rhetoric. Strict Type Hinting might have been seen as a
> battleground for fans of strict and fans of weak to fight through a
> keyboard, but this RFC will not be the repeat.
> 
> We'll have a nice, orderly, constructive conversation about this RFC,
> and improve the patch as you all provide feedback.
> 
> Let me know what you think folks!

---

## #91694 — Adam Harvey — 2016-03-16T17:08:53+00:00

URL: https://externals.io/message/91692#91694 · In reply to: #91692

> 3. Weak vs Strict. Right now this is entirely strict, with no
> declare() to change mode. Reasons for this vary, from various sources,
> but include "Not sure how to implement it" and "Well people should not
> be using properties as part of their public API".

As much as I didn't (and don't) particularly like the declare()
switch, it doesn't seem like a good idea to me to introduce a typing
feature a year after it that doesn't use it, but has its own mode of
operation. To me, it seems like this:

class Foo {
  public int $num;
}

(new Foo)->num = $bar;

Should behave the same as the setter equivalent does today:

class Foo {
  public $num;
  public function setNum(int $num) { $this->num = $num; }
}

(new Foo)->setNum($num);

That is: if $num either can't be coerced to an integer (in weak mode)
or isn't itself an integer (in strict mode), a TypeError should be
thrown.

We could argue about whether properties should be part of a public
API, but the reality is that a class declaring a public property
effectively is making it part of its API, whether you or I think it's
a good idea or not. :)

> We'll have a nice, orderly, constructive conversation about this RFC,
> and improve the patch as you all provide feedback.
>
> Let me know what you think folks!

The above leads into another question I'm interested in your (and
Joe's) general thoughts on: how do you think this would potentially
intersect with a property getter/setter RFC in the future? Might be
good fodder for the future scope section!

Finally, while the RFC shows invalid assignments generating fatal
errors, the patch seems like it throws TypeError exceptions instead.
Which one is the desired behaviour? (I'd prefer TypeError, personally,
for consistency with function type declarations today.)

Adam

---

## #91695 — Bob Weinand — 2016-03-16T17:17:17+00:00

URL: https://externals.io/message/91692#91695 · In reply to: #91692

Hey, thank you both for investing your time :-)
Property types are definitely interesting.

> Am 16.03.2016 um 17:36 schrieb Phil Sturgeon <pjsturgeon@gmail.com>:
> 
> Hello everyone,
> 
> I have completed the draft for an RFC, to add Typed Properties. The
> patch has been written by the one and only Joe Watkins.
> 
> https://wiki.php.net/rfc/typed-properties
> 
> I would really appreciate constructive feedback on this RFC, with a
> few areas especially:
> 
> 1. How scared are we that integers can be expanded to floats on runtime?

This IMHO is quite necessary, for the same reasons why we even allow int to float widening with strict return types.

class foo {
    float $bar;
    function __construct(int $x) {
        assert($x > 0);
        $this->bar = 10 / $x;
    }
}

This is perfectly innocuous, but will fail for values 1, 2, 5 and 10, if we don't allow widening.
Depending on the values it might also be not caught in testing.

> 2. This whole temporary nullability situation, where unset properties
> will error on attempted usage if not set. Should they instead error
> after the constructor has been called if they are still not holding a
> value?

Erroring when using the unset property is the way to go.

The example from the RFC is showing exactly why...

class Foo {
    public int $foo;
} 
$foo = new Foo();
echo $foo->foo; // Patch currently errors here

With one property, not so much an issue, we could force a constructor.
But with 20 properties, definitely an issue.

If we'd error after constructor call, there are also other complications…

class Foo {
    public int $bar;
    function __construct() {
        global $foo;
        $foo = $this;
    }
}
try {
    new Foo;
} catch (Error $e) {}
var_dump($foo->bar); // not set, but instance is referenced

Sure, we could find ways to circumvent that and change the class to totally non-functional and making every usage of it throw an Error, but it isn't quite elegant.

> 3. Weak vs Strict. Right now this is entirely strict, with no
> declare() to change mode. Reasons for this vary, from various sources,
> but include "Not sure how to implement it" and "Well people should not
> be using properties as part of their public API".
> 
> Help on 3 would be appreciated.

Now, if we already have int to float widening (which I recommend), we anyway need to do certain checks.
At that point we can just as well add weak typing, because, why not?

We do not have an exceptional handling for return types (which are even more subject to be strict-only as it is function-local — properties may be public). And so we shouldn't have either for property types.

Thus, my recommendation is to be consistent regarding strict and weak typing regarding argument and return types.

> Also let's please avoid "PHP IS TURNING INTO JAVA" and the other
> rather common rhetoric. Strict Type Hinting might have been seen as a
> battleground for fans of strict and fans of weak to fight through a
> keyboard, but this RFC will not be the repeat.
> 
> We'll have a nice, orderly, constructive conversation about this RFC,
> and improve the patch as you all provide feedback.
> 
> Let me know what you think folks!

Thanks,
Bob

---

## #91696 — Phil Sturgeon — 2016-03-16T17:23:52+00:00

URL: https://externals.io/message/91692#91696 · In reply to: #91693

>
>
> 
> > […]
>
> First, this looks awesome, Phil!
>
> After reading through it, I think we can consult with function return
> types:
>
> function blah() : int {
>     return 55.5;
> }
>
> var_dump(blah());
>
> Will return 55.  It's a little different with properties, but what are
> your thoughts on this runtime conversion?
>

Hey Will,

Sure you'll see 55 in weak mode, but in strict mode you'll see 55.5.

I don't really want to delve too much into how return types work in
this RFC, because it doesn't feel entirely relevant.

---

## #91697 — Phil Sturgeon — 2016-03-16T17:26:33+00:00

URL: https://externals.io/message/91692#91697 · In reply to: #91694

> 
> > […]
>
> As much as I didn't (and don't) particularly like the declare()
> switch, it doesn't seem like a good idea to me to introduce a typing
> feature a year after it that doesn't use it, but has its own mode of
> operation. To me, it seems like this:
>
> class Foo {
>   public int $num;
> }
>
> (new Foo)->num = $bar;
>
> Should behave the same as the setter equivalent does today:
>
> class Foo {
>   public $num;
>   public function setNum(int $num) { $this->num = $num; }
> }
>
> (new Foo)->setNum($num);
>
> That is: if $num either can't be coerced to an integer (in weak mode)
> or isn't itself an integer (in strict mode), a TypeError should be
> thrown.
>
> We could argue about whether properties should be part of a public
> API, but the reality is that a class declaring a public property
> effectively is making it part of its API, whether you or I think it's
> a good idea or not. :)
>
> > […]

> > […]
>
> The above leads into another question I'm interested in your (and
> Joe's) general thoughts on: how do you think this would potentially
> intersect with a property getter/setter RFC in the future? Might be
> good fodder for the future scope section!

Yeah, I'll add a note about that. :)

> Finally, while the RFC shows invalid assignments generating fatal
> errors, the patch seems like it throws TypeError exceptions instead.
> Which one is the desired behaviour? (I'd prefer TypeError, personally,
> for consistency with function type declarations today.)
>
> Adam

If you put them in the class definition you'll get a fatal error from
the compiler (might change) and at runtime you get an Error. Different
things for different things. :)

---

## #91698 — Chris Riley — 2016-03-16T17:27:55+00:00

URL: https://externals.io/message/91692#91698 · In reply to: #91695

> Hey, thank you both for investing your time :-)
> Property types are definitely interesting.
>
> > […]
>
> This IMHO is quite necessary, for the same reasons why we even allow int
> to float widening with strict return types.
>
> class foo {
>     float $bar;
>     function __construct(int $x) {
>         assert($x > 0);
>         $this->bar = 10 / $x;
>     }
> }
>
> This is perfectly innocuous, but will fail for values 1, 2, 5 and 10, if
> we don't allow widening.
> Depending on the values it might also be not caught in testing.
>
> > […]
>
> Erroring when using the unset property is the way to go.
>
> The example from the RFC is showing exactly why...
>
> class Foo {
>     public int $foo;
> }
> $foo = new Foo();
> echo $foo->foo; // Patch currently errors here
>
> With one property, not so much an issue, we could force a constructor.
> But with 20 properties, definitely an issue.
>
> If we'd error after constructor call, there are also other complications…
>
> class Foo {
>     public int $bar;
>     function __construct() {
>         global $foo;
>         $foo = $this;
>     }
> }
> try {
>     new Foo;
> } catch (Error $e) {}
> var_dump($foo->bar); // not set, but instance is referenced
>
> Sure, we could find ways to circumvent that and change the class to
> totally non-functional and making every usage of it throw an Error, but it
> isn't quite elegant.
>
> > […]
>
> Now, if we already have int to float widening (which I recommend), we
> anyway need to do certain checks.
> At that point we can just as well add weak typing, because, why not?
>
> We do not have an exceptional handling for return types (which are even
> more subject to be strict-only as it is function-local — properties may be
> public). And so we shouldn't have either for property types.
>
> Thus, my recommendation is to be consistent regarding strict and weak
> typing regarding argument and return types.
>
> > […]
>
> Thanks,
> Bob
> --
> 
> 
>
>
I'm not 100% convinced that we need this now we have full type hint support
for parameters and return types; but it does have potential to remove
boiler plate for public properties. For point 2 nullable properties, how
about some syntax which allows for a property to be null, or for it to be a
specific type. I'd suggest a null assignment to fall in line with parameter
type hints eg:

class Foo {
    protected int $bar = null; //can be null
    private stdClass $baz; //can't be null
}

---

## #91700 — johannes@schlueters.de — 2016-03-16T17:39:52+00:00

URL: https://externals.io/message/91692#91700 · In reply to: #91692

> Hello everyone,
> 
> I have completed the draft for an RFC, to add Typed Properties. The
> patch has been written by the one and only Joe Watkins.
> 
> https://wiki.php.net/rfc/typed-properties

I'm no fan of all this typing business, but that's a lost case. Anyways:
What about references? (yeah, references should die, but currently they
still exist)

What's expected here:

class A {
  public int $i;
}

$a = new A();
$r = &$a->i;
$r = "foobar";

johannes

---

## #91699 — Bob Weinand — 2016-03-16T17:39:57+00:00

URL: https://externals.io/message/91692#91699 · In reply to: #91698

> Am 16.03.2016 um 18:27 schrieb Chris Riley <t.carnage@gmail.com>:
> 
> > […]
> 
> Erroring when using the unset property is the way to go.
> 
> The example from the RFC is showing exactly why...
> 
> class Foo {
>     public int $foo;
> }
> $foo = new Foo();
> echo $foo->foo; // Patch currently errors here
> 
> With one property, not so much an issue, we could force a constructor.
> But with 20 properties, definitely an issue.
> 
> If we'd error after constructor call, there are also other complications…
> 
> class Foo {
>     public int $bar;
>     function __construct() {
>         global $foo;
>         $foo = $this;
>     }
> }
> try {
>     new Foo;
> } catch (Error $e) {}
> var_dump($foo->bar); // not set, but instance is referenced
> 
> Sure, we could find ways to circumvent that and change the class to totally non-functional and making every usage of it throw an Error, but it isn't quite elegant.
> 
> I'm not 100% convinced that we need this now we have full type hint support for parameters and return types; but it does have potential to remove boiler plate for public properties. For point 2 nullable properties, how about some syntax which allows for a property to be null, or for it to be a specific type. I'd suggest a null assignment to fall in line with parameter type hints eg:
> 
> class Foo {
>     protected int $bar = null; //can be null
>     private stdClass $baz; //can't be null
> }

The point is basically, the value should never be accessed and actually return null.
If it is accessed, it always should return the type I provided.
Having it potentially return null would completely miss the point (and also confuse static analysis which would assume the value could be null, when in reality it never should be).

Concrete example: https://github.com/amphp/aerys/blob/master/lib/InternalRequest.php <https://github.com/amphp/aerys/blob/master/lib/Client.php>
That's a bunch of public properties (value object). The values are all initialized when the object is created — if a property is accessed and was forgotten to be initialized, it should error. That's helpful for detecting bugs.
You definitely don't want to define these values, which are supposed to be set upon initialization, to be _possibly_ null. Because they actually are never null from their first read access on.
E.g. InternalRequest->responseWriter is *always* a Generator object when accessed. The value is *never* potentially null (and thus would theoretically have to be checked for being null or not).

Having to force null here, would be a big mistake. Semantically and for static analysis.

Bob

---

## #91701 — Bob Weinand — 2016-03-16T17:50:23+00:00

URL: https://externals.io/message/91692#91701 · In reply to: #91700

> Am 16.03.2016 um 18:39 schrieb Johannes Schlüter <johannes@schlueters.de>:
> 
> 
> > […]
> 
> I'm no fan of all this typing business, but that's a lost case. Anyways:
> What about references? (yeah, references should die, but currently they
> still exist)
> 
> What's expected here:
> 
> class A {
>  public int $i;
> }
> 
> $a = new A();
> $r = &$a->i;
> $r = "foobar";
> 
> johannes

The patch currently prevents that.
It prevents all creation of references to properties.

The reason is technical:
We'd basically need typed zvals.
Or add some sort of write callback to typed references.

If you have a clean solution to these issues, you're more than welcome to contribute here.

Bob

---

## #91703 — johannes@schlueters.de — 2016-03-16T18:05:31+00:00

URL: https://externals.io/message/91692#91703 · In reply to: #91701

> The patch currently prevents that.
> It prevents all creation of references to properties.

To all properties? Thus

class C {
  private $data = []; // No type, old code

  public function `sort()` {
    sort($this->data);
  }
}

won't work anymore? - I think that's a major break to the language.

Workaround then would be:

class C {
  private $data = []; // No type, old code

  public function `sort()` {
    $data = $this->data;
    sort($data);
    $this->data = $data;
  }
}

Or is there a simpler way? - Quite ugly and quite some migration pain.

> The reason is technical:
> We'd basically need typed zvals.
> Or add some sort of write callback to typed references.

That matches my assumption.


Slightly un-serious:

> If you have a clean solution to these issues, you're more than welcome to contribute here.

- No typing
- No references

:-D

johannes

---

## #91704 — Bob Weinand — 2016-03-16T18:15:18+00:00

URL: https://externals.io/message/91692#91704 · In reply to: #91703

> Am 16.03.2016 um 19:05 schrieb Johannes Schlüter <johannes@schlueters.de>:
> 
> 
> > […]
> 
> To all properties? Thus
> 
> class C {
>  private $data = []; // No type, old code
> 
>  public function `sort()` {
>    sort($this->data);
>  }
> }
> 
> won't work anymore? - I think that's a major break to the language.
> 
> Workaround then would be:
> 
> class C {
>  private $data = []; // No type, old code
> 
>  public function `sort()` {
>    $data = $this->data;
>    sort($data);
>    $this->data = $data;
>  }
> }
> 
> Or is there a simpler way? - Quite ugly and quite some migration pain.

Eih, only to typed properties. Everything else would be insane ;-)
Sorry for being imprecise.

> > […]
> 
> That matches my assumption.
> 
> 
> Slightly un-serious:
> 
> > […]
> 
> - No typing
> - No references
> 
> :-D

E_BC_BREAK :-P

> johannes

Bob

---

## #91705 — johannes@schlueters.de — 2016-03-16T18:41:35+00:00

URL: https://externals.io/message/91692#91705 · In reply to: #91704

> 
> Eih, only to typed properties. Everything else would be insane ;-)
> Sorry for being imprecise.

Ok, quite a lot better, but still weird difference to the language. 


There's a notable amount of places where references are being used and
often users aren't aware. (Binding parameters in database queries, in
order to support OUT parameters, comes to mind, many array functions
take an array, some functions use it to report error codes, ...)

I guess this will be a famous support issue.

And yeah, I'd love to "fix" all those places and get rid of the
references, but BC ... it's quite massive :-)


johannes

---

## #91706 — Larry Garfield — 2016-03-16T18:50:25+00:00

URL: https://externals.io/message/91692#91706 · In reply to: #91692

> Hello everyone,
>
> I have completed the draft for an RFC, to add Typed Properties. The
> patch has been written by the one and only Joe Watkins.
>
> https://wiki.php.net/rfc/typed-properties

Overall thought: <3

> I would really appreciate constructive feedback on this RFC, with a
> few areas especially:
>
> 1. How scared are we that integers can be expanded to floats on runtime?

As others have said, follow the existing widening rules. int->float is 
safe for strict params and returns, so should be safe here for the same 
reason.  Inconsistency here would suck.

> 2. This whole temporary nullability situation, where unset properties
> will error on attempted usage if not set. Should they instead error
> after the constructor has been called if they are still not holding a
> value?

I fall back to a statement I made in a blog post a while back:

http://www.garfieldtech.com/blog/empty-return-values

" But consider what you could do instead that would not force me to 
throw `is_null()` around my code, because throwing `is_null()` around my 
code makes me sad. `NULL` should be the return value of last resort, 
because it means nothing. (Literally.)"

Allowing default-null on properties means that as someone using that 
property, I have two options:

1) Throw a lot of `is_null()` calls around my code.
2) Assume that whoever initialized the code provided a value by the time 
initialization is done and skip those extra checks.

Insert that old adage about what happens when you assume.

End-of-constructor checks seem like a good approach; they have to be 
uninitialized at some point when new is called initially, but they 
should be guaranteed set as soon as possible.  End of the constructor is 
"as soon as possible", and I think reasonably 
static-analysis-catchable.  (Meaning my IDE can yell at me appropriately.)

That removes `is_null()` calls from the rest of my codebase, which is a 
good thing.

> 3. Weak vs Strict. Right now this is entirely strict, with no
> declare() to change mode. Reasons for this vary, from various sources,
> but include "Not sure how to implement it" and "Well people should not
> be using properties as part of their public API".

I cannot help on the implementation front, but logically it doesn't make 
sense to me as an end-user that properties are always-strict while 
params and returns are not.  As with integer->float widening, 
consistency should be the default position.  If that means a slight 
performance hit in weak mode (does it?), well, that's one more reason 
people should be using strict mode. :-)

Regarding the void type (as noted in the Open Issues section): A void 
type on a property renders that property useless.  You couldn't ever 
assign to it, and it would only ever evaluate to `NULL` at best. So... do 
whatever is easiest, implementation-wise.  If it's technically possible 
to define a property as void, meh, I don't much care since it's useless 
anyway.  If it's easy enough to forbid, forbid.  If it's easier to make 
it legal syntax but optimize out of the class structure on compile, 
that's good too.

Syntactically, what happens if you omit the visibility keyword, or use 
var?  (Assuming var survives.)  Ie, is this legal:

class Foo {
   int $a;
}

And/or, since most other pre-keywords are of flexible position would 
this be legal:

class Foo {
   int public $a;
}


Like Adam, I'd also be interested in the implications for the property 
getter/setter RFC as I would love for that to come back at some point.  
(Out of scope for this RFC, certainly, but making sure it won't break 
anything in that direction later would be good.)

-- 
--Larry Garfield

---

## #91707 — Bob Weinand — 2016-03-16T18:51:11+00:00

URL: https://externals.io/message/91692#91707 · In reply to: #91705

> Am 16.03.2016 um 19:41 schrieb Johannes Schlüter <johannes@schlueters.de>:
> 
> 
> > […]
> 
> Ok, quite a lot better, but still weird difference to the language. 
> 
> 
> There's a notable amount of places where references are being used and
> often users aren't aware. (Binding parameters in database queries, in
> order to support OUT parameters, comes to mind, many array functions
> take an array, some functions use it to report error codes, ...)
> 
> I guess this will be a famous support issue.
> 
> And yeah, I'd love to "fix" all those places and get rid of the
> references, but BC ... it's quite massive :-)
> 
> 
> johannes

Totally one of my biggest issues with it...

While I'm liking the general idea, this definitely may be the reason why I'd vote "no" later.

But we're in a very early state, maybe some clever mind finds a solution to this problem and makes everyone happy :-)

Bob

---

## #91708 — Net Mo — 2016-03-16T18:58:26+00:00

URL: https://externals.io/message/91692#91708 · In reply to: #91705

class SomeStruct{ public int $a; }

class Joe
{
    public SomeStruct $struct;

    function test1() : SomeStruct{
        return new SomeStruct();                // TypeError: can't return
a type whose fields' type declarations aren't fulfilled
    }

    function test2(SomeStruct $struct){         // TypeError: can't pass in
a type whose fields' type declarations aren't fulfilled [*]
    }

    function test3(){
        $this->struct = new SomeStruct();       // TypeError: can't assign
to a typed field a type whose fields' type declarations aren't fulfilled
    }
}

(new Joe)->test2(new SomeStruct()); // [*]

2016-03-16 19:41 GMT+01:00 Johannes Schlüter <johannes@schlueters.de>:

> 
> > […]
>
> Ok, quite a lot better, but still weird difference to the language.
>
>
> There's a notable amount of places where references are being used and
> often users aren't aware. (Binding parameters in database queries, in
> order to support OUT parameters, comes to mind, many array functions
> take an array, some functions use it to report error codes, ...)
>
> I guess this will be a famous support issue.
>
> And yeah, I'd love to "fix" all those places and get rid of the
> references, but BC ... it's quite massive :-)
>
>
> johannes

---

## #91709 — Ryan Pallas — 2016-03-16T19:21:10+00:00

URL: https://externals.io/message/91692#91709 · In reply to: #91706

On Wed, Mar 16, 2016 at 12:50 PM, Larry Garfield <larry@garfieldtech.com>
wrote:

> 
>
> > […]
>
> I fall back to a statement I made in a blog post a while back:
>
> http://www.garfieldtech.com/blog/empty-return-values
>
> " But consider what you could do instead that would not force me to throw
> `is_null()` around my code, because throwing `is_null()` around my code makes
> me sad. `NULL` should be the return value of last resort, because it means
> nothing. (Literally.)"
>
> Allowing default-null on properties means that as someone using that
> property, I have two options:
>
> 1) Throw a lot of `is_null()` calls around my code.
> 2) Assume that whoever initialized the code provided a value by the time
> initialization is done and skip those extra checks.
>
> Insert that old adage about what happens when you assume.
>
> End-of-constructor checks seem like a good approach; they have to be
> uninitialized at some point when new is called initially, but they should
> be guaranteed set as soon as possible.  End of the constructor is "as soon
> as possible", and I think reasonably static-analysis-catchable.  (Meaning
> my IDE can yell at me appropriately.)
>
> That removes `is_null()` calls from the rest of my codebase, which is a good
> thing.
>
>
I'm not sure I like the "after contructor" because that's not necessarily
when the object is finished being initialized. Consider this:

abstract class Contract
{
    private function __construct() {}

    public static function fromArray(array $aProps) : Contract
    {
        $s = new static();
        foreach ($aProps as $k => $v) {
            if (property_exists(static::class, $k)) {
                $s->$k = $v;
            }
        }

        return $s;
    }
}

class User extends Contract {
   public int $id;
   public string $name;
}

$user = User::fromArray(['id' => 123, 'name' => 'derokorian']);

In this example, the constructor finishes but the properties still are not
initialized at time of finishing. This is a pretty common pattern as well.

---

## #91710 — Phil Sturgeon — 2016-03-16T19:29:55+00:00

URL: https://externals.io/message/91692#91710 · In reply to: #91700

On Wed, Mar 16, 2016 at 1:39 PM, Johannes Schlüter
<johannes@schlueters.de> wrote:
> 
> > […]
>
> I'm no fan of all this typing business, but that's a lost case. Anyways:
> What about references? (yeah, references should die, but currently they
> still exist)
>
> What's expected here:
>
> class A {
>   public int $i;
> }
>
> $a = new A();
> $r = &$a->i;
> $r = "foobar";
>
> johannes
>
>

Hey there!

I put your code into 3v4l so you could see what would happen:

https://3v4l.org/taC8D

Fatal error: Uncaught TypeError: Typed property A::$i must not be referenced

Is that what you expect? If not, what would you expect?

---

## #91711 — Andrey Andreev — 2016-03-16T19:30:44+00:00

URL: https://externals.io/message/91692#91711 · In reply to: #91709

Hi,



> On Wed, Mar 16, 2016 at 12:50 PM, Larry Garfield <larry@garfieldtech.com>
> wrote:
>
> > […]
> soon
> > […]
> good
> > […]
> I'm not sure I like the "after contructor" because that's not necessarily
> when the object is finished being initialized. Consider this:
>
> abstract class Contract
> {
>     private function __construct() {}
>
>     public static function fromArray(array $aProps) : Contract
>     {
>         $s = new static();
>         foreach ($aProps as $k => $v) {
>             if (property_exists(static::class, $k)) {
>                 $s->$k = $v;
>             }
>         }
>
>         return $s;
>     }
> }
>
> class User extends Contract {
>    public int $id;
>    public string $name;
> }
>
> $user = User::fromArray(['id' => 123, 'name' => 'derokorian']);
>
> In this example, the constructor finishes but the properties still are not
> initialized at time of finishing. This is a pretty common pattern as well.
>

Also, a LOT of code would end up with e.g. a default value of 0 for an
integer property, still having to check if it was properly populated with a
positive value - not much of an improvement over NULLs.

Cheers,
Andrey.

---

## #91712 — Fleshgrinder — 2016-03-16T20:29:53+00:00

URL: https://externals.io/message/91692#91712 · In reply to: #91692

Awesome feature thanks for the RFC. :)


> 1. How scared are we that integers can be expanded to floats on runtime?
>

This is already what happens in PHP all the time and I personally only
see harm if we change that. People are already not understand what the
difference between the two is and someone who is serious about this
topic is taking care of it on her/his own (many thanks to *intdiv*) or
is using strings anyways (*bcmath*/*gmp*).


> 2. This whole temporary nullability situation, where unset properties
> will error on attempted usage if not set. Should they instead error
> after the constructor has been called if they are still not holding a
> value?
>

I see a big problem with the erroring no matter when as others already
pointed out, e.g. together with named constructors (or factory methods
if you prefer that name) but also with lazy loading. I think that the
null value of properties during and after construction should simply be
ignored and left to the implementer. I know that it would be nice to
have 100% assurance that the property is always set but it would simply
result in rules that are too strict for various use cases. I mean,
aren't we trying to solve a problem that never was a problem here?

Another more complicated user case would be *mysqli_fetch_object* that
populates the properties with values from a storage but values that
should become something specific and strict at some point but are
initially populated as strings. Type coercion would be a nice thing here
but with strict checks afterwards. Note that this cannot be handled by
the extension due to user types:

    final class Bar {

        private string $data;

        public function __construct(string $data) {
            $this->data = $data;
        }

    }

    final class Foo {

        private Bar $bar;

        private function __construct() {
            if (isset($this->bar)) {
                $this->bar = new Bar($bar);
            }
        }

    }

    $mysqli_result->fetch_object(Foo::class);

It is correctly populated with a string and the constructor changes it
to the desired instance. All fine, but the strict type check would kill
everything here.

I think that the strict type checks should start with the first
*userland* assignment and at no other point in time. The correct
initialization of an object is up to the implementer as it always was.


> [...] how about some syntax which allows for a property to be null,
> or for it to be a specific type. I'd suggest a null assignment to
> fall in line with parameter type hints eg:
>
> class Foo {
>     protected int $bar = null; //can be null
>     private stdClass $baz; //can't be null
> }
>

This aligns nicely with the syntax that is present in PHP for arguments
since ages and it directly could solve the Nullable problem mentioned in
future scope. An example to illustrate how nicely it aligns with
existing PHP 5+ syntax:

    final class Foo {

        private int $bar = null;

        public function setBar(int $bar = null): void {
            $this->bar = $bar;
        }

    }

    (new Foo)->setBar(42);
    (new Foo)->setBar(null);

Additionally the extreme verbosity is super nice.


> 3. Weak vs Strict. Right now this is entirely strict, with no
> declare() to change mode. Reasons for this vary, from various sources,
> but include "Not sure how to implement it" and "Well people should not
> be using properties as part of their public API".
> 

An ini setting to control type checks and hints would be a nice thing to
have. Like the checked mode of Google's Dart language. Such a setting
could and should also allow to disable type checks altogether, like we
have it with assertions:

    strict_types = -1 ; NOOP
    strict_types = 0  ; PHP 5 Style
    strict_types = 1  ; PHP 7 Coercion Style
    strict_types = 2  ; PHP 7 Strict Style

Where 1 would be the default since the default should be for development
and people who hate strict types just throw that zero in their ini and
are fine to reuse any code out there while ignoring all property/scalar
type checks/hints.

This would make the `declare` thingy pretty useless and I think it is
easier to understand. I thought that this approach was kind of weird
since its inception.


> What about references? (yeah, references should die, but currently
> they still exist)
>
> What's expected here:
>
> class A {
>   public int $i;
> }
>
> $a = new A();
> $r = &$a->i;
> $r = "foobar";
>

I think this missing functionality is a blocker right now. Either we
have a plan to get rid of references altogether as Johannes mentions it
or the typed properties need support for it.

Note that the following currently works with the patch, which might lead
to more ranting in regards to missing/overlooked functionality if the
properties on their own do not support it.

    declare(strict_types=1);

    class A {

        private int $x = 0;

        public function &x(): int {
            return $this->x;
        }

    }

    $a = new A;
    $x =& $a->x();
    $x = 42;

    echo $a->x(); // 42

-- 
Richard "Fleshgrinder" Fussenegger

---

## #91714 — bjorn.x.larsson@telia.com — 2016-03-16T21:12:30+00:00

URL: https://externals.io/message/91692#91714 · In reply to: #91692

Den 2016-03-16 kl. 17:36, skrev Phil Sturgeon:
> Hello everyone,
>
> I have completed the draft for an RFC, to add Typed Properties. The
> patch has been written by the one and only Joe Watkins.
>
> https://wiki.php.net/rfc/typed-properties
>
> I would really appreciate constructive feedback on this RFC, with a
> few areas especially:
>
> 1. How scared are we that integers can be expanded to floats on runtime?
>
> 2. This whole temporary nullability situation, where unset properties
> will error on attempted usage if not set. Should they instead error
> after the constructor has been called if they are still not holding a
> value?
>
> 3. Weak vs Strict. Right now this is entirely strict, with no
> declare() to change mode. Reasons for this vary, from various sources,
> but include "Not sure how to implement it" and "Well people should not
> be using properties as part of their public API".
>
> Help on 3 would be appreciated.
>
> Also let's please avoid "PHP IS TURNING INTO JAVA" and the other
> rather common rhetoric. Strict Type Hinting might have been seen as a
> battleground for fans of strict and fans of weak to fight through a
> keyboard, but this RFC will not be the repeat.
>
> We'll have a nice, orderly, constructive conversation about this RFC,
> and improve the patch as you all provide feedback.
>
> Let me know what you think folks!
>
Like the RFC :)

Could this be an opportunity to have default visibility for property's when
they are typed in a similar fashion like for functions? Meaning no 
visibility
implies public and code below would work.
class A {
   int $i=7;
   function f() {
       echo $this->i;
   }
}
$a = new A();
$a->f();
echo $a->i;

Was inspired by discussion in "var" Deprecation thread.

Regards //Björn

---

## #91715 — Fleshgrinder — 2016-03-16T21:47:09+00:00

URL: https://externals.io/message/91692#91715 · In reply to: #91714

> Like the RFC :)
> 
> Could this be an opportunity to have default visibility for property's when
> they are typed in a similar fashion like for functions? Meaning no
> visibility
> implies public and code below would work.
> class A {
>   int $i=7;
>   function f() {
>       echo $this->i;
>   }
> }
> $a = new A();
> $a->f();
> echo $a->i;
> 
> Was inspired by discussion in "var" Deprecation thread.
> 
> Regards //Björn
> 

I'd rather like to see this being package visible rather than public. Of
course, that would be yet another Java thingy and I am not trying to
jump on the bandwagon here.

First, I like the Class Friendship RFC because it is very explicit in
terms of giving access to your members. However, it fails to solve some
issues in API design because friendship is not inherited and it is
especially useless in a composer package world where the classes you
might define as a friend are not even available (example follows).

Second, I like the Private Class PR because it is very simple in hiding
a class. The fact that is is purely namespace based is however a problem
because one might want to have a class in a sub-namespace but still have
the ability to instantiate it. Also protected classes would be only
possible by restricting them from the current down to sub-namespaces
which is totally meh.

The introduction of a new `package` keyword to provide access modifiers
for more fine grained control could solve all of the above issues.

    <?php
    // Composer Package `fleshgrinder/best-cms-entity`

    package fleshgrinder/entity;

    namespace Fleshgrinder\Entity;

    use DateTimeImmutable;

    final public class Entity {

        int $id;

        string $name;

        DateTimeImmutable $created;

        DateTimeImmutable $changed;

        private function __construct() {}

        public function equals($other) {
            if ($other instanceof self) {
                return $this->id === $other->id
                    || $this->name === $other->name;
            }
            return false;
        }

    }

    <?php
    // Composer Package `fleshgrinder/best-cms-entity`

    package fleshgrinder/entity;

    namespace Fleshgrinder\Repo;

    use Fleshgrinder\Entity\Entity;

    public interface Repo {

        public function create(string $name): Entity:

    }

    <?php
    // Composer Package `fleshgrinder/best-cms-in-memory-entity-repo`

    package fleshgrinder/entity;

    namespace Fleshgrinder\Repo;

    use DateTimeImmutable;
    use Fleshgrinder\Entity\Entity;

    final public class InMemoryRepo implements Repo {

        private array $entities = [];

        public function create(string $name): Entity {
            $new = new Entity();
            $new->id = count($this->entities) + 1;
            $new->name = $name;
            $new->created = $new->changed = new DateTimeImmutable();

            foreach ($this->entities as $entity) {
                if ($entity->equals($new)) {
                    throw new \Exception;
                }
            }

            $this->entities[] = $new;

            return clone $new;
        }

    }

-- 
Richard "Fleshgrinder" Fussenegger

---

## #91717 — Larry Garfield — 2016-03-16T22:00:39+00:00

URL: https://externals.io/message/91692#91717 · In reply to: #91711

> Also, a LOT of code would end up with e.g. a default value of 0 for an 
> integer property, still having to check if it was properly populated 
> with a positive value - not much of an improvement over NULLs. Cheers, 
> Andrey. 

That's fine.  Type checking doesn't say that a value is correct or 
meaningful; it just enforces the shape of the data.

Vis, type enforcement tells you that the property is an integer; it 
doesn't tell you that the integer is within the range of legal values 
for the temperature of a room.  It tells you that a property is a 
string; it doesn't tell you that the string doesn't contain NSFW words.  
Those are all application-level concerns, not type-level concerns, no 
matter what we do here.  (Just like they are for parameters and returns 
already.)

IMO, int/string/float is only a big deal on properties if you're using 
reflection for DB schema generation or similar, as it lets you remove an 
annotation.  (That's a useful benefit, though.)  The bigger impact for 
me is for class names, so I can enforce a given object type on a certain 
property.  Knowing "at least it's not NULL" has a much larger benefit in 
that case, as you avoid many "method called on non-object 100 execution 
lines later than the actual bug, good luck finding it" errors. :-)

-- 
--Larry Garfield

---

## #91719 — Andrey Andreev — 2016-03-16T22:17:01+00:00

URL: https://externals.io/message/91692#91719 · In reply to: #91717

On Thu, Mar 17, 2016 at 12:00 AM, Larry Garfield <larry@garfieldtech.com>
wrote:

> 
>
> > […]
>
> That's fine.  Type checking doesn't say that a value is correct or
> meaningful; it just enforces the shape of the data.
>
> Vis, type enforcement tells you that the property is an integer; it
> doesn't tell you that the integer is within the range of legal values for
> the temperature of a room.  It tells you that a property is a string; it
> doesn't tell you that the string doesn't contain NSFW words.  Those are all
> application-level concerns, not type-level concerns, no matter what we do
> here.  (Just like they are for parameters and returns already.)
>
> IMO, int/string/float is only a big deal on properties if you're using
> reflection for DB schema generation or similar, as it lets you remove an
> annotation.  (That's a useful benefit, though.)  The bigger impact for me
> is for class names, so I can enforce a given object type on a certain
> property.  Knowing "at least it's not NULL" has a much larger benefit in
> that case, as you avoid many "method called on non-object 100 execution
> lines later than the actual bug, good luck finding it" errors. :-)


Yet, your argument was about avoiding `is_null()` calls within application
logic and you'd gain nothing if you end up having to write ! empty()
instead. :)
I'd rather have a `NULL` to tell me that I have nothing instead of a
supposedly initialized but otherwise invalid value.

Cheers,
Andrey.

---

## #91721 — Phil Sturgeon — 2016-03-16T22:23:35+00:00

URL: https://externals.io/message/91692#91721 · In reply to: #91719

> On Thu, Mar 17, 2016 at 12:00 AM, Larry Garfield <larry@garfieldtech.com>
> wrote:
>
> > […]
>
>
> Yet, your argument was about avoiding `is_null()` calls within application
> logic and you'd gain nothing if you end up having to write ! empty()
> instead. :)
> I'd rather have a `NULL` to tell me that I have nothing instead of a
> supposedly initialized but otherwise invalid value.
>
> Cheers,
> Andrey.

Not sure what you're saying there Andrey.

> That's fine.  Type checking doesn't say that a value is correct or meaningful; it just enforces the shape of the data.
> Larry

Solid points! Exactly that. A type relevant default of 0 is not
definitively invalid, it's up to application logic to work that out. 0
is totally valid as an integer.

I do quite like the idea of type relevant defaults being provided, so
0, [], "", etc, just like Go.

The only trouble I see there is: what sane default is given for
`public Foo $foo;`? Instantiate the class? Erf.

---

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