Towards Taming Java Wildcards and Extending Java with Interval Types

05/18/2018 ∙ by Moez A. AbdelGawad, et al. ∙ Rice University 0

Of the complex features of generic nominally-typed OO type systems, wildcard types and variance annotations are probably the hardest to fully grasp. As demonstrated when adding closures (a.k.a., lambdas) and when extending type inference in Java, wildcard types and variance annotations make the development and progress of OO programming languages, and of their type systems in particular, a challenging and delicate task. In this work we build on our concurrent work, in which we model Java subtyping using a partial graph product, to suggest how wildcard types in Java can be generalized, and simplified, to interval types. In particular, interval types correspond to endpoints of paths in the Java subtyping graph. In addition to being a simple and more familiar notion, that is easier to grasp than wildcard types, interval types are strictly more expressive than wildcard types. As such, we believe interval types, when developed and analyzed in full, will be a welcome addition to Java and other similar generic nominally-typed OO programming languages.

READ FULL TEXT VIEW PDF
POST COMMENT

Comments

There are no comments yet.

Authors

page 1

page 2

page 3

page 4

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

Java wildcard types JLS05 ; JLS14 ; Torgersen2004 ; MadsTorgersen2005 (also known as ‘Java wildcards’) are wild. Wildcard types in Java are an instance of so-called usage-site variance annotations. Another form of variance annotations, called declaration-site variance annotations, is supported in other generic nominally-typed OO programming languages such as C# CSharp2015 , Scala Odersky14 and Kotlin Kotlin18 . Declaration-site variance annotations are (almost) as wild as usage-site variance annotations.

1.1 Motivating Example

To illustrate how wild Java wildcard types, and variance annotations more generally, can be, consider the following Java code. The reader is invited to tell (before he or she checks the answer below) which of the variable assignments in the following code—all involving wildcard types—will typecheck and which ones will the Java typechecker complain about.

class E<T> {}
class C<T> extends E<E<T>> {}
class D<T> extends C<D<T>> {}
class App {
  public static void main(String[] args){
    C<? extends D<?>> cxd = null;
    C<D<?>> cd = null;
    D<?> d = null;
    D<D<?>> dd = null;
    D<? extends D<?>> dxd = null;
    // Assuming the decls above typecheck,
    // which of the following eleven assign-
    // ments typecheck and which ones don’t?
    // ... and why?? (The answer involves
    // figuring out the correct subtyping
    // relations between the types of the
    // variables in the assignments).
    //
    cxd = cd;      cd = d;        cxd = d;
    d = dd;        dd = d;
    dxd = dd;      dd = dxd;
    d = dxd;       dxd = d;
    cxd = dxd;     cd = dxd;
  }
}

Answer: All class and variable declarations in the code above typecheck, but the second assignment in each of the five groups of variable assignments (i.e., elements of the middle column) does not typecheck, while the other six assignments will typecheck.

Now, did the reader figure this answer correctly? … and quickly? … and, most importantly, can the reader tell the why for his or her findings? … (Unfortunately, the error messages that the Java compiler emits, which involve wildcard “capturing”, are largely unhelpful in this regard).

The difficulty in figuring out which of the assignments above (let alone assignments involving even more complex generic types) do typecheck and which ones do not, as well as the difficulty in figuring out the reason in each case, and the almost total unhelpfulness of error messages, is an example of how hard (a.k.a., wild) reasoning about wildcard types can be.

A main motivation for our research, and for the work presented in this paper in particular, is to face this situation head-on and try to significantly improve it. We believe the research presented here and in other closely-related publications is a significant step towards that goal. (Based on earlier research we did AbdelGawad2016c ; AbdelGawad2017b that largely complements the work we present in this paper, we believe Java generics error diagnostics, for example, can be significantly improved once wildcard types are fully tamed and generalized to interval types.)

