Decidable Tag-Based Semantic Subtyping for Nominal Types, Tuples, and Unions

12/17/2019
by   Julia Belyakova, et al.
Northeastern University
0

Semantic subtyping enables simple, set-theoretical reasoning about types by interpreting a type as the set of its values. Previously, semantic subtyping has been studied primarily in the context of statically typed languages with structural typing. In this paper, we explore the applicability of semantic subtyping in the context of a dynamic language with nominal types. Instead of static type checking, dynamic languages rely on run-time checking of type tags associated with values, so we propose using the tags for semantic subtyping. We base our work on a fragment of the Julia language and present tag-based semantic subtyping for nominal types, tuples, and unions, where types are interpreted set-theoretically, as sets of type tags. The proposed subtyping relation is shown to be decidable, and a corresponding analytic definition is provided. The implications of using semantic subtyping for multiple dispatch are also discussed.

READ FULL TEXT VIEW PDF
POST COMMENT

Comments

There are no comments yet.

Authors

page 1

page 2

page 3

page 4

09/19/2018

Audio Based Disambiguation Of Music Genre Tags

In this paper, we propose to infer music genre embeddings from audio dat...
04/19/2017

Dependency resolution and semantic mining using Tree Adjoining Grammars for Tamil Language

Tree adjoining grammars (TAGs) provide an ample tool to capture syntax o...
12/05/2020

A Sequence-Oblivious Generation Method for Context-Aware Hashtag Recommendation

Like search, a recommendation task accepts an input query or cue and pro...
07/10/2021

Approximate Normalization and Eager Equality Checking for Gradual Inductive Families

Harnessing the power of dependently typed languages can be difficult. Pr...
08/22/2017

Tags2Parts: Discovering Semantic Regions from Shape Tags

We propose a novel method for discovering shape regions that strongly co...
07/11/2013

Artificial Intelligence MArkup Language: A Brief Tutorial

The purpose of this paper is to serve as a reference guide for the devel...
10/18/2019

Gradual Typing for Extensibility by Rows

This work studies gradual typing for row types and row polymorphism. Key...
This week in AI

Get the week's most popular data science and artificial intelligence research sent straight to your inbox every Saturday.

1. Introduction

In static type systems, subtyping is used to determine when a value of one type can be safely used at another type. It is often convenient to think of subtyping T S in terms of the set inclusion: “the elements of T are a subset of the elements of S” (Pierce, 2002). This intuition is not always correct, but, in the case of semantic subtyping (Hosoya and Pierce, 2003; Frisch et al., 2008; Ancona and Corradi, 2016), subtyping is defined exactly as the subset relation. Under semantic subtyping, types are interpreted as sets , and subtyping is defined as inclusion of the interpretations .

Subtyping can also be used for run-time dispatch of function calls. For example, object-oriented languages usually support single dispatch — the ability to dispatch a method call based on the run-time type of the receiver object. A more complex form of dispatch is multiple dispatch (MD) (Chambers, 1992; Clifton et al., 2000), which takes into account run-time types of all arguments when dispatching a function call. One way to implement MD is to interpret both function signatures and function calls as tuple types (Leavens and Millstein, 1998) and then use subtyping on these types.

Dynamic dispatch is not limited to statically typed languages, with multiple dispatch being even more widespread among dynamically typed ones, e.g., CLOS, Julia, Clojure. Unlike statically typed languages, which conservatively prevent type errors at compile-time, dynamic languages detect type errors at run-time: whenever an operator is restricted to certain kinds of values, the run-time system checks type tags associated with the operator’s arguments to determine whether it can be safely executed. A type tag indicates the run-time type of a value. Thus, any class that can be instantiated induces a tag — the name of the class — whereas an abstract class or interface does not. Some structural types also give rise to tags, e.g., tuples and sums (tagged unions).

While dynamically typed languages do use subtyping, semantic subtyping is not applicable in this case, for the semantic definition refers to a static typing relation. To enable semantic reasoning in the context of dynamic languages, we propose tag-based semantic subtyping where a type is interpreted as a set of run-time type tags instead of values.

We define tag-based semantic subtyping for a fragment of the Julia language (Bezanson et al., 2017) that includes nominal types, tuples, and unions. Tuples and unions are rather typical for semantic subtyping systems; they have a clear set-theoretic interpretation and make up an expressive subtyping relation where tuples distribute over unions. At the same time, to the best of our knowledge, the interaction of unions with nominal types has not been studied before in the context of semantic subtyping. This interaction introduces an unusual subtyping rule between abstract nominal types and unions, with implications for multiple dispatch. Note that the combination of unions and nominal types is not unique to Julia; for instance, it also appears in the statically typed language Ceylon (King, 2017).

