Opting into totality

Guy Steele guy.steele at oracle.com
Tue Aug 25 16:59:53 UTC 2020


I have now gone back and re-read some of the previous email about totality, including four that I now quote below:

> On Aug 14, 2020, at 1:20 PM, Brian Goetz <brian.goetz at oracle.com> wrote:
> 
>>  . . . totality is a "subtree all the way down" property.

This observation was later refined by the message quoted below, but I think we never remarked explicitly on that fact.  It turns out that “weak totality” is a “subtree all the way down property” but “strong totality” is not.

> On Aug 20, 2020, at 3:09 PM, Brian Goetz <brian.goetz at oracle.com> wrote:
> 
> Here's an attempt at a formalism for capturing this.  
> 
> There are several categories of patterns we might call total on a type T.  We could refine the taxonomy as:
> 
>  - Strongly total -- matches all values of T.  
>  - Weakly total -- matches all values of T except perhaps null.
> 
> What we want to do is characterize the aggregate totality on T of a _set_ of patterns P*.  A set of patterns could in the aggregate be either of the above, or also: 
> 
>  - Optimistically total -- matches all values of subtypes of T _known at compile time_, except perhaps null.  
> 
> Note that we have an ordering:
> 
>     partial < optimistically total < weakly total < strongly total
> 
> Now, some rules about defining the totality of a set of patterns.  
> 
> T-Total: The singleton set containing the type pattern `T t` is strongly total on U <: T.  (This is the rule we've been discussing, but that's not the point of this mail -- we just need a base case right now.) 
> 
> T-Subset: If a set of patterns P* contains a subset of patterns that is X-total on T, then P* is X-total on T.  
> 
> T-Sealed: If T is sealed to U* (direct subtypes only), and for each U in U*, there is some subset of P* that is optimistically total on U, then P* is optimistically total on T.  
> 
> T-Nested: Given a deconstructor D(U) and a collection of patterns { P1..Pn }, if { P1..Pn } is X-total on U, then { D(P1)..D(Pn) } is min(X,weak)-total on D.

That “min(X,weak)” is crucial here.

> 
> OK, examples.
> . . .
> 
> { Box(Object o) } weakly total on Box<Object>
> 
>  - Object o total on Object
>  - { Object o } total on Object by T-Subset
>  - { Box(Object o) } weakly total on Box<Object> by T-Nested

So, going back to my earlier email about the box of frogs and the bag of objects:

> On Aug 12, 2020, at 10:46 PM, Guy Steele <guy.steele at oracle.com> wrote:
> 
>> On Aug 12, 2020, at 3:57 PM, forax at univ-mlv.fr <mailto:forax at univ-mlv.fr> wrote:
>> . . .
>> 
>> I agree destructuring is just as important as conditionality and those two things should be orthogonal.
>> But i still think having a keyword to signal that a pattern (not a case) is total is better than letting people guess.
> 
> Yes, and here is the example that convinced me that one needs to be able to mark patterns as total, not just cases:
> 
> (Assume for the following example that any pattern may be preceded by “default”, that the only implication of “default” is that you get a static error if the pattern it precedes is not total, and that we can abbreviate “case default” as simply “default”.)
> 
> 	record Box<T>(T t) { }
> 	record Bag<T>(T t) { }
> 
> 	record Pair<T,U>(T t, U u) { }
> 
> 	Triple<Box<Frog>, Bag<Object>> p;
> 
> 	switch (x) {
> 		case Pair(Box(Tadpole t), Bag(String s)): …
> 		case Pair(Box(Tadpole t), Bag(default Object o)): …
> 		case Pair(Box(default Frog f), Bag(String s)): …
> 		default Pair(Box(Frog f), Bag(Object o)): …
> 	}

and here we can see that this was wrong, now that we have the terminology to distinguish weak totality and strong totality.  When I wrote "you get a static error if the pattern it precedes is not total” we would now say "you get a static error if the pattern it precedes is not _strongly_ total”.  But “subtree all the way down” is a property of weak totality but not of string totality.  Therefore

	default Pair(Box(Frog f), Bag(Object o)): …

and

	case Pair(Box(default Frog f), Bag(default Object o)): …

do _not_ mean the same thing after all.  We conclude that not only is the latter preferable, as Rémi indicated:

> On Aug 13, 2020, at 8:19 AM, forax at univ-mlv.fr wrote:
> . . .
> 
> I think i prefer using "default" (or any other keyword) only where it makes sense and doesn't allow "default" to be propagated.
> so
>   default Pair p: ...
> is ok but 
>   default Pair(Box(Frog f), Bag(Object o)): …
> should be written
>   case Pair(Box(default Frog f), Bag(default Object o)): …

(I have corrected a typo), but in fact only the latter is _correct_.

Taking all this into account in the context of my latest proposal: while “switch case” would forbid the use of a switch label that begins with the keyword “default”, nevertheless “default” as a _pattern marker_ may be profitably used within a “switch case” construction:

	switch case (x) {
		case Pair(Box(Tadpole t), Bag(String s)): …
		case Pair(Box(Tadpole t), Bag(default Object o)): …
		case Pair(Box(default Frog f), Bag(String s)): …
		case Pair(Box(default Frog f), Bag(default Object o)): …
	}

or perhaps just

	switch case (x) {
		case Pair(Box(Tadpole t), Bag(String s)): …
		case Pair(Box(Tadpole t), Bag(Object o)): …
		case Pair(Box(Frog f), Bag(String s)): …
		case Pair(Box(default Frog f), Bag(default Object o)): …
	}

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20200825/17fde31b/attachment.htm>


More information about the amber-spec-experts mailing list