This paper is structured as follows. In Section 2 we briefly discuss the background needed for reading this paper. In Section 3 we then formally define OO interval types and the construction method of the Java subtyping relation with interval types. In Section 4 we present examples that illustrate the definitions in Section 3 (In Appendix A we present the SageMath code we developed to help us in generating these examples). In Section 5 we briefly discuss research related to the research we present in this paper. In Section 6 we make some concluding remarks and discuss some possible future work that can build on work presented in this paper.

2 Background

The background necessary for reading this paper is basically the same as that of AbdelGawad2017a (A summary is presented in Section 2 of AbdelGawad2018b ). In the following sections of this paper we largely adopt the same assumptions, vocabulary and notation of AbdelGawad2017a ; AbdelGawad2018b .

In particular, the construction method we use to construct the Java subtyping relation with interval types (which is formalized in Section 3 of this paper), except for its use of interval types, is the same as the construction method used to construct the Java subtyping relation with wildcard types (as presented in AbdelGawad2018b ).

3 Interval Types and Constructing The Java Subtyping Relation

In this section we formally introduce interval types, then we formally define the construction method of the Java subtyping relation between generic reference types with interval type arguments.

3.1 Object-Oriented Interval Types

Informally, similar to closed intervals over real numbers or over integers, which are sets of numbers between and including two bounding numbers, intervals over a directed graph are sets of vertices between and including two bounding vertices in the graph.111The two bounds of a graph interval are usually called its lowerbound and its upperbound, particularly when the graph is that of a partially-ordered set, as is the case for the OO subtyping relation and for the smaller-than-or-equals relation on numbers.

Formally, we define intervals of a directed graph as the quotient set of the set of paths of the graph (including trivial, zero-length paths from vertices of the graph to themselves) over the equivalence relation of paths of the graph with the same endpoints, as follows.

Let be a directed graph, and let be the set of paths in . For a path in let and denote the (possibly equal) start and end vertices of (i.e., the endpoints of path ). For paths and in (i.e., ), define the relation over as the equivalence relation

In agreement with intuition, using the properties of and conjunction () it is easy to show that relation is a reflexive (), symmetric () and transitive relation (), i.e., that is an equivalence relation. Relation thus partitions .

The set of intervals of graph is then defined as the quotient set

(i.e., as the set of equivalence classes defined by ).

Equivalently, intervals of can be defined using the reflexive transitive closure of . That is because the intervals of are in one-to-one correspondence with the edges (including self-edges/loops) of , the reflexive transitive closure of . In other words, if then we have

Hence, based on the definition of graph intervals, one graph interval can correspond to multiple (one or more) paths of the graph, all having the same endpoints, but one path of the graph corresponds to exactly one graph interval, namely the interval defined by the endpoints of the path (i.e., its start and end vertices Hammack2011 ).222We call paths corresponding to a graph interval its ‘witnesses’. More precisely, similar to formal proofs of valid logical statements in formal logic, we call a path in a graph a witness to the graph interval defined by the endpoints of the path. In fact we found some resemblance between graph intervals in graph theory (as we define them in this paper) and valid logical statements in formal mathematical logic. In formal logic a logical statement must have a formal proof for the statement to be a valid logic statement. Similarly, a pair of graph vertices must have a path connecting its two vertices for the pair to define a graph interval. Further, in formal logic a valid logical statement can have multiple (one or more) witnessing proofs. Likewise, a graph interval can have multiple (one or more) witnessing paths. Also, the relation between graph paths is analogous to the equivalence of proofs with the same premises and conclusions (‘proof irrelevance’), but, other than noting the analogy in this footnote, we do not explore or take the analogy any further in this paper. As such, using two standard notations for intervals, we denote a graph interval with endpoints and either by , or sometimes equivalently by (given that we define intervals over directed graphs, the order of the vertices in a graph interval expression matters).