Our contributions are as follows:

  1. A definition of tag-based semantic subtyping for nominal types, tuples, and unions (Sec. 2).

  2. Two syntactic definitions of subtyping, declarative (Sec. 3.1) and reductive (Sec. 3.2), along with Coq-mechanized proofs that these definitions are equivalent and coincide with the semantic definition (Sec. 4).

  3. Proof of decidability of reductive subtyping (App. C).

  4. Discussion of the implications of using semantic subtyping for multiple dispatch, as well as an alternative semantic interpretation of nominal types (Sec. 5).

2. Semantic Subtyping in MiniJl

We base our work on a small language of types MiniJl, presented in Fig. 1. Types, denoted by , include pairs, unions, and nominal types; denotes concrete nominal types that can be instantiated, and denotes abstract nominal types.

Num

Real

Int

Flt

Cmplx

Str
Figure 1. MiniJl: type grammar and nominal hierarchy

We work with a particular hierarchy of nominal types (presented in Fig. 1 as a tree) instead of a generic class table to simplify the development. There are four concrete leaf types (depicted in rectangles) and two abstract types in the hierarchy. Formally, the hierarchy can be represented with a list of declarations read as “ extends ” where is either or . In the case of MiniJl, the hierarchy is defined as follows:

Nominal hierarchies should not have cycles, and each type can have only one parent.

Value Types

Only instantiatable types induce type tags, which we call value types. Their formal definition is given in Fig. 2: value type is either a concrete nominal type or a pair of value types. For example, , , and are all value types. Union types, like abstract nominal types, are not value types. Therefore, a type such as is not a value type despite it describing the same set of values as the value type .

Figure 2. Value types

2.1. Semantic Interpretation of Types

As mentioned in Sec. 1, we interpret a type as a set of type tags (i.e. value types) instead of values and call this semantic interpretation tag-based. Formally, the interpretation is given by the function that maps a type into a set of value types , as presented in Fig. 3.

Figure 3. Tag-based semantic interpretation of types

A type’s interpretation states what values constitute the type: means that values tagged with (i.e. instances of ) belong to . Thus, in MiniJl, a concrete nominal type is comprised only of its direct instances.111In the general case, the interpretation of a concrete nominal type would include the type and all its concrete subtypes. Abstract nominal types cannot be instantiated, but their interpretation needs to reflect the nominal hierarchy. For example, a value is either a concrete complex or real number, which in turn is either a concrete integer or a floating point value. Therefore, the set of value types describes the set of all possible values of type . More generally, the interpretation of an abstract nominal type can be given as follows:

where the relation means that nominal type transitively extends : *[right=] ∈NomHrc

*[right=]
. Finally, pairs and unions are interpreted set-theoretically as in standard semantic subtyping.

Once we have the tag interpretation of types, we define tag-based semantic subtyping in the usual manner — as the subset relation:

(1)

3. Syntactic Definitions of Subtyping

While the semantic approach does enable intuitive set-theoretic reasoning about subtyping, a subtyping relation also needs to be computable. However, the semantic definition (1) does not suit this purpose, as it operates on interpretations. In the general case, the interpretation of a type can be an infinite set, and as such, it cannot be computed. In the finite case, generating the interpretation sets and checking the subset relation on them would be inefficient. Therefore, we provide an alternative, syntactic definition of subtyping that is equivalent to (1) and straightforward to implement.

We do this in two steps. First, we give an inductive declarative definition that is handy to reason about and prove it equivalent to the semantic definition. Second, we provide a reductive analytic222Inference rules are called analytic (Martin-Löf, 1994) if there is a finite number of rules applicable to a judgment, and the premises of each rule are comprised of the subcomponents of its conclusion. Such rules give rise to a straightforward bottom-up algorithm. If there is always only one rule applicable to a judgment, analytic rules are called syntax-directed. definition of subtyping and prove it equivalent to the declarative one (and, hence, the semantic definition as well). We prove that the reductive subtyping relation is decidable, i.e. for any two types and , it is possible to prove that either is a subtype of or it is not. The proofs are mechanized in Coq, and since Coq logic is constructive, the decidability proof is also a subtyping algorithm. The algorithm can also be implemented as a straightforward recursive function.

