Re: [PHP-DEV] Extensions to traits

2011-02-23 Thread Ben Schmidt

On 13/02/11 9:15 PM, André Rømcke wrote:

On Thu, Feb 10, 2011 at 6:25 PM, Ben Schmidt
mail_ben_schm...@yahoo.com.auwrote:


On 11/02/11 3:37 AM, Philip Olson wrote:


You now have rights to the wiki rfc namespace.



Thanks a lot, Philip.

I have now made an RFC based on the most recent discussions:

http://wiki.php.net/rfc/traitsmodifications

I think this is a more solid proposal than my original one, and I hope
we can continue to discuss it and agree to the extent that it's worth
starting an implementation.

Please read it and comment whenever you can find some time, guys!




As for your first example:


trait T {
public function foo() {
   echohttp://www.php.net/echo  T;
}}class C {
use T;
public function foo() {
   echohttp://www.php.net/echo  C;
}}


I think it would sometimes be desirable to allow this, for instance when a
trait has been updated in a framework to adapt to what has become common
practice in classes that uses it in the wild.
( I assume you already get error if function signature is different like in
inheritance? )

So to allow both cases, what about letting people use the final keyword on
functions to signal functions that can not be re declared without alias. Or
better, add a new keyword since final should mean final.


I don't mind that idea all that much, but perhaps doing the reverse
makes more sense: allowing a trait author to add a keyword to methods
which they intend and expect class authors to shadow. This means the
status quo is leaning towards stability, not breakages. Perhaps we could
reuse the 'default' keyword for this? That would indicate that the trait
has provided a default implementation of this method, but expects the
class author may well provide a more specialised implementation. Best
practice would then dictate that a responsible trait author should only
provide a default method for methods that were previously abstract
methods of the trait, so things wouldn't break, but traits can still
adapt to common practice, as you say.

So then this would generate an error, which could be resolved with an
insteadof in the use block:

trait T {
public function foo() {
   echo T;
}
}
class C {
use T;
public function foo() {
   echo C;
}
}

But this would not:

trait T {
default public function foo() {
   echo T;
}
}
class C {
use T;
public function foo() {
   echo C;
}
}

How does that sound?

Ben.




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



Re: [PHP-DEV] Extensions to traits

2011-02-23 Thread Ben Schmidt

That might seem odd but it's not inheritance.


Yeah. And that's my main concern with it. It seems like inheritance (and
is described like inheritance in the RFC at present--which is a
documentation issue that will need to be addressed in the manual
eventually), but it isn't. I feel it should be one or the other: either
have full inheritance semantics, or have full conflict-resolution
semantics like when trait methods conflict, at least by default. I think
the latter is better.

I'm really warming to the idea of using 'default' as I proposed in my
last email, though, as essentially doing what André suggested 'in
reverse'--i.e. a 'non-final' marker.

Ben.





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



Re: [PHP-DEV] Extensions to traits

2011-02-23 Thread Ben Schmidt

http://wiki.php.net/rfc/traitsmodifications



Some thoughts:

a) Class method conflict with trait

Class implementation always wins I feel is the right way to think about
traits.

But 'abstract' already has special meaning, so maybe a keyword like 'final'
could also do something special.


André had the same kinds of feelings. I feel marking 'non-final' would
be better, and suggest using 'default' for this purpose. See my earlier
email for more details and reasoning.


b) Support for 'non-breakable traits'

  - Add trait-local scope

Really like the idea and how this could make traits less fragile.
e.g.
trait Foo {
   trait $bar;
   public $bar;
}

Could change the syntax to:
trait Foo {
   var $bar = 'visibleByTrait'; // variable private to the trait --
zend_mangle_property_name('#Foo {NULL} bar')
   public $bar = 'visibleByClass';  // variable public to the class it gets
composed in
}

class Test {
   use Foo;
}

$t = new Test;
echo $t-bar; // 'visibleByClass'

Seems like it could allow traits to have their own independent state
(private properties), internally ~ zend_mangle_property_name('#' trait name
{NULL} prop name).

Small note: is there a plan to drop the T_VAR token?

Any objections, concerns, more thoughts on the concept?


I think it needs to work for methods as well as properties, so think the
'trait' keyword is better than the 'var' keyword for that reason. It
would seem strange prefixing a method with 'var'.


