Re: [PHP-DEV] Traits and Properties

2011-01-06 Thread Stefan Marr
Hi Jonathan:

Sorry, was not able to get back to those discussions earlier.


On 22 Dec 2010, at 16:39, Jonathan Bond-Caron wrote:

 There are two remaining questions I have:
 1) How do traits affect the reflection API?
Johannes implemented some features in the Reflection API.

However, they are very ad-hoc, and there are some points which could be 
designed differently to make the concepts more clear.

On of those things is that you actually use ReflectionClass to reflect on a 
trait.
That is really an implementation detail, and should be changed to not confuse 
anyone on a conceptional level. We should not expose that kind of 
engine/implementation detail.

Thus, there remains stuff to be done about reflection. In general, I would like 
to be able to access all information that was in the source code. However, time 
constraints are an issue for me. If there would be a new release date for an 
alpha or something, I think I could get some time to work on it...


 2) Do we want to be able to declare trait requirements for properties and
 methods? If so what syntax?
Well, there was the proposal to use require to express constraints for the 
composing class, which is something I liked.

However, I would not go to support properties, too, since I still maintain the 
opinion that we do not actually do something about state with regard to traits. 


 
 A note on the syntax proposed by Nathan:
 trait require Foo
 
 An option could be:
 
 trait Foo {
  require {
 public $var;
 function ratio();
  }

Hm, well, we already got abstract methods for the methods part.


 trait Bar {
  require interface Iterator;
 }
And expressing the requirement for an interface or an abstract class seems to 
be the only thing missing, I think.

However, I would not put that in the body but into the hat.

trait Bar require OneSpecificClass, AndPossiblyAnInterface, 
OrPossiblyAnotherInterface {}


 
 The idea comes from:
 http://code.google.com/p/es-lab/wiki/Traits
 
 I found this trying to look for alternative keyword for 'require'.
Yes, Tom worked on that a while ago, but it was to easy to implement it in a 
library for JavaScript. To easy to be considered for a language feature...

Best regards
Stefan

-- 
Stefan Marr
Software Languages Lab
Vrije Universiteit Brussel
Pleinlaan 2 / B-1050 Brussels / Belgium
http://soft.vub.ac.be/~smarr
Phone: +32 2 629 2974
Fax:   +32 2 629 3525


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



Re: [PHP-DEV] Traits and Properties

2011-01-06 Thread Stefan Marr
Hi Larry:

On 21 Dec 2010, at 03:24, Larry Garfield wrote:

 I don't believe the RFC mentions how those resolve in case of collision, 
 though.  If two traits define the same abstract method, does that cause a 
 collision that needs manual resolution or can the using class just define it 
 once and thereby support both traits?
Abstract methods do not cause collisions, no. So, there can be an arbitrary 
number of traits asking for an abstract method with identical name, and the 
only thing that has to happen is that it is implemented eventually, perhaps by 
another trait.

Best regards
Stefan

-- 
Stefan Marr
Software Languages Lab
Vrije Universiteit Brussel
Pleinlaan 2 / B-1050 Brussels / Belgium
http://soft.vub.ac.be/~smarr
Phone: +32 2 629 2974
Fax:   +32 2 629 3525


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



Re: [PHP-DEV] RFC: about class names as values

2011-01-06 Thread Martin Scotta
Yes, my intention was to only add a magic constant with the class, similar
to this

namespace Bar {
  class Foo {
const KLASS = __CLASS__;
  }
}

namespace Buzz {
  use \Bar\Foo as BazFoo;

  class Bar extends BazFoo {
const KLASS = __CLASS__;
  }

  $bar = new Bar;
  $baz = new BazFoo;

  var_dump( get_class($baz), BazFoo::KLASS);
  var_dump( get_class($bar), Bar::KLASS );
}

This is 100% valid PHP 5.3.3 code, but that includes a lot of effort from
the developer. Someone miss to include the KLASS constant on a class and the
result is undefined.

If that PHP could add a magic constant --named CLASS or whatever you like--
to each class it will reduce the amount of class names hardcoded onto
strings, probably to zero.

The only issue that I found today is related to interfaces. I'm not sure if
they should include this sort of magic constant, but I would rather include
them just for consistency but, as I previously said, I'm not sure about this
one.

 Martin Scotta


2011/1/5 John LeSueur john.lesu...@gmail.com



 2011/1/5 Johannes Schlüter johan...@php.net

 On Wed, 2011-01-05 at 21:53 -0300, Martin Scotta wrote:
  $obj = newInstance( MyClass ); // notice. undefined constant MyClass

 This describes the major change with your idea.

 What happens if a constant MyClass exists?

 Another question is something like this:

 ?php
 function  factory($class) {
return new $class();
 }

 factory( SomeClass );
 ?


 To proper support this we'd have to make classes first class elements.
 For making this consistent it would make sense to make functions first
 class elements. And best drop the $ in front of variables and create a
 new language. Everything else becomes a mess.

 johannes



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


 I think he's actually proposing creating for each class the magic class
 constant CLASS, so your example becomes:


 ?php

 function factory($class) {
 return new $class();
 }

 factory( SomeClass::CLASS );

 ?

 This is actually doable without a magic class constant, but requires a
 function or class constant to be declared in each class.

 ?php
 class SomeClass {
 const CLASS = __NAMESPACE__ . '\' . __CLASS__;
 static function getNameWithNSPath()
 {
 return __NAMESPACE__ . '\' . __CLASS__;
 }
 }


 factory( SomeClass::getNameWithNSPath() );
 ?

 Perhaps this could be simplified with traits, if __NAMESPACE__ and
 __CLASS__ work in traits that way. In fact, that's an interesting question,
 what is __NAMESPACE__ in a trait defined in one namespace, then used in a
 class in a different namespace?

 I think the point is that the factory function could exist without any
 knowledge of the namespaces of the classes it would work on. Then, somewhere
 else where the class has been aliased or is otherwise accessible without the
 full namespace path, the developer wouldn't need to specify the full
 namespace path to the factory, but could ask the class itself what it's full
 namespace path was. I don't know that I agree with the idea, but I don't
 think it requires making classes first class elements.

 John




Re: [PHP-DEV] Traits and Properties

2011-01-06 Thread Johannes Schlüter
On Thu, 2011-01-06 at 14:38 +0100, Stefan Marr wrote:
 
 On of those things is that you actually use ReflectionClass to reflect
 on a trait.
 That is really an implementation detail, and should be changed to not
 confuse anyone on a conceptional level. We should not expose that kind
 of engine/implementation detail.

This is the same with interfaces. What does class_exists('some_trait')
do? - I assume that returns true too.

 Thus, there remains stuff to be done about reflection. In general, I
 would like to be able to access all information that was in the source
 code. However, time constraints are an issue for me. If there would be
 a new release date for an alpha or something, I think I could get some
 time to work on it...

I hoped to do some work on it over Christmas vacation, too, but did
other stuff in the end ...

johannes



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



RE: [PHP-DEV] Extensions to traits

2011-01-06 Thread Jonathan Bond-Caron
On Sun Jan 2 07:16 AM, Ben Schmidt wrote:
 I would also like to propose some extensions to the functionality as 
 currently described, which I think could potentially add tremendous 
 power to the mechanism, with relatively little additional conceptual 
 complexity and implementation effort. I've written it up as a bit of a 
 proposal below.
 
 I'd love to hear what you think.
 

- New ideas are always welcome
- Don't write long e-mails to a mailing list, write an RFC
http://wiki.php.net/rfc?do=register

- Don't overuse the word 'simple'

IMHO, if something is simple it should take 1-2 days to create a patch. That 
doesn't seem to be the case with what you're proposing.
But feel free to prove me wrong :)

