Java Subtyping as an Infinite Self-Similar Partial Graph Product

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

Due to supporting variance annotations, such as wildcard types, the subtyping relation in Java and other generic nominally-typed OO programming languages is both interesting and intricate. In these languages, the subtyping relation between ground object types (ones with no type variables) is the basis for defining the full OO subtyping relation (i.e., that includes type variables). In this paper we present how the subtyping relation between ground Java types can be precisely constructed using a binary operation on directed graphs. The binary operation we use, called a partial Cartesian graph product, is similar in its essence to standard graph products and group products. Its definition is based in particular on that of the standard Cartesian graph product. We believe the use of this graph operation in constructing the ground generic Java subtyping relation reveals some of the not-immediately-obvious structure of the subtyping relation in generic nominally-typed OO programming languages. Accordingly, we believe that describing precisely how this graph operation is used to construct the subtyping relation of these languages, as we do in this paper, may significantly improve our understanding of wildcard types and variance annotations in those 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

The addition of generics and wildcard types to Java [JLS05, ; JLS14, ] made the subtying relation in Java elaborately intricate. Wildcard types in Java express so-called usage-site variance annotations [Torgersen2004, ]. As Torgersen et al. explain, supporting wildcard types in Java causes the subtyping relation between generic types in Java to be governed by three rules, namely:

  • Covariant subtyping, which, for example, for a generic class111In this work we treat Java interfaces as abstract classes. List causes type List<? extends Integer> to be a subtype of type List<? extends Number> because type Integer is a subtype of type Number,

  • Contravariant subtyping, which causes type List<? super Integer> to be a supertype of type List<? super Number> because type Integer is a subtype of type Number, and

  • Invariant subtyping, which causes type List<Integer> to be unrelated by subtyping to type List<Number> even when type Integer is a subtype of type Number.

The subtyping relation in other industrial-strength generic nominally-typed OOP languages such as C# [CSharp2015, ], Scala [Odersky14, ] and Kotlin [Kotlin18, ] exhibits similar intricacy. C#, Scala and Kotlin support another form of variance annotations (called declaration-site variance annotations) as part of their support of generic OOP. Usage-site and declaration-site variance annotations have a similar effect on the structure of the generic subtyping relation in nominally-typed OOP languages.

The introduction of variance annotations in mainstream OOP, even though motivated by earlier research, has generated much additional interest in researching generics and in having a good understanding of variance annotations in particular. In this paper we augment this research and improve on earlier research by presenting how a precise product-like graph operation can be used to construct the subtyping relation in Java, exhibiting and making evident in our construction the self-similarity in the definition and construction of the relation, with the expectation that our construction method will apply equally well to subtyping in other OO languages such as C#, Scala and Kotlin.

As such, this paper is structured as follows. In Section 2 we discuss the intricacy and self-similarity of the subtyping relation in Java, followed by an introduction to partial Cartesian graph products. Then, in Section 3, we define another new unary graph operation (called the wildcards graph constructor), then we present the formal construction of the subtyping relation in Java using partial Cartesian graph products and the new unary operation. In Section 4 we present examples of the application of our construction method that demonstrate how it works (in Appendix A we present SageMath code implementations for constructing our examples). In Section 5 we discuss some research that is related to ours. We conclude in Section 6 by discussing some conclusions we made and discussing some future research that can build on our work.

2 Background

In this section we give an example of how the subtyping relation in a simple Java program can be constructed iteratively, based on the type and subtype declarations in the program. We follow that by a brief introduction to the partial Cartesian graph product operation and a presentation of its formal definition.

2.1 Iterative Construction of The Java Subtyping Relation

To explore the intricacy of the subtyping relation in Java, we borrow a simple example from [AbdelGawad2017a, ]. Let’s consider a simple generic class declaration. Assuming we have no classes or types declared other than class Object (whose name we later abbreviate to O), with a corresponding type that has the same name, then the generic class declaration class C<T> extends Object {} results in a subclassing relation in which class C is a subclass of O.

For subtyping purposes in Java, it is useful to also assume the existence of a special class Null (whose name we later abbreviate to N) that is a subclass of all classes in the program, and whose corresponding type, hence, is a subtype of all Java reference types.

Following the description of [AbdelGawad2017a, ], the generic subtyping relation in our Java program can be constructed iteratively, based on the mentioned assumptions and the declaration of generic class C. (As done by [AbdelGawad2017a, ], we also assume that a generic class takes only one type parameter, and that type variables of all generic classes have type O as their upper bound.)

Given that we have at least one generic class, namely C, we should first note that, since generic types can be arbitrarily nested, the generic subtyping relation will have an infinite number of types. As such, to construct the infinite subtyping relation we go in iterations, where we start with a finite first approximation to the relation then, after each iteration, we get a step closer to the full infinite relation. Since [AbdelGawad2017a, ] describes this informal construction process in detail, we do not repeat less relevant details here. We instead refer the interested reader to AbdelGawad’s paper [AbdelGawad2017a, ; AbdelGawad2017, ].

For the purposes of this paper however, the reader should appreciate the intricacy of the generic subtyping relation in Java by noticing, at least in a rough informal sense so far, the self-similarity that is evident in the relation, where the subtyping relation between different covariant types (those of the form ‘C<? extends Type>’) inside a result relation is the same as the relation between types in the input relation. Contravariant subtyping results in an opposite ordering relation (between different types of the form ‘C<? super Type>’) and invariant subtyping results in no relation (between different types of the form ‘C<Type>’).

To construct the final, most accurate version of the subtyping relation, the process described above is continued ad infinitum. The purpose of using partial Cartesian graph products to define the construction method of the Java subtyping relation, as we do later in this paper, is to formally present how each iteration in this construction process can be precisely modeled mathematically, based on the informal intuitions presented in the example above.

2.2 Partial Cartesian Graph Products ()

Graph products are commonplace in computer science [Hammack2011, ]. Graph products are often viewed as a convenient language with which to describe structures. [AbdelGawad2018a, ] presents a notion of a partial Cartesian graph product, which we use in constructing the subtyping relation in generic nominally-typed OOP languages. A full discussion of the partial Cartesian graph product operation, denoted by , is presented by [AbdelGawad2018a, ]. Here we present a summary of its definition and of some of its properties most relevant to constructing the generic OO subtyping relation.

Definition 1.

(Partial Cartesian Graph Product, ). For two directed graphs and where

  • such that and partition (i.e., and ),

  • such that , , , and partition ,

  • and are two disjoint subgraphs of (the ones induced by and , respectively, which guarantees that edges of connect only vertices of and edges of connect only vertices of ), and and connect vertices from to and vice versa, respectively, and

  • is any directed graph (i.e., , unlike , need not have some partitioning of its vertices and edges),

the partial Cartesian graph product of and relative to the set of vertices is the graph

(2.1)

where

  • ( and are the standard Cartesian set product and disjoint union operations),

  • is the standard Cartesian graph product of and , and,

  • for defining , the operator is defined (implicitly relative to ) such that, if denotes adjacency, we have

Viewed abstractly, graph constructor is a binary graph operation that takes as input two graphs and and is parameterized also by a subset of the vertices of its first input graph . Informally, constructs a (standard) Cartesian product of the subgraph induced by the given subset of vertices with the second input graph and adds to this product the non-product vertices of (i.e., ) appropriately connecting them to the product based on edges in . The example in Figure 2.1 helps demonstrate the definition of .

(a)
(b)
(c)
Figure 2.1: Illustrating the partial Cartesian graph product operation

More details on the definition of and some of its properties can be found in [AbdelGawad2018a, ].

For using in constructing (the graph of) the generic OO subtyping relation, the most interesting property of is that some vertices in the first input graph do not fully participate in the product operation. This makes suited for constructing the generic OO subtyping relation because some classes in a Java program (where classes and types are mapped to vertices in the graphs of the subclassing and subtyping relations) may not be generic classes (e.g., classes Object and Null are always non-generic), so these classes do not participate in the subtyping relation with generic types (since they do not take type arguments to begin with). We explain the construction method formally in the following section.

3 Constructing The Java Subtyping Relation Using

3.1 The Wildcards Graph Constructor ()

To construct the Java subtyping relation using , we first define a graph operator that constructs the graph whose vertices are all wildcard type arguments that can be defined over the graph of a subtyping relation , and whose edges express the containment relation between these arguments. Informally, the containment relation between wildcard type arguments is a very simple relation, where we only have type argument ‘T’ contained in wildcard type argument ‘? <: T’ (shorthand for ‘? extends T’) and contained in wildcard type argument ‘? :> T’ (shorthand for ‘? super T’), and also, by containment, we identify the wildcard type arguments ‘?’, ‘? <: O’, and ‘? :> N’. (If wildcard types are generalized to interval types, as we do in [AbdelGawad2018c, ], we have a fuller, more elaborate containment relation).

Definition 2.

(Triangle/Wildcards Graph, ) Formally, for a bipointed graph (i.e., is a graph with two distinguished “source” and “sink” vertices , sometimes called top and bottom, or, for our purposes, called O and N), the triangle graph (or, wildcards graph) of is defined as the reflexive transitive closure () of the immediate (i.e., one-step) containment graph (i.e., ) where is defined as follows.

  • , such that , , and are three appropriately-labeled “copies” of corresponding to the three variant subtyping rules (i.e., vertices in are labeled with ? <: T for each label/type name T in , while vertices in are labeled with ? :> T, and vertices in are labeled with T—meaning that labels in are exact copies of the labels/type names in ), and such that the union-like operator identifies (i.e., coalesces) the pair of vertices with labels/type names ? <: O (denoting all subtypes of O) and ? :> N (denoting all supertypes of N), the pair with ? :> O (denoting all supertypes of O) and O, and the pair with ? <: N (denoting all subtypes of N) and N. (Thus we have ), and,

  • for , we have

As such, the graph operator basically constructs three “copies” of the input graph (corresponding to the three variance subtyping rules) and connects the vertices of these graphs based on the containment relation222Hence the triangle symbol , where one copy—a “side” of the “triangle”—is for the covariantly-ordered ‘? <: T’ wildcard type arguments, another side is for the oppositely/contravariantly-ordered ‘? :> T’ arguments, and the third, bottom side is for the invariantly/flatly-ordered ‘T’ arguments. See the graph examples in Section 4 for illustration, where green edges correspond to the “covariant side of the triangle” and red edges correspond to the “contravariant side”, while the row/line of vertices/types at the bottom (ones right above type N, with no interconnecting edges between them) correspond to the third “invariant side”..

3.2 Construction of The Java Subtyping Relation

Based on the informal description of the construction method for the Java subtyping relation and of the partial Cartesian graph product constructor provided in Section 2, we now define the graph of the subtyping relation of a particular Java program as the solution of the recursive graph equation

(3.1)

where is the finite graph of the subclassing/inheritance relation between classes of the program, and is the set of generic classes of the program (a subset of classes in ).

Equation (3.1) can be solved for (as the least fixed point of Equation (3.1)) iteratively, using the equation

(3.2)

where the are finite successive better approximations of the infinite relation , and is an appropriate initial graph of the containment relation (which we take as the graph with one vertex, having the default wildcard type argument ‘?’, standing for ? <: O, as its only vertex, and having no containment relation edges).333We conjecture that the greatest fixed point of Equation (3.1) may be useful in modeling “F-bounded generics”, given the strong connection between gfps (greatest fixed points) and coalgebras. The study of coalgebras seems to be the area of universal algebra (and category theory) on which the theory of F-bounded polymorphism (and F-bounded generics) is based. We do not explore this point any further in this paper however.

3.3 Self-Similarity and The Role of Nominal-Typing

Equation (3.2) formally and succinctly describes the construction method of the generic Java subtyping relation between ground Java reference types. The self-similarity in the Java subtyping relation can now be clearly seen to result from the fact that the second factor in the partial product defining (i.e., the wildcards graph the graph of the containment relation between wildcard type arguments) is derived iteratively, in all but the first iteration, from the first factor of the product (i.e., from , the subclassing relation).

Noting that subclassing/type inheritance is an inherently nominal notion in OOP (i.e., is always defined using class names, to express that corresponding named classes preserve inherited behavioral contracts associated with the names), the observation of the dependency of on makes it evident that the dependency of the OO subtyping relation on the nominal subclassing/inheritance relation in mainstream nominally-typed OO programming languages (such as Java, C#, C++, Scala and Kotlin, as discussed by [NOOPsumm, ; AbdelGawad14, ; InhSubtyNWPT13, ; AbdelGawad2015, ]) has strongly continued after generic types were added to these languages, further illustrating the value of nominal typing in mainstream OOP languages and the influence and effects of nominal typing on their type systems.

Further, it should be noted that the properties of the partial Cartesian graph product (as presented by [AbdelGawad2018a, ] and summarized above) imply that non-generic OOP is a special case of generic OOP, which is a fact that is intuitively clear to OO software developers. In particular, the property of that for (i.e., if no classes in are generic) the result of the partial product is equal to the left factor of the partial product makes Equation (3.1) become

which just expresses the identification of the subtyping relation () with the subclassing/type inheritance relation (), as is well-known to be the case in non-generic nominally-typed OOP (again, see [NOOPsumm, ; AbdelGawad14, ; InhSubtyNWPT13, ; AbdelGawad2015, ]).

To strengthen our understanding of the formal construction of the Java subtyping relation , we can go on to discuss some of the properties of the graphs approximating , particularly their size, order and element rank properties. Given that there are formulae for (bounds on) the size and order of the product graph constructed by  [AbdelGawad2018a, ] and of the triangle graph constructed by in terms of the sizes and orders of their input graphs, (bounds on) the size and order of a graph can be computed in terms of the size and order of , and , recursively going down to (with size 1 and order 0, i.e., one vertex and zero edges). For the sake of brevity, though, we do not present equations of the size and order of in this paper444Even though an interesting mental exercise (and programming exercise, given that the values given by the equations can be verified for some sample graphs using SageMath code that builds on the code we present in Appendix A), we currently see the equations as being interesting more as a mathematical curiosity than of them having much practical or theoretical value.,555As the equations presented in [AbdelGawad2018a, ] demonstrate, the reader may also like to note that coalescence of multiedges—for graphs that model posets such as the OO subtyping relation (where multiedges are meaningless)—and transitive reduction—used to present graphs of subtyping as Hasse diagrams—make the equations for computing the orders of constructed graphs in particular not immediately straightforward or simple. In fact there is no known formula for computing the order of the transitive reduction of a general graph in terms of only the order and size of the graph. The same inexistence of formulae applies to the order of the transitive closure of a graph, the number of paths of a graph, and, seemingly, also the number of ‘graph intervals’ [AbdelGawad2018c, ] of a graph., and proceed to illustrating examples instead.

4 Examples of Constructing The Java Subtyping Relation

In this section we present examples of how the generic Java subtyping relation between ground reference types with wildcard type arguments can be iteratively constructed. To decrease clutter, given that OO subtyping is a transitive relation, the transitive reduction of the subtyping graphs is presented in the examples below. Also, we use colored edges of graphs to indicate the self-similarity of the Java subtyping relation, where green edges correspond to subtyping due to the covariant subtyping rule, while red edges correspond to subtyping due to the contravariant subtyping rule. (Note also, as we explained in the description of graph operator , that types C<?> and C<? <: O> and C<? :> N> are different expressions of the same type, i.e., are identified. The same applies to types C<O> and C<? :> O>, as well as types C<N> and C<? <: N>).

Example 3.

Consider the Java class declaration

class C<T> {}.

The graphs in Figure 4.1 illustrate the first three iterations of the construction of the subtyping relation corresponding to this declaration.666The subscript is used in and following examples to denote the example index. We use double-indexing to additionally refer to iteration indices, as in , for example, which denotes the first version of as defined by the first iteration of the iterative construction method. 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)
(b)
(c)
(d)
Figure 4.1: Constructing generic OO subtyping using
Example 4.

Consider the two Java class declarations

class C {} // class C is non-generic

class D<T> {}.

The graphs in Figure 4.2 illustrate the first two iterations of the construction of the subtyping relation corresponding to these declarations. (We do not present graphs of in this and later examples below, due to the large size of these graphs).

(a)
(b)
(c)
Figure 4.2: Constructing generic OO subtyping using
Example 5.

