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 what kind of errors can happen. The annotation library is
also the one reading the annotations and it can therefore easily handle
those errors and act upon them. Of course in the above case the fatal
error is just fine and it is the developers duty to write unit tests and
take care of writing proper configuration. It is not PHP's duty to
ensure to absolutely no error can happen in any subsystem. (This is
actually ridiculous to think of in the first place.)

On 5/17/2016 11:06 AM, Rasmus Schultz wrote:
> I maintain that the majority use-case is object annotations - and that
> deferring the construction of those objects doesn't solve anything.
> 

Seriously? Every construction is deferred, always, again see the console
example from above.

On 5/17/2016 11:06 AM, Rasmus Schultz wrote:
> You're just deferring or hiding the problem, adding complexity, and
> mental as well as practical debugging effort - but the problem doesn't
> go away.
> 

I am putting a runtime feature to runtime like all runtime features are
at runtime in PHP. The error is hidden during reflection, that is true,
but on purpose! You do not want reflection to error out while you are
performing introspection on a data structure.

The annotation reader however will error out in the moment you try to
access something. This separation of concern makes it actually easier
and is in the vain of good software development too.

I understand what you want to solve. I am just telling you that this is
the wrong approach and others are telling it to you too.

-- 
Richard "Fleshgrinder" Fussenegger

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to