UP | HOME

Basic object model in Scheme revisited

Table of Contents

% Latex Preamble definitions here (mostly usepackage)
\usepackage%
%[dvipsnames]
{xcolor}
% make sure this is before the loading font packages
\newcommand\hmmax{0}
\newcommand\bmmax{0}
\usepackage{amssymb}
\usepackage{amsmath}
\usepackage{mathtools}
\usepackage
%[dvipsnames]
{graphicx}
\usepackage{float}
%\usepackage[numbers]{natbib}
\usepackage[document]{ragged2e}
%
% enumitem doesn't seem to work with beamer
%\usepackage[inline]{enumitem}
\usepackage{wrapfig}
\usepackage{stackrel}
% extensible arrows
\usepackage{extpfeil}
% \usepackage{trfrac}
\usepackage{amsthm}
\usepackage{tikz}
\usepackage{tikz-cd}
\usepackage{tikz}
\usepackage{tikz-qtree}
\usetikzlibrary{automata, positioning, arrows, shapes.geometric}
\usepackage{turnstile}
\usepackage{comment}
%https://tex.stackexchange.com/questions/21334/is-there-a-package-that-has-the-clockwise-gapped-circle-arrow-in-it
% \usepackage{mathbx}
\usepackage{datetime}
\usepackage{datetime2}

