\documentclass{article}
\usepackage{amsmath}
\usepackage{611-lecture}
\usepackage{alltt}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% CS611: Please fill in these macros as appropriate:
\lecture{35} %% Lecture number
\title{Existential types}   %% Title of lecture
\author{based on notes by H. Chao, D. Yeh, A. Montalban, Y. Zhang \\
\hfill edited by Sam Arbesman and Maksim Orlovich}  %% name of scribe
\date{11/23/05}    %% Date of lecture
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\newcommand{\mth}[1]{\ensuremath{#1}}
\newcommand{\arr}{\ensuremath{\to}}

% See 611.sty for a variety of macros that will be helpful in
% typesetting the lecture
%
% quotes can be used for typewriter font
% <> can be used for angle brackets
\def\parfun{\rightharpoonup}

\newcommand\unpack[3]{"unpack"\ #1\ "as"\ #2\ "in"\ #3}
\newcommand\pack[2]{"pack"_{#1}#2}


\begin{document}

\maketitle

\section {Modeling objects with recursive types}

With our typing model complete, we'll now begin to explore
objects and classes.  Consider the following Java
implementation of integer sets as binary search trees:

\begin{alltt}
class intset \{
    intset union(intset S) \{ ... \}
    boolean contains(int n) \{
        if (n == value) return true;
        if (n \lt value) then return (left != null) && left.contains(n);
        else return (right != null) && right.contains(n);
    \}
    int value;
    intset left,right;
\}
\end{alltt}

\noindent This code snippet is implicitly using self-reference (the values "left" and "right" are actually "this.left" and "this.right"). With recursive types and records we can
approximate this in the typed lambda calculus.
First, there is a type "intset" being declared:

\[ "intset" = \mu S.(\{ "union" : S \rightarrow S, "contains"
: "int" \rightarrow "bool", "value" : "int", "left" : S,
"right" : S \} + 1)
\]

Note that we need recursive types to represent the fact that
"union" returns an object of the same type.

And we can construct ``objects'' of this type:

\begin{alltt}
let s = inl fold\mth{_{\scriptsize\mathtt{intset}}} (rec this: \{ union : intset \mth{\rightarrow} intset, ... \}. // the unfolding of intset
    \{ union = \fn{s'} : intset. \ldots
      contains = \fn{n} : int. if n = this.value then true
          else if m \lt this.value then case this.left of
                  \fn{u}:1. false 
                  \fn{s'}:intset. ((unfold s').contains) n
                else ...
    \}
\end{alltt}

This whole expression has type "intset" and will behave
mostly like an object. There are a couple of ways in which
this falls short of what Java objects provide: first, there
is no inheritance and we'll have trouble extending this code
to support inheritance. Second, the internals of the class
are fully exposed to any other objects or functions that might
use it. We need some way of providing a restricted interface
to our objects and classes. It is this second problem we
will talk about now.

\section {Encapsulation/Information Hiding}

While we can encode objects currently, we are missing one of the key concepts
of object-oriented programming: information hiding. Information hiding is important since it both provides an abstraction barrier as well as allowing for division of labor and assignment of blame. We can indeed encode information hiding
with the use of existential types, which correspond closely to the logical
equivalent.

The idea is that we can hide part of a type $\tau$ and
replace it with a type variable $X$. We write $\exists X.\tau$
to represent this type, where $X$ may be mentioned inside
$\tau$. But because this type doesn't say what $X$ is, no
code receiving a value of this type can make use of
knowledge of the hidden part of this type.

\newcommand{\kw}[1]{\ensuremath{\mathtt{#1}}}
\newcommand{\pr}{^{\prime}}
\newcommand{\evd}{\cdot}

For example, in the "intset" example we would write a type like this:
\begin{alltt}
\mth{\exists}X. \{ union:    \mth{S \to S}
      contains: int \arr bool
      private:  X \}
\end{alltt}

We can think of
values of this type as being a kind of pair consisting of a
type and a value. That is, the pair $[\tau,v] : \exists X .
\sigma$ where $v : \sigma \lbrace \tau / X \rbrace$.  To
manipulate these values, we introduce two new
operators, "pack" (the introduction form) and "unpack" (the elimination form).

These two forms look, and type-check, as follows:

\[
\frac{\Delta; \Gamma \vdash \subst{e}{\tau}{X}:\subst{\sigma}{\tau}{X} \qquad \Delta \vdash \exists X.\sigma}
{\Delta; \Gamma \vdash \kw{pack}~_{\exists X.\sigma}[\tau,e]:\exists X.\sigma }
\]

\[
\frac{\Delta;\Gamma \vdash e:\exists X.\sigma \qquad \Delta, Y; \Gamma,
x:\subst{\sigma}{Y}{X} \vdash e\pr:\tau\pr \qquad \Delta \vdash \tau\pr \qquad Y\notin \Delta}
{\Delta; \Gamma \vdash \kw{unpack}~e~\kw{as}~[Y,x]~\kw{in}~e\pr:\tau\pr}
\]

Notice that we had to add the context $\Delta$, just as in the case of polymorphism, in order to make sure that no types refer to unbound type variables.

The following are the operational semantics for this feature:
\[
\kw{unpack}~(\kw{pack}~_{\exists X.\sigma}[\tau, v])~\kw{as}~[Y,
x]~\kw{in}~e \to e\{\tau/Y, v/x\}
\]

There are also additional evaluation contexts:
\[
  E ::= \ldots ~|~ \kw{pack}~[\tau,[\evd]] ~|~ \kw{unpack}~[\evd]~\kw{as}~[Y,x]~\kw{in}~e
\]

Here is a simple example illustrating how these new language features can be used:
\[
\begin{array}{l}
\kw{let}~p_1 = \kw{pack}_{\exists X.X * (X \to \kw{bool})}
[\kw{int}, (5, \lambda n:\kw{int}.(n=1))]~\kw{in} \\
\kw{let}~p_2 = \kw{pack}_{\exists X.X * (X \to \kw{bool})} 
[\kw{bool}, (\kw{true}, \lambda x:\kw{bool}.(n=1))]~\kw{in} \\
\kw{let}~\mathit{apply} = \fn{p:\exists X.X * (X \to \kw{bool})}\,.\,(\#2 p)(\#1 p)~\kw{in} \\
  \qquad \mathit{apply}(p_1) + \mathit{apply}(p_2) \\
\end{array}
\]

\noindent Notice that the function $\mathit{apply}$ can be applied to
both $p_1$ and $p_2$ because they have the same existential type, even
though internally their structure differs.

\section{Existential Types and Constructive Logic}
The existential types get their names partly because they correspond to inference rules of constructive logic involving the $\exists$ qualifier:

\[
\begin{array}{ccc}
\Rule{
\Delta; \Gamma \vdash \subst e\tau X: \subst\sigma\tau{X}
         & \Delta \vdash \tau :: "type"
	 & X \not\in\Delta}{
\Delta; \Gamma \vdash \kw{pack}~_{\exists X.\sigma}[\tau,e]:\exists X.\sigma }
 & \!\!\!\!
 \Leftrightarrow
 & \!\!\!\!\!\!
\Rule{\Gamma \vdash \subst{\phi}AX &
      \Gamma \vdash A\in S}{\Gamma \vdash \exists X\in S.\phi} \\
\\
\Rule{\Delta;\Gamma \vdash e:\exists X.\sigma ~~ \Delta, Y; \Gamma,
x:\subst{\sigma}{Y}{X} \vdash e\pr:\tau\pr ~~ \Delta \vdash \tau\pr ~~ Y\notin \Delta}
{\Delta; \Gamma \vdash \kw{unpack}~e~\kw{as}~[Y,x]~\kw{in}~e\pr:\tau\pr}
& \!\!\!\!
\Leftrightarrow
& \!\!\!\!\!\!
\Rule{\Gamma \vdash \exists X\!\in\!S.\phi &
      \Gamma, Y\!\in\!S,\subst \phi Y X \vdash \phi_2 &
      Y \notin FTV(\phi_2)}{\Gamma \vdash \phi\pr}
\end{array}
\]

Note that the set $S$ corresponds here to the kind "type". If there were
more kinds in the type system then the correspondence would be even
closer.

\section{Existentials and modules in ML}
There is a rough correspondence between existential types and the SML
module mechanism.  For example, the SML signature
\begin{alltt}
sig
  type T
  val toBool: T-{\char62}bool
end
\end{alltt}
Is roughly the same as $\exists X.X\to \kw{bool}$.
The $\kw{unpack}$ primitive is similar to the $\kw{open}$
operation on modules.

\end{document}