c)  Extend 'use' syntax

Didn't quite understand, will read again.
Have you thought about how this could affect the reflection api and
documentation?


Yes, I had thought about it a bit. Now I've thought a bit further.

When extended syntax is just moving class and trait methods around
(essentially either duplicating them or omitting them), the reflection
API should just work on the results of that movement. I presume that is
what happens with traits.

When extended syntax is generating forwarding functions, I expect the
reflection API to return details of those forwarding functions. It can't
do anything else, as due to PHP's dynamic nature, the functions being
forwarded to are not immutable. I would document it as a forwarding
function generation mechanism, too, so confusion is avoided.

Having thought about it a bit further now, though, the reflection API is
arguably a bit useless in this case. Perhaps to mitigate this, a new
method could be added to ReflectionMethod to find details of the target
of a forwarding method for a particular object (at the particular time
the method is invoked).

Ben.




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



RE: [PHP-DEV] Extensions to traits

2011-02-15 Thread Jonathan Bond-Caron
On Sun Feb 13 05:15 AM, André Rømcke wrote:
 
  I have now made an RFC based on the most recent discussions:
 
  http://wiki.php.net/rfc/traitsmodifications
 
 
 I think it would sometimes be desirable to allow this, for instance 
 when a trait has been updated in a framework to adapt to what has 
 become common practice in classes that uses it in the wild.
 ( I assume you already get error if function signature is different 
 like in inheritance? )
 
 So to allow both cases, what about letting people use the final 
 keyword on functions to signal functions that cannot be re declared 
 without alias. Or better, add a new keyword since final should mean 
 final.
 

I find the implementation in trunk convenient, traits aren't meant to replace 
inheritance  ~polymorphism.

The 'final' keyword currently means nothing to the class:
trait Foo {
final static function test() {
return 'Test';
}
}

class A {
use Foo;
static function test() {
return 'Test2';
}
}

echo A::test(); // returns 'Test2' in trunk

That might seem odd but it's not inheritance.
There is no error if the class method signature is different from a trait.
I'm comfortable with 'the class always wins', not really sure if should I be 
thinking differently...

It makes a trait somewhat fragile but that's part of the design vs. grafts. 



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



RE: [PHP-DEV] Extensions to traits

2011-02-15 Thread Jonathan Bond-Caron
On Thu Feb 10 12:25 PM, Ben Schmidt wrote:
 
 http://wiki.php.net/rfc/traitsmodifications
 

Some thoughts:

a) Class method conflict with trait

Class implementation always wins I feel is the right way to think about
traits.

But 'abstract' already has special meaning, so maybe a keyword like 'final'
could also do something special.

b) Support for 'non-breakable traits'

 - Add trait-local scope

Really like the idea and how this could make traits less fragile. 
e.g.
trait Foo {
  trait $bar;   
  public $bar;
}

Could change the syntax to:
trait Foo {
  var $bar = 'visibleByTrait'; // variable private to the trait --
zend_mangle_property_name('#Foo {NULL} bar')
  public $bar = 'visibleByClass';  // variable public to the class it gets
composed in
}

class Test {
  use Foo;
}

$t = new Test;
echo $t-bar; // 'visibleByClass'

Seems like it could allow traits to have their own independent state
(private properties), internally ~ zend_mangle_property_name('#' trait name
{NULL} prop name).

Small note: is there a plan to drop the T_VAR token?

Any objections, concerns, more thoughts on the concept?

c)  Extend 'use' syntax

Didn't quite understand, will read again.
Have you thought about how this could affect the reflection api and
documentation?



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



Re: [PHP-DEV] Extensions to traits

2011-02-13 Thread André Rømcke
On Thu, Feb 10, 2011 at 6:25 PM, Ben Schmidt
mail_ben_schm...@yahoo.com.auwrote:

 On 11/02/11 3:37 AM, Philip Olson wrote:

 You now have rights to the wiki rfc namespace.


 Thanks a lot, Philip.

 I have now made an RFC based on the most recent discussions:

 http://wiki.php.net/rfc/traitsmodifications

 I think this is a more solid proposal than my original one, and I hope
 we can continue to discuss it and agree to the extent that it's worth
 starting an implementation.

 Please read it and comment whenever you can find some time, guys!



As for your first example:


