[PHP-DEV] SVN Account Request: dominis

2011-01-08 Thread Nandor Sivok
Maintaining the documentation
Maintaining an official, bundled PHP extension

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

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

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,

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, 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] RFC: about class names as values

2011-01-08 Thread Ben Schmidt

I think doing something like this is a good idea for classes and
interfaces.

Ben.



On 7/01/11 1:16 AM, Martin Scotta wrote:

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




2011/1/5 Johannes Schlüter


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:




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:




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



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






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