Hi,
I think traits will lend themselves to frequent runtime checking against the
type of class in which they were used. Consider a trait designed for use
with an Iterator class; the first thing might be to check the type of $this.
<?php
trait InnerIteratorImpl {
public function apply() {
if(!$this instanceof Iterator)
throw new UnexpectedValueException(get_class($this) . ' not an
Iterator ..');
...
}
}
?>
do you not think checks like this will be common / messy / performance
costly; is there something i'm missing?
thx,
-nathan
Hi Nathan:
Hi,
I think traits will lend themselves to frequent runtime checking against the
type of class in which they were used. Consider a trait designed for use
with an Iterator class; the first thing might be to check the type of $this.
Why would you need such a check?
You want to ensure that the class that is using your trait obeys a certain interface, right?
More specifically, you need it to implement a number of methods of an interface, correct?
So, why not asking for it explicitly?
<?php
trait InnerIteratorImpl {
abstract function next()
;
public function apply() {
do somthing with $this->next() ...
}
}
?>
Does that what you want it to do?
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
Hi Nathan:
Hi,
I think traits will lend themselves to frequent runtime checking against
the
type of class in which they were used. Consider a trait designed for use
with an Iterator class; the first thing might be to check the type of
$this.
Why would you need such a check?
To avoid a fatal error at runtime.
You want to ensure that the class that is using your trait obeys a certain
interface, right?
Not really, it's so the trait can guarantee the class it has been used with
implements a given interface that it may need to accomplish its job.
More specifically, you need it to implement a number of methods of an
interface, correct?
So, why not asking for it explicitly?<?php
trait InnerIteratorImpl {
abstract functionnext()
;public function apply() {
do somthing with $this->next() ...
}
}
?>Does that what you want it to do?
Not really, in this example above the trait is self-contained, implementing
all the methods of a particular interface so it's reasonable to expect from
one of the methods in the trait, another of the Iterator interface to be
there.
What I'm getting at is the scenario when a trait is designed to be used in
concert with the class in which it is being used. In this case the trait
expects certain functions to be available on the class in which it is used
with. If the methods aren't there (or checked for at runtime) a fatal error
is raised.
A quick example
<?php
class A {
use AHelper;
function blah() {}
}
trait AHelper {
function meh() {
// hoping we get used w/ instances of A ...
return $this->blah() * 5;
}
}
class B {
use AHelper;
/// waiting for a runtime error if blah() is ever called ..
}
?>
Do you see what I mean?
-nathan
Hi Nathan:
What I'm getting at is the scenario when a trait is designed to be used in
concert with the class in which it is being used. In this case the trait
expects certain functions to be available on the class in which it is used
with. If the methods aren't there (or checked for at runtime) a fatal error
is raised.A quick example
<?php
class A {
use AHelper;function blah() {}
}trait AHelper {
function meh() {
// hoping we get used w/ instances of A ...
return $this->blah() * 5;
}
}class B {
use AHelper;/// waiting for a runtime error if blah() is ever called ..
}
?>Do you see what I mean?
No, do not really see what you are getting at.
How is your approach using the instanceof checks (from the first mail) different from changing AHelper to require blah() by stating this requirement using an abstract method definition?
For the trait it is not important where that method is implemented, it just has to be in the final composed class.
So, why don't you want the following trait?
trait AHelper {
abstract function blah();
function meh() {
// hoping we get used w/ instances of A ...
return $this->blah() * 5;
}
}
You want to avoid the fatal error during runtime, right?
Do you prefer dynamic checks over compile time checks?
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
Personally, I believed that traits are a compile time injection to a
class, so that at runtime a class behaves completely as it would if trait
methods were implemented directly in the class. That said, everything like
trait requirements for a certain interface, should be done at compile time
and constructions like abstract foo(); in a trait serve that purpose. IMHO.
2010/12/10 Stefan Marr php@stefan-marr.de
Hi Nathan:
What I'm getting at is the scenario when a trait is designed to be used
in
concert with the class in which it is being used. In this case the trait
expects certain functions to be available on the class in which it is
used
with. If the methods aren't there (or checked for at runtime) a fatal
error
is raised.A quick example
<?php
class A {
use AHelper;function blah() {}
}trait AHelper {
function meh() {
// hoping we get used w/ instances of A ...
return $this->blah() * 5;
}
}class B {
use AHelper;/// waiting for a runtime error if blah() is ever called ..
}
?>Do you see what I mean?
No, do not really see what you are getting at.How is your approach using the instanceof checks (from the first mail)
different from changing AHelper to require blah() by stating this
requirement using an abstract method definition?
For the trait it is not important where that method is implemented, it just
has to be in the final composed class.So, why don't you want the following trait?
trait AHelper {
abstract function blah();function meh() {
// hoping we get used w/ instances of A ...
return $this->blah() * 5;
}}
You want to avoid the fatal error during runtime, right?
Do you prefer dynamic checks over compile time checks?
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--
--
С уважением,
Виктор
Hi Nathan:
What I'm getting at is the scenario when a trait is designed to be used
in
concert with the class in which it is being used. In this case the trait
expects certain functions to be available on the class in which it is
used
with. If the methods aren't there (or checked for at runtime) a fatal
error
is raised.A quick example
<?php
class A {
use AHelper;function blah() {}
}trait AHelper {
function meh() {
// hoping we get used w/ instances of A ...
return $this->blah() * 5;
}
}class B {
use AHelper;/// waiting for a runtime error if blah() is ever called ..
}
?>Do you see what I mean?
No, do not really see what you are getting at.How is your approach using the instanceof checks (from the first mail)
different from changing AHelper to require blah() by stating this
requirement using an abstract method definition?
For the trait it is not important where that method is implemented, it just
has to be in the final composed class.So, why don't you want the following trait?
trait AHelper {
abstract function blah();function meh() {
// hoping we get used w/ instances of A ...
return $this->blah() * 5;
}}
Ahh, I see how the abstract methods are working in traits now, I didn't
catch that from your first post; thanks for showing that to me.
You want to avoid the fatal error during runtime, right?
Yes, exactly, and the runtime check for expected interface / class / method.
Do you prefer dynamic checks over compile time checks?
Def not :D, however, I still think this paradigm is lacking. Don't you
think it makes more sense if I write a trait that expects a given interface
or class to be able to specify said interface/class in it's entirety with
just a single identifier rather than listing out all the methods?
For example, I think this would be ugly
<?php
trait IteratorHelper{
abstract public current()
;
abstract public key()
;
abstract public next()
;
abstract public rewind()
;
abstract public valid();
}
?>
essentially you're redeclaring the entire interface in the trait, the same
would be true of the public interface of an expected class. i think it
would be much more elegant to allow a specification on the trait declaration
itself, something like
<?php
trait IteratorHelper expects Iterator {
...
}
?>
-nathan
Hi Nathan:
Def not :D, however, I still think this paradigm is lacking. Don't you think it makes more sense if I write a trait that expects a given interface or class to be able to specify said interface/class in it's entirety with just a single identifier rather than listing out all the methods?
For example, I think this would be ugly
<?php
trait IteratorHelper{
abstract publiccurrent()
;
abstract publickey()
;
abstract publicnext()
;
abstract publicrewind()
;
abstract public valid();
}
?>essentially you're redeclaring the entire interface in the trait, the same would be true of the public interface of an expected class. i think it would be much more elegant to allow a specification on the trait declaration itself, something like
<?php
trait IteratorHelper expects Iterator {
...
}
?>
:D That was exactly my thought when I was writing my first answer.
My second thought was, damn, not another keyword...
But since you also seem to see the need, we should give it a thought.
Anyone else with an opinion on that?
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
First i have to say that I am not a PHP internals developer, but as a user I
think it would maybe be better to just let the trait use the implements
keyword, and "copy" that to the classes utilizing the trait?
Or does that seem illogical when the trait does not implement all of the
methods specified by the interface?
(Because I think "expects" might be a common name in APIs for some kind of
validation.)
Best Regards
Martin Wernstahl
Hi Nathan:
Def not :D, however, I still think this paradigm is lacking. Don't you
think it makes more sense if I write a trait that expects a given interface
or class to be able to specify said interface/class in it's entirety with
just a single identifier rather than listing out all the methods?For example, I think this would be ugly
<?php
trait IteratorHelper{
abstract publiccurrent()
;
abstract publickey()
;
abstract publicnext()
;
abstract publicrewind()
;
abstract public valid();
}
?>essentially you're redeclaring the entire interface in the trait, the
same would be true of the public interface of an expected class. i think it
would be much more elegant to allow a specification on the trait declaration
itself, something like<?php
trait IteratorHelper expects Iterator {
...
}
?>
:D That was exactly my thought when I was writing my first answer.
My second thought was, damn, not another keyword...But since you also seem to see the need, we should give it a thought.
Anyone else with an opinion on that?
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
Hello Martin:
First i have to say that I am not a PHP internals developer, but as a user I
think it would maybe be better to just let the trait use the implements
keyword, and "copy" that to the classes utilizing the trait?
Or does that seem illogical when the trait does not implement all of the
methods specified by the interface?
Implements sounds misleading to me. Read: trait Foo implements Bar. Sounds like Foo is providing Bar and not expecting the interface to be there.
But require might be a good keyword to be reused.
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
First i have to say that I am not a PHP internals developer, but as a user
I think it would maybe be better to just let the trait use the implements
keyword, and "copy" that to the classes utilizing the trait?
This is actually in the RFC as a rejected proposal
http://wiki.php.net/rfc/traits#rejected_features
But what I'm talking about is something different. We're not trying to say
'these are the methods implemented in the trait', rather, 'this trait
expects a class it is used with to be of a certain type or implement a
certain interface' for the trait to do its job.
-nathan
Oh, sorry, should have read the RFC thoroughly before sending an email.
But yeah, require might be a good choice, provided it doesn't collide with
the specific require logic in the scanner/parser (I don't have much
knowledge on that subject, but I've peeked a few times on it as it is
interesting).
Best Regards
Martin Wernstahl
On Fri, Dec 10, 2010 at 10:15 AM, Martin Wernstahl m4rw3r@gmail.comwrote:
First i have to say that I am not a PHP internals developer, but as a user
I think it would maybe be better to just let the trait use the implements
keyword, and "copy" that to the classes utilizing the trait?This is actually in the RFC as a rejected proposal
http://wiki.php.net/rfc/traits#rejected_features
But what I'm talking about is something different. We're not trying to say
'these are the methods implemented in the trait', rather, 'this trait
expects a class it is used with to be of a certain type or implement a
certain interface' for the trait to do its job.-nathan
First i have to say that I am not a PHP internals developer, but as a user
I think it would maybe be better to just let the trait use the implements
keyword, and "copy" that to the classes utilizing the trait?This is actually in the RFC as a rejected proposal
http://wiki.php.net/rfc/traits#rejected_features
But what I'm talking about is something different. We're not trying to say
'these are the methods implemented in the trait', rather, 'this trait
expects a class it is used with to be of a certain type or implement a
certain interface' for the trait to do its job.-nathan
Shouldn't the burden be on the programmer to make sure the trait works
with the class using it rather than on the compiler? If they try to
use a trait that requires methods that don't exist, it will error out
anyway, so it won't be difficult to debug.
On Fri, Dec 10, 2010 at 9:29 AM, Nathan Nobbe quickshiftin@gmail.com
wrote:On Fri, Dec 10, 2010 at 10:15 AM, Martin Wernstahl m4rw3r@gmail.com
wrote:First i have to say that I am not a PHP internals developer, but as a
user
I think it would maybe be better to just let the trait use the
implements
keyword, and "copy" that to the classes utilizing the trait?This is actually in the RFC as a rejected proposal
http://wiki.php.net/rfc/traits#rejected_features
But what I'm talking about is something different. We're not trying to
say
'these are the methods implemented in the trait', rather, 'this trait
expects a class it is used with to be of a certain type or implement a
certain interface' for the trait to do its job.-nathan
Shouldn't the burden be on the programmer to make sure the trait works
with the class using it rather than on the compiler? If they try to
use a trait that requires methods that don't exist, it will error out
anyway, so it won't be difficult to debug.
Well I know PHP is a dynamic language but what about all the compile time
features that have come along over the years. The abstract keyword for
example vs. the PHP4 way of implementing an 'abstract' method which was
triggering an error in the default implementation in a base class.
One of the main things a lot of PHP programmers I've worked with hate is
waiting for code to hit production and encountering a runtime error w/
something that could have been caught at compile time. I know the notion of
compile time in a scripting language like PHP is much less removed from that
of C++, Java etc, however there is a notion of it there, obviously.
Also, I would suggest this feature be optional, so there is no need to use
it if you don't like it. But for those of us who would like to defer as
much type checking to the compiler as possible so we don't need runtime
checks all over our code or prayers that we've tested every line before
production, it would certainly be nice.
Lastly, you may know that traits will allow PHP programmers to move away
from the delegate pattern which is a common workaround to multiple
inheritance at this point. However, in speaking with a colleague over the
concept I'm proposing yesterday we discovered the delegate model actually
does allow you to specify which class/interface the delegate is used w/, it
would be sad not to see comparable support in the trait feature which will
mostly eliminate the need for the delegate pattern, see my quick example.
<?php
class MainClass {
private $_oDelegate = null;
function addDelegate() {
$this->_oDelegate = new Delegate($this);
}
}
class Delegate {
private function $_oMain = null;
/// delegate gets to say what it can be used with via type hinting
function __construct(MainClass $oMainClass)
{
$this->_oMain = $oMainClass;
}
}
?>
Imagine how much cleaner this could be w/ traits, yet just as expressive
<?php
class MainClass {
use Delegate;
}
trait Delegate require MainClass {
...
}
?>
-nathan
On Fri, Dec 10, 2010 at 9:29 AM, Nathan Nobbe quickshiftin@gmail.com
wrote:On Fri, Dec 10, 2010 at 10:15 AM, Martin Wernstahl m4rw3r@gmail.com
wrote:First i have to say that I am not a PHP internals developer, but as a
user
I think it would maybe be better to just let the trait use the
implements
keyword, and "copy" that to the classes utilizing the trait?This is actually in the RFC as a rejected proposal
http://wiki.php.net/rfc/traits#rejected_features
But what I'm talking about is something different. We're not trying to
say
'these are the methods implemented in the trait', rather, 'this trait
expects a class it is used with to be of a certain type or implement a
certain interface' for the trait to do its job.-nathan
Shouldn't the burden be on the programmer to make sure the trait works
with the class using it rather than on the compiler? If they try to
use a trait that requires methods that don't exist, it will error out
anyway, so it won't be difficult to debug.Well I know PHP is a dynamic language but what about all the compile time
features that have come along over the years. The abstract keyword for
example vs. the PHP4 way of implementing an 'abstract' method which was
triggering an error in the default implementation in a base class.
One of the main things a lot of PHP programmers I've worked with hate is
waiting for code to hit production and encountering a runtime error w/
something that could have been caught at compile time. I know the notion of
compile time in a scripting language like PHP is much less removed from that
of C++, Java etc, however there is a notion of it there, obviously.
Also, I would suggest this feature be optional, so there is no need to use
it if you don't like it. But for those of us who would like to defer as
much type checking to the compiler as possible so we don't need runtime
checks all over our code or prayers that we've tested every line before
production, it would certainly be nice.
Lastly, you may know that traits will allow PHP programmers to move away
from the delegate pattern which is a common workaround to multiple
inheritance at this point. However, in speaking with a colleague over the
concept I'm proposing yesterday we discovered the delegate model actually
does allow you to specify which class/interface the delegate is used w/, it
would be sad not to see comparable support in the trait feature which will
mostly eliminate the need for the delegate pattern, see my quick example.
<?php
class MainClass {
private $_oDelegate = null;
function addDelegate() {
$this->_oDelegate = new Delegate($this);
}
}
class Delegate {
private function $_oMain = null;
/// delegate gets to say what it can be used with via type hinting
function __construct(MainClass $oMainClass)
{
$this->_oMain = $oMainClass;
}
}
?>
Imagine how much cleaner this could be w/ traits, yet just as expressive
<?php
class MainClass {
use Delegate;
}
trait Delegate require MainClass {
...
}
?>
-nathan
As a note, I'm not strongly opposed to this proposal, since I don't
think it would do any harm. It just seems to me like a "kitchen sink"
feature.
The issue for me is that traits, as I understand them, are there
primarily for horizontal code re-use via compile-time "copy/paste".
With that in mind, I feel like the developer is responsible for making
sure the methods they copy into their classes make sense, just as they
would have to do if they physically copied and pasted them.
I think your example above isn't quite what you meant to show, since
you're requiring a specific class and not an interface (since PHP only
allows one class definition for a class name, you're not gaining
anything via traits, since the trait could only be used for that
specific class, in which case why not just have the code in the class
in the first place?).
If we take your example in a more general case using interfaces, I
still can't see what the benefit is. All it does is provide a more
explicit and immediate error message for developers (e.g. instead of
"method not found" error when the bad method call is made at runtime,
you get a "classes using trait <trait> must implement <interface>" at
compile time).
Again, I'm not against it, but maybe be too much hand holding, since
the developer should make sure using the trait makes sense first?
On Fri, Dec 10, 2010 at 10:39 AM, Nathan Nobbe quickshiftin@gmail.com
wrote:On Fri, Dec 10, 2010 at 11:04 AM, Chad Fulton chadfulton@gmail.com
wrote:On Fri, Dec 10, 2010 at 9:29 AM, Nathan Nobbe quickshiftin@gmail.com
wrote:On Fri, Dec 10, 2010 at 10:15 AM, Martin Wernstahl m4rw3r@gmail.com
wrote:First i have to say that I am not a PHP internals developer, but as a
user
I think it would maybe be better to just let the trait use the
implements
keyword, and "copy" that to the classes utilizing the trait?This is actually in the RFC as a rejected proposal
http://wiki.php.net/rfc/traits#rejected_features
But what I'm talking about is something different. We're not trying
to
say
'these are the methods implemented in the trait', rather, 'this trait
expects a class it is used with to be of a certain type or implement a
certain interface' for the trait to do its job.-nathan
Shouldn't the burden be on the programmer to make sure the trait works
with the class using it rather than on the compiler? If they try to
use a trait that requires methods that don't exist, it will error out
anyway, so it won't be difficult to debug.Well I know PHP is a dynamic language but what about all the compile time
features that have come along over the years. The abstract keyword for
example vs. the PHP4 way of implementing an 'abstract' method which was
triggering an error in the default implementation in a base class.
One of the main things a lot of PHP programmers I've worked with hate is
waiting for code to hit production and encountering a runtime error w/
something that could have been caught at compile time. I know the notion
of
compile time in a scripting language like PHP is much less removed from
that
of C++, Java etc, however there is a notion of it there, obviously.
Also, I would suggest this feature be optional, so there is no need to
use
it if you don't like it. But for those of us who would like to defer as
much type checking to the compiler as possible so we don't need runtime
checks all over our code or prayers that we've tested every line before
production, it would certainly be nice.
Lastly, you may know that traits will allow PHP programmers to move away
from the delegate pattern which is a common workaround to multiple
inheritance at this point. However, in speaking with a colleague over
the
concept I'm proposing yesterday we discovered the delegate model actually
does allow you to specify which class/interface the delegate is used w/,
it
would be sad not to see comparable support in the trait feature which
will
mostly eliminate the need for the delegate pattern, see my quick example.
<?php
class MainClass {
private $_oDelegate = null;
function addDelegate() {
$this->_oDelegate = new Delegate($this);
}
}
class Delegate {
private function $_oMain = null;
/// delegate gets to say what it can be used with via type hinting
function __construct(MainClass $oMainClass)
{
$this->_oMain = $oMainClass;
}
}
?>
Imagine how much cleaner this could be w/ traits, yet just as expressive
<?php
class MainClass {
use Delegate;
}
trait Delegate require MainClass {
...
}
?>
-nathanAs a note, I'm not strongly opposed to this proposal, since I don't
think it would do any harm. It just seems to me like a "kitchen sink"
feature.The issue for me is that traits, as I understand them, are there
primarily for horizontal code re-use via compile-time "copy/paste".
With that in mind, I feel like the developer is responsible for making
sure the methods they copy into their classes make sense, just as they
would have to do if they physically copied and pasted them.
Copy & paste itself leads to duplicated unmaintainable code, so traits are
introduced (among other reasons) to prohibit this practice. Why not take it
a step further and let a trait definition be as expressive as possible,
eliminating ambiguity, right out of the gate?
I think your example above isn't quite what you meant to show, since
you're requiring a specific class and not an interface (since PHP only
allows one class definition for a class name, you're not gaining
anything via traits, since the trait could only be used for that
specific class, in which case why not just have the code in the class
in the first place?).
In retrospect Chad, that's a good point, and perhaps there is no reason to
allow marking of classes as required by traits.
If we take your example in a more general case using interfaces, I
still can't see what the benefit is. All it does is provide a more
explicit and immediate error message for developers (e.g. instead of
"method not found" error when the bad method call is made at runtime,
you get a "classes using trait <trait> must implement <interface>" at
compile time).
Exactly, catch it at compile time rather than runtime, that's all it is
really, just like the benefit of discovering a given subclass doesn't
implement a given abstract method so that I don't go any further and run
code guaranteed not to work.
Again, I'm not against it, but maybe be too much hand holding, since
the developer should make sure using the trait makes sense first?
Couldn't the same be said for a developer extending an abstract class, or
implementing an interface? And also, a developer is to look through the
entire definition of a trait to know which methods it's going to depend on?
I know abstract is there as Stefan showed, but as we've both observed that
approach can get messy quickly.
-nathan
As a note, I'm not strongly opposed to this proposal, since I don't
think it would do any harm. It just seems to me like a "kitchen sink"
feature.The issue for me is that traits, as I understand them, are there
primarily for horizontal code re-use via compile-time "copy/paste".
With that in mind, I feel like the developer is responsible for making
sure the methods they copy into their classes make sense, just as they
would have to do if they physically copied and pasted them.Copy & paste itself leads to duplicated unmaintainable code, so traits are
introduced (among other reasons) to prohibit this practice. Why not take it
a step further and let a trait definition be as expressive as possible,
eliminating ambiguity, right out of the gate?I think your example above isn't quite what you meant to show, since
you're requiring a specific class and not an interface (since PHP only
allows one class definition for a class name, you're not gaining
anything via traits, since the trait could only be used for that
specific class, in which case why not just have the code in the class
in the first place?).In retrospect Chad, that's a good point, and perhaps there is no reason to
allow marking of classes as required by traits.If we take your example in a more general case using interfaces, I
still can't see what the benefit is. All it does is provide a more
explicit and immediate error message for developers (e.g. instead of
"method not found" error when the bad method call is made at runtime,
you get a "classes using trait <trait> must implement <interface>" at
compile time).Exactly, catch it at compile time rather than runtime, that's all it is
really, just like the benefit of discovering a given subclass doesn't
implement a given abstract method so that I don't go any further and run
code guaranteed not to work.Again, I'm not against it, but maybe be too much hand holding, since
the developer should make sure using the trait makes sense first?Couldn't the same be said for a developer extending an abstract class, or
implementing an interface? And also, a developer is to look through the
entire definition of a trait to know which methods it's going to depend on?
I know abstract is there as Stefan showed, but as we've both observed that
approach can get messy quickly.
-nathan
I think that you make a convincing argument. Thinking more about your
Iterator example, this idea makes a lot of sense and could be quite
useful.
Also, I was wrong about requiring a class. It could be very useful,
especially if it is an internal class (e.g. ArrayObject) which might
have many children, and of course in this case the parent can't be
changed.
I think the require keyword works well.
--0016e6dbe7fb8861a1049712ad63
Content-Type: text/plain; charset=UTF-8On Fri, Dec 10, 2010 at 9:29 AM, Nathan Nobbe quickshiftin@gmail.com
wrote:On Fri, Dec 10, 2010 at 10:15 AM, Martin Wernstahl m4rw3r@gmail.com
wrote:First i have to say that I am not a PHP internals developer, but as a
user
I think it would maybe be better to just let the trait use the
implements
keyword, and "copy" that to the classes utilizing the trait?This is actually in the RFC as a rejected proposal
http://wiki.php.net/rfc/traits#rejected_features
But what I'm talking about is something different. We're not trying to
say
'these are the methods implemented in the trait', rather, 'this trait
expects a class it is used with to be of a certain type or implement a
certain interface' for the trait to do its job.-nathan
Shouldn't the burden be on the programmer to make sure the trait works
with the class using it rather than on the compiler? If they try to
use a trait that requires methods that don't exist, it will error out
anyway, so it won't be difficult to debug.Well I know PHP is a dynamic language but what about all the compile time
features that have come along over the years. The abstract keyword for
example vs. the PHP4 way of implementing an 'abstract' method which was
triggering an error in the default implementation in a base class.One of the main things a lot of PHP programmers I've worked with hate is
waiting for code to hit production and encountering a runtime error w/
something that could have been caught at compile time. I know the notion of
compile time in a scripting language like PHP is much less removed from that
of C++, Java etc, however there is a notion of it there, obviously.
To me, putting this into the language feels like overkill.
Unless you're using an opcode cache, the notion of compile time as a
differentiation from runtime in PHP has little relevance -- you still
only find out when the script executes.
There's already a way to mitigate this as well: write a testing suite
for your application, and exercise it often. If you write your tests
well (targeting the discrete behaviors of your application), then most
likely they'll catch such errors -- allowing you to fix them before you
deploy.
--
Matthew Weier O'Phinney
Project Lead | matthew@zend.com
Zend Framework | http://framework.zend.com/
PGP key: http://framework.zend.com/zf-matthew-pgp-key.asc
On Fri, Dec 10, 2010 at 12:55 PM, Matthew Weier O'Phinney <
weierophinney@php.net> wrote:
--0016e6dbe7fb8861a1049712ad63
Content-Type: text/plain; charset=UTF-8On Fri, Dec 10, 2010 at 11:04 AM, Chad Fulton chadfulton@gmail.com
wrote:On Fri, Dec 10, 2010 at 9:29 AM, Nathan Nobbe quickshiftin@gmail.com
wrote:On Fri, Dec 10, 2010 at 10:15 AM, Martin Wernstahl <m4rw3r@gmail.com
wrote:
First i have to say that I am not a PHP internals developer, but as
a
user
I think it would maybe be better to just let the trait use the
implements
keyword, and "copy" that to the classes utilizing the trait?This is actually in the RFC as a rejected proposal
http://wiki.php.net/rfc/traits#rejected_features
But what I'm talking about is something different. We're not trying
to
say
'these are the methods implemented in the trait', rather, 'this trait
expects a class it is used with to be of a certain type or implement
a
certain interface' for the trait to do its job.-nathan
Shouldn't the burden be on the programmer to make sure the trait works
with the class using it rather than on the compiler? If they try to
use a trait that requires methods that don't exist, it will error out
anyway, so it won't be difficult to debug.Well I know PHP is a dynamic language but what about all the compile time
features that have come along over the years. The abstract keyword for
example vs. the PHP4 way of implementing an 'abstract' method which was
triggering an error in the default implementation in a base class.One of the main things a lot of PHP programmers I've worked with hate is
waiting for code to hit production and encountering a runtime error w/
something that could have been caught at compile time. I know the notion
of
compile time in a scripting language like PHP is much less removed from
that
of C++, Java etc, however there is a notion of it there, obviously.To me, putting this into the language feels like overkill.
Unless you're using an opcode cache, the notion of compile time as a
differentiation from runtime in PHP has little relevance -- you still
only find out when the script executes.
Only if you hit the line of code at runtime that would destroy your
script; often times this doesn't happen until it's too late, and the code
has made it to production. And there is a notion of compile time in PHP,
I'm not sure what it's referred to by the internals group, but abstract
methods and interfaces definitely constitue compile time checks to me.
There's already a way to mitigate this as well: write a testing suite
for your application, and exercise it often. If you write your tests
well (targeting the discrete behaviors of your application), then most
likely they'll catch such errors -- allowing you to fix them before you
deploy.
Right, so you have to do tons of extra work (writing unit tests) which have
to actually test every potential line of failure, when this could just
simply be caught up front w/o any second guessing whether or not you've
covered all cases in your tests. I'm not against unit tests at all, just
saying it's much easier to guarantee you're safely using a trait w/ a
compile time check rather than deferring the application author to test
suite development.
-nathan
--0016e6d7e101e083a4049714bad3
Content-Type: text/plain; charset=UTF-8On Fri, Dec 10, 2010 at 12:55 PM, Matthew Weier O'Phinney <
weierophinney@php.net> wrote:--0016e6dbe7fb8861a1049712ad63
Content-Type: text/plain; charset=UTF-8On Fri, Dec 10, 2010 at 11:04 AM, Chad Fulton chadfulton@gmail.com
wrote:On Fri, Dec 10, 2010 at 9:29 AM, Nathan Nobbe quickshiftin@gmail.com
wrote:On Fri, Dec 10, 2010 at 10:15 AM, Martin Wernstahl <m4rw3r@gmail.com
wrote:
First i have to say that I am not a PHP internals developer, but as
a
user
I think it would maybe be better to just let the trait use the
implements
keyword, and "copy" that to the classes utilizing the trait?This is actually in the RFC as a rejected proposal
http://wiki.php.net/rfc/traits#rejected_features
But what I'm talking about is something different. We're not trying
to
say
'these are the methods implemented in the trait', rather, 'this trait
expects a class it is used with to be of a certain type or implement
a
certain interface' for the trait to do its job.-nathan
Shouldn't the burden be on the programmer to make sure the trait works
with the class using it rather than on the compiler? If they try to
use a trait that requires methods that don't exist, it will error out
anyway, so it won't be difficult to debug.Well I know PHP is a dynamic language but what about all the compile time
features that have come along over the years. The abstract keyword for
example vs. the PHP4 way of implementing an 'abstract' method which was
triggering an error in the default implementation in a base class.One of the main things a lot of PHP programmers I've worked with hate is
waiting for code to hit production and encountering a runtime error w/
something that could have been caught at compile time. I know the notion
of
compile time in a scripting language like PHP is much less removed from
that
of C++, Java etc, however there is a notion of it there, obviously.To me, putting this into the language feels like overkill.
Unless you're using an opcode cache, the notion of compile time as a
differentiation from runtime in PHP has little relevance -- you still
only find out when the script executes.Only if you hit the line of code at runtime that would destroy your
script; often times this doesn't happen until it's too late, and the code
has made it to production.
That's what good testing is about -- exercising all the expected
behaviors of your code. If you hit an unexpected behavior in production,
you add a test to your suite that reproduces it, fix it, and re-deploy.
And there is a notion of compile time in PHP, I'm not sure what it's
referred to by the internals group, but abstract methods and
interfaces definitely constitue compile time checks to me.There's already a way to mitigate this as well: write a testing suite
for your application, and exercise it often. If you write your tests
well (targeting the discrete behaviors of your application), then most
likely they'll catch such errors -- allowing you to fix them before you
deploy.Right, so you have to do tons of extra work (writing unit tests) which have
to actually test every potential line of failure, when this could just
simply be caught up front w/o any second guessing whether or not you've
covered all cases in your tests.
Writing tests should not be considered "tons of extra work"; it should
be considered a basic part of development. How can you prove your code
does what it should without them? How can you insulate your code from
future changes? As long as you consider it "extra work", I don't care
what the compiler offers you -- you're going to shoot yourself in the
foot some day.
I'm not against unit tests at all, just saying it's much easier to
guarantee you're safely using a trait w/ a compile time check rather
than deferring the application author to test suite development.
Again, are the benefits worth it, if you're writing code where an
unexpected runtime exception could still occur because you didn't test
properly in the first place?
--
Matthew Weier O'Phinney
Project Lead | matthew@zend.com
Zend Framework | http://framework.zend.com/
PGP key: http://framework.zend.com/zf-matthew-pgp-key.asc
On Fri, Dec 10, 2010 at 2:42 PM, Matthew Weier O'Phinney <
weierophinney@php.net> wrote:
--0016e6d7e101e083a4049714bad3
Content-Type: text/plain; charset=UTF-8On Fri, Dec 10, 2010 at 12:55 PM, Matthew Weier O'Phinney <
weierophinney@php.net> wrote:--0016e6dbe7fb8861a1049712ad63
Content-Type: text/plain; charset=UTF-8On Fri, Dec 10, 2010 at 11:04 AM, Chad Fulton chadfulton@gmail.com
wrote:On Fri, Dec 10, 2010 at 9:29 AM, Nathan Nobbe <
quickshiftin@gmail.com>
wrote:On Fri, Dec 10, 2010 at 10:15 AM, Martin Wernstahl <
m4rw3r@gmail.comwrote:
First i have to say that I am not a PHP internals developer, but
as
a
user
I think it would maybe be better to just let the trait use the
implements
keyword, and "copy" that to the classes utilizing the trait?This is actually in the RFC as a rejected proposal
http://wiki.php.net/rfc/traits#rejected_features
But what I'm talking about is something different. We're not
trying
to
say
'these are the methods implemented in the trait', rather, 'this
trait
expects a class it is used with to be of a certain type or
implement
a
certain interface' for the trait to do its job.-nathan
Shouldn't the burden be on the programmer to make sure the trait
works
with the class using it rather than on the compiler? If they try to
use a trait that requires methods that don't exist, it will error
out
anyway, so it won't be difficult to debug.Well I know PHP is a dynamic language but what about all the compile
time
features that have come along over the years. The abstract keyword
for
example vs. the PHP4 way of implementing an 'abstract' method which
was
triggering an error in the default implementation in a base class.One of the main things a lot of PHP programmers I've worked with hate
is
waiting for code to hit production and encountering a runtime error w/
something that could have been caught at compile time. I know the
notion
of
compile time in a scripting language like PHP is much less removed
from
that
of C++, Java etc, however there is a notion of it there, obviously.To me, putting this into the language feels like overkill.
Unless you're using an opcode cache, the notion of compile time as a
differentiation from runtime in PHP has little relevance -- you still
only find out when the script executes.Only if you hit the line of code at runtime that would destroy your
script; often times this doesn't happen until it's too late, and the code
has made it to production.That's what good testing is about -- exercising all the expected
behaviors of your code. If you hit an unexpected behavior in production,
you add a test to your suite that reproduces it, fix it, and re-deploy.
Right, and implementing an interface or subclassing an abstract class does
not require a unit test in order to determine if I've at least met the
obligations set forth by the interface or abstract class. The basic idea of
a unit test is to write meaningful tests that actually offer you some milage
for your time. I mean sure, I could write tests for setters and getters,
but that's pretty much a waste of time compared to writing tests that
actually get into semantics the class aims to provide.
And there is a notion of compile time in PHP, I'm not sure what it's
referred to by the internals group, but abstract methods and
interfaces definitely constitue compile time checks to me.There's already a way to mitigate this as well: write a testing suite
for your application, and exercise it often. If you write your tests
well (targeting the discrete behaviors of your application), then most
likely they'll catch such errors -- allowing you to fix them before you
deploy.Right, so you have to do tons of extra work (writing unit tests) which
have
to actually test every potential line of failure, when this could just
simply be caught up front w/o any second guessing whether or not you've
covered all cases in your tests.Writing tests should not be considered "tons of extra work"; it should
be considered a basic part of development.
Shrug, taken out of context. I'm sure you can see how writing an extra word
in the trait definition is much less work than including a unit test suite
in your project and then a test against each class that uses the trait..,
IMO, that is a ton of extra work. Even in the context of unit test
writing a compile time check would eliminate the need of writing what I
would consider bolier plate unit tests for traits. It's like, well I just
wrote a trait, now any class I write against it I should go ahead and test
that it provides all the methods for said trait .. that's just a waste of
time. Again the abstract keyword is there; just not nearly as elegant for
naming an entire interface or set of them, when that was your intention in
the first place.
How can you prove your code does what it should without them? How can you
insulate your code from
future changes? As long as you consider it "extra work", I don't care
what the compiler offers you -- you're going to shoot yourself in the
foot some day.
How can you prove your class implements all the abstract methods it claims
to - simple, by loading it into the interpreter w/o error.
I'm not against unit tests at all, just saying it's much easier to
guarantee you're safely using a trait w/ a compile time check rather
than deferring the application author to test suite development.Again, are the benefits worth it, if you're writing code where an
unexpected runtime exception could still occur because you didn't test
properly in the first place?
I'd be curious to see how interfaces and abstract methods made it into the
language since they embrace what is essentially the same concept. And I
have tested properly.., the class loads w/o error so it implements any
external methods the traits it uses need, guaranteed. If there's a logic
bug in one of those methods, then let's hope I've caught them in an actual,
meaningful unit test :D
-nathan
Hi:
I added the proposal to the RFC.
See http://wiki.php.net/rfc/horizontalreuse#requiring_composing_class_to_implement_interface
===== Requiring Composing Class to Implement Interface =====
Traits are able to express required methods by using abstract method declarations.
An abstract method can be satisfied in varios ways, for instance by implementing it
in the composing class or by bringing it in from another Trait.
However, for traits that require complex interfaces to be satisfied, this approach is tedious
and fragile, since it requires the developer to state all used methods explicitly.
Another solution is that a Trait expresses a requirement for the composing class to implement
a certain interface. This is not entirely identical to using abstract methods, however.
First, it imposes a requirement on interface level and thus will have the same fragility
with respect to interface changes as all other clients of an interface.
On the other hand, it avoids duplications of abstract method definitions and makes
the interface the main entity of responsibility as for normal client-interface uses
in current code.
<?php
// IteratorUser works with $this using the Iterator interface
trait IteratorUser require Iterator {
function foo() {
$next = $this->next();
...
}
}
// composed into a class that needs to implement the interface
class Example implements Iterator {
use IteratorUser;
}
Are there any objections to implementing this?
Thanks
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
http://wiki.php.net/rfc/horizontalreuse#requiring_composing_class_to_impleme
nt_interface
Are there any objections to implementing this?
It's not a bad idea, though I haven't found a strong need for it in the way
I plan to use traits.
It also turns a trait into something more complex 'copy & paste' code with
requirements/dependencies.
-1 on using 'require' (T_REQUIRE token), an option could be 'within'
trait IteratorUser within Iterator {
function foo() {
$next = $this->next();
...
}
}
class MyIterator implements Iterator {
with IteratorUser;
}
So the 'with/within' tokens would apply to traits.
Overall I feel -1, more use cases around "Trait expresses a requirement for
the composing class" would help, it seems like useful theory... not
convinced it's worth the trouble.
On Sun, Dec 12, 2010 at 7:25 AM, Jonathan Bond-Caron jbondc@openmv.comwrote:
http://wiki.php.net/rfc/horizontalreuse#requiring_composing_class_to_impleme
nt_interfaceAre there any objections to implementing this?
It's not a bad idea, though I haven't found a strong need for it in the way
I plan to use traits.
Do you intend to use traits as reusable implementations of interfaces? If
not, I could see why this feature isn't of interest to you :)
It also turns a trait into something more complex 'copy & paste' code with
requirements/dependencies.
I think copy & paste is a good way to conceptualize traits, but feel,
practically, they're a bit more complex than that w/ conflict resolution,
traits composed of traits, and the issue w/ attributes Stefan has brought
up. Essentially, there are already rules being added around the copy &
paste concept. Also, this feature is mostly an extension of the abstract
keyword concept in traits, which they already support.
-1 on using 'require' (T_REQUIRE token), an option could be 'within'
trait IteratorUser within Iterator {
function foo() {
$next = $this->next();
...
}
}class MyIterator implements Iterator {
with IteratorUser;
}So the 'with/within' tokens would apply to traits.
I feel 'expect', 'need', 'require' etc sound better, matter of opinion
really, but it sounds like from an internals perspective it's preferred to
reuse existing keywords if possible.
Overall I feel -1, more use cases around "Trait expresses a requirement for
the composing class" would help, it seems like useful theory... not
convinced it's worth the trouble.
If you see the value in the abstract keyword in abstract classes or moreover
interfaces in general, I'd consider the value of this feature equal. Of
course not everyone uses abstract classes or interfaces :D
-nathan
So the 'with/within' tokens would apply to traits.
I feel 'expect', 'need', 'require' etc sound better, matter of opinion
really, but it sounds like from an internals perspective it's
preferred to reuse existing keywords if possible.
Well my opinion is more of linguistics, given the definitions:
http://www.thefreedictionary.com/trait
http://www.thefreedictionary.com/use
http://www.thefreedictionary.com/with
Using 'with/within' keywords for a trait seem more natural and intuitive (at least as an English speaker).
I can understand re-using existing keywords and why 'use' was ok but adding a 'require' for traits just feels awkward (saying you can 'require' code or an interface for a trait).
I know someone's bound to say "you'll get used to it", fair enough. I'll add that Scala also uses 'with' for traits, so it's worth considering.
If you see the value in the abstract keyword in abstract classes or
moreover interfaces in general, I'd consider the value of this feature
equal. Of course not everyone uses abstract classes or interfaces :D
I agree with what you're saying, a little hesitant to say of equal value since a lot of research has went into 'abstract' or 'interface' :)