[PHP-DEV] [RFC] Simple Annotations

2016-05-13 Thread Rasmus Schultz
Dear Internals,

I'm announcing a simplified RFC for annotations:

https://wiki.php.net/rfc/simple-annotations

It's an alternative to the proposed Attributes RFC and the (2010)
Annotations RFC.

I'm attempting with this to describe a feature that is closer to the
language than what is proposed by the Attributes RFC, by permitting
the use of any valid PHP expression as an annotation value.

Where the Attributes RFC proposes new syntax for what is essentially
arrays, this proposal instead permits you to use actual arrays, e.g.
without inventing any new syntax. It also allows you to use values of
any other type, including objects. This makes the proposed feature
more immediately useful, with a minimal learning curve.

Compared with the old Annotations RFC (and Doctrine Annotations, etc.)
this proposal does not attempt to define or enforce any rules about
what annotations are, permitted usage, inheritance rules, etc. -
instead it adds a very simple language feature upon which the
community may choose to build (and evolve) facilities that implement
additional rules and logic.

My hope is that, if we can agree on something very small and simple,
we can defer the more opinionated discussions about rules and logic to
the community.

In my opinion, language features should be simple, and consistent with
the language - I believe the way to do that, is to avoid discussions
about how such as facility should be used, and instead focus on how it
should work. There is a lot of opinion built into the old Annotations
RFC, and into Doctrine - features that attempt to dictate how the
feature should be used. I don't believe the language should dictate
what is or isn't correct or appropriate use.

Please review and comment.

Thanks,
  Rasmus Schultz

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Simple Annotations

2016-05-13 Thread Davey Shafik
On Fri, May 13, 2016 at 2:11 PM, Rasmus Schultz  wrote:

> Dear Internals,
>
> I'm announcing a simplified RFC for annotations:
>
> https://wiki.php.net/rfc/simple-annotations
>
> It's an alternative to the proposed Attributes RFC and the (2010)
> Annotations RFC.
>
> I'm attempting with this to describe a feature that is closer to the
> language than what is proposed by the Attributes RFC, by permitting
> the use of any valid PHP expression as an annotation value.
>
> Where the Attributes RFC proposes new syntax for what is essentially
> arrays, this proposal instead permits you to use actual arrays, e.g.
> without inventing any new syntax. It also allows you to use values of
> any other type, including objects. This makes the proposed feature
> more immediately useful, with a minimal learning curve.
>
> Compared with the old Annotations RFC (and Doctrine Annotations, etc.)
> this proposal does not attempt to define or enforce any rules about
> what annotations are, permitted usage, inheritance rules, etc. -
> instead it adds a very simple language feature upon which the
> community may choose to build (and evolve) facilities that implement
> additional rules and logic.
>
> My hope is that, if we can agree on something very small and simple,
> we can defer the more opinionated discussions about rules and logic to
> the community.
>
> In my opinion, language features should be simple, and consistent with
> the language - I believe the way to do that, is to avoid discussions
> about how such as facility should be used, and instead focus on how it
> should work. There is a lot of opinion built into the old Annotations
> RFC, and into Doctrine - features that attempt to dictate how the
> feature should be used. I don't believe the language should dictate
> what is or isn't correct or appropriate use.


I think I like this, however a couple of simple questions:

1) Any chance for (optionally) _naming_ annotations? It would be nice to be
able to do: ->getAnnotation('table') and not have to handle unnecessary
annotations

2) I like the idea of Hacks memoize for example, how do you see those being
implemented? Or don't you?

3) When are annotations executed? On ->getAnnotations()? Every time?

Thanks,


Re: [PHP-DEV] [RFC] Simple Annotations

2016-05-13 Thread Mathieu Rochette


On 05/13/2016 02:57 PM, Davey Shafik wrote:
> On Fri, May 13, 2016 at 2:11 PM, Rasmus Schultz  wrote:
>
>> Dear Internals,
>>
>> I'm announcing a simplified RFC for annotations:
>>
>> https://wiki.php.net/rfc/simple-annotations
>>
>> It's an alternative to the proposed Attributes RFC and the (2010)
>> Annotations RFC.
>>
>> I'm attempting with this to describe a feature that is closer to the
>> language than what is proposed by the Attributes RFC, by permitting
>> the use of any valid PHP expression as an annotation value.
>>
>> Where the Attributes RFC proposes new syntax for what is essentially
>> arrays, this proposal instead permits you to use actual arrays, e.g.
>> without inventing any new syntax. It also allows you to use values of
>> any other type, including objects. This makes the proposed feature
>> more immediately useful, with a minimal learning curve.
>>
>> Compared with the old Annotations RFC (and Doctrine Annotations, etc.)
>> this proposal does not attempt to define or enforce any rules about
>> what annotations are, permitted usage, inheritance rules, etc. -
>> instead it adds a very simple language feature upon which the
>> community may choose to build (and evolve) facilities that implement
>> additional rules and logic.
>>
>> My hope is that, if we can agree on something very small and simple,
>> we can defer the more opinionated discussions about rules and logic to
>> the community.
>>
>> In my opinion, language features should be simple, and consistent with
>> the language - I believe the way to do that, is to avoid discussions
>> about how such as facility should be used, and instead focus on how it
>> should work. There is a lot of opinion built into the old Annotations
>> RFC, and into Doctrine - features that attempt to dictate how the
>> feature should be used. I don't believe the language should dictate
>> what is or isn't correct or appropriate use.
>
> I think I like this, however a couple of simple questions:
>
> 1) Any chance for (optionally) _naming_ annotations? It would be nice to be
> able to do: ->getAnnotation('table') and not have to handle unnecessary
> annotations
not sure you need that, you can do this instead:
->getAnnotations(Table::class)
however it won't throw an error if you have more than one "Table::class
annotation" whereas I supposed you would expect so with a named annotation
>
> 2) I like the idea of Hacks memoize for example, how do you see those being
> implemented? Or don't you?
if Rasmus goal is to that "we can agree on something very small and
simple" I guess it would best be left for another rfc
>
> 3) When are annotations executed? On ->getAnnotations()? Every time?
given they are context free, I suppose they would be executed on the
first call only

but what about this kind of annotation classes? :

class Counter {
  private static $i = 0;
  private $n;
  function __construct() {
$this->n = self::$i++;
  }
  function get() { return $this->n; }
}

both the getAnnotations() calls order and whether or not annotations are
executed every time would make a difference

>
> Thanks,
>

-- 
Mathieu Rochette



Re: [PHP-DEV] [RFC] Simple Annotations

2016-05-13 Thread Marco Pivetta
Love the simplicity of the RFC, but I can already see people doing terrible
things with it:

 << new DateTimeImmutable() >>
<< log(get_instance('logger')) >>

And other global-state related stuff.

TBH, I'd rather just allow a constant array (with constant expressions
only), and that would be good enough :-)

Cheers,


Marco Pivetta

http://twitter.com/Ocramius

http://ocramius.github.com/

On 13 May 2016 at 15:15, Mathieu Rochette  wrote:

>
>
> On 05/13/2016 02:57 PM, Davey Shafik wrote:
> > On Fri, May 13, 2016 at 2:11 PM, Rasmus Schultz 
> wrote:
> >
> >> Dear Internals,
> >>
> >> I'm announcing a simplified RFC for annotations:
> >>
> >> https://wiki.php.net/rfc/simple-annotations
> >>
> >> It's an alternative to the proposed Attributes RFC and the (2010)
> >> Annotations RFC.
> >>
> >> I'm attempting with this to describe a feature that is closer to the
> >> language than what is proposed by the Attributes RFC, by permitting
> >> the use of any valid PHP expression as an annotation value.
> >>
> >> Where the Attributes RFC proposes new syntax for what is essentially
> >> arrays, this proposal instead permits you to use actual arrays, e.g.
> >> without inventing any new syntax. It also allows you to use values of
> >> any other type, including objects. This makes the proposed feature
> >> more immediately useful, with a minimal learning curve.
> >>
> >> Compared with the old Annotations RFC (and Doctrine Annotations, etc.)
> >> this proposal does not attempt to define or enforce any rules about
> >> what annotations are, permitted usage, inheritance rules, etc. -
> >> instead it adds a very simple language feature upon which the
> >> community may choose to build (and evolve) facilities that implement
> >> additional rules and logic.
> >>
> >> My hope is that, if we can agree on something very small and simple,
> >> we can defer the more opinionated discussions about rules and logic to
> >> the community.
> >>
> >> In my opinion, language features should be simple, and consistent with
> >> the language - I believe the way to do that, is to avoid discussions
> >> about how such as facility should be used, and instead focus on how it
> >> should work. There is a lot of opinion built into the old Annotations
> >> RFC, and into Doctrine - features that attempt to dictate how the
> >> feature should be used. I don't believe the language should dictate
> >> what is or isn't correct or appropriate use.
> >
> > I think I like this, however a couple of simple questions:
> >
> > 1) Any chance for (optionally) _naming_ annotations? It would be nice to
> be
> > able to do: ->getAnnotation('table') and not have to handle unnecessary
> > annotations
> not sure you need that, you can do this instead:
> ->getAnnotations(Table::class)
> however it won't throw an error if you have more than one "Table::class
> annotation" whereas I supposed you would expect so with a named annotation
> >
> > 2) I like the idea of Hacks memoize for example, how do you see those
> being
> > implemented? Or don't you?
> if Rasmus goal is to that "we can agree on something very small and
> simple" I guess it would best be left for another rfc
> >
> > 3) When are annotations executed? On ->getAnnotations()? Every time?
> given they are context free, I suppose they would be executed on the
> first call only
>
> but what about this kind of annotation classes? :
>
> class Counter {
>   private static $i = 0;
>   private $n;
>   function __construct() {
> $this->n = self::$i++;
>   }
>   function get() { return $this->n; }
> }
>
> both the getAnnotations() calls order and whether or not annotations are
> executed every time would make a difference
>
> >
> > Thanks,
> >
>
> --
> Mathieu Rochette
>
>


Re: [PHP-DEV] [RFC] Simple Annotations

2016-05-13 Thread Benjamin Eberlei
On Fri, May 13, 2016 at 2:11 PM, Rasmus Schultz  wrote:

> Dear Internals,
>
> I'm announcing a simplified RFC for annotations:
>
> https://wiki.php.net/rfc/simple-annotations
>
> It's an alternative to the proposed Attributes RFC and the (2010)
> Annotations RFC.
>
> I'm attempting with this to describe a feature that is closer to the
> language than what is proposed by the Attributes RFC, by permitting
> the use of any valid PHP expression as an annotation value.
>
> Where the Attributes RFC proposes new syntax for what is essentially
> arrays, this proposal instead permits you to use actual arrays, e.g.
> without inventing any new syntax. It also allows you to use values of
> any other type, including objects. This makes the proposed feature
> more immediately useful, with a minimal learning curve.
>

The attributes RFC actually does not specific syntax or arrays, but either
a scalar (number, string) or an ast\node.

A proposal for arrays *would* actually be "closer to the language" as you
describe it.

Compared with the old Annotations RFC (and Doctrine Annotations, etc.)
> this proposal does not attempt to define or enforce any rules about
> what annotations are, permitted usage, inheritance rules, etc. -
> instead it adds a very simple language feature upon which the
> community may choose to build (and evolve) facilities that implement
> additional rules and logic.
>
> My hope is that, if we can agree on something very small and simple,
> we can defer the more opinionated discussions about rules and logic to
> the community.
>
> In my opinion, language features should be simple, and consistent with
> the language - I believe the way to do that, is to avoid discussions
> about how such as facility should be used, and instead focus on how it
> should work. There is a lot of opinion built into the old Annotations
> RFC, and into Doctrine - features that attempt to dictate how the
> feature should be used. I don't believe the language should dictate
> what is or isn't correct or appropriate use.
>
> Please review and comment.


I see you took my question about context from the other thread and defined
annotations to be context less.
You should add to the RFC examples of what is happening, if you do access
context, for example access to undefined variable notices:

<<$x>>
class Foo {}

$refl = new ReflectionClass('Foo');
var_dump($refl->getAttributes(Foo::class));
// PHP Notice:  Undefined variable: x in Command line code on line 1

Still this is imho a weak point of your RFC. You already stated that a
"simplified annotation" the way you see it is the expression wrapped in a
closure:

function () {
return php-expression;
}

So if an annotation is a function/closure that belongs to its target
(class, property, function, method, ...) then why wouldn't there be a way
to specify arguments?
The RFC should give an answer to that. The statement you add doesn't make
sense without examples. How does dependency injection even work, when you
don't have a context?

"Annotations that do require context should explicitly ask for that context
- for example, you could use an anonymous function, a callable, or an
anonymous class, to provide context via dependency injection."

greetings
Benjamin


> Thanks,
>   Rasmus Schultz
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: http://www.php.net/unsub.php
>
>


Re: [PHP-DEV] [RFC] Simple Annotations

2016-05-14 Thread Rasmus Schultz
Thank you for your comments!

Benjamin,

I have removed the comment about annotation expressions executing in
an empty closure, since this example was clearly confusing, and I have
tried to clarify the fact that annotation expressions execute in an
empty scope. To be clear, annotation expressions are *not* closures,
and they do not accept arguments - there is no reason to complicate
the concept of annotations by introducing an implied scope, when you
can introduce one explicitly, for example:

class Validation {
private $validate;

public function __construct(callable $validate) {
$this->validate = $validate;
}

public function validate($instance) {
return call_user_func($this->validate, $instance);
}
}

<< new Validation(function (User $user) { return false !==
filter_var($user->email, FILTER_VALIDATE_EMAIL); }) >>
class User {
public $email;
}

Of course, you could just as well do this with an interface - as it
the case with most examples I can think of.

If you can think of a meaningful annotation that actually requires
context and can't be implemented in a better/safer/cleaner way with
abstraction, please post? I'd like to add an example, but really have
never seen one that can't be solved better without annotations.

Marco,

> Love the simplicity of the RFC, but I can already see people doing terrible 
> things with it

Every language lets you do terrible and great things - I don't believe
in putting up roadblocks and complicating the language that prevent
people from learning.

> TBH, I'd rather just allow a constant array (with constant expressions only), 
> and that would be good enough :-)

I don't agree with the idea of crippling a language feature to prevent
beginners from making mistakes - when doing so would also prevent
static analysis and block experienced developers from doing useful
things with objects.

Davey and Mathieu,

Annotations can be "named" by using classes. Per the RFC, defining or
enforcing a rule about allowing only one instance of the same type, is
not a feature.

Hack's memoize is an annotation for the language interpreter itself -
that's beyond the scope of this RFC, but could be implemented in the
future.

Your third question is answered by the RFC here:

> Annotation expressions are not evaluated until reflection is invoked, and are 
> evaluated only once and internally memoized upon the first call to 
> getAnnotations().

Thank you for your input so far!

The RFC is 0.2 with the last updates based on your feedback - I would
like to add a suitable case example for annotations that require
context before I'd say this RFC is 1.0.

If anyone can point at a real case example using Doctrine Annotations
(or anything else) please do!

Thanks,
  Rasmus


On Sat, May 14, 2016 at 4:38 AM, Benjamin Eberlei  wrote:
>
>
> On Fri, May 13, 2016 at 2:11 PM, Rasmus Schultz  wrote:
>>
>> Dear Internals,
>>
>> I'm announcing a simplified RFC for annotations:
>>
>> https://wiki.php.net/rfc/simple-annotations
>>
>> It's an alternative to the proposed Attributes RFC and the (2010)
>> Annotations RFC.
>>
>> I'm attempting with this to describe a feature that is closer to the
>> language than what is proposed by the Attributes RFC, by permitting
>> the use of any valid PHP expression as an annotation value.
>>
>> Where the Attributes RFC proposes new syntax for what is essentially
>> arrays, this proposal instead permits you to use actual arrays, e.g.
>> without inventing any new syntax. It also allows you to use values of
>> any other type, including objects. This makes the proposed feature
>> more immediately useful, with a minimal learning curve.
>
>
> The attributes RFC actually does not specific syntax or arrays, but either a
> scalar (number, string) or an ast\node.
>
> A proposal for arrays *would* actually be "closer to the language" as you
> describe it.
>
>> Compared with the old Annotations RFC (and Doctrine Annotations, etc.)
>> this proposal does not attempt to define or enforce any rules about
>> what annotations are, permitted usage, inheritance rules, etc. -
>> instead it adds a very simple language feature upon which the
>> community may choose to build (and evolve) facilities that implement
>> additional rules and logic.
>>
>> My hope is that, if we can agree on something very small and simple,
>> we can defer the more opinionated discussions about rules and logic to
>> the community.
>>
>> In my opinion, language features should be simple, and consistent with
>> the language - I believe the way to do that, is to avoid discussions
>> about how such as facility should be used, and instead focus on how it
>> should work. There is a lot of opinion built into the old Annotations
>> RFC, and into Doctrine - features that attempt to dictate how the
>> feature should be used. I don't believe the language should dictate
>> what is or isn't correct or appropriate use.
>>
>> Please review and comment.
>
>
> I see you took my question about context 

Re: [PHP-DEV] [RFC] Simple Annotations

2016-05-14 Thread Dan Ackroyd
On 14 May 2016 at 12:48, Rasmus Schultz  wrote:
>
> Hack's memoize is an annotation for the language interpreter itself -
> that's beyond the scope of this RFC, but could be implemented in the
> future.

Please can you add something to the RFC that reserves the possibility
to do this, so that it can be introduced in a BC compatible way in the
future?

Hand-waving away problems and saying that they aren't in scope is a
sure-fire way to build deficiencies into a design.

This is not a smaller problem in userland code, as it is easy for
people to migrate from one library to another, but is almost
impossible to overcome in core PHP, where any BC-breaking change
causes lots of difficultly for end-users.

cheers
Dan

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Simple Annotations

2016-05-14 Thread Benjamin Eberlei
On Sat, May 14, 2016 at 1:48 PM, Rasmus Schultz  wrote:

> Thank you for your comments!
>
> Benjamin,
>
> I have removed the comment about annotation expressions executing in
> an empty closure, since this example was clearly confusing, and I have
> tried to clarify the fact that annotation expressions execute in an
> empty scope. To be clear, annotation expressions are *not* closures,
> and they do not accept arguments - there is no reason to complicate
> the concept of annotations by introducing an implied scope, when you
> can introduce one explicitly, for example:
>
> class Validation {
> private $validate;
>
> public function __construct(callable $validate) {
> $this->validate = $validate;
> }
>
> public function validate($instance) {
> return call_user_func($this->validate, $instance);
> }
> }
>
> << new Validation(function (User $user) { return false !==
> filter_var($user->email, FILTER_VALIDATE_EMAIL); }) >>
> class User {
> public $email;
> }
>
> Of course, you could just as well do this with an interface - as it
> the case with most examples I can think of.
>
> If you can think of a meaningful annotation that actually requires
> context and can't be implemented in a better/safer/cleaner way with
> abstraction, please post? I'd like to add an example, but really have
> never seen one that can't be solved better without annotations.
>

Every proposal before was about annotation/attributes as metadata for code.
Your proposal makes them executable functions instead (nameless, attached
to code blocks).

I think this is just way out of scope of what the 80% want to achieve with
this feature.

>
> Marco,
>
> > Love the simplicity of the RFC, but I can already see people doing
> terrible things with it
>
> Every language lets you do terrible and great things - I don't believe
> in putting up roadblocks and complicating the language that prevent
> people from learning.
>
> > TBH, I'd rather just allow a constant array (with constant expressions
> only), and that would be good enough :-)
>
> I don't agree with the idea of crippling a language feature to prevent
> beginners from making mistakes - when doing so would also prevent
> static analysis and block experienced developers from doing useful
> things with objects.
>
> Davey and Mathieu,
>
> Annotations can be "named" by using classes. Per the RFC, defining or
> enforcing a rule about allowing only one instance of the same type, is
> not a feature.
>
> Hack's memoize is an annotation for the language interpreter itself -
> that's beyond the scope of this RFC, but could be implemented in the
> future.
>
> Your third question is answered by the RFC here:
>
> > Annotation expressions are not evaluated until reflection is invoked,
> and are evaluated only once and internally memoized upon the first call to
> getAnnotations().
>
> Thank you for your input so far!
>
> The RFC is 0.2 with the last updates based on your feedback - I would
> like to add a suitable case example for annotations that require
> context before I'd say this RFC is 1.0.
>
> If anyone can point at a real case example using Doctrine Annotations
> (or anything else) please do!
>
> Thanks,
>   Rasmus
>
>
> On Sat, May 14, 2016 at 4:38 AM, Benjamin Eberlei 
> wrote:
> >
> >
> > On Fri, May 13, 2016 at 2:11 PM, Rasmus Schultz 
> wrote:
> >>
> >> Dear Internals,
> >>
> >> I'm announcing a simplified RFC for annotations:
> >>
> >> https://wiki.php.net/rfc/simple-annotations
> >>
> >> It's an alternative to the proposed Attributes RFC and the (2010)
> >> Annotations RFC.
> >>
> >> I'm attempting with this to describe a feature that is closer to the
> >> language than what is proposed by the Attributes RFC, by permitting
> >> the use of any valid PHP expression as an annotation value.
> >>
> >> Where the Attributes RFC proposes new syntax for what is essentially
> >> arrays, this proposal instead permits you to use actual arrays, e.g.
> >> without inventing any new syntax. It also allows you to use values of
> >> any other type, including objects. This makes the proposed feature
> >> more immediately useful, with a minimal learning curve.
> >
> >
> > The attributes RFC actually does not specific syntax or arrays, but
> either a
> > scalar (number, string) or an ast\node.
> >
> > A proposal for arrays *would* actually be "closer to the language" as you
> > describe it.
> >
> >> Compared with the old Annotations RFC (and Doctrine Annotations, etc.)
> >> this proposal does not attempt to define or enforce any rules about
> >> what annotations are, permitted usage, inheritance rules, etc. -
> >> instead it adds a very simple language feature upon which the
> >> community may choose to build (and evolve) facilities that implement
> >> additional rules and logic.
> >>
> >> My hope is that, if we can agree on something very small and simple,
> >> we can defer the more opinionated discussions about rules and logic to
> >> the community.
> >>
> >> In my opinion, l