trait T {
   public function foo() {
  echo http://www.php.net/echo T;
   }}class C {
   use T;
   public function foo() {
  echo http://www.php.net/echo C;
   }}


I think it would sometimes be desirable to allow this, for instance when a
trait has been updated in a framework to adapt to what has become common
practice in classes that uses it in the wild.
( I assume you already get error if function signature is different like in
inheritance? )

So to allow both cases, what about letting people use the final keyword on
functions to signal functions that can not be re declared without alias. Or
better, add a new keyword since final should mean final.

My 2 Euro cents,

André


Re: [PHP-DEV] Extensions to traits

2011-02-10 Thread Philip Olson

On Feb 9, 2011, at 9:55 PM, Ben Schmidt wrote:

 - Don't write long e-mails to a mailing list, write an RFC
 http://wiki.php.net/rfc?do=register
 
 OK. I tried to do this. I got an account (username:isfs), but it seems
 it is nothing more than an unprivileged account--I don't seem to be able
 to edit or add pages at all. What do I need to do to be granted some?

Greetings Ben,

You now have rights to the wiki rfc namespace.

Regards,
Philip


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



Re: [PHP-DEV] Extensions to traits

2011-02-10 Thread Ben Schmidt

On 11/02/11 3:37 AM, Philip Olson wrote:

You now have rights to the wiki rfc namespace.


Thanks a lot, Philip.

I have now made an RFC based on the most recent discussions:

http://wiki.php.net/rfc/traitsmodifications

I think this is a more solid proposal than my original one, and I hope
we can continue to discuss it and agree to the extent that it's worth
starting an implementation.

Please read it and comment whenever you can find some time, guys!

Cheers,

Ben.


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



Re: [PHP-DEV] Extensions to traits

2011-02-09 Thread Ben Schmidt

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


OK. I tried to do this. I got an account (username:isfs), but it seems
it is nothing more than an unprivileged account--I don't seem to be able
to edit or add pages at all. What do I need to do to be granted some?

Thanks,

Ben.




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



RE: [PHP-DEV] Extensions to traits

2011-01-09 Thread Jonathan Bond-Caron
On Sat Jan 8 06:33 AM, Ben Schmidt wrote:
 
  Creating a patch will help getting feedback about what you're 
  proposing http://ca3.php.net/reST/php-src/README.MAILINGLIST_RULES
 
 I hope I haven't broken any of the mailing list rules, but my 
 apologies if I have, and please point out specifically where I've gone 
 wrong.
 

No rules broken in my opinion but in general consider:
http://www.faqs.org/rfcs/rfc1855.html
Over 100 lines is considered long

The proposal (473 lines of plain text) would be easier to read on the web with 
some markup.

 As far as a patch goes, I don't think that is appropriate at this 
 stage.
 I don't want to spend a lot of time creating a patch only to have it 
 rejected if this could be avoided by a little discussion. My time is 
 too valuable to me to waste like that, and with something as 
 controversial as this, there's a real danger of that happening.
 

Np, since you mentioned hacking the source I thought you had done some 
tinkering.



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



Re: [PHP-DEV] Extensions to traits

2011-01-08 Thread Ben Schmidt

Hi, Jonathan,

On 7/01/11 4:42 AM, Jonathan Bond-Caron wrote:

- New ideas are always welcome


That's great to hear!


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


Sure. Once I've digested and responded to Stefan's replies, I'll work on
putting something up there.

Perhaps this advice would be worth adding to the mailing list rules
page, as nothing about post length is mentioned there at all; it only
talks about attachments.


- 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 :)


Yeah, well, I meant simple conceptually, and relatively speaking, not
that it wouldn't take time and effort. I don't think I'll be proving you
wrong! But as I said, I am willing to get my hands dirty with this.


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


I hope I haven't broken any of the mailing list rules, but my apologies
if I have, and please point out specifically where I've gone wrong.

As far as a patch goes, I don't think that is appropriate at this stage.
I don't want to spend a lot of time creating a patch only to have it
rejected if this could be avoided by a little discussion. My time is too
valuable to me to waste like that, and with something as controversial
as this, there's a real danger of that happening.

Cheers,

Ben.




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



Re: [PHP-DEV] Extensions to traits

2011-01-08 Thread Ben Schmidt

Hi, Stefan,

Thanks for considering my ideas so carefully and for your detailed
replies.


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.