%% Also See
%% http://u.cs.biu.ac.il/~tsaban/Pdf/LaTeXCommonErrs.pdf
%% for general tips
\usepackage{listings}
\usepackage{subfigure}
\usepackage{bm}
\usepackage{amsfonts} %% - also included by amssymb
\usepackage{mathpazo} %% - because the OP uses mathpazo, optional
%\usepackage{tufte-latex}
\usepackage{comment}
\usepackage{mathtools}
\usepackage{bussproofs}
\usepackage{hyperref}
%\usepackage{cleveref}
%% Your math definitions here
% \newcommand{\alphaequiv}{{\underset{\raise 0.7em\alpha}{=}}}
\newcommand{\yields}{\Rightarrow}
\newcommand{\derives}{\overset{*}{\yields}}
\newcommand{\alphaequiv}{=_{\alpha}}
\newcommand{\tto}[2]{{\overset{#1}{\underset{#2}{\longrightarrow}}}}
\newcommand{\transitsto}[2]{{\overset{#1}{\underset{#2}{\longrightarrow}}}}
\newcommand{\xtransitsto}[2]{{\underset{#2}{\xrightarrow{#1}}}}
\newcommand{\xtransitsfrom}[2]{{\underset{#2}{\xleftarrow{#1}}}}
\newcommand{\xto}[2]{{\xtransitsto{#1}{#2}}}
\newcommand{\xfrom}[2]{{\xtransitsfrom{#1}{#2}}}
\newcommand{\xreaches}[2]{{\underset{#2}{\xtwoheadrightarrow{#1}}}}
\newcommand{\reaches}[2]{{\underset{#2}{\xtwoheadrightarrow{#1}}}}
%\newcommand{\reaches}[2]{{\overset{#1}{\underset{#2}{\twoheadrightarrow}}}}
%\newcommand{\goesto}[2]{\transitsto{#1}{#2}}
%\newcommand{\betareducesto}{{\underset{\beta}{\rightarrow}}}
\newcommand{\betareducesto}{\rightarrow_{\beta}}
%\newcommand{\etareducesto}{{\underset{\eta}{\rightarrow}}}
\newcommand{\etareducesto}{\rightarrow_{\eta}}
%\newcommand{\betaetareducesto}{{\underset{\beta\ \eta}{\rightarrow}}}
\newcommand{\betaetareducesto}{\rightarrow_{\beta\eta}}
\newcommand{\preducesto}{\rhd}
\newcommand{\psimplifiesto}{\stackrel{\scriptstyle{*}}{\rhd}}
\newcommand{\lreducesto}{\rightsquigarrow}
\newcommand{\lsimplifiesto}{\stackrel{\scriptstyle{*}}{\lreducesto}}
\newcommand{\rewritesto}{\hookrightarrow}
\newcommand{\goesto}[1]{\stackrel{#1}{\rightarrow}}
\newcommand{\xgoesto}[1]{\xrightarrow{#1}}
\newcommand{\reducesto}{\stackrel{}{\rightarrow}}
\newcommand{\simplifiesto}{\stackrel{\scriptstyle{*}}{\rightarrow}}
\newcommand{\connected}[1]{\stackrel{#1}{\leftrightarrow}}
\newcommand{\joins}{\downarrow}
\newcommand{\evaluatesto}{\Longrightarrow}
%\newcommand{\lit}[1]{\hbox{\sf{#1}}}
\newcommand{\lit}[1]{{\sf{#1}}}
\newcommand{\true}{\lit{true}}
\newcommand{\false}{\lit{false}}
\def\Z{\mbox{${\mathbb Z}$}}
\def\N{\mbox{${\mathbb N}$}}
\def\P{\mbox{${\mathbb P}$}}
\def\R{\mbox{${\mathbb R}$}}
\def\T{\mbox{${\mathbb T}$}}
\newcommand{\Rp}{{\mathbb{R}}^+}
\def\Bool{\mbox{${\mathbb B}$}}
\def\Q{\mbox{${\mathbb Q}$}}
\def\sA{\mbox{${\cal A}$}}
\def\sB{\mbox{${\cal B}$}}
\def\sC{\mbox{${\cal C}$}}
\def\sD{\mbox{${\cal D}$}}
\def\sF{\mbox{${\cal F}$}}
\def\sG{\mbox{${\cal G}$}}
\def\sL{\mbox{${\cal L}$}}
\def\sP{\mbox{${\cal P}$}}
\def\sM{\mbox{${\cal M}$}}
\def\sN{\mbox{${\cal N}$}}
\def\sR{\mbox{${\cal R}$}}
\def\sS{\mbox{${\cal S}$}}
\def\sO{\mbox{${\cal O}$}}
\def\sT{\mbox{${\cal T}$}}
\def\sU{\mbox{${\cal U}$}}
\def\th{\mbox{$\widetilde{h}$}}
\def\tg{\mbox{$\widetilde{g}$}}
\def\tP{\mbox{$\widetilde{P}$}}
\def\norm{\mbox{$\parallel$}}
\def\osum{${{\bigcirc}}\!\!\!\!{\rm s}~$}
\def\pf{\noindent {\bf Proof}~~}
\def\exec{\mathit{exec}}
\def\Act{\mathit{A\!ct}}
\def\Traces{\mathit{Traces}}
\def\Spec{\mathit{Spec}}
\def\uns{\mathit{unless}}
\def\ens{\mathit{ensures}}
\def\lto{\mathit{leads\!\!-\!\!to}}
\def\a{\alpha}
\def\b{\beta}
\def\c{\gamma}
\def\d{\delta}
\def\sP{\mbox{${\cal P}$}}
\def\sM{\mbox{${\cal M}$}}
\def\sA{\mbox{${\cal A}$}}
\def\sB{\mbox{${\cal B}$}}
\def\sC{\mbox{${\cal C}$}}
\def\sI{\mbox{${\cal I}$}}
\def\sS{\mbox{${\cal S}$}}
\def\sD{\mbox{${\cal D}$}}
\def\sF{\mbox{${\cal F}$}}
\def\sG{\mbox{${\cal G}$}}
\def\sR{\mbox{${\cal R}$}}
\def\tg{\mbox{$\widetilde{g}$}}
\def\ta{\mbox{$\widetilde{a}$}}
\def\tb{\mbox{$\widetilde{b}$}}
\def\tc{\mbox{$\widetilde{c}$}}
\def\tx{\mbox{$\widetilde{x}$}}
\def\ty{\mbox{$\widetilde{y}$}}
\def\tz{\mbox{$\widetilde{z}$}}
\def\tI{\mbox{$\widetilde{I}$}}
\def\norm{\mbox{$\parallel$}}
\def\sL{\mbox{${\cal L}$}}
\def\sM{\mbox{${\cal M}$}}
\def\sN{\mbox{${\cal N}$}}
\def\th{\mbox{$\widetilde{h}$}}
\def\tg{\mbox{$\widetilde{g}$}}
\def\tP{\mbox{$\widetilde{P}$}}
\def\norm{\mbox{$\parallel$}}
\def\to{\rightarrow}
\def\ov{\overline}
\def\gets{\leftarrow}
\def\too{\longrightarrow}
\def\To{\Rightarrow}
%\def\points{\mapsto}
%\def\yields{\mapsto^{*}}
\def\un{\underline}
\def\vep{$\varepsilon$}
\def\ep{$\epsilon$}
\def\tri{$\bigtriangleup$}
\def\Fi{$F^{\infty}$}
\def\Di{\Delta^{\infty}}
\def\ebox\Box
\def\emp{\emptyset}
\def\leadsto{\rightharpoondown^{*}}

\newcommand{\benum}{\begin{enumerate}}
\newcommand{\eenum}{\end{enumerate}}
\newcommand{\bdes}{\begin{description}}
\newcommand{\edes}{\end{description}}
\newcommand{\bt}{\begin{theorem}}
\newcommand{\et}{\end{theorem}}
\newcommand{\bl}{\begin{lemma}}
\newcommand{\el}{\end{lemma}}
% \newcommand{\bp}{\begin{prop}}
% \newcommand{\ep}{\end{prop}}
\newcommand{\bd}{\begin{defn}}
\newcommand{\ed}{\end{defn}}
\newcommand{\brem}{\begin{remark}}
\newcommand{\erem}{\end{remark}}
\newcommand{\bxr}{\begin{exercise}}
\newcommand{\exr}{\end{exercise}}
\newcommand{\bxm}{\begin{example}}
\newcommand{\exm}{\end{example}}
\newcommand{\beqa}{\begin{eqnarray*}}
\newcommand{\eeqa}{\end{eqnarray*}}
\newcommand{\bc}{\begin{center}}
\newcommand{\ec}{\end{center}}
\newcommand{\bcent}{\begin{center}}
\newcommand{\ecent}{\end{center}}
% \newcommand{\la}{\langle}
% \newcommand{\ra}{\rangle}
\newcommand{\bcor}{\begin{corollary}}
\newcommand{\ecor}{\end{corollary}}
\newcommand{\bds}{\begin{defns}}
\newcommand{\eds}{\end{defns}}
\newcommand{\brems}{\begin{remarks}}
\newcommand{\erems}{\end{remarks}}
\newcommand{\bxrs}{\begin{exercises}}
\newcommand{\exrs}{\end{exercises}}
\newcommand{\bxms}{\begin{examples}}
\newcommand{\exms}{\end{examples}}
\newcommand{\bfig}{\begin{figure}}
\newcommand{\efig}{\end{figure}}
\newcommand{\set}[1]{\{#1\}}
\newcommand{\pair}[1]{\langle #1\rangle}
\newcommand{\tuple}[1]{\langle #1\rangle}
\newcommand{\size}[1]{| #1 |}
\newcommand{\union}{\cup}
\newcommand{\Union}{\bigcup}
\newcommand{\intersection}{\cap}
\newcommand{\Intersection}{\bigcap}
\newcommand{\B}{\textbf{B}}
%\newcommand{\be}[2]{\begin{equation} \label{#1} \tag{#2} \end{equation}}
\newcommand{\abs}[1]{{\lvert}#1{\rvert}}
\newcommand{\id}[1]{\mathit{#1}}
\newcommand{\pfun}{\rightharpoonup}
\newcommand{\ra}[1]{\kern-1.5ex\xrightarrow{\ \ #1\ \ }\phantom{}\kern-1.5ex}
\newcommand{\ras}[1]{\kern-1.5ex\xrightarrow{\ \ \smash{#1}\ \ }\phantom{}\kern-1.5ex}
\newcommand{\da}[1]{\bigg\downarrow\raise.5ex\rlap{\scriptstyle#1}}
\newcommand{\ua}[1]{\bigg\uparrow\raise.5ex\rlap{\scriptstyle#1}}
% \newcommand{\lift}[1]{#1_{\bot}}
\newcommand{\signal}[1]{\tilde{#1}}
\newcommand{\ida}{\stackrel{{\sf def}}{=}}
\newcommand{\eqn}{\doteq}
\newcommand{\deduce}[1]{\sststile{#1}{}}

%% These don't sit very well with MathJax
%% so we don't plan to use theorem like environments
%% in org documents.
%% instead we plan to use headings with
%%  1. property drawers with a CLASS property identifying
%%  the environment
%%  2. A tag with the same name as the CLASS property
%%  In LaTeX export, these turn into (sub)sections.


%% See http://u.cs.biu.ac.il/~tsaban/Pdf/LaTeXCommonErrs.pdf
%% \newtheorem{prop}[thm]{Proposition}
%% \theoremstyle{plain}%default
%% \newtheorem{theorem}{Theorem}[section]
%% \newtheorem{lemma}{Lemma}[section]
%% \newtheorem{corollary}{Corollary}[section]
%% \newtheorem{definition}{Definition}[section]
%% \newtheorem{remark}{Remark}[section]
%% \newtheorem{example}{Example}[section]
%% \newtheorem{exercise}{Exercise}[section]



\newcommand{\less}[1]{#1_{<}}
\newcommand{\pfn}{\rightharpoonup}
\newcommand{\ffn}{\stackrel{{\sf fin}}{\rightharpoonup}}
\newcommand{\stkout}[1]{\ifmmode\text{\sout{\ensuremath{#1}}}\else\sout{#1}\fi}

% Caution: Not supported by MathJax!
% ----------------------------------
% \DeclareMathSymbol{\shortminus}{\mathbin}{AMSa}{"39}


% \usepackage{amsfonts} %% <- also included by amssymb
% \DeclareMathSymbol{\shortminus}{\mathbin}{AMSa}{"39}
\usepackage{mathpazo} %% <- because the OP uses mathpazo, optional



\newcommand{\mbf}[1]{\mathbf{#1}}

\newcommand{\floor}[1]{\left\lfloor #1 \right\rfloor}
\newcommand{\ceil}[1]{\left\lceil #1 \right\rceil}
\newcommand{\rel}{\twoheadrightarrow}
\newcommand{\map}{\rightarrow}

%\newcommand{\fixed}{\boldsymbol{\circlearrowleft}}
\newcommand{\terminal}{\not\xto{}{}}
\newcommand{\fixed}{\bm\circlearrowleft}

\newcommand{\imp}{\rightarrow}
\newcommand{\dimp}{\leftrightarrow}  % double implication
\newcommand{\lequiv}{\Longleftrightarrow} % logical equivalence
\newcommand{\limplies}{\Rightarrow}
\newcommand{\lxor}{\veebar}

1 Introduction

In anticipation of the Javascript model, we refine our basic model of objects in Scheme. The main refinement is the definition of a new primitive to define objects, called make-basic-object which provides a more flexible way of creating objects.

2 Immutable fields

In the refined object model, certain fields are immutable. The set of immutable fields is fixed.

immutable-field? determines which fields are immutable. In the present implementation they are owns?, which determines whether a field is owned by an object, and closure which is a field in Javascript function objects.

;;; immutable-field? : symbol? -> boolean?
  (define  (immutable-field?  x)
    (memq x '(owns? closure)))

3 Identifying objects as procedures

Objects are represented as procedures.

(define obj? procedure?)

4 Error object

error-obj raises an error in response to any message it receives.

(define error-obj 
  (lambda (msg . args)
    (error 'error-obj "no field ~a" msg)))

5 Setters, Getters and Checkers

The fundamental data structure underlying an object is a hashtable (or an environment whose entities are mutable).

The three functions below implement basic operations on a hash-table functions for a hash-table:

(define (make-setter h)
  (lambda (x v)
    (hash-set! h x v)))

(define (make-getter h parent)
  (lambda (x)
    (hash-ref h x  (lambda () (parent x)))))

(define (make-checker h)
  (lambda (x)
    (hash-has-key? h x)))

6 The basic-make-obj function

Let o be an object. The parent of o is an object p consulted during the lookup of a field f not owned by o.

The basic-make-obj function takes a parent, and hash table binds that holds bindings, and a thunk init. It builds a simple object with a message interface, populates the object with an owns? method, and then further initialises the object with init before returning it.

The main difference between the earlier make-obj and basic-make-obj is presence of a hash table as a parameter. This is necessary so that certain updates on the hash table may happen from within, e.g., during the installation of the closure and owns? fields. (See the implementations of make-obj based on basic-make-obj in the next section.)

(define basic-make-obj
  (lambda (parent binds init)
    (let ([set (make-setter binds)]
	  [get (make-getter binds parent)]
	  [chk (make-checker binds)])
      (let ([o 
	      (lambda msg
		(match msg
		  [(list (? symbol? x)) (get x)]
		  [(list (? symbol? x) v)
		   (if (immutable-field? x)
		     (error 'make-obj "field not mutable ~a" x)
		     (set x v))]
		  [else (error 'make-obj  
			 "invalid object lookup syntax ~a" msg)]))])
	(let ([owns? (lambda (this x) (chk x))])
	  (set 'owns? owns?)
	  (init)
	  o)))))

7 Constructing objects using make-obj

make-obj creates an object with a parent. The default parent is error-obj. An object with error-obj as parent is called a ground object.

(define (select/default thing default)
  (if (null? thing) 
    default
    (first thing)))

(define make-obj
  (lambda parent   ;; '() or a singleton list.
    (let ([parent (select/default parent error-obj)])
      (let ([binds (make-hash)])
	(basic-make-obj parent binds void)))))

Note that void is the Scheme function that takes nothing and returns nothing.

8 Method calls

We have learned earlier that a method is a function that takes an object and additional arguments. A method may be installed as a field of an object. A method call with name method-name in the context of an object a first locates method against method-name in a. Then it invokes method with a and any additional arguments args.

(define call
  (lambda (a method-name . args)
    (let ([method (a method-name)])
      (apply method (cons a args)))))

9 Literal objects

obj takes a list of bindings and builds a ground object:

(define obj
  (lambda binds
    (let ([a (make-obj)])
      (for-each (lambda (bind)
		  (a (first bind) (second bind)))
	binds)
      a)))

10 Unit tests

(require rackunit)
(require rackunit/text-ui)

(define (check-err thunk)
  (check-exn exn:fail? thunk))

(define check-eq check-eq?)

(define literal-tc
  (test-case 
   "literals and owns?"
   (let ()
     (define a (obj '(x 3)))
     (define b (make-obj a))
     (check-eq       (a 'x) 3)
     (check-err      (lambda () (a 'y)))
     (check-true     (call a 'owns? 'x))
     (check-false    (call a 'owns? 'y))
     (b 'y 5)
     (check-eq       (b 'y) 5)
     (check-eq       (b 'x) 3)
     (check-false    (call b 'owns? 'x))

     ;;; error trying to set owns? field

     (check-err (lambda () (b 'owns? 9)))
     (check-err (lambda () (b 'closure 0)))
     )))

11 Source code

./obj.rkt
Implementation of Scheme objects using the basic-make-obj mechanism.

Author: choppell

Created: 2023-11-25 Sat 09:15

Validate