| 1 | % take of review (for line numbers) and anonymous (for anonymization) on submission
|
|---|
| 2 | \documentclass[format=acmlarge, anonymous, review]{acmart}
|
|---|
| 3 |
|
|---|
| 4 | \usepackage{listings} % For code listings
|
|---|
| 5 |
|
|---|
| 6 | % Useful macros
|
|---|
| 7 | \newcommand{\CFA}{C$\mathbf\forall$} % Cforall symbolic name
|
|---|
| 8 | \newcommand{\CC}{\rm C\kern-.1em\hbox{+\kern-.25em+}} % C++ symbolic name
|
|---|
| 9 | \newcommand{\CCeleven}{\rm C\kern-.1em\hbox{+\kern-.25em+}11} % C++11 symbolic name
|
|---|
| 10 | \newcommand{\CCfourteen}{\rm C\kern-.1em\hbox{+\kern-.25em+}14} % C++14 symbolic name
|
|---|
| 11 | \newcommand{\CCseventeen}{\rm C\kern-.1em\hbox{+\kern-.25em+}17} % C++17 symbolic name
|
|---|
| 12 |
|
|---|
| 13 | \newcommand{\TODO}{\textbf{TODO}}
|
|---|
| 14 | \newcommand{\eg}{\textit{e}.\textit{g}.}
|
|---|
| 15 | \newcommand{\ie}{\textit{i}.\textit{e}.}
|
|---|
| 16 | \newcommand{\etc}{\textit{etc}.}
|
|---|
| 17 |
|
|---|
| 18 | % CFA programming language, based on ANSI C (with some gcc additions)
|
|---|
| 19 | \lstdefinelanguage{CFA}[ANSI]{C}{
|
|---|
| 20 | morekeywords={_Alignas,_Alignof,__alignof,__alignof__,asm,__asm,__asm__,_At,_Atomic,__attribute,__attribute__,auto,
|
|---|
| 21 | _Bool,catch,catchResume,choose,_Complex,__complex,__complex__,__const,__const__,disable,dtype,enable,__extension__,
|
|---|
| 22 | fallthrough,fallthru,finally,forall,ftype,_Generic,_Imaginary,inline,__label__,lvalue,_Noreturn,one_t,otype,restrict,sized,_Static_assert,
|
|---|
| 23 | _Thread_local,throw,throwResume,trait,try,typeof,__typeof,__typeof__,zero_t},
|
|---|
| 24 | }%
|
|---|
| 25 |
|
|---|
| 26 | \lstset{
|
|---|
| 27 | language=CFA,
|
|---|
| 28 | columns=fullflexible,
|
|---|
| 29 | basicstyle=\linespread{0.9}\sf, % reduce line spacing and use sanserif font
|
|---|
| 30 | stringstyle=\tt, % use typewriter font
|
|---|
| 31 | tabsize=4, % 4 space tabbing
|
|---|
| 32 | xleftmargin=\parindent, % indent code to paragraph indentation
|
|---|
| 33 | % extendedchars=true, % allow ASCII characters in the range 128-255
|
|---|
| 34 | % escapechar=§, % LaTeX escape in CFA code §...§ (section symbol), emacs: C-q M-'
|
|---|
| 35 | mathescape=true, % LaTeX math escape in CFA code $...$
|
|---|
| 36 | keepspaces=true, %
|
|---|
| 37 | showstringspaces=false, % do not show spaces with cup
|
|---|
| 38 | showlines=true, % show blank lines at end of code
|
|---|
| 39 | aboveskip=4pt, % spacing above/below code block
|
|---|
| 40 | belowskip=3pt,
|
|---|
| 41 | % replace/adjust listing characters that look bad in sanserif
|
|---|
| 42 | literate={-}{\raisebox{-0.15ex}{\texttt{-}}}1 {^}{\raisebox{0.6ex}{$\scriptscriptstyle\land\,$}}1
|
|---|
| 43 | {~}{\raisebox{0.3ex}{$\scriptstyle\sim\,$}}1 {_}{\makebox[1.2ex][c]{\rule{1ex}{0.1ex}}}1 {`}{\ttfamily\upshape\hspace*{-0.1ex}`}1
|
|---|
| 44 | {<-}{$\leftarrow$}2 {=>}{$\Rightarrow$}2 {->}{$\rightarrow$}2,
|
|---|
| 45 | % moredelim=**[is][\color{red}]{®}{®}, % red highlighting ®...® (registered trademark symbol) emacs: C-q M-.
|
|---|
| 46 | % moredelim=**[is][\color{blue}]{ß}{ß}, % blue highlighting ß...ß (sharp s symbol) emacs: C-q M-_
|
|---|
| 47 | % moredelim=**[is][\color{OliveGreen}]{¢}{¢}, % green highlighting ¢...¢ (cent symbol) emacs: C-q M-"
|
|---|
| 48 | % moredelim=[is][\lstset{keywords={}}]{¶}{¶}, % keyword escape ¶...¶ (pilcrow symbol) emacs: C-q M-^
|
|---|
| 49 | }% lstset
|
|---|
| 50 |
|
|---|
| 51 | % inline code @...@
|
|---|
| 52 | \lstMakeShortInline@
|
|---|
| 53 |
|
|---|
| 54 | % ACM Information
|
|---|
| 55 | \citestyle{acmauthoryear}
|
|---|
| 56 |
|
|---|
| 57 | \acmJournal{PACMPL}
|
|---|
| 58 |
|
|---|
| 59 | \title{Generic and Tuple Types with Efficient Dynamic Layout in \CFA{}}
|
|---|
| 60 |
|
|---|
| 61 | \author{Aaron Moss}
|
|---|
| 62 | \affiliation{%
|
|---|
| 63 | \institution{University of Waterloo}
|
|---|
| 64 | \department{David R. Cheriton School of Computer Science}
|
|---|
| 65 | \streetaddress{Davis Centre, University of Waterloo}
|
|---|
| 66 | \city{Waterloo}
|
|---|
| 67 | \state{ON}
|
|---|
| 68 | \postcode{N2L 3G1}
|
|---|
| 69 | \country{Canada}
|
|---|
| 70 | }
|
|---|
| 71 | \email{a3moss@uwaterloo.ca}
|
|---|
| 72 |
|
|---|
| 73 | \author{Robert Schluntz}
|
|---|
| 74 | \affiliation{%
|
|---|
| 75 | \institution{University of Waterloo}
|
|---|
| 76 | \department{David R. Cheriton School of Computer Science}
|
|---|
| 77 | \streetaddress{Davis Centre, University of Waterloo}
|
|---|
| 78 | \city{Waterloo}
|
|---|
| 79 | \state{ON}
|
|---|
| 80 | \postcode{N2L 3G1}
|
|---|
| 81 | \country{Canada}
|
|---|
| 82 | }
|
|---|
| 83 | \email{rschlunt@uwaterloo.ca}
|
|---|
| 84 |
|
|---|
| 85 | \author{Peter Buhr}
|
|---|
| 86 | \affiliation{%
|
|---|
| 87 | \institution{University of Waterloo}
|
|---|
| 88 | \department{David R. Cheriton School of Computer Science}
|
|---|
| 89 | \streetaddress{Davis Centre, University of Waterloo}
|
|---|
| 90 | \city{Waterloo}
|
|---|
| 91 | \state{ON}
|
|---|
| 92 | \postcode{N2L 3G1}
|
|---|
| 93 | \country{Canada}
|
|---|
| 94 | }
|
|---|
| 95 | \email{pabuhr@uwaterloo.ca}
|
|---|
| 96 |
|
|---|
| 97 | \terms{generic, tuple, types}
|
|---|
| 98 | \keywords{generic types, tuple types, polymorphic functions, C, Cforall}
|
|---|
| 99 |
|
|---|
| 100 | \begin{CCSXML}
|
|---|
| 101 | <ccs2012>
|
|---|
| 102 | <concept>
|
|---|
| 103 | <concept_id>10011007.10011006.10011008.10011024.10011025</concept_id>
|
|---|
| 104 | <concept_desc>Software and its engineering~Polymorphism</concept_desc>
|
|---|
| 105 | <concept_significance>500</concept_significance>
|
|---|
| 106 | </concept>
|
|---|
| 107 | <concept>
|
|---|
| 108 | <concept_id>10011007.10011006.10011008.10011024.10011028</concept_id>
|
|---|
| 109 | <concept_desc>Software and its engineering~Data types and structures</concept_desc>
|
|---|
| 110 | <concept_significance>500</concept_significance>
|
|---|
| 111 | </concept>
|
|---|
| 112 | <concept>
|
|---|
| 113 | <concept_id>10011007.10011006.10011041.10011047</concept_id>
|
|---|
| 114 | <concept_desc>Software and its engineering~Source code generation</concept_desc>
|
|---|
| 115 | <concept_significance>300</concept_significance>
|
|---|
| 116 | </concept>
|
|---|
| 117 | </ccs2012>
|
|---|
| 118 | \end{CCSXML}
|
|---|
| 119 |
|
|---|
| 120 | \ccsdesc[500]{Software and its engineering~Polymorphism}
|
|---|
| 121 | \ccsdesc[500]{Software and its engineering~Data types and structures}
|
|---|
| 122 | \ccsdesc[300]{Software and its engineering~Source code generation}
|
|---|
| 123 |
|
|---|
| 124 | \begin{abstract}
|
|---|
| 125 | \TODO{} Write abstract.
|
|---|
| 126 | \end{abstract}
|
|---|
| 127 |
|
|---|
| 128 | \begin{document}
|
|---|
| 129 |
|
|---|
| 130 | \maketitle
|
|---|
| 131 |
|
|---|
| 132 | \section{Introduction \& Background}
|
|---|
| 133 |
|
|---|
| 134 | \CFA{}\footnote{Pronounced ``C-for-all'', and written \CFA{} or Cforall.} is an evolutionary extension of the C programming language which aims to add modern language features to C while maintaining both source compatibility with C and a familiar mental model for programmers. Four key design goals were set out in the original design of \CFA{} \citep{Bilson03}:
|
|---|
| 135 | \begin{enumerate}
|
|---|
| 136 | \item The behaviour of standard C code must remain the same when translated by a \CFA{} compiler as when translated by a C compiler.
|
|---|
| 137 | \item Standard C code must be as fast and as small when translated by a \CFA{} compiler as when translated by a C compiler.
|
|---|
| 138 | \item \CFA{} code must be at least as portable as standard C code.
|
|---|
| 139 | \item Extensions introduced by \CFA{} must be translated in the most efficient way possible.
|
|---|
| 140 | \end{enumerate}
|
|---|
| 141 | The purpose of these goals is to ensure that existing C codebases can be converted to \CFA{} incrementally and with minimal effort, and that programmers who already know C can productively produce \CFA{} code without extensive training beyond the extension features they wish to employ.
|
|---|
| 142 |
|
|---|
| 143 | \CFA{} has been previously extended with polymorphic functions and name overloading (including operator overloading) \citep{Bilson03}, and deterministically-executed constructors and destructors \citep{Schluntz17}. This paper describes how generic and tuple types are designed and implemented in \CFA{} in accordance with both the backward compatibility goals and existing features described above.
|
|---|
| 144 |
|
|---|
| 145 | \subsection{Polymorphic Functions}
|
|---|
| 146 | \label{sec:poly-fns}
|
|---|
| 147 |
|
|---|
| 148 | \CFA{}'s polymorphism was originally formalized by \citet{Ditchfield92}, and first implemented by \citet{Bilson03}. The signature feature of \CFA{} is parametric-polymorphic functions; such functions are written using a @forall@ clause (which gives the language its name):
|
|---|
| 149 | \begin{lstlisting}
|
|---|
| 150 | forall(otype T)
|
|---|
| 151 | T identity(T x) {
|
|---|
| 152 | return x;
|
|---|
| 153 | }
|
|---|
| 154 |
|
|---|
| 155 | int forty_two = identity(42); // T is bound to int, forty_two == 42
|
|---|
| 156 | \end{lstlisting}
|
|---|
| 157 | The @identity@ function above can be applied to any complete object type (or ``@otype@''). The type variable @T@ is transformed into a set of additional implicit parameters to @identity@, which encode sufficient information about @T@ to create and return a variable of that type. The \CFA{} implementation passes the size and alignment of the type represented by an @otype@ parameter, as well as an assignment operator, constructor, copy constructor and destructor. If this extra information is not needed, the type parameter can be declared as @dtype T@, where @dtype@ is short for ``data type''.
|
|---|
| 158 |
|
|---|
| 159 | Here, the runtime cost of polymorphism is spread over each polymorphic call, due to passing more arguments to polymorphic functions; preliminary experiments have shown this overhead to be similar to \CC{} virtual function calls. An advantage of this design is that, unlike \CC{} template functions, \CFA{} @forall@ functions are compatible with separate compilation.
|
|---|
| 160 |
|
|---|
| 161 | Since bare polymorphic types do not provide a great range of available operations, \CFA{} provides a \emph{type assertion} mechanism to provide further information about a type:
|
|---|
| 162 | \begin{lstlisting}
|
|---|
| 163 | forall(otype T | { T twice(T); })
|
|---|
| 164 | T four_times(T x) {
|
|---|
| 165 | return twice( twice(x) );
|
|---|
| 166 | }
|
|---|
| 167 |
|
|---|
| 168 | double twice(double d) { return d * 2.0; } // (1)
|
|---|
| 169 |
|
|---|
| 170 | double magic = four_times(10.5); // T is bound to double, uses (1) to satisfy type assertion
|
|---|
| 171 | \end{lstlisting}
|
|---|
| 172 | These type assertions may be either variable or function declarations that depend on a polymorphic type variable. @four_times@ can only be called with an argument for which there exists a function named @twice@ that can take that argument and return another value of the same type; a pointer to the appropriate @twice@ function is passed as an additional implicit parameter to the call of @four_times@.
|
|---|
| 173 |
|
|---|
| 174 | Monomorphic specializations of polymorphic functions can themselves be used to satisfy type assertions. For instance, @twice@ could have been defined using the \CFA{} syntax for operator overloading as:
|
|---|
| 175 | \begin{lstlisting}
|
|---|
| 176 | forall(otype S | { S ?+?(S, S); })
|
|---|
| 177 | S twice(S x) { return x + x; } // (2)
|
|---|
| 178 | \end{lstlisting}
|
|---|
| 179 | This version of @twice@ works for any type @S@ that has an addition operator defined for it, and it could have been used to satisfy the type assertion on @four_times@.
|
|---|
| 180 | The compiler accomplishes this by creating a wrapper function calling @twice // (2)@ with @S@ bound to @double@, then providing this wrapper function to @four_times@\footnote{\lstinline@twice // (2)@ could also have had a type parameter named \lstinline@T@; \CFA{} specifies renaming of the type parameters, which would avoid the name conflict with the type variable \lstinline@T@ of \lstinline@four_times@.}.
|
|---|
| 181 |
|
|---|
| 182 | \subsection{Traits}
|
|---|
| 183 |
|
|---|
| 184 | \CFA{} provides \emph{traits} as a means to name a group of type assertions, as in the example below:
|
|---|
| 185 | \begin{lstlisting}
|
|---|
| 186 | trait has_magnitude(otype T) {
|
|---|
| 187 | bool ?<?(T, T); // comparison operator for T
|
|---|
| 188 | T -?(T); // negation operator for T
|
|---|
| 189 | void ?{}(T*, zero_t); // constructor from 0 literal
|
|---|
| 190 | };
|
|---|
| 191 |
|
|---|
| 192 | forall(otype M | has_magnitude(M))
|
|---|
| 193 | M abs( M m ) {
|
|---|
| 194 | M zero = { 0 }; // uses zero_t constructor from trait
|
|---|
| 195 | return m < zero ? -m : m;
|
|---|
| 196 | }
|
|---|
| 197 |
|
|---|
| 198 | forall(otype M | has_magnitude(M))
|
|---|
| 199 | M max_magnitude( M a, M b ) {
|
|---|
| 200 | return abs(a) < abs(b) ? b : a;
|
|---|
| 201 | }
|
|---|
| 202 | \end{lstlisting}
|
|---|
| 203 | This capability allows specifying the same set of assertions in multiple locations, without the repetition and likelihood of mistakes that come with manually writing them out for each function declaration.
|
|---|
| 204 |
|
|---|
| 205 | @otype@ is essentially syntactic sugar for the following trait:
|
|---|
| 206 | \begin{lstlisting}
|
|---|
| 207 | trait otype(dtype T | sized(T)) {
|
|---|
| 208 | // sized is a compiler-provided pseudo-trait for types with known size & alignment
|
|---|
| 209 | void ?{}(T*); // default constructor
|
|---|
| 210 | void ?{}(T*, T); // copy constructor
|
|---|
| 211 | void ?=?(T*, T); // assignment operator
|
|---|
| 212 | void ^?{}(T*); // destructor
|
|---|
| 213 | };
|
|---|
| 214 | \end{lstlisting}
|
|---|
| 215 | Given this information, variables of polymorphic type can be treated as if they were a complete struct type -- they can be stack-allocated using the @alloca@ compiler builtin, default or copy-initialized, assigned, and deleted. As an example, the @abs@ function above would produce generated code something like the following (simplified for clarity and brevity):
|
|---|
| 216 | \begin{lstlisting}
|
|---|
| 217 | void abs( size_t _sizeof_M, size_t _alignof_M,
|
|---|
| 218 | void (*_ctor_M)(void*), void (*_copy_M)(void*, void*),
|
|---|
| 219 | void (*_assign_M)(void*, void*), void (*_dtor_M)(void*),
|
|---|
| 220 | bool (*_lt_M)(void*, void*), void (*_neg_M)(void*, void*),
|
|---|
| 221 | void (*_ctor_M_zero)(void*, int),
|
|---|
| 222 | void* m, void* _rtn ) { // polymorphic parameter and return passed as void*
|
|---|
| 223 | // M zero = { 0 };
|
|---|
| 224 | void* zero = alloca(_sizeof_M); // stack allocate 0 temporary
|
|---|
| 225 | _ctor_M_zero(zero, 0); // initialize using zero_t constructor
|
|---|
| 226 | // return m < zero ? -m : m;
|
|---|
| 227 | void *_tmp = alloca(_sizeof_M)
|
|---|
| 228 | _copy_M( _rtn, // copy-initialize return value
|
|---|
| 229 | _lt_M( m, zero ) ? // check condition
|
|---|
| 230 | (_neg_M(m, _tmp), _tmp) : // negate m
|
|---|
| 231 | m);
|
|---|
| 232 | _dtor_M(_tmp); _dtor_M(zero); // destroy temporaries
|
|---|
| 233 | }
|
|---|
| 234 | \end{lstlisting}
|
|---|
| 235 |
|
|---|
| 236 | Semantically, traits are simply a named lists of type assertions, but they may be used for many of the same purposes that interfaces in Java or abstract base classes in \CC{} are used for. Unlike Java interfaces or \CC{} base classes, \CFA{} types do not explicitly state any inheritance relationship to traits they satisfy; this can be considered a form of structural inheritance, similar to implementation of an interface in Go, as opposed to the nominal inheritance model of Java and \CC{}. Nominal inheritance can be simulated with traits using marker variables or functions:
|
|---|
| 237 | \begin{lstlisting}
|
|---|
| 238 | trait nominal(otype T) {
|
|---|
| 239 | T is_nominal;
|
|---|
| 240 | };
|
|---|
| 241 |
|
|---|
| 242 | int is_nominal; // int now satisfies the nominal trait
|
|---|
| 243 | {
|
|---|
| 244 | char is_nominal; // char satisfies the nominal trait
|
|---|
| 245 | }
|
|---|
| 246 | // char no longer satisfies the nominal trait here
|
|---|
| 247 | \end{lstlisting}
|
|---|
| 248 |
|
|---|
| 249 | Traits, however, are significantly more powerful than nominal-inheritance interfaces; firstly, due to the scoping rules of the declarations that satisfy a trait's type assertions, a type may not satisfy a trait everywhere that the type is declared, as with @char@ and the @nominal@ trait above. Secondly, traits may be used to declare a relationship among multiple types, a property that may be difficult or impossible to represent in nominal-inheritance type systems:
|
|---|
| 250 | \begin{lstlisting}
|
|---|
| 251 | trait pointer_like(otype Ptr, otype El) {
|
|---|
| 252 | lvalue El *?(Ptr); // Ptr can be dereferenced into a modifiable value of type El
|
|---|
| 253 | }
|
|---|
| 254 |
|
|---|
| 255 | struct list {
|
|---|
| 256 | int value;
|
|---|
| 257 | list *next; // may omit "struct" on type names
|
|---|
| 258 | };
|
|---|
| 259 |
|
|---|
| 260 | typedef list *list_iterator;
|
|---|
| 261 |
|
|---|
| 262 | lvalue int *?( list_iterator it ) {
|
|---|
| 263 | return it->value;
|
|---|
| 264 | }
|
|---|
| 265 | \end{lstlisting}
|
|---|
| 266 |
|
|---|
| 267 | In the example above, @(list_iterator, int)@ satisfies @pointer_like@ by the user-defined dereference function, and @(list_iterator, list)@ also satisfies @pointer_like@ by the built-in dereference operator for pointers. Given a declaration @list_iterator it@, @*it@ can be either an @int@ or a @list@, with the meaning disambiguated by context (\eg, @int x = *it;@ interprets @*it@ as an @int@, while @(*it).value = 42;@ interprets @*it@ as a @list@).
|
|---|
| 268 | While a nominal-inheritance system with associated types could model one of those two relationships by making @El@ an associated type of @Ptr@ in the @pointer_like@ implementation, few such systems could model both relationships simultaneously.
|
|---|
| 269 |
|
|---|
| 270 | \section{Generic Types}
|
|---|
| 271 |
|
|---|
| 272 | The generic types design for \CFA{} must integrate efficiently and naturally with the existing polymorphic functions in \CFA{}, while retaining backwards compatibility with C; maintaining separate compilation is a particularly important constraint on the design. However, where the concrete parameters of the generic type are known, there should not be extra overhead for the use of a generic type.
|
|---|
| 273 |
|
|---|
| 274 | A generic type can be declared by placing a @forall@ specifier on a @struct@ or @union@ declaration, and instantiated using a parenthesized list of types after the type name:
|
|---|
| 275 | \begin{lstlisting}
|
|---|
| 276 | forall(otype R, otype S) struct pair {
|
|---|
| 277 | R first;
|
|---|
| 278 | S second;
|
|---|
| 279 | };
|
|---|
| 280 |
|
|---|
| 281 | forall(otype T)
|
|---|
| 282 | T value( pair(const char*, T) *p ) { return p->second; }
|
|---|
| 283 |
|
|---|
| 284 | forall(dtype F, otype T)
|
|---|
| 285 | T value_p( pair(F*, T*) p ) { return *p.second; }
|
|---|
| 286 |
|
|---|
| 287 | pair(const char*, int) p = { "magic", 42 };
|
|---|
| 288 | int magic = value( &p );
|
|---|
| 289 |
|
|---|
| 290 | pair(void*, int*) q = { 0, &p.second };
|
|---|
| 291 | magic = value_p( q );
|
|---|
| 292 | double d = 1.0;
|
|---|
| 293 | pair(double*, double*) r = { &d, &d };
|
|---|
| 294 | d = value_p( r );
|
|---|
| 295 | \end{lstlisting}
|
|---|
| 296 |
|
|---|
| 297 | \CFA{} classifies generic types as either \emph{concrete} or \emph{dynamic}. Dynamic generic types vary in their in-memory layout depending on their type parameters, while concrete generic types have a fixed memory layout regardless of type parameters. A type may have polymorphic parameters but still be concrete; \CFA{} refers to such types as \emph{dtype-static}. Polymorphic pointers are an example of dtype-static types -- @forall(dtype T) T*@ is a polymorphic type, but for any @T@ chosen, @T*@ will have exactly the same in-memory representation as a @void*@, and can therefore be represented by a @void*@ in code generation.
|
|---|
| 298 |
|
|---|
| 299 | The \CFA{} compiler instantiates concrete generic types by template-expanding them to fresh struct types; concrete generic types can therefore be used with zero runtime overhead. To enable interoperation between equivalent instantiations of a generic type, the compiler saves the set of instantiations currently in scope and re-uses the generated struct declarations where appropriate. As an example, the concrete instantiation for @pair(const char*, int)@ would look something like this:
|
|---|
| 300 | \begin{lstlisting}
|
|---|
| 301 | struct _pair_conc1 {
|
|---|
| 302 | const char* first;
|
|---|
| 303 | int second;
|
|---|
| 304 | };
|
|---|
| 305 | \end{lstlisting}
|
|---|
| 306 |
|
|---|
| 307 | A concrete generic type with dtype-static parameters is also expanded to a struct type, but this struct type is used for all matching instantiations. In the example above, the @pair(F*, T*)@ parameter to @value_p@ is such a type; its expansion would look something like this, and be used as the type of the variables @q@ and @r@ as well, with casts for member access where appropriate:
|
|---|
| 308 | \begin{lstlisting}
|
|---|
| 309 | struct _pair_conc0 {
|
|---|
| 310 | void* first;
|
|---|
| 311 | void* second;
|
|---|
| 312 | };
|
|---|
| 313 | \end{lstlisting}
|
|---|
| 314 |
|
|---|
| 315 | Though \CFA{} implements concrete generic types efficiently, it also has a fully-general system for computing with dynamic generic types. As mentioned in Section~\ref{sec:poly-fns}, @otype@ function parameters (in fact all @sized@ polymorphic parameters) come with implicit size and alignment parameters provided by the caller. Dynamic generic structs also come with an \emph{offset array} which contains the offsets of each member of the struct\footnote{Dynamic generic unions need no such offset array, as all members are at offset 0.}. Access to members\footnote{The \lstinline@offsetof@ macro is implmented similarly.} of a dynamic generic struct is provided by adding the corresponding member of the offset array to the struct pointer at runtime, essentially moving a compile-time offset calculation to runtime where neccessary.
|
|---|
| 316 |
|
|---|
| 317 | \TODO{} Discuss caller-provided versus callee-provided offset arrays, layout functions.
|
|---|
| 318 |
|
|---|
| 319 | Whether a type is concrete, dtype-static, or dynamic is decided based solely on the type parameters and @forall@ clause on the struct declaration. This allows opaque forward declarations of generic types like @forall(otype T) struct Box;@ -- like in C, all uses of @Box(T)@ can be in a separately compiled translation unit, and callers from other translation units will know the proper calling conventions to use. If the definition of a struct type was included in the determination of dynamic or concrete, some further types may be recognized as dtype-static (\eg, @forall(otype T) struct unique_ptr { T* p };@ does not depend on @T@ for its layout, but the existence of an @otype@ parameter means that it \emph{could}.), but preserving separate compilation (and the associated C compatibility) in this way is judged to be an appropriate trade-off.
|
|---|
| 320 |
|
|---|
| 321 | The re-use of dtype-static struct instantiations enables some useful programming patterns at zero runtime cost. The most important such pattern is using @forall(dtype T) T*@ as a type-checked replacement for @void*@, as in this example, which takes a @qsort@ or @bsearch@-compatible comparison routine and creates a similar lexicographic comparison for pairs of pointers:
|
|---|
| 322 | \begin{lstlisting}
|
|---|
| 323 | forall(dtype T)
|
|---|
| 324 | int lexcmp( pair(T*, T*)* a, pair(T*, T*)* b, int (*cmp)(T*, T*) ) {
|
|---|
| 325 | int c = cmp(a->first, b->first);
|
|---|
| 326 | if ( c == 0 ) c = cmp(a->second, b->second);
|
|---|
| 327 | return c;
|
|---|
| 328 | }
|
|---|
| 329 | \end{lstlisting}
|
|---|
| 330 | Since @pair(T*, T*)@ is a concrete type, there are no added implicit parameters to @lexcmp@, so the code generated by \CFA{} will be effectively identical to a version of this written in standard C using @void*@, yet the \CFA{} version will be type-checked to ensure that the fields of both pairs and the arguments to the comparison function match in type.
|
|---|
| 331 |
|
|---|
| 332 | Another useful pattern enabled by re-used dtype-static type instantiations is zero-cost ``tag'' structs. Sometimes a particular bit of information is only useful for type-checking, and can be omitted at runtime. Tag structs can be used to provide this information to the compiler without further runtime overhead, as in the following example:
|
|---|
| 333 | \begin{lstlisting}
|
|---|
| 334 | forall(dtype Unit) struct scalar { unsigned long value; };
|
|---|
| 335 |
|
|---|
| 336 | struct metres {};
|
|---|
| 337 | struct litres {};
|
|---|
| 338 |
|
|---|
| 339 | forall(dtype U)
|
|---|
| 340 | scalar(U) ?+?(scalar(U) a, scalar(U) b) {
|
|---|
| 341 | return (scalar(U)){ a.value + b.value };
|
|---|
| 342 | }
|
|---|
| 343 |
|
|---|
| 344 | scalar(metres) half_marathon = { 21093 };
|
|---|
| 345 | scalar(litres) swimming_pool = { 2500000 };
|
|---|
| 346 |
|
|---|
| 347 | scalar(metres) marathon = half_marathon + half_marathon;
|
|---|
| 348 | scalar(litres) two_pools = swimming_pool + swimming_pool;
|
|---|
| 349 | marathon + swimming_pool; // ERROR -- caught by compiler
|
|---|
| 350 | \end{lstlisting}
|
|---|
| 351 | @scalar@ is a dtype-static type, so all uses of it will use a single struct definition, containing only a single @unsigned long@, and can share the same implementations of common routines like @?+?@ -- these implementations may even be separately compiled, unlike \CC{} template functions. However, the \CFA{} type-checker will ensure that matching types are used by all calls to @?+?@, preventing nonsensical computations like adding the length of a marathon to the volume of an olympic pool.
|
|---|
| 352 |
|
|---|
| 353 | \section{Tuples}
|
|---|
| 354 |
|
|---|
| 355 | \TODO{} Integrate Rob's work
|
|---|
| 356 |
|
|---|
| 357 | \TODO{} Check if we actually can use ttype parameters on generic types (if they set the complete flag, it should work, or nearly so).
|
|---|
| 358 |
|
|---|
| 359 | \section{Related Work}
|
|---|
| 360 |
|
|---|
| 361 | \TODO{} Talk about \CC{}, Cyclone, maybe D, Rust, \etc{}
|
|---|
| 362 |
|
|---|
| 363 | A major difference between the approaches of \CC{} and \CFA{} to polymorphism is that the set of assumed properties for a type is \emph{explicit} in \CFA{}. One of the major limiting factors of \CC{}'s approach is that templates cannot be separately compiled. In contrast, the explicit nature of assertions allows \CFA{}'s polymorphic functions to be separately compiled.
|
|---|
| 364 |
|
|---|
| 365 | \section{Conclusion \& Future Work}
|
|---|
| 366 |
|
|---|
| 367 | \TODO{} Among future work, talk about ideas for selectively template-expanding code (on decls for specific types, or on calls for accessible decls).
|
|---|
| 368 |
|
|---|
| 369 | \bibliographystyle{ACM-Reference-Format}
|
|---|
| 370 | \bibliography{generic_types}
|
|---|
| 371 |
|
|---|
| 372 | \end{document}
|
|---|