Informally, an interval over a graph can be viewed as a pair of vertices in where a path from to is guaranteed to exist in ( is said to be reachable from ). Not all pairs of vertices of satisfy this condition. A pair of vertices that do satisfy this connectedness condition corresponds to an interval over , while the vertices of a pair that does not satisfy the condition are called disconnected vertices (they are sometimes also called parallel vertices, particularly when is the graph of a partial order and when also the inverse pair does not form an interval, and are usually denoted by in order theory literature). In other words, a graph interval over a directed graph corresponds to a pair of connected or reachable vertices in , where (in the context of directed graphs) ‘connectivity’ is understood to be to the second mentioned vertex () and ‘reachability’ is understood to be from the first mentioned vertex (), i.e., we say is reachable from or, equivalently, that is connected to .

We then simply define OO interval types in an OO type system as graph intervals over the graph of the OO subtyping relation (i.e., the graph whose vertices are OO types and whose edges correspond to the subtyping relation between OO types).

3.1.1 The Containment and Precedence Relations

Similar to intervals of real numbers or intervals of integers, graph intervals and interval types can be (partially) ordered by a containment relation, where a graph interval is said to be contained-in another interval if some path corresponding to is, in its entirety, a subpath Hammack2011 of some path corresponding to (i.e., for to be contained in the path must share its vertices with , in the same order as the vertices occur in ). If an interval is contained in an interval , sometimes we call a subinterval of and, equivalently, call a superinterval of .

The definition of the containment relation between graph intervals may seem a bit convoluted, but it should be intuitively clear. (Visually speaking, i.e., when presented with the diagram of a graph, it is usually immediately obvious whether a graph interval is contained in another.)

In accordance with our definition of interval types, we define the containment relation between interval types as containment between their corresponding graph intervals over the graph of the OO subtyping relation. It should be intuitively clear also that the containment relation is a partial ordering between interval types, which itself—i.e., the containment ordering—can be modeled by a directed graph (which can be presented, for example, using the Hasse diagram of the partial ordering).

Another relation that can be defined on graph intervals (and interval types accordingly) is the precedence relation, where an interval is said to precede an interval if and only if there exists an interval (i.e., if and only if the pair actually defines an interval). In other words, interval precedes interval if and only if the end vertex of and the start vertex of are connected. If precedes it may be equivalently said that succeeds or follows . Currently (i.e., in this paper), we do not have a particular use or application of the precedes relation in constructing and modeling the generic Java subtyping relation, but we do not preclude the possibility—indeed, we believe—that the precedes relation may be useful in some future work that builds on the work we present in this paper.

3.2 Constructing The Java Subtyping Relation with Interval Types

As we did for wildcard types (see AbdelGawad2018b ), to construct the Java subtyping relation with interval types we use the partial Cartesian graph product operator from AbdelGawad2018a .

First, however, we define a graph constructor (similar to our definition of the graph constructor in AbdelGawad2018b ) that constructs the graph whose vertices are all the interval type arguments that can be defined for the graph of a subtyping relation and whose edges model the containment relation between these arguments. In other words, operator constructs (the graph of) the containment relation between interval types over as described in Section 3.1.1.

With in hand, the Java subtyping relation with interval types can now be defined as the solution of the recursive graph equation

(1)

where is the graph of the subtyping relation, is the graph of the subclassing relation, and is the set of generic classes (a subset of classes in ).

As is standard for recursive equations, Equation (1) can be solved iteratively (thereby formalizing our construction method) using the equation

(2)

where the are finite successive better approximations to the infinite relation , and is an appropriate initial graph of the containment relation between interval types (which we take as the graph with one vertex, having the default interval type argument ‘?’ as its only vertex, and having no containment relation edges). Equation (2) thus formally and concisely describes the construction method of the generic Java subtyping relation between ground Java reference types with interval types.

As a comparison of their defining equations reveals, the main difference between the construction of the graph of the Java subtyping relation with interval types (presented here) and the construction of the graph of the Java subtyping relation with wildcard types (presented in AbdelGawad2018b ) lies in using the operator in place of operator to construct the type arguments of generic classes.