3.1. Declarative Subtyping

The declarative syntactic definition of subtyping is provided in Fig. 4. It comprises most of the standard rules of syntactic subtyping for unions and pairs: reflexivity and transitivity (SD-Refl and SD-Trans), subtyping of pairs (SD-Pairs), and subtyping of unions (SD-UnionL, SD-UnionR1, SD-UnionR2). Though SD-UnionR* rules are seemingly very strict (they require the left-hand side type to be syntactically equivalent to a part of the right-hand side type), transitivity allows us to derive judgments such as via and .

Note that all rules from Fig. 4 are essential for the definition to be equivalent to semantic subtyping. Thus, for example, the syntactic definition needs to be reflexive and transitive because so is the subset relation, which is used to define semantic subtyping. Semantic subtyping also forces us to add rules for distributing pairs over unions, SD-Distr1 and SD-Distr2. For instance, consider two types, and . They have the same semantic interpretation —  — so they are equivalent. Therefore, we should also be able to derive their equivalence using the declarative definition, i.e. declarative subtyping should hold in both directions. One direction is trivial: *[right=] *[right=]

*[right=] … .
But the other direction,

cannot be derived without SD-Distr2 rule.

The novel part of the definition resides in subtyping of nominal types. There are four obvious rules coming directly from the nominal hierarchy, for instance, SD-RealNum mirrors the fact that . But the rules SD-RealUnion and SD-NumUnion (highlighted in Fig. 4) are new, dictated by semantic subtyping. Thus, SD-RealUnion allows us to prove the equivalence of types and , which are both interpreted as .


*[right=SD-Refl]

*[right=SD-Trans]

[SD-IntReal]

[SD-FltReal]

[SD-RealNum]

[SD-CmplxNum]


*[right=SD-Pair]

[SD-UnionL]

[SD-UnionR1]

[SD-UnionR2]

*[right=SD-Distr1]

*[right=SD-Distr2]

Figure 4. Declarative subtyping for MiniJl

3.2. Reductive Subtyping

The declarative definition is neither syntax-directed nor analytic and cannot be directly turned into a subtyping algorithm. For one, the transitivity rule SD-Trans overlaps with any other rule in the system and also requires “coming up” with an intermediate type to conclude . For instance, to derive

we need to apply transitivity several times, in particular, with the intermediate type . Another source of overlap is the reflexivity and distributivity rules.



[SR-IntReal]

[SR-FltReal]

[SR-CmplxNum]


*[right=SR-Pair]

*[right=SR-UnionL]


Figure 5. Reductive subtyping for MiniJl

By contrast, the rules of reductive subtyping enable straightforward bottom up reasoning; the rules are presented in Fig. 5. The reductive definition lacks the most problematic rules of declarative subtyping, i.e. general reflexivity, transitivity, and distributivity. Some of the inductive rules have the exact declarative counterparts, e.g. subtyping of pairs (SR-Pair) or subtyping of a union on the left (SR-UnionL).

The differing rules are highlighted. The explicit reflexivity rule SR-BaseRefl now only works with concrete nominal types, but this already makes the reductive definition reflexive. The definition also has to be transitive, so several rules are added or modified to enable derivations that used to rely on transitivity in the declarative definition. These include subtyping of nominal types (SR-IntNum, SR-FltNum), subtyping of a union on the right (SR-UnionR1, SR-UnionR2), and normalization (SR-NF).

The last rule of the definition, SR-NF, is the most important, as it covers all useful interactions of transitivity and distributivity that are possible in the declarative definition. The rule rewrites type into its normal form before applying other subtyping rules. Any normalized type has the form , i.e. a union of value types (we omit parenthesis because union is associative). The normalization function is presented in Fig. 6 (the auxiliary function can be found in Fig. 9, App. A). It produces a type in disjunctive normal form by replacing an abstract nominal type with the union of all its concrete subtypes, and a pair of unions with the union of pairs of value types (each of this pairs is itself a value type), for instance:

As shown in Sec. 4.1, a type and its normal form are equivalent according to the declarative definition. This property is essential for the reductive subtyping being equivalent to the declarative one.

Figure 6. Computing normal form of MiniJl types

Subtyping Algorithm.