Creating a patch will help getting feedback about what you're proposing
http://ca3.php.net/reST/php-src/README.MAILINGLIST_RULES



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



Re: [PHP-DEV] Extensions to traits

2011-01-06 Thread Stefan Marr
Hi Ben:

On 02 Jan 2011, at 13:16, Ben Schmidt wrote:

 While it's still in the pre-release stage, though, I would like to put
 in a vote for the assignment syntax: I think it is a lot easier to read
 and understand than the 'insteadof' syntax.
The reason to go with insteadof is that the assignment syntax hides changes 
that might cause problems.
Thus, when you change any of the traits participating in a composition in a way 
that a conflict would be introduced, the assignment syntax is hiding this. With 
the insteadof syntax you are actually forced to reevaluate whether your code 
still makes sense and include the offending change explicitly.




 There are two limitations of traits in their current implementation for
 which I would like to propose extensions. The first limitation is that
 traits can very easily break, particularly when methods are omitted from
 classes in which the rest of the trait is used
Ehm, not sure I follow what you are getting at.
One thing to emphasize here is the explicit design choice to use the insteadof.
This does not only have the mentioned benefit of making problematic changes in 
the traits hierarchy explicit, but the second reason to go with this design was 
the wish to have a 'exclude' operator without actually having a full-exclude 
operator. Thus, there is no way that you can leave out arbitrary methods from a 
trait.
That means, you cannot build compositions which suddenly miss certain expected 
method implementations.

