Index: doc/papers/general/Paper.tex
===================================================================
--- doc/papers/general/Paper.tex	(revision 14a3dad2e0f2e2f5519af8bee19bdacdbf8b5091)
+++ doc/papers/general/Paper.tex	(revision 6dba9f99298d009feb56392f7ccd516f29ca2e4f)
@@ -451,7 +451,7 @@
 };
 forall( otype T ) T value( pair( const char *, T ) p ) { return p.second; } $\C{// dynamic}$
-forall( dtype F, otype T ) T value( pair( F *, T * ) p ) { return *p.second; } $\C{// concrete}$
-
-pair( const char *, int ) p = { "magic", 42 }; $\C{// dynamic}$
+forall( dtype F, otype T ) T value( pair( F *, T * ) p ) { return *p.second; } $\C{// dtype-static (concrete)}$
+
+pair( const char *, int ) p = { "magic", 42 }; $\C{// concrete}$
 int i = value( p );
 pair( void *, int * ) q = { 0, &p.second }; $\C{// concrete}$
@@ -464,6 +464,6 @@
 \CFA classifies generic types as either \newterm{concrete} or \newterm{dynamic}.
 Concrete types have a fixed memory layout regardless of type parameters, while dynamic types vary in memory layout depending on their type parameters.
-A type may have polymorphic parameters but still be concrete, called \newterm{dtype-static}.
-Polymorphic pointers are an example of dtype-static, \eg @forall(dtype T) T *@ is a polymorphic type, but for any @T@, @T *@  is a fixed-sized pointer, and therefore, can be represented by a @void *@ in code generation.
+A \newterm{dtype-static} type has polymorphic parameters but is still concrete.
+Polymorphic pointers are an example of dtype-static types, \eg @forall(dtype T) T *@ is a polymorphic type, but for any @T@, @T *@  is a fixed-sized pointer, and therefore, can be represented by a @void *@ in code generation.
 
 \CFA generic types also allow checked argument-constraints.
@@ -507,7 +507,14 @@
 The offset arrays are statically generated where possible.
 If a dynamic generic-type is declared to be passed or returned by value from a polymorphic function, the translator can safely assume the generic type is complete (\ie has a known layout) at any call-site, and the offset array is passed from the caller;
-if the generic type is concrete at the call site, the elements of this offset array can even be statically generated using the C @offsetof@ macro.
-As an example, @p.second@ in the @value@ function above is implemented as @*(p + _offsetof_pair[1])@, where @p@ is a @void *@, and @_offsetof_pair@ is the offset array passed into @value@ for @pair( const char *, T )@.
-The offset array @_offsetof_pair@ is generated at the call site as @size_t _offsetof_pair[] = { offsetof(_pair_conc0, first), offsetof(_pair_conc0, second) }@.
+if the generic type is concrete at the call site, the elements of this offset array can even be statically generated using the C @offsetof@ macro. 
+As an example, the body of the second @value@ function is implemented like this:
+\begin{cfa}
+_assign_T(_retval, p + _offsetof_pair[1]); $\C{// return *p.second}$
+\end{cfa}
+@_assign_T@ is passed in as an implicit parameter from @otype T@, and takes two @T*@ (@void*@ in the generated code), a destination and a source; @_retval@ is the pointer to a caller-allocated buffer for the return value, the usual \CFA method to handle dynamically-sized return types.
+@_offsetof_pair@ is the offset array passed into @value@; this array is generated at the call site as:
+\begin{cfa}
+size_t _offsetof_pair[] = { offsetof(_pair_conc0, first), offsetof(_pair_conc0, second) }
+\end{cfa}
 
 In some cases the offset arrays cannot be statically generated.