Re: [PHP-DEV] [RFC] Simple Annotations

2016-05-14 Thread Rasmus Schultz
Dan,

I've added a note about special annotations to the "future scope"
section, naming the memoization-annotation as an example.

Benjamin,

I don't think you mean "out of scope" of what 80% want, I think you
mean "beyond the scope"?

I think this will definitely cover what 80% want to achieve, and
possibly a lot more - possibly new and useful patterns that we can't
even predict.


On Sat, May 14, 2016 at 3:41 PM, Benjamin Eberlei  wrote:
>
>
> On Sat, May 14, 2016 at 1:48 PM, Rasmus Schultz  wrote:
>>
>> Thank you for your comments!
>>
>> Benjamin,
>>
>> I have removed the comment about annotation expressions executing in
>> an empty closure, since this example was clearly confusing, and I have
>> tried to clarify the fact that annotation expressions execute in an
>> empty scope. To be clear, annotation expressions are *not* closures,
>> and they do not accept arguments - there is no reason to complicate
>> the concept of annotations by introducing an implied scope, when you
>> can introduce one explicitly, for example:
>>
>> class Validation {
>> private $validate;
>>
>> public function __construct(callable $validate) {
>> $this->validate = $validate;
>> }
>>
>> public function validate($instance) {
>> return call_user_func($this->validate, $instance);
>> }
>> }
>>
>> << new Validation(function (User $user) { return false !==
>> filter_var($user->email, FILTER_VALIDATE_EMAIL); }) >>
>> class User {
>> public $email;
>> }
>>
>> Of course, you could just as well do this with an interface - as it
>> the case with most examples I can think of.
>>
>> If you can think of a meaningful annotation that actually requires
>> context and can't be implemented in a better/safer/cleaner way with
>> abstraction, please post? I'd like to add an example, but really have
>> never seen one that can't be solved better without annotations.
>
>
> Every proposal before was about annotation/attributes as metadata for code.
> Your proposal makes them executable functions instead (nameless, attached to
> code blocks).
>
> I think this is just way out of scope of what the 80% want to achieve with
> this feature.
>>
>>
>> Marco,
>>
>> > Love the simplicity of the RFC, but I can already see people doing
>> > terrible things with it
>>
>> Every language lets you do terrible and great things - I don't believe
>> in putting up roadblocks and complicating the language that prevent
>> people from learning.
>>
>> > TBH, I'd rather just allow a constant array (with constant expressions
>> > only), and that would be good enough :-)
>>
>> I don't agree with the idea of crippling a language feature to prevent
>> beginners from making mistakes - when doing so would also prevent
>> static analysis and block experienced developers from doing useful
>> things with objects.
>>
>> Davey and Mathieu,
>>
>> Annotations can be "named" by using classes. Per the RFC, defining or
>> enforcing a rule about allowing only one instance of the same type, is
>> not a feature.
>>
>> Hack's memoize is an annotation for the language interpreter itself -
>> that's beyond the scope of this RFC, but could be implemented in the
>> future.
>>
>> Your third question is answered by the RFC here:
>>
>> > Annotation expressions are not evaluated until reflection is invoked,
>> > and are evaluated only once and internally memoized upon the first call to
>> > getAnnotations().
>>
>> Thank you for your input so far!
>>
>> The RFC is 0.2 with the last updates based on your feedback - I would
>> like to add a suitable case example for annotations that require
>> context before I'd say this RFC is 1.0.
>>
>> If anyone can point at a real case example using Doctrine Annotations
>> (or anything else) please do!
>>
>> Thanks,
>>   Rasmus
>>
>>
>> On Sat, May 14, 2016 at 4:38 AM, Benjamin Eberlei 
>> wrote:
>> >
>> >
>> > On Fri, May 13, 2016 at 2:11 PM, Rasmus Schultz 
>> > wrote:
>> >>
>> >> Dear Internals,
>> >>
>> >> I'm announcing a simplified RFC for annotations:
>> >>
>> >> https://wiki.php.net/rfc/simple-annotations
>> >>
>> >> It's an alternative to the proposed Attributes RFC and the (2010)
>> >> Annotations RFC.
>> >>
>> >> I'm attempting with this to describe a feature that is closer to the
>> >> language than what is proposed by the Attributes RFC, by permitting
>> >> the use of any valid PHP expression as an annotation value.
>> >>
>> >> Where the Attributes RFC proposes new syntax for what is essentially
>> >> arrays, this proposal instead permits you to use actual arrays, e.g.
>> >> without inventing any new syntax. It also allows you to use values of
>> >> any other type, including objects. This makes the proposed feature
>> >> more immediately useful, with a minimal learning curve.
>> >
>> >
>> > The attributes RFC actually does not specific syntax or arrays, but
>> > either a
>> > scalar (number, string) or an ast\node.
>> >
>> > A proposal for arrays *would* actually be "closer to the language" as
>> > you
>> > describe it

Re: [PHP-DEV] [RFC] Simple Annotations

2016-05-16 Thread Rowan Collins

On 14/05/2016 20:49, Rasmus Schultz wrote:

Dan,

I've added a note about special annotations to the "future scope"
section, naming the memoization-annotation as an example.


This doesn't really explain how such a feature would fit it into the 
proposal. For instance, how can we avoid the syntax clashing with 
existing userland issues? Given that annotations in this proposal don't 
have names, we can't just reserve all names beginning "__" or "php\".


Perhaps they would be pseudo-function calls, like <<__memoize()>>? How 
would that (or any other undefined function) act if accessed on a 
version that didn't have the feature?


I realise you don't want to define the details, but an idea of what an 
annotation targeting the engine would look like would make the 
future-proofing clearer.


Regards,
--
Rowan Collins
[IMSoP]



--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Simple Annotations

2016-05-16 Thread Fleshgrinder
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] Simple Annotations

2016-05-16 Thread Fleshgrinder
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

2016-05-16 Thread Rasmus Schultz
Rowan,

I'm afraid I don't follow. Why is it a problem to simply add a
function or class to the global namespace?

<< new Memoize() >>

or maybe a class with factory functions for built-in annotations:

<< Meta::memoize() >>

I tend to agree with Richard though, that system directives really
ought to be supported by the language with keywords rather than
annotations.

Richard,

Regarding your point of view:

> The problem is that an annotation by definition is just meta-data. Your
> proposal however might result in fatal errors from meta-data

I agree that annotations are just meta-data. Values.

I disagree that we can't permit the use of PHP expressions to generate
those values.

You can't eliminate problems such as missing classes - and you
shouldn't. With the examples in the Attributes RFC, as well as with
e.g. Doctrine Annotations, we have the exact same problems, they're
just one step removed from the language feature, which only adds
complexity and makes it harder to debug these things.

The only work-around to an issue such as a missing class, is to
complete ignore the annotation - which leads to undefined behavior and
scenarios that are even harder to debug.

The other big problem with this position, is that it goes more or less
directly against what the community wants - the majority of those who
use annotations in PHP today, use Doctrine Annotations, and they
expect annotations as classes.

Source code can contain errors. I don't think there's really any way
around that. Even if you wittled down metadata to the absolute minimum
- a string, such as what it is in Go code, that string is invariably
going to contain something that needs to be parsed or interpreted
somehow, somewhere, at some point, and it can lead to errors.

In my opinion, it's better to allow those errors to be caught early -
for example, being able to catch syntax errors in expressions already
at load-time. The attributes RFC is much worse in this regard - you
could be lugging around all kinds of dependency errors, missing
classes and whatnot, and you'd never know about it until the day you
hit one of those annotations. Now instead, you're just stuck having to
type out redundant unit-tests to prove that every annotation is valid,
when the language could have taken care of that in a much simpler way.

The other issue is dependencies. The Attributes RFC will lead to code
with all sorts of hidden dependencies - possibly dependencies that you
can't even know about, because you can't know how your metadata is
going to be interpreted precisely. You can't know which classes your
metadata might get mapped to or how. Simple Annotations take care of
that, and they force you to e.g. `composer require` the package that
provides the annotation classes you're using - this is a good thing.

Hiding dependencies makes it really difficult for others to reason
about your code. The Attributes RFC will lead to a lot of hidden rules
- whereas Simple Annotations are simple and straight-forward, nothing
hidden or implicit, your dependencies visible and traceable, which
will lead to much better tooling. For example, an IDE or offline code
analysis tool would catch syntax errors and missing classes and warn
about those right away.

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.


On Mon, May 16, 2016 at 11:16 AM, Rowan Collins  wrote:
> On 14/05/2016 20:49, Rasmus Schultz wrote:
>>
>> Dan,
>>
>> I've added a note about special annotations to the "future scope"
>> section, naming the memoization-annotation as an example.
>
>
> This doesn't really explain how such a feature would fit it into the
> proposal. For instance, how can we avoid the syntax clashing with existing
> userland issues? Given that annotations in this proposal don't have names,
> we can't just reserve all names beginning "__" or "php\".
>
> Perhaps they would be pseudo-function calls, like <<__memoize()>>? How would
> that (or any other undefined function) act if accessed on a version that
> didn't have the feature?
>
> I realise you don't want to define the details, but an idea of what an
> annotation targeting the engine would look like would make the
> future-proofing clearer.
>
> Regards,
> --
> Rowan Collins
> [IMSoP]
>
>
>
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: http://www.php.net/unsub.php
>

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Simple Annotations

2016-05-16 Thread Rowan Collins
On 16/05/2016 14:05, Rasmus Schultz wrote:
> I'm afraid I don't follow. Why is it a problem to simply add a
> function or class to the global namespace?
>
> << new Memoize() >>
>
> or maybe a class with factory functions for built-in annotations:
>
> << Meta::memoize() >>

Well, those particular names look quite likely to collide with users' code, 
though I guess more obviously reserved names could be used.

More generally, though, neither feels a natural fit, because of the need to 
specify a value, rather than a name. On Reflection, what would an instance of 
class Memoize look like? Could you call "new Memoize" somewhere else?

If a memoize() function was executed, what value would it return? Since you can 
only see the evaluated value, how could you detect the annotation for debugging?

Indeed, if we're interested only in values, not where they come from, are the 
following all equivalent, and the mechanics totally unndetectable by Reflection?

<>

<<(function(){return null;})()>>

function foo() { return null; }
<< foo() >>