The reductive rules are analytic, and if a derivation of exists, it can always be found by the following algorithm.

  1. Use the normalization rule SR-NF once (normalize );

  2. Use all the other rules to derive in the standard manner, bottom up; except for an overlap between SR-UnionR1 and SR-UnionR2, these rules are syntax-directed.

However, this algorithm does not always produce the shortest derivation. For instance, for , it produces a derivation with eight applications of the rules, whereas the shortest derivation needs only five applications (see App. B). It is possible that in practice, an algorithm that tries the short path first and only then resorts to normalization would work better.

The actual Julia implementation uses a clever algorithm to check subtyping of tuples and unions without having to normalize types (Chung et al., 2019). The algorithm is equivalent to the normalization-based one discussed above, but instead of computing the whole normal form, it computes only the components of the normalized type, one at a time.

Note that the rules for subtyping of nominal types do not have to be built-in. Instead of five separate rules, as presented in Fig. 5, we can use a single rule that relies on the relation ( transitively extends ) from Sec. 2.1: *[right=SR-Nom] . Then, for any and , the relation can be checked algorithmically, using the nominal hierarchy NomHrc.

4. Properties of Subtyping Relations

4.1. Correctness of Declarative Subtyping


*[right=MT-CName]

[MT-IntReal]

[MT-FltReal]

[MT-IntNum]

[MT-FltNum]

[MT-CmplxNum]

*[right=MT-Pair]

*[right=MT-Union1]

*[right=MT-Union2]

Figure 7. Matching relation in MiniJl

In order to show correctness of declarative subtyping, we need to prove that the declarative definition of subtyping is sound and complete with respect to the semantic definition. Formally, we write this statement as:

(2)

Instead of directly proving (2), it is more convenient to prove the equivalence of declarative subtyping to the following relation (referred to as matching-based semantic subtyping):

(3)

The definition (3) relies on the relation (defined in Fig. 7), read “tag  matches type ”, which we call the matching relation.

Tag-based and matching-based semantic subtyping relations are equivalent:

To see why, let us recall that tag-based semantic subtyping (1) is defined as and the subset relation as . Therefore, the definition (1) can be rewritten as:

(4)

It is easy to show by induction on that the matching relation is equivalent to the belongs-to relation . Therefore, the definitions (3) and (4) are also equivalent.

Since is equivalent to and the equivalence relation is transitive, it suffices to prove the following theorem to show (2).

Theorem 1 (Correctness of Declarative Subtyping).

The full proof of Theorem 1 is Coq-mechanized (Belyakova, 2018), so we only discuss some key aspects and leave details to the proof. First, subtyping a value type coincides with matching:

(5)

Having that, we can prove , i.e. the soundness direction of Theorem 1 (below, we embed the definition (3) of matching-based semantic subtyping):

(6)

Knowing and , we need to show that . First, by applying (5) to , we get . Then, follows from and by transitivity. Finally, by applying (5) again, we get . ∎

The other direction of Theorem 1 is more challenging:

(7)

The key observation here is that (7) can be shown for in normal form, i.e. (formally, this fact is denoted by predicate defined in Fig. 8, App. A):

(8)

In this case, in the definition (3) of , the only value types that match and are of . By (5), we know that matching implies subtyping, so we conclude that all . From the latter, it is easy to show that because, according to the SD-UnionL rule, subtyping of the left-hand side union amounts to subtyping its components. To show (7), we need several more facts in addition to (8).

  • Function produces a type in normal form:

    (9)
  • Normalized type is equivalent to the source type:

    (10)
  • Normalization preserves the subtyping relation:

    (11)

To prove (7), we need to show given . For this, we first apply (11) to , which gives . Then we can apply (8) to the latter because of (9) to get . Finally, (10) and transitivity gives . ∎

4.2. Reductive Subtyping

Since we have already shown that declarative subtyping is equivalent to semantic subtyping, it suffices to show that reductive subtyping is equivalent to declarative subtyping:

Theorem 2 (Correctness of Reductive Subtyping).

The proof is split into two parts: soundness and completeness. For soundness (completeness), we show that for each SR- rule (SD- rule) it is possible to build a corresponding declarative (reductive) derivation using SD- rules (SR- rules).

The soundness direction is mostly straightforward, as most SR- rules have an immediate SD- counterpart (or require one extra application of transitivity). In the case of SR-NF, the induction hypothesis of the proof, , and the fact that according to (10), allow to conclude .

The challenging part of the proof is to show completeness, as this requires proving that the reductive definition is reflexive, transitive, and distributive (App. C).