Well, of course, you can always build bugs into the code, but that is not 
different from the standard situation. You can always call arbitrary method 
names that just do not exist. Traits do not protect you from that. But the 
current design, protects you from explicitly allowing you to shot yourself in 
the foot.



 , or shadowed by method
 definitions in the class proper. The second limitation is that the trait
 overriding semantics are impoverished and needlessly restrictive.
Hm, don't understand you here either. I needed to look up what impoverished 
actually means, you are not insulting me here, right? Just kidding ;)



 Incorrect method calls spring from the way trait methods can be omitted
 from classes where the rest of the trait is used, or shadowed by methods
 defined in the class proper. In either of these scenarios, any call in a
 trait to such a method may not call the method that was originally
 intended--they may fail, or they may call a different method, with
 unpredictable results. Of course, sometimes such a behaviour is
 desirable, if writing a trait which communicates with the rest of the
 class by means of method calls, yet provides a fallback methods in case
 the class author does not wish to provide such methods. However, when it
 is not intended, this could lead to incorrect and difficult-to-pinpoint
 behaviour.
Ok, now I see what you are getting at.
And my answer to that is: If you require your trait to guarantee a certain 
non-trivial invariants, then well, what you are actually doing is something 
which should become a class with all its benefits.
Traits are not intended to replace classes as a mechanism to structure code, 
but they should supplement it.

However, I am open to votes on these things since I do not have any reason to 
believe that my standpoint is  especially useful or superior, thats just how I 
understand what traits are useful for.


 trait ErrorReporting {
   public function error($message) {
  $this-print($message);
   }
   private function print($message) {
  fputs($this-output,$message.\n);
   }
 }
 
 class Printer {
   use ErrorReporting;
   public $output=null;
   public function print($document) {
  /* Send the document to the printer--$this-output. */
  /* ... */
  if (there_was_an_error()) {
 $this-error(printing failed);
  }
  /* ... */
   }
 }
Ok, to summarize the example, you get a recursion because there is a naming 
problem, i.e., incompatibility between the used trait and the composing class.


 No error or warning will be
 generated, but the class will not work as intended; probably it will
 infinitely recurse; a nasty problem to track down.
 Furthermore, even if the incorrect method call didn't occur, there would
 be data-sharing problems, as both the ErrorReporting trait and the
 class' print() function make use of the $output data member,
 unintentially sharing data.
Well, short answer: it is compiler-assisted copy-and-past, why isn't that trait 
just providing the glue that gets your class the necessary functionality to use 
a proper ErrorReporting class?
Sorry, I know not a really helpful answer, but I hope that examples shows how I 
see traits.
They are for reusing code in situations where the other concepts just break 
down. Not meant to replace those.


 
 Proposal
 
 
 I suggest these problems should be solved from two angles. Firstly,
 additional warnings should be triggered to alert the programmer to the
 problems, and secondly, the 

Re: [PHP-DEV] Extensions to traits

2011-01-06 Thread Stefan Marr
Hi Ben:

Here the second part, on your extension proposal.

On 02 Jan 2011, at 13:16, Ben Schmidt wrote:

 Extension
 - - - - -
 
 I suggest these two problems can be simply solved by introducing two
 additional uses of the trait keyword: as a scoping keyword and an access
 specifier.
 
 As a scoping keyword, it would be used analogously to self. Method calls
 such as $this-print() could be replaced with trait::print() when the
 programmer desires to ensure that their trait method, and only their
 trait method, is called--when there is no intention that overriding
 should be possible. It would only be able to be used in a trait, and
 could only be used to reference methods or properties defined in the
 same trait, using their original name.
 
 As an access specifier, it would be used instead of public, private,
 etc. in trait definitions, to mean that the member (data or method) can
 and can only be accessed using the mechanism above (trait::).

Ok, that would actually get us around all the meta-programming problems.
When you say that the 'trait'-access modifier always requires the access via a 
specific keyword (trait::) then mangling the name should be possible.
On the other hand, what would iterating over the object properties show?
Multiple properties with the same name, like with inherited private properties 
I suppose?

And an occurrence of trait:: would mean, do a $this- but mangle the name first 
with the trait's name the original definition was in. Should be possible, but 
would certainly impact the Zend Engine a bit more than what we have now.

Certainly an interesting approach.


Has someone else an opinion on that?



 
 
 Overriding
 ==
 
 Limitation
 --
 
 At present, the overriding semantics of traits are that a method defined
 in a class proper overrides a method defined in a used trait which in
 turn overrides a method defined in an ancestor class.
Bye the way, where comes that terminology from: class proper? We are talking 
about the body of a class, right?

Well, but I will stop here, and try to cover the rest in the next mail...

Best regards
Stefan


