[sv-ec] RE: Last major issues on interface classes - 1356 review

From: Tipp, Brandon P <brandon.p.tipp@intel.com>
Date: Fri Aug 12 2011 - 11:22:12 PDT

I'll add the following to the proposal in the top section 8.25:

A virtual class shall define or inherit a pure virtual method prototype or virtual method implementation for each pure virtual method prototype in each implemented interface class. The virtual keyword shall be used unless a virtual method is inherited.

I think that covers issues 16-18. But, as a thought, what if this occurs:

interface class intfA;
  pure virtual function void f();
endclass

virtual class base;
  virtual function void f();
    $display("base::f");
  endfunction
endclass

virtual class ext extends base implements intfA;
  function void f(); // Is this an error since "virtual" not explicit, but inherited from base?
    $display("ext::f");
  endfunction
endclass

Do we want the above to be legal? I worded the above to make it so.

Also, I had some outside feedback proposing that we allow "interface module _identifier_" to be legal syntax synonymous with "interface _identifier_" for symmetry. Any thoughts?

Thanks,
Brandon

From: Gordon Vreugdenhil [mailto:gordonv@model.com]
Sent: Thursday, August 11, 2011 4:47 PM
To: Tipp, Brandon P
Cc: Alsop, Thomas R; SV_EC List
Subject: Re: Last major issues on interface classes - 1356 review

On 8/11/2011 4:10 PM, Tipp, Brandon P wrote:
[...]

I don't think that we'd want to disallow virtual (abstract)
classes which implement interfaces.
[Alsop, Thomas R] I never said this and actually agree with you. I just think that when you 'implement' an interface class, you have to provide the full definition, regardless of it being in an abstract class or non-abstract class. Otherwise we run into this inherit causality effect.
An abstract class
should be allowed to be partial in the sense of not defining
implementations but must be complete in terms of
defining prototypes that satisfy the contract obligations
(whether directly or through inheritance).
[Alsop, Thomas R] But isn't this just a cut-n-paste. Please convince me of the point of doing this.

[Tipp, Brandon P] By declaring a virtual class as implementing an interface class, you add assignment and casting capabilities (class compatibility) that you don't get with cut-and-paste. An abstract class shouldn't be forced to provide an implementation for any method; that defeats the purpose of an abstract class. I've previously removed language regarding a class "inheriting" virtual method prototypes from implemented interface classes; I'm not sure that I see a big deal about "effectively" inheriting it, but I can add language that
"A virtual class shall define or inherit a method prototype or implementation for each method prototype from each interface class that it implements."
Which requires a prototype or definition to be present where an interface class is implemented by an abstract class or
"Any method of an interface class may be called on a variable of a type which implements that interface class."
Which explicitly allows the method call without requiring a prototype or definition to be present.
If a prototype is required, then adding an implements could result in compile errors on the abstract class due to missing prototypes even if there is a definition further down the line. Fixing those compile errors would require any non-virtual methods down the line to implicitly become virtual. If the prototype is not required, then adding an implements could result in a compile errors on the non-abstract classes which inherit the abstract class if no definition is provided. Furthermore, it could implicitly/silently change the behavior of non-virtual methods to virtual without any errors reported. Pick your poison.

GORD: Right. I'll going to go back to my earlier statement -- adding "implements" shouldn't change *behavior*. So, yes, you might get compile errors if an abstract class didn't have a prototype for an implemented method, but at least you find out early. If you don't do that, you can get behavior changes in the existing class code which then becomes a run-time debug exercise. Personally, I prefer compile/elab errors to run-time debug sessions. So, I'd prefer to require that the prototypes exist (either by inheritance or explicitly required).

In 18, the base method is NOT virtual and as you point
out in your comments on 17, we would not want it to become
implicitly virtual by way of "der" implementing the interface
class. But the committee's discussion of 16 would require
"der" to provide a prototype (which would hide the non-virtual
base method) or would generate an error since the base method
is non-virtual. That is clean and doesn't require any particular
change or special consideration of the normal class rules.
[Alsop, Thomas R] Hold on, are you saying the committee wants to allow the abstract class to use 'implements' to do the following. This is the cut and paste of the IC prototype into the abstract class in order to "satisfy the contract obligation".

        class base;
            function void f(); endfunction
        endclass
        interface class intf;
            pure virtual function void f();
        endclass
        virtual class der extends base implements intf;
            pure virtual function void f();
        endclass
        class der2 extends der;
            function void f(); endfuntion
        endclass
    If you have:
        der d = some_legal_obj;
        d.f();