Theorem 3 (Decidability of Reductive Subtyping).

To prove the theorem, it suffices to show that reductive subtyping is decidable when is in normal form. This is done by induction on a derivation of . We refer the reader to App. C for more details.

5. Semantic Subtyping and
Multiple Dynamic Dispatch

We set out to define semantic subtyping that can be useful in the context of dynamic languages, however, the semantic definition we presented appears to have an undesired implication for dynamic dispatch. In this section, using multiple dispatch as a running example, we discuss the implication and suggest a solution.

Consider the following methods333In the context of MD, different implementations of the same function are usually called methods, and the set of all methods a generic function. of the addition function defined in the Julia syntax (we assume that function flt converts its argument to a float):

+(x::Int, y::Int) = prim_add_int(x, y)
+(x::Flt, y::Flt) = prim_add_flt(x, y)
+(x::IntFlt, y::IntFlt) = prim_add_flt(flt(x), ..)

and the function call 3 + 5. With multiple dynamic dispatch, the call is resolved at run-time, based on the types of all arguments. But how exactly does method resolution work?

One approach to implementing multiple dispatch, adopted by some languages such as Julia (Bezanson, 2015), is to use subtyping on tuple types (Leavens and Millstein, 1998). Namely, method signatures and function calls are interpreted as tuple types, and then subtyping is used to determine applicable methods as well as pick one of them. In the example above, the three methods are interpreted as the following types (from top to bottom):
mII Int Int
mFF Flt Flt
mUU (IntFlt) (IntFlt)
and the call as having type cII Int Int. To resolve the call, the language run-time ought to perform two steps.

  1. Find the applicable methods (or raise an error if there are none). For this, subtyping is checked between the type of the call cII and the method signatures. Since cII mII and cII mUU but cII mFF, only two methods are applicable — mII for integers and mUU for mixed-type numbers.

  2. Pick the most specific of the applicable methods (or raise an error if there is an ambiguity). For this, subtyping is checked pairwise between all the applicable methods. In this example, naturally, we would like mII to be called for 3 + 5. And indeed, since mII mUU and mUU mII, the integer addition is picked as the most specific.

As another example, consider the call 3.14 + 5, which type is Flt Int. There is only one applicable method mUU that is a supertype of the call type, so it should be picked.

What happens if the programmer defines several implementations with the same argument types? In the case of a static language, an error can be reported. In the case of a dynamic language, however, the second implementation simply replaces the earlier one in the same way as reassignment to a variable replaces its previous value.

For instance, consider a program that contains the three previous implementations of (+) and also:

+(x::Real, y::Real) = ...   # mRR
print(3.14 + 5)

According to the semantic subtyping relation, type Real is equivalent to IntFlt in MiniJl. Therefore, the implementation of mRR will replace mUU defined earlier, and the mixed-type call 3.14 + 5 will be dispatched to mRR.

But there is a problem: the semantics of the program above will change if the programmer adds a new subtype of Real into the nominal hierarchy, e.g. Int8 Real. In this case, type Real stops being equivalent to IntFlt and becomes equivalent to IntFltInt8. Thus, when the program is re-run, type mUU will be a strict subtype of mRR, so the implementation of mRR will not replace mUU. Therefore, this time, the call 3.14 + 5 will be dispatched to mUU, not mRR as before.

We can gain stability by removing subtyping rules that equate abstract nominal types with the union of their subtypes (i.e. SD-RealUnion and SD-NumUnion in the declarative definition444To get equivalent reductive subtyping, we need to change the SR-NF rule by replacing normalization function with (Fig. 11, App. A). from Fig. 4). Then, to fix the discrepancy between the new definition and semantic subtyping, the latter should be modified. To account for potential extension of the nominal hierarchy, abstract nominal type can be interpreted as containing an extra element  — “a future subtype of ”. In the case of MiniJl, the new interpretation is as follows:

It can be shown that the modified declarative definition of subtyping is equivalent to semantic subtyping based upon the new interpretation.555The proof can be found in FullAtomicJl folder of (Belyakova, 2018).

6. Related Work