If the function form doesn't receive any context, its only purpose would be to 
copy some runtime global state into the annotation value on first access, which 
seems like a strange thing to do. 


> I tend to agree with Richard though, that system directives really
> ought to be supported by the language with keywords rather than
> annotations.

That would be one way around it, indeed, so rather than "Future Scope", 
you could label "compiler directive" type annotations as "deliberately 
out of scope".

Regards,
-- 
Rowan Collins
[IMSoP]

Re: [PHP-DEV] [RFC] Simple Annotations

2016-05-16 Thread Fleshgrinder
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

2016-05-17 Thread Rasmus Schultz
Richard,

I believe I have already stated my position on all of these concerns
in my last email.

Short recap:

There's no such thing as optional dependencies - if you depend on a
Doctrine ORM annotation, you depend on that package.

The code should (must) error the moment you try to instantiate those
annotations - whether you intend to use them or not is besides the
question - a missing class is an error, in annotations as it is
anywhere else in your code.

Silently ignoring missing annotations solves nothing - it just leads
to errors that are even harder to find and debug.

You seem awfully concerned about name collisions? Most packages use a
vendor\package namespace convention now - PHP has always been adding
things to the global namespace, and it's never been a really
substantial problem. I'm not that concerned.

The one new thing you brought up here, is the issue of potentially
loading/instantiating a bunch of annotations that go unused. From a
dependency point of view, I maintain that that's correct and it should
error out on missing classes.

>From a performance point of view, you may have a valid concern, and
this had occurred to me before - but I decided to leave it alone, for
a couple of reasons. The most important reason being, look at how
annotations get used in practice: controllers get things like route
and filter annotations, all of which are usually needed at the same
time; entities get ORM annotations, all of which are usually needed at
the same time; form models get validation and input-type annotations,
all of which are usually needed at the same time. And so on.

The fact of the matter is that classes tend to have a single
responsibility, and this usually means that applicable annotations
tend to belong to a specific domain, and are needed at the same time.

In other words, this problem is pretty theoretical - in reality, it's
a very small problem, which, if somebody was very concerned about,
could absolutely be solved in userland, by adding a cache layer. Which
projects like Doctrine Annotations would likely do anyway, in order to
cache the result of mode complex annotation logic to control
inheritance, cardinality, applicability, etc. - all the complex stuff
that this RFC stays away from.

The extreme case of what you're proposing, is what Go does - an
annotation is simply a string. No chance of any error, anywhere, ever,
right? Wrong. People put JSON data in those strings for example, and
parsing that data leads to run-time errors instead. That's the extreme
example, but the problem with what you're proposing is precisely the
same: you allow something like nested array data structures, those are
still going to get interpreted and mapped to objects at run-time, and
it leads to run-time errors instead.

I maintain that the majority use-case is object annotations - and that
deferring the construction of those objects doesn't solve anything.

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 and will always be in favor of language design that takes the
most direct route to satisfy a requirement. In this case, the
requirement is annotations as objects - and the most natural and
direct route is the "new" keyword, static method calls, or whatever
way you normally create objects; inventing a more indirect way to do
that just adds complexity.


On Mon, May 16, 2016 at 8:39 PM, Fleshgrinder  wrote:
> 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.

Re: [PHP-DEV] [RFC] Simple Annotations

2016-05-17 Thread Rasmus Schultz
I'd like to finish this RFC, but I have two remaining issues.

The syntax is a minor issue - since any valid PHP expression can be
used, the bit-shift ambiguity is technically an issue, however
marginal.

A lot of people commented on the syntax when I posted the RFC on
reddit - they don't like it.

Anyone have any ideas for an alternative syntax? It needs to be
delimited, e.g. needs to use opening and closing delimiters or a
recognizable opening delimiter... Here's some ideas:

@{ new Table("user") }

@[ new Table("user") ]

{{ new Table("user") }}

+{ new Table("user") }

I don't like any of these really, but the bit-shift operator isn't
going when the stuff inside is an expression which could include
bit-shift (is it?)

The other issue is the dependency (context) injection example - no one
seems to be able to cite an actual use-case, and if that's the case, I
should probably just remove it from the RFC entirely?

@Larry can you think of a case example in the myriad annotations
you've seen in Drupal code? :-)

Anyone else using Doctrine Annotations actually seen anyone making use
of a closure in an annotation?


On Tue, May 17, 2016 at 11:06 AM, Rasmus Schultz  wrote:
> Richard,
>
> I believe I have already stated my position on all of these concerns
> in my last email.
>
> Short recap:
>
> There's no such thing as optional dependencies - if you depend on a
> Doctrine ORM annotation, you depend on that package.
>
> The code should (must) error the moment you try to instantiate those
> annotations - whether you intend to use them or not is besides the
> question - a missing class is an error, in annotations as it is
> anywhere else in your code.
>
> Silently ignoring missing annotations solves nothing - it just leads
> to errors that are even harder to find and debug.
>
> You seem awfully concerned about name collisions? Most packages use a
> vendor\package namespace convention now - PHP has always been adding
> things to the global namespace, and it's never been a really
> substantial problem. I'm not that concerned.
>
> The one new thing you brought up here, is the issue of potentially
> loading/instantiating a bunch of annotations that go unused. From a
> dependency point of view, I maintain that that's correct and it should
> error out on missing classes.
>
> From a performance point of view, you may have a valid concern, and
> this had occurred to me before - but I decided to leave it alone, for
> a couple of reasons. The most important reason being, look at how
> annotations get used in practice: controllers get things like route
> and filter annotations, all of which are usually needed at the same
> time; entities get ORM annotations, all of which are usually needed at
> the same time; form models get validation and input-type annotations,
> all of which are usually needed at the same time. And so on.
>
> The fact of the matter is that classes tend to have a single
> responsibility, and this usually means that applicable annotations
> tend to belong to a specific domain, and are needed at the same time.
>
> In other words, this problem is pretty theoretical - in reality, it's
> a very small problem, which, if somebody was very concerned about,
> could absolutely be solved in userland, by adding a cache layer. Which
> projects like Doctrine Annotations would likely do anyway, in order to
> cache the result of mode complex annotation logic to control
> inheritance, cardinality, applicability, etc. - all the complex stuff
> that this RFC stays away from.
>
> The extreme case of what you're proposing, is what Go does - an
> annotation is simply a string. No chance of any error, anywhere, ever,
> right? Wrong. People put JSON data in those strings for example, and
> parsing that data leads to run-time errors instead. That's the extreme
> example, but the problem with what you're proposing is precisely the
> same: you allow something like nested array data structures, those are
> still going to get interpreted and mapped to objects at run-time, and
> it leads to run-time errors instead.
>
> I maintain that the majority use-case is object annotations - and that
> deferring the construction of those objects doesn't solve anything.
>
> 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 and will always be in favor of language design that takes the
> most direct route to satisfy a requirement. In this case, the
> requirement is annotations as objects - and the most natural and
> direct route is the "new" keyword, static method calls, or whatever
> way you normally create objects; inventing a more indirect way to do
> that just adds complexity.
>
>
> On Mon, May 16, 2016 at 8:39 PM, Fleshgrinder  wrote:
>> 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 muc

Re: [PHP-DEV] [RFC] Simple Annotations

2016-05-17 Thread Rowan Collins

On 17/05/2016 15:22, Rasmus Schultz wrote:

The other issue is the dependency (context) injection example - no one
seems to be able to cite an actual use-case, and if that's the case, I
should probably just remove it from the RFC entirely?

@Larry can you think of a case example in the myriad annotations
you've seen in Drupal code? :-)

Anyone else using Doctrine Annotations actually seen anyone making use
of a closure in an annotation?


Possibly nobody's responded to your call for an example because they're 
not sure what it is you're asking for an example of. I don't really 
understand what closures have to do with annotations, or how that 
relates to capturing context.


An example from the other thread of a context-bound annotation would be 
implementing validation like this:


<>
function foo(int $percentage)


This would appear to be unsupported as such by your proposal, so you 
would instead just have to use strings to represent how it needed to be 
accessed:


<>

and then have extra machinery in the reflection logic to extract the 
parameters and pass them to the object, e.g. 
$annotation->validate($reflected_parameters)



This might be the more sensible approach to such an annotation anyway, 
but without any access to variables, I don't really understand the value 
of evaluating an expression for the annotation, just to get a constant 
value that is cached by the Reflection infrastructure.


If the expression would have to be made up entirely of constants anyway, 
might the same "constant expressions" used in class const definitions be 
a better fit than "any valid PHP expression" - plus a specific exception 
for creating objects out of those constant expressions.


Regards,
--
Rowan Collins
[IMSoP]

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Simple Annotations

2016-05-17 Thread Larry Garfield

On 05/17/2016 04:22 PM, Rasmus Schultz wrote:

I'd like to finish this RFC, but I have two remaining issues.

The syntax is a minor issue - since any valid PHP expression can be
used, the bit-shift ambiguity is technically an issue, however
marginal.

A lot of people commented on the syntax when I posted the RFC on
reddit - they don't like it.

Anyone have any ideas for an alternative syntax? It needs to be
delimited, e.g. needs to use opening and closing delimiters or a
recognizable opening delimiter... Here's some ideas:

@{ new Table("user") }

@[ new Table("user") ]

{{ new Table("user") }}

+{ new Table("user") }

I don't like any of these really, but the bit-shift operator isn't
going when the stuff inside is an expression which could include
bit-shift (is it?)

The other issue is the dependency (context) injection example - no one
seems to be able to cite an actual use-case, and if that's the case, I
should probably just remove it from the RFC entirely?

@Larry can you think of a case example in the myriad annotations
you've seen in Drupal code? :-)


That's on my todo list for later this week. :-)  I'm recently arrived in 
Paris so jetlagged beyond coherent thought at the moment, but I will see 
what I can do on a Drupal case study.


--Larry Garfield

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Simple Annotations

2016-05-17 Thread guilhermebla...@gmail.com
@Rasmus: This approach is too broad, allowing situations like Marco pointed
out. I'd have to vote -1 on it too if you move forward, specially if you
consider things like << "How do I grab this?" >> and other weirdness.


@Rowan: Annotations should be immutable by nature. Still, I would love if
you can detail (in the context of your example) what should be the output
in the following examples:

<>
function foo(int $percentage) {
$reflection = new \ReflectionFunction(__FUNCTION__);

var_dump($reflection->getAnnotations()); // #2
}


$reflection = new \ReflectionFunction("foo");

var_dump($reflection->getAnnotations()); // #1

foo(10);

When executing the code, what should I expect from #1 and #2? I can foresee
that #1 should crash (?) or should it return an ast\node or what?
It all sounds reasonable on #2 what everyone is heavily forcing/suggesting
because of DbC, but it *only* makes sense in the context of a function call
(or a bound object in case of OO members). In any other case its outcome is
unpredictable.




There're 2 potential approaches I can foresee with future for Annotations:

1- This one I see as a simple approach. Take the idea of Dmitry and extend
to support scalars and arrays (only, no objects, no AST\Nodes). Example: <<
Entity(["name" => "User"]) >>
Strings could be easily converted into AST\Nodes internally and DbC would
be possible. Context is inferred at libraries' desire.
Solution here would not have a 1-1 dependency with classes, simplifying the
implementation for meta parameters such as "override", "inherit",
"memoize", "jit", etc.

2- Take an OO approach and correlate 1-1 class. But before that I'd tackle
object initialization first. We'd require to make this to work:

new Foo() {
"property" => "value"
}

After that, we could get back to Annotations and support a subset of PHP
grammar, similar to this:

<< Foo { "property" => "value" } >>


Why I suggest this approach, some may ask? Simple young padawans... We're
already seeing people discuss about final/read-only properties, where they
could only be set at constructor time. We could easily expose this
possibility through scopes. The {} block would be post constructor, but
still in the initialization context, allowing sets to happen for read-only
properties. It's a smart solution against adding a long list of constructor
arguments (and handling default values for each one) and also a nice
alternative to "named parameters".
However, this approach would still require a 1-1 dependency with classes,
which would make "override", "inherit", "jit" a PITA, and likely empower a
more robust annotation solution (like defining which class can be an
annotation and what cannot, or specify annotation target, like class,
method, property, etc).