In AbdelGawad2017a ; AbdelGawad2018b we noted that the generic Java subtyping relation exhibits self-similarity. The equation for Java subtyping with interval types demonstrates that extending Java with interval types, as a generalization of wildcard types, preserves the self-similarity of the subtyping relation. As is the case for wildcard types, the self-similarity of the Java subtyping relation with interval types comes from the fact that the second factor (i.e., , the graph of the containment relation between interval type arguments) of the partial product defining is derived iteratively (in all but the first iteration) from the first factor of the product (i.e., from , the subclassing relation). The implications (see [AbdelGawad2018b, , Section 3]) of the dependency of the definition of the subtyping relation on the definition of the subclassing/class inheritance relation in nominally-typed OO programming languages, regarding the value of nominal typing and its influence and effects on the type system of Java and other similar nominally-typed OO languages, are thus also preserved.

4 Examples of Constructing The Java Subtyping Relation with Interval Types

In this section we present examples for how the generic Java subtyping relation between ground reference types with interval type arguments can be iteratively constructed. As we do in the examples section of AbdelGawad2018b , we use colored edges in the diagrams below to indicate the self-similarity of the Java subtyping relation.

Also, so as to have the lower bound always on the left of a type argument expression and the upper bound always on the right of a type argument expression (as is the customary mathematical notation for intervals) in the diagrams we use the notation ‘T <: ?’ (to mean ‘T extends ?’) instead of ‘? :> T’ (which means ‘? super T’) to express type arguments upper-bounded by O (i.e., Object).

Also, in the diagrams we use wildcards notation (‘?’, ‘? <: T’ and ‘T <: ?’) as much as possible, even though unnecessary, so as to indicate the equivalence of some types that have interval type arguments to types that have wildcard type arguments. As such, only interval type arguments that cannot be expressed as wildcard type arguments are expressed using the proper intervals notation (‘T1 - T2’).

Example 1.

Consider the Java class declaration

class C<T> {}.

The graphs in Figure 1 illustrate the construction of the subtyping relation corresponding to this declaration. (In Figure (d)d, so as to shorten names of types in , we use T1 to T6 to stand for types of other than O and N.)

A comparison of Figure (d)d to Figure 2—which is a reproduction of Figure 2d of AbdelGawad2018b —clearly illustrates that interval types are more expressive (i.e., can express more types) than wildcard types.333Given that we do not present graphs of or higher in the remaining examples below (due to the very large size of these graphs), this difference in expressiveness between interval types and wildcard types is not as evident in later examples as it is in this example.

It should also be noted that the subgraph highlighted with blue edges in the graph of Figure (d)d (and some other unhighlighted subgraphs of the same graph) seems to hint at how bounded type variables—with both upper and lower bounds—may be dealt with in the full subtying relation, but we keep this research to future work.

Example 2.

Consider the two Java class declarations

class C<T> {}

class D<T> {}.

The graphs in Figure 3 illustrate the construction of the subtyping relation corresponding to these class declarations.

Example 3.

Consider the two Java class declarations

class C<T> {}

class E<T> extends C<T> {}.

The graphs in Figure 4 illustrate the construction of the subtyping relation corresponding to these class declarations.

Example 4.

Consider the four Java class declarations

class C {}

class E extends C {}

class D {}

class F<T> extends D {}.

The graphs in Figure 5 illustrate the construction of the subtyping relation corresponding to these declarations. (As done in earlier examples via highlighting, in this example the reader is invited to find out the subgraphs of that are similar—i.e., isomorphic—to or its subgraphs, and to layout accordingly.)

(a)
(b)
(c)
(d)
Figure 1: Constructing generic OO subtyping with interval types
Figure 2: with wildcard types (for comparison)
(a)
(b)
(c)
Figure 3: Constructing generic OO subtyping with interval types
(a)
(b)
(c)
Figure 4: Constructing generic OO subtyping with interval types
(a)
(b)
(c)
Figure 5: Constructing generic OO subtyping with interval types (automatic layout by yEd)

In Appendix A we present SageMath Stein2017 code that helped us produce some of the examples in this paper. We used the code to produce larger examples of Java subtyping with interval types, with larger numbers of generic class declarations and for higher iteration indices than presented here. However, the very large size of these graphs—with hundreds, thousands, and even tens of thousands of vertices and edges—seems to diminish the usefulness of presenting diagrams of these graphs.

