Re: Traits expecting interfaces implicitly leads to expensive runtime checks
| From: | Nathan Nobbe | Date: | Fri, 10 Dec 2010 21:00:14 +0000 |
| Subject: | Re: Traits expecting interfaces implicitly leads to expensive runtime checks | ||
| References: | 1 2 3 4 5 6 7 8 9 10 11 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-51001@lists.php.net to get a copy of this message | ||
On Fri, Dec 10, 2010 at 12:39 PM, Chad Fulton <chadfulton@gmail.com> wrote:
> 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 {
> > ...
> > }
> > ?>
> > -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