#L01

Welcome!

Welcome to CS251: Principals of Programming Languages!

Agenda for today:

Name magnets/name tents

If you missed class, I will have more on Monday!

Professor introduction

I'm Alexa VanHattum-you can call me "Alexa", "Prof. Alexa", or "Prof VanHattum".

This is my second year as an Assistant Professor at Wellesley. My research focus is the intersection of programming languages & computer systems, with a focus on applying lightweight formal methods to compilers for systems languages.

Before Wellesley, I spent time as a software engineer for Apple health, then completed grad school at Cornell.

Student introductions

(Names, pronouns, year, favorite, least favorite, or weirdest programming language).

This is a smaller elective, and we want to all get to know each other!

Go over the syllabus/website

Goals

In this class, you will:

Programming languages as a field of study

Paradigms

Paradigms are specific models and shared features across different languages. These are usually not strict boundaries, but rather broad groupings.

The imperative paradigm

Most programming you've done up to this point is imperative.
We can think of imperative code as being "step-by-step": you tell the computer what to do via a series of instructions. This comes from the lineage of assembly code, which is organized as a sequence of instructions grouped by jumping between blocks of code.

The primary means of processing data in imperative code is via loops: for, while, do while, etc.

Data in imperative languages is more closely aligned with its representation in memory: memory is a contiguous array of bytes. Types group the bytes into e.g. integers. Types further group basic data types like integers into composite data like arrays.

Examples of primarily imperative languages: C, Java, Python.

The functional paradigm

Functional programming languages are more declarative: they describe what a computation is, rather than how to do it step-by-step. This more closely aligned with pure mathematics.

The primary means of processing data in imperative code is via recursion, instead of loops. Functional languages avoid mutating data, and are thus less close of a representation to low-level program memory.

For example, you'd avoid the following pattern of mutation in most functional languages:

# This code is more imperative than functional
x = 3
x = 5

A primary feature of functional languages is that they treat functions as values.
This is related to "first class functions" and "higher order functions", which we'll define more precisely over the coming weeks.

Imperative languages also often support some version of functions as values, even though functions are not necessarily "first class".

For example:

(Think, then click!)
You can use an _anonymous function_:
my_list.sort(key=lambda x: x.field)

lambda x: x.field is a function (with no name, and thus anonymous) that is passed as an optional argument to the sort function.


"Lambda" more broadly means an unnamed function. Later in the semester, we will briefly cover the lambda calculus.

Examples of primarily functional languages: Racket, OCaml, Lisp, Rust

Why study functional languages?

Why should we study these languages, when the most popular programming languages are primarily imperative?

Functional languages:

These skills are important because (1) they are less error prone in many cases, (2) they can lead to performance improvements, e.g., by enabling parallel code, and (3) some data and tasks are much easier to use recursion on, but you have had less practice with it.

Mindset

Functional programming is a whole new way of doing things! I encourage you feel comfortable approaching learning Racket and OCaml as fun new games, distinct from the programming you've done prior to now. :)

What is a PL? Syntax + semantics

Syntax

A programming language’s syntax defines its form
Syntax tells us:

Semantics

Syntax vs semantics example

Good syntax, bad semantics:

colorless green ideas sleep furiously

vs.

Bad syntax, good semantics:

can anyway probably you this read

Which PL is best? How do we choose what PL to use?

Power versus expressiveness:

Computational power

All languages that are Turing-complete have equal computational power.

Tradeoffs

This class will help you think about picking the right language for the task.

Group exercise: mapping what you know about PLs

4 of the most common languages folks have used
(Python, Java, Javascript, R)

Back to PL paradigms: types

Types tell us what operators are valid on what data.

Static means before the program runs.

Dynamic means as the program is running.

Broadly: A static type system finds type errors before the program runs. A dynamic type system only hits the error when the program actually reaches is. People tend to think of static as "stronger" and dynamic as "weaker" types.

Primarily imperative Primarily functional
Dynamically typed Python 🆕 Racket
Statically typed Java 🆕 OCaml

Intro to Racket: your first (probably) functional language!

We will boil down programming to very basic pieces, then build up from there.

The Racket syntax is weird! I'm sorry!

Parenthesis for almost everything: ((()))

Basic values:

Booleans #t and #f
Numbers 1 1.0 and 1/2

Expressions:

Operators: +, -, etc

Operators are prefix: they come before the arguments. Use parens to group.

(+ 1 2) ; evaluates to the value 3

Control Flow

So called "one-arm" ifs are not a thing. Instead, if always results in a value:

(if b
    #t
    #f)

(if b
    1
    2)

Instead of a chain of if then else if then else, we use cond:

(cond ((= x 0) 5)
      ((= x 1) 6)
      (else 7))

Variable definitions

(define x 1)

Binds the variable x to the value 1.

Functions

How do we define functions? More parens!

(define (add-one x)
  (+ x 1))

; Note: whitespace does not matter!
; Same as:
(define (add-one x) (+ x 1))

Group exercise:

Define our absolute value function in Racket.

Use: < or > , -

(define (abs x)
   (if (< 0 x)
       x
       (- x)))
; or
(define (abs x)
   (if (< x 0)
       (- 0 x)
       x))
; or many other variants...

; Note: x alone does not need parens

Next time, we'll see more Racket in an actual IDE!