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
© Copyright 2024 Paperzz