PS: I hate to write long emails... =(

Cheers,

On Tue, May 17, 2016 at 11:28 AM, Rowan Collins 
wrote:

> On 17/05/2016 15:22, Rasmus Schultz wrote:
>
>> The other issue is the dependency (context) injection example - no one
>> seems to be able to cite an actual use-case, and if that's the case, I
>> should probably just remove it from the RFC entirely?
>>
>> @Larry can you think of a case example in the myriad annotations
>> you've seen in Drupal code? :-)
>>
>> Anyone else using Doctrine Annotations actually seen anyone making use
>> of a closure in an annotation?
>>
>
> Possibly nobody's responded to your call for an example because they're
> not sure what it is you're asking for an example of. I don't really
> understand what closures have to do with annotations, or how that relates
> to capturing context.
>
> An example from the other thread of a context-bound annotation would be
> implementing validation like this:
>
> <>
> function foo(int $percentage)
>
>
> This would appear to be unsupported as such by your proposal, so you would
> instead just have to use strings to represent how it needed to be accessed:
>
> <>
>
> and then have extra machinery in the reflection logic to extract the
> parameters and pass them to the object, e.g.
> $annotation->validate($reflected_parameters)
>
>
> This might be the more sensible approach to such an annotation anyway, but
> without any access to variables, I don't really understand the value of
> evaluating an expression for the annotation, just to get a constant value
> that is cached by the Reflection infrastructure.
>
> If the expression would have to be made up entirely of constants anyway,
> might the same "constant expressions" used in class const definitions be a
> better fit than "any valid PHP expression" - plus a specific exception for
> creating objects out of those constant expressions.
>
> Regards,
> --
> Rowan Collins
> [IMSoP]
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: http://www.php.net/unsub.php
>
>


-- 
Guilherme Blanco
Lead Architect at E-Block


Re: [PHP-DEV] [RFC] Simple Annotations

2016-05-17 Thread Rowan Collins

On 17/05/2016 17:21, guilhermebla...@gmail.com wrote:

It all sounds reasonable on #2 what everyone is heavily
forcing/suggesting because of DbC, but it *only* makes sense in the
context of a function call (or a bound object in case of OO members). In
any other case its outcome is unpredictable.


Yeah, you're right, access to an actual parameter value or runtime 
instance requires logic somewhere else to provide the context, and to 
run the check on every execution of a function requires some magic to 
inject it into the call stack, or the function body, so my example 
doesn't really make any sense.


Regards,
--
Rowan Collins
[IMSoP]

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Simple Annotations

2016-05-17 Thread Fleshgrinder
On 5/17/2016 11:06 AM, Rasmus Schultz wrote:
> I believe I have already stated my position on all of these concerns
> in my last email.
> 

Sorry if I cannot keep everything in my mind.

On 5/17/2016 11:06 AM, Rasmus Schultz wrote:
> There's no such thing as optional dependencies - if you depend on a
> Doctrine ORM annotation, you depend on that package.
> 

Both statements are not true.

#1
A good example of an optional dependency can be found in the Symfony
console package:

https://github.com/symfony/console/blob/master/composer.json#L28
https://github.com/symfony/console/blob/master/Application.php#L814-L816

#2
I could have code in a third-party package that provides some default
annotations which suggests me to install some annotation systems that
are capable of handling exactly those annotations. However, I decide to
only use one of the suggested annotation systems in my project. With
your solution this is not possible because it always ends up in fatal
errors; although I consciously decided to not install one suggested
dependency. See #1 for such an example.

The only solution for the maintainer of the third-party package would be
to provide multiple versions of the same package:

1. No annotations.
2. Annotations from System X.
3. Annotations from System Y.
4. Annotations from System X and Y.
5. ...

This is not an acceptable approach.

On 5/17/2016 11:06 AM, Rasmus Schultz wrote:
> The code should (must) error the moment you try to instantiate those
> annotations - whether you intend to use them or not is besides the
> question - a missing class is an error, in annotations as it is
> anywhere else in your code.
> 

It is not (again see #1) a problem at compile time and always at
runtime. You can try this easily on your console:

  $ php -r 'if (false) { new NonExistingClass; }'
  $ php -r 'if (true) { new NonExistingClass; }'
  Fatal error: Uncaught Error: Class 'NonExistingClass' not found in
Command line code:1
  Stack trace:
  #0 {main}
thrown in Command line code on line 1

On 5/17/2016 11:06 AM, Rasmus Schultz wrote:
> Silently ignoring missing annotations solves nothing - it just leads
> to errors that are even harder to find and debug.
> 

My proposal errors as soon as you try to retrieve an annotation with the
annotation reader which was not previously registered as such. However,
you can use Reflection and introspect any existing annotation without
any kind of error.

That is how it should be!

On 5/17/2016 11:06 AM, Rasmus Schultz wrote:
> You seem awfully concerned about name collisions?
> 

No, I am not. It is just a nice side product of my proposal.

On 5/17/2016 11:06 AM, Rasmus Schultz wrote:
> The one new thing you brought up here, is the issue of potentially
> loading/instantiating a bunch of annotations that go unused. [...]
> From a performance point of view [...]
> 

The problem is parsing and interpreting them although they might not be
used because the current path of logic will not go through them at all.
This is not a micro optimization thing. You just don't want to interact
with annotations at all until they are actually needed. This is true for
any kind of PHP code.

See console commands above.

On 5/17/2016 11:06 AM, Rasmus Schultz wrote:
> The extreme case of what you're proposing, is what Go does - an
> annotation is simply a string. No chance of any error, anywhere, ever,
> right? Wrong. People put JSON data in those strings for example, and
> parsing that data leads to run-time errors instead. That's the extreme
> example, but the problem with what you're proposing is precisely the
> same: you allow something like nested array data structures, those are
> still going to get interpreted and mapped to objects at run-time, and
> it leads to run-time errors instead.
> 

Runtime errors for a runtime feature, well, yes. Again, see console
command example above.

  @someAnnotation('{"json": "data"}') function f();
  @someAnnotation('invalid json') function x();

  $reflector = new ReflectionFunction('f');
  $annotations = $reflector->getAnnotations();
  /*
  $annotations = [
'someAnnotation' => [
  ['{"json": "data"}'],
],
  ];
  */

  $reflector = new ReflectionFunction('x');
  $annotations = $reflector->getAnnotations();
  /*
  $annotations = [
'someAnnotation' => [
  ['invalid json'],
],
  ];
  */

  annotation_register('someAnnotation', function (string $json) {
$decoded_json = json_decode($json);
if ($decoded_json === false) {
  throw new JsonParseException(json_last_error_msg());
}
return $decoded_json;
  });

  $annotations = new AnnotatedFunction('f');
  $some_annotations = $annotations->getAnnotations('someAnnotations');
  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 w

Re: [PHP-DEV] [RFC] Simple Annotations

2016-05-17 Thread Rasmus Schultz
> I don't really understand what closures have to do with annotations, or how 
> that relates to capturing context.

The point is that, rather than trying to capture context, you can just
as well ask for what you need.

I'm going to use a very contrived example, because I really can't
think of any real case that requires context:

class User
{
<< new Validation(function ($value) { return false !==
filter_var($value, FILTER_VALIDATE_EMAIL); }) >>
public $email;
}

Like I said, extremely contrived - in practice, you wouldn't need to
attach functionality in that way.

> An example from the other thread of a context-bound annotation would be 
> implementing validation like this

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
) { ... }

> If the expression would have to be made up entirely of constants anyway, 
> might the same "constant expressions" used in class const definitions be a 
> better fit than "any valid PHP expression" - plus a specific exception for 
> creating objects out of those constant expressions.

Probably not - what happens with what is today "nested annotations"
then? Or will you make an exception for those too?

The problem is, you're just reinventing a subset of the programming
language, and I'm sure you can keep expanding on that indefinitely.
What for? Just use the facilities already defined by the language.

This fear of any feature that lets you do "evil" is incomprehensible
to me. Most features of almost any programming language can be used
for "evil". IMO, the real question is whether a feature accomplishes
what you want. If you insist on something that also prevents things
you don't want, you're bound to end up with something a lot more
complex that fits into the language a lot less naturally...


On Tue, May 17, 2016 at 5:28 PM, Rowan Collins  wrote:
> On 17/05/2016 15:22, Rasmus Schultz wrote:
>>
>> The other issue is the dependency (context) injection example - no one
>> seems to be able to cite an actual use-case, and if that's the case, I
>> should probably just remove it from the RFC entirely?
>>
>> @Larry can you think of a case example in the myriad annotations
>> you've seen in Drupal code? :-)
>>
>> Anyone else using Doctrine Annotations actually seen anyone making use
>> of a closure in an annotation?
>
>
> Possibly nobody's responded to your call for an example because they're not
> sure what it is you're asking for an example of. I don't really understand
> what closures have to do with annotations, or how that relates to capturing
> context.
>
> An example from the other thread of a context-bound annotation would be
> implementing validation like this:
>
> <>
> function foo(int $percentage)
>
>
> This would appear to be unsupported as such by your proposal, so you would
> instead just have to use strings to represent how it needed to be accessed:
>
> <>
>
> and then have extra machinery in the reflection logic to extract the
> parameters and pass them to the object, e.g.
> $annotation->validate($reflected_parameters)
>
>
> This might be the more sensible approach to such an annotation anyway, but
> without any access to variables, I don't really understand the value of
> evaluating an expression for the annotation, just to get a constant value
> that is cached by the Reflection infrastructure.
>
> If the expression would have to be made up entirely of constants anyway,
> might the same "constant expressions" used in class const definitions be a
> better fit than "any valid PHP expression" - plus a specific exception for
> creating objects out of those constant expressions.
>
>
> Regards,
> --
> Rowan Collins
> [IMSoP]
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: http://www.php.net/unsub.php
>

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Simple Annotations

2016-05-17 Thread Fleshgrinder
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

2016-05-17 Thread Rowan Collins

On 17/05/2016 18:47, Rasmus Schultz wrote:

I don't really understand what closures have to do with annotations, or how 
that relates to capturing context.


The point is that, rather than trying to capture context, you can just
as well ask for what you need.

I'm going to use a very contrived example, because I really can't
think of any real case that requires context:

class User
{
<< new Validation(function ($value) { return false !==
filter_var($value, FILTER_VALIDATE_EMAIL); }) >>
public $email;
}

Like I said, extremely contrived - in practice, you wouldn't need to
attach functionality in that way.


Right, in my mind this is less about *context*, and more about *passing 
code into the implementation*. I think we agree that an implementation 
of validation-by-annotation would look something like:


$validators = $reflected_thing->getAnnotations('someFilter');
foreach ( $validators as $validator ) {
$validator->validate($some_instance);
}

This gets its *context* from the code running the validator; the 
implementation of the validate() method would normally just be part of 
the annotation type:


<>
var $foo;


The closure example you gave would be a way of providing on-the-fly 
dynamic *behaviour* as the argument to an annotation. This wouldn't 
really make sense for validation (a custom validator would still 
probably be defined once and used for several fields, but theoretically 
you could have:


<>

It's not the context that's magic here, it's the ability to specify code 
as part of the annotation *value*, rather than the annotation *definition*.



A more obvious example therefore is using annotations to implement DbC:

<>

Although as I admitted to Guilherme, that requires some magic to run it 
at the right time anyway...




An example from the other thread of a context-bound annotation would be 
implementing validation like this


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
) { ... }


Sure, but it's easy to come up with a variant that requires access to 
more than one parameter, say:


<< ValidateLessThan($min, $max) >>
function foo($min, $max)

Which without any context or AST would need to be either:

<< ValidateLessThan('$min', '$max') >>
function foo($min, $max)

...which rather defeats the point of having code rather than just a string.

Or:

<< ValidateCustom(function($min, $max) { return $min < $max } >>
function foo($min, $max)

...which feels rather clunky.



If the expression would have to be made up entirely of constants anyway, might the same 
"constant expressions" used in class const definitions be a better fit than "any 
valid PHP expression" - plus a specific exception for creating objects out of those constant 
expressions.


Probably not - what happens with what is today "nested annotations"
then? Or will you make an exception for those too?


How would you "nest" annotations in your scheme anyway? As far as I can 
see, they would be either multi-level arrays (a valid constant 
expression) or nested constructor calls. So there's still exactly one 
exception made, the "new Foo(args)" construct.




The problem is, you're just reinventing a subset of the programming
language, and I'm sure you can keep expanding on that indefinitely.
What for? Just use the facilities already defined by the language.


That's a fair point. The flipside is that the more things you allow the 
user to do, the more edge cases you have to deal with when evaluating 
the expressions in your special "zero context".




This fear of any feature that lets you do "evil" is incomprehensible
to me. Most features of almost any programming language can be used
for "evil".


I am not suggesting removing the ability to avoid people doing evil; I'm 
suggesting that the feature you call "simple annotations" could be a lot 
simpler.


What is the value of being able to write this:

function foo() { return 'MyAnnotation'; }

<< foo() >>
class A {}

When you could just write this:

<< 'MyAnnotation' >>



IMO, the real question is whether a feature accomplishes
what you want. If you insist on something that also prevents things
you don't want, you're bound to end up with something a lot more
complex that fits into the language a lot less naturally...


In my mind, something that lets me evaluate an arbitrary expression in 
some weird null-context, at an unspecified time (because I don't know 
what code will be the first to request that annotation), only to have 
the result stored in some invisible static variable, is *more* complex 
than many of the alternatives.


Regards,
--
Rowan Collins
[IMSoP]

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Simple Annotations

2016-06-11 Thread Rasmus Schultz
So this thread kind of died, apparently mostly due to some concerns about
possible side-effects.

I would just like to point out one thing: when it comes to
metadata/annotations, whatever you come up with, even if it's something
that allows only constant expressions and simple data-structures, as
opposed to classes, what's going to happen - like, immediately - is someone
will figure out how to map it to classes.

The thing is that, even if annotations are simple data attached to
source-code elements, someone is going to need/want things like range and
type validations for those annotations and their attributes - essentially
the only way to get that, is with code, and the most obvious way to do
that, is map annotations to classes, which is basically what every userland
annotation project is doing.

I maintain the position that simply allowing arbitrary expressions as
annotations is the simplest, most direct way to this feature.

Whatever you come up with that is more restrictive, someone will simply
figure out how to map that to the thing they really wanted, which is
objects - and then you have all the same problems and risks of
global/mutable state, side-effects, etc.

Anything directly or indirectly executable is going to allow you to create
those problems - presently that is true everywhere in PHP, literally for
everything, including files, classes, functions, even expressions can have
side-effects.

Inventing a more restrictive form of annotations will only make the road
longer and more confusing - it won't remove those risks or solve those
problems. The only real solution to those problems, is teach people how to
program.

Another concern was about optional dependency on classes for annotations.
Again, that's going to happen when people figure out how to map a more
restrictive feature to classes - and in either case, if you could somehow
ignore annotations that fail to initialize because of a missing dependency,
that would be a very bad idea; quietly ignoring a missing class would
create very strange and difficult debugging situations.

I think that this problem is exaggerated. Needing to include the
annotations you actually use is hardly a roadblock to anything. Leaving out
dependencies would be as strange to me as allowing the extends or
implements keyword to ignore a missing interface or base class. I simply
don't see the usefulness, and can only see that turning into a real
debugging nightmare.

I think that, given how simple this proposed feature really is, it's really
not likely to generate a lot of surprises for anyone - I mean, we're used
to the fact that new Foo() fails if the class Foo does not exist. In fact,
it would be a lot more surprising if you had to explain why that wasn't the
case. We're also used to the fact that such expressions fail not when
they're loaded, but when they're evaluated - like when you run a method.
That's not surprising at all.

I think that this feature is really very simple, in every sense of the word
- it's easy to explain, there are very few rules and no real surprises, it
just basically lets you insert a list of values or objects defined using
simple everyday PHP expressions, which behave, for better or for worse,
like they do every day.

I wish you wouldn't shoot down this feature on the basis of some missing
language qualities you seem to be seeking - if PHP someday supports
immutable objects, or functions without side-effects, annotations would
immediately support those too. At the moment, it does not, and I don't
believe it's going to be even the least bit surprising that annotations
don't have those language qualities either.

Nor do I think people are going to do "evil" with it - I think that for
example Symfony annotations, or annotations in C#, have all of the same
problems, just like any language with global and mutable state, and people
are quite happy and productive using them anyway.

I think that there is real value to having a very simple feature that
leverages the language as-is instead of inventing new, special syntax,
restrictions or limitations, and I'd be much less worried about "evil"
somebody might do with that, and more excited to see the interesting and
clever things people would come up with.

It seemed like there was some initial excitement about this idea.

I'm not opposed to developing the idea further, if there's any interest.
For example, one possible idea would be to allow object constructions only:

class User {
<< Length(20) >>
public $email;
}

This creates a limitation, but covers the most popular use-case of object
annotations, and that limitation would enable a reflection reader along the
lines of:

$annotations =
$reflection->getProperty("email")->getAnnotations(User::class);

This differs from what I previously proposed, since you are now required to
ask specifically for one type of annotation, which means you can have
"optional" annotations - just check first, e.g. if
(class_exists(Length::class

Re: [PHP-DEV] [RFC] Simple Annotations

2016-06-27 Thread Rasmus Schultz
Tonight I started trying to write a proposal for even more simplified
annotations, e.g. something simple enough that it cannot result in
fatal errors. I eventually gave up, and here's why.

Essentially, if you have to restrict yourself to things that cannot
under any circumstances error out, the only things you can use are
constant scalar values - even constant scalar expressions could not be
allowed, because even those could error when CONST_NAME or
Class::CONST_NAME aren't defined.

So, in a nutshell, what you're saying (Richard) is that annotations
can only consist of scalar values, and possibly arrays of values? (and
I don't even see your gist doing that - it's just invoking closures,
as far as I can tell, and any of those could error, or not?)

So, regardless of syntax, literally the only annotation data allowed
would be blatantly simple things like:

["max_length" => 20]

["data_type" => "int"]

Or in other words, constant arrays, int, string, float and bool
values. Nothing else.

Nothing can depend on any kind of external symbol (class names,
constants, etc.) since any such reference can cause an error.

No static analysis or type-checking of any kind can ever be performed
- no assertions or declarations can be made about the shape or types
of metadata, at all.

The problem is, that's simply not useful.

It's also not very different from what we have today with php-doc
blocks - the only real difference is we can check array nesting and
int, string, float and bool syntax, e.g. nothing really useful or
important.

In other words, this would be a very slight improvement on syntax -
nothing that actually amounts to any kind of functionality.

If we were to ship a feature like that, what would happen is precisely
the same thing that happened with php-doc blocks: the real work will
be done in userland (and likely dominated by one library), there will
be no IDE support (except proprietary support for that one dominating
library), no useful offline static analysis tools.

At the end of the day, what we end up with will have all of the same
issues we have with php-doc blocks and existing libraries.

I don't understand how such a feature would be useful to anybody?

I especially don't understand why you want a language feature that
isn't allowed to reference external symbols - e.g. isn't allowed to
have any kind of relationship with anything declared in userland.

It seems to me a peculiar, arbitrary and unrealistic restriction to
put on annotations.

It's going to have no immediate usefulness, and mapping the data to
objects is going to happen in userland, just as it does today.

I'd like to work on this proposal, but I feel that you're giving me
nothing to work with here.


On Mon, May 16, 2016 at 12:38 PM, Fleshgrinder  wrote:
> 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
>

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Simple Annotations

2016-06-28 Thread Marco Pivetta
Hi Rasmus,

On 27 June 2016 at 20:37, Rasmus Schultz  wrote:

> Tonight I started trying to write a proposal for even more simplified
> annotations, e.g. something simple enough that it cannot result in
> fatal errors. I eventually gave up, and here's why.
>
> Essentially, if you have to restrict yourself to things that cannot
> under any circumstances error out, the only things you can use are
> constant scalar values - even constant scalar expressions could not be
> allowed, because even those could error when CONST_NAME or
> Class::CONST_NAME aren't defined.
>
> So, in a nutshell, what you're saying (Richard) is that annotations
> can only consist of scalar values, and possibly arrays of values? (and
> I don't even see your gist doing that - it's just invoking closures,
> as far as I can tell, and any of those could error, or not?)
>
> So, regardless of syntax, literally the only annotation data allowed
> would be blatantly simple things like:
>
> ["max_length" => 20]
>
> ["data_type" => "int"]
>
> Or in other words, constant arrays, int, string, float and bool
> values. Nothing else.
>
> Nothing can depend on any kind of external symbol (class names,
> constants, etc.) since any such reference can cause an error.
>
> No static analysis or type-checking of any kind can ever be performed
> - no assertions or declarations can be made about the shape or types
> of metadata, at all.
>
> The problem is, that's simply not useful.
>

That's actually what doctrine/annotations has been for a while  tho, and a
lot of people rely just on that.
The data-structure is still enforced by a VO-style class (the annotation
itself) in the library, though.

It would still be very useful, in my opinion.

Note that the existing annotation libs out there do indeed trigger
autoloading for referenced class constants.

Marco Pivetta

http://twitter.com/Ocramius

http://ocramius.github.com/


Re: [PHP-DEV] [RFC] Simple Annotations

2016-06-28 Thread Pedro Cordeiro
I completely agree with Marco. Throwing class-loading errors for
value-object classes is alright. For logic-parsing inside annotations, I
don't feel any need for it. Metadata should be static, IMO, but it could
very well be (and should be) value-objects.

>At the end of the day, what we end up with will have all of the same
>issues we have with php-doc blocks and existing libraries.
>
>I don't understand how such a feature would be useful to anybody?

As an addition, I don't think this feature should ADD new functionality to
those already present on DocBlocks. I just feel like docblocks are an ugly
hack for the lack of native annotations. Pasting from a previous discussion
in this same list, Rowan and I were discussing whether to add a native
docblock-annotation-retrieval feature or a native annotation syntax:

1) It might not be objectively bad to add this feature in docblocks, but it
will be objectively wrong to keep calling them "DocBlocks" if they are no
longer documentation-only blocks.

2) Even though PHP already treats docblocks differently from comments,
that's not the common view on userland, nor is explained on the manuals.
There are no separate entries to explain docblocks, and no mention to them
on the "Comments" page. The Reflection method to retrieve DocBlocks is
"getDocCOMMENT", which suggests they are comment that do not affect runtime
behaviour.

We'd have to update the comments page to say "'/*' starts a comment, unless
if they're immediately followed by another asterisk ('/**'), in which case
it may or may not be a comment, depends on the following token". It's very
confusing.

3) To make this work within docblocks, we'd have to get rid of at least one
configuration setting (opcode.save_comments).

4) Dockblocks are stripped from obfuscators and transpilers, which are a
part of the ecosystem and do affect users, even if they are not first-class
citizens here.

Annotations in dockblocks are hard to understand because they they may or
may not be runtime-affecting annotations and there is no way to tell.

I hate this comparison with docblock annotations, because they are an UGLY
HACK. It works wonderfully, yes, but so do global variables, singletons and
what-not, and we are not using them anymore, are we? Adding this very same
feature that already exists in userland as a dedicated syntax would fix a
lot of issues, cited above. There is no need to evaluate logic inside
annotations, let them be value-objects, let it throw errors autoloading
said objects, and let's get this rolling.

Please, don't embargo this ONCE again. It's a very much needed feature, and
people want it! There have been innumerous discussions on reddit, and
almost everyone agrees annotations are a missing feature and
comment-annotations are an ugly hack for the lack of native syntax.

Please, make this happen.

2016-06-28 11:12 GMT-03:00 Marco Pivetta :

> Hi Rasmus,
>
> On 27 June 2016 at 20:37, Rasmus Schultz  wrote:
>
> > Tonight I started trying to write a proposal for even more simplified
> > annotations, e.g. something simple enough that it cannot result in
> > fatal errors. I eventually gave up, and here's why.
> >
> > Essentially, if you have to restrict yourself to things that cannot
> > under any circumstances error out, the only things you can use are
> > constant scalar values - even constant scalar expressions could not be
> > allowed, because even those could error when CONST_NAME or
> > Class::CONST_NAME aren't defined.
> >
> > So, in a nutshell, what you're saying (Richard) is that annotations
> > can only consist of scalar values, and possibly arrays of values? (and
> > I don't even see your gist doing that - it's just invoking closures,
> > as far as I can tell, and any of those could error, or not?)
> >
> > So, regardless of syntax, literally the only annotation data allowed
> > would be blatantly simple things like:
> >
> > ["max_length" => 20]
> >
> > ["data_type" => "int"]
> >
> > Or in other words, constant arrays, int, string, float and bool
> > values. Nothing else.
> >
> > Nothing can depend on any kind of external symbol (class names,
> > constants, etc.) since any such reference can cause an error.
> >
> > No static analysis or type-checking of any kind can ever be performed
> > - no assertions or declarations can be made about the shape or types
> > of metadata, at all.
> >
> > The problem is, that's simply not useful.
> >
>
> That's actually what doctrine/annotations has been for a while  tho, and a
> lot of people rely just on that.
> The data-structure is still enforced by a VO-style class (the annotation
> itself) in the library, though.
>
> It would still be very useful, in my opinion.
>
> Note that the existing annotation libs out there do indeed trigger
> autoloading for referenced class constants.
>
> Marco Pivetta
>
> http://twitter.com/Ocramius
>
> http://ocramius.github.com/
>


Re: [PHP-DEV] [RFC] Simple Annotations

2016-06-28 Thread Rasmus Schultz
Note that I only make comparisons with doc-blocks to point out the
fact that, functionally, they would not be very different from an
annotation feature that solely permits you to annotate with values. A
doc-block is a string, which is a value - an
array/int/float/string/bool is a value. It's only very slightly better
than a bare string, in the sense that neither doc-blocks nor simple
values permit any kind of definition of which annotations are actually
available, hence offer no means of validation of that data (except at
run-time by a userland facility), provides no support for static
analysis, no IDE support, no clear indication of real dependencies,
and so on.

Since the discussion isn't completely dead yet (thank you Pedro and
Marco), I will just briefly explain what I had in mind for another
RFC.

This would be largely based on my previous proposal:

https://wiki.php.net/rfc/simple-annotations

But with the following differences.

The syntax would no longer allow arbitrary expressions - instead, it
would allow object annotations only, declared in one of three ways:

<< RequiresLogin >> // equivalent to new RequiresLogin()

<< Length(20) >> // equivalent to new Length(20)

<< HttpMethod::post() >> // equivalent to static method-call HttpMethod::post()

The latter permits you to declare and call static factory methods,
e.g. "named constructors" for some types of annotations.

Annotations are now consistently objects, which simplifies filtering
annotations, etc.

This declaration syntax enables better in-language analysis - because
the declarations always include the annotation class-name, this means
it can now support deferred as well as conditional creation, by having
a slightly different reflection API:

$annotations = $class_reflection->getAnnotations();

At this point, we have a list of ReflectionAnnotation objects - the
actual annotation objects have *not* been created at this point, which
would allow for conditional evaluation, such as:

foreach ($annotations as $annotation) {
echo $annotation->className; // => "Length" etc.

if ($annotation->classExists()) {
var_dump($annotation->getInstance()); // => Length object, etc.
} else {
var_dump($annotation->getInstance()); // => UnknownAnnotation object
   }
}

The UnknownAnnotation object has three properties: class-name,
method-name ("__construct" if constructor was used) and the list of
arguments.

In other words, this would provide support for "optional
dependencies", in much the same way that unserialize() does it - the
getInstance() method will trigger autoloading, and if the class is
unavailable, it takes this "typeless" information and puts it in a
general object, so that the information itself isn't lost.

It may *seem* like this solves the optional dependency problem, but
let me be clear, it does *not* fully address that issue, because
something like << Method(Http::GET) >> could still fail, if the Method
class is defined, but the Http class is not. That's a much more
marginal case, but it's not completely unlikely that you would use
constants from one dependency and pass them to annotation classes from
another dependency, e.g. if the HTTP method constants were part of an
HTTP package, and the annotation itself were part of a different
package. Arguably it's much less likely to occur though - if you have
the annotation package installed, most likely you have the dependent
package of that package installed as well.

So this is much safer, but just to be clear, the only way you can make
it any safer than that, is by completely disallowing anything but
values as arguments to annotation constructors - which, in my opinion,
simply isn't useful.

Alternatively to the above, you could imagine a simpler reflection
facility that does eagerly construct annotations, but constructs
UnknownAnnotation instances for missing classes - this would perhaps
balance more towards immediate usefulness and less towards performance
perfectionism, as it increases the chance of loading an unused
annotation.

This would be my preference though - as previously argued, the odds of
having a large number of unrelated annotations on the same member are
extremely low in practice; an annotated entity tends to be a persisted
property, a form input element, or an action method, etc... rarely do
you mix annotations from different domains onto the same member;
annotations that are applicable to a given domain are usually relevant
to a consumer belonging to the same (or a closely related) domain, so
this performance concern is mostly a theoretical micro optimization.

For another, eager construction means we can filter annotations with
instanceof rather than by class-name, which is much powerful, enabling
you to leverage inheritance - for example, you'd be able to ask
directly for all instances of ValidationAnnotation and get those with
a single call, which is incredibly useful.

Anyways, let me know your feelings abou

Re: [PHP-DEV] [RFC] Simple Annotations

2016-06-28 Thread Rowan Collins

Hi Rasmus,

I think you may be onto something here... :)


On 28/06/2016 17:31, Rasmus Schultz wrote:

The UnknownAnnotation object has three properties: class-name,
method-name ("__construct" if constructor was used) and the list of
arguments.


I'm not sure we need an extra UnknownAnnotation class. It seems like all 
of that information could be available on the ReflectionAnnotation 
object, so you can get it without the class being available if you want to.


If the idea is to lazily-evaluate the arguments to the annotation, that 
could be handled by storing the AST and only evaluating them when you 
call either $annotation->getInstance() or $annotation->getArguments():


use MyAnnotations\FooAnnotation as Foo;
// Class alias resolved at compile time as normal
<< Foo(time()) >>
class A {}

$class_reflection = new ReflectionClass('A');
$annotations = $class_reflection->getAnnotations();
foreach ($annotations as $annotation) {
   if ( $annotation->getClassName() == 'MyAnnotations\\FooAnnotation' ) {
   var_dump( $annotation->getArguments() ); // `time()` evaluated here
   var_dump( $annotation->getInstance() ); // `new 
MyAnnotations\FooAnnotation(time())` evaluated here

   }
}

It's not the responsibility of the ReflectionAnnotation class to worry 
about calling the autoloader, issuing errors, etc, it should just 
delegate that to the engine like any other constructor call. There's no 
need for an extra $annotation->classExists() method, either, because you 
can just say "class_exists($annotation->getClassName())".



Interestingly, this same delayed evaluation of arguments opens us up to 
include direct access to the AST as some (Nikita?) have asked for:


// Constructor argument can be any valid expression,
// however nonsensical it would be to evaluate it directly
<< Pre($a >= 42) >>
function foo($a) {}

$r = new ReflectionFunction('foo');
$annotations = $r->getAnnotations();
foreach ( $annotations as $annotation ) {
   if ( $annotation->getClassName() == 'Pre' ) {
   $ast = $annotation->getArgumentAST();
   // Now we can do funky things with the AST, like evaluating it 
in a custom context :)

   }
}


Regards,
--
Rowan Collins
[IMSoP]

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Simple Annotations

2016-06-28 Thread Fleshgrinder
On 6/28/2016 6:31 PM, Rasmus Schultz wrote:
> Since the discussion isn't completely dead yet (thank you Pedro and
> Marco), I will just briefly explain what I had in mind for another
> RFC.
> 

I want to see this feature happen too but the right way, so let us just
spend some more time wrapping our heads around it. We could also discuss
and work on the RFC at a different place (GitHub with issues?), since
many people are always complaining about too many emails that are sent
to this ML.

On 6/28/2016 6:31 PM, Rasmus Schultz wrote:
> The syntax would no longer allow arbitrary expressions - instead, it
> would allow object annotations only, declared in one of three ways:
> 
> << RequiresLogin >> // equivalent to new RequiresLogin()
> 
> << Length(20) >> // equivalent to new Length(20)
> 
> << HttpMethod::post() >> // equivalent to static method-call 
> HttpMethod::post()
> 
> The latter permits you to declare and call static factory methods,
> e.g. "named constructors" for some types of annotations.
> 
> Annotations are now consistently objects, which simplifies filtering
> annotations, etc.
> 
> This declaration syntax enables better in-language analysis - because
> the declarations always include the annotation class-name, this means
> it can now support deferred as well as conditional creation, by having
> a slightly different reflection API:
> 
> $annotations = $class_reflection->getAnnotations();
> 
> At this point, we have a list of ReflectionAnnotation objects - the
> actual annotation objects have *not* been created at this point, which
> would allow for conditional evaluation, such as:
> 
> foreach ($annotations as $annotation) {
> echo $annotation->className; // => "Length" etc.
> 
> if ($annotation->classExists()) {
> var_dump($annotation->getInstance()); // => Length object, etc.
> } else {
> var_dump($annotation->getInstance()); // => UnknownAnnotation 
> object
>}
> }
> 
> The UnknownAnnotation object has three properties: class-name,
> method-name ("__construct" if constructor was used) and the list of
> arguments.
> 
> In other words, this would provide support for "optional
> dependencies", in much the same way that unserialize() does it - the
> getInstance() method will trigger autoloading, and if the class is
> unavailable, it takes this "typeless" information and puts it in a
> general object, so that the information itself isn't lost.
> 

Awesome! This is exactly the kind of thing that one wants from
reflection, information and not exceptions or worse. :)

On 6/28/2016 6:31 PM, Rasmus Schultz wrote:
> It may *seem* like this solves the optional dependency problem, but
> let me be clear, it does *not* fully address that issue, because
> something like << Method(Http::GET) >> could still fail, if the Method
> class is defined, but the Http class is not. That's a much more
> marginal case, but it's not completely unlikely that you would use
> constants from one dependency and pass them to annotation classes from
> another dependency, e.g. if the HTTP method constants were part of an
> HTTP package, and the annotation itself were part of a different
> package. Arguably it's much less likely to occur though - if you have
> the annotation package installed, most likely you have the dependent
> package of that package installed as well.
> 
> So this is much safer, but just to be clear, the only way you can make
> it any safer than that, is by completely disallowing anything but
> values as arguments to annotation constructors - which, in my opinion,
> simply isn't useful.
> 

I would argue that this should fail if the Method class from the example
exists and is actually being created. However, if the Method class does
not exist (and we construct an UnknownAnnotation stub for it) nothing
should go wrong. I mean, the assumption that the dependency of a missing
dependency is/might be missing sounds logical too me.

Of course we would need to have something like an
UnknownAnnotationArgument stub too.

Note that this allows you in consequence to create other kinds of
objects within annotations:

  << Annotation(new Argument) >> final class {}

This would allow nesting as some DocBlock libraries allow it currently.

On 6/28/2016 6:31 PM, Rasmus Schultz wrote:
> Alternatively to the above, you could imagine a simpler reflection
> facility that does eagerly construct annotations, but constructs
> UnknownAnnotation instances for missing classes - this would perhaps
> balance more towards immediate usefulness and less towards performance
> perfectionism, as it increases the chance of loading an unused
> annotation.
> 
> This would be my preference though - as previously argued, the odds of
> having a large number of unrelated annotations on the same member are
> extremely low in practice; an annotated entity tends to be a persisted
> property, a form input element, or an action method, etc... rarely do
> you mix annotations from differen

Re: [PHP-DEV] [RFC] Simple Annotations

2016-06-28 Thread Rowan Collins

On 28/06/2016 17:31, Rasmus Schultz wrote:

For another, eager construction means we can filter annotations with
instanceof rather than by class-name, which is much powerful, enabling
you to leverage inheritance - for example, you'd be able to ask
directly for all instances of ValidationAnnotation and get those with
a single call, which is incredibly useful.


Sorry for the extra mail with only one point, but I missed this before. 
This can be achieved using the fully-qualified class-name by using 
is_a() or is_subclass_of(). This obviously needs to trigger the 
autoloader anyway, but can still avoid actually instantiating the class. 
(And thus, per my other mail, evaluating the args.)


I think lazy construction (without magic stub classes) gives the best of 
both worlds here.


--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Simple Annotations

2016-06-28 Thread Rasmus Schultz
Thanks, Richard and Rowan - this gives me more to work with!

I will work on a new proposal and ask for more input when I have a
draft ready :-)


On Tue, Jun 28, 2016 at 7:56 PM, Rowan Collins  wrote:
> On 28/06/2016 17:31, Rasmus Schultz wrote:
>>
>> For another, eager construction means we can filter annotations with
>> instanceof rather than by class-name, which is much powerful, enabling
>> you to leverage inheritance - for example, you'd be able to ask
>> directly for all instances of ValidationAnnotation and get those with
>> a single call, which is incredibly useful.
>
>
> Sorry for the extra mail with only one point, but I missed this before. This
> can be achieved using the fully-qualified class-name by using is_a() or
> is_subclass_of(). This obviously needs to trigger the autoloader anyway, but
> can still avoid actually instantiating the class. (And thus, per my other
> mail, evaluating the args.)
>
> I think lazy construction (without magic stub classes) gives the best of
> both worlds here.
>
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: http://www.php.net/unsub.php
>

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Simple Annotations

2016-06-28 Thread Pedro Cordeiro
> << HttpMethod::post() >> // equivalent to static method-call
> HttpMethod::post()
>

What would this, specifically, do? Would it call HttpMethod::post() when
the class gets instantiated and return its return on a
ReflectionClass::getAnnotations()? Why is it necessary to be able to
evaluate expressions on annotations? I do agree that throwing
errors/exceptions when classes are not found is needed (otherwise we wont
be able to use value-objects), but evaluating expressions seems a little
crazy for me... why should metadata be computed in runtime?


Re: [PHP-DEV] [RFC] Simple Annotations

2016-06-28 Thread Rowan Collins
On 28 June 2016 20:10:15 GMT+01:00, Pedro Cordeiro  
wrote:
>> << HttpMethod::post() >> // equivalent to static method-call
>> HttpMethod::post()
>>
>
>What would this, specifically, do? Would it call HttpMethod::post()
>when
>the class gets instantiated and return its return on a
>ReflectionClass::getAnnotations()? Why is it necessary to be able to
>evaluate expressions on annotations?

I'm not sure if it's definitely necessary, but the stated use case was for 
factories / named constructors. PHP only has one constructor per class, so it's 
not uncommon to have static createFromX methods.

Since this will eventually evaluate as "new Foo(42)":
<< Foo(42) >>

The idea is that this would be available to call a factory instead:
<< Foo::fromRoman('XLII') >>

The neat thing being that by limiting the options to this, you can still 
extract a class name for every annotation.

I say "eventually", because as proposed, this won't actually happen until you 
explicitly ask for the "instance" of the annotation. See previous examples.

Regards,

-- 
Rowan Collins
[IMSoP]

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Simple Annotations

2016-06-28 Thread Rasmus Schultz
This was just an example of a value object - for example:

class HttpMethod {
private $method;

protected function __construct($method) {
$this->method = $method;
}

public function getMethod() {
return $this->method;
}

public static function get() {
return new self("GET");
}

public static function post() {
return new self("POST");
}

// ...
}

You could picture using a flyweight constructor inside those factory
methods maybe, and probably other patterns... I think there's plenty
of cases for "named constructors", this is just the PHP variety of
that. There are also cases (such as this one) where only certain
constructions are permitted - allowing any string for HTTP method
(e.g. wrong names, wrong case etc.) is prevented by protecting the
constructor...


On Tue, Jun 28, 2016 at 9:10 PM, Pedro Cordeiro  wrote:
>
>> << HttpMethod::post() >> // equivalent to static method-call
>> HttpMethod::post()
>
>
> What would this, specifically, do? Would it call HttpMethod::post() when the
> class gets instantiated and return its return on a
> ReflectionClass::getAnnotations()? Why is it necessary to be able to
> evaluate expressions on annotations? I do agree that throwing
> errors/exceptions when classes are not found is needed (otherwise we wont be
> able to use value-objects), but evaluating expressions seems a little crazy
> for me... why should metadata be computed in runtime?

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Simple Annotations

2016-06-28 Thread Larry Garfield

On 06/28/2016 04:24 PM, Rasmus Schultz wrote:

This was just an example of a value object - for example:

class HttpMethod {
 private $method;

 protected function __construct($method) {
 $this->method = $method;
 }

 public function getMethod() {
 return $this->method;
 }

 public static function get() {
 return new self("GET");
 }

 public static function post() {
 return new self("POST");
 }

 // ...
}

You could picture using a flyweight constructor inside those factory
methods maybe, and probably other patterns... I think there's plenty
of cases for "named constructors", this is just the PHP variety of
that. There are also cases (such as this one) where only certain
constructions are permitted - allowing any string for HTTP method
(e.g. wrong names, wrong case etc.) is prevented by protecting the
constructor...


A possibly uglier but useful case would be where you have a large number 
of properties in an annotation and want to pass them in by name, but not 
using an anonymous array.  (See also, my earlier Drupal examples.)


To wit:

<>
class Node {

  public static function definition() {
$def = new NodeDefinition();
$def->name = "node";
$def->label = "A Node";
$def->addLink('foo', 'bar');
// ...
return $def;
  }

  // The rest of the node class here.
}

$annotations = $class_reflection->getAnnotations();

print get_class($annotations[0]); // prints "NodeDefinition".

Or would that fail because it's not returning a self instance, but of 
another class?


Rasmus, let me know when you have a proposal together and I'll try to 
dig up time to try rendering Drupal annotations in it again. :-)


--Larry Garfield

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php