Re: [PHP-DEV] [RFC][Vote] Typed Properties
On 5/27/2016 2:34 PM, Lester Caine wrote: > Hence the 'in an ideal world'! It is perhaps worth making clear that a > 'typed property' element IS simply a holder for the pointer to the real > element while the untyped properties are the element themselves? The > differentiation of 'scalar' probably comes into play, but does that > result in untyped scalers having to have the overheads for adding the > type flags? > Nope, they both work exactly the same way. Typed properties just guard the properties from assignment of values that are not typed hinted against. I don't know what you mean with untyped scalars. Every variable always has a type. It is up to you if you care about it or not. On 5/27/2016 2:34 PM, Lester Caine wrote: > And 32bit builds mess things up as well ... > YES! On 5/27/2016 2:34 PM, Lester Caine wrote: > With the proviso that $o is not used again ... currently all of my > object classes have a constructor for a blank object along with a loader > to 'initialize' the data. Empty objects such as 'father' can be > populated with data and saved, loaded with an existing record, or wiped > if incorrect associations existed ... allowing the correct data to be > added. AJAX allows things to happen within a page which in the past > would have been complete new page loads without any of the problems of > 'cached' data? > Sounds like bad design to me where you always need to know when to call what and when what was called but if it works for you. :) -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC][Vote] Typed Properties
On 5/27/2016 11:53 AM, Lester Caine wrote: > On 27/05/16 10:16, Rowan Collins wrote: >> My comment was in reaction to Lester expressing surprise at destroying >> and re-creating objects when new data is fetched. To be clear, I'm >> talking about this: >> >> // Clear old data >> $this->data = []; >> // Re-populate from new DB result >> foreach ( $db_resultset as $row ) { >>$this->data[] = new SomeModel($row); >> } >> >> The most useful typehints are inside the SomeModel class, not the >> table-level wrapper. This is true even if they're just dumb structs, and >> all the behaviour is at the table level, because it presumably has >> basically one field: array $data. > > Probably the only difference here is that '$row' in my result set is not > a dumb structure. It has type information, field lengths and potentially > even value constraints. So my table level wrapper can potentially have > the same typehints that you are then adding to SomeModel. All the > properties of SomeModel already exist and if typed properties are > working correctly in PHP $row can simply be accessed directly. This is > why in my book all of the debate about 'attributes' and everything else > is so tied up in the definition of making a simple variable a much more > flexible generic object. > The type hints belong to SomeModel because you want to insert the data into SomeModel and not into your repository (Table). class Person { public int $id; public DateTimeImmutable $created; public DateTimeImmutable $changed; public string $name; public DateTimeImmutable $birth; public ?DateTimeImmutable $marriage; public ?DateTimeImmutable $death; public int $number_of_siblings = 0; } class SomeModels { public function findAll() { foreach ($db->select('SELECT * FROM `SomeModel`') as $row) { $some_model = new SomeModel; $some_model->id = $row['id']; $some_model->created = new DateTimeImmutable($row['created']); $some_model->changed = new DateTimeImmutable($row['changed']); $some_model->name = $row['name']; $some_model->birth = new DateTimeImmutable($row['birth']); if (isset($row['marriage'])) { $some_model->marriage = new DateTimeImmutable($row['marriage']); } if (isset($row['death'])) { $some_model->death = new DateTimeImmutable($row['death']); } $some_model->number_of_siblings = $row['number_of_siblings']; yield $some_model; } } } The Person object is however still behaviorless and anemic, throwing type hints at public properties does not change that fact. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC][Vote] Typed Properties
On 5/27/2016 11:41 AM, Lester Caine wrote: > Now I am confused, but it's probably because I'm looking at a simple > > $f->d = new DateTime( $initial ); > > While you are looking at > > If ( isset($initial) ) > then $f->d = new DateTime( $initial ); > else $f->d = null; > > While the original code would have simply been > > $f->d = $initial; > > And in an ideal world, because $d has been typed as DateTime this would > magically run 'new DateTime($initial)' which is where I am stumbling > because *I* simply look at '?DateTime $d' as creating a DateTime object > where in fact $d is a different type of object which will then hold the > link to the real one. I am still looking for $d to be an object I can do > all of the checks on that are provided by int or DateTime as appropriate > ... the object needs to exist before the 'new' in order to know if you > need the first or second type of $initial code ... or we make typed > properties only work one way or the other? > PHP does not automagically instantiate the DateTime object for you, this is still your responsibility. The type hint on the property only restricts what you are allowed to assign to the property, nothing else. It is true that PHP will coerce the value automatically if you are in weak mode but this is only true for scalar values and nothing else. Also note that you might not want that while working with a database because PHP might destroy your UNSIGNED BIGINTs without you noticing. class O { public ?DateTime $d; } if (isset($row['d'])) { $o->d = new DateTime($row['d']); } No need to assign null since it already is null by default and the nullable hint will not result in any errors upon accessing it. PS: The UNSIGNED BIGINT thing is one of the reasons why I want intersection and union types so that we can do the following: class O { private int|string $id; } And leave it to a more intelligent system to determine whether this can be safely converted to an int or not (e.g. MySQLi). -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC][Vote] Typed Properties
On 5/27/2016 10:35 AM, Tony Marston wrote: > I disagree completely. In a database system there is no rule that says > an object can only hold data from a single row otherwise Martin Fowler, > the author of PoEE, would not have patterns that hold data from several > rows. When I instantiate one of my table classes it is a valid but empty > object. There are two actions I can perform - inject data from the > client via the $_POST array, or tell it to retrieve data from the > database. This may involve just a single row, or multiple rows. When > reading from the database it may even result in zero rows. > Yes?!? That is how everybody does it. On 5/27/2016 10:35 AM, Tony Marston wrote: > You are trying to change the language to suit the way that you work > without considering the fact that your way is not the only way and this > change may not suit the way that others work. As far as I can see this > proposal not only does not solve a genuine problem, it adds levels of > complexity that will do nothing but increase the WTF! factor for untold > numbers of programmers who have been happily using the language for years. > Oh come on, this story again? Please, just keep on using PHP in the way you like it without making use of these new features. Nothing is changing and if all your problems are solved, good. And please, please don't start the PHP 5.2 was so much better discussion now and claiming that we all are incapable programmers. We know it by now. ;) -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC][Vote] Typed Properties
On 5/26/2016 11:40 PM, Rowan Collins wrote: > On 26/05/2016 21:00, Fleshgrinder wrote: >> PS: This needs a cast unless some special driver options are active. >> >>$me->numSiblings = (int) $db_record['num_siblings']; > > ...or unless strict_types=0, in which case PHP will add an implicit cast > for you. :) > > Regards, > I need to get used to that nice new feature. ;) -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC][Vote] Typed Properties
On 5/26/2016 10:40 PM, Lester Caine wrote: > I think what is irritating here is that actually both of these can still > validly be null. It's HAVING to add the ? to every item when actually by > conventions 'NOT NULL' is the exception. Would ? indicating 'NOT NULL' > actually be better since it IS only adding that flag which is required > here to block the use of null? > The use case for the majority is the opposite. Java decided to go for the /everything can be null/ and people are making jokes about it all the time. On 5/26/2016 10:40 PM, Lester Caine wrote: > BUT DateTime currently will not store 'null' - it returns 'now' instead. > We end up having to store string or integer values because we can't > store a null date :( > This is unrelated to typed properties. You can implement your own DateTime class that has support for your special use case. On 5/26/2016 10:40 PM, Lester Caine wrote: > The suggestion I was seeing was that a 'NOT NULL' value had to be > initialized. I think my problem is perhaps is just what errors are > created that break the normal flow and what gets returned when checking > to see IF a value has been initialised. > Nothing breaks your normal flow, you will be able to use isset() and empty() as you always were. On 5/26/2016 10:40 PM, Lester Caine wrote: > $me->numSiblings would actually be null in this case if it has not yet > been established since the answer may well be '0' but that just explains > why null is still valid even for an int property. We just have no idea > if it's null because it's just been created or because the database read > returned 'null'. > 0 !== null and if your database can return null for this field add it to its definition: `public ?int $num_siblings` On 5/26/2016 10:40 PM, Lester Caine wrote: > The alternate 'not null' value is more clear cut in that 'null' can mean > that it is uninitialized, and one needs to run the initialization code > for it. I need is_null($me->numSiblings) to work and return true so I > can select the initialization code, or should there be a new state of > 'uninit' as well? Then if we want to 'reset' the person object do the > 'not null' entries get rest to null so they can be re-initialized. > 'unset' the person does not remove the object simply rewinds it to an > unset state ... so should unset of these typed properties do that or do > we actually need an uninit? > Not null would result in the same questions being raised as we are facing them now. You can use !isset() instead of is_null(), it does the same thing without errors being raised. The concept of reseting objects and reinitializing them is something I read very often from you. This is against all of OOP. What you are basically doing is misusing classes as behaviorless anemic containers of data. Even Smalltalk from the '70s did not encourage this and PHP never did so either. Just because it is possible does not mean that it is the proper way. Just make a new instance. ;) -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC][Vote] Typed Properties
On 5/26/2016 9:56 PM, Rowan Collins wrote: > The current proposal (or the one which I am advocating) for that is that > you would have something like the following: > > class Person { > public \DateTime $birth; > public ?\DateTime $marriage; > public ?\DateTime $death; > public int $numSiblings; > } > > Creating an object would leave it in an invalid state: > > $me = new Person; > // accessing $me->birth or $me->numSiblings is an error in this state, > because defaulting to NULL would violate their type constraint > // accessing $me->marriage or $me->death returns NULL (because they > allow nulls) but raises E_NOTICE > > Now you can initialise the mandatory fields: > > $me->birth = new \DateTime($db_record['birth_date']); > $me->marriage = new \DateTime($db_record['marriage_date']); > $me->death = new \DateTime($db_record['death_date']); > $me->numSiblings = $db_record['num_siblings']; > // all properties can now be safely accessed > // $me->marriage and $me->death may still be null, as indicated by the > "?" in their type spec > // $me->birth is guaranteed to be a \DateTime object > > Regards, > Nothing to add here. :) PS: This needs a cast unless some special driver options are active. $me->numSiblings = (int) $db_record['num_siblings']; -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC][Vote] Typed Properties
On 5/26/2016 9:10 PM, Lester Caine wrote: > DateTime is probably a better example to work with than 'int' since it > already has a long pedigree of problems and clashes where many projects > had their own interpretation and still use their own version of the > class. My problem with '\DateTime $d' is that by default it returns > 'now' rather than an 'empty/null' value in which to put the data from > the database. I can't create a 'null' version of DateTime so one has to > have a phantom date simply to ensure you know if it has been initialized > with your own data later - or continue to use the older user space classes. > > It is handling just how the variable/property is initialized that is the > whole problem here and there may be very good reasons that the > initialization is later then the 'construct' be that a DateTime or an > int ... null is the correct way of indicating that 'as yet we do not > have the value of type xxx' just as it does for an untyped value, so > trying to make a special case to block it's use is simply strangling > normal usage in other cases? > Could you come up with some example code of what you cannot achieve? I cannot think of a single situation that is valid and not a developer error which would be impossible with the currently discussed approach. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC][Vote] Typed Properties
On 5/26/2016 7:20 PM, Rowan Collins wrote: > I think the difference is the emphasis of whose responsibility it is to > fix it: a TypeError confirms that the error is in the O class for > exposing an incorrectly typed property; a NullPointerException, as you > put it, makes it my fault for trusting the class. > > Or to put it a different way, is the error in the first arrow (accessing > "->d") or the second one (de-referencing "d->"). > > > At the end of the day, all the type notations being added to PHP are > just assertions anyway. So the same could be said of this: > > function foo(\DateTime $d) { >echo $d->format('Y-m-d H:i:s'); > } > foo(null); > > If this didn't throw an error at "foo(null)", it would throw an error at > "$d->format". > Yes, they are just assertions and design by contract and you make a very good point here for an actual error. I am convinced. ;) However, it should not throw an error for isset() and empty() to allow more special constructs. As we already have it in place everywhere with the two. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC][Vote] Typed Properties
On 5/26/2016 7:00 PM, Tom Worster wrote: > On 5/26/16, 12:48 PM, "Fleshgrinder" wrote: >> This would be a valid approach too, yes. I personally would be against >> it because I do not want to initialize all my properties. >> >> class A { >> >>private int $x; >> >>public function getX() { >> if (empty($this->x)) { >>$this->x = 42; >> } >> return $this->x; >>} >> >> } >> >> This would not yield an E_NOTICE because both isset() and empty() never >> do. This allows the attentive programmers to keep up there coding >> practices without the necessity to assign meaningless values everywhere. >> >> class A { >> >>/** -1 is invalid */ >>public int $x = -1; >> >>/** 'INVALID' is invalid but empty string is allowed */ >>public string $s = 'INVALID'; >> >>/** Null byte is invalid but anything else is valid */ >>public string $welcome_to_the_c_world = '\0'; >> >> } > > If you want that kind of thing, you can do it the old PHP way like this > > class A { > private ?int $x = null; > ... > Doing that defeats the whole purpose of typed properties in my opinion. I want to be sure that nobody can assign null to this property and only allow it to be null until I initialize it myself. class A { private int $x; private function getX() { if (empty($this->x)) { $this->x = 42; } return $this->x; } public function doSomething() { // lots of code ... $_ = $__ * $this->x; // lots of code ... } } This would emit an E_NOTICE (and possibly end up in an error due to null) and the developer of the doSomething() method will notice that she should call getX() instead. This would not be the case with private ?int $x. :( -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC][Vote] Typed Properties
On 5/26/2016 6:50 PM, Rowan Collins wrote: > As I'm sure has already been pointed out (I haven't followed the whole > thread) this defeats a large advantage of typed properties - I now can't > read from the property without checking if it's null, so I can't do this: > > class O { >public \DateTimeImmutable $d; > } > echo (new O)->d->format('Y-m-d H:i:s'); > > There's no ? on the type def, so I ought to be able to trust the type. A > TypeError makes more sense here, because it is a programming error for > it to be in this state. > That is exactly what Stanislav raised too. I really have no idea how we should prevent this from happening and honestly think we shouldn't. Your construct will result in a fatal error (also known as NullPointerException to some, *evil-laughter*) anyways preceded by an E_NOTICE that tells you that your property is not defined. I am of course open for ideas but emitting another kind of fatal error does not really make things better imho. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC][Vote] Typed Properties
On 5/26/2016 6:40 PM, Tom Worster wrote: > On 5/26/16, 12:30 PM, "Fleshgrinder" wrote: > >> The problem is a completely different one, how should the following code >> behave? >> >> class A { >> >>public int $x; >> >> } >> >> (new A)->x; >> >> The property has no value assigned but it is being accessed. The current >> PHP behavior is to simply initialize it with null. But this is >> impossible according to the type definition. >> >> There are not many ways to handle this. I think we already had all of >> them proposed: >> >> 0. Fatal error after __construct was called. >> 1. Fatal error and abort. >> 2. Initialize with appropriate type. >> 3. Initialize with null. > > Under another 5th option, the problem you state does not arise. Disallow > "public int $x;". Under this option you may declare $x with type int and > an initial value or you may declare $x without type but you may not > declare $x with type (nullable or not) and undefined initial value. > > Tom > This would be a valid approach too, yes. I personally would be against it because I do not want to initialize all my properties. class A { private int $x; public function getX() { if (empty($this->x)) { $this->x = 42; } return $this->x; } } This would not yield an E_NOTICE because both isset() and empty() never do. This allows the attentive programmers to keep up there coding practices without the necessity to assign meaningless values everywhere. class A { /** -1 is invalid */ public int $x = -1; /** 'INVALID' is invalid but empty string is allowed */ public string $s = 'INVALID'; /** Null byte is invalid but anything else is valid */ public string $welcome_to_the_c_world = '\0'; } Not cool. :( -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC][Vote] Typed Properties
The problem is a completely different one, how should the following code behave? class A { public int $x; } (new A)->x; The property has no value assigned but it is being accessed. The current PHP behavior is to simply initialize it with null. But this is impossible according to the type definition. There are not many ways to handle this. I think we already had all of them proposed: 0. Fatal error after __construct was called. 1. Fatal error and abort. 2. Initialize with appropriate type. 3. Initialize with null. Option 0. is out the window because it creates endless edge cases. Option 1. is extremely brutal and not necessarily what we want (lazy, anyone?). Option 2. has a huge problem with objects because it cannot initialize e.g. a \Fleshgrinder\Custom\SuperClass nor a \DateTime. Option 3. is the current behavior but silently doing so results in a type hint violation. Emitting an E_NOTICE at this point is the most sensible thing that we can do at this point in my opinion. Extending this logic to all kind of properties is just logical to keep conditionals in the internals low and have a consistent behavior across all of the userland functionality. After all, aren't the following things equal? $a; echo $a; // null + E_NOTICE class O { public int $x; } echo (new O)->x; // null + E_NOTICE One could even argue that an E_NOTICE is required for void routines too. function f() {} echo f(); // null + E_NOTICE But that's another story. :) -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC][Vote] Typed Properties
On 5/26/2016 1:57 PM, Rowan Collins wrote: > I am definitely in favour of this from a language point of view. The > notice is warning about *initialization*, not *declaration*, so it makes > sense to warn on "var $foo" and not "var $foo = null". > > The only thing I'm not sure is what the impact would have on the > internals, which may be why it doesn't already work that way. With a > simple variable the notice can be easily raised based on the variable > name not being in the current symbol table; with an object property, the > name *is* in the relevant table, because it's been *declared* even > though it hasn't been *initialized*. Thus you need some extra flag to > track that a declared property exists but has never been written to. > > But it sounds like typed properties require adding some such overhead > anyway... > > Regards, Looking at `zend_object_handlers.c` and `zend_std_read_property` there is the line: retval = &EG(uninitialized_zval); This is what gives us the default null of our properties if I interpret everything correctly. This is also the place where the undefined property error comes from. We need help here from people who know the PHP source better. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC][Vote] Typed Properties
On 5/26/2016 1:41 PM, Lester Caine wrote: >> var_dump(property_exists($g, 'x')); // true > > or array_key_exists('x', $g) in our consistent style but as has been > pointed out we do not have a simple 'exists' ... > $g->exists('x') ? > along with $g->isinit('x') > I like the exists() idea. :) But we might not need it. On 5/26/2016 1:41 PM, Lester Caine wrote: >> var_dump($g->x); // null + E_NOTICE Uninitialized >> var_dump(is_null($g->x));// true + E_NOTICE Uninitialized >> var_dump($g->x == null); // true + E_NOTICE Uninitialized >> var_dump($g->x === null);// true + E_NOTICE Uninitialized > > Unless null IS the required initial value? Why should we have to > initialize a nullable typed property explicitly? > You don't have to unless null *is* the required initial value. You are only punished with an E_NOTICE if you try to access a property that was never initialized with anything. This would be 100% consistent with old PHP behavior. $x; var_dump($x); // null + E_NOTICE Undefined $y = null; var_dump($y); // null class O { public $x; public $y = null; } $o = new O; var_dump($o->x); // null + E_NOTICE Undefined / Uninitialized var_dump($o->y); // null Only the E_NOTICE for $o->x would be new. On 5/26/2016 1:41 PM, Lester Caine wrote: > I'm still stuck in the simple model of things where 'x' is expandable so > we have the simple generic variable of old (PHP4 days) which now has > additional attributes such as accessibility (public etc) and a few > special cases of type filtering but is lacking a tidy way of adding the > more useful filtering attributes such as constraints and yes typing. > > properties and associative arrays are simply managed list of these > simple variables so why do we need different functions to access them. > Within a class isset($x) should mirror isset($this->x) and exists($x) > makes sense along with other 'object' related functions, but is there no > way to get back to a lot simpler consistent handling of variables ... > and a more constructive way to add flexible type constraints. > With this proposal we would not go anywhere else. We would make it more consistent and allow the typed properties RFC to continue. Unless I missed something in the discussion or got something wrong again. Please correct me! -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC][Vote] Typed Properties
On 5/26/2016 12:39 PM, Rowan Collins wrote: > On 26/05/2016 11:16, Fleshgrinder wrote: >> $o = (object) ['x' => null]; >> var_dump(isset($a->x)); // false >> var_dump(property_exists($a, 'x')); // true > > Apart from a typo in your example (you change from $o to $a), this is > already the current behaviour, and always has been: https://3v4l.org/NeqGl > > isset() is really very simple: if the thing your accessing would give > you the value null, it returns false, otherwise it returns true. > > Regards, Now I feel stupid but I guess I got lost myself. :P This means it is even simpler, we just have to add the E_NOTICE and be done with it. $g = new class { public $x; }; var_dump($g->x); // null + E_NOTICE Uninitialized var_dump(isset($g->x)); // false var_dump(property_exists($g, 'x')); // true var_dump(is_null($g->x));// true + E_NOTICE Uninitialized var_dump($g->x == null); // true + E_NOTICE Uninitialized var_dump($g->x === null);// true + E_NOTICE Uninitialized This behavior would be true for all variations: class A { var $x; public $x; public int $x; public ?int $x; } No notice for the following: class A { var $x = null; public $x = null; public int $x = 0; public ?int $x = null; } -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC][Vote] Typed Properties
On 5/26/2016 12:03 PM, Rowan Collins wrote: > Could you summarise what your proposal actually is; I got a bit lost > with what your long list of examples was trying to show me. > To summarize it: we should change the behavior of isset() to work exactly the same way as it does for associative array keys if they have null assigned to them. Shorter example of current PHP implementation: $a = ['x' => null]; var_dump(isset($a['x']));// false var_dump(array_key_exists($a, 'x')); // true $o = (object) ['x' => null]; var_dump(isset($a->x)); // true var_dump(property_exists($a, 'x')); // true PHP 8 $o = (object) ['x' => null]; var_dump(isset($a->x)); // false var_dump(property_exists($a, 'x')); // true This would actually be more consistent with the isset() behavior together with associative arrays and it would allow us to handle typed properties that where not initialized (as illustrated in the longer example). On 5/26/2016 12:03 PM, Rowan Collins wrote: > Can you provide a reference for that? The only thing mentioned in the > changelog in the manual is this rather rare situation: > > $foo = 'a string'; > isset($foo['some_key']); > > $foo['some_key'] doesn't actually have much of a meaning in that case, > anyway, and it has nothing to do with initialisation. > Just tested it with those ancient versions and you are right that I interpreted that sentence incorrectly. The behavior of isset() with array keys that were explicitly set to null never changed. ref: https://3v4l.org/TS621 However, this does not change my proposal. :) -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC][Vote] Typed Properties
Have a look at my latest message: http://marc.info/?l=php-internals&m=146424924029857&w=2 -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC][Vote] Typed Properties
/ false var_dump(property_exists($g, 'x')); // true var_dump(is_null($g->x));// true + E_NOTICE Uninitialized var_dump($g->x == null); // true + E_NOTICE Uninitialized var_dump($g->x === null);// true + E_NOTICE Uninitialized /* }}} */ The only thing I personally dislike is the fact that there is no counterpart to isset(). This means that one cannot create a positive conditional that checks for the opposite case without raising an E_NOTICE. class T { private int $x; public function getX() { if (isset($this-x) === false) { $this->x = 42; } return $this->x; } } However, one could argue that empty() is good enough at this point -- despite the fact that many values are considered empty that might be valid values in other circumstances -- because we want to know the uninitialized case here. From the manual: > The following things are considered to be empty: [...] a variable > declared, but without a value > > --- https://secure.php.net/function.empty class T { private int $x; public function getX() { if (empty($this->x)) { $this->x = 42; } return $this->x; } } I could live with that. Note that the behavior of isset() and empty() was already once changed during the 5.4 feature release! I am proposing to change it with a major version for existing code and only emitting an E_STRICT till then. This is not even close as brutal as that behavioral change back then but other than that pretty much the same change. This time it just affects objects and not associative arrays. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC][Vote] Typed Properties
On 5/25/2016 11:37 PM, Stanislav Malyshev wrote: > Hi! > >> We already have the differentiation between IS_NULL and IS_UNDEF, why >> not expose the latter to userland? I mean, JavaScript has it too and >> people are able to understand it. > > IS_UNDEF is not a PHP type, it is an engine implementation flag. Now, > adding a new type "undefined" would be a pretty big thing and then you'd > need to deal with all the implications of it. Including a huge BC break > of changing the type of all uninitialized variables, and the question of > "what if I want my parameter to be able to accept undefined values" and > so on. Huge can of worms, and all of it again just to have a type that > is exactly like null but not null. While the only reason null exists is > to do exactly what "undefined" is proposed to do. > Andrea already said that we would not use it for untyped properties, hence, no BC. It is not the same as null, very similar, but definitely not the same. Think of it in DB terms: | table | | - | | id| SELECT name FROM table; That's not null, it's not defined (undefined, unset, ...). In other words, null is a value and undefined/unset a state. Whether this proposal should become part of this RFC or not is something that needs to be discussed. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC][Vote] Typed Properties
On 5/25/2016 11:35 PM, Thomas Bley wrote: > Following "Type safety is the goal of this RFC, not validating objects.", it > would be better to do implicit casting for uninitialized properties (whenever > implicit casting is possible) or use null for nullable types: > > class A { > public int $x; > public ?int $y = null; > public int $z = 42; > public ?int $u; > public ?datetime $v; > public datetime $w; > } > > $a = new A; > var_dump($a->x); // 0 + notice > var_dump($a->y); // null > var_dump($a->z); // 42 > unset($a->z); > var_dump($a->z); // 0 + notice > var_dump($a->u); // null + notice > var_dump($a->v); // null + notice > var_dump($a->w); // Fatal error, uninitialized... > This was proposed many times but it renders checks whether something was initialized or not completely useless and is not really a solution to the problem at hand. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC][Vote] Typed Properties
On 5/25/2016 11:29 PM, Stanislav Malyshev wrote: > OTOH, we do have precedent for properties that can not be unset - > namely, static properties can not be unset. They can be nulled-out, of > course, and they default to null. I have no idea how "static int $x;" > would work though. The current RFC doesn't implement it, which > definitely would be weird since people would expect if you can have > typed object property, you can have typed static property, but that's > not what the RFC says. > This was also a point that I found to be weird and I am absolutely sure that this will cast confusion as you are. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC][Vote] Typed Properties
On 5/25/2016 5:49 PM, Andrea Faulds wrote: > PHP's existing untyped properties are implicitly initialised to null, > and so yes, we would essentially only be copying our existing behaviour. > > However, I think it is worth asking whether our existing behaviour is > useful before we preserve it here. From my perspective, it is unhelpful > that PHP does not warn you about using properties you haven't > initialised, and this applies to both typed and untyped properties. In > some cases (like in my linked list example in a previous email), null > might be a meaningful value and worth distinguishing from a property not > having being initialised yet. > > We can't change the behaviour of our existing untyped properties (or at > least, that's beyond the scope of this RFC), but we could choose the > behaviour we find more useful for our typed properties. > We already have the differentiation between IS_NULL and IS_UNDEF, why not expose the latter to userland? I mean, JavaScript has it too and people are able to understand it. class A { public int $x; public ?int $y = null; public int $z = 42; } $a = new A; var_dump($a->x); // undefined var_dump($a->y); // null var_dump($a->z); // 42 unset($a->z); var_dump($a->z); // undefined + error At least to me this makes sense and there would be no problem with unset() anymore. Although I truly question the usefulness of its functionality. Can anyone come up with a real world use case for unset()? Or maybe not use /undefined/ but /unset/ as a term because it is already baked in? (Well the constant IS_UNDEF should be renamed to IS_UNSET to stay consistent in all layers.) class A { public int $x; public ?int $y = null; public int $z = 42; } $a = new A; var_dump($a->x); // unset var_dump($a->y); // null var_dump($a->z); // 42 // NOT SURE IF THIS SHOULD BE POSSIBLE $a->z = (unset) $a->z; // was null (PHP<7.1) would become unset var_dump($a->z); // unset + error $a->z = unset; var_dump($a->z); // unset + error unset($a->z); var_dump($a->z); // unset + error Of course this would also requires the introduction of an unset (and UNSET) constant in userland. class A { private $x; public function getX() { if ($x === unset) { $this->x = 42; } return $this->x; } } I love the difference to null, this makes the code much more expressive. There would be the following rules: - Access always results in error. - Usage as argument results in error. - Usage as return results in error (could be void but BC). - ... more errors ... - Comparison is possible! - The following existing operations would need to be changed to make use of unset instead of null (possible BC): - unset() - (unset) cast - The following new operations would need to be introduced: - is_unset() - The following existing operations would need to be extended: - gettype() - settype() -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC][Vote] Typed Properties
On 5/25/2016 10:23 PM, Benoit Schildknecht wrote: > Le Wed, 25 May 2016 21:40:28 +0200, Fleshgrinder > a écrit: > >> and unset simply because the property is not >> explicitly assigned null by unset, it is being undefined. > > > Because null !== undefined. That's why you get an error after an > unset($this->var), and you don't get one after $this->var = null; . > "$var = null;" and "unset($var)" are totally different, it has been like > that for years. If you want to change this behavior, propose an RFC, and > make it approve. But meanwhile, you'll have to keep this in mind : > "null" is a value. While "unset" does not affect a value, it deletes the > variable, it deletes any references of the variable it targets, the > variable doesn't exist anymore. With unset, the variable is dead. With > null, it has amnesia. I can't find any better analogy. > Which is exactly what I wrote and think is correct. ;) -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC][Vote] Typed Properties
On 5/25/2016 9:13 PM, Niklas Keller wrote: > 2016-05-25 20:39 GMT+02:00 Fleshgrinder : > >> In my opinion it should simply vanish along with its definition. I mean, >> > > Usually, yes. But suddenly `private Type $foo` isn't reliable anymore if > unset is supported for typed properties, because the following would just > remove all type info / enforcement: > > $backup = $this->foo; > unset($this->foo); > $this->foo = $backup; > > Unset can reset it to the default value, but wiping type information is > probably > not an option here. > > Regards, Niklas > I had to check because I never tried this once in my life (why would one need it anyways) ... class A { private $foo = "foo"; function get() { return $this->foo; } function unset() { unset($this->foo); } } $a = new A; echo $a->get(); // foo $a->unset(); echo $a->get(); // Notice: Undefined property: A::$foo $a->foo = "foo"; // Fatal error: Uncaught Error: Cannot access private property A::$foo In other words, unset is not really unset already! QED: Preserving *all* attributes of a property is the only consistent way. However, preserving its value is not. I do not think that there is a problem together with the typed properties, nullability, and unset simply because the property is not explicitly assigned null by unset, it is being undefined. I think internally null is actually assigned and it's not IS_UNDEF, right? However, from a userland perspective it is definitely not defined anymore and access should (as it does) result in an error (in our case E_INFO) plus null is being returned but only because undefined does not exist in PHP userland. I did not read up on all the history yet but I am on it ... -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC][Vote] Typed Properties
On 5/25/2016 8:01 PM, Stanislav Malyshev wrote: > Hi! > >> Why do you say "now"? unset() has done this for a long time, so far as I >> know. > > True. But I don't see how would it work for typed properties - what > exactly would happen after unset? Would it be - as it is now - that it > is as if the property was never defined, or would it be something else? > In my opinion it should simply vanish along with its definition. I mean, isn't that the definition of unset in general. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] Simple Annotations
On 5/17/2016 7:47 PM, Rasmus Schultz wrote: > You're not annotating the function - this is just a round-about way of > annotating the argument. > > You would do that directly, like this: > > function foo( > << ValidateRange(0, 100) >> > int $percentage > ) { ... } > What is this good for? When is /ValidateRange/ being evaluated? On every call? How? I really do not get it, sorry. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] Simple Annotations
#x27;); echo $some_annotations[0]->json; // data $annotations = new AnnotatedFunction('x'); $some_annotations = $annotations->getAnnotations('someAnnotations'); // Fatal error: Uncaught JsonParseException in ... The above is just fine. The annotation library registered the callback and it knows what kind of errors can happen. The annotation library is also the one reading the annotations and it can therefore easily handle those errors and act upon them. Of course in the above case the fatal error is just fine and it is the developers duty to write unit tests and take care of writing proper configuration. It is not PHP's duty to ensure to absolutely no error can happen in any subsystem. (This is actually ridiculous to think of in the first place.) On 5/17/2016 11:06 AM, Rasmus Schultz wrote: > I maintain that the majority use-case is object annotations - and that > deferring the construction of those objects doesn't solve anything. > Seriously? Every construction is deferred, always, again see the console example from above. On 5/17/2016 11:06 AM, Rasmus Schultz wrote: > You're just deferring or hiding the problem, adding complexity, and > mental as well as practical debugging effort - but the problem doesn't > go away. > I am putting a runtime feature to runtime like all runtime features are at runtime in PHP. The error is hidden during reflection, that is true, but on purpose! You do not want reflection to error out while you are performing introspection on a data structure. The annotation reader however will error out in the moment you try to access something. This separation of concern makes it actually easier and is in the vain of good software development too. I understand what you want to solve. I am just telling you that this is the wrong approach and others are telling it to you too. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] Simple Annotations
On 5/16/2016 3:05 PM, Rasmus Schultz wrote: > I'm sorry, but I think that the idea of meta-data that can't error > somehow, somewhere, at some point, is completely unrealistic. > > And I'd much rather have a simple facility that enables those errors > to surface quickly. > It should error and it should error exactly at the point when you want to use it and at no other point. Right now they will error anytime anyone wants to do anything with any annotation. I fully understand the urge to directly access objects and I actually support it and I want them to error out at the point where you try to instantiate them. However, not when I simply access annotations in introspection. According to your logic I have to load the whole dependency chain, even thought I just want to generate my documentation that might have some annotations in use. I also need to load all my dependencies even though I wanted to leave the security dependency out because I wanted to easily disable the security annotation system locally for development. I even have to load the whole dependency chain, even though I just want to introspect the single data structure at hand without invoking anything. Even worse if I am using a package that has Doctrine annotations but I use it without them: /fatal error/ Nice? No! Solutions? Make the /simple/ annotations /simple/. ;-) Only allow scalar data to be defined and allow userland to register themselves for specific annotations. I mentioned this before but somehow everyone wants something more fancy and I have no karma (even though requested but ignored) to write my own RFC. That being said, you have the ability to write an RFC so please just take it. :-) Some PHP code to illustrate what I was thinking of since I am better with code than with words. :-P https://gist.github.com/Fleshgrinder/d26cd4751827b8c10a0dc33da32b48c3 Reflection is the wrong tool for the job to build annotation systems. Reflection should not be used in production it should be used to introspect data structures and reason about them or other stuff during unit tests. However, reflection should provide the ability to read annotations, it just does not do anything with them by default and outputs stupid arrays. You will definitely understand what I mean it you follow the Gist. I am sure there is room for improvement and that I overlooked something in my Gist. But I think it is a starting point, some additional notes: - I do not see any benefit in annotations for parameters. - I do not see any benefit in annotations for Generators. - I do not see any benefit for annotations in php-src. My proposal would include to ban annotations from php-src and make it a pure userland functionality. This has many advantages: - No name collisions. - Clear policy for the future. - php-src features are never optional. - php-src does not provide meta-data. Let me know what you think or if you have questions in regards to the Gist that are unclear. (Or maybe you found mistakes.) -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] Simple Annotations
On 5/13/2016 2:57 PM, Davey Shafik wrote: > 2) I like the idea of Hacks memoize for example, how do you see those being > implemented? Or don't you? > I wrote it in the /attribute grammar/ thread and I write it here again. Stuff like memoize should be implemented as keywords as part of the language and not via annotations. memoized function f() {} Same goes for deprecated: deprecated memoized function f() {} Or other special effects: deprecated inlined memoized function f() {} These things are not meta-data for userland, they are meta-data for PHP and should be part of, well, PHP. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] Simple Annotations
On 5/13/2016 2:11 PM, Rasmus Schultz wrote: > Dear Internals, > > I'm announcing a simplified RFC for annotations: > > https://wiki.php.net/rfc/simple-annotations > -1 again, I am sorry. The problem is that an annotation by definition is just meta-data. Your proposal however might result in fatal errors from meta-data: $reflector = new ReflectionClass(User::class); $reflector->getAnnotations(); // Fatal error: Uncaught Error: Class 'TableName' not found ... This is an absolute No-Go for meta-data. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] Allow loading extensions by name
On 5/10/2016 10:07 PM, Lester Caine wrote: > I would be most surprised to find windows users running php command > line, but I suppose I am somewhat out of the loop on that side. All my > windows users run PHP on a web server and have trouble even accessing > the command line. > I am using Windows and the CLI all day professionally. Yes, people tend to think like that but it is ancient thinking. Windows is a very capable operating system and allows you to perform all tasks. Although I have to admit that PHP tends to be very slow on Windows compared to Linux, that is a fact. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] Allow loading extensions by name
On 5/10/2016 9:01 PM, Lester Caine wrote: > The idea has been proposed before, but the addition of php_ for windows > installs has not been universally applied. Extensions like eAccelerator, > adodb and other third party extensions that did not form part of the > windows 'installation' files. Most of these have been killed off by the > restructuring of the core so it's probably less of a problem now than 5 > years ago! > > Another negative is the fact that most Linux installations do not use > entries in the php.ini file to enable extensions, preferring to manage > them via the package manager. THAT particular practice is something I > already copy back to the windows installs, using individual .ini files > for each extension, and stripping those extensions and settings from the > main php.ini. > > This is not simply a matter of adding another load mechanism to the mix, > so any rfc should perhaps bear in mind all the aspects of 'package > management' process? Certainly it's not quite as simple as assuming > windows extensions start php_ and end .dll ... > Handling of the prefix is a no brainer. Just check for php_NAME.dll and fallback to NAME.dll on Windows otherwise. If both fail error out. The approach to split ini files does not work on CLI. UNIX: `php -d extension=foo.so -d zend_extension=bar.so` WIN: `php -d extension=php_foo.dll -d zend_extension=php_bar.dll` RFC: `php -d extension=foo -d zend_extension=bar` Are there really extension on Windows without `.dll` extension? I highly doubt it and would consider erroring out to be okay. Users can still specify the exact path if the want to. function load_extension($name) { $extension_dir = ini_get('extension_dir'); $extension_dir = rtrim($extension_dir, DIRECTORY_SEPARATOR); $extension_dir .= DIRECTORY_SEPARATOR; if (DIRECTORY_SEPARATOR === '\\') { foreach (['php_', ''] as $prefix) { $path = $extension_dir . $prefix . $name . '.dll'; if (is_file($path)) { return do_load_extension($path); } } else { $path = $extension_dir . $name . '.so'; if (is_file($path)) { return do_load_extension($path); } } return do_load_extension($name); } Something along these lines should do it (of course in C). :) -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] [VOTE] PHP Attributes
On 5/10/2016 8:29 PM, Dmitry Stogov wrote: > Hi internals, > > I've started voting on "PHP Attributes" RFC. > > https://wiki.php.net/rfc/attributes > > In my opinion, "PHP Attributes" might be a smart tool for PHP extension, but > it's not going to be the end of the world, if we decided to live with > doc-comments only. > I hope it's going to be negative. The name is misleading and the AST approach is not really useful in userland. :( -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] Allow loading extensions by name
On 5/10/2016 6:56 PM, Fleshgrinder wrote: > On 5/10/2016 6:54 PM, Stanislav Malyshev wrote: >> Hi! >> >>>> Please read and comment : >>>> >>>> https://wiki.php.net/rfc/load-ext-by-name >> >> The RFC says " it is currently impossible to write a single >> configuration file that will work in both environments" - but even with >> extension fix, wouldn't it be still impossible since Windows are Unix >> paths would probably be different? >> > > Usage of slashes and relative paths works perfectly fine in Windows; or > do you mean something different? > Just checked it with a simple script on Windows 7 with PHP 7.0.6. Slashes are no problem but relative paths seem problematic, hence, there would be the problem regarding `C:/some/path` vs. `/some/path`. This RFC would still be a big step ahead because we could do something like the following: php -v PHP 7.0.6 (cli) (built: Apr 28 2016 13:48:13) ( NTS ) Copyright (c) 1997-2016 The PHP Group Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies php -d zend_extension=xdebug -v PHP 7.0.6 (cli) (built: Apr 28 2016 13:48:13) ( NTS ) Copyright (c) 1997-2016 The PHP Group Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies with Xdebug v2.4.0, Copyright (c) 2002-2016, by Derick Rethans php composer install php -d zend_extension=xdebug test This is currently not possible. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] Allow loading extensions by name
On 5/10/2016 6:54 PM, Stanislav Malyshev wrote: > Hi! > >>> Please read and comment : >>> >>> https://wiki.php.net/rfc/load-ext-by-name > > The RFC says " it is currently impossible to write a single > configuration file that will work in both environments" - but even with > extension fix, wouldn't it be still impossible since Windows are Unix > paths would probably be different? > Usage of slashes and relative paths works perfectly fine in Windows; or do you mean something different? -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC DRAFT] Automatic CSRF Protection
On 5/10/2016 5:24 AM, Yasuo Ohgaki wrote: > Hi all, > > It's not nice to work on the same code (i.e. session module) for > multiple RFCs, but time is limited. > > I would like to hear from ideas/comments before I write patch for this. > https://wiki.php.net/rfc/automatic_csrf_protection > > Thank you for your comments. > > Regards, > > P.S. Precise session ID management is important, but this one is also > important. I'll finish and start voting 2 active session RFCs soon. I > may finish all of them hopefully. > -1 CSRF protection is a very specific need of some parts of a website and not something that is universally required. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] Allow loading extensions by name
On 5/10/2016 3:22 PM, François Laupretre wrote: > Please read and comment : > > https://wiki.php.net/rfc/load-ext-by-name > +1 and I am wondering why nobody else ever came to this idea. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] Pipe Operator
author asks /why?/ On 5/3/2016 11:23 PM, Ryan Pallas wrote: > You didn't address the fact that your "solution" makes it much harder to > modify the steps in place. > > $ret = getConfig() > |> buildApp($$) > |> buildRouter($$) > |> parseResponse($$); > > Shoot, I forgot to build Dispatcher; Let me add that > > $ret = getConfig() > |> buildApp($$) > |> buildRouter($$) > +|> buildDispatcher($$) > |> parseResponse($$); > > Such a minimal change. Lets try yours: > > final class ResponseBuilder { > private $config; > private $app; > private $router; > private $response; > > private function loadConfig() {} > > private function buildApp() { > $this->app = new App($this->config); > } > > private function buildRouter() { > $this->router = new Router($this->app); > } > > private function parseResponse() { > $this->response = new Response($this->router); > } > > public function build() { > $this->loadConfig(); > $this->buildApp(); > $this->buildRouter(); > $this->parseResponse(); > > return $this->response; > } > } > > Shoot, I forgot dispatcher; let me add that > > final class ResponseBuilder { > private $config; > private $app; > private $router; > + private $dispatcher; > private $response; > > private function loadConfig() {} > > private function buildApp() { > $this->app = new App($this->config); > } > > private function buildRouter() { > $this->router = new Router($this->app); > } > > + private function buildDispatcher() { > + $this->dispatcher = new Dispatcher($this->router); > + } > + > private function parseResponse() { > - $this->response = new Response($this->router); > + $this->response = new Response($this->dispatcher); > } > > public function build() { > $this->loadConfig(); > $this->buildApp(); > $this->buildRouter(); > +$this->buildDispatcher(); > $this->parseResponse(); > > return $this->response; > } > } > > Whoa that's significantly more changes, and therefore significantly more > chances to make a typo! > At least the complexity is not completely hidden behind some arbitrary procedural function call. You assume that the procedural function that you are introducing already exists and returns the correct thingy that continues the chain in exactly the order you want it too. Those are a lot of assumptions considering the fact that the pipe operator is meant for combining arbitrary libraries. Sorry, not convinced but a real world example might change that. ;) -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] Attributes/Annotations Case Study: Drupal
On 5/6/2016 8:02 AM, Dmitry Stogov wrote: > On 05/06/2016 05:06 AM, Jesse Schalken wrote: >> If you're going to say "do what you want" with regards to annotations, >> then >> just let them be a text string. Parsing the annotation as PHP but not >> evaluating it as PHP seems a very strange and arbitrary half-way >> point. If >> the thing consuming the AST is expected to eval() it, then why didn't PHP >> do that already? If the thing consuming the AST is expected not to eval() >> it, then it must effectively implement it's own language sharing PHP's >> syntax but not PHP's semantics. Since it can't possibly attach meaning to >> all of PHP's syntax, PHP will enforce that the string is valid PHP even >> though the annotation language will be a very small subset. Not only does >> that buy you very little in terms of validity checking, but it constrains >> the annotation language to be a subset of PHP's syntax even when such a >> constraint may be entirely inappropriate. >> >> A true "do what you want" approach, if that is the right approach, >> would be >> for the annotation body to be a free text string. > > You talk about a subset of the proposed RFC. > It proposes an additional question about AST usage. > I think he is talking exactly about the proposed RFC, it is completely arbitrary and will lead to much confusion and it is not anymore useful than the current PhpDoc approach that we have in userland. Having an attribute grammar [1] adds overhead to PHP while parsing our files and removes only the regular expression stuff that is currently implemented in the annotation systems of all the software out there; which is at least offline. I do not see a single benefit in the current feature proposal. Especially since one can already run the content of a PhpDoc tag through the AST thingy and *bam* you have exactly the same thing. What we need is an annotation system that works for userland and not this attribute grammar crutch just because it is easier to come up with and agree upon. [1] https://en.wikipedia.org/wiki/Attribute_grammar -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] Pipe Operator
On 5/3/2016 10:22 PM, Ryan Pallas wrote: > I have to disagree, I haven't seen an example of rewriting the original > example from the RFC in a more expressive AND readable way. Yes, you can > use lots of intermediate variables, but this makes the code HARDER to read > QUICKLY which is entirely the point of a syntatic sugar addition like this. > Syntactic sugar makes a language sweeter, and more palatable. Like cane > sugar makes your cookies taste good, but doesn't make them more nutritious. > Opinions you know but I am still waiting for that example. On 5/3/2016 10:22 PM, Ryan Pallas wrote: > This breaks dependency injection, and makes testing harder. You now depend > on an array of data which is accessed internally, and can only minimally > control it's contents in a testing environment. > Why do you need dependency injection in the most outer point of your application? This should be tested with your acceptance/integration tests and nothing else. How many unit tests have you written for your Symfony app kernel lately? A rather extreme example of such a /most outer/ but you know how it is with constructed examples: http://www.yegor256.com/2014/10/03/di-containers-are-evil.html#the-right-way On 5/3/2016 10:22 PM, Ryan Pallas wrote: > Again, how do I dependency inject a config during testing to make sure I > build the dic correctly? I'm assuming you're using a bunch of temporary > properties? Also you just made adding a step significantly harder, what if > from building the app, I need to build another layer build for the router, > for |> I add ONE line of code, for yours I edit the build function in the > right location, and change the build router function to load from a > different property, and build another boilerplate function to build this > new thing, and add another property to hold this new thing... WHOA that's a > lot more steps, and a MUCH higher risk of a mistake! > Again, this is the most outer place of everything. I mean, all frameworks and applications were and are able to solve these issues easily, nicely, and testable. Just because my /proposed/ solution to an example that is constructed in the first place is not as nice as those solutions does not make the examples better. :P On 5/3/2016 10:22 PM, Ryan Pallas wrote: > Again, you're solution is to use OOP, but the pipe operator's purpose is to > make procedural code cleaner. Not one of your solutions maintained a > procedural interface, and therefore is not an argument against the |> > operator. The purpose of this operator is syntactic sugar, which "is syntax > within a programming language that is designed to make things easier to > read or to express. It makes the language "sweeter" for human use: things > can be expressed more clearly, more concisely, or in an alternative style > *that > some may prefer*."[1] (emphasis mine). Its not designed to solve a problem > of how can I do this thing, but how can I write this thing such that my > team might be able to understand it better. > > Yes, you can rewrite these examples in an entirely different way, but now > you're not comparing apples to even other fruit (procedural vs OO is not > the same). The point of this is to take a very common pattern (nesting many > procedural calls) and make it easier to read and manage later. > foreach (scandir($arg) as $path) { if ($path !== '.' && $path !== '..') { $ret[] = getFileArg($arg . DIRECTORY_SEPARATOR . $path); } } What can I say ... -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] Pipe Operator
On 5/3/2016 8:57 PM, Sara Golemon wrote: > Ooops, missed a negation when I typed it out. > > "Pretending that poorly designed libraries DON'T exist is naîve." > I am not pretending that they do not exist, quite the contrary, I explicitly stated that they exist and that I fear that this syntactic sugar yields more of them in the future. On 5/3/2016 8:57 PM, Sara Golemon wrote: > As I've said already. Yes, intermediate variables do address this > style of coding. Yes, this proposal is syntactic sugar. > > Intermediate variables also add cognitive overhead of their own in > cataloging all the various intermediates used in a large function. By > removing the explicit intermediate variables and replacing them with > unnamed temporaries, the code becomes easier to read because there's > less unnecessary assignments cluttering up the space. > Still waiting for a real life example that illustrates exactly that. All examples and code I have seen so far is either extremely constructed (the request-application-response thingy that is now part of the RFC) or can be trivially rewritten to be super expressive and readable (the original from the RFC and most in this thread). $request = getGlobals() |> parseRequest($$) |> buildPsr7Request($$); Ask, don't tell! final class RequestBuilder { public static function fromGlobals() { return new static($_GLOBALS); } public function buildPsr7Request() { $parsed_request = $this->parseRequest(); return new Psr7Request($parsed_request); } } $request = RequestBuilder::fromGlobals()->buildPsr7Request(); $response = loadConfig() |> buildDic($$) |> getApp($$) |> getRouter($app) |> getDispatcher($$, $request) |> dispatchBusinessLogic($$, $request, new Response()) |> renderResponse($$) |> buildPsr7Response($$) |> emit($$); Ask, don't tell! final class ResponseBuilder { public static function fromGlobals() { return new static($_GLOBALS); } public function build() { $this->loadConfig(); $this->buildDic(); $this->buildApp(); $this->buildRouter(); $this->buildDispatcher(); $this->dispatchBusinessLogic(); $this->parseResponse(); return $this->response; } } $response = ResponseBuilder::fromGlobals()->build(); The third is exactly the same ... Now my favorite: $ret = array_merge( $ret, getFileArg( array_map( function ($x) use ($arg) { return $arg . '/' . $x; }, array_filter( scandir($arg), function ($x) { return $x !== '.' && $x !== '..'); } ) ) ) ); I already rewrote it in another message but once more with the most relevant parts of my original message: array_filter with O(n) array_map with O(n) array_merge with O(∑ array_i, i != 1) and in our case O(n) where n equals the total count of elements in $files/$$. In my universe `getFileArg` (note the absence of a plural form) would operate on a single path and not on an array of paths: foreach (new DirectoryIterator($arg) as $path) { if ($path->isDot() === false) { $ret[] = getFileArg($arg . DIRECTORY_SEPARATOR . $path); } } Ocramius mentioned that the pipe operator would be super useful in async libraries and stuff but I am lacking real world examples here that illustrate how this new operator would make those experimental stuff benefit from it. Especially benefit besides scalar objects. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] Pipe Operator
On 5/3/2016 8:45 PM, Sara Golemon wrote: >> The pipe operator is also just a work around for poorly designed >> libraries in this case and yields more poorly designed libraries. >> > Pretending that poorly designed libraries exist is naîve. PHP is > dominated by poorly designed software but it manages to work because > it responds with practicality. > > It's practical to provide a functional version of object method chaining. > I really do not know what you want to tell me with that first sentence. The solution for the problem is already baked into PHP and usable: intermediate variables with meaningful names. Yes, this might sometimes be overly verbose. Yes, this might tempt some people to create meaningless variable names. All in all no argument that was brought up so far showed that this kind of operator is really useful to solve something that cannot be already solved. It is always just about source code formatting and laziness to write out some variables. Sorry -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] Pipe Operator
On 5/3/2016 8:12 PM, Sara Golemon wrote: > The difference with scalar objects is: > A) We need to agree on what methods these objects are going to have. > ((And we won't agree)) > The nice thing here is that we could start with the things that we agree on and develop it from there further. On 5/3/2016 8:12 PM, Sara Golemon wrote: > We could maybe hedge our bets with a ->invoke(Callable) method that > pushes the value into an arbitrary closure, but that's just adding > complexity to... avoid adding complexity... o.O > That would be pure evil. On 5/3/2016 8:12 PM, Sara Golemon wrote: > B) It's not just about scalars. > > $foo = SomeLibrary::create(...) > |> SomeOtherLibrary::render($$) > |> $foo->send($$); > > Scalar objects don't help this case at all, and since the object > instances are coming from some third-party library, making them > instantiate extended children instead isn't necessarily a trivial > thing (arguments about poorly designed libraries aside). > > I like the scalar objects approach as well. Heck, I wrote one three > years ago: https://github.com/sgolemon/objectifier but I don't think > it solves the same problem space as pipe chaining. > The pipe operator is also just a work around for poorly designed libraries in this case and yields more poorly designed libraries. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] Pipe Operator
On 5/3/2016 4:53 AM, Terry Cullen wrote: > Doesn't Nikic's scalar objects (https://github.com/nikic/scalar_objects) > more or less achieve the same thing while also cleaning up the std lib? > > $ret = scandir($arg) > ->filter(function(){}) > ->map(function(){}) > ->merge($someOtherArray); > It is indeed a much better approach. The more I read and think about the pipe operator the more I am against it. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] PHP Annotations VS Attributes
eal world, we wouldn't use either term if we > wanted to unambiguously refer to a new feature. At best, the Rust > example is irrelevant to the discussion; at worst, it weakens the case > for "annotation" being an unambiguous term, which I thought was part of > your argument. > I disagree in the context of programming. There are multiple dictionaries available (and linked in this thread) that define the term over and over again in the same manner. However, the term attribute changes its meaning based on context. On 4/30/2016 11:52 PM, Rowan Collins wrote: > Absolutely! But all we're deciding is what the language will call the > overall feature - what page it will be on in the manual, what word will > be used in the error messages, etc. In some languages, like Java, those > resources would refer to "Annotations"; in other languages, like C#, > those resources would refer to "Attributes". > > Both terms have advantages and disadvantages, precedents and > connotations - and both have potential ambiguities with other uses of > the normal English words that have been borrowed. In the end, it really > is mostly a matter of taste. > Very true but the last sentence is not in my book; maybe in .NET, Perl, and Hack. I guess we can summarize: - .NET world, Perl, and Hack are different than others. - Rust is complicated and is definitely different than others. - All others use the term according to most/all dictionaries. - Richard thinks annotations is the correct term. [1] - Rowan likes annotations but thinks attributes are equally suited. I can live with that. Anyone can read our discussion and make up their mind on their own (and hopefully share it with us). [1] Unless of course---and I wrote that before---we extend the name of the new functionality to be more precise: - Attribute Grammar (what the current proposal effectively is) - Meta-Attributes - Custom Attributes - Annotation Attributes - Aspects [2] - ... [2] https://en.wiktionary.org/wiki/aspect > In aspect-oriented programming, a feature or component that can be > applied to parts of a program independent of any inheritance > hierarchy. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] Pipe Operator
On 4/30/2016 5:51 PM, Fleshgrinder wrote: > $ret = scandir($arg) > |> array_filter($$, function($x) { return $x !== '.' && $x != '..'; }) > |> array_map(function ($x) use ($arg) { return $arg . '/' . $x; }, $$) > |> getFileArg($$) > |> array_merge($ret, $$); This should actually be formatted as to be fair contender to the procedural example: $ret = scandir($arg) |> array_filter($$, function ($x) { return $x !== '.' && $x !== '..'; }) }> array_map(function ($x) use ($arg) { return $arg . '/' . $x; }, $$) |> getFileArg($$) |> array_merge($ret, $$); Not a big difference now... $files = scandir($arg); $files = array_filter($files, function ($x) { return $x !== '.' && $x !== '..'; }); $files = array_map(function ($x) use ($arg) { return $path . '/' . $x; }, $files); $ret = array_merge($ret, getFileArg($files)); ...the only thing that bugs me in the procedural code is the fact that array_filter and array_map take their arguments in different order. :P -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] Pipe Operator
On 4/30/2016 5:23 PM, Marco Pivetta wrote: > This feature has nothing to do with fluent interfaces, nor has their flaws. > The readability of piped processing for functional code is simply a > no-brainer here, and doesn't require any API changes in function signatures > either: it is not "a different way of doing the same thing". > On Apr 30, 2016 17:05, "Fleshgrinder" wrote: > This is the example code from the RFC written in a normal procedural way. $files = scandir($arg); $files = array_filter($files, function ($x) { return $x !== '.' && $x !== '..'; }); $files = array_map(function ($x) use ($arg) { return $path . '/' . $x; }, $files); $ret = array_merge($ret, getFileArg($files)); This is the example code with the pipe operator. $ret = scandir($arg) |> array_filter($$, function($x) { return $x !== '.' && $x != '..'; }) |> array_map(function ($x) use ($arg) { return $arg . '/' . $x; }, $$) |> getFileArg($$) |> array_merge($ret, $$); Definitely looks like "a different way of doing the same thing" to me. So does the initial super ugly example code of nesting. Again, I am not really against the proposal nor do I argue against the fact that it improves readability of certain code constructs. I am just meh on it because such code can pretty much always be rewritten in a way that makes it more readable, easier to debug, and even faster. In the example code we have: array_filter with O(n) array_map with O(n) array_merge with O(∑ array_i, i != 1) and in our case O(n) where n equals the total count of elements in $files/$$. In my universe `getFileArg` (note the absence of a plural form) would operate on a single path and not on an array of paths: foreach (new DirectoryIterator($arg) as $path) { if ($path->isDot() === false) { $ret[] = getFileArg($arg . DIRECTORY_SEPARATOR . $path); } } I cannot tell if this construct is really equivalent to the example from the RFC (because I do not know what $ret contains) but it should do exactly the same. It is more readable, easier to debug, and much faster. Now you may argue that the example is simply flawed. Well, maybe, but functional programming is nice if you have a language that is functional. The only functional part in PHP are callbacks, everything else is just plain old procedural + OO and importing more functional concepts will not change that. However, I am not saying that every functional concept makes no sense just that the pipes are not very appealing to me because I only see "a different way of doing the same thing" with slower code. :P -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] Pipe Operator
On 4/30/2016 8:49 AM, Marco Pivetta wrote: > I think this is much more readable/clear than any event-driven or > procedural approach. > We know exactly what is going on, we will get clear stack traces (this > could need some fine-tuning of the current PR - I didn't try it out yet) > and we will be able to introduce intermediate steps with ease. In addition > to all that, this will ease reactive programming by a lot, as piping is a > natural fit for streams and all abstractions around streams. > > The syntax is also already effective in F# (you can write very expressive > and easy to understand code with it) and now also landed in Hack. > > I'd say +10 to this proposal :D > I am with Stanislav on this one or rather meh. It also goes against what you usually advocate: there should be only one way to achieve things (I remember your /fluent interface/ example very well). Unless you changed your mind regarding that. Hence, it is nice syntactic sugar but it does not allow us to solve problems that we cannot solve already. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] PHP Attributes
On 4/25/2016 10:31 AM, Dmitry Stogov wrote: > completely disagree. > Each value in multi-value attribute may have its own meaning. e.g. > <> > That is a different example but I think that I misinterpreted it anyways. <> function foo() {} I thought that the above would result in the following: reflect foo => [ test => 1 test => 2 ] But I think in reality it results int: reflect foo => [ test => [ 1, 2 ] ] In case the latter is true, than everything is fine. :) On 4/25/2016 10:31 AM, Dmitry Stogov wrote: > You should try to implement this syntax to understand the problem. > It leads to parse conflicts. > The inclusion of the semicolon definitely does, yes. Usage of the @ should not but Stanislav already offered to jump in. I am not fit enough yet with the php-src to take up such a big challenge. On 4/25/2016 10:31 AM, Dmitry Stogov wrote: > This RFC is not going to propose coding standards. > Only talking about a standard for internal attributes, userland can and should do whatever they want. But we need to ensure consistency for internal attributes and that userland is not going to collide with internal ones. Currently the RFC does not include any attributes but many examples that others might use to deduce a coding standard and later we add internal attributes and things go south. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: Fwd: [PHP-DEV] [RFC] PHP Attributes
On 4/28/2016 11:15 PM, Stanislav Malyshev wrote: > I think we should not try to be Haskell, Scala and Eiffel at the same > time. DbC is not something most of the users of the language require and > would ever use, unlike Eiifel where it is major part of what the > language is. Giving a possibility of implementing it using attributes is > fine. But bringing yet another conceptual framework into PHP looks like > overkill to me. > Yes, we should not be copy cats. However, we already have `assert()` and people are just discovering it, despite being there forever. I am not proposing the previously mentioned syntax as a real RFC yet, simply because I do not think that it is the right time to do so. However, I do believe that DbC does not belong into meta-attributes. My question remains: why DbC in meta? What could be any advantages? -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] PHP Annotations VS Attributes
he term annotation is wrong in the Rust example. It is a hint for the compiler that can be added by the programmer or the compiler. That's pretty much a perfect usage according to the definition of an annotation. > Extra information associated with a particular point in a document or > program. Annotations may be added either by a compiler or by the > programmer. They are not usually essential to the correct function of > the program but give hints to improve performance. > > --- http://encyclopedia2.thefreedictionary.com/annotation On 4/28/2016 9:43 PM, Rowan Collins wrote: > OK, I'm completely lost now. I thought your argument was that the > feature should under no circumstances be called "attributes", because > that is too general a term, and that it should instead be called > "annotations", because that is the only correct term. Then you link to a > page which demonstrates *annotations* being used as a general term, and > *attributes* being used for the feature being proposed. > C#/.NET calls them "Data Annotation Attributes" and not "Attributes" (see above). Perl does but I am still not sure if it is wrong or right in their context and included an /if/ in my initial review of their usage of the word. In case of doubt it's wrong I guess. Hack definitely uses it wrong. Also note that the current Attributes proposal is in some way closer to "Attribute Grammar" [3] than to annotations. I just hope that we can make an annotation system out of it and not end up with an attribute grammar system (or would we have to call it /attribution/ system then). On 4/28/2016 9:43 PM, Rowan Collins wrote: > Except that the Rust example demonstrates that "annotation" can be used > just as generically and ambiguously as "attribute". There really is very > little to choose between the two terms. > > Declarations can be annotated with ‘attributes’ in Rust. > > --- https://doc.rust-lang.org/book/attributes.html That is exactly the definition I gave in the initial message. There is no annotation system in Rust: > Currently, you are not allowed to create your own attributes, the > Rust compiler defines them. > > --- https://doc.rust-lang.org/book/attributes.html I am repeating myself but: @deprecated function f() {} We annotated (`@`) the function /f/ with the `deprecated` attribute, hence, _deprecated_ is now an attribute of function /f/ because we annotated it. > Allows use of the #[start] attribute, which changes the entry point > into a Rust program. This capability, especially the signature for > the annotated function, is subject to change. > > --- https://doc.rust-lang.org/reference.html The past and current RFCs are not proposing any attributes, they are proposing a system to annotate data with custom attributes. [1] http://dataannotationsextensions.org/ [2] https://www.it-visions.de/glossar/alle/454/MetaAttribut.aspx (German) [3] https://en.wikipedia.org/wiki/Attribute_grammar -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: Fwd: [PHP-DEV] [RFC] PHP Attributes
Is there a reason why you think that Design by Contract (DbC) should be implemented via annotations/attributes? I personally think that such a system should be implemented directly in the language, like Eiffel has it. I even think that it would be easy to add it without any BC. It might be a bit more complicated to implement thought. [assert] assert.active= 1 assert.invariant = 1 assert.require = 1 ; preconditions assert.ensure= 1 ; postconditions class PreconditionError extends AssertionError {} class PostconditionError extends AssertionError {} function hello(string $who): string { return "Hello {$who}\n"; } require { # argument must have content $who !== ''; # argument cannot contain unprintable characters ctype_print($who); } hello(''); // PHP Warning: require(): argument must have content: "$who !== ''" // failed in ... hello("\0"); // PHP Warning: require(): argument cannot contain unprintable // characters: "ctype_print($who)" failed in ... class A { private DateTimeImmutable $created; private DateTimeImmutable $changed; function f() {} require {} // Special scope "old" available... ensure { # error message $this->x = old::$x - 42; } } ensure { # created cannot be less than changed time $this->created <= $this->changed; } -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] PHP Annotations VS Attributes
loose sense of "you are annotating the source code". Meanwhile, in the > menu on the left, we can see a section on "Attributes", which look much > more like arbitrary metadata of the sort we are discussing right now: > http://rustbyexample.com/attribute.html > That is why there is an empty line between the pages that are actually documenting the usage of an annotation functionality and the pages that are using the term annotation correctly in natural language to describe something. Again, it is about language and terminology. Here is the relevant formatting again, note the dots and empty line: On 4/27/2016 10:11 PM, Fleshgrinder wrote: > http://ceylon-lang.org/documentation/1.2/tour/annotations/ > http://clojure-doc.org/articles/ecosystem/core_typed/start/annotations.html > https://www.dartlang.org/effective-dart/style/ > ... > > https://rubygems.org/search?utf8=%E2%9C%93&query=annotation > http://rustbyexample.com/scope/lifetime/explicit.html > https://www.google.de/search?q=javascript+annotation > ... > On 4/28/2016 8:02 PM, Rowan Collins wrote: > I think a survey of what different languages call their metadata > features would be interesting, but so far, I'm not seeing a clear bias > in favour of one or the other. > > Like I say, I personally prefer the term "annotations", but I'm not > going to discount the evidence that major languages like C#/.net, Perl, > and Rust have chosen the name "attributes" instead. > > Regards, Me neither, I am saying that the term is too generic and that we should use the term annotation in order to make it unique, easily understandable, non-ambiguous in terms of natural language and not in terms of what others use or do. [1] https://en.wikipedia.org/wiki/Attribute_%28computing%29 -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] PHP Annotations VS Attributes
On 4/27/2016 11:36 PM, Lester Caine wrote: > To add to your list ... > https://www.phpdoc.org/docs/latest/guides/docblocks.html > > The glossary entry is rather bare, but I would dispute THEIR statement - > "but also influences the way the application behaves." > > In my book, these comment blocks are 'annotation' is it's simplest form, > and we add tags within that annotation to make particular details of > that annotation both machine readable and humanly prominent. That some > of these keys may be used to "influences the way the application > behaves." is secondary? > It is totally secondary but still possible, hence, stating it is correct. A problem is the that attributes that were added via annotations are per definition not guaranteed to be executed (influence the way the application behaves) and are as such not a good fit for design by contract, validation, nor security checks. However, "per definition" does not mean that one is not allowed to model it in such a way. On 4/27/2016 11:36 PM, Lester Caine wrote: > My continuing irritation is that while subsets keep getting discussed as > duplicate elements outside of the phpdoc wrapper, there is no provision > for the annotations that would actually help data validation. > Value objects are a better approach towards validation in the very core than annotations could ever be. Validation of user input should happen at the most outer layer to fail early. Validation of developers should happen via design by contract where we currently only have assert() at our disposal. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] PHP Annotations VS Attributes
On 4/28/2016 11:36 AM, Rowan Collins wrote: > While I personally prefer the name "annotations", I don't see it as > particularly urgent, or nearly as clear-cut as you claim. > That's okay and why we are discussing things. ;) On 4/28/2016 11:36 AM, Rowan Collins wrote: > I clicked through on your MSDN link [1] because I was pretty sure .net > referred to them as "attributes", and am amused to find sentences like > this: > >> The System.ComponentModel.DataAnnotations namespace contains the > classes that are used as data attributes. > > In other words, the implementer of that particular library preferred the > word "annotations", but the language/framework itself calls them > "attributes"; here's a nice summary [2]: > >> For example, the accessibility of a method in a class is specified by > decorating it with the /method-modifiers/ |public|, |protected|, > |internal|, and |private|. C# enables programmers to invent new kinds of > declarative information, called attributes. > > So, that's one rather large ecosystem that calls them "attributes". > Actually Microsoft got it exactly right and they are explaining in depth what I wrote as well. The result of an annotation is an attribute. So it is only natural to call the classes attributes. public class Customer { [DataType(DataType.EmailAddress)] public string EmailAddress { get; set; } } The `[DataType(DataType.EmailAddress)]` is the annotation and the attribute that we add to the property is a DataTypeAttribute of DataType EmailAddress. https://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.datatypeattribute%28v=vs.95%29.aspx Note that you could achieve the above in PHP with the property type RFC: class Customer { public EmailAddress $email; } Here public and EmailAddress are attributes of the instance variable email and hence properties of a property that together result in a class or instance attribute. On 4/28/2016 11:36 AM, Rowan Collins wrote: > Your claims for Perl also don't make much sense: > >> Last but not least, Perl has/attribute/ support. However, Perl actually >> uses it for interaction with*all* attributes that can be set. Hence, >> this is what attributes really do. >> >> http://perldoc.perl.org/attributes.html > > None of the built-in attributes mentioned in that manual are standard > syntax used in the majority of Perl programs; in fact, they are all > marked as experimental, and most of the examples are of defining custom > attributes. As far as I can see, this is Perl's version of precisely the > feature that is being proposed for PHP. > The name they chose is okay because Perl does not offer any other way of adding attributes to any kind of data in any way (at least none that I am aware off but I am not a Perl programmer). Hence, it is not too dangerous to call this functionality attributes as it would be in our context where many other attributes are already available. The fact that it is experimental does not add anything to this discussion. On 4/28/2016 11:36 AM, Rowan Collins wrote: > I haven't looked through any of your other links to see if you've fallen > foul of similar confirmation bias, but am satisfied in my mind that > there are plenty of people outside Hack who call them "attributes". > > > [1] https://msdn.microsoft.com/en-us/library/dd901590%28VS.95%29.aspx > [2] https://msdn.microsoft.com/en-us/library/aa664611%28v=vs.71%29.aspx > > Regards, No confirmation bias and as I said, Microsoft got it completely right. To give you an analogy, Microsoft is calling the egg an egg and the chicken a chicken. We would be calling a chicken an egg because it is able to create eggs. In other words: an *annotation* allows you to add additional custom *attributes* to data that cannot be added by other means. :) -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
[PHP-DEV] [RFC] PHP Annotations VS Attributes
I am writing this in a separate thread because of the urgency that I see regarding the naming of past, current, and future proposals regarding this functionality. It was and is proposed to create this feature with the name *Attributes* as Facebook did in their Hack language. Main argument is to blindly follow /because/. On 4/25/2016 10:31 AM, Dmitry Stogov wrote: > Different languages names this differently. > I may add an additional voting question - "annotation vs attributes?". > It is true and only natural that different languages choose different names for equivalent features but this discussion is not about taste, style, nor coolness. It is about natural language, proper computer science terminology, and what PHP users will search for in search engines. I already tried to explain this in the actual thread but I guess my attempts resulted in more confusion than clarification, let me try again. ATTRIBUTE The word *attribute* has several meanings in computer science and this is mainly due to its extremely generic nature: > a usually good quality or feature that someone or something has > > --- http://www.merriam-webster.com/dictionary/attribute > In computing, an attribute is a specification that defines a property > of an object, element, or file. [...] For clarity, attributes should > more correctly be considered metadata. An attribute is frequently and > generally a property of a property. > > --- https://en.wikipedia.org/wiki/Attribute_%28computing%29 This pretty much sums it up already. An attribute is the metadata that is attached to an element of source code. This metadata is anything unessential that is additionally added but not necessarily required. class A { var $x; } The `class` and `var` keywords are essential in this example and define the actual element and the names are required too. public final class A { private static int $x = 42; } Class A has the attributes `public` and `final`. Property `$x` has the attributes `private`, `static`, `int`, and `42`. All of these attributes of the class and the property add additional metadata to the source code elements that define their qualities or features and consequently their behavior and usage. http://www.onelook.com/?w=attribute&ls=a http://encyclopedia2.thefreedictionary.com/attribute Sebastian Bergmann already explained this but I think it is important to be repeated and further clarified. The word attribute is often used to refer to properties with additional metadata (e.g. access modifiers, default values, ...; illustrated above) in an OO context. This makes the usage of the word attribute additionally to its generic nature ambiguous as well: https://en.wikipedia.org/wiki/Attribute_%28computing%29 http://encyclopedia2.thefreedictionary.com/instance+attribute https://en.wikipedia.org/wiki/Instance_variable http://encyclopedia2.thefreedictionary.com/static+attribute https://en.wikipedia.org/wiki/Static_variable *All* userland implementations that are called /attributes/ in the free and open world deal with completely different things: https://packagist.org/search/?q=attribute Last but not least, Perl has /attribute/ support. However, Perl actually uses it for interaction with *all* attributes that can be set. Hence, this is what attributes really do. http://perldoc.perl.org/attributes.html ANNOTATION > Extra information associated with a particular point in a document or > program. Annotations may be added either by a compiler or by the > programmer. They are not usually essential to the correct function of > the program but give hints to improve performance. > > --- http://encyclopedia2.thefreedictionary.com/annotation http://www.onelook.com/?w=annotation&ls=a The term *annotation* is not only used by Java: https://packagist.org/search/?q=annotation https://en.wikipedia.org/wiki/Annotation https://en.wikipedia.org/wiki/Ruby_character https://en.wikipedia.org/wiki/Java_annotation https://msdn.microsoft.com/en-us/library/dd901590%28VS.95%29.aspx http://docs.scala-lang.org/tutorials/tour/annotations.html https://kotlinlang.org/docs/reference/annotations.html https://www.python.org/dev/peps/pep-3107/ https://ghc.haskell.org/trac/ghc/wiki/Annotations http://ceylon-lang.org/documentation/1.2/tour/annotations/ http://clojure-doc.org/articles/ecosystem/core_typed/start/annotations.html https://www.dartlang.org/effective-dart/style/ ... https://rubygems.org/search?utf8=%E2%9C%93&query=annotation http://rustbyexample.com/scope/lifetime/explicit.html https://www.google.de/search?q=javascript+annotation ... Ignoring these facts just because Facebook did not do proper research is a total no go. It is also not up for a vote, it is just proper English and computer science terminology! Last but not least, it also ensures that users find the correct PHP manual page when they search for this new feature that migh
Re: [PHP-DEV] Re: Request for Karma
On 4/27/2016 7:56 PM, Dmitry Stogov wrote: > Hi Richard, > > I already got help from Pierrick. He is the author of previous RFC > https://wiki.php.net/rfc/annotations > sorry, I have no idea who can give the karma. > > Thanks. Dmitry. > Ah, alright. Well it says in the HowTo that one needs to send a request to internals list to ask for karma so somebody knows. I keep the request, I am sure it will be useful to step in and help on other occasions. :) -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] PHP Attributes
On 4/25/2016 10:04 AM, Dmitry Stogov wrote: > > > On 04/24/2016 11:24 AM, Fleshgrinder wrote: >> The invariant could also be added as an additional branch to the class >> instead of a method, since it would not work like a method. >> >>class A {} invariant {} >> >>function f() {} require {} ensure {} >> >> This would also align nicely with closures and anonymous classes, which >> is kind a problematic with annotations. >> >>$A = new class {} invariant {}; >> >>$f = function () {} require {} ensure {}; >> >> The only thing that remains that might be of interest to both is >> `@throws` but that was not discussed at all as of yet. >> >>use Ns\SomeException; >> >>@throws SomeException >>function f() { >> >>} >> >> This is at least how one would expect it to work and it is something >> that should be covered by annotations and not as part of the language. >> The ABNF should account for that: >> >> ANNOTATION= "@" NAME [ " " VALUE ] >> NAME = STRING >> VALUE = QUOTED-STRING / PHP-REFERENCE / EXPRESSION >> QUOTED-STRING = ( "'" / DQUOTE ) STRING ( "'" / DQUOTE ) >> EXPRESSION= PHP-CODE ";" >> >> Where PHP references are any of the already possible ones: >> >>use F\Q\C\N; >> >>@annotation \F\Q\C\N >>@annotation N >>@annotation \F\Q\C\N::CONSTANT >>@annotation N::CONSTANT >>@annotation \F\Q\C\N::function() >>@annotation N::function() >>@annotation \F\Q\C\N::$variable >>@annotation N::$variable >> >> I also though some more about function support for annotations and this >> would actually be a nice thing for userland. >> >>annotation deprecated(Reflection $element, string $message = '') { >> @trigger_error($message, E_USER_DEPRECATED); >>} >> >>@deprecated('because') >>function x() {} >> >>@deprecated >>function y() {} >> >> This would allow users to implement simple and easy reactive annotations >> in userland. Even if this could or should be an extension of the feature >> in the future, it should be thought about know. Simply because the >> brackets make sense if such a feature is to be implemented. ;) >> > Looks interesting, but try to think where the "annotation deprecated" > should be declared,to be visible in every compiled script, when the > corresponding code should be called (in what context), what if we need > to do something at compile-time? Single answers to these question are > going to be great for "deprecated" use case, however they will limit > usability for other cases. > > Thanks. Dmitry. > Reactive annotations would have their limitations, e.g. calls to the reactive annotation function only happen during runtime and any attempts to perform something at compile time directly results in an engine error. It limits their use cases but allows interesting ones at the same time. Another approach could be to allow registration of reactive annotation functions at runtime, this would make it even more useful. Of course that would mean that the function is only called for each encountered annotation at runtime after it was registered. However, such a limitation is pretty much the same as we have it for any other function right now too. class User { public function hasRole($right) { if (false) { throw new InsufficientPrivileges; } } } $user = new User(); register_annotation('Framework\Role', [ $user, 'hasRole' ]); class Controller { @Framework\Role('admin') public function editAction(){} } // ENGINE (pseudo code) array registered_annotations = []; void register_reactive_annotation(annotation, callback) { registered_annotations[annotation] = callback; } void reactive_annotation_call(annotation, ...arguments) { if (annotation exists in registered_annotations) { call registered_annotations[annotation](...arguments); } else { log_info("Unknown reactive annotation %s", annotation); } } However, this is a story for another RFC. It is only important because usage of the brackets in the current RFC would make such a feature more complicated to implement. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
[PHP-DEV] Request for Karma
Hello fellows! I would like to request karma for the PHP wiki to support others in writing RFCs and maybe some time in the future contribute RFCs. For now I plan to help Dmitry Stogov as co-author with the already existing Attributes RFC. A few words about my person might not hurt I guess. I am an MSc and PHP developer from Austria. I work with PHP since many years, however, I am also fluent in Java, JavaScript, Shell, ... and know my ways around in C, C++, Rust, ... I am currently working at trivago in Germany as lead PHP developer of a small development team. I already registered a wiki account under the name "fleshgrinder". -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] PHP Attributes
On 4/25/2016 10:31 AM, Dmitry Stogov wrote: > > > On 04/23/2016 06:29 PM, Fleshgrinder wrote: >> +1 for the basic idea, however, I have various remarks. >> >> The RFC text is hard to read and contains many grammatical mistakes. How >> could one help you here? > I would need a co-author :) > I would love to help you but would require some karma. I need to check how to get it. I will answer more tomorrow. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] Patch for Union and Intersection Types
On 4/26/2016 9:40 PM, Levi Morrison wrote: > I think he meant to post a different case: > > function (Foo $foo = null, $concrete_param); > > This is based on a conversation I've had with him elsewhere. > Gosh, I know such code. That should result in an error! :P -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] Patch for Union and Intersection Types
On 4/26/2016 9:13 PM, Bob Weinand wrote: > There's undefined (= not a value) and there's the value null. We just don't > expose undefined to userland. [You see it when accessing undefined variables, > which PHP converts to null with a notice for example.] > > Null is definitely a value. You can pass it around, reflect on it, assign it > etc.. > And as it is a value, it also has a type, which is null. > > Null is not special, it just has specific behavior, like any other primitive > type has. The only special thing is that it's allowed as a default value with > function (Foo $foo = null), but this should be somewhen deprecated and > removed once we have proper null unions. > > If you want to continue arguing, please open a new thread, but don't > side-track this thread to much, please. > > Bob > Null is a type, no argument there! Deprecation of null as default value makes no sense, nor does it make sense to deprecate 42 as default value. ;) -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC][Discussion] Parser extension API
On 4/26/2016 10:38 AM, Alexander Lisachenko wrote: > Hello, Nikita! > > It's a great news! Having this stuff in the 7.1 core is awesome! > > But I have several petitions for this API: > 1) Could it avoid using of raw functions for parsing API, like > ast\parse_file or ast\parse_code > 2) Could you please put all the parsing stuff into the `Parser` class and > put it into the `Php\` namespace, as well with node classes? > The current coding standard still prescribes to do so. However, these requests keep popping up and I think that this should be discussed at some point. However, putting everything into a static class just to mimic some OO that you might like makes absolutely no sense. We have multi-paradigm support for a reason: best tool for the job? That being said, the current implementation violates more rules of the coding standard (camelCase vs. snake_case). Currently we have the following: namespace ast { parse_file() parse_code() get_kind_name() kind_uses_flags() class Node { public $kind; public $flags; public $lineno; public $children; } } namespace ast\Node { class Decl extends ast\Node { public $endLineno; public $name; public $docComment; } } From a pure coding standards view and current conventions in core at least the following has to change: ast_parse_file() ast_parse_code() ast_get_kind_name() // ast_kind_name? ast_kind_uses_flags() // ast_kind_has_flags? class AstNode { public $kind; public $flags; public $lineno; public $children; } class AstDecl extends AstNode { public $end_lineno; public $name; public $doc_comment; } Of course usage of the \Php\Ast or \PHP\AST or \Php\AST or \PHP\Ast namespaces is possible but you already see from the four variations that this opens a huge can of worms that would require discussion. Personally I would design the API as follows, given that it is not a goal to have an anemic model in order to support direct changes of the public properties without any kind of validation. If that is an intended functionality things might need to be implemented a bit differently (and the anemic DTO approach could even make sense). Also note that I am modelling it in an OO way because it fits the actual data structure (tree). enum AstKind { /*API = [ ORDINAL, NAME ]*/ FUNCTION = [ 66, 'AST_FUNC_DECL' ]; CLASS = [ 67, 'AST_CLASS' ]; // ... /** @see \AstKind::getName() */ public function __toString(): string; /** bitfield */ public function getFlags(): int; public function getName(): string; public function getOrdinal(): int; public function hasFlags(): bool; } final class AstNode implements Countable, Traversable { private AstKind $kind; private int $line_number; private array $children = []; public function getKind(): AstKind; public function getLineNumber(): int; } final class AstDeclarationNode extends AstNode { private string $doc_comment; private int $end_line_number; private string $name; /** @see \AstDeclarationNode::getName() */ public function __toString(): string; public function getDocComment(): string; public function getEndLineNumber(): int; public function getName(): string; } final class Ast implements Countable, Traversable { private AstNode $root; private function __construct(); public static function fromFile(string $path): Ast; public static function fromCode( string $code, string $filename = 'string code' ): Ast; /** @see \Ast::getDump() */ public function __toString(): string; public function getDump(bool $line_numbers = false): string; } I do not think that it is necessary to use the exact same constant names as are used in the C source (e.g. AST_FUNC_DECL vs. AST_CLASS). The userland API could be more consistent here. You might disagree thought but in the end only the ordinal must be an absolute perfect match. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] PHP Attributes
On 4/25/2016 10:04 PM, Rowan Collins wrote: > On 25/04/2016 19:37, Stanislav Malyshev wrote: >> Hi! >> >>> @attr() - is a valid "silenced" call to function named "attr". >>> This syntax can't be reused. >> Not valid if it's in the middle of class definition, and not valid in >> form of: >> >> @attr() function foo() { ... } >> >> This is not a valid PHP syntax now. So I'm not sure why it can't be >> used. << is an operator too and so is >> . >> > > No, but this is valid: > > @atrr(); function foo() { ... } > > That's perhaps a little too close for comfort...? > > Regards, > Actually I agree with Stanislav (in pretty much every point he made so far) on the syntax discussion, however, I already said that the brackets are the main problem and it seems as it nobody sees it but your example illustrates it perfectly. @fopen('file', 'r'); function foo(){} @deprecated function foo(){} @throws InvalidArgumentException function foo(){} @route ['name' => 'foo'] function foo(){} Leaving out the brackets makes it very clear. I am in an extreme rush and will read more in the thread the next days, sorry. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] PHP Attributes
On 4/24/2016 6:57 PM, Levi Morrison wrote: > Genuine question[1]: how is @attr() different than `<>`? Also, > isn't `@attr()` 100% valid user-land code today that can precede > function or constant declarations? > > [1] I don't like that I have to make that explicit but it is what it is. > ROFL, that is actually totally true and I never thought about it. Damn silencing operator! :P However, i still think that the brackets are unnecessary and make it look like function calls. <> function f() {} -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] PHP Attributes
On 4/24/2016 2:54 PM, Fleshgrinder wrote: > Another way to illustrate what I mean: > > The feature will be used /to annotate/ (add metadata) and the so > /annotated/ data has additional /attributes/ afterwards. > > Trying building the sentence if the feature is called /attributes/. > > @entity > @invariant > final class A { > > @inject > private static $x; > > @test > public memoized function f(){} > > } > > r = reflect A > r.getModifiers = [ final ] > r.getAnnotations = [ entity, invariant ] > r.getAttributes = [ final, entity, invariant ] > > r = reflect A.x > r.getModifiers = [ private, static ] > r.getAnnotations = [ inject ] > r.getAttributes = [ private, static, inject ] > > r = reflect A.f > r.getModifiers = [ public, memoized ] > r.getAnnotations = [ test ] > r.getAttributes = [ public, memoized, test ] > > Note that there are programming languages that allow adding of metadata > solely via annotations: Ceylon. No matter the data to annotate. Hence, > in Ceylon no differentiation would be made between modifiers and > annotations. However, one could check the actual annotation type to > determine what it is. > > https://modules.ceylon-lang.org/repo/1/ceylon/language/1.2.2/module-doc/api/index.html#section-annotations > The example isn't actually complete, sorry: @entity @invariant final class A { @inject private static $x = 0; @test public memoized function f(){} } r = reflect A r.getModifiers = [ final ] r.getAnnotations = [ entity, invariant ] r.getAttributes = [ final, entity, invariant, $x, f() ] r = reflect A.x r.getModifiers = [ private, static ] r.getAnnotations = [ inject ] r.getAttributes = [ private, static, inject, value((int) 0) ] r = reflect A.f() r.getModifiers = [ public, memoized ] r.getAnnotations = [ test ] r.getAttributes = [ public, memoized, test ] I hope I didn't forgot any attribute. :P All in all, attributes are things that things have to describe those things and annotations allows us to add additional attributes to things, on top of possible other attributes that are already addable by other means (modifiers, values, ...). -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] PHP Attributes
Another way to illustrate what I mean: The feature will be used /to annotate/ (add metadata) and the so /annotated/ data has additional /attributes/ afterwards. Trying building the sentence if the feature is called /attributes/. @entity @invariant final class A { @inject private static $x; @test public memoized function f(){} } r = reflect A r.getModifiers = [ final ] r.getAnnotations = [ entity, invariant ] r.getAttributes = [ final, entity, invariant ] r = reflect A.x r.getModifiers = [ private, static ] r.getAnnotations = [ inject ] r.getAttributes = [ private, static, inject ] r = reflect A.f r.getModifiers = [ public, memoized ] r.getAnnotations = [ test ] r.getAttributes = [ public, memoized, test ] Note that there are programming languages that allow adding of metadata solely via annotations: Ceylon. No matter the data to annotate. Hence, in Ceylon no differentiation would be made between modifiers and annotations. However, one could check the actual annotation type to determine what it is. https://modules.ceylon-lang.org/repo/1/ceylon/language/1.2.2/module-doc/api/index.html#section-annotations -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] PHP Attributes
I am not arguing against the RFC nor the feature itself, on the contrary, I like it. I just do not like certain aspects and design decisions of it; that is all. Configuration and AOP are the best usecases for annotations and those should be stressed in the RFC. They are not mentioned at all! Another usecase that I am missing completely is the usage of it for documentation and static code analysis. I already mentioned the /throws/ annotation, this could help e.g. IDEs to warn you better about uncatched exceptions form methods you call. DbC is a possible usecase but better implemented at language level. The RFC could mention the possibility of it. However, right now it is the sole usecase beside the not very PHP applicable `<>` and `<>` examples. You see, this is more a problem of the RFC text and not of the feature. ;) Another think I complained about is the proposed syntax because it makes annotations look like function calls, which they simply are not and will not be. The syntax is misleading and a possible built-in functionality of reactive annotations (not saying we need them) at the language level for userland is blocked. I know I just repeated myself. The extension you mentioned works just fine without the brackets. @invariant CONDITION; class A { @ensure CONDITION; @require CONDITION; function f(){} } -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] PHP Attributes
On 4/24/2016 1:58 PM, Benjamin Eberlei wrote: > The article *you* reference about attributes lists C# attributes as the > *first* example. > > And defines an attribute as: > > "For clarity, attributes should more correctly be considered metadata > <https://en.wikipedia.org/wiki/Metadata>. An attribute is frequently and > generally a property of a property." > > HHVM uses the name attribute, for the same syntax that Dimitry proposes > here. > > *MUST* is such a strong word in this context, this is not an 0 XOR 1 issue. > On 4/24/2016 2:07 PM, Zeev Suraski wrote: > Thanks for the programming 101 lesson :) > > I pointed out to Sebastian, who suggested that 'attributes' are equivalent to 'member variables' or 'properties', that they're very consistently referred to in PHP as 'properties' and that I'm not aware that they were ever referred to as 'attributes'. > > Nothing in your links suggested otherwise, arguably the opposite. According to https://en.wikipedia.org/wiki/Attribute_(computing), "An attribute is frequently and generally a property of a property", and while "the term attribute can and is often treated as equivalent to a property depending on the technology being discussed", when the technology in question is PHP, this is not the case. > > Of course, member visibility modifiers and access modifiers (public/protected/private, static, etc.) are a different thing. Saying member variables are referred to as attributes (incorrect in the context of PHP, AFAIK) is very different from saying these modifiers are referred to as attributes (correct and sensible). > > Last, we're absolutely allowed to have our own definitions of terms as long as they're sensible. Both attributes and annotations are sensible here, and the fact there may be languages that treat attributes as equivalent to properties isn't a strong reason against using that term for something sensible, that is different from these other languages, in PHP. > > Zeev > As I said, unless somebody knows an even better term. It also depends on which source code is going to be allowed to have this kind of additional metadata. If we limit it to functions, classes, properties, and methods: /all good./ Why? We might want to allow adding of metadata to other parts of the source code in the future. I already asked regarding annotating files themselves (as is possible with PhpDoc's file-level docblock) and then it becomes complicated. I am not saying we need this, I am saying we need to clarify this. Using the term attribute without defining what the term means is problematic. I know, Facebook/HHVM/Hack but we are not required to be compliant with them and they are not our benchmark. Using the term annotation is not so problematic because it has a clear definition (not only in computer science) and it does not say anything about the applicability of what it does, it only states the functionality of the feature itself: /adding metadata to data/. You want to avoid writing extensive definitions of terms that are going to be used since people then need to learn these terms. Just think about the normal usage of the word attribute in language, e.g. describe the attributes of this image. The answer could be "it shows a woman with long hair and blue eyes". Hence, /long hair/ and /glue eyes/ are attributes of the woman. However, asking for the annotations of this image would result in a different answer, the asked person, assuming she knows what the word in general means, turns the image and would tell us the date and time it was taken or printed, or maybe the ISO level, ... whatever. Is *public* an attribute of the property? /Yes/ Is *static* an attribute of the method? /Yes/ Is *name* an attribute of a person? /Yes/ Is *__toString* an attribute of the class? /Yes, behavioral/ Is *inattentive* an attribute of the child? /Yes/ ... So, what should `$r->getAttributes()` return? It is to broad, it is to generic, it is too often mixed up. `$r->getAnnotations()` is less ambiguous in the context of programming and thus a better choice. I hope you can follow my /Gedankenspiel/ (mind game) better now. :) -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] PHP Attributes
On 4/24/2016 1:36 PM, Benjamin Eberlei wrote: > On Sun, Apr 24, 2016 at 10:24 AM, Fleshgrinder wrote: > >> The invariant could also be added as an additional branch to the class >> instead of a method, since it would not work like a method. >> >> class A {} invariant {} >> >> function f() {} require {} ensure {} >> >> This would also align nicely with closures and anonymous classes, which >> is kind a problematic with annotations. >> > > You are way off topic with this imho. > No, not at all! The RFC explicitly mentions design by contract (DbC) and that is why I am responding to that. I do not think that annotations should or could be used for DbC and want to raise this issue here. Of course all of the above is a completely different story and requires its own RFC as well as implementation. However, DbC should not be used to justify the addition of annotations to PHP. (If libraries choose to use it for that, different story.) On 4/24/2016 1:36 PM, Benjamin Eberlei wrote: > Attributes as proposed by Dimitry are not executing functions, they are > only metadata > that can be retrieved through reflection API. I think a python style > decorator approach > that you propose here, executing functions is not what the different > pro-annotations, > pro-attributes or pro-DesignByContract fractions want/need. > > You are proposing something along the lines of AOP, which is an entirely > different beast > in my opinion. > I know and that is why I am writing that the usage of brackets is not a good idea because it suggests exactly that. We need to think about a possible feature as outlined by myself (reactive annotations or /Python style decorator approach/ as you call it) in order to not implement annotations in a way that would kill exactly such a feature in a possible future. Hence, I am not off topic because I am thinking outside of the box in the context of the whole ecosystem. Something that I see not happening in this RFC nor its discussion. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] PHP Attributes
On 4/24/2016 1:00 PM, Zeev Suraski wrote: > > >> -Original Message- >> From: Sebastian Bergmann [mailto:sebast...@php.net] >> Sent: Sunday, April 24, 2016 12:14 PM >> To: internals@lists.php.net >> Subject: Re: [PHP-DEV] [RFC] PHP Attributes >> >> On 04/21/2016 11:13 PM, Dmitry Stogov wrote: >>> I would like to present an RFC proposing support for native annotation. >> >> Dmitry, >> >> please use "annotation" as the name for this feature and not "attribute". >> >> We already have attributes: it's what we use to store data in objects. And >> while some people call them "member variables" or "properties" the correct >> term for them (AFAIK) is "attribute". > > I don't think I've ever heard properties referred to as attributes in the > context of PHP. The PHP manual defines them and refers to them throughout as > 'properties'. > > (I'm not voicing an opinion on attributes vs. annotations; Just pointing out > that data storage inside objects isn't named attributes). > > Zeev > The terminology here is pretty clear and you can just look it up, it has nothing to do with PHP or Java or whatever. The main problem is simply that people do not know the terminology and get mixed up. That is usually okay in a casual discussion where each peer understands what the other is referring to. However, we are dealing with language specification here and need to be very exact or we fuck it up for the users. `$x` is a property in the following example: class A { $x; } https://en.wikipedia.org/wiki/Property_%28programming%29 `private` is an attribute of property `$x` and an access modifier (not visibility, because the property is still visible, e.g. via reflection, and it only alters access to the property): class A { private $x; } https://en.wikipedia.org/wiki/Attribute_%28computing%29 Note that these things go further up in the terminology hierarchy to: Field - https://en.wikipedia.org/wiki/Field_%28computer_science%29 Record - https://en.wikipedia.org/wiki/Record_%28computer_science%29 Data Structure - https://en.wikipedia.org/wiki/Data_structure This is not the whole image yet, there are more things like (random order): - functions - methods - members - class variables - static variables - behavior - data - ... You will notice, if you read all Wikipedia articles and related documents, that these terms are too often used interchangeable. This is, as mentioned before, mainly the case because people to not care about terminology in general. To sum it up, calling them attributes is outright wrong because not all parts of a source code of a programming language has attributes. That is why Sun chose the word annotation. Annotation means metadata that was added to data. It does not say anything about the data itself and it does not necessarily alter the data in any way, however, it can. This is exactly what this feature is about. Since, an entity annotation does not alter the data (in this case a class) itself but this additional metadata may be used to configure other parts of the program. The same is true for a method that has been annotated with test. The data is not altered at all but is helps other parts of the program to configure specific data and behavior based on this additional metadata that was added to the data. Execution of the same method without those other parts that react on the metadata does not do anything and the program will execute normally. TL;DR this feature *MUST* be called annotations (unless someone knows an even better term) and the annotations *MAY* be used to add attributes to properties but for many other things too. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] PHP Attributes
The invariant could also be added as an additional branch to the class instead of a method, since it would not work like a method. class A {} invariant {} function f() {} require {} ensure {} This would also align nicely with closures and anonymous classes, which is kind a problematic with annotations. $A = new class {} invariant {}; $f = function () {} require {} ensure {}; The only thing that remains that might be of interest to both is `@throws` but that was not discussed at all as of yet. use Ns\SomeException; @throws SomeException function f() { } This is at least how one would expect it to work and it is something that should be covered by annotations and not as part of the language. The ABNF should account for that: ANNOTATION= "@" NAME [ " " VALUE ] NAME = STRING VALUE = QUOTED-STRING / PHP-REFERENCE / EXPRESSION QUOTED-STRING = ( "'" / DQUOTE ) STRING ( "'" / DQUOTE ) EXPRESSION= PHP-CODE ";" Where PHP references are any of the already possible ones: use F\Q\C\N; @annotation \F\Q\C\N @annotation N @annotation \F\Q\C\N::CONSTANT @annotation N::CONSTANT @annotation \F\Q\C\N::function() @annotation N::function() @annotation \F\Q\C\N::$variable @annotation N::$variable I also though some more about function support for annotations and this would actually be a nice thing for userland. annotation deprecated(Reflection $element, string $message = '') { @trigger_error($message, E_USER_DEPRECATED); } @deprecated('because') function x() {} @deprecated function y() {} This would allow users to implement simple and easy reactive annotations in userland. Even if this could or should be an extension of the feature in the future, it should be thought about know. Simply because the brackets make sense if such a feature is to be implemented. ;) -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] PHP Attributes
On 4/24/2016 1:48 AM, Benoit Schildknecht wrote: > If I was a popular framework creator, this wouldn't stop me. I would > release two packages : one for 7.0, another one for 7.1. And the 7.0 one > would be the 7.1 one that has been processed through a script to remove > any <<>> syntax, or to transform it (if pre/post attributes instructions > were to be implemented in the core). > > Regards, > Ben. > > Le Sun, 24 Apr 2016 01:09:08 +0200, "Thomas Bley" > a écrit: > >> The <<>> syntax comes with the problem that previous versions cannot >> ignore it on parsing. >> So poeple write new frameworks for 7.0 which cannot be parsed in 5.x, >> then they write new frameworks for 7.1 which cannot be parsed with 7.0 >> and 5.x and so on. >> For companies staying on Linux distributions with long term support on >> 7.0, this is rather a nightmare for both users and framework maintainers. >> When choosing <<>> or any other non-backward compatible syntax for >> 7.1, there should be a patch for 7.0 to ignore the new syntax without >> parse errors. >> >> Regards >> Thomas >> > That is the nature of a feature release, you find many of those in any PHP feature release. Think of for instance `yield`, directly results in a parse error in older PHP versions. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] PHP Attributes
On 4/22/2016 4:15 AM, Sara Golemon wrote: > All that said, I love the proposal overall, and I can't wait to > propose builtin annotations like <<__Memoize>>, <<__Mock>>, and > similar. > I'd rather see these two functionalities added as modifiers at the language level instead since they change the code behavior rather dramatically. Not sure if knowledge of them is of interest in stages where annotations might not be readily available; this was a driving factor in Kotlin's decision what becomes a modifier or annotation.[1] I know that this is true for `@invariant`, `@require`, and `@ensure` as well, they are fully-fledged assertions after all. Especially the `@invariant` could be easily added as a magic method. [assert] assert.invariants = 1 Both `@require` and `@ensure` are a bit harder to implement at language level. The following is the best I can come up with and is inspired by the Eiffel syntax.[2] [assert] assert.preconditions = 1 assert.postconditions = 1 balance -= $this->balance - $sum; } require { $sum >= 0; $sum <= ($this->balance - self::MIN_BALANCE); } ensure { $this->balance === (old::$balance - $sum); } } $account = new Account; $account->withdraw(-10); /* Uncaught PreconditionError: $sum >= 0 */ $account->withdraw(10); /* Uncaught PreconditionError: $sum <= ($this->balance - self::MIN_BALANCE) */ $account->deposit(10); $account->withdraw(5); /* Uncaught PostconditionError: $this->balance === (old::$balance - $sum) */ ?> I actually think now that it would be better to go for this than for annotations. [1] http://blog.jetbrains.com/kotlin/2015/08/modifiers-vs-annotations/ [2] https://archive.eiffel.com/doc/online/eiffel50/intro/language/invitation-07.html -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] PHP Attributes
+1 for the basic idea, however, I have various remarks. The RFC text is hard to read and contains many grammatical mistakes. How could one help you here? I think that the Hack name attributes is unintelligible and annotations would be much clearer to any audience. Simply because the name is very well known. I do not see the need for multi-annotation nor multi-value support. It just creates multiple ways to achieve the exact same thing for no good reason. I do not like the <<>> syntax. It requires many key strokes, is hard to read, and looks ugly. Why not simply @ and be done with it. I am not so sure about the bracket requirement, is it somehow required for the parsing? Otherwise I would leave it off. I guess it might be hard to find the end of an annotation but have you considered to use the semicolon for that? Would align nicely with existing PHP syntax. The following would be the ABNF for my proposal: ANNOTATION= "@" NAME [ " " VALUE ] NAME = STRING VALUE = QUOTED-STRING / PHP-CONSTANT / EXPRESSION QUOTED-STRING = ( "'" / DQUOTE ) STRING ( "'" / DQUOTE ) EXPRESSION= PHP-CODE ";" A semicolon would only be required if it is not a single quoted string (see following example) or constant. A question that I see unanswered is how embedding of variables in quoted strings should be dealt with. I see no need for this but people might assume it is supported because PHP supports it everywhere else. " class A {} <")>> class B {} ?> Requiring PHP code to be terminated with a semicolon should also ensure that people do not start to write fully-fledged programs in annotations. Since that is not what they are intended for. An alternative approach I see here would be to go for the brackets but then again only for PHP code: EXPRESSION = "(" PHP-CODE ")" Then again, it looks similar to a function call and this is imho not good. Unless of course new annotations can be defined as special functions directly in userland, e.g. with an `annotation function` and/or `annotation class`. However, this would require more thought. Another question that is unanswered for me is: how to go about adding annotations to a complete file as is currently possible with PhpDoc and its file-level doc block: ' @copyright '2016 Richard Fussenegger' @license 'MIT' declare(strict_types=1); namespace Fleshgrinder\PhpInternals; @description 'True annotation support could be a very good thing.' @invariant $this->balance >= self::MIN_BALANCE; class Account { private const int MIN_BALANCE = 0; private int $balance; private Person $owner; @require $sum >= 0; @ensure $this->balance === (old::$balance + $sum); public function deposit(int $sum): void { $this->balance += $sum; } @require $sum >= 0; @require $sum <= $this->balance - self::MIN_BALANCE; @ensure $this->balance === (old::$balance - $sum); public function withdraw(int $sum): void { $this->balance -= $sum; } @deprecated 'for various reasons' public function setOwner(Person $wner): void { $this->owner = $owner; } } @inheritDoc class OverdraftAccount extends Account { private const int MIN_BALANCE = -1000; } ?> We also need to make sure to add something regarding coding standards for annotation names. I would propose to go for camelCase (same as for method names) since this is what PhpDoc used to use for many years now. We also need to define how people can avoid to collide with internal annotations. The typical double-underscore prefix approach that we have for magic methods creates a lot of visual clutter and looks weird if spread among all kinds of places. A namespace approach as we have it already for userland code could help here. 'user', 'unique_constraints' => [ 'name' => 'user_unique', 'columns' => [ 'username' ], ], 'indexes' => [ 'name' => 'user_idx', 'clumns' => [ 'email' ], ], 'schema' => 'schema_name', ]; class User {} ?> -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] Nullable Types
On 4/22/2016 11:42 AM, Quim Calpe wrote: > IMHO, the point of Optional types is the intention, if you get an > Option from a method, you have to deal with a None branch. Of course > you can just unwrap and go on, but it's a developer decision to do that, > not an oversight as using a Foo|null (or ?Foo) as an object directly. > IMOH, the point of ?T is the intention, if you get a null from a method, you have to deal with a null branch. Of course you can just ignore it and go on, but it's a developer decision to do that, not an oversight as using a Option as an object directly. Sorry, but this works in both directions. The problem is not null, the problem is that there is no system that warns you (e.g. a compiler) about the missing null check. I think that Ceylon solved this problem extremely nicely without the introduction of something special. function fn(): ?T {} $x = fn(); if (is $x T) {} else {} Not doing as above is a compiler error in Ceylon. However, I already wrote multiple times that there are already statical code analysis tools available that can find exactly such things in your code. One just needs to use them. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] Nullable Types
On 4/21/2016 1:00 PM, Lin Yo-An wrote: > I think this is not to make PHP like Java, and it totally makes sense - > Nullable should be a type of a type instead of a state. In Haskell it's > named Maybe or Option, and It's better than NullPointerException. > > Here is a discussion from Haskell community: > https://mail.haskell.org/pipermail/haskell-cafe/2011-April/091269.html > Why is it /better/? final class None {} final class Some { public $value; public function __construct($value) { $this->value = $value; } } final class Maybe { private static $none; private $value; private function __construct($value) { $this->value = $value; } public static function NOTHING() { if (self::$nothing === null) { self::$nothing = new Nothing(); } return new static(self::$nothing); } public static function SOME($value) { return new static(new Some($value)); } public function hasSome(): bool { return $this->value !== static::$none; } public function isNone(): bool { return $this->value === static::$none; } public function unwrap() { if ($this->value === static::$none) { trigger_error('NullPointerException', E_USER_ERROR); } return $this->value->value; } } // function f1(): Option {} $x = f1(); if ($x->hasSome()) { echo $x->unwrap(); // 42 } $x = f1(); if ($x->isNone()) { echo -1; } echo f1()->unwrap(); // error: NullPointerException :P // function f2(): ?int {} $y = f2(); if (isset($y)) { echo $y; // 42 } $y = f2(); if ($y === null) { echo -1; } echo f2(); // null You can easily build your own Option or Maybe and add the additional bookkeeping to your runtime but it will not make your program more secure or anything. It just adds more method calls and makes it more verbose. You can already use static code analyzers to detect if null is being ignored in your code, however, right now they mainly have to rely on PhpDoc that is often not properly documented. Adding an explicit syntax to PHP for documentation would make PhpDoc obsolete and allow static code analyzers to perform their job better and PHP to error out during runtime if something else is being returned. Honestly, null is not our problem. Every language has its null, just because they wrap it or rename it does not make null suddenly vanish from the universe. :P -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] Nullable Types
On 4/21/2016 6:33 PM, Thomas Bley wrote: > Hello Tom, > > with default return value I mean to return a certain value if nothing else is > returned (similar to method parameters with a default value). > > example 1: > > declare(strict_types=0); > > function my_strpos(string $haystack, string $needle): int = false { > return 42; // return 42 > return false; // return false > return true; // return 1 > return; // return false > } > > example 2: > > declare(strict_types=1); > > function my_strpos(string $haystack, string $needle): int = false { > return 42; // return 42 > return false; // return false > return true; // fatal error > return; // return false > } > I definitely do not like the equal sign in there because it goes against all my mathematical knowledge; an int is false?!? Note that the same /would/ be possible with union types if given precedence: function fn(): int|false {} That being said, it is way too magic! A return without an argument is *void* and has to result in a `TypeError`. Really, start to think about the types as /checked annotations/ ... /** * @return int|false */ function fn() {} function fn(): int|false {} ... are equivalent and the former does not suddenly return *false* on its own and hell it shouldn't. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] Re: Improving PHP's type system
On 4/20/2016 10:18 PM, Dominic Grostate wrote: > Just a thought that crossed my mind which might satisfy both worlds. Has > anyone every considered unions as a type declaration? > > namespace Vector/TypeDefs > > union Stringable > { > as string; > as int; > as float; > > private $value; > > public function __make($type) > { > switch (type) { > case 'string': return (string) $this->value; > case 'int':return (int)$this->value; > case 'float': return (float) $this->value; > } > } > } > > my_echo_func("123"); // << A scalar variable on the outside. > > function my_echo_func(Stringable $stringable) // << a union on the inside > { > var_dump($stringable as string); // string(3) "123" > var_dump($stringable as int); // int(123) > var_dump($stringable as float); // float(123.0) > } > > Perhaps not exactly like this, but adding unions as type of class > declaration should save a hell of a lot of keywords, and may save a number > of "instanceof" type checks as well. > I do not like the idea because these types directly become part of your public API and you end up including a dozen packages just to get the basic union types in. More IO, more cache utilization, more dependencies, ... Also, one cannot change any type that was ever declared without a direct BC. No, sorry, I thing that this is very bad. :( However, the idea to make objects castable to more of the various scalar types is not new and would be awesome. interface Object { function __toBool(): bool; function __toFloat(): float; function __toInt(): int; function __toString(): string; function __toArray(): array; function __toObject(): object; function __toResource(): resource; } Auto-conversion only if not ambiguous (`$o1 + $o2` where both have `__toInt()` and `__toFloat()` throws an ?Error but `(float)$o1 + (float)$o2` works so does `intdiv($o1, $o2)`), next is operator overloading. ;) -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] Quick sanity check ...
On 4/20/2016 11:03 PM, Stanislav Malyshev wrote: > No of course not. The specific instance of error you had *this time* may > be solved. The problem won't be. You still have to deal with: > - How this object is initialized? How you ensure it *is* initialized and > that initialization is correct (0 is perfectly valid int)? > - How this object is unserialized and what if unserialized data has > non-integer or 0 or __wakeup has a bug? > - What if some code just writes 0 into $olderThan - you declared it as > public so anybody could mess with it? > - What if some code mixes signed and unsigned and you get negative > number instead of positive? > - What if this code runs on 32-bit but receives 64-bit value and > truncates it? > > And so on, and so forth, I probably missed more possibilities than I > mentioned. Declaring a type does not magically free one from correct > design and testing, and typed programs have bugs as much as non-typed > ones (maybe slightly different ones). Actually, one of the harms relying > on it would be the same problem safe_mode had - it's full of holes, it's > not safe and it creates wrong expectations. If you just write "int" and > expect your problems to magically go away - you're in for big and bad > surprises. > While I agree with Stanislav and the others that a stricter type system would not have prevented the bug. However, a stricter type system helps to limit the amount of tests one has to perform and that is often a good thing. That does not mean that dynamic type systems are shit. Actually the opposite is the case, it is the same situation with paradigms. What I love about PHP is that we have a lot under one hood: multi-paradigm as well as loose and strict types. This allows one to choose the best tool for the current job. Relying on your language for a bit of safety as asked of it cannot be compared to `safe_mode` where magic happens in the background. When one declares and `int` than it should be an `int`. Of course that also means that one should know what an `int` is and how to validate it according to the current business rules. That being said, isn't Lester's goal to validate scalar strings all the time anyways? I mean, at least `mysqlnd` transforms all data from the DB automatically to the proper scalar types for optimal performance in your program. But if one keeps scalar strings everywhere and leaves proper type coercion to PHP, I mean, why not. It is definitely doable and strict types are definitely not necessary if done properly. The big difference I see is that Lester is working on his code for himself (or for a customer) and does not have to design APIs for hundreds of other developers. PHP is used in the way it was initially designed, as a glue language. I repeat myself but I cannot see the need for strict types here. If you are developing APIs that are going to be (ab)used by hundreds of other developers in ways you would never have foreseen things change. One wants to ensure that the API is as self-explanatory as possible and as easy to use as possible. This includes (to get back to one of your examples) that objects that should not be serialized are not serializable (`private function __sleep()`) and not deserializable (`private function __wakeup()`) nor cloenable if necessary. This includes self-explanatory required types, sane default values, and appropriate visibility of things. PhpDoc is the classical tool for us here and Stanislav wrote in another thread that this is the tool of choice. I completely disagree with this because PhpDoc might be nice and already features more complicated types (e.g. unions), however, it is also lacking many features as the development of the PSR-5 shows. Another problem is that documentation is not kept in sync and it is extremely hard to teach people how important proper documentation is. Believe me, I know. You might say now that those programmers are bad, well, yes, maybe. But that is what you get when you are working in huge teams; ask Google. In the end it is about better APIs for me as I explained in many other messages and I stay true to that. :) -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] Quick sanity check ...
On 4/21/2016 2:52 AM, Lester Caine wrote: > PHP5.4 http://lsces.org.uk/ 0.41s 3.65Mb > PHP5.6 http://php6.lsces.org.uk/ 0.54s 11.77Mb > PHP7 http://php7.lsces.org.uk/ 0.45s 1.83Mb > > Same set of code ... 3 different fpm instances > PHP5.2 one with eaccelerator will not run :( but I think I now have PHP7 > configured properly with OPcache but it still does not match the speeds > I get on the PHP5.2/eaccelerator production machines! > Well, hard to tell if you could improve further without any info on setup and/or configuration but the numbers look good to me. Also, do not forget that the times and memory consumption you get from PHP might not reflect the real world. I would suggest to measure this with independent tools. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] Quick sanity check ...
I do not see a single reason why you would need to change anything if you are not requiring any of the new features and would say that the only reason to upgrade for you is security patches. However, I hardly believe that you cannot see a speed improvement; or at least less memory consumption. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] Re: Improving PHP's type system
I am not quoting anything because the formatting of your emails is completely off in Thunderbird. However, I want to add one to the list: declare(strict_types=1); interface Stringable { function __toString(): string; } function fn(string|Stringable $arg) { $param = (string) $arg; } We could add a new *stringable* primitive to PHP though, but do we guys really want to start doing so? There is pretty much an endless amount of combinations and finding names alone is endlessly hard. declare(strict_types=1); function fn(int|string $maybe_bigint) { // mysqlnd automatically creates the proper type based on the value. // Expressing this in userland is impossible ... :( } -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] Re: Improving PHP's type system
On 4/19/2016 10:19 PM, Zeev Suraski wrote: > I can only repeat - primitive types can and should get dedicated solutions. > There's really no need for allowing over creativity with userland-customized > scalar types. If we think that a certain scalar definition makes a lot of > sense, we can add it at the language level. There's no need to complicate > the language, add syntax which makes no sense for objects and isn't really > needed for scalars either. > We can for many: type number := int|float type object := type scalar := bool|int|float|string ... However, what about: type ? := array|Traversable type ? := int|string type ? := float|string type ? := bool|null ... I actually argue that we do not even want to define them on a language level (with the exception of array|Traversable) because these combinations are too usecase specific. >> interface HouseCat { >> function drink(); >> } >> >> interface Dog { >> function eat(); >> } >> >> -interface Lion { >> +interface Lion extends HouseCat, Dog{ >> function drink(); >> function eat(); >> } > > Pardon me saying this but it doesn't appear as if you've read what I wrote. > Please take a look at the 'diff' I made in the definition of your Lion class, > because without it, your sample and mine have little to do with each other. > > With that change in place, please reevaluate whether what you said is > relevant: > I guess I just jumped over that fact and misinterpreted it because what you are proposing is a magic intersection type limited to interfaces. While I cannot think of a situation where this creates problems from a technical point of view (it is duck typing after all) I find it highly, highly unusual and way too magic as well as even confusing. I think there are two ways: - No union/intersection at all! + Union and intersection! Going somewhere in between destroys generics, bounded quantification, and F-bounded quantification in the future or at least makes it harder to implement cleanly. You need to consider that this RFC might be voted negative but it might come back in PHP 8 or PHP 9 where the landscape has changed so vastly that it might become a yes. Let's not introduce half backed features that nobody ever implemented and found useful in any context or we end up with more weirdness that we already have a some points. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [VOTE] Catching Multiple Exception Types
On 4/19/2016 9:39 PM, Stanislav Malyshev wrote: > Hi! > >> Except these two are in separate libraries that cannot share an interface. > > If these are separate libraries, you can't be sure that method does the > same thing, or even that it will be existing in both. > >> An interface is not possible: separate libraries. Duck-typing is not >> appropriate: only these two specific classes are supported. > > This looks very strange and brittle design - two random classes from two > unrelated libraries, which you rely on have exactly the same > functionality and keep it that way. Not a robust design if you ask me. > Also, it looks strange why only those two random classes can be > converted to arrays but none others can. What if you had third class > that also can be converted to array? What if you had 20 of them? Again, > looks like brittle and ad-hoc design. > Stanislav is completely right here, this is exactly one of the usages of union types that is completely wrong. You had this example: namespace Application; function log(Eloquent\Collection | Haldayne\Map $entity) { $logger->log($entity->toArray()); } try { log(Config::find()); } catch (Eloquent\Exception\UnexpectedValue | \UnexpectedValueException $ex) { die('Configuration is neither array nor object'); } The problem with this is that you now require both libraries to be installed at the same time because otherwise the union type cannot be verified by PHP's type system. This will bite you in the ass in no time. Just think of your composer: "require": { "eloquent/collection": "*", "haldayne/map": "*" } Both do the same?!? Better rely on duck typing in such cases. function log($entity) { if (method_exists($entity, 'toArray')) { $logger->log($entity->toArray()); } else { // handle is in another way. } } If you really want to ensure that the method is not being called by a dev in that way go for assertions. function log($entity) { assert('method_exists($entity, "toArray")', 'entity must implement `toArray` method'); // Check in production too to avoid fatal errors? if (method_exists($entity, 'toArray')) { $logger->log($entity->toArray()); } } Union types only have a few special use cases but those are worth exploring imho. function div(int|float $x, int|float $y): int|float { if (is_float($x) || is_float($y)) { return $x / $y; } else { return intdiv($x, $y); } } function even(int|string $x): bool { if (is_int($x)) { return $x % 2 === 0; } else { return gmp_mod($x, 2) == 0; } } -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] Re: Improving PHP's type system
On 4/19/2016 8:48 PM, Zeev Suraski wrote: >> but it does not help with primitive types. :( > > Which is fine. Primitive types can and should get dedicated solutions. > There's really no need for allowing over creativity with userland-customized > scalar types. > Hmmm... nope. I already brought various examples where I personally see the strength of union types and that is exactly with the primitives.[1] *int|string* is so powerful if you deal with MySQLi and its BIGINT stuff because I can fully type hint it now (like the /mysqli/ extension does in C) and check very fast if I need to use GMP or not. I can only repeat. I am fully supporting to block union types if we instead commit to the introduction of additional primitive types (as outlined in the generics RFC)[2] and operator overloading in userland. However, use cases remain and union/intersection types can help especially if you do not want any kind of is-a relationship in your classes. In other words, we do not want to introduce an additional interface for something because we do not want the instance to pass through other checks. Or, of course, the situation where it is simply impossible for me to introduce the interface: built-in classes. I might want to decorate them and pass through all checks but I cannot because, well, how? [1] http://marc.info/?l=php-internals&m=146080503103988&w=2 [2] https://wiki.php.net/rfc/generics#related_enhancements > I believe you think I meant that instead of checking that $b's class actually > implements foo and bar, we'd check whether $b has all of the methods needed > by foo and bar - which means that theoretically means that it may have > methods foo() and bar() but not actually 'officially' implement their > respective interfaces. But there's no reason to do it this way and that's > not what I meant. > Instead, with my proposal, a $b object whose class implements both foo and > bar - will automatically be accepted as one that also implements baz. The > checks will be conducted at the interface level, not the function list level. > In other words, if $b doesn't explicitly implement baz, we'd take a look at > 'baz', see it's comprised of foo & bar, and check whether $b's class > implements them. > > At this point, I can't imagine any negative side effect to automatically > deducing that an object that implements foo and bar also implements baz > (other than a small performance hit, probably roughly the same as the AND > union type). Like I mentioned in my original post, I don't necessarily think > it's needed - I personally see no reason not to add 'baz' to the list of > interfaces impl implements, or as you said, replace foo and bar with baz > altogether. > interface HouseCat { function drink(); } interface Dog { function eat(); } interface Lion { function drink(); function eat(); } A lion drinks and eats but is neither a HouseCat nor a Dog. This is dangerous and introduces many potential hard to find bugs. Better don't touch it and go for duck typing or the introduction of a dedicated interface: *always* -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] Proposal: Startup snapshot for optimizing app load time
On 4/19/2016 6:54 PM, David Zuelke wrote: > I think this solution is merely a band-aid for a more profound architectural > weakness of current PHP setups, where a web server call out to the engine > (via embedding or FastCGI) to execute a script, which causes this recurring > initialization overhead in the first place. > > The future is (or should be) servers implemented fully in PHP code (e.g. > PHP-PM), just like every other comparable language (Ruby, Python, Java, ...) > already does. That also brings many other benefits, such as the ability to > handle upgrades to WebSockets in the same codebase, stream request bodies as > they're being uploaded, and so forth. > > And the performance figures that PHP-PM delivers with Symfony validate that > approach IMO. > This requires proper memory management, no matter how: https://software-gunslinger.tumblr.com/post/47131406821/php-is-meant-to-die https://software-gunslinger.tumblr.com/post/48215406921/php-is-meant-to-die-continued -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] Re: Improving PHP's type system
On 4/19/2016 4:36 AM, Tom Worster wrote: > On 4/18/16 4:34 AM, Tony Marston wrote: > >> I repeat, where was the insult in the post in question? What exactly >> were the insulting words? > > I chose just one example: > >> Those who cannot write effective software without these "clever" >> additions to the language are doing nothing but announcing to the >> world that they are not clever enough to write effective software >> using their own limited abilities. > > I think it's hard to avoid construing an implication that people > proposing and/or supporting changes to how PHP handles type in the > current discussions here are incompetent programmers. > > There's no doubt that this sentence posits a class of incompetent > programmers who need crutches ('these "clever" additions') and a > complementary class of competent programmer who don't. Saying so is > pointless without some assignment (imaginary, implied or real) of > individuals to the classes. It's hard to imagine that present company or > the people whose interests we attempt to represent are not involved in > the assignment. I find this a bit insulting. > > Insult is something experienced as well as something performed. If > enough people experience it then probably it was performed, regardless > of intent. So to this extent I just disagree that... > >> The fact that you don't like what I say does >> not make it an insult. > > "It's Not What You Say, It's What People Hear" > > > But we are now completely off topic. To bring us back on topic I repeat > my request that you try to be specific about what you want and why, with > respect to the RFCs under discussion. > > Tom > > Very well said! :) -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] Re: Improving PHP's type system
On 4/19/2016 11:41 AM, Zeev Suraski wrote: > It could actually implement all of them - the two parents, and the child. > That sounds like a pretty good, explicit way that requires no introduction of > any new syntax, concepts or engine complexity in order to do what you're > describing. This works fine: > > interface foo { function foo(); } > interface bar { function bar(); } > interface baz extends foo,bar {} > > class impl implements foo, bar, baz { > function foo(){} > function bar(){} > } > > function sth(baz $b){} > `class impl implements baz {}` is actually already enough here because `baz` extends `foo` and `bar`. This is the only way to solve such situations right now but it does not help with primitive types. :( > One thing we could consider is adding some intelligence for these cases, and > for interfaces that only extend other interfaces (without adding new > signatures) - a class would be considered to implement that interface if it > implements all of the 'parent' interfaces that the child interface extends: > > class impl implements foo, bar { > function foo(){} > function bar(){} > } > > function sth(baz $b){} <-- would work, as impl implements both foo and bar, > and baz does nothing but extending those. > > I'm not sure that's necessary, and believe the current mechanisms and syntax > satisfy these use cases already, but it's probably a possibility. > That sounds like runtime checked duck typing. This actually makes the type system less strict and might have horrific side effects and that is exactly the opposite of what union/intersection types are meant for: preventing this. Above code is the same as: function sth($b) { $b->foo(); $b->bar(); } It will definitely fail if something else is passed in but if it is `foo`, `bar`, or `baz` everything is fine. The problem is that any object that satisfies the implementation of the methods `foo` and `bar` would ultimately fulfill the contract here. function sth(foo&bar $b) {} This is a different situation because now we know that it is something that actually implements exactly those two interfaces. Including possible additional constraints like argument and return type hints. There might even be a documentation shipped together with them that the implementer should take care of honoring. The intersection type hint is much stricter in such cases. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] Nullable Return Type Declaration
On 4/19/2016 12:02 AM, Lester Caine wrote: > On 18/04/16 20:08, Fleshgrinder wrote: >> This is however a useful shortcut and shortcuts are good things in >> terms of usability if done write. Think of + vs. right click >>>> copy (or any other example of useful keyboard shortcuts). > > Except when some sod adds a or decides left click is quicker ... > all of which are in use on one or other Linux desktop tool :( > > A CONSISTENT way of doing things would save a lot of time, so adding > even deeper levels of functionality is just overkill ... > Everything that is good can backfire if overused. We need to ensure that we do not do that and the fact that we are discussing it right here shows that we are not taking the decision lightly. :) -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] Nullable Return Type Declaration
On 4/18/2016 7:22 AM, Marcio Almada wrote: > 2016-04-17 23:56 GMT-04:00 Larry Garfield : >> Rather than debate the relative merits of Null as a concept, since I think >> all agree removing Null from the language is not even a thing, what do you >> think of my recommendation to NOT have the ? shorthand for "or null" on >> types, but keep the |null for union types? That is, if you want to return >> Foo or null, you have to use the long-hand version: >> >> function foo($a) : Foo|null >> >> That >> >> 1) Allows for explicit or-null behavior. >> 2) Doesn't make it quite so easy, which hopefully discourages (but does >> not prohibit) its usage. >> 3) Neatly avoids the ?Foo / Foo? question entirely. >> >> I think that's a win-win arrangement. >> > I can agree with that. > > Language design wise, if you have no way to forecast how language features > independently proposed are going to interact then it's a good idea to have > a converging strategy. Fortunately, this seems to be happening almost > spontaneously towards union types representation, as in the "multiple > catch" RFC (https://wiki.php.net/rfc/multiple-catch) now in voting phase. > > Even if we decide not to commit to a full union types implementation now, > the design process will be much easier in the future if we decide to use > Foo|null instead of Foo? or ?Foo and we will not end up with 2 or 3 ways > alternative to declare the same thing. > I actually do not see a problem with the shorthand notation. I am usually an extreme opponent of duplicated or aliased functionality because it increases the cognitive load to keep all this crap in your mind. This is however a useful shortcut and shortcuts are good things in terms of usability if done write. Think of + vs. right click > copy (or any other example of useful keyboard shortcuts). The usage of *null* as an union type is the most common case compared to all the others that are truly rare in comparison. There are other shortcuts in PHP that are perfect: - Iterator vs. Generator: they can achieve the exact same thing but slightly different and a generator can almost always be used to replace an iterator with less code, even if the special effects of it are irrelevant. - `$x = $x + $y` vs. `$x += $y`: we have many of those and that is just fine as it is. - `$x = $x + 1` vs. `++$x` vs. `$x++`: ditto - ` signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] Nullable Return Type Declaration
On 4/18/2016 8:24 PM, Stanislav Malyshev wrote: >> to have them calls them a "billion dollar mistake", many languages >> actively avoid having NULL in favor of something deliberately more >> structured. NULLs are a very common cause of avoidable fatal errors in >> many languages (including PHP). NULLs are rude to users of your API, as >> it balloons the error handling code they need to deal with. > > I think this description is misleading in a way. Nulls are immediate > causes of many errors, technically, in a meaning that "if I find null > where I expected to have DB connection, I get an error" - but this is > only a technical cause. The *real* cause is the failure to check whether > your attempt to connect to the database succeeded, or that you have > proper DB configuration, or such, and null is just a symptom of that > error - and that error is not automagically fixed by having some other > object instead of null. You have to actually design and write code for > it, there's no replacement for it. > > So declaring null "cause of all evils" is ignoring the real causes and > blaming immediate technical cause instead, and it would not be helpful. > It is true that for some languages with more complex type systems it is > possible to largely get rid of nulls by using those complex types and > ensure type system controls for all checks at least to be present (note > that doesn't guarantee proper function either, since no type system can > ensure you handle the case of missing DB connection properly, it just > can ensure you have a branch for it). But that requires much more > complex and involved type system that PHP has - or, in my opinion, > should have. > I agree with Stanislav here. *NULL* is not evil per se and just because some functional languages get some attention right now does not mean that they solved the biggest mistake in CS history. On the contrary, they just invented another way of handling it by introducing new types that require more book keeping and by refusing to compile if they encounter a place where proper handling is missing. As I wrote earlier, we could introduce such a feature into the language. However, static code analyzers can already provide this functionality. People just need to use them. TL;DR *NULL* is just fine if used correctly and we cannot make sure that people use it correctly. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] RFC: Functional Interfaces
+1 for the feature, very nice syntactic sugar to solve some edge cases. I agree with Rowan, i also do not like the name and propose to call them *closure interfaces*. There are already various synonyms for closures: - anonymous function - lambda function - callback* However, the strongest argument to call them *closure* is the fact that the the class in PHP itself is actually called *\Closure*. I would even go as far as saying that the documentation should be updated to always use that word everywhere.* The fact that only closures can implement such interfaces strengthens the reason to call them as proposed in my opinion. Just because Java calls them /functional/ does not mean that we should. Regarding error messages: Fatal error: cannot implement non functional interface IFoo in /in/65W6i on line 7 Fatal error: cannot implement nonclosure interface IFoo in /in/65W6i on line 7 Note on grammar: http://www.chicagomanualofstyle.org/qanda/data/faq/topics/HyphensEnDashesEmDashes/faq0079.html *) There is of course the situation of the various other ways to declare the so called *user functions* (/call_user_func()/ and /call_user_func_array()/) and those should always be referred to as *callback*; imho. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] Re: Improving PHP's type system
On 4/17/2016 5:58 PM, Lester Caine wrote: > And this is where the likes of Hack should be exactly where you are > working ... The vast majority of grass roots users don't need another > layer of complexity loaded on top of what IS a perfectly functional > platform. Adding types, complicating procedure calls and lumbering > everything with 'optional' layers of complexity is not something that a > small jobbing shop user has time to investigate the implications on his > client base. I'm still working through code that other have written and > trying to in many cases unravel exotic code that no longer fits the > modern programming style. I no longer take on any new clients as there > is enough work keeping my existing client base working, but there are a > LOT of people still using PHP5.2/3 who now need help if they are ever to > be brought forward. > > Now if you were proposing something that actually validated the data > fully rather than some very restricted 'type' elements then it might be > worth the effort, but 'int' is only a very small part of validating a > number and we still need the rest of the validation library after you > install a replacement for that bit mf it ... > Union and intersection types already get us closer to stricter data types that are flexible too. Of course they are not the best solution. I already mentioned in another mail that operator overloading is the only way to get us there. It is the only thing that allows us to create truly meaningful types. However, the problem of primitives remains, as was illustrated in this and related threads multiple types, e.g. `array|Traversable`. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] Re: Improving PHP's type system
On 4/17/2016 2:57 PM, Lester Caine wrote: > On 17/04/16 13:35, Fleshgrinder wrote: >> If you are only afraid that usage of your libraries declines because >> users demand these new features to be part of it and you do not want to >> implement them. Sorry, but that would be a clear sign that the features >> are good and should be used. > > I have two major libraries I have used since day one of PHP5 ... ADOdb > and Smarty ... both of these have provided the core of my framework, but > have needed a lot of work simply keeping my code in sync with them, and > the latest 'improvements' to both are not BC for reasons that are blamed > on needing to 'modernise' the code. Now I DID keep my own copies of both > for many years to keep the PHp5.2 code working, and perhaps I should > simply close the door on PHP7 and stay with what is currently working. > But PHP7 ... ignoring any of the new features ... does provide > improvements in some areas if you REMOVE the legacy stuff which prevents > the optimisations from giving their best. The 'improvements' to ADOdb > and Smarty are claimed to help this process but unfortunately the people > pushing those changes are 'new school' and expect all the new stuff as > well. So exactly where is PHP heading? Do we keep with the original > simple flexible language that even today still works fine, or do we > accept that everything that is being demanded should also be included > and just roll over. > > I do not accept the statement that 'You do not have to use it'! That may > have been true in the past, but today one has to live with the fact that > legacy code and modern hosting simply do not co-exist. One HAS to take > care that the key third party bits still work, and it's libraries like > the mapping extensions which relied on many key elements that HAVE now > been removed from PHP. > The situation you describe is a pain that I know myself and I agree. There are too many libraries that try to solve things in the most possible generic way and abuse OO to ridiculous excesses instead of just solving a single, simple problem with a few functions (as our old but gold Unix philosophy has taught us). The simple rule "If it ain't broke don't fix it" is also violated too much. The reasons for this are manifold and hard to grasp from time to time. I guess most often the problem boils down to "my library is not cool if it does not use the latest language features". Ignoring completely if those language features are actually appropriate for the problem. E.g. excessive usage of exceptions without a single assertion spread all over a code base to validate developer input. However, you should seek the discussion with the maintainers of these libraries and have a serious talk about BC, stability, and appropriate usage of language constructs to solve problems. Instead of trying to block advancement and evolution within the language itself. Most features that are currently discussed are aiming at enterprise applications that require more built-in functionality to ensure correctness, reduce the amount of tests (unit as well as runtime) to detect bugs, and where many developers work together at the same code base. Most features can increase agility and productiveness of such teams and allow them to implement new features and A/B tests faster. Of course many features require more knowledge about programming. This can also be bad for such teams because big teams almost always suffer from a huge knowledge gap. Despite that, it helps the more advance developers to create richer APIs that are harder to abuse and in turn allow the overall design to achieve previously mentioned goals. This is the sole reason why new language like Rust and Ceylon were invented in the last years. Of course there are also projects that aim at the novice user, e.g. Golang[1]. PHP currently achieves both in the context of web projects and support for enterprise was grew and grew and big companies like Facebook or my employee trivago who decided to go for PHP do not want to invest a shitload of money into rewriting everything from scratch in another language[2] like Twitter did (and exchange all their developers who were already extremely hard to find in the first place with new ones) just to get enterprise features. No, they want to see advances in PHP to support exactly those features. Facebook did not see those advancements and sent out their OCaml/C++ team to create something that has exactly those enterprise features while we at trivago plan to upgrade to PHP 7, while I am writing these lines, to get more performance out of the language and strict type checks. There are always pros and cons and it is hard to satisfy everyone but the type system of PHP is definitely one of its main weak spots and it must be improved to
Re: [PHP-DEV] Re: Improving PHP's type system
On 4/17/2016 2:19 PM, Lester Caine wrote: > On 17/04/16 11:29, Fleshgrinder wrote: >> Especially since its not needed at all. HHVM already solved most of >> these issues extremely nicely: >> >> - https://docs.hhvm.com/hack/types/type-system >> - https://docs.hhvm.com/hack/type-aliases/introduction >> - https://docs.hhvm.com/hack/shapes/introduction >> >> We want the same but do not want to copy?!? > > The simple answer NO > > If that is how you think it should be done, then use it. On my platform, > 'point' is a number of floating point numbers depending on your > geometry. And shapes use those points. So that area of 'hack' is of > little use to any mapping system, and trying to shoehorn existing code > to fit is 'pointless' ... > > It's the fact that many of these problems HAVE been solved without > resorting to overloading PHP with a subset that does not provide a > complete solution to the alleged problems that is the reall problem > here. Having to re-write libraries because some one else thinks the > basic rules are wrong and need fixing :( > Why do you need to rewrite anything? Why do you need to use it? Especially, why do you thing that PHP was made solely for auto-mappers from some SQL to PHP? $array_point = array('x' => 0.0, 'y' => 0.0); // valid type Point = shape('x' => float, 'y' => float); $point = shape('x' => 0.0, 'y' => 0.0); // valid function distance(array|Point $p1, array|Point $p2) { // works } function distance(Point $p1, Point $p2) { // works better } var_dump($point); // array(2) { // ["x"]=> // float(0.0) // ["y"]=> // float(0.0) // } Both works and both is valid. Only the latter case ensures that it is as defined and the former allows arbitrary changes. If you need arbitrary changes go for it. It does not matter why you want to use the former (anemic domain, legacy support, no time to adopt, no muse to adopt, "everything was better in the old days", ...) as long as it solves your use case and satisfies your users. All changes that were proposed are *without any BC!* If you are only afraid that usage of your libraries declines because users demand these new features to be part of it and you do not want to implement them. Sorry, but that would be a clear sign that the features are good and should be used. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] Re: Improving PHP's type system
On 4/17/2016 12:22 PM, Lin Yo-An wrote: > On Sun, Apr 17, 2016 at 6:06 AM, Bastian Schneider < > bastian.schnei...@commerce-plus.com> wrote: > >> Just a quick thought. >> >> >> union Iterable { >> use array; >> use ArrayAccess; >> use Traversable; >> } >> > > I think this example creates another meaning on the "use" syntax, which > make "use" context depended. > > The "use" statement is already used to "create an class name alias in the > current namespace." and this makes "use" confusing. > Especially since its not needed at all. HHVM already solved most of these issues extremely nicely: - https://docs.hhvm.com/hack/types/type-system - https://docs.hhvm.com/hack/type-aliases/introduction - https://docs.hhvm.com/hack/shapes/introduction We want the same but do not want to copy?!? -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] Re: Improving PHP's type system
On 4/17/2016 11:19 AM, Tony Marston wrote: > Where is the insult in what I wrote? > You are not only insulting people in this thread, you do it in every thread you contribute to. You were exhorted multiple times for doing so. Pretending otherwise does not change these facts so *please* get a grip. -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature
Re: [PHP-DEV] [RFC] Nullable Return Type Declaration
On 4/15/2016 5:50 PM, Larry Garfield wrote: > That there are a few small cases where PHP's current design makes NULL a > reasonable sentinel value (custom iterators, fread() as you mention, > etc.) does not mean that in most cases, returning ValueObject|Null is > rude and abusive to users of your API. Yes, end-of-file is not an > exceptional case so should not throw an exception. I completely agree > there. But "user not found" I'd argue is. (Or rather, if it's not an > exceptional case your data model is kinda broken to begin with, because > why are you asking for a missing user?) Or you're better off having an > "empty" value instead, such as an anonymous user object. That's still > type safe. > I disagree here. Your user example with the anonymous user object works if I am asking for e.g. the creation of a session but it is a very different situation if I would be asking for a user profile. The fact that a user might have deleted her account is not an exceptional case, is is to be expected and should be handled accordingly. How is up to the caller. Otherwise any `array_key_exists($k, $a)` should result in an exception or some default value according to your logic here. I completely agree that `NULL` is not the best type and others languages have other means to solve the issue but absolutely every language has some way to indicate the absence of a meaningful value. PHP has `NULL` like many others and that is fine. The problem is not that we have `NULL` the problem is that it is just too often not checked if it can be `NULL`. Rust and many functional language solve this with an Option or Maybe that requires creation, allocation, and userland checks for every return and the compilers fail if you do not unpack it. Ceylon solves this with union types as we are discussing it right now, however, the difference to other languages is that the compiler will fail if you are not checking the return value and bugs are avoided in this way. This is something that we could adopt. http://ceylon-lang.org/documentation/faq/language-design/#optional_types The absence of something must be modellable. class ConstraintViolation { private ?Throwable $cause; private string $message; public function __construct( string $message, ?Throwable $cause = null ) { $this->message = $message; $this->cause = $cause; } public function getCause(): ?Throwable { return $this->cause; } public function hasCause(): bool { return isset($this->cause); } // ... } An example of a class I was just working on. How could, would, or should one model this without `NULL`? Throwing an exception? It is not exceptional for such an object and expected that there is no cause available. It is up to the caller how she wants to take care of this. /** @var ConstraintViolation $violation */ if ($violation->hasCause()) { // Handle cause ... } $cause = $violation->getCause(); if (isset($cause)) { // Handle cause ... } // Or maybe we just want it stringified? // Works nicely with `NULL`. :) echo $violation->getCause(); Throwing exceptions everywhere for non exceptional cases is a code smell too and I see that ever to often in current open source code. Especially throwing extremely low-level exception everywhere for real errors from which one should not recover (e.g. `InvalidArgumentException`) because they indicate developer mistakes and only add a lot of checks in production for no reason. That being said, the above could be rewritten to. class ConstraintViolation { public function getCause(): Throwable {} public function hasCause(): bool {} } This would mean that PHP emits an Error if someone calls `getCause` and there is no cause and there would be only one way to check: `hasCause`. This is a valid design decision since it minimizes the amount of possibilities to work with the class and avoids `NULL` altogether. However, the caller code did not really become less verbose; as was already illustrated in the above examples. Plus, the ability to directly use the `__toString`ability paired with `NULL` in a string is gone. Everything always has pros and cons and I do not think that there is one answer to all of these questions. Different languages handle this problem differently. PHP has `NULL` and we should keep it this way. To minimize bugs resulting from unchecked `NULL` usage a compiler feature could be implemented that warns a developer in such cases. We already have it for uncatched exceptions (although IDEs are currently not telling one about that; Eclipse does in Java though). -- Richard "Fleshgrinder" Fussenegger signature.asc Description: OpenPGP digital signature