slides

Principles of
Programming
Languages
www.cs.bgu.ac.il/~ppl172
- Types
CollaborationLesson
and 2Management
Dana Fisman
with
TypeScript
1
Types
What are types in programming languages?
What types are you familiar with?
Why are they needed?
Why should we distinguish different types?
2
Type of Values
A value-type defines a set of values.
Examples:
Booleans { true, false } Numbers { 0, 1, 2, …, -17.63, 1/3, e, …}
Strings { ‘a’, ‘abc’, ‘some words’, …}
Each value-type is associated with a set of operations that
can be done on these values.
Different value-types are represented differently in memory
3
Expressions and Types
Programming language use complex expressions.
age > 18 ? true : false
Eventually we would like to compute the resulting
value of an expression.
Different expressions evaluate to different value
types.
Does the calculation process needs to be aware of
types?
4
Expressions and Types
the
f
i
t
Wha f age is
o
value b” ???
“a
age > 18 ? true : false
Is it legal?
If not, when should the error be discovered
(compilation-time? run-time?)
If yes, what should be the result?
5
Why distinguish types?
Because some operators
(and functions)
can operate
only on
certain types of values
6
A Programming Language
Syntax
A grammar defining the
set of allowed programs
Built inductively from
atomic elements and
operations that can be applied
to (possibly compound) elements
7
Semantics
Defines the meaning of
the program unambiguously
The definition follows
the inductive
definition of programs
Why do we need a formal semantics?
So that we can agree what is the output of a given program.
o The formal semantics provides an unambiguous definition of what its execution should achieve.
o Various tools manipulate programs (compilers, interpreters, debuggers, IDEs, verification tools).
o All of these tools must agree upon a formal specification of what is expected when we execute
the program.
o Without formal semantics we cannot validate the correctness
of programs
8
Semantic Domain
Formal semantics gives rules for translation
from one domain (usually the program’s syntax)
to another formally defined domain.
There are various ways to define the semantics
of a programming language (denotational,
operational, axiomatizational, …)
We will use the operational semantics approach.
9
Operational Semantics
The Operational Semantics approach determines that:
the meaning of an expression in the programming
language is specified by the computation it induces
when it is executed on a machine.
It prescribes how to execute the program step by
step. When we follow this specification, we can record the
steps and keep track of the state of the computation
as steps are executed.
10
Example using an Imperative Program
Initial state:
[x:5, y:3, z:7]
Program: "z = x;
x = y;
y = z;"
Processes so far
Computation
state:
11
Left to process
z = x; x = y; y = z;
x:5
y:3
z:7
Example using an Imperative Program
Initial state:
[x:5, y:3, z:7]
Program: "z = x;
x = y;
y = z;"
Processes so far
Left to process
z = x; x = y; y = z;
Computation
state:
12
x:5
y:3
z:7
x:5
y:3
z:5
Example using an Imperative Program
Initial state:
[x:5, y:3, z:7]
Program: "z = x;
x = y;
y = z;"
Processes so far Left to process
z = x; x = y; y = z;
Computation
state:
13
x:5
y:3
z:7
x:5
y:3
z:5
x:3
y:3
z:5
Example using an Imperative Program
Initial state:
[x:5, y:3, z:7]
Program: "z = x;
x = y;
y = z;"
Processes so far Left to process
z = x; x = y; y = z;
Computation
state:
14
x:5
y:3
z:7
x:5
y:3
z:5
x:3
y:3
z:5
ation
u
l
a
v
e
e
Th
lts in
u
s
e
r
s
s
e
p ro c
tion
a
t
u
p
m
o
c
history
x:3
y:5
z:5
at
e
t
a
t
s
w
The ne ep was
each st ed by
n
determi g the
applyin of the
cs
semanti d step
processe nment)
s ig
(here as
Operational Semantics
Is it a complete recipe for tool implementors?
No. The operational semantics provides an abstraction. It does not provide all the details of what should happen in a
concrete computation on specific hardware. For example, it does not mention registers, translation to
machine language, encoding of data types. The computation history is a formal mathematical object
which is in the semantic domain.
15
Operational Semantics
The rules of the semantics of the specific programming language
indicate:
o
how to select a sub-expression to evaluate at each step of the
computation, and
o
what are the effects on the state of the computation each time a
primitive sub-expression is executed
o
the state of the computation includes the program that is left to
process and the environment
o
the environment includes the information that was recorded and is
needed to complete the processing of the program
In summary, the operational semantics of the language maps a program
and an initial state to a formal structure we call a computation history.
16
Expressions vs. Statements
Programs in FP are compound expressions (built
from sub-expressions using the syntax of the
programming language)
In FP programs are processed
by evaluating expressions
Programs in IP are compound statements (built from
sub-statements using the syntax of the
programming language)
In IP programs are processed
by executing statements
17
In FP programs are expressions
Expressions can either be:
Atomic
not made up of sub-expressions
-12
true
x
// a number expression
// a boolean expression
// a variable expression
Compound
made up of sub-expressions according to the syntax
12 >= 7 // made up by applying comparison
// to sub-expressions 12 and 7
(x < 100) ? -1 : 2 // conditional expression applied
// to sub-expressions (x < 100),
//
-1 and 2
18
Expression Tree
Expressions are combined recursively to form trees of
compound expressions with atomic expressions at the leaves.
{ let v = 12;
(v >= 7) ? (v * 3) : 9
}
let
=
v
? :
12
>=
v
19
7
*
v
9
3
Expression Tree
Expressions are combined recursively to form trees of
compound expressions with atomic expressions at the leaves.
{ let v = 12;
(v >= 7) ? (v * 3) : 9
}
let
=
v
? :
12
>=
v
20
7
*
v
9
3
Operational Semantics of FP
In FP programs are processed
by evaluating expressions
The evaluation function maps expressions to values.
The operational semantics of an FP language describes how the
evaluation function operates over all possible expressions in the
language.
It is defined inductively over the syntactic structure of
expressions.
It uses an environment to record the needed info.
21
The Evaluation Algorithm
Given an expression e
o Identify the top-level syntactic construct of e
o Identify the immediate sub-expressions of e
o Perform the specific evaluation rule defined for the construct of e 22
ntil
u
y
l
e
v
i
s
r
r ecu
s
e
u
n
i
t
n
o
C
subo
n
e
r
a
e
ther
luate
a
v
e
o
t
t
f
s le
expression ves are reached)
(when lea
let
{ let v = <expr>; <body-expr> }
Intuitive semantics:
Evaluate <body-expr> using local variable v
Operational semantics:
o Evaluate the <expr> to value v1
o Bind v to v1
o Evaluate <body-expr> to value v2
o Discard the binding of v
o Return v2
23
Example of Evaluation
{ let v = 12;
(v >= 7) ? (v * 3) : 9
}
let
=
v
Environment
24
? :
12
>=
v
7
*
v
9
3
Example of Evaluation
{ let v = 12;
(v >= 7) ? (v * 3) : 9
}
let
=
v
Environment
v
25
12
? :
12
>=
v
7
*
v
9
3
Example of Evaluation
{ let v = 12;
(v >= 7) ? (v * 3) : 9
}
let
? :
>=
Environment
v
26
12
v
7
*
v
9
3
Example of Evaluation
{ let v = 12;
(v >= 7) ? (v * 3) : 9
}
let
? :
>=
Environment
v
27
12
v
7
*
v
9
3
Example of Evaluation
{ let v = 12;
(v >= 7) ? (v * 3) : 9
}
let
? :
*
true
Environment
v
28
12
v
9
3
Example of Evaluation
{ let v = 12;
(v >= 7) ? (v * 3) : 9
}
let
? :
*
true
Environment
v
29
12
v
9
3
Example of Evaluation
{ let v = 12;
(v >= 7) ? (v * 3) : 9
}
let
? :
true
Environment
v
30
12
36
9
Example of Evaluation
{ let v = 12;
(v >= 7) ? (v * 3) : 9
}
let
? :
true
Environment
v
31
12
36
9
Example of Evaluation
{ let v = 12;
(v >= 7) ? (v * 3) : 9
let
36
Environment
v
32
12
}
Example of Evaluation
{ let v = 12;
(v >= 7) ? (v * 3) : 9
let
36
Environment
v
33
12
}
Example of Evaluation
{ let v = 12;
(v >= 7) ? (v * 3) : 9
}
36
Environment
34
ocess
r
p
n
o
i
t
a
The evalu xpression step
he e
reduces t until the entire
the
o
t
by step
d
e
c
u
d
is re
n
o
i
s
s
e
r
p
x
e
alue
v
d
e
n
r
u
t
re
often
s
u
h
t
s
i
s
es
This proc reduction
termed
Summary - Operational Semantics
Semantics gives meaning to the program constructs
(by which we can derive the meaning of a complete
program)
Operational semantics provides the meaning by
prescribing step by step evaluation
It distinguishes mathematical functions from
functions in programming language (which, by the
operational semantics we can view as procedures).
35
Types of Expressions
The Javascript language mixes both expressions
and statements (as it is a multi-paradigm
language). This makes it difficult to describe completely its
operational semantics in a concise manner. We will completely define a smaller language later
on in the course, and suffice now with an informal
description for Javascript.
36
Types of Expressions in Javascript
Atomic expressions:
number expressions -12,
string expressions "abc",
boolean expressions false.
Compound expressions:
arithmetic expressions (10 + v) * (w / 5),
conditional expressions (x > 5),
ternary conditional expression <condition> ? <expr1> : <expr2>.
37
Types of Expressions in Javascript
Variable bindings:
let <var> = <expr1>;
<expr2>
Function invocation:
f(<expr1>,...,<exprn>)
Function definition:
(<var1>,…) => <expr>.
This list of expressions determines the syntax
of a subset of programs in Javascript.
38
Types in Programming Languages
In the same manner that
expressions
can be atomic or compound, the values that a program generates
can be atomic or command
no subts
n
e
n
o
p
m
o
c
numbers
booleans
39
Have subcomponen
ts
arrays
Compound Values
Ways to create compound variables:
Literals in the program
o
[1,2,3,4,5]
Using primitive constructs
o
[1,2,3].concat([7,27])
o
40
[1,2,3,7,27]
[1,[100,200],3]
How would you
write/create
such a
compound
value in Java?
Deserialized from strings that represent compound
values according to a value syntax (see the later lecture on
JSON for example).
Typed vs. Untyped Languages
a
v
a
J
,
+
C+
o Typed Languages Require programmers to specify the type of variables upon their declaration
t,
p
i
r
c
aS
v
a
J
on
o UnTyped Languages h
ner f
t
i
y
f
P
e
r ns o
e,
a
m
e
e
r
Sch
Thesificatios in
las penes ing
c
Do not have such requirement
ty ramm s
rog guage
p
lan
41
What are the advantages and disadvantages of
declaring types?
Typing Errors at Runtime
x is
untyped
function square(x) {return x * x;}
Yet, a
number
value is
expected
square(3)
==> 9
42
square(“abc”)
==> NaN
Not a Number
If on evaluation typeincompatibility is
discovered usually a runtime error is issued.
special
This is a value
numeric a runan
rather therror…
time
When should a runtime error be issued?
Python
3 + 6
(+ 3
6)
JavaScript
3 + 6
==> 9
==> 9
==> 9
‘abc’
“abc”
‘abc’
==> ‘abc’
‘ab’ + ‘cd’
==> ‘abcd’
‘ab’ + 3
==>
43
Scheme
TypeError: must
be str, not int
==> “abc”
(+ “ab” “cd”)
==>
+: contract violation
expected: number?
given: "ab"
argument position: 1st
(+ “ab” 3)
==>
+: contract violation
expected: number?
given: "ab"
argument position: 1st
==> ‘abc’
‘ab’ + ‘cd’
==> ‘abcd’
‘ab’ + 3
==> ‘ab3’
Javascript Primitives do not Fail
Javascript design choice:
Primitive operators are extremely flexible and robust
Evaluation of strange things do not trigger a runtime-error,
instead it either makes automatic conversions
or returns special symbols denoting impossible values.
"a" > 2
==> false
2 + "ab"
==> ‘2ab’
"a" * 2
==> NaN
Not a
Number
"a" && true
==> true
This is a dubious decision - as such automatic handling of unexpected variations
is most often a sign of poorly written code and produces surprising results.
44
Variable Access in Javascript
Accessors to compound data
in Javascript do not fail
let arr=[1,2,3];
arr[10]
==> undefined
a special
value
not a
rumtime
error!
let map={a:1, b:2}
map.c
==> undefined
45
Referencing undefined
variables in Javascript do fail
let b=2;
c; //
c is undefined
==> ReferenceError:
c is not defined
◦
e.k
at
at
at
at
at
at
at
at
at
at
evalmachine.<anonymous>:3:1
ContextifyScript.Script.runInThisContext (vm.js:26:33)
Object.exports.runInThisContext (vm.js:79:17)
run ([eval]:608:19)
onRunRequest ([eval]:379:22)
onMessage ([eval]:347:17)
emitTwo (events.js:106:13)
process.emit (events.js:191:7)
process.nextTick (internal/child_process.js:752:12)
_combinedTickCallback (internal/process/next_tick.js:6
// e is undefined
==> ReferenceError:
E is not defined
◦
◦
◦
◦
◦
◦
◦
◦
◦
at
at
at
at
at
at
at
at
at
evalmachine.<anonymous>:2:1
ContextifyScript.Script.runInThisContext (vm.js:26:
Object.exports.runInThisContext (vm.js:79:17)
run ([eval]:608:19)
onRunRequest ([eval]:379:22)
onMessage ([eval]:347:17)
emitTwo (events.js:106:13)
process.emit (events.js:191:7)
process.nextTick (internal/child_process.js:752:12)
Type Safety
Can we avoid such errors and unpleasant surprises?
What are the benefits of declaring the types of
variables?
Type safety is the extent to which a programming
language discourages or prevents type errors.
A type error is erroneous or undesirable program
behavior caused by a discrepancy between
differing data types for the program's constants,
variables, and methods (functions).
46
Type Safety
Type enforcement can be either:
static
catching potential errors at compile time,
or dynamic
associating type information with values at run-time
and consulting them as needed to detect imminent errors
or a combination of both.
Type safety in static-type (compile-time) systems, usually
involves a guarantee that the eventual value of any expression
will be a legitimate member of that expression's static type.
47
Type of Values
A value-type defines a set of values.
Examples:
Booleans { true, false } Numbers { 0, 1, 2, …, -17.63, 1/3, e, …}
Strings { ‘a’, ‘abc’, ‘some words’, …}
Each value-type is associated with a set of operations that
can be done on these values.
Different value-types are represented differently in memory
48
Types: Value vs. Variable
type of a value
a value always
has a type
it belongs to
some set of
values
perhaps to
several
49
type of a variable
a variable are part
of expressions
on evaluation they
are bound to a
value
a declaration of a type of a
variable expresses the
programmers intent for the
values the variable will assume
Types and Set Relations
Since value-types define set of values we can reason about
them using set theory notions
Let T1, T2 denote value-types. We can say that
o T1 is a subset of T2
o T1 and T2 are disjoint
o T1 is universal (any in Javascript)
o T1 is finite
o T1 is infinite
50
Types and Set Relations
We can construct new types using existing types
o T1 union T2
o T1 intersection T2
o T1 x T2 (cartesian product)
Compound types
(such as arrays)
can be defined
using just these
basic set relation
operators
51
Programming
languages offer
additional ways to
construct new types
These are basically
syntactic sugaring
Javascript vs. Typescript
Typescript is an extension of Javascript (every Javascript program is legal Typescript program) In Javascript variables are not typed, values have types Typescript adds the ability to define a type of variable (this is
optional)
Typescript programs can be translated to Javascript programs
This process does both:
Eliminates the types definition (so the result is (untyped) Javascript program)
52
Checks types compatibility
Javascript Primitive Value Types
“Ordinary” atomic value types
o
Booleans : { true, false }
o
Numbers : { 0, 1, 2, …, -17.63, 1/3, e, …}
o
Strings :
{ ‘a’, ‘abc’, ‘some words’, …}
Special atomic value types
53
o
null: { null }
o
undefined: { undefined }
Javascript Compound Value Types
Compound types (types that are built from primitive operators )
o
Arrays :
- a list of values
[100, 200, 300]
- values are referred to by their order The value The value
(first, second, third, etc.)
of pos 0
of pos 2
o
Maps :
- a list of (key, value) pairs
{ a : 100, b : 200 }
- values are referred to by their keys 54
The value
of key b
Javascript Value Types
This is an inductive definition:
Atomic : boolean, number, string, null, undefined
Compound : array, map
The elements of an array/map can be any Javascript
data value [100, [1,2], 300]
{ a : 100, b : 200 , c : [1,2], d : {foo : 15} , e : 500}
55
More
on
Compound Value Types
in
Javascript
Compound values can also be constructed by invoking
the appropriate constructors and mutators (functions
which incrementally change a value).
let arrConstructed = Array(1,2,3)
arrConstructed
==> [1,2,3]
let mapConstructed = {}
mapConstructed.a = 1
mapConstructed.b = 2
mapConstructed
56
==> { a: 1, b: 2 }
Types Introspection
Different languages offer various levels of
introspection / reflection to enable the analysis
of the type of values at runtime, or at
interpretation /compile-time.
Javascript offers very minimal reflection
abilities, only the type of atomic value types or
the indication that it is compound (unfortunately
called object)
57
Javascript Types Introspection
console.log(typeof("a"))
console.log(typeof(6))
console.log(typeof(true)
==> string
number boolean
let null1 = null;
let undef = undefined;
console.log(typeof(null1));
console.log(typeof(undef));
58
==> object
undefined
a well known error
Javascript Types Introspection
let arr1 = [1, 2, 3],
arr2 = ['a', 'b', 'c'];
console.log(typeof(arr1));
console.log(typeof(arr2));
==> object
object
let map1 = { a : 1, b : 2},
map2 = { 'a' : 1, 'b' : 2};
console.log(typeof(map1));
console.log(typeof(map2));
==> object
object
59
Javascript Types Introspection
In Javascript typeof is very limited
We will see later how Typescript improves capabilities of typeof
More specific reflection :
let arrIns = [1, 2],
mapIns = { a:1 }
console.log(arrIns instanceof Array);
console.log(mapIns instanceof Array);
==> true
false
60
Javascript Compound Value Getters
Compound values can be "put apart" by using getters
let arrInd = ["a", "b", "c", "d", "e"]
console.log(arrInd[0])
console.log(arrInd[1])
console.log(arrInd.slice(1))
console.log(arrInd.slice(1,4))
==> a
b
[ 'b', 'c', 'd', 'e' ]
[ 'b', 'c', 'd' ]
61
Javascript Compound Value Getters
Compound values can be "put apart" by using getters
let mapInd = { a : 1, b : 2 } console.log(mapInd['a'])
console.log(mapInd.a)
console.log(mapInd['b'])
console.log(mapInd.b)
==> 1
1
2
2
62
Compound Value Getters
Compound values can be "put apart" by using getters
let mapKey = { a : 1, b : 2},
arrKey = ['a', 'b', 'c'];
console.log(Object.keys(mapKey));
console.log(Object.keys(arrKey));
==> [ 'a', 'b' ]
[ '0', '1', '2' ]
63
Compound Value Getters
for (let k in mapKey) {
console.log(`${k} has value ${mapKey[k]}`);
}
for (let i in arrKey) {
console.log(`${i} has value ${arrKey[i]}`);
}
==> a
b
0
1
2
64
has
has
has
has
has
value
value
value
value
value
1
2
a
b
c
The `backward notation`
creates interpolated strings
${expression} is replaced by the
value of the expression
converted to a strings
Variable Types in Typescript: Gradual Typing
As we said:
o In static languages (c++, Java) variables must typed
o
In dynamic languages (Javascript, Python) variables are not typed
- variables are bound to values
- we can inspect their values in runtime
o
Typescript introduces optional variable types into Javascript
let typedVarNum
typedVarStr
: number = 6,
: string = "blue",
typedVarBool : boolean = true;
65
Summary
Programming Language semantics
defines the requirements for tools that manipulate
programs: interpreters, compilers, debuggers etc.
helps determine whether two programs are
equivalent.
66
Summary
The Operational Semantics of programming language defines the meaning of programs by mapping
programs to evaluation histories.
provides recursive evaluation rules for each specific
syntactic construct in a programming language.
67
Summary
Expressions in an FP language are computed into
values. This process can be described as reduction.
Runtime errors can be triggered when parameters
of the wrong type are passed to primitives (in
Scheme) or when undefined variables are accessed.
Type safety guarantees at compile-time that a welltyped program will not lead to type runtime errors.
68
Summary
Data types are defined by 2 aspects: they are
sets of values and they determine which
operations can be used on values.
Values can be atomic (no sub-part) or
compound (made up of multiple parts).
69
Summary
Typescript adds the option of gradual typing
on top of Javascript.
Primitive atomic types in Typescript are
number, boolean, string, undefined and null.
Primitive compound types in Typescript are
array and map.
70