> -----Ursprüngliche Nachricht-----
> Von: François Laupretre [mailto:franc...@php.net]
> Gesendet: Samstag, 14. Februar 2015 07:17
> An: 'Yasuo Ohgaki'
> Cc: 'Dmitry Stogov'; 'Joe Watkins'; 'Stanislav Malyshev'; 'PHP Internals'
> Betreff: RE: [PHP-DEV] Design by Contract
> 
> I will try to explain but that’s not so clear for me too.
> 
> 
> 
> The theory (from Eiffel guru) states that, to respect this fucking LSP rule, 
> the pre-conditions to check when entering a
> method must be less strict than when entering its parent method. Don’t ask 
> why, I don’t understand the reason very well.
> But that’s his rule, and everyone seems to respect it.
> 

The theory is actually quite simple. Roughly it says that if you use a type 
hint of a certain class then you can rely on all pre/post-conditions of this 
class even if a sub-class is passed. Hence the sub-class cannot have more 
restrict conditions. Consider the following (no longer sure which syntax is the 
one you intend to use, so I just use pre and post):

class A{
  function foo($x){
     pre($x > 100);
  }
}

class B extends A{
  function foo($x){
    pre($x > 50); // less restrictive, that's fine
  }
}

class C{
  function foo($x){
    pre($x > 150); //more restrictive that's not allowed
  }
}

function foo(A $a){
  $a->foo(101); // that is ok as long as LSP is not violated
}

foo(new A()); //that's fine
foo(new B()); //fine as well
foo(new C()); //nope, C violates LSP and thus will result in an error

> 
> In your RFC, you say that, when we enter a method, we must check its 
> pre-conditions, as well as the ones of every parents.
> As you can only add conditions, compared to what you would do for the parent, 
> the checks can only be stricter (more
> conditions).
> 
> 
> 
> The logic described in the D documentation is : if a method defines 
> pre-conditions, check them and stop (don’t check
> parent’s pre-conditions). If the method does not define pre-conditions, go 
> down one level and check if parent method
> defines some. As soon as a method defining pre-conditions is found, these are 
> checked and control is returned without
> going further. This way, it is still the developer’s responsibility to loosen 
> conditions in derived classes but it is possible. If you
> check every parent’s pre-conditions, it is just *not* possible.
> 
> 
> 
> I am not sure I am clear.

I guess from the example above it should be clear why D has implemented it this 
way

> 
> 
> I chose not to follow exactly this logic as I think we can do it more ‘PHP 
> way’ (something like the way constructors and
> destructors explicitly call their parent methods). My logic is : if the 
> method we are entering has no pre-conditions, we don’t
> check anything (don’t search a parent method). If it defines some, we execute 
> them. I introduce a ‘special’ condition : the
> ‘@parent’ pseudo-condition means ‘go down checking my parent’s conditions’. 
> This way, similar to ‘parent::__construct()’
> logic allows the developer to decide if he wants to check parent’s conditions 
> or not.
> 
> 
> 
> Example :
> 
> 
> 
> /**
> 
> * @requires ($a < $b)
> 
> * @requires @parent   <- Go checking parent’s pre-conditions
> 
> * @requires …
> 
> 
> 
> For better consistence, I chose to implement the same for post-conditions and 
> invariants, but I am not sure I will keep
> 
> the same logic.
> 
> 
> 
> The only thing that remains not clear for me is the role of conditions 
> defined in interfaces, as the D documentation says that
> they can be defined but it does not explain when they are checked. I assume 
> this is considered as a parent but the order
> matters in pre-conditions as we only execute the first conditions we find. I 
> think I’ll assume that ‘@parent’ means ‘check
> the conditions defined in the parent method and the method of the interface 
> that defines it’. Unfortunately, interfaces
> have parents too and can define methods with same name. So, it’s the same 
> sort of problems as multiple inheritance. I will
> need to make a choice here. The simplest one would be ‘no support for DbC in 
> interfaces’.
> 
> 
> 
> 
> 
> De : yohg...@gmail.com [mailto:yohg...@gmail.com] De la part de Yasuo Ohgaki 
> Envoyé : samedi 14 février 2015 05:16 À :
> francois Cc : Dmitry Stogov; Joe Watkins; Stanislav Malyshev; PHP Internals 
> Objet : Re: [PHP-DEV] Design by Contract
> 
> 
> 
> Hi Francois,
> 
> 
> 
> On Sat, Feb 14, 2015 at 12:53 PM, Yasuo Ohgaki <yohg...@ohgaki.net> wrote:
> 
> On Sat, Feb 14, 2015 at 12:03 PM, François Laupretre <franc...@php.net> wrote:
> 
> > For method calls, overridden method should not evaluate parents contract on 
> > entry.
> > It should be evaluated when parent method is called.
> 
> I already told you : the logic you are using for pre-conditions is NOT 
> compatible with Eiffel and D logic, although this is what
> you're supposed to mimic. It is actually the opposite. Is it a wanted 
> behavior ? because you should be aware that it does not
> respect the LS principle.
> 
> 
> Did you mean "Least Concern Principle" here?
> 
> 
> I'm lost here. Eiffel does not even allow method overriding. Therefore, child 
> class's method contract
> 
> will never evaluated unless it is explicitly called. Semantics is basically 
> the same as what I wrote.
> 
> (Eiffel requires to drop parent method by "redefine" or rename parent method 
> by "rename" when
> 
> the same method name is needed)
> 
> 
> 
> I agree that Eiffel's approach is stricter with respect to least concern 
> principle.
> 
> It's just not suitable for PHP, is it?
> 
> 
> 
> Similar argument can be done for D's invariant. D dropped invariant from 
> class in favor of
> 
> immutables. Immutable is better for least concern, but we don't have 
> immutables now.
> 
> Even if we have it, people would like to manage object state. We may have 
> both.
> 
> 
> 
> Anyway, could you explain what kind of issues we may have?
> 
> 
> 
> Regards,
> 
> 
> 
> 
> --
> Yasuo Ohgaki
> yohg...@ohgaki.net



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

Reply via email to