However, a comparison of the sizes and orders of graphs corresponding to Java subtyping wildcard types to those of graphs corresponding to Java subtyping with interval types does reveal the greater degree of expressiveness of interval types compared to the expressiveness of wildcard types. The comparison of the sizes and orders of the subtyping graphs also reveals that the difference in expressiveness is more prominent when the subclassing relation (i.e., , the basis for defining the subtyping relation in both cases) has longer paths (i.e., than those of the examples we present in this paper. Much longer/deeper subclassing hierarchies are in fact typically the case for most real-world OO programs) or for higher iteration numbers in constructing the subtyping relation (i.e., for deeper-nested/higher-ranked generic types, which however are not quite widely used in real-world OO programs).

5 Related Work

Although viewing wildcard types in Java as “some sort of intervals” seems to not be quite a new idea, but, other than presenting the idea as a vague intuition that may help in understanding wildcard types, it seems the idea has not been researched and presented more thoroughly before.

As to other work that is related to the research we present here, we already mentioned our concurrent work presented in AbdelGawad2018b and our earlier work presented in AbdelGawad2017a , both of which paved the way for the work presented here.

The addition of generics to Java has motivated much earlier research on generic OOP and also on the type safety of Java and similar languages. Much of this research was done before generics were added to Java. For example, the work in Bank96 ; Bracha98 ; Corky98 was mostly focused on researching OO generics, while the work in drossopoulou99 ; flatt99 was focused on type safety.

Some research on generics was also done after generics were added to Java, e.g.Zhang:2015:LFO:2737924.2738008 ; AbdelGawad2016c ; Grigore2017 ; AbdelGawad2017b . However, Featherweight Java/Featherweight Generic Java (FJ/FGJ) FJ/FGJ is probably the most prominent work done on the type safety of Java, including generics. Variance annotations and wildcard types were not put in consideration in the construction of the operational model of generic nominally-typed OOP presented in FJ/FGJ however.

Separately, probably as the most complex feature of Java generics, the addition of “wildcards” (i.e., wildcard type arguments) to Java (in Torgersen2004 , which is based on the earlier research in Igarashi02onvariance-based ) also generated some research that is particularly focused on modeling wildcards and variance annotations MadsTorgersen2005 ; KennedyDecNomVar07 ; Cameron2008 ; Summers2010 ; Tate2011 ; Tate2013 ; Greenman2014 . This substantial work, particularly the latest work (of Tate2011 Tate2013 and Greenman2014 ), clearly points to the need for more research on wildcard types and generic OOP.

6 Discussion and Future Work

In this paper we presented how type arguments for ground generic OO types can be smoothly generalized from wildcard types to interval types, thereby uniformly supporting types other than Object and Null as upper and lower bounds for generic type arguments, thereby subsuming and generalizing wildcard types. Also, our work can be made more comprehensive—covering more features of the Java generic subtyping relation—if it is extended to model subtyping between generic types that have type variables in them. We hinted earlier in this paper, in particular, to how bounded type variables can be modeled, but including type variables and bounded type variables in the construction of the Java subtyping relation remains to be done.

We also believe it may be useful if a notion of nominal intervals AbdelGawad2016c (i.e., nominal type intervals) is supported in Java and other similar generic nominally-typed OO programming languages, where type variables (including bounded ones) can be viewed as names for interval types (as presented in this paper) and where nominal intervals with the same bounds but with different names are considered distinct (i.e., unequal) nominal intervals. We conjecture that the nominality of nominal intervals can be a notion that is simpler to reason about than the existentiality and “capturing” notions currently used in modeling wildcard types. The fine details of this work, however, also have yet to be decided and sorted out.

