<!DOCTYPE HTML>
<html>
<head>
	<title>Contracts and virtual functions for the Contracts MVP</title>

	<style>
	p {text-align:justify}
	li {text-align:justify}
	blockquote.note
	{
		background-color:#E0E0E0;
		padding-left: 15px;
		padding-right: 15px;
		padding-top: 1px;
		padding-bottom: 1px;
	}
	ins {color:#00A000}
	del {color:#A00000}
	</style>
</head>
<body>

<address align=right>
Document number: P2954R0
<br/>
Audience: SG21
<br/>
<br/>
<a href="mailto:ville.voutilainen@gmail.com">Ville Voutilainen</a><br/>
2023-08-03<br/>
</address>
<hr/>
<h1 align=center>Contracts and virtual functions for the Contracts MVP</h1>

<h2>Abstract</h2>

<p>There have been various disagreements and different understandings
  on how contracts on virtual function overrides should behave.
  There is disagreement over whether an override should allow only
  contracts that are identical to the functions overridden, and there's
  disagreement over whether requiring an override of multiple base
  functions to have "the same list of contract annotations" is the right
  choice.</p>
<p>So, to decouple this problem from the progress of the MVP, this paper
  proposes a simple solution that makes the uncertain cases ill-formed,
  and makes well-formed the cases that have no future compatibility risk. Thus:
  <ol>
    <li>a virtual function that overrides a base function cannot have any
      contract annotation on the declaration of the override. It will inherit the contract of the function that it overrides, so when called via a reference/pointer to a base, the preconditions and postconditions of the base function are still checked, but the definition that is called is the override.</li>
    <li>if a virtual function overrides multiple base functions, none
      of those base functions can have any contract annotations on their declarations.</li>
  </ol>
</p>

<h2>Rationale</h2>

<p>The main goal here is to avoid any and all complexity, and be able
  to ship the MVP in C++26 without getting bogged down into questions
  and discussions about what "identical" means, what "narrower" means,
  and what "wider" means, and even what "substitutable" means, and according
  to what definition/principle/rule.</p>

<h2>What the MVP currently says</h2>

<p>In <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2388r4.html">P2388R4</a>, the wording part says two relevant things:
  <ol>
    <li> If an overriding function specifies contract annotations (9.12.4), it shall specify the same list of contract annotations as its overridden functions</li>
    <li>If a function overrides more than one function, all of the overridden functions shall have the same list of contract annotations</li>
  </ol>
</p>
<p>In <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2521r4.html">P2521R4</a>, however, <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2521r4.html#pro.vir">{pro.vir}</a> says what the first
  part of this proposal says, that an override cannot have a contract of its own, but inherits the contract of the overridden base function.</p>
<p>In <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2521r4.html#pro.2bs">{pro.2bs}</a>, that same paper suggests that what happens
  with an override that overrides multiple base functions is something that
  "we do not want to specify".</p>

<h2>What this proposal proposes saying</h2>

<p>
  <ol>
    <li>An overriding function shall not specify contract annotations, and inherits the contract of the overridden function</li>
    <li>If a function overrides more than one function, none of the overridden functions shall specify contract annotations</li>
  </ol>
</p>

<h2>Some explanation of what is complex and why</h2>

<p>The MVP already has some complex bits in it for simple overrides;
  it states that "the program is ill formed, no diagnostic required, if name lookup in the predicate finds different entities than if the name lookup were performed in the context of the base class". This is skating around a problem
  with "identical" and "shall have the same list of contract annotations".
</p>
<p>Token-by-token equality ends up being useless, because using-declarations can change
  what tokens mean in different scopes, and overriding functions can be
  in very different scopes from their base functions; they can be in different
  namespaces. Any use of something like decltype(*this) might well be
  token-by-token identical, but have a different meaning. IFNDR is a big
  hammer, and hard to understand, so we can apply a much simpler
  approach by completely avoiding the problematic cases.</p>
<p>"ODR-identical" is a lofty notion, but even if an implementation could
  perhaps compute that identicality without much trouble, we don't have any
  field experience on what that's like for users. So, again, we can apply
  a much simpler approach by completely avoiding the problematic cases.</p>
<p>We actually do have an implementation of checking odr-identicality
  for a virtual function override that has its own contract declaration; that is
  properly checked by GCC for identicality with a single overridden base function. That implementation, however, doesn't check multiple base function
  contracts for identicality in the case where the override doesn't have
  a contract declared.</p>

<h2>So, what do we lose?</h2>

<p>For the inability to be able to repeat the contract of an overridden
  function, we can't, for example, write a class with a dependent
  base that adds a contract if a virtual function is not an override,
  but repeats it if the virtual function is an override, depending
  on whether the dependent base declares such a virtual function.</p>
<p>For the same restriction, we can't repeat a contract that we'd like
  to repeat for ease-of-reading purposes, or for the hope that if the
  contract ends up deviating from the base function's contract, we'd get
  some sort of a diagnostic.</p>
<p>For the multiple inheritance restriction, we can't mix base classes
  with virtual functions with contracts on them into classes that inherit
  multiple bases. This is a fairly strict structural design restriction,
  and more or less makes contract annotations on virtual functions and
  multiple inheritance incompatible. It will more or less discourage
  using contract annotations on virtual functions overall to some extent,
  and certainly discourage using such annotations unless there's some
  confidence that multiple inheritance mixtures aren't likely to be used.</p>

<h2>So, what do we gain?</h2>

<p>
  We don't have to precisely define what "identical" or "has the same list
  of contract annotations" means. We have fewer technical obstacles to
  conquer, while keeping the ability to contract-annotate simple
  single-inheritance cases at their base function level. We can entertain
  future designs that do not restrict a contract of an override to be
  identical, we can entertain allowing them to be wider or narrower,
  once we've had more time to do more design work, more time to think about
  those problems, more time to discuss them and gain a shared understanding
  of them, and more time to experiment with those ideas.
</p>
<p>We also keep completely open a design option of, in a future revision,
  allowing a contract on an override to be different from that of the
  base, being additive. There's a strong likelihood that we will eventually
  see a proposal for that.</p>

</body>
</html>
