principles of programming languages - home - new€¦ · the javascript language mixes both...
TRANSCRIPT
Collaboration and ManagementDana Fisman
1
Principles of Programming Languages
www.cs.bgu.ac.il/~ppl172
Lesson 2 - Typeswith
TypeScript
2
Types
What are types in programming languages?
What types are you familiar with?
Why are they needed? Why should we distinguish different types?
3
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
Programming language use complex expressions.
4
Expressions and Types
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?
5
Expressions and Types
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?
What if the
value of age is
“ab” ???
6
Why distinguish types?
Because some operators
(and functions)
can operate
only on
certain types of values
7
A Programming Language
Syntax Semantics
A grammar defining the set of allowed programs
Built inductively from atomic elements and operations that can be applied to (possibly compound) elements
The definition follows the inductive definition of programs
Defines the meaning of the program unambiguously
8
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
9
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.
10
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.
Processes so far Left to process
11
Example using an Imperative Program Initial state: [x:5, y:3, z:7]Program: "z = x; x = y; y = z;"
x:5y:3z:7
z = x; x = y; y = z;
Computation state:
Processes so far Left to process
12
Example using an Imperative Program Initial state: [x:5, y:3, z:7]Program: "z = x; x = y; y = z;"
x:5y:3z:7
z = x; x = y; y = z;
x:5y:3z:5
Computation state:
Processes so far Left to process
13
Example using an Imperative Program Initial state: [x:5, y:3, z:7]Program: "z = x; x = y; y = z;"
x:5y:3z:7
z = x; x = y; y = z;
x:5y:3z:5
x:3y:3z:5
Computation state:
Processes so far Left to process
14
Example using an Imperative Program Initial state: [x:5, y:3, z:7]Program: "z = x; x = y; y = z;"
x:5y:3z:7
z = x; x = y; y = z;
x:5y:3z:5
x:3y:3z:5
x:3y:5z:5
The new state at
each step was
determined by applying the
semantics of the
processed step
(here assignment)
Computation state:
The evaluation
process results in
computation history
15
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.
16
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.
17
Expressions vs. Statements
Programs in FP are compound expressions (built from sub-expressions using the syntax of the programming language)
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
In FP programs are processed by evaluating expressions
18
In FP programs are expressions Expressions can either be:
Atomic not made up of sub-expressions
Compound made up of sub-expressions according to the syntax
-12 // a number expressiontrue // a boolean expressionx // a variable expression
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
19
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
? :
>= * 9
v 3
=
v 7
{ let v = 12; (v >= 7) ? (v * 3) : 9 }
20
Expression Tree Expressions are combined recursively to form trees of compound expressions with atomic expressions at the leaves.
let
v 12
? :
>= * 9
v 3
=
v 7
21
Operational Semantics of FP
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.
In FP programs are processed by evaluating expressions
22
The Evaluation AlgorithmGiven 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
Continues recursively until
there are no sub-
expressions left to evaluate
(when leaves are reached)
23
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
24
Example of Evaluation
let
v 12
? :
>= * 9
v 3
=
v 7Environment
{ let v = 12; (v >= 7) ? (v * 3) : 9 }
25
Example of Evaluation
let
v 12
? :
>= * 9
v 3
=
v 7
v 12
Environment
{ let v = 12; (v >= 7) ? (v * 3) : 9 }
26
Example of Evaluation
let
? :
>= * 9
v 3v 7
v 12
Environment
{ let v = 12; (v >= 7) ? (v * 3) : 9 }
27
Example of Evaluation
let
? :
>= * 9
v 3v 7
v 12
Environment
{ let v = 12; (v >= 7) ? (v * 3) : 9 }
28
Example of Evaluation
let
? :
true * 9
v 3
v 12
Environment
{ let v = 12; (v >= 7) ? (v * 3) : 9 }
29
Example of Evaluation
let
? :
true * 9
v 3
v 12
Environment
{ let v = 12; (v >= 7) ? (v * 3) : 9 }
30
Example of Evaluation
let
? :
true 36 9
v 12
Environment
{ let v = 12; (v >= 7) ? (v * 3) : 9 }
31
Example of Evaluation
let
? :
true 36 9
v 12
Environment
{ let v = 12; (v >= 7) ? (v * 3) : 9 }
32
Example of Evaluation
let
36
v 12
Environment
{ let v = 12; (v >= 7) ? (v * 3) : 9 }
33
Example of Evaluation
let
36
v 12
Environment
{ let v = 12; (v >= 7) ? (v * 3) : 9 }
34
Example of Evaluation
36
Environment
The evaluation process
reduces the expression step
by step until the entire
expression is reduced to the
returned value
This process is thus often
termed reduction
{ let v = 12; (v >= 7) ? (v * 3) : 9 }
35
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).
36
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.
37
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>.
38
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.
39
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 sub-components
numbers booleans
Have sub-components arrays
40
Compound Values Ways to create compound variables:
o Literals in the program
o Using primitive constructs
o Deserialized from strings that represent compound values according to a value syntax (see the later lecture on JSON for example).
[1,2,3,4,5]
[1,2,3].concat([7,27])
[1,2,3,7,27]
How would you write/create
such a compound
value in Java?
[1,[100,200],3]
41
Typed vs. Untyped Languages o Typed Languages Require programmers to specify the type of variables upon their declaration o UnTyped Languages Do not have such requirement
C++, Java
JavaScript,
Scheme, Python
What are the advantages and disadvantages of declaring types?
There are finer
classification
s of
typeness in
programming
languages
42
Typing Errors at Runtime
square(3)
function square(x) {return x * x;}
x is untyped
Yet, a number value is expected
square(“abc”)
==> 9 ==> NaNNot a Number
If on evaluation type- incompatibility is
discovered usually a run-time error is issued.
This is a special
numeric value
rather than a run-
time error…
43
When should a runtime error be issued?
3 + 6
Python JavaScriptScheme3 + 6(+ 3 6)
==> 9 ==> 9 ==> 9
‘abc’
==> ‘abc’ ==> “abc” ==> ‘abc’
“abc” ‘abc’
‘ab’ + ‘cd’
==> ‘abcd’ ==> +: contract violation expected: number? given: "ab" argument position: 1st
==> ‘abcd’
(+ “ab” “cd”) ‘ab’ + ‘cd’
‘ab’ + 3
==> TypeError: must be str, not int
==> ‘ab3’
(+ “ab” 3) ‘ab’ + 3
==> +: contract violation expected: number? given: "ab" argument position: 1st
44
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.
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.
==> false
"a" > 2
==> ‘2ab’
2 + "ab"
==> NaN
"a" * 2
==> true
"a" && true
Not a Number
45
Variable Access in Javascript Accessors to compound data in Javascript do not fail
Referencing undefined variables in Javascript do fail
==> undefined
let arr=[1,2,3]; arr[10]
==> undefined
let map={a:1, b:2} map.c
a special value
not a rumtime error!
let b=2; c; // c is undefined
e.k // e is undefined
==> ReferenceError: c is not defined
◦ at evalmachine.<anonymous>:3:1 at ContextifyScript.Script.runInThisContext (vm.js:26:33) at Object.exports.runInThisContext (vm.js:79:17) at run ([eval]:608:19) at onRunRequest ([eval]:379:22) at onMessage ([eval]:347:17) at emitTwo (events.js:106:13) at process.emit (events.js:191:7) at process.nextTick (internal/child_process.js:752:12) at _combinedTickCallback (internal/process/next_tick.js:67:7)
==> ReferenceError: E is not defined
◦ at evalmachine.<anonymous>:2:1◦ at ContextifyScript.Script.runInThisContext (vm.js:26:33)◦ at Object.exports.runInThisContext (vm.js:79:17)◦ at run ([eval]:608:19)◦ at onRunRequest ([eval]:379:22)◦ at onMessage ([eval]:347:17)◦ at emitTwo (events.js:106:13)◦ at process.emit (events.js:191:7)◦ at process.nextTick (internal/child_process.js:752:12)◦ at _combinedTickCallback (internal/process/next_tick.js:67:7)
46
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).
47
Type SafetyType 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.
48
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
49
Types: Value vs. Variable
type of a value type of a variable
a value always has a type
it belongs to some set of
values
perhaps to several
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
50
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
51
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 These are basically syntactic sugaring
Programming languages offer
additional ways to construct new types
52
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) Checks types compatibility
53
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
o null: { null } o undefined: { undefined }
54
Javascript Compound Value Types
Compound types (types that are built from primitive operators )
o Arrays : - a list of values - values are referred to by their order
(first, second, third, etc.) o Maps : - a list of (key, value) pairs - values are referred to by their keys
[100, 200, 300]
{ a : 100, b : 200 }
The value of pos 0
The value of pos 2
The value of key b
55
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}
56
Compound Value Types 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
==> { a: 1, b: 2 }
More on
in Javascript
57
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)
58
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));
==> object undefined
a well known error
59
Javascript Types Introspectionlet arr1 = [1, 2, 3],
arr2 = ['a', 'b', 'c'];
console.log(typeof(arr1));
console.log(typeof(arr2));
==> object object
==> object object
let map1 = { a : 1, b : 2},
map2 = { 'a' : 1, 'b' : 2};
console.log(typeof(map1));
console.log(typeof(map2));
60
Javascript Types Introspection
let arrIns = [1, 2],
mapIns = { a:1 }
console.log(arrIns instanceof Array);
console.log(mapIns instanceof Array);
==> true false
In Javascript typeof is very limited
We will see later how Typescript improves capabilities of typeof
More specific reflection :
61
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' ]
62
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
63
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' ]
64
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 has value 1 b has value 2 0 has value a 1 has value b 2 has value c
The `backward notation` creates interpolated strings
${expression} is replaced by the value of the expression converted to a strings
65
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 : number = 6,
typedVarStr : string = "blue",
typedVarBool : boolean = true;
66
Summary
Programming Language semantics defines the requirements for tools that manipulate programs: interpreters, compilers, debuggers etc.
helps determine whether two programs are equivalent.
67
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.
68
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 well-typed program will not lead to type runtime errors.
69
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).
70
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.