Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Here's the rule for function sub-typing:</p> <p><strong>Argument types must be contra-variant, return types must be co-variant.</strong></p> <p>Co-variant == preserves the "A is a subtype of B" hierarchy for the type of the results parameter. </p> <p>Contra-variant == <em>reverses</em> ("goes against") the type hierarchy for the arguments parameter.</p> <p>So, in your example:</p> <pre><code>f1: int -&gt; bool f2: bool -&gt; bool </code></pre> <p>We can safely conclude that f2 is a subtype of f1. Why? Because (1) looking at just the argument types for both functions, we see that the type hierarchy of "bool is a subtype of int" is in fact co-variant. It preserves the type hierarchy between ints and bools. (2) looking at just the results types for both functions, we see that contra-variance is upheld.</p> <p>Put another way (the plain English way I think about this subject):</p> <p>contra-variant arguments: "my caller can pass in <em>more</em> than I require, but that's okay, because I'll use only what I need to use." co-variant return values: "I can return <em>more</em> than the caller requires, but that's okay, he/she will just use what they need, and will ignore the rest"</p> <p>Let's look at another examples, using structs where everything is an integer:</p> <pre><code>f1: {x,y,z} -&gt; {x,y} f2: {x,y} -&gt; {x,y,z} </code></pre> <p>So here again, we're asserting that f2 is a subtype of f1 (which it is). Looking at the argument types for both functions (and using the &lt; symbol to denote "is a subtype of"), then if f2 &lt; f1, is {x,y,z} &lt; {x,y} ? The answer is yes. {x,y,z} is co-variant with {x,y}. i.e. in defining the struct {x,y,z} we "inherited" from the {x,y} struct, but added a third member, z.</p> <p>Looking at the return types for both functions, if f2 &lt; f1, then is {x,y} > {x,y,z}? The answer again is yes. (See above logic).</p> <p>Yet a third way to think about this, is to assume f2 &lt; f1, then try various casting scenarios, and see if everything works. Example (psuedo-code):</p> <pre><code> F1 = f1; F2 = f2; {a,b} = F1({1,2,3}); // call F1 with a {x,y,z} struct of {1,2,3}; This works. {a,b,c} = F2({1,2}); // call F2 with a {x,y} struct of {1,2}. This also works. // Now take F2, but treat it like an F1. (Which we should be able to do, // right? Because F2 is a subtype of F1). Now pass it in the argument type // F1 expects. Does our assignment still work? It does. {a,b} = ((F1) F2)({1,2,3}); </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload