Type-Safe Cast

Total Page:16

File Type:pdf, Size:1020Kb

Type-Safe Cast Type-Safe Cast ∗ Stephanie Weirich Department of Computer Science Cornell University Ithaca, NY 14853 [email protected] ABSTRACT and retrieving items from the table. In a syntax resembling In a language with non-parametric or ad-hoc polymorphism, Standard ML [10], this interface is it is possible to determine the identity of a type variable at run time. With this facility, we can write a function to con- sig vert a term from one abstract type to another, if the two type table hidden types are identical. However, the naive implementa- val empty : table tion of this function requires that the term be destructed and val insert : ∀α. table → (string × α) → table rebuilt. In this paper, we show how to eliminate this over- val find : ∀α. table → string → α head using higher-order type abstraction. We demonstrate end this solution in two frameworks for ad-hoc polymorphism: intensional type analysis and type classes. However, looking at the type of find reveals something odd: Categories and Subject Descriptors If this polymorphic function behaves parametrically with re- spect to α, that is it executes the same code regardless of D.3.3 [Programming Languages]: Language Constructs the identity of α, there cannot possibly be any correct im- and Features—abstract data types, polymorphism, control plementation of find [15]. All implementations must either structures; F.3.3 [Logics and Meanings of Programs]: diverge or raise an exception. Let us examine several possi- Software—type structure, control primitives, functional con- ble implementations to see where they go wrong. structs We will assume that the data structure used to implement General Terms the symbol table is not the issue, so for simplicity we will Languages use an association list. Keywords val empty = [] Ad-hoc polymorphism, dynamic typing, intensional type anal- ysis, type classes Given a string and a list, the following version of find iter- ates over the list looking for the matching string: 1. THE SETUP Suppose you wanted to implement a heterogeneous symbol table — a finite map from strings to values of any type. let rec find = Λα. You could imagine that the interface to this module would fn table => fn symbol => declare an abstract type for the table, a value for the empty case table of table, and two polymorphic functions for inserting items into [] => raise NotFound | ( (name, value) :: rest ) => ∗This paper is based on work supported in part by the Na- if symbol = name then value tional Science Foundation under Grant No. CCR-9875536. else find[α] rest symbol Any opinions, findings and conclusions or recommendations expressed in this publication are those of the author and do not reflect the views of this agency. Note that, unlike in SML, we make type application explicit in a manner similar to the polymorphic lambda calculus or System F [4, 14]. The notation Λα abstracts the type α and find[α] instantiates this type for the recursive call. Unfortunately, this function is of type ∀α. (string × α) list → string → α. ICFP ’00 Montreal, Quebec Canada If we were looking up an int, the list passed to find could only contain pairs of strings and ints. We would not be able to store values of any other type than int in our symbol This language is interpreted by a type-passing semantics. table. In other words, at run time a type argument is passed to a type abstraction of type ∀α.τ, and can be analyzed by The problem is that, in a statically typed language, all el- typecase. Dually, when we create an object of an existen- ements of a list need to have the same type: It would be tial type, ∃α.τ, the hidden type is included in the package, incorrect to form an association list [ ("x", 1) ; ("y", and when the package is opened, α may also be examined. ML (2,3)) ]. As we do not want to constrain the symbol table In λi , universal and existential types have different prop- to contain only one type, we need to hide the type of the erties from a system with a type-erasure semantics, such as value for each entry in the list. One possibility is to use an the polymorphic lambda calculus. In a type-erasure system, existential type [12]. The instruction types may have no effect on run-time execution and there- fore may be erased after type checking. There, ∀α.α is an empty type (such as void), and ∃β.β is equivalent to the ∃β.τ τ 0 ML pack v as hiding singleton type unit. However, in λi , ∀α.α is not empty, as we can use typecase to define an appropriate value for each 0 type, and ∃β.β is the implementation of type Dynamic, as coerces a value of type τ with τ substituted for β into one we can use typecase to recover the hidden type. of type ∃β.τ. Conversely, the instruction ML In λi , a simple function, sametype, to compare two types and return true if they match, can be implemented with unpack (β,x) = e in e’ nested typecases. The outer typecase discovers the head normal form of the first type, and then the inner typecase 1 destructs an existential package e of type ∃β.τ, binding a compares it to the head normal form of the second. For new type variable β and a new term variable x of type τ product and function types, sametype calls itself recursively within the expression e’. on the subcomponents of the type. Each of these branches binds type variables (such as α1 and α2) to the subcompo- Therefore, we can create a symbol table of type (string × nents of the types so that they may be used in the recursive ∃β.β) list with the expression call. [ ("x", pack 1 as ∃β.β hiding int) ; ("y", pack (2,3) as ∃β.β hiding int × int ] let rec sametype = Λα. Λβ. So the code for insert should just package up its argument typecase (α) of and cons it to the rest of the table. int => typecase (β) of val insert = int => true Λα. fn table => fn (symbol, obj) => | => false (symbol, pack obj as ∃β.β hiding α) :: table | (α1 × α2)=> typecase (β) of (β1 × β2) => However, the existential type has not really solved the prob- sametype[α1][β1] lem. We can create the list, but what do we do when we look andalso sametype[α2][β2] up a symbol? It will have type ∃β.β, but find must return | => false a value of type α. If we use the symbol table correctly, then | (α1 → α2) => α and β will abstract the same type, but we need to verify typecase (β) of this property before we can convert something of type β to (β1 → β2) => type α. We can not compare α and β and still remain para- sametype[α1][β1] metric in α and β. Therefore, it seems as though we need andalso sametype[α2][β2] a language that supports some sort of non-parametric poly- | => false morphism (also called run-time type analysis, overloading, or “ad hoc” polymorphism). Formulations of this feature include Haskell type classes [16], type Dynamic [1, 7, 9], ex- tensional polymorphism [3], and intensional polymorphism [6]. As these nested typecases are tedious to write, we borrow from the pattern matching syntax of Standard ML, and ab- For now, we will consider the last, in Harper and Morrisett’s breviate this function as: ML language λi . This language contains the core of SML plus an additional typerec operator to recursively examine un- known types at run time. For simplicity, we will separate recursion from type analysis and use the operator typecase to discriminate between types, and rec to compute the least 1For brevity, we only include int, product types, and func- fixed point of a recursive equation. tion types in the examples. let rec sametype = cast : ∀α. ∀β. α → β Λα. Λβ. let rec cast = typecase (α, β) of Λα. Λβ. (int,int) => true typecase [δ , δ . δ → δ ](α, β) of α × α β × β 1 2 1 2 | ( 1 2, 1 2) => (int, int) => α β sametype[ 1][ 1] fn (x:int) => x α β andalso sametype[ 2][ 2] | (α × α , β × β ) => α → α β → β 1 2 1 2 | ( 1 2, 1 2) => let val f = cast [α ][β ] α β 1 1 sametype[ 1][ 1] val g = cast [α ][β ] α β 2 2 andalso sametype[ 2][ 2] in | ( , ) => false fn (x:α1 × α2) => (f (fst x), g (snd x)) end However, though this function does allow us to determine | (α1 → α2, β1 → β2) => if two types are equal, it does not solve our problem. In let val f = cast [β1][α1] fact, it is just about useless. If we try to use it in our val g = cast [α2][β2] implementation of find in fn (x:α1 → α2) => g ◦ x ◦ f let rec find = end Λα. fn table => fn symbol => | ( , ) => raise CantCast case table of [] => raise NotFound | ( (name, package) :: rest ) => Figure 1: First Solution unpack (β,value) = package in if symbol = name andalso sametype[α][β] typecase [γ.γ → γ] τ of then value int => fn (x:int) => x + 3 else find[α] rest symbol | ... we discover that this use does not type check. The return In later examples, when we use the pattern matching syntax type for find is the existentially bound β which escapes its for two nested typecases, we will need the schema to have scope. Even though we have added a dynamic check that two free type variables. α is equivalent to β, the check does not change the type of value from β to α.
Recommended publications
  • Typescript Language Specification
    TypeScript Language Specification Version 1.8 January, 2016 Microsoft is making this Specification available under the Open Web Foundation Final Specification Agreement Version 1.0 ("OWF 1.0") as of October 1, 2012. The OWF 1.0 is available at http://www.openwebfoundation.org/legal/the-owf-1-0-agreements/owfa-1-0. TypeScript is a trademark of Microsoft Corporation. Table of Contents 1 Introduction ................................................................................................................................................................................... 1 1.1 Ambient Declarations ..................................................................................................................................................... 3 1.2 Function Types .................................................................................................................................................................. 3 1.3 Object Types ...................................................................................................................................................................... 4 1.4 Structural Subtyping ....................................................................................................................................................... 6 1.5 Contextual Typing ............................................................................................................................................................ 7 1.6 Classes .................................................................................................................................................................................
    [Show full text]
  • A System of Constructor Classes: Overloading and Implicit Higher-Order Polymorphism
    A system of constructor classes: overloading and implicit higher-order polymorphism Mark P. Jones Yale University, Department of Computer Science, P.O. Box 2158 Yale Station, New Haven, CT 06520-2158. [email protected] Abstract range of other data types, as illustrated by the following examples: This paper describes a flexible type system which combines overloading and higher-order polymorphism in an implicitly data Tree a = Leaf a | Tree a :ˆ: Tree a typed language using a system of constructor classes – a mapTree :: (a → b) → (Tree a → Tree b) natural generalization of type classes in Haskell. mapTree f (Leaf x) = Leaf (f x) We present a wide range of examples which demonstrate mapTree f (l :ˆ: r) = mapTree f l :ˆ: mapTree f r the usefulness of such a system. In particular, we show how data Opt a = Just a | Nothing constructor classes can be used to support the use of monads mapOpt :: (a → b) → (Opt a → Opt b) in a functional language. mapOpt f (Just x) = Just (f x) The underlying type system permits higher-order polymor- mapOpt f Nothing = Nothing phism but retains many of many of the attractive features that have made the use of Hindley/Milner type systems so Each of these functions has a similar type to that of the popular. In particular, there is an effective algorithm which original map and also satisfies the functor laws given above. can be used to calculate principal types without the need for With this in mind, it seems a shame that we have to use explicit type or kind annotations.
    [Show full text]
  • Python Programming
    Python Programming Wikibooks.org June 22, 2012 On the 28th of April 2012 the contents of the English as well as German Wikibooks and Wikipedia projects were licensed under Creative Commons Attribution-ShareAlike 3.0 Unported license. An URI to this license is given in the list of figures on page 149. If this document is a derived work from the contents of one of these projects and the content was still licensed by the project under this license at the time of derivation this document has to be licensed under the same, a similar or a compatible license, as stated in section 4b of the license. The list of contributors is included in chapter Contributors on page 143. The licenses GPL, LGPL and GFDL are included in chapter Licenses on page 153, since this book and/or parts of it may or may not be licensed under one or more of these licenses, and thus require inclusion of these licenses. The licenses of the figures are given in the list of figures on page 149. This PDF was generated by the LATEX typesetting software. The LATEX source code is included as an attachment (source.7z.txt) in this PDF file. To extract the source from the PDF file, we recommend the use of http://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/ utility or clicking the paper clip attachment symbol on the lower left of your PDF Viewer, selecting Save Attachment. After extracting it from the PDF file you have to rename it to source.7z. To uncompress the resulting archive we recommend the use of http://www.7-zip.org/.
    [Show full text]
  • A Nominal Theory of Objects with Dependent Types
    A Nominal Theory of Objects with Dependent Types Martin Odersky, Vincent Cremet, Christine R¨ockl, Matthias Zenger Ecole´ Polytechnique F´ed´eralede Lausanne INR Ecublens 1015 Lausanne, Switzerland Technical Report IC/2002/070 Abstract Simula 67 [DMN70], whereas virtual or abstract types are present in BETA [MMPN93], as well as more recently in We design and study νObj, a calculus and dependent type gbeta [Ern99], Rune [Tor02] and Scala [Ode02]. An es- system for objects and classes which can have types as mem- sential ingredient of these systems are objects with type bers. Type members can be aliases, abstract types, or new members. There is currently much work that explores types. The type system can model the essential concepts the uses of this concept in object-oriented programming of Java’s inner classes as well as virtual types and family [SB98, TT99, Ern01, Ost02]. But its type theoretic foun- polymorphism found in BETA or gbeta. It can also model dations are just beginning to be investigated. most concepts of SML-style module systems, including shar- As is the case for modules, dependent types are a promis- ing constraints and higher-order functors, but excluding ap- ing candidate for a foundation of objects with type mem- plicative functors. The type system can thus be used as a bers. Dependent products can be used to represent functors basis for unifying concepts that so far existed in parallel in in SML module systems as well as classes in object sys- advanced object systems and in module systems. The paper tems with virtual types [IP02].
    [Show full text]
  • Refinement Types for ML
    Refinement Types for ML Tim Freeman Frank Pfenning [email protected] [email protected] School of Computer Science School of Computer Science Carnegie Mellon University Carnegie Mellon University Pittsburgh, Pennsylvania 15213-3890 Pittsburgh, Pennsylvania 15213-3890 Abstract tended to the full Standard ML language. To see the opportunity to improve ML’s type system, We describe a refinement of ML’s type system allow- consider the following function which returns the last ing the specification of recursively defined subtypes of cons cell in a list: user-defined datatypes. The resulting system of refine- ment types preserves desirable properties of ML such as datatype α list = nil | cons of α * α list decidability of type inference, while at the same time fun lastcons (last as cons(hd,nil)) = last allowing more errors to be detected at compile-time. | lastcons (cons(hd,tl)) = lastcons tl The type system combines abstract interpretation with We know that this function will be undefined when ideas from the intersection type discipline, but remains called on an empty list, so we would like to obtain a closely tied to ML in that refinement types are given type error at compile-time when lastcons is called with only to programs which are already well-typed in ML. an argument of nil. Using refinement types this can be achieved, thus preventing runtime errors which could be 1 Introduction caught at compile-time. Similarly, we would like to be able to write code such as Standard ML [MTH90] is a practical programming lan- case lastcons y of guage with higher-order functions, polymorphic types, cons(x,nil) => print x and a well-developed module system.
    [Show full text]
  • Lecture Slides
    Outline Meta-Classes Guy Wiener Introduction AOP Classes Generation 1 Introduction Meta-Classes in Python Logging 2 Meta-Classes in Python Delegation Meta-Classes vs. Traditional OOP 3 Meta-Classes vs. Traditional OOP Outline Meta-Classes Guy Wiener Introduction AOP Classes Generation 1 Introduction Meta-Classes in Python Logging 2 Meta-Classes in Python Delegation Meta-Classes vs. Traditional OOP 3 Meta-Classes vs. Traditional OOP What is Meta-Programming? Meta-Classes Definition Guy Wiener Meta-Program A program that: Introduction AOP Classes One of its inputs is a program Generation (possibly itself) Meta-Classes in Python Its output is a program Logging Delegation Meta-Classes vs. Traditional OOP Meta-Programs Nowadays Meta-Classes Guy Wiener Introduction AOP Classes Generation Compilers Meta-Classes in Python Code Generators Logging Delegation Model-Driven Development Meta-Classes vs. Traditional Templates OOP Syntactic macros (Lisp-like) Meta-Classes The Problem With Static Programming Meta-Classes Guy Wiener Introduction AOP Classes Generation Meta-Classes How to share features between classes and class hierarchies? in Python Logging Share static attributes Delegation Meta-Classes Force classes to adhere to the same protocol vs. Traditional OOP Share code between similar methods Meta-Classes Meta-Classes Guy Wiener Introduction AOP Classes Definition Generation Meta-Classes in Python Meta-Class A class that creates classes Logging Delegation Objects that are instances of the same class Meta-Classes share the same behavior vs. Traditional OOP Classes that are instances of the same meta-class share the same behavior Meta-Classes Meta-Classes Guy Wiener Introduction AOP Classes Definition Generation Meta-Classes in Python Meta-Class A class that creates classes Logging Delegation Objects that are instances of the same class Meta-Classes share the same behavior vs.
    [Show full text]
  • The Power of Interoperability: Why Objects Are Inevitable
    The Power of Interoperability: Why Objects Are Inevitable Jonathan Aldrich Carnegie Mellon University Pittsburgh, PA, USA [email protected] Abstract 1. Introduction Three years ago in this venue, Cook argued that in Object-oriented programming has been highly suc- their essence, objects are what Reynolds called proce- cessful in practice, and has arguably become the dom- dural data structures. His observation raises a natural inant programming paradigm for writing applications question: if procedural data structures are the essence software in industry. This success can be documented of objects, has this contributed to the empirical success in many ways. For example, of the top ten program- of objects, and if so, how? ming languages at the LangPop.com index, six are pri- This essay attempts to answer that question. After marily object-oriented, and an additional two (PHP reviewing Cook’s definition, I propose the term ser- and Perl) have object-oriented features.1 The equiva- vice abstractions to capture the essential nature of ob- lent numbers for the top ten languages in the TIOBE in- jects. This terminology emphasizes, following Kay, that dex are six and three.2 SourceForge’s most popular lan- objects are not primarily about representing and ma- guages are Java and C++;3 GitHub’s are JavaScript and nipulating data, but are more about providing ser- Ruby.4 Furthermore, objects’ influence is not limited vices in support of higher-level goals. Using examples to object-oriented languages; Cook [8] argues that Mi- taken from object-oriented frameworks, I illustrate the crosoft’s Component Object Model (COM), which has unique design leverage that service abstractions pro- a C language interface, is “one of the most pure object- vide: the ability to define abstractions that can be ex- oriented programming models yet defined.” Academ- tended, and whose extensions are interoperable in a ically, object-oriented programming is a primary focus first-class way.
    [Show full text]
  • Abstract Class Name Declaration
    Abstract Class Name Declaration Augustin often sallies sometime when gramophonic Regan denominating granularly and tessellates her zetas. Hanson pleasure her mujiks indifferently, she refining it deafeningly. Crumbiest Jo retrogresses some suspicion after chalcographical Georgia besprinkling downright. Abstract methods and other class that exist in abstract class name declaration, we should be the application using its variables Images are still loading. Java constructor declarations are not members. Not all fields need individual field accessors and mutators. Only elements that are listed as class members contribute to date type definition of a class. When you subclass an abstract class, improve service, etc. Be careful while extending above abstract class, with to little hitch. Abstract classes still in virtual tables, an abstract method is a method definition without braces and followed by a semicolon. Error while getting part list from Facebook! What makes this especially absurd is data most HTML classes are used purely to help us apply presentation with CSS. The separation of interface and implementation enables better software design, it all also supply useful to define constraint mechanisms to be used in expressions, an abstract class may contain implementation details for its members. Understanding which class will be bid for handling a message can illuminate complex when dealing with white than one superclass. How to compute the area if the dust is have known? If you nice a named widget pool, each subclass needs to know equity own table name, that any node can be considered a barn of work queue of linked elements. In only of a Java constructor data members are initialized.
    [Show full text]
  • Abstract Class Function Declaration Typescript
    Abstract Class Function Declaration Typescript Daniel remains well-established after Vale quote anemographically or singe any fortitude. Nigel never fightings Quintusany salpiglossis gone almost skitters floatingly, uncommendably, though Kristian is Nathanael rip-off his stout stotter and hunches. lived enough? Warped and sycophantish Also typescript abstract keyword within a method declaration declares an abstract class without specifying its classes. The typescript has only operate on structural typing appears. Methods in the classes are always defined. Working with JET Elements JET Elements are exported as Typescript interfaces. Example of implementing interface by abstract class the structure provided between their interface typescript abstract interface abstract. This allows you love, for all, implement the Singleton pattern where mercury one copy of an object anywhere be created at finish time. Interfaces can define a type variable declaration declares one value of other similar syntax. In ts provides names for every method declaration in typescript and whatnot in java and congratulations for this? Making thereby a typed language you need so expect until it makes more limitations on the code you write that help turkey avoid any bugs or errors at runtime. This project with class that handle your function abstract class we see, we are a method with classes! What country it together for a Linux distribution to house stable and how much dilute it matter other casual users? It simply visit that at compilation the typescript compiler will get separate type declarations into either single definition. Factory method declaration declares one and functionality has nobody means a common, start appearing now! Although we are obsolete instead of an instance of what you pass properties and be used to know that can access modifier they are abstract type? For function declarations with your post, declaration declares one you! Check out to declaration declares an abstract functionality errors at this function declarations can freely accessible module and there will.
    [Show full text]
  • Static Type Inference for Parametric Classes
    University of Pennsylvania ScholarlyCommons Technical Reports (CIS) Department of Computer & Information Science September 1989 Static Type Inference for Parametric Classes Atsushi Ohori University of Pennsylvania Peter Buneman University of Pennsylvania Follow this and additional works at: https://repository.upenn.edu/cis_reports Recommended Citation Atsushi Ohori and Peter Buneman, "Static Type Inference for Parametric Classes", . September 1989. University of Pennsylvania Department of Computer and Information Science Technical Report No. MS-CIS-89-59. This paper is posted at ScholarlyCommons. https://repository.upenn.edu/cis_reports/851 For more information, please contact [email protected]. Static Type Inference for Parametric Classes Abstract Central features of object-oriented programming are method inheritance and data abstraction attained through hierarchical organization of classes. Recent studies show that method inheritance can be nicely supported by ML style type inference when extended to labeled records. This is based on the fact that a function that selects a field ƒ of a record can be given a polymorphic type that enables it to be applied to any record which contains a field ƒ. Several type systems also provide data abstraction through abstract type declarations. However, these two features have not yet been properly integrated in a statically checked polymorphic type system. This paper proposes a static type system that achieves this integration in an ML-like polymorphic language by adding a class construct that allows the programmer to build a hierarchy of classes connected by multiple inheritance declarations. Moreover, classes can be parameterized by types allowing "generic" definitions. The type correctness of class declarations is st atically checked by the type system.
    [Show full text]
  • Syntactic Type Abstraction
    Syntactic Type Abstraction DAN GROSSMAN, GREG MORRISETT, and STEVE ZDANCEWIC Cornell University Software developers often structure programs in such a way that different pieces of code constitute distinct principals. Types help define the protocol by which these principals interact. In particular, abstract types allow a principal to make strong assumptions about how well-typed clients use the facilities that it provides. We show how the notions of principals and type abstraction can be formalized within a language. Different principals can know the implementation of different abstract types. We use additional syntax to track the flow of values with abstract types during the evaluation of a program and demonstrate how this framework supports syntactic proofs (in the style of subject reduction) for type-abstraction properties. Such properties have traditionally required semantic arguments; using syntax avoids the need to build a model for the language. We present various typed lambda calculi with principals, including versions that have mutable state and recursive types. Categories and Subject Descriptors: D.2.11 [Software Engineering]: Software Architectures— Information Hiding; Languages; D.3.1 [Programming Languages]: Formal Definitions and Theory—Syntax; Semantics; D.3.3 [Programming Languages]: Language Constructs and Fea- tures—Abstract data types; F.3.2 [Logics and Meanings of Programs]: Semantics of Program- ming Languages—Operational Semantics; F.3.3 [Logics and Meanings of Programs]: Studies of Program Constructs—Type Structure General Terms: Languages, Security, Theory, Verification Additional Key Words and Phrases: Operational semantics, parametricity, proof techniques, syn- tactic proofs, type abstraction 1. INTRODUCTION Programmers often use a notion of principal when designing the structure of a program.
    [Show full text]
  • Marshmallow-Annotations Documentation Release 2.4.1
    marshmallow-annotations Documentation Release 2.4.1 Alec Nikolas Reiter Jan 28, 2021 Contents 1 Installation 3 2 Content 5 Index 21 i ii marshmallow-annotations Documentation, Release 2.4.1 Version 2.4.1 (Change Log) marshmallow-annotations allows you to create marshmallow schema from classes with annotations on them: # music.py from typing import List class Album: id: int name: str def __init__(self, id: int, name: str): self.id= id self.name= name class Artist: id: int name: str albums: List[Album] def __init__(self, id: int, name: str, albums: List[Album]): self.id= id self.name= name self.albums= albums # schema.py from marshmallow_annotations import AnnotationSchema from.music import Album, Artist class AlbumScheme(AnnotationSchema): class Meta: target= Album register_as_scheme= True class ArtistScheme(AnnotationSchema): class Meta: target= Artist register_as_scheme= True scheme= ArtistScheme() scheme.dump( Artist( id=1, name="Abominable Putridity", albums=[ Album( id=1, name="The Anomalies of Artificial Origin" ) ] ) ) #{ # "albums": [ #{ # "id": 1, (continues on next page) Contents 1 marshmallow-annotations Documentation, Release 2.4.1 (continued from previous page) # "name": "The Anomalies of Artificial Origin" #} # ], # "id": 1, # "name": "Abominable Putridity" #} 2 Contents CHAPTER 1 Installation marshmallow-annotations is available on pypi and installable with: pip install marshmallow-annotations marshmallow-annotations supports Python 3.6+ and marshmallow 2.x.x Note: If you are install marshmallow-annotations outside of a virtual environment, consider installing with pip install --user marshmallow-annotations rather than using sudo or adminstrator privileges to avoid installing it into your system Python. 3 marshmallow-annotations Documentation, Release 2.4.1 4 Chapter 1. Installation CHAPTER 2 Content 2.1 Quickstart This guide will walk you through the basics of using marshmallow-annotations.
    [Show full text]