Semantic subtyping has been studied primarily in the context of statically typed languages with structural typing. For example, Hosoya and Pierce (2003) defined a semantic type system for XML that incorporates unions, products, and recursive types, with a subtyping algorithm based on tree automata (Hosoya et al., 2005). Frisch et al. (2008) presented decidable semantic subtyping for a language with functions, products, and boolean combinators (union, intersection, negation); the decision procedure for is based on checking the emptiness of . Dardha et al. (2013) adopted semantic subtyping to objects with structural types, and Ancona and Corradi (2016) proposed decidable semantic subtyping for mutable records. Unlike these works, we are interested in applying semantic reasoning to a dynamic language with nominal types.

Though multiple dispatch is more often found in dynamic languages, there has been research on safe integration of dynamic dispatch into statically typed languages (Chambers, 1992; Castagna et al., 1992; Clifton et al., 2000; Allen et al., 2011; Park et al., 2019). There, subtyping is used for both static type checking and dynamic method resolution. In the realm of dynamic languages, Bezanson (2015) employed subtyping for multiple dynamic dispatch in the Julia language. Julia has a rich language of type annotations (including, but not limited to, nominal types, tuples, and unions) and a complex subtyping relation (Zappa Nardelli et al., 2018). However, it is not clear whether the subtyping relation is decidable or even transitive, and transitivity of subtyping is important for correct implementation of method resolution. In this paper, while we work with only a subset of Julia types, subtyping is transitive and decidable.

Recently, a framework for building transitive, distributive, and decidable subtyping of union and intersection types was proposed by Muehlboeck and Tate (2018). Our language of types does not have intersection types but features pair types that distribute over unions in a similar fashion.

Finally, Chung et al. (2019) proved that Julia’s algorithm for subtyping tuples, unions, and primitive types (without a nominal hierarchy) is equivalent to a semantic subtyping model similar to ours. Combined with our results, this shows that a normalization-based subtyping algorithm for tuples and unions can be implemented efficiently.

7. Conclusion and Future Work

We have presented a decidable relation for subtyping of nominal types, tuples, and unions. Our system has the advantages of semantic subtyping, such as simple set-theoretic reasoning, yet it can be used in the context of dynamically typed languages. We interpret types in terms of type tags, as is typical for dynamic languages, and provide a decidable syntactic subtyping relation equivalent to the subset relation of the interpretations (aka tag-based semantic subtyping).

We found that the initially proposed subtyping relation, if used for dynamic dispatch, would make the semantics of dynamically typed programs unstable due to an interaction of abstract nominal types and unions. A slightly different semantic interpretation of nominal types appeared to fix the issue, and we would like to further explore this alternative.

In future work, we plan to extend tag-based semantic subtyping to top and bottom types, and also invariant type constructors such as parametric references :

As usual for invariant constructors, we would like types such as and to be equivalent. However, a naive interpretation of invariant types below is not well defined because to find all s.t. , we need to already know all the interpretations:

Our plan is to introduce an indexed interpretation

and define semantic subtyping as:

Acknowledgements.
We are grateful to Ryan Culpepper, Artem Pelenitsyn, and Mitchell Wand for insightful conversations. We thank Ellen Arteca, Benjamin Chung, Jane Kokernak, Artem Pelenitsyn, Alexi Turcotte, Jan Vitek, and anonymous reviewers for feedback on earlier drafts of the paper.

