Skip to content

Commit 3a65740

Browse files
committed
apr 1 files
1 parent 0792378 commit 3a65740

7 files changed

Lines changed: 540 additions & 0 deletions

File tree

S25/vignettes/apr1/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules

S25/vignettes/apr1/package-lock.json

Lines changed: 237 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

S25/vignettes/apr1/package.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"name": "apr1",
3+
"version": "1.0.0",
4+
"main": "index.js",
5+
"scripts": {
6+
"test": "echo \"Error: no test specified\" && exit 1"
7+
},
8+
"keywords": [],
9+
"author": "",
10+
"license": "ISC",
11+
"description": "",
12+
"devDependencies": {
13+
"ts-node": "^10.9.2",
14+
"typescript": "^5.8.2"
15+
}
16+
}

S25/vignettes/apr1/src/branding.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
export {}
2+
3+
/* Here is one thing we could do. In Java, we could just create a
4+
new class for each, probably a record with only one argument.
5+
Then its nominal type system would see the error. In TypeScript,
6+
we need to force its structural type system to see the two kinds
7+
of IDs as different somehow.
8+
9+
Enter: "branding".
10+
*/
11+
12+
type StudentId = (string & {readonly _StudentId: unique symbol})
13+
interface Student {
14+
id: StudentId,
15+
studentName: string,
16+
concentration: string
17+
}
18+
19+
type CourseId = (string & {readonly _CourseId: unique symbol})
20+
interface Course {
21+
id: CourseId,
22+
name: string,
23+
enrollment: Set<Student>
24+
}
25+
26+
/** The registrar maps student IDs to the number of credits taken. */
27+
type RegistrarCredits = {[id: StudentId]: number}
28+
let registrar: RegistrarCredits = {}
29+
/** ...and is told to give credit by invoking this function (which
30+
in reality would return a promise...) */
31+
function registrarGiveCredit(studentId: StudentId) {
32+
registrar[studentId] = registrar[studentId] + 1
33+
}
34+
35+
/** The course is over, and, to keep the example simple all students
36+
* enrolled passed. Great! Let's give them credit. */
37+
function courseFinished(c: Course) {
38+
c.enrollment.forEach((s: Student) => {
39+
console.log(`Congratulations ${s}.`)
40+
registrarGiveCredit(c.id) // ERROR! Huzzah
41+
})}
42+
43+
44+
45+
/////////////////////////////////////////////////////////////////////
46+
47+
48+
49+
// Whenever we do some type gymnastics, we want to make sure we have
50+
// not made the new type impossible to instantiate!
51+
const nimTelson: Student = {
52+
id: '123',
53+
studentName: "Nim Telson",
54+
concentration: "undeclared"
55+
}
56+
// Uh oh. This shouldn't be surprising: there's no brand in '123'.
57+
// But we also don't want to spend actual memory storing the field...
58+
function makeStudentId(id: string): StudentId {
59+
// Yes! A typecast! But invoking this function "blesses" the use
60+
// of this string as a StudentId
61+
return id as StudentId
62+
}
63+
const nimTelson2: Student = {
64+
id: makeStudentId('123'), // not a "constructor" really.
65+
studentName: "Nim Telson",
66+
concentration: "undeclared"
67+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
Both Java and TypeScript (like most languages, today) are
3+
"call by value". This means that before a function or method
4+
can be called, its arguments need to be evaluated.
5+
6+
There are a few ways this can manifest.
7+
*/
8+
9+
function printTwice(value: number) {
10+
console.log(value)
11+
console.log(value)
12+
}
13+
function halfOf(value: number): number {
14+
console.log(`halfOf called on ${value}`)
15+
return value / 2
16+
}
17+
printTwice(halfOf(100)) // 150
18+
/* We only see "halfOf called on 50" _once_, because the value
19+
of halfOf(100) must be computed before printTwice can be called. */
20+
console.log('----------------------------------')
21+
22+
///////////////////////////////////////////////////////////
23+
24+
/* Maybe that seems obviously right. In this case I think it is, too.
25+
Here's a situation where you might need to do some work, though. */
26+
27+
/**
28+
* Call this function to increment a numeric value.
29+
* @param value The numeric variable to increment
30+
*/
31+
function incrementValue(value: number) {
32+
value++
33+
}
34+
let x = 0
35+
incrementValue(x)
36+
console.log(x)
37+
/* What prints? */

0 commit comments

Comments
 (0)