Presentation is loading. Please wait.

Presentation is loading. Please wait.

Reasoning with Types.

Similar presentations


Presentation on theme: "Reasoning with Types."— Presentation transcript:

1 Reasoning with Types

2 Common Type Errors Performing arithmetic operations (e.g. multiplication) on non-numbers let x = "Hello World"; let y = 10 * x; Indexing as if an array, but variable value is not an array let x = 42; let y = x[0]; Calling as if a function, but variable value is not a function let x = 42; let y = x(10); Referring to member of object, but variable value is not object type, or does not have member. let x = 42; let y = x.length; Note that JavaScript has types. However, the types are checked when you run the program, not when you compile the program.

3 The Basic Types in JavaScript
> typeof 3 "number" > typeof 1.5 > typeof "compsci220" "string" > typeof true "boolean" > typeof undefined "undefined" Note that undefined is a special vaue that is similar to null in Java / C. JavaScript also has a value called null, but it is rarely used. You can ignore it in this class. > function f(x, y) { return x + y + 1; } > function g(z) { return z * 100; } > typeof f "function" > typeof g Unfortunately, saying that f and g have type “function” is not very useful. After all, they accept a different number of arguments. > typeof { x: 100 } "object" > typeof { x: "hello" } Similarly, saying that both objects have type “object” is not useful, since one has a number if the field x and the other has a string in the field x.

4 A Notation for Types in JavaScript
We need a convenient way to talk about the types of functions and objects in JavaScript. We are going to write types as comments, to help us understand our code. Since they are merely comments, the compiler cannot check that they are correct. However, the notation that we are going to use is not something that we’ve made up. It is the same notation that Is used by TypeScript, which is a dialect of JavaScript that supports type-checking. We do not cover TypeScript in this class, but we encourage you to check it out for yourself. A simple, first-order function function F(x, y) { return x + y * 10; } It is obvious that F below is a function. But, what else can we say about it? F is a function that takes two arguments, x and y. x must be a number Y must be a number The result produced by F is a number. Instead of writing all that prose, we will write the type of F as: // F(x: number, y: number): number Another first-order function function G(a, x) { return a[0] + x; } What we can say about G: G is a function that takes two arguments, a and x. a must be an array of numbers x must be a number The result produced by G is a number. // G(a: number[], y: number): number Note that G requires a to be a non-empty array. We could write that in the type, but it will get really cumbersome. When requirements get complicated, we will just write it as a comment below the type. // G requires a to be non-empty A function with a type error function H(x) { if (x > 0) { return x + 10; } else { Return "hello"; } What we can say about H: H is a function that takes an argument x. If x is positive, H returns a number. Otherwise, H returns a function. This function returns two different types! You cannot do this in Java or C, but it is totally possible to do so in JavaScript. However, we are going to avoid writing these kinds of functions because they make code harder to write (and read).

5 Types for Higher-Order Functions
A simple higher-order function function F(f, x) { return f(x + 1) + 20; } What can we say about F: F is a function that takes two arguments, f and x. x must be a number, since we calculate x + 1. f must be a function that takes one argument, since we call it in the body of F. The argument to f must be a number The result produced by f must be a number, since we add 20 to the result. Therefore, the result of F must be a number. More succinctly: // F(f: (y: number) => number, x: number): number Another higher-order function function function G(a, x) { a.reduce(function(y, f) { return f(y) }, x + 1); } What we can say about G: G is a function that takes two arguments, a and x. x must be a number. a must be an array of functions Each function in the array must take one argument. Each function in the array must consume a number and produce a number. Therefore, G must produce a number. More succinctly: // G(a: ((y: number) => number)[], x: number): number

6 Types for Objects In Java, every object has a class. We will discuss JavaScript classes later in the course. However, you do not need classes to create objects in JavaScript. For example, the following expression creates an object with two fields: > let o = { x: 200, y: "number" }; > o.x 200 To describe the type of an object, we simply describe the types of its fields. A function that consumes an object function F(o) { return o.x + o.y; } What can we say about F: F is a function that takes one argument o o must be an object with fields x and y, both of which are numbers. The result of F must be a number More succinctly: // F(o: { x: number, y: number }): number A function that consumes and produces an object function G(o) { return { sum: o.x + o.y }; } What we can say about G: F is a function that takes one argument o. o must be an object with fields x and y, both of which are numbers. The result of G is an object, with a field called sum, which has type number. More succinctly: // G(o: { x: number, y: number }): { sum: number }

7 Generic Types Implementation: function F(o) { return { z: o.x }; }
Examples: > F({ x: 200 }) { z: 200 } > F({ x: "hello" }) { z: string } > F({ x: {y : 90 }}) { z: { y: number } } What can we say about F: F is a function that takes one argument o o must be an object with a field called x. The type of value in the field x could be any type. The result of F is an object with a field called z. The type of value in the field z is the same as the type of the field x. More succinctly: // F(o: { x: T }): { z: T } Above, we are using the letter T to stand for any type T. We use it twice to indicate that the field x and field z have the same type T. Implementation: function G(o) { return { a: o.y, b: o.x }; } Examples: > F({ x: 200, y: "hello" }) { a: "hello", b: 200 } > F({ x: 200, y: 100 }) { a: 100, b: 200 } What we can say about G: G is a function that takes one argument o. o must be an object with fields x and y, which could have any type. The result of G is an object with two fields, a and b. The type of field x is the same as the type of field b. The type of field y is the same as the type of field a. However, fields x and y may have different types. More succinctly: // G(o: { x: T1, y: T2 }): { a: T2, b: T1 } Above, we are using the letters T1 and t2 to stand for any two types that may be different (or the same).

8 Calculating the type of map
Implementation: function map(f, a) { let result = []; for (let i = 0; i < a.length; ++i) { result.push(f(a[i])); } return result; Examples: > map(function(x) { return x + 1; }, [10, 20, 30]) [11, 21, 31] > map(function(x) { return !x; }, [true, false]) [ false, true] > map(function(x) { return x.f * 2; }, [{ x: 5 }, { x: 10 }]); [ 10, 20 ] Type Constraints: map is a function that takes two arguments, f and a. a is an array. f is a function that takes one argument. Let’s call this argument x. The result of map is an array. The type of x must be the same as the type of each element of a. The values produced of f are stored in the array produced by map. Therefore, the result type of f must be the same as the type of value in the array returned by map. Type Signature: map(f: (x: T1) => T2, a: T1[]): T2[]

9 What are the errors in these programs?
The two programs below signal errors. Can we explain the errors using types? map(f: (x: T1) => T2, a: T1[]): T2[] Program: let a = ["1", "2", "4", "8"]; function f(x) { return 1 / x; } map(f, a); The type of f is f(x: number): number. The type of a is []string. Based on the type of f, T1 must be number. Based on the type of a, T1 must be string. However, number !== string. Program: let a = [1, 2, 3]; function f(o) { return o.x + 1; } map(f, a); The type of f is f(o: { x: number }): number. The type of a is []number. Based on the type of f, T1 must be { x: number }. Based on the type of a, T1 must be number. However, { x: number } !== number.


Download ppt "Reasoning with Types."

Similar presentations


Ads by Google