OK. That makes sense. I'll rework any surviving parts of my proposal to
be based on the insteadof syntax.


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.


This seems wrong to me. Doesn't it go against the stated principle that
the class author should have full control of traits? How is it full
control if you can't exclude a method? What is the reasoning behind this
wish not to have a full exclude operator?


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 ;)


Sorry. I forget that a lot of you people aren't native English speakers
and sometimes funny words like that slip in! I think all you people who
communicate so fluently in additional languages are amazing.


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.


I agree. I did say it was a poor example. I think the kinds of
behavioural problems it demonstrates, though, could be found in
situations where traits *are* truly appropriate.

No need to argue over examples, though. Plenty of other things to argue
about. :-)


Warnings
- - - -

To avoid silent unintended shadowing, I suggest issuing a warning when a
conflict between trait and class methods occurs. So this would trigger
a warning:

   trait SaySomething {
  public function sayIt() {
 echo Something\n;
  }
   }
   class Sayer {
  use SaySomething;
  public function sayIt() {
 echo Hello world!\n;
  }
   }


Ok, well, we could see the actual class body as another trait, and
require it to follow the same composition rules, and that way make
require the programmer to use insteadof in such a case.

In return that would mean, that traits are not part of the inheritance
chain at all anymore.

Thus, first is the inheritance chain used to build up the
implementation of a class, and afterwards all the traits are composed,
while the original class is seen as another trait.

That idea has certainly something to it.


Yes, I think that would be good.

Having read your other emails, as well as having allowed my proposal
itself to clarify in my mind, I'm beginning to think it might be
clearest and cleverest to avoid inheritance altogether with traits. Of
course, this is in contrast to my original proposal, which was to
increase traits' participation in inheritance.

In this case, parent:: will always do what you expect then, and there's
no need for prev::.

Now to the other emails!

Ben.




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



Re: [PHP-DEV] Extensions to traits

2011-01-08 Thread Ben Schmidt

Hi again, Stefan,

Continuing the conversation.

On 7/01/11 10:18 AM, Stefan Marr wrote:

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?


Well, I hadn't thought about it before. :-)

But yes, I think that makes perfect sense.


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.


One complication I hadn't thought of before is whether it should be
possible to access trait:: methods and properties in different objects.
And if it should be, what syntax to use. $that-trait::method() seems
somewhat ugly to me. That would also suggest we should use
$this-trait::method() for the same-object case.


Certainly an interesting approach.

Has someone else an opinion on that?


I think actually this is the most important part of my proposal, so if
it could be accepted, I would be very pleased. Obviously it does need a
bit more thought and discussion yet, though.


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?


Yes. 'Class proper' = 'class itself'. We seem to use 'proper' in English
as an adjective after a noun with a Latin-like sense of 'own/itself'. I
guess we probably got it from French, and surprisingly it hasn't died
out.

Cheers,

Ben.




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



Re: [PHP-DEV] Extensions to traits

2011-01-08 Thread Ben Schmidt

Hi, Stefan,

I think if the other stuff goes ahead, we can probably scrap what I
originally proposed here. But perhaps something else would be helpful. I
won't comment very specifically on aspects of my original proposal, but
will just raise some new ideas for consideration and further thought.

It all hinges on aliasing: how it works and how it can be avoided when
necessary. Your comment on my example made this most clear.


   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;
 if ($current_values!=trait::$original_values) return false;
 return prev::save();
  }
   }
   trait UsingHashesForIDs {
  public function save() {
 if ($this-id===null) $this-id=random_hash();
 return prev::save();
  }
   }
   class SessionRecord extends ActiveRecord {
  protected static $default_values=array(
 'user'='',
 'time'=''
  );
  use UsingHashesForIDs;
   }
   class Client extends ActiveRecord {
  protected static $default_values=array(
 'user'='',
 'name'='',
 'address'=''
  );
  use EnsuringNoConcurrentChanges, LoggingOperations {
 save = EnsuringNoConcurrentChanges::save,
   LoggingOperations::save;
  }
   }


Ok, that example is, well, not actually helping you.

You can do all the things here without your extensions, I believe.