[Alsop, Thomas R] Hmmm, I think I get it. You would only do this if you wanted to explicitly override the base method to be virtual. This is kind of a weird case because there doesn't seem to be any point in using the 'implements' for this example since you are cutting and pasting what is in the interface class. Are we bottom line stating that we can do one of two things when we 'implements' an IC into an abstract class. We either fully define it, or we just cut-n-paste the prototype in so the prototype can hide the base implementation. And what is the decision in this case, does it hide the base method or do we generate an error because the base extension did not meet the prototype contract?

All of the above is related to a very strong paradigm requirement
that I would like to see met. I would like to be able to say that
adding an "implements" to any class never changes the behavior
of that class in any way; it "obligates" the class the behave in
some manner, but it doesn't impact the behavior of the class.
So, assuming that the code compiles/elaborates, one can
generalize any class based design by adding "implements"
clauses broadly (with wild abandon) and not change any of
the existing class behavior. Keeping that as a strong requirement
will, I believe, lead to much more compositional code in the
long term with much more consistent ways of reasoning about
interactions.
[Alsop, Thomas R] I am in complete agreement with this mindset. In all the discussions so far I don't think I contradicted this in any way. But appreciate the clarity of what 'implements' should do.

[Tipp, Brandon P] The example is slightly flawed. The section on conflicts would create a method name conflict at the declaration of der, which would require resolution within that class. That is already in the proposal. The declaration within der must be virtual (either implicitly or explicitly depending on the answer to #17). Despite the fact that der2 declares f() as non-virtual, it would be implicitly virtual once you have the [pure] virtual declaration in der. The desired behavior would be that der2::f() would be called. I think that resolving question #17 would be sufficient for this proposal; and if you want to clarify the behavior of a pure virtual method hiding a non-pure-virtual method then that should be opened in a new Mantis item since it is a broad question which happens to apply to some of the issues that we've been discussing.

GORD: I agree and that is what I said in earlier comments -- making it clear that a virtual prototype exists resolves the issue and it is then clear that the virtual definition at that point *hides* the earlier non-virtual method. All the subsequent behaviors follow directly.

 [...]

17) Does the user need to explicitly indicate "virtual" on the
    first implementing definition or is that implied by the implements
    in the same way as it would be during inheritance?
        interface class intf;
            pure virtual function void f();
        endclass
        class base implements intf;
            function void f(); endfunction
        endclass

talsop> It's a contract. When you implement an interface class the return type, the number of arguments, and types must all match. If the interface class declares a method as virtual, then the implementing class must declare it as virtual. We should make a 'shall' statement on this and note that implementations will issue and error if the user forgets this. So my take on this is the user must explicitly do this and we do not have any inheriting notions here. Can you imagine if the implementing class did not make this virtual, but it was 'inherited' how hard this would be to debug when the end user thought he was implementing an non-virtual interface method and it turned out to be polymorphic?

[Tipp, Brandon P] The interface class method must be virtual; the only question is if the "virtual" key word in an implementing class would be implicit like it is in an extending class . It sounds like you want it to be explicit and required, in which case something needs to be added to the proposal since that is not the behavior for inherited virtual methods. If declaring the method as virtual is implicit, I don't see a reason to change anything.

GORD -- I would object to having "virtual" be effectively inherited. This means that real class behavior flows from the interface class to the interface class -- the behavior of the class hierarchy changes due to the presence of the implements. I think that is a long-term recipe for debugging nightmares. Imagine that you had a long inheritance change from "base" (without the implements) and some much later descendent defined a "f" that hid base::f but happened to be compatible. By adding the implements you now change the behavior of any calls based on the intervening handle types. This will potentially lead to pretty fragile code where the fragile part is *behavior* and arbitrarily far away from the point of the "implements". I (and others on the committee) would much rather see a clear, local compile/elab error regarding a missing prototype than the otherwise bizarre issues that you'll have to debug.

Obviously just mechanically adding the prototype would introduce the issue, but that issue can be behaviorally debugged with the single prototype change in place; you don't have to make the problem more involved for the end person by adding the intellectual effort of having to think through what is going on with the implements and interface classes. You at least have fair warning that you are explicitly changing the behavior of a method.

If you can gather consensus for the implicit virtual application, then we'll have to change the wording. As I've continued to say, "implements" is not inheritance and use of that term will continue to have me object. You cannot appeal to inheritance to define the behavior of implements, you must define it explicitly. So unless you've already added explicit wording saying that a class method becomes virtual in this kind of case, I don't agree that such behavior would follow from the proposal.

Gord

--
--------------------------------------------------------------------
Gordon Vreugdenhil                                503-685-0808
Model Technology (Mentor Graphics)                gordonv@model.com<mailto:gordonv@model.com>
-- 
This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.
Received on Fri Aug 12 11:23:01 2011

This archive was generated by hypermail 2.1.8 : Fri Aug 12 2011 - 11:23:11 PDT