CS558 Programming Languages

Similar documents
CS558 Programming Languages

CS558 Programming Languages

CS558 Programming Languages

CS321 Languages and Compiler Design I Winter 2012 Lecture 13

CS558 Programming Languages. Winter 2013 Lecture 3

CS321 Languages and Compiler Design I. Winter 2012 Lecture 2

Lecture Notes on Queues

CS558 Programming Languages Winter 2018 Lecture 4a. Andrew Tolmach Portland State University

Chapter 19: Program Design. Chapter 19. Program Design. Copyright 2008 W. W. Norton & Company. All rights reserved.

QUIZ. What is wrong with this code that uses default arguments?

C++ Inheritance and Encapsulation

Short Notes of CS201

The SPL Programming Language Reference Manual

CS201 - Introduction to Programming Glossary By

Today s lecture. CS 314 fall 01 C++ 1, page 1

CS558 Programming Languages

September 10,

CSE 12 Week Eight, Lecture One

Typed Racket: Racket with Static Types

The list abstract data type defined a number of operations that all list-like objects ought to implement:

CSE-505: Programming Languages. Lecture 18 Existential Types. Zach Tatlock 2016

CMSC 330: Organization of Programming Languages. Basic OCaml Modules

Fast Introduction to Object Oriented Programming and C++

CSE 374 Programming Concepts & Tools. Hal Perkins Spring 2010

CSCI-GA Scripting Languages

CS 330 Lecture 18. Symbol table. C scope rules. Declarations. Chapter 5 Louden Outline

Programming Languages and Techniques (CIS120)

Some Advanced ML Features

CPS 506 Comparative Programming Languages. Programming Language

Goals of this Lecture

OCaml Data CMSC 330: Organization of Programming Languages. User Defined Types. Variation: Shapes in Java

Data Abstraction. Hwansoo Han

Functional programming in mainstream languages. CS 3110 Lecture 26 Andrew Myers

Modular Programming. Prof. Clarkson Fall Today s music: "Giorgio By Moroder" by Daft Punk

The Typed Racket Guide

CS558 Programming Languages

Lecture 5: Methods CS2301

CMSC 132: Object-Oriented Programming II

CE221 Programming in C++ Part 2 References and Pointers, Arrays and Strings

Tokens, Expressions and Control Structures

AP Computer Science Chapter 10 Implementing and Using Classes Study Guide

CS 251 INTERMEDIATE SOFTWARE DESIGN SPRING C ++ Basics Review part 2 Auto pointer, templates, STL algorithms

1/29/2011 AUTO POINTER (AUTO_PTR) INTERMEDIATE SOFTWARE DESIGN SPRING delete ptr might not happen memory leak!

Object Oriented Modeling

Outline. Java Models for variables Types and type checking, type safety Interpretation vs. compilation. Reasoning about code. CSCI 2600 Spring

Object Oriented Programming. Solved MCQs - Part 2

MARKING KEY The University of British Columbia MARKING KEY Computer Science 260 Midterm #2 Examination 12:30 noon, Thursday, March 15, 2012

Class Information ANNOUCEMENTS

Introduce C# as Object Oriented programming language. Explain, tokens,

EMBEDDED SYSTEMS PROGRAMMING OO Basics

CS349/SE382 A1 C Programming Tutorial

Chapter 2: Java OOP I

PIC 10A Objects/Classes

CMSC 132: Object-Oriented Programming II

C++ Programming: Polymorphism

Typed Scheme: Scheme with Static Types

CMSC 330: Organization of Programming Languages

Abstract data types &

Abstract Data Types & Object-Oriented Programming

QUIZ on Ch.5. Why is it sometimes not a good idea to place the private part of the interface in a header file?

Object Oriented Design

Data Types. Every program uses data, either explicitly or implicitly to arrive at a result.

CS412/CS413. Introduction to Compilers Tim Teitelbaum. Lecture 17: Types and Type-Checking 25 Feb 08

G Programming Languages - Fall 2012

Static Semantics. Winter /3/ Hal Perkins & UW CSE I-1

Francesco Nidito. Programmazione Avanzata AA 2007/08

QUIZ Friends class Y;

CS558 Programming Languages

Instantiation of Template class

Agenda. Peer Instruction Question 1. Peer Instruction Answer 1. Peer Instruction Question 2 6/22/2011

G Programming Languages Spring 2010 Lecture 8. Robert Grimm, New York University

Operating Systems CMPSCI 377, Lec 2 Intro to C/C++ Prashant Shenoy University of Massachusetts Amherst

Princeton University Computer Science 217: Introduction to Programming Systems. Modules and Interfaces

Chapter 4 Defining Classes I

Lecture Notes on Memory Management

CA341 - Comparative Programming Languages

CS260 Intro to Java & Android 03.Java Language Basics

Chapter 2. Procedural Programming

Assignment 4: Semantics