Before commenting speciically I'd like to point out that whether
something *can* be done shouldn't be the only thing considered. Other
important aspects are how easily it can be done, how tidily it can be
done, how much code duplication it requires, and so on. Sometimes, a
construct by merely providing elegance, without any additional power, is
worthwhile. In fact, you *can* model any program as a Turing machine, so
we actually need very little; but there aren't many popular languages
like that!

In this case, though, I think there are a couple of shortcomings in the
current trait behaviour that mean this can't quite be done reliably.

One thing of note is the use of the trait-scoped property, making the
trait more robust. That was the subject of an earlier email, and one of
the parts of the proposal you viewed most favourably, so I'm happy about
that. I won't dwell on it here.


Your problem with the save methods is solved by aliases and parent::
(parent:: only has semantics with respect to inheritance, so it will
do the right thing.

Your Client will have a save method that calls the aliased versions of
the saves in the order you want.

And in get() you can also just use parent::, no?


Aliases come a long way, and to be honest, I am still coming to terms
with how powerful they are, particularly in combination with traits'
ability to have abstract methods.

But there is at least one missing link.

You can't reliably use parent:: in a trait method, because that
jeopardises the reusability of the trait. In some composing classes, you
might want it to call a method that isn't from the superclass. In this
minimal example, parent:: happens to work; but that shouldn't be relied
upon when writing a trait, and in the generalised case, where there are
more traits and more composition combinations, it would fall apart.

This means at the very least, you would have to use a method declared in
the trait, and then write forwarding methods. In this case, you have
basically 

Re: [PHP-DEV] Extensions to traits

2011-01-08 Thread Ben Schmidt

In fact, this is so nice, could I suggest it would be nice to allow
other delegation-like forwarding to be done like this? You could have
'use' without a trait even, just like this:

use {
   $queue-add as addToQueue;
}

Since the properties' object wouldn't be available at compile time, this
extra ability would probably have to be implemented by basically
generating an addToQueue method, and it wouldn't work with arguments
passed by reference. It would basically be a shorthand for

public function addToQueue() {
   return call_user_func(array($queue,'add'),func_get_args());
}

but much more elegant.


Of course should have been

public function addToQueue() {
   return call_user_func(array($this-queue,'add'),func_get_args());
}

Ben.




--
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;
   

[PHP-DEV] Extensions to traits

2011-01-02 Thread Ben Schmidt

Hello, PHP developers,

I'm new to the list, but have been using PHP for a number of years, have
done a little hacking in the source code, and have an interest in the
development of the language.

Particularly recently I have been reading with a good deal of excitement
Stefan Marr's RFC on 'horizontal reuse' on the PHP Wiki:
http://wiki.php.net/rfc/horizontalreuse

The trait functionality looks like a great start and an innovative
language development, and I'm looking forward to trying it out soon
(when I can find some more time!), and particularly looking forward to
making good use of it when it makes it into a release.

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.

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.

I would be willing to play a part implementing it, too.

Cheers,

Ben.



=
Proposed extensions to traits
=

Background
==

Traits in PHP [1] enable improved code reuse. They can be simplistically
viewed as compiler-assisted copy-and-paste. Methods designed to be
reused can be defined in traits and then these traits can be used in
classes. The traits are 'flattened', so it is as if the trait methods
were defined directly in the class in which they are used. Traits can
access other methods and properties of the class, including those of
other traits. They also fit in with the method overriding system:
methods defined directly in a class override those in used traits, which
in turn override those in ancestor classes.

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, or shadowed by method
definitions in the class proper. The second limitation is that the trait
overriding semantics are impoverished and needlessly restrictive.

Breakability


Limitation
--

There are two main aspects of traits which make them easy to break:
incorrect method calls and unintentionally shared state.

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.

The other way traits can break is by unintentionally sharing state.
Traits may make use of the same data members (not recommended, but
possible), or the same accessors, when each should actually have their
own independent state. Again, this could lead to incorrect and
difficult-to-pinpoint behaviour.

Example
---

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);
  }
  /* ... */
   }
}

This example is very contrived, and hopefully no programmer would be
silly enough to fall into this exact trap. However, it is easy to
imagine more subtle cases where this kind of thing could happen,
particularly as traits and classes are modified from their original
conception.

The ErrorReporting trait allows the programmer to report errors in a
consistent way by using the trait in many classes. It includes a print()
method that is used to print the error to the screen. However, this
method has been unintentionally shadowed by a print method in the class,
intended to print a document on a printer. 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,