Consider the two Java class declarations

class C<T> {}

class D<T> {}.

The graphs in Figure 4.3 illustrate the first two iterations of the construction of the subtyping relation corresponding to these declarations.

(a)
(b)
(c)
Figure 4.3: Constructing generic OO subtyping using
Example 6.

Consider the two Java class declarations

class C<T> {}

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

The graphs in Figure 4.4 illustrate the first two iterations of the construction of the subtyping relation corresponding to these declarations.

(a)
(b)
(c)
Figure 4.4: Constructing generic OO subtyping using
Example 7.

Consider the four Java class declarations

class C {}

class E extends C {}

class D {}

class F<T> extends D {}.

The graphs in Figure 4.5 illustrate the first two iterations of the construction of the subtyping relation corresponding to these declarations. (Readers are invited to find out the subgraphs of that are similar—i.e., isomorphic—to , and, at least mentally in their minds, to layout accordingly.)

(a)
(b)
(c)
Figure 4.5: Constructing generic OO subtyping using (automatic layout by yEd)

(In Appendix A we present SageMath [Stein2017, ] code that helped us—and can help the readers—in producing some of the diagrams presented in this paper.)

5 Related Work

Using a graph product to construct the generic OO subtyping relation seems to be a new idea, with no similar prior work. We already mentioned, however, the earlier work of [AbdelGawad2017a, ] that uses category theoretic tools (namely operads) to model generic OO subtyping, which is work that has paved the way for the work we present in this paper.

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 of [Bank96, ; Bracha98, ; Corky98, ] was mostly focused on researching OO generics, while the work of [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 by 

[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 the work of [Torgersen2004, ], which is based on the earlier research by [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 points to the need for more research on wildcard types and generic OOP.

6 Discussion and Future Work

In this paper we demonstrate, much more precisely than was done by [AbdelGawad2017a, ], how the graph of the Java subtyping relation between ground Java reference types can be constructed as an infinite self-similar partial Cartesian graph product. The simple construction method we presented in this paper nicely captures some of the main features of the generic subtyping relation in Java and similar OO languages, particularly the details of the self-similarity of the relation. Based on our development of a notion of a partial Cartesian graph product and the earlier development of the outline of the operad (by [AbdelGawad2017a, ]) for use in modeling the generic Java subtyping relation (both of which particularly reveal the intricate self-similarity of the relation) we strongly believe that using more mathematical tools from category theory (such as operads) and from graph theory (such as partial graph products) is very likely to be the key to having a better understanding of complex features of programming languages such as wildcard types and generics.

In agreement with the detailed explanation of [AbdelGawad2017a, ], in our opinion the most important reason for obscuring the self-similarity of the generic subtyping relation in Java, and the exact details of the intricacy of its self-similarity, is thinking about the subtyping relation in structural-typing terms rather than nominal-typing ones. Although the polymorphic structural subtyping relation, with variance annotations, may exhibit some form of self-similarity that is similar to the one we demonstrate for Java, it should be noted that, as explained by [NOOPsumm, ; InhSubtyNWPT13, ; AbdelGawad14, ; AbdelGawad2015, ], nominal typing in OO languages such as Java, C#, Kotlin and Scala causes the full identification of (i.e., one-to-one correspondence between) type/contract inheritance and nominal subtyping in non-generic OOP. Such a simple and strong connection between type inheritance and subtyping does not exist when thinking about the OO subtyping relation in structural typing terms. Based on the discussion of the source of self-similarity in the Java subtyping relation that we present in Section 3, it seems to us that not making this observation, keeping instead the subtyping relation separate and independent from the inheritance relation, makes it harder to see the self-similarity of generic nominal subtyping, its intricacies, and its fundamental dependency on the subclassing/inheritance relation.

Having said that, more work is needed, however, to model Java and generic nominal subtyping more accurately. In particular, in this paper we do not model bounded type variables (other than those upper-bounded with type Object). An immediate extension of our work, that gets us closer to modeling bounded type variables (with both lower and upper bounds), is to construct a more general Java subtyping relation that uses interval types instead of wildcard types (we conjecture that lower bounds on type variables, which are unsupported so far in Java, will mesh well with interval types, which [AbdelGawad2018c, ] introduces).

Other investigations that can build on the work we present here are to construct the Java subtyping relation with less restrictions/assumptions, such as allowing more complex inheritance relations between generic types777So as to allow, for example, generic class declarations such as class C<T> extends D<E<T>> {} and class C<T> extends D<E<F<T>> {} (assuming the simple obvious declarations of generic classes D, E, and F). We believe these type inheritance declarations can be handled in (a simple extension of) our Java subtyping construction method by introducing instantiations of class C one and two iterations after (i.e., will be of a higher rank than) generic instantiations of classes E and F respectively. Instantiation of a generic class C in its own supertype (e.g., as in the Java class declaration class C<T> extends D<C<T>> {}) presents a circularity problem however. (Although similar in flavor, and related, this issue is separate from the notion of “F-bounded generics”). and allowing multiple type arguments. To analyze the full Java subtyping relation, i.e., between ground and non-ground reference types, type variables may also be included in the construction of the Java subtyping relation. We suggest in [AbdelGawad2016a, ; AbdelGawad2016c, ; AbdelGawad2017a, ; AbdelGawad2017b, ] how this might be done, but we leave the actual work to future work.

References

Appendix A SageMath Code

In this appendix we present the 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.

TopCls = ’O’
BotCls = ’N’
WLP = ’<’ # LeftParen for wildcard type args
WRP = ’>’ # RightParen for wildcard type args
ExtStr = <:
SupStr = :>
W = ’?’ # Wildcard
WExt = W+ExtStr
WSup = W+SupStr
#Construct Type Arguments (TAs)
def TAs(S):
  CovTA=S.copy()
  CovTA.relabel(lambda T: W if (T==TopCls) else
                          (BotCls if (T==BotCls)
                           else WExt+T))
  ConTA=S.copy()
  ConTA.reverse_edges(ConTA.edges())
  # all of them, due to contravariant subtyping
  ConTA.relabel(lambda T: W if (T==BotCls) else
                          (TopCls if (T==TopCls)
                           else WSup+T))
  InvTA=S.copy()
  InvTA.delete_edges(InvTA.edges())
  # all of them, due to invariant subtyping
  TA=CovTA.union(ConTA).union(InvTA)
  # earlier relabelling helps identify type args.
  # Add subtyping edges from InvTA to corrspndng
  # type args in CovTA and ConTA.
  MinON = InvTA.copy()
  MinON.delete_vertex(TopCls)
  MinON.delete_vertex(BotCls)
  TA.add_edges([(T,WExt+T) for T in MinON])
  TA.add_edges([(T,WSup+T) for T in MinON])
  TA = TA.transitive_reduction()
  # to remove unnecessary edges added in last
  # two steps, if any.
  return TA
#Construct Generic Subtyping Product (GSP)
def GSP(subclassing, lngc, TAs, lbl_fn):
  # main step
  S=DiGraph.cartesian_product(subclassing,TAs)
  lngcc = map(lambda ngc: filter(lambda(c,_):
                c==ngc, S.vertices()), lngc)
  # lngcc is list of non-generic class clusters
  # merge the clusters
  map(lambda cc: S.merge_vertices(cc), lngcc)
  S = S.transitive_reduction()
  S.relabel(lambda (c,ta): c if (c in lngc)
                           else lbl_fn(c,ta))
  return S
def wty(c,wta):
  return c+WLP+wta+WRP
def WildcardsSubtyping(subclassing, lngc,
                       FN_Prfx, num_iter):
  #Definition of S0 (initial S)
  S0=subclassing.copy()
  S0.relabel(lambda c: c if (c in lngc) else
                       wty(c,W))
  S = S0
  lst = [S0]
  for i in [1..num_iter]:
    TA = TAs(S)
    # main step
    S = GSP(subclassing, lngc, TA, wty)
    lst.append(TA)
    lst.append(S)
  # Repeat as needed.
  # S = F(S)  final (infinite) subtyping
  #  relation is soln of this eqn (a fixed
  #  point).
  return lst

(Note: The code presented in Appendix A of [AbdelGawad2018c, ] builds on and makes use of the SageMath code presented here.)