-- 
Stefan Marr
Software Languages Lab
Vrije Universiteit Brussel
Pleinlaan 2 / B-1050 Brussels / Belgium
http://soft.vub.ac.be/~smarr
Phone: +32 2 629 2974
Fax:   +32 2 629 3525


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



Re: [PHP-DEV] Extensions to traits

2011-01-06 Thread Stefan Marr
Hi Ben:

On 02 Jan 2011, at 13:16, Ben Schmidt wrote:
 Proposal
 
 
 I would therefore like to propose an extension backwards-compatible with
 the current trait implementation. I will, however, extend the assignment
 syntax, rather than the 'insteadof' syntax, as I find that clearer, and
 more amenable to this extension. Of course, though, other syntaxes could
 be found.
 
 There are four aspects to this extension: (1) Introducing a new scoping
 keyword. (2) Allowing a method name to be used from multiple traits. (3)
 Allowing a trait to be included multiple times.
 
 (1) Introducing a new scoping keyword.
 - - - - - - - - - - - - - - - - - - -
 
 I suggest something such as 'prev', to refer to the previous definition
 of the method. Similar to 'parent', and the same in the absence of
 traits, this refers to the 'next higher definition in the trait
 hierarchy'; the 'trait hierarchy' is pictured like the 'class hierarchy'
 but including traits. So if 'prev' is used in a class method when a
 trait method of the same name exists, it will refer to the trait method,
 rather than referring to a method in a parent class. Alternatively, the
 'parent' keyword meaning could be changed to have this meaning. My
 apologies if this is already the case: I have not played with the
 implementation in the trunk (though look forward to doing so at some
 stage) so am basing my comments purely on the RFC.
 
 (2) Allowing a method name to be used from multiple traits.
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
 When multiple methods of the same name are defined they simply take
 their place in the 'trait hierarchy' and can be accessed by means of
 'prev' (see (1) above).
 
 So we could write, for instance:
 
   trait Hello {
  public function sayIt() {
 echo Hello ;
  }
   }
   trait World {
  public function sayIt() {
 prev::sayIt();
 echo world ;
  }
   }
   class HelloWorld {
  use Hello, World {
 sayIt = Hello::sayIt, World::sayIt;
  }
  public function sayIt() {
 prev::sayIt();
 echo !\n;
  }
   }
   $o = new HelloWorld();
   $o-sayIt();
   // Outputs Hello world !\n
 
 sayIt() in the class overrides sayIt() in World, which overrides sayIt()
 in Hello, but all are included. The first two make use of 'prev' to
 reference those higher up the hierarchy.
Hm, after writing the part of my mail below, and coming back here,
why can't you use aliases for that kind of problem?

Instead of the prev:: stuff, you could just introduce an alias for the method 
you are 'hiding'. That should provide you with identical properties. And it 
would avoid 'magic' and weakening the flattening. Furthermore, traits are very 
explicit in what they do bring into your class at the moment, that would get 
lost with the approach required for 'prev::'.




 
 (3) Allowing a trait to be included multiple times.
 - - - - - - - - - - - - - - - - - - - - - - - - - -

I still do not know what to say to the previous proposal, the 'prev' stuff.
But, this one gets a reject, because you actually want to use classes here.
I do not see the benefit of using a trait here instead of a class for your 
queues.

Or you might want to elaborate why this design is better than one that uses 
proper objects.


   abstract class ActiveRecord {
  protected $new;
  protected $id;
  protected $other_values;
  protected function __construct($id,$values,$new) {
 $this-id=$id;
 $this-other_values=$values;
 $this-new=$new;
  }
  public function save() {
 if ($this-new) {
if (!create_in_the_database()) return false;
if ($this-id===null) $this-id=last_insert_id();
 } else {
if (!update_in_the_database()) return false;
 }
 return true;
  }
  public static function new() {
 return new static(null,static::$default_values,true);
  }
  public static function get($id) {
 return new static($id,get_from_the_database(),false);
  }
   }
   trait LoggingOperations {
  public function save() {
 if ($this-new) {
log(Creating .get_called_class());
 } else {
log(Updating .get_called_class(). ID .$this-id);
 }
 if (!prev::save()) {
log(Failed);
return false;
 }
 log(Succeeded);
 return true;
  }
   }
   trait EnsuringNoConcurrentChanges {
  trait $original_values = array();
  protected function setOriginalValues($values) {
 trait::$original_values = $values;
  }
  public static function get($id) {
 $record = prev::get($id);
 $record-setOriginalValues($record-other_values);
 return $record;
  }
  public function save() {
 $current_values=select_from_database();
 if ($this-new$current_values) return false;
 if (!$this-new!$current_values) return false;