Union and Intersection Contracts Are Hard, Actually

Total Page:16

File Type:pdf, Size:1020Kb

Union and Intersection Contracts Are Hard, Actually Union and intersection contracts are hard, actually Teodoro Freund Yann Hamdaoui Arnaud Spiwack Universidad de Buenos Aires Tweag Tweag Buenos Aires, Argentina Paris, France Paris, France [email protected] [email protected] [email protected] Abstract the configuration of an application. In traditional configura- Union and intersection types are a staple of gradually typed tion languages, such as YAML, TOML, or JSON, the config- language such as TypeScript. While it’s long been recog- uration is fully, and explicitly, spelt out. nized that union and intersection types are difficult to ver- However, with the advent of DevOps, configurations have ify statically, it may appear at first that the dynamic part of been extended to describe the entire state of a computer, or gradual typing is actually pretty simple. even a fleet of computers. For instance, with Kubernetes you It turns out however, that in presence of higher-order con- needto configure a large fleet of (possibly replicated) docker tracts union and intersection are deceptively difficult. The containers. To describe this sort of configurations, you re- literature on higher-order contracts with union and inter- ally want to be able to re-use and abstract parts of the con- section, while keenly aware of the fact, doesn’t really ex- figuration, like traditional programming languages do. To plain why. We point and illustrate the problems and trade- meet this need, languages such as Cue [2], Dhall [4], Json- offs inherent to union and intersection contracts, via exam- net [5], or Nickel [6], where configurations are generated ple and a survey of the literature. rather than spelt out, were created. Another example is continuous integration systems: it’s CCS Concepts: • General and reference → Surveys and fairly typical to need a matrix of jobs, wherein the same tests overviews; • Software and its engineering → Language are run on different infrastructures, or with different ver- features; Software verification and validation. sions of a compiler. Traditional configuration would have Keywords: contracts, higher-order contracts, union, inter- you copy the same steps for each infrastructure. This is te- section dious, hard to maintain, and error prone. It’s much better, instead, to write the steps once, and instantiate them for 1 Introduction each infrastructure. Continuous integration systems typi- cally do this using a templating system layered on top of Union types, meaning a type A ∪ B containing values which YAML. Each of the configuration-generating languages above belong either to a type A or B, are a popular tool when adding static types to a dynamic language. In particular, both Type- allow such job-matrix definition natively. Script [9] and MyPy [7], use union types to model the fre- 1.2 Nickel quent practice to use the value null (None in Python) to rep- resent an absent optional value. This is why the gradual typ- In this article, we will use the Nickel language [6] as illus- ing literature, concerned with formalising the interplay be- tration and motivation. At its core, Nickel is the JSON data tween static and dynamic type systems, has been quite in- model, augmented with abstraction mechanisms, and its con- terested in union types [10, 14, 17, 20, 22]. formed of: On the other hand, unions are not a common feature of • dictionaries, written as: arXiv:2106.06278v1 [cs.PL] 11 Jun 2021 static type systems, mostly because they are quite difficult {field1 = value1,..., fieldn = valuen} to verify statically. So unions are really only worth it in grad- • arrays: ually typed language where they formalise existing dynami- cally typed patterns. On the other hand, surely, for dynamic [x1, x2,..., xn] tests, unions are really easy: it is simply the Boolean disjunc- • functions: tions of two tests. fun Unfortunately, as we document in this article, as soon as arg1. .argn ⇒ body you extend dynamic checksto contracts [11], unions become • and let-definitions: actually pretty difficult, and threaten desirable properties of let id = value in exp your language. A Nickel configuration is then evaluated to an explicit 1.1 Configuration languages configuration, e.g. in JSON, which can then be consumed To motivate contracts and the problem caused by unions, by an application. Therefore a design constraint of Nickel is let’s make a detour through configuration languages. A con- any Nickel data must have a straightforward interpretation figuration language is a language concerned with describing in JSON. Conference’17, July 2017, Washington, DC, USA Teodoro Freund, Yann Hamdaoui, and Arnaud Spiwack 1.3 Contracts Unfortunately, the delayed check of contract, while essen- A useful feature of a configuration language is to provide fa- tial to ensuring that schema validation doesn’t affect per- cilities for schema validation. That is, help answer questions formance (or, indeed, is possible at all on functions), make like: does our configuration have all the required fields? does union contracts (and their less appreciated sibling, intersec- the url field indeed contains a URL? tion contracts) quite problematic. These are inherently dynamic questions, as they are all questions about the evaluated configuration. To this effect, 1.4 Contributions Nickel lets us annotate any expression with a dynamic schema Our contributions are as follows check: exp | C. There is also syntactic sugar to annotate def- • We describe the fundamental difficulties caused by pres- initions: let id | C = value in exp stands for let id = ( ence of union and intersection contracts in a language, value | C) in exp. which are kept implicit in the literature (Section 4) Let us pause for a moment and consider the following: • We survey the various trade-offs which appear in im- it is Nickel’s ambition to be able to manipulate configura- plemented languages and in the literature to work around tions like Nixpkgs. With over 50 000 packages, it is one of these difficulties (Section 5) the largest repository of software packages in existence [8]. Concretely, Nixpkgs is a dictionary mapping packages to 2 A typology of language features build recipes. That is, a massive, over-50 000-key-value-pair Union contracts are not only difficult to implement, their wide dictionary. It is absolutely out of the question to eval- unrestricted presence is incompatible with potentially desir- uate the entirety of this dictionary every time one needs to able properties of the language. In this section we present install 10 new packages: this would result in a painfully slow some of these properties; we will show how these properties experience. interact with union contracts in Sections 4 and 5. To be able to support such large dictionaries, Nickel’s dic- tionaries are lazy, that is, the values are only evaluated when 2.1 User-defined contracts explicitly required. For instance, when writing nixpkgs.hello, only the hello package gets evaluated. A strength of dynamic checking is that we can easily check But let’s consider now writing something like nixpkgs | properties which are impractical to check statically. For in- packages, to guarantee that all the packages conform to the stance that a string represents a well-formed URL, or a num- desired schema. If this were a simple Boolean test, it would ber is a valid port. have to evaluate all 50 000 package to check their validity, This same property is desirable of contracts as well, oth- hence breaking the laziness of dictionaries. Do we have to erwise we lose an important benefit of dynamic checking. choose between laziness and schema validation? Fortunately, Preferably, we want to be able to extend the universe of con- we don’t! Enter contracts [11]: dynamic checks which can tracts with user-defined predicates. be partially delayed, yet errors can be reported accurately. For instance, Figure 2 shows the definition of a contract Contracts can respect laziness of dictionaries, and they can for valid ports in Nickel syntax. User-defined contracts can be use to add schema validation to functions as well (in fact be combined with other contracts normally: Int → Port is functions were the original motivation for contracts). a contract verified by functions which, given an integer re- ThereisnoBooleanfunctionwhichcancheckthatavalue turns a valid port. has type Str → Str.Instead,acontractfor Str → Str checks This type of contracts are present in many different lan- for each call of the function whether guages, for instance, the Eiffel programming language[16], the precursor of the Design by Contract philosophy, makes 1. the argument has type Str, otherwise the caller of the it possible to assert these kinds of expression as pre- and function is faulty post-conditions on functions and as invariants on classes[3]. 2. if so, that the returned value has type Str, otherwise The Racket programming language also has a system to the implementation of the function is faulty work with contracts, powerful enough to define flat con- Like in the case of lazy dictionaries, the checks are de- tracts, and to compose them with other kinds of dynamic layed. Contracts keep track of whether the caller or the im- checks, like higher order contracts or a lightweight take on plementation is at fault for a violation, hence it can report union and intersection contracts[1]. precise error messages. Contracts are said to blame either the caller or the implementation. Compare Figure 1a and Fig- 2.2 Referential transparency ure 1b: in Figure 1a an error is reported inside the catHosts The performance of modern programs heavily relies on the function, but catHosts is, in fact, correct, as is made clear by optimizations performed by the compiler or the interpreter. Figure 1b, where catHosts is decorated with the Str → Str Even more so for functional languages, whose execution contract, and correctly reports that the caller failed to call model is often far removed from the hardware, causing naive catHosts with a string argument.
Recommended publications
  • First Class Overloading Via Insersection Type Parameters⋆
    First Class Overloading via Insersection Type Parameters? Elton Cardoso2, Carlos Camar~ao1, and Lucilia Figueiredo2 1 Universidade Federal de Minas Gerais, [email protected] 2 Universidade Federal de Ouro Preto [email protected], [email protected] Abstract The Hindley-Milner type system imposes the restriction that function parameters must have monomorphic types. Lifting this restric- tion and providing system F “first class" polymorphism is clearly desir- able, but comes with the difficulty that inference of types for system F is undecidable. More practical type systems incorporating types of higher- rank have recently been proposed, that rely on system F but require type annotations for the definition of functions with polymorphic type parameters. However, these type annotations inevitably disallow some possible uses of higher-rank functions. To avoid this problem and to pro- mote code reuse, we explore using intersection types for specifying the types of function parameters that are used polymorphically inside the function body, allowing a flexible use of such functions, on applications to both polymorphic or overloaded arguments. 1 Introduction The Hindley-Milner type system [9] (HM) has been successfuly used as the basis for type systems of modern functional programming languages, such as Haskell [23] and ML [20]. This is due to its remarkable properties that a compiler can in- fer the principal type for any language expression, without any help from the programmer, and the type inference algorithm [5] is relatively simple. This is achieved, however, by imposing some restrictions, a major one being that func- tion parameters must have monomorphic types. For example, the following definition is not allowed in the HM type system: foo g = (g [True,False], g ['a','b','c']) Since parameter g is used with distinct types in the function's body (being applied to both a list of booleans and a list of characters), its type cannot be monomorphic, and this definition of foo cannot thus be typed in HM.
    [Show full text]
  • Disjoint Polymorphism
    Disjoint Polymorphism João Alpuim, Bruno C. d. S. Oliveira, and Zhiyuan Shi The University of Hong Kong {alpuim,bruno,zyshi}@cs.hku.hk Abstract. The combination of intersection types, a merge operator and parametric polymorphism enables important applications for program- ming. However, such combination makes it hard to achieve the desirable property of a coherent semantics: all valid reductions for the same expres- sion should have the same value. Recent work proposed disjoint inter- sections types as a means to ensure coherence in a simply typed setting. However, the addition of parametric polymorphism was not studied. This paper presents Fi: a calculus with disjoint intersection types, a vari- ant of parametric polymorphism and a merge operator. Fi is both type- safe and coherent. The key difficulty in adding polymorphism is that, when a type variable occurs in an intersection type, it is not statically known whether the instantiated type will be disjoint to other compo- nents of the intersection. To address this problem we propose disjoint polymorphism: a constrained form of parametric polymorphism, which allows disjointness constraints for type variables. With disjoint polymor- phism the calculus remains very flexible in terms of programs that can be written, while retaining coherence. 1 Introduction Intersection types [20,43] are a popular language feature for modern languages, such as Microsoft’s TypeScript [4], Redhat’s Ceylon [1], Facebook’s Flow [3] and Scala [37]. In those languages a typical use of intersection types, which has been known for a long time [19], is to model the subtyping aspects of OO-style multiple inheritance.
    [Show full text]
  • Create Union Variables Difference Between Unions and Structures
    Union is a user-defined data type similar to a structure in C programming. How to define a union? We use union keyword to define unions. Here's an example: union car { char name[50]; int price; }; The above code defines a user define data type union car. Create union variables When a union is defined, it creates a user-define type. However, no memory is allocated. To allocate memory for a given union type and work with it, we need to create variables. Here's how we create union variables: union car { char name[50]; int price; } car1, car2, *car3; In both cases, union variables car1, car2, and a union pointer car3 of union car type are created. How to access members of a union? We use . to access normal variables of a union. To access pointer variables, we use ->operator. In the above example, price for car1 can be accessed using car1.price price for car3 can be accessed using car3->price Difference between unions and structures Let's take an example to demonstrate the difference between unions and structures: #include <stdio.h> union unionJob { //defining a union char name[32]; float salary; int workerNo; } uJob; struct structJob { char name[32]; float salary; int workerNo; } sJob; main() { printf("size of union = %d bytes", sizeof(uJob)); printf("\nsize of structure = %d bytes", sizeof(sJob)); } Output size of union = 32 size of structure = 40 Why this difference in size of union and structure variables? The size of structure variable is 40 bytes. It's because: size of name[32] is 32 bytes size of salary is 4 bytes size of workerNo is 4 bytes However, the size of union variable is 32 bytes.
    [Show full text]
  • Cyclone: a Type-Safe Dialect of C∗
    Cyclone: A Type-Safe Dialect of C∗ Dan Grossman Michael Hicks Trevor Jim Greg Morrisett If any bug has achieved celebrity status, it is the • In C, an array of structs will be laid out contigu- buffer overflow. It made front-page news as early ously in memory, which is good for cache locality. as 1987, as the enabler of the Morris worm, the first In Java, the decision of how to lay out an array worm to spread through the Internet. In recent years, of objects is made by the compiler, and probably attacks exploiting buffer overflows have become more has indirections. frequent, and more virulent. This year, for exam- ple, the Witty worm was released to the wild less • C has data types that match hardware data than 48 hours after a buffer overflow vulnerability types and operations. Java abstracts from the was publicly announced; in 45 minutes, it infected hardware (“write once, run anywhere”). the entire world-wide population of 12,000 machines running the vulnerable programs. • C has manual memory management, whereas Notably, buffer overflows are a problem only for the Java has garbage collection. Garbage collec- C and C++ languages—Java and other “safe” lan- tion is safe and convenient, but places little con- guages have built-in protection against them. More- trol over performance in the hands of the pro- over, buffer overflows appear in C programs written grammer, and indeed encourages an allocation- by expert programmers who are security concious— intensive style. programs such as OpenSSH, Kerberos, and the com- In short, C programmers can see the costs of their mercial intrusion detection programs that were the programs simply by looking at them, and they can target of Witty.
    [Show full text]
  • Polymorphic Intersection Type Assignment for Rewrite Systems with Abstraction and -Rule Extended Abstract
    Polymorphic Intersection Type Assignment for Rewrite Systems with Abstraction and -rule Extended Abstract Steffen van Bakel , Franco Barbanera , and Maribel Fernandez´ Department of Computing, Imperial College, 180 Queen’s Gate, London SW7 2BZ. [email protected] Dipartimento di Matematica, Universita` degli Studi di Catania, Viale A. Doria 6, 95125 Catania, Italia. [email protected] LIENS (CNRS URA 8548), Ecole Normale Superieure,´ 45, rue d’Ulm, 75005 Paris, France. [email protected] Abstract. We define two type assignment systems for first-order rewriting ex- tended with application, -abstraction, and -reduction (TRS ). The types used in these systems are a combination of ( -free) intersection and polymorphic types. The first system is the general one, for which we prove a subject reduction theorem and show that all typeable terms are strongly normalisable. The second is a decidable subsystem of the first, by restricting types to Rank 2. For this sys- tem we define, using an extended notion of unification, a notion of principal type, and show that type assignment is decidable. Introduction The combination of -calculus (LC) and term rewriting systems (TRS) has attracted attention not only from the area of programming language design, but also from the rapidly evolving field of theorem provers. It is well-known by now that type disciplines provide an environment in which rewrite rules and -reduction can be combined with- out loss of their useful properties. This is supported by a number of results for a broad range of type systems [11, 12, 20, 7, 8, 5]. In this paper we study the combination of LC and TRS as a basis for the design of a programming language.
    [Show full text]
  • REFPERSYS High-Level Goals and Design Ideas*
    REFPERSYS high-level goals and design ideas* Basile STARYNKEVITCH† Abhishek CHAKRAVARTI‡ Nimesh NEEMA§ refpersys.org October 2019 - May 2021 Abstract REFPERSYS is a REFlexive and orthogonally PERsistent SYStem (as a GPLv3+ licensed free software1) running on Linux; it is a hobby2 but serious research project for many years, mostly aimed to experiment open science ideas close to Artificial General Intelligence3 dreams, and we don’t expect use- ful or interesting results before several years of hard work. audience : LINUX free software developers4 and computer scientists interested in an experimental open science approach to reflexive systems, orthogonal persistence, symbolic artificial intelligence, knowledge engines, etc.... Nota Bene: this report contains many hyperlinks to relevant sources so its PDF should rather be read on a computer screen, e.g. with evince. Since it describes a circular design (with many cycles [Hofstadter:1979:GEB]), we recommend to read it twice (skipping footnotes and references on the first read). This entire document is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License. To view a copy of this license, visit creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA. *This document has git commit fb17387fbbb7e200, was Lua-LATEX generated on 2021-May-17 18:55 MEST, see gitlab.com/bstarynk/refpersys/ and its doc/design-ideas subdirectory. Its draft is downloadable, as a PDF file, from starynkevitch.net/Basile/refpersys-design.pdf ... †See starynkevitch.net/Basile/ and contact [email protected], 92340 Bourg La Reine (near Paris), France. ‡[email protected], FL 3C, 62B PGH Shah Road, Kolkata 700032, India.
    [Show full text]
  • [Note] C/C++ Compiler Package for RX Family (No.55-58)
    RENESAS TOOL NEWS [Note] R20TS0649EJ0100 Rev.1.00 C/C++ Compiler Package for RX Family (No.55-58) Jan. 16, 2021 Overview When using the CC-RX Compiler package, note the following points. 1. Using rmpab, rmpaw, rmpal or memchr intrinsic functions (No.55) 2. Performing the tail call optimization (No.56) 3. Using the -ip_optimize option (No.57) 4. Using multi-dimensional array (No.58) Note: The number following the note is an identification number for the note. 1. Using rmpab, rmpaw, rmpal or memchr intrinsic functions (No.55) 1.1 Applicable products CC-RX V2.00.00 to V3.02.00 1.2 Details The execution result of a program including the intrinsic function rmpab, rmpaw, rmpal, or the standard library function memchr may not be as intended. 1.3 Conditions This problem may arise if all of the conditions from (1) to (3) are met. (1) One of the following calls is made: (1-1) rmpab or __rmpab is called. (1-2) rmpaw or __rmpaw is called. (1-3) rmpal or __rmpal is called. (1-4) memchr is called. (2) One of (1-1) to (1-3) is met, and neither -optimize=0 nor -noschedule option is specified. (1-4) is met, and both -size and -avoid_cross_boundary_prefetch (Note 1) options are specified. (3) Memory area that overlaps with the memory area (Note2) read by processing (1) is written in a single function. (This includes a case where called function processing is moved into the caller function by inline expansion.) Note 1: This is an option added in V2.07.00.
    [Show full text]
  • Spindle Documentation Release 2.0.0
    spindle Documentation Release 2.0.0 Jorge Ortiz, Jason Liszka June 08, 2016 Contents 1 Thrift 3 1.1 Data model................................................3 1.2 Interface definition language (IDL)...................................4 1.3 Serialization formats...........................................4 2 Records 5 2.1 Creating a record.............................................5 2.2 Reading/writing records.........................................6 2.3 Record interface methods........................................6 2.4 Other methods..............................................7 2.5 Mutable trait...............................................7 2.6 Raw class.................................................7 2.7 Priming..................................................7 2.8 Proxies..................................................8 2.9 Reflection.................................................8 2.10 Field descriptors.............................................8 3 Custom types 9 3.1 Enhanced types..............................................9 3.2 Bitfields..................................................9 3.3 Type-safe IDs............................................... 10 4 Enums 13 4.1 Enum value methods........................................... 13 4.2 Companion object methods....................................... 13 4.3 Matching and unknown values...................................... 14 4.4 Serializing to string............................................ 14 4.5 Examples................................................. 14 5 Working
    [Show full text]
  • Union Types for Semistructured Data
    Edinburgh Research Explorer Union Types for Semistructured Data Citation for published version: Buneman, P & Pierce, B 1999, Union Types for Semistructured Data. in Union Types for Semistructured Data: 7th International Workshop on Database Programming Languages, DBPL’99 Kinloch Rannoch, UK, September 1–3,1999 Revised Papers. Lecture Notes in Computer Science, vol. 1949, Springer-Verlag GmbH, pp. 184-207. https://doi.org/10.1007/3-540-44543-9_12 Digital Object Identifier (DOI): 10.1007/3-540-44543-9_12 Link: Link to publication record in Edinburgh Research Explorer Document Version: Peer reviewed version Published In: Union Types for Semistructured Data General rights Copyright for the publications made accessible via the Edinburgh Research Explorer is retained by the author(s) and / or other copyright owners and it is a condition of accessing these publications that users recognise and abide by the legal requirements associated with these rights. Take down policy The University of Edinburgh has made every reasonable effort to ensure that Edinburgh Research Explorer content complies with UK legislation. If you believe that the public display of this file breaches copyright please contact [email protected] providing details, and we will remove access to the work immediately and investigate your claim. Download date: 27. Sep. 2021 Union Typ es for Semistructured Data Peter Buneman Benjamin Pierce University of Pennsylvania Dept of Computer Information Science South rd Street Philadelphia PA USA fpeterbcpiercegcisupenn edu Technical
    [Show full text]
  • Coredx DDS Type System
    CoreDX DDS Type System Designing and Using Data Types with X-Types and IDL 4 2017-01-23 Table of Contents 1Introduction........................................................................................................................1 1.1Overview....................................................................................................................2 2Type Definition..................................................................................................................2 2.1Primitive Types..........................................................................................................3 2.2Collection Types.........................................................................................................4 2.2.1Enumeration Types.............................................................................................4 2.2.1.1C Language Mapping.................................................................................5 2.2.1.2C++ Language Mapping.............................................................................6 2.2.1.3C# Language Mapping...............................................................................6 2.2.1.4Java Language Mapping.............................................................................6 2.2.2BitMask Types....................................................................................................7 2.2.2.1C Language Mapping.................................................................................8 2.2.2.2C++ Language Mapping.............................................................................8
    [Show full text]
  • A Proposal for a Standard Systemverilog Synthesis Subset
    A Proposal for a Standard Synthesizable Subset for SystemVerilog-2005: What the IEEE Failed to Define Stuart Sutherland Sutherland HDL, Inc., Portland, Oregon [email protected] Abstract frustrating disparity in commercial synthesis compilers. Each commercial synthesis product—HDL Compiler, SystemVerilog adds hundreds of extensions to the Encounter RTL Compiler, Precision, Blast and Synplify, to Verilog language. Some of these extensions are intended to name just a few—supports a different subset of represent hardware behavior, and are synthesizable. Other SystemVerilog. Design engineers must experiment and extensions are intended for testbench programming or determine for themselves what SystemVerilog constructs abstract system level modeling, and are not synthesizable. can safely be used for a specific design project and a The IEEE 1800-2005 SystemVerilog standard[1] defines specific mix of EDA tools. Valuable engineering time is the syntax and simulation semantics of these extensions, lost because of the lack of a standard synthesizable subset but does not define which constructs are synthesizable, or definition for SystemVerilog. the synthesis rules and semantics. This paper proposes a standard synthesis subset for SystemVerilog. The paper This paper proposes a subset of the SystemVerilog design reflects discussions with several EDA companies, in order extensions that should be considered synthesizable using to accurately define a common synthesis subset that is current RTL synthesis compiler technology. At Sutherland portable across today’s commercial synthesis compilers. HDL, we use this SystemVerilog synthesis subset in the training and consulting services we provide. We have 1. Introduction worked closely with several EDA companies to ensure that this subset is portable across a variety of synthesis SystemVerilog extensions to the Verilog HDL address two compilers.
    [Show full text]
  • Julia's Efficient Algorithm for Subtyping Unions and Covariant
    Julia’s Efficient Algorithm for Subtyping Unions and Covariant Tuples Benjamin Chung Northeastern University, Boston, MA, USA [email protected] Francesco Zappa Nardelli Inria of Paris, Paris, France [email protected] Jan Vitek Northeastern University, Boston, MA, USA Czech Technical University in Prague, Czech Republic [email protected] Abstract The Julia programming language supports multiple dispatch and provides a rich type annotation language to specify method applicability. When multiple methods are applicable for a given call, Julia relies on subtyping between method signatures to pick the correct method to invoke. Julia’s subtyping algorithm is surprisingly complex, and determining whether it is correct remains an open question. In this paper, we focus on one piece of this problem: the interaction between union types and covariant tuples. Previous work normalized unions inside tuples to disjunctive normal form. However, this strategy has two drawbacks: complex type signatures induce space explosion, and interference between normalization and other features of Julia’s type system. In this paper, we describe the algorithm that Julia uses to compute subtyping between tuples and unions – an algorithm that is immune to space explosion and plays well with other features of the language. We prove this algorithm correct and complete against a semantic-subtyping denotational model in Coq. 2012 ACM Subject Classification Theory of computation → Type theory Keywords and phrases Type systems, Subtyping, Union types Digital Object Identifier 10.4230/LIPIcs.ECOOP.2019.24 Category Pearl Supplement Material ECOOP 2019 Artifact Evaluation approved artifact available at https://dx.doi.org/10.4230/DARTS.5.2.8 Acknowledgements The authors thank Jiahao Chen for starting us down the path of understanding Julia, and Jeff Bezanson for coming up with Julia’s subtyping algorithm.
    [Show full text]