References

  • [1] C# language specification, version 5.0. http://msdn.microsoft.com/vcsharp, 2015.
  • [2] Kotlin language documentation, v. 1.2. http://www.kotlinlang.org, 2018.
  • [3] Moez A. AbdelGawad. Towards an accurate mathematical model of generic nominally-typed OOP (extended abstract). arXiv:1610.05114 [cs.PL], 2016.
  • [4] Moez A. AbdelGawad. Novel uses of category theory in modeling OOP (extended abstract). Accepted at The Nordic Workshop on Programming Theory (NWPT’17), Turku, Finland, November 1-3, 2017. (Full version available at arXiv.org: 1709.08056 [cs.PL]), 2017.
  • [5] Moez A. AbdelGawad. Towards a Java subtyping operad. Proceedings of FTfJP’17, Barcelona, Spain, June 18-23, 2017, 2017.
  • [6] Moez A. AbdelGawad. Java subtyping as an infinite self-similar partial graph product. Available as arXiv preprint at http://arxiv.org/abs/1805.06893, 2018.
  • [7] Moez A. AbdelGawad. Partial cartesian graph product (and its use in modeling Java subtyping). Available as arXiv preprint at http://arxiv.org/abs/1805.07155, 2018.
  • [8] Joseph A. Bank, Barbara Liskov, and Andrew C. Myers. Parameterized types and Java. Technical report, 1996.
  • [9] Gilad Bracha, Martin Odersky, David Stoutamire, and Philip Wadler. Making the future safe for the past: Adding genericity to the Java programming language. In Craig Chambers, editor, ACM Symposium on Object-Oriented Programming: Systems, Languages and Applications (OOPSLA), volume 33, pages 183–200, Vancouver, BC, October 1998. ACM, ACM SIGPLAN.
  • [10] Nicholas Cameron, Sophia Drossopoulou, and Erik Ernst. A model for Java with wildcards. In ECOOP’08, 2008.
  • [11] Robert Cartwright and Jr. Steele, Guy L. Compatible genericity with run-time types for the Java programming language. In Craig Chambers, editor, ACM Symposium on Object-Oriented Programming: Systems, Languages and Applications (OOPSLA), volume 33, pages 201–215, Vancouver, BC, October 1998. ACM, ACM SIGPLAN.
  • [12] Sophia Drossopoulou, Susan Eisenbach, and Sarfraz Khurshid. Is the Java type system sound? TAPOS, 5(1):3–24, 1999.
  • [13] Matthew Flatt, Shriram Krishnamurthi, and Matthias Felleisen. A programmer’s reduction semantics for classes and mixins. In Formal syntax and semantics of Java, pages 241–269. Springer, 1999.
  • [14] James Gosling, Bill Joy, Guy Steele, and Gilad Bracha. The Java Language Specification. Addison-Wesley, 2005.
  • [15] James Gosling, Bill Joy, Guy Steele, Gilad Bracha, and Alex Buckley. The Java Language Specification. Addison-Wesley, 2014.
  • [16] Ben Greenman, Fabian Muehlboeck, and Ross Tate. Getting f-bounded polymorphism into shape. In PLDI ’14: Proceedings of the 2014 ACM SIGPLAN conference on Programming Language Design and Implementation, 2014.
  • [17] Radu Grigore. Java generics are Turing complete. In Proceedings of the 44th ACM SIGPLAN Symposium on Principles of Programming Languages, POPL 2017, pages 73–85, New York, NY, USA, 2017. ACM.
  • [18] Richard Hammack, Wilfried Imrich, and Sandi Klavzar. Handbook of Product Graphs. CRC Press, second edition edition, 2011.
  • [19] Atsushi Igarashi, Benjamin C. Pierce, and Philip Wadler. Featherweight Java: A minimal core calculus for Java and GJ. ACM Transactions on Programming Languages and Systems, 23(3):396–450, May 2001.
  • [20] Atsushi Igarashi and Mirko Viroli. On variance-based subtyping for parametric types. In In ECOOP, pages 441–469. Springer-Verlag, 2002.
  • [21] Andrew J. Kennedy and Benjamin C. Pierce. On decidability of nominal subtyping with variance. In International Workshop on Foundations and Developments of Object-Oriented Languages (FOOL/WOOD), 2007.
  • [22] Martin Odersky. The Scala language specification, v. 2.9. http://www.scala-lang.org, 2014.
  • [23] William Stein. Sagemath 8.1. http://www.sagemath.org, 2017.
  • [24] Alexander J. Summers, Nicholas Cameron, Mariangiola Dezani-Ciancaglini, and Sophia Drossopoulou. Towards a semantic model for Java wildcards. 10th Workshop on Formal Techniques for Java-like Programs, 2010.
  • [25] Ross Tate. Mixed-site variance. In FOOL ’13: Informal Proceedings of the 20th International Workshop on Foundations of Object-Oriented Languages, 2013.
  • [26] Ross Tate, Alan Leung, and Sorin Lerner. Taming wildcards in Java’s type system. PLDI’11, June 4–8, 2011, San Jose, California, USA., 2011.
  • [27] Mads Torgersen, Erik Ernst, and Christian Plesner Hansen. Wild FJ. In Foundations of Object-Oriented Languages, 2005.
  • [28] Mads Torgersen, Christian Plesner Hansen, Erik Ernst, Peter von der Ahé, Gilad Bracha, and Neal Gafter. Adding wildcards to the Java programming language. In SAC, 2004.
  • [29] Yizhou Zhang, Matthew C. Loring, Guido Salvaneschi, Barbara Liskov, and Andrew C. Myers. Lightweight, flexible object-oriented generics. In Proceedings of the 36th ACM SIGPLAN Conference on Programming Language Design and Implementation, PLDI 2015, pages 436–445, New York, NY, USA, 2015. ACM.