CS 11 Ocaml track: lecture 4. Today: modules

Review of the C Programming Language for Principles of Operating Systems

CMSC 202 Section 010x Spring Justin Martineau, Tuesday 11:30am

The issues. Programming in C++ Common storage modes. Static storage in C++ Session 8 Memory Management

Types II. Hwansoo Han

However, in C we can group related variables together into something called a struct.

CS 237 Meeting 19 10/24/12

Chapter 1 Getting Started

OOPs Concepts. 1. Data Hiding 2. Encapsulation 3. Abstraction 4. Is-A Relationship 5. Method Signature 6. Polymorphism 7. Constructors 8.

CS321 Languages and Compiler Design I. Fall 2013 Week 8: Types Andrew Tolmach Portland State University

Implementing an abstract datatype. Linked lists and queues

The PCAT Programming Language Reference Manual

Review of the C Programming Language

Week 8: Operator overloading

Records. ADTs. Objects as Records. Objects as ADTs. Objects CS412/CS413. Introduction to Compilers Tim Teitelbaum. Lecture 15: Objects 25 Feb 05

Chapter 11. Categories of languages that support OOP: 1. OOP support is added to an existing language

Supporting Class / C++ Lecture Notes

CS61, Fall 2012 Section 2 Notes

Lecture 10 Notes Linked Lists

Interview Questions of C++

5) Attacker causes damage Different to gaining control. For example, the attacker might quit after gaining control.

Transcription:

CS558 Programming Languages Winter 2017 Lecture 9b Andrew Tolmach Portland State University 1994-2017

Programming in the large Language features for modularity are crucial for writing large programs Idea: related definitions can be grouped together into a named unit module, package, class, namespace, etc. defining functions, types, variables, constants, exceptions, sub-modules, etc. Often possible to export just a subset of definitions, specified by an interface, for use outside the module Uses of definitions outside the module are qualified by module name

Why use modules? Enable programmers to work on small part of a large system without understanding every detail of the whole Manage name space: avoid conflicts in the choice of top-level names Hide representation and implementation details: module internals are not visible outside the module Independent development: often, module implementations can be changed without requiring its clients to be rewritten (or, ideally, even recompiled)

Example: Java packages declares that all definitions in this file belong to package foo makes declaration visible outside the package other declarations are only visible inside the package file2.java: a = foo.a() w = foo.b.x file1.java: from outside of package, elements are accessed using dot notation or by importing entire package package foo; public class A { A() { B.y+C.z class B { public static int x; static int y; class C { static int z; file3.java: import foo; a = A() w = B.x

Hiding and Abstraction A module typically encapsulates a set of services or a facility for use by other parts of the program Sometimes we just want a sane naming scheme, e.g. putting all the trigonometric functions into a library called Math Usually we also want to abstract over these services, by keeping some implementation info (internal functions, type definitions, etc.) hidden behind an interface Allows independent development of service and client Allows implementation to be changed without affecting client code Improves clarity, maintainability, etc. of the code base

Interfaces In many languages, interface to a module is given implicitly by using privacy modifiers on individual definitions Some languages allow interfaces to be specified explicitly, maybe in a separate file from the implementation An explicit interface is usually a set of top-level identifiers each with its type signature Makes it possible to write, type-check and (maybe) compile client code based just on the interface (In a sense, whole interface is type signature of whole module) Would also be nice to specify what interface elements do but this is hard

Abstract Data Types (ADT s) Can we apply same kind of abstraction to user-defined types to make client code independent of type representation and operator implementation? Ideally, user-defined types should have an associated set of operators, and clients should only be able to manipulate values via these operators (and maybe a few generic operators such as assignment or equality testing) Clients should not be able to inspect or change the fields of the value representation Idea: try to implement ADTs using modules and interfaces ability to do this is an important test for language s module facilities

ADT Example: Environments Consider an ADT for mutable environments mapping strings to values (of some arbitrary type), with this interface (in a made-up language): environment carrying values of type v type env V disjoint union operator empty() returns env V operator extend(env V,string,V) returns void operator lookup(env V,string) returns (Found(V) + NotFound) One way to give a formal description of the desired ADT behavior is to state some laws that we want the operators to obey: { e = empty(); v = lookup(e,k) = v = NotFound { v0 = lookup(e,k ); extend(e,k,v); v1 = lookup(e,k ) = v1 = if k = k then Found(v) else v0 { stmts P means P is true after execution of stmts"

OCaml version: Interface and Client env.mli: env is explicitly polymorphic.mli contains just the interface type a t val empty : unit -> a t val extend : a t -> string -> a -> unit val lookup : a t -> string -> a option encodes disjoint union example-client.ml: clients can be compiled using just the information in.mli even if implementation doesn t exist yet! let main = let e = Env.empty() in Env.extend e "a" "alpha"; Env.extend e "b" "beta"; Env.extend e "a" "gamma"; assert (Env.lookup e "a" = Some "gamma"); assert (Env.lookup e "c" = None);

.ml contains just the implementation OCaml version: Implementation env.ml: type a tree = Node of a tree * string * a * a tree Leaf type of boxes type a t = a tree ref let empty () = ref Leaf creates a box representation is a box containing a (pure) binary search tree let extend e k v = let rec ext e = match e with Leaf -> Node (Leaf,k,v,Leaf) Node (l,k0,v0,r) -> if k < k0 then Node(ext l,k0,v0,r) else if k > k0 then Node(l,k0,v0,ext r) stores into a box else (* k = k0 *) Node(l,k,v,r) in e := ext (!e) fetches from a box let lookup e k =... recompiling.ml does not affect clients as long as.mli is unchanged; only relinking is needed

Java version: Interface declares list of methods with their type signatures Env.java: Java generics handle the polymorphism straightforwardly could use an abstract class instead interface Env<V> { void extend(string k, V v); V lookup(string k); We again use null (unreliably) to represent NotFound there is no empty method; we will need to use a (concrete) constructor to make new environments

Java version: implementation ListEnv.java: uses private linked list representation creates new empty env class ListEnv<V> implements Env<V> { private class Node { String key; V value; Node next; // terminate with null Node(String key,v value,node next) { this.key = key; this.value = value; this.next = next; private Node e; public ListEnv() { this.e = null; can only run out of space if entire Java program heap is full Java garbage collector takes care of freeing environments when they are no longer accessible public void extend(string k, V v) { e = new Node(k,v,e); public V lookup(string k) { for (Node u = e; u!= null; u = u.next) if (k.equals(u.key)) return u.value; return null;

Java version: client EnvClient.java: class EnvClient { public static void main(string argv[]) { Env<String> e = new ListEnv<String>(); e.extend("a","alpha"); e.extend("b","beta"); e.extend("a","gamma"); String ax = e.lookup("a"); assert (ax.equals("gamma")); String cx = e.lookup("c"); assert (cx == null); client must commit to a particular implementation but is completely isolated from implementation internals

C version: Interface C doesn t have explicit module constructs, but separate compilation and header files can be used to simulate them (unsafely) header file to be #included in both implementation and clients Defines Env as a synonym for a pointer to the incomplete envrep structure type. This lets client compile without knowing details of envrep env.h: struct envrep; typedef struct envrep* Env; Env empty(void); void extend(env e, char* k, void* v); void* lookup(env e, char* k); We use NULL (unreliably) to represent NotFound Allow polymorphism over values as long as they are pointers; C permits (unsafe!) casting of any pointer to/from void*

C Version: Implementation env.c: #include "env.h" #define SIZE 100 struct envrep { int count; char *keys[size]; char *values[size]; ; uses a pair of arrays to represent env Env empty(void) { Env e = malloc(sizeof(struct envrep)); if (e == NULL) exit(exit_failure); e->count = 0; return e; static int find(env e, char* k) { int i; for (i = 0; i < e->count; i++) if (e->keys[i] == k) return i; return -1; envrep is private to this file only by convention (not enforced by C) can run out of room (unlike our abstract ADT description) C enforces that static function is invisible outside this file one possible implementation void extend(env e, char* k, void* v) { int i = find(e,k); if (i >= 0) e->values[i] = v; else { if (e->count >= SIZE) exit(exit_failure); e->keys[e->count] = k; e->values[e->count] = v; e->count += 1; all non-static functions are globally visible and must be unique across entire program void* lookup(env e, char* k) { int i = find(e,k); if (i >= 0) return e->values[i]; else return NULL; can leak storage: ADT has no operator to delete an environment, but C does not have garbage collection

C version: Client example-client.c: #include <assert.h> #include "env.h" int main(void) { Env e = empty(); extend(e,"a","alpha"); we must downcast the void* extend(e,"b","beta"); values returned by lookup extend(e,"a","gamma"); char* ax = (char*) lookup(e,"a"); assert (strcmp(ax,"gamma") == 0); char* cx = (char*) lookup(e,"c"); assert (cx == NULL); Nothing in the C language prevents a bad client from including the concrete definition of envrep (or using a different definition altogether) and corrupting the representation arrays.

Universal operations Although the idea of defining all operators for an ADT explicitly seems sensible, it can get quite tedious for the ADT author! For every types, we will need a way to assign values or pass them as arguments. We may also expect to be able to compare them (at least for equality). So many languages that support ADTs have built-in support for these basic operations, defined in an uniform way across all types and sometimes also mechanisms for ADT authors to customize them.

Too much abstraction? It is impossible for a compiler to generate client code for operations that move or compare data without knowing the size and layout of that data. But these are characteristics of the type s implementation, not its interface! So these universal operations break the abstraction barrier around the type and prevent separate compilation A common fix (seen in our examples) is to require all abstract values to be boxed, giving a simple universal implementation for assignment and equality comparison