References

  • E. Allen, J. Hilburn, S. Kilpatrick, V. Luchangco, S. Ryu, D. Chase, and G. Steele (2011) Type checking modular multiple dispatch with parametric polymorphism and multiple inheritance. SIGPLAN Not. 46 (10), pp. 973–992. External Links: ISSN 0362-1340, Link, Document Cited by: §6.
  • D. Ancona and A. Corradi (2016) Semantic subtyping for imperative object-oriented languages. In Proceedings of the 2016 ACM SIGPLAN International Conference on Object-Oriented Programming, Systems, Languages, and Applications, OOPSLA 2016, New York, NY, USA, pp. 568–587. External Links: ISBN 978-1-4503-4444-9, Link, Document Cited by: §1, §6.
  • J. Belyakova (2018) Coq mechanization of MiniJl. External Links: Link Cited by: Appendix C, §4.1, footnote 5.
  • J. Bezanson, A. Edelman, S. Karpinski, and V. B. Shah (2017) Julia: a fresh approach to numerical computing. SIAM review 59 (1), pp. 65–98. External Links: Link Cited by: §1.
  • J. Bezanson (2015) Abstraction in technical computing. Cited by: §5, §6.
  • G. Castagna, G. Ghelli, and G. Longo (1992) A calculus for overloaded functions with subtyping. In Proceedings of the 1992 ACM Conference on LISP and Functional Programming, LFP ’92, New York, NY, USA, pp. 182–192. External Links: ISBN 0-89791-481-3, Link, Document Cited by: §6.
  • C. Chambers (1992) Object-oriented multi-methods in cecil. In Proceedings of the European Conference on Object-Oriented Programming, ECOOP ’92, Berlin, Heidelberg, pp. 33–56. External Links: ISBN 3-540-55668-0, Link Cited by: §1, §6.
  • B. Chung, F. Zappa Nardelli, and J. Vitek (2019) Julia’s efficient algorithm for subtyping unions and covariant tuples (pearl). In 33rd European Conference on Object-Oriented Programming (ECOOP 2019), pp. (To appear). Cited by: §3.2, §6.
  • C. Clifton, G. T. Leavens, C. Chambers, and T. Millstein (2000) MultiJava: modular open classes and symmetric multiple dispatch for java. In Proceedings of the 15th ACM SIGPLAN Conference on Object-oriented Programming, Systems, Languages, and Applications, OOPSLA ’00, New York, NY, USA, pp. 130–145. External Links: ISBN 1-58113-200-X, Link, Document Cited by: §1, §6.
  • O. Dardha, D. Gorla, and D. Varacca (2013) Semantic subtyping for objects and classes. In Formal Techniques for Distributed Systems, D. Beyer and M. Boreale (Eds.), Berlin, Heidelberg, pp. 66–82. Cited by: §6.
  • A. Frisch, G. Castagna, and V. Benzaken (2008) Semantic subtyping: dealing set-theoretically with function, union, intersection, and negation types. J. ACM 55 (4), pp. 19:1–19:64. External Links: ISSN 0004-5411, Link, Document Cited by: §1, §6.
  • H. Hosoya and B. C. Pierce (2003) XDuce: a statically typed xml processing language. ACM Trans. Internet Technol. 3 (2), pp. 117–148. External Links: ISSN 1533-5399, Link, Document Cited by: §1, §6.
  • H. Hosoya, J. Vouillon, and B. C. Pierce (2005) Regular expression types for xml. ACM Trans. Program. Lang. Syst. 27 (1), pp. 46–90. External Links: ISSN 0164-0925, Link, Document Cited by: §6.
  • G. King (2017) The ceylon language specification, version 1.3. External Links: Link Cited by: §1.
  • G. T. Leavens and T. D. Millstein (1998) Multiple dispatch as dispatch on tuples. In Proceedings of the 13th ACM SIGPLAN Conference on Object-oriented Programming, Systems, Languages, and Applications, OOPSLA ’98, New York, NY, USA, pp. 374–387. External Links: ISBN 1-58113-005-8, Link, Document Cited by: §1, §5.
  • P. Martin-Löf (1994) Analytic and synthetic judgements in type theory. In Kant and Contemporary Epistemology, P. Parrini (Ed.), pp. 87–99. External Links: ISBN 978-94-011-0834-8, Document, Link Cited by: footnote 2.
  • F. Muehlboeck and R. Tate (2018) Empowering union and intersection types with integrated subtyping. Proc. ACM Program. Lang. 2 (OOPSLA), pp. 112:1–112:29. External Links: ISSN 2475-1421, Link, Document Cited by: §6.
  • G. Park, J. Hong, G. L. Steele Jr., and S. Ryu (2019)

    Polymorphic symmetric multiple dispatch with variance

    .
    Proc. ACM Program. Lang. 3 (POPL), pp. 11:1–11:28. External Links: ISSN 2475-1421, Link, Document Cited by: §6.
  • B. C. Pierce (2002) Types and programming languages. 1st edition, The MIT Press. External Links: ISBN 0262162091, 9780262162098 Cited by: §1.
  • F. Zappa Nardelli, J. Belyakova, A. Pelenitsyn, B. Chung, J. Bezanson, and J. Vitek (2018) Julia subtyping: a rational reconstruction. Proc. ACM Program. Lang. 2 (OOPSLA), pp. 113:1–113:27. External Links: ISSN 2475-1421, Link, Document Cited by: §6.

Appendix A Normal Forms

*[right=NF-ValType] ()

*[right=NF-Union] ( _1)
( _2) ()

Figure 8. Normal form of types in MiniJl
Figure 9. Computing normal form of MiniJl types

[Atom-CName] ()

[Atom-AName] ()

*[right=NFAt-Atom] () ()

*[right=AtNF-Union] ( _1)
( _2) ()

Figure 10. Atomic normal form of types in MiniJl
Figure 11. Computing atomic normal form of MiniJl types

Fig. 8 defines the predicate , which states that type is in normal form. Fig. 9 contains the full definition of function, which computes the normal form of a type.

Fig. 10 and Fig. 11 present “atomic normal form”, which can be used to define reductive subtyping that disables derivations such as .

Appendix B Non-unique Derivations

There are two derivations of

The shortest derivation: *[right=Pair] [BaseRefl]
*[right=UnionL] [IntReal]
[FltReal]
The normalization-based derivation: *[right=NF] *[right=UnionL]


Appendix C Overview of Coq Proofs

In this section we give a brief overview of the Coq-mechanization (Belyakova, 2018) of the paper. When referring to a file fname, we mean the file Mechanization/fname in (Belyakova, 2018).

c.1. Definitions

Most of the relevant definitions are in MiniJl/BaseDefs.v. In the table below, we show the correspondence between paper definitions (left column) and Coq definitions (middle column), possibly with syntactic sugar (right column).

Types
ty
value_type v

Relations
match_ty v t |- v <$ t
sem_sub t1 t2 ||- [t1] <= [t2]
sub_d t1 t2 |- t1 << t2
sub_r t1 t2 |- t1 << t2

Auxiliary definitions
in_nf t InNF(t)
mk_nf t MkNF(t)
unite_pairs t1 t2

c.2. Basic Properties of Normalization Function

File MiniJl/BaseProps.v contains several simple properties that are needed for proving the major theorems discussed in the paper, in particular, the following properties of the normalization function :

Statement Ref in text Name in Coq
(9) mk_nf__in_nf
mk_nf_nf__equal
mk_nf__idempotent

c.3. Basic Properties of Matching Relation

The following properties are proven in MiniJl/PropsMatch.v.

  • Matching relation is reflexive, match_valty__rflxv (by induction on ):

  • The only value type that a value type matches is the value type itself, valty_match_valty__equal (by induction on ):

  • The matching relation is decidable, match_ty__dcdbl (by induction on , then by induction on ):

c.4. Correctness of Declarative Subtyping

First, we discuss some auxiliary statements that are needed for proving Theorem 1 (located in MiniJl/DeclSubProp.v).

One direction of (5),

(12)

is proven in match_ty__sub_d_sound by induction on . The other direction,

is proven in match_valty__sub_d_complete by induction on . The transitivity case, SD-Trans, requires a helper statement, match_valty__transitive_on_sub_d:

(13)

which is proven by induction on .

The equivalence of a type and its normal form (10) is shown by induction on in lemmas mk_nf__sub_d1 () and mk_nf__sub_d2 ().

Semantic completeness of declarative subtyping for a normalized type (8),

is shown in nf_sem_sub__sub_d by induction on . When , we use (12). By definition of , we know that follows from .
When , we use induction hypothesis and , SD-UnionL rule, and the fact that

Finally, soundness and completeness parts of Theorem 1 (sub_d__semantic_sound and sub_d__semantic_complete) are proven in MiniJl/Props.v. Note that soundness (6) is the same as transitivity of the matching relation (13). The completeness part (7) is proven as explained at the end of Sec. 4.1.

c.5. Correctness of Reductive Subtyping

As discussed in Sec. 4.2, the soundness part of Theorem 2 (lemma sub_r__sound in MiniJl/Props.v),

is proven by induction on . The only interesting case is the rule SR-NF where we have the induction hypothesis and need to show . Since , we can use transitivity (rule SD-Trans).

The completeness part of Theorem 2 (lemma sub_r__complete in MiniJl/Props.v),

is ultimately proven by induction on . However, the proof requires showing that reductive subtyping satisfies the following properties (defined in MiniJl/RedSubProps.v):

  • Reflexivity, sub_r__reflexive (by induction on ):

  • Transitivity, sub_r__transitive:

  • Distributivity of pairs over unions:

    and

The transitivity proof is done by induction on . In some cases it relies on the fact that subtyping a type is the same as subtyping its normal form,

(14)

The right-to-left part follows from SR-NF, and the left-to-right is shown by induction on (sub_r__mk_nf_sub_r1). In the SR-Pair case of the transitivity proof, we also need to perform induction on . The last case, SR-NF, uses the two auxiliary facts:

proven in sub_r__mk_nf_sub_r by induction on