Appendix A SageMath Code

In this appendix we present SageMath Stein2017 code that we used to help produce some of the graph examples presented in this paper. The code presented here is not optimized for speed of execution but rather for clarity and simplicity of implementation, and it builds on and makes use of code presented in Appendix A of AbdelGawad2018b .

IntvlFromTo = -
ExtW = ExtStr+W
# is subpath/sublist/subinterval?
def is_sublist(sl, l):
  if sl == []:
     return True
  if l.count(sl[0]) == 0:
     return False
  start = l.index(sl[0])
  return (sl == l[start:start+len(sl)])
# interval string
def ty_intvl(path):
  f = path[0]
  l = path[len(path)-1]
  return W if f == BotCls and l == TopCls else
        (f if f == l else
        (WExt+l if f == BotCls else
        (f+ExtW if l == TopCls else
        (f+IntvlFromTo+l))))
# Use paths to get interval type arguments
# (subsumes Cov,Con,Inv)
def ITAs(S):
  ITA = DiGraph()
  ntps = S.all_simple_paths()
  # non-trivial paths, shortest to longest
  ntps.reverse() # from longest to shortest
  i=0
  for ntp in ntps:
    i=i+1
    lp = len(ntp)
    if lp > 2:
       shrtr_paths = S.all_simple_paths(
          max_length=lp-2, trivial=true)
       # most time-consuming step. constant
       # for all ntp of same length.
       # all_simple_paths doesn’t work
       # properly if max_length == 0
       # (returns [] rather than trivial
       # paths only)
    else:
       shrtr_paths = map(lambda x: [x],
                         S.vertices())
    for sp in shrtr_paths:
      if is_sublist(sp, ntp):
         ITA.add_edge((ty_intvl(sp),
                       ty_intvl(ntp)))
  ITA = ITA.transitive_reduction()
  return ITA
ILP = ’[’ # LeftParen for intrvl type args
IRP = ’]’ # RightParen for intrvl type args
def ity(c,ita):
  return c+ILP+ita+IRP
def IntervalsSubtyping(subclassing, lngc,
                       FN_Prfx, num_iter):
  #Definition of SI0 (initial SI)
  SI0=subclassing.copy()
  SI0.relabel(lambda c: c if (c in lngc)
                        else ity(c,W))
  SI = SI0
  lst = [SI]
  for i in [1..num_iter]:
    ITA = ITAs(SI)
    # main step
    SI = GSP(subclassing, lngc, ITA, ity)
    lst.append(ITA)
    lst.append(SI)
  return lst