• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# ArkTS Migration Background
2
3This chapter explains why it makes sense to migrate from the standard TypeScript to
4ArkTS. In general, there are two reasons for doing this:
5
6- Program stability. Dynamically typed languages like JavaScript are very good at
7  allowing programs to write code fast. At the same time, these languages are
8  notorious for unexpected runtime errors. For example, a developer may forget
9  to check some value for `undefined`, and as a result of this, the program
10  may crash, which causes inconvenience to the users. Detecting such issues
11  during development time would be much more beneficial. TypeScript helps greatly
12  here: It allows to annotate the code with types, and many errors will be
13  detected by the compiler, prior to deployment and usage of the code.
14  However, even TypeScript has limitations and sometimes permits to annotate the code
15  with types “loosely”, which still leaves a gap for runtime errors. ArkTS
16  tries to overcome this drawback: It enforces static typing for even stricter
17  type checking and less runtime errors.
18- Program performance. To ensure correctness of the program, dynamically
19  languages have to check actual types of objects when the program actually
20  runs. Back to our example, JavaScript does not allow to read a property from
21  `undefined`. But the only way to check if some value is `undefined` is to
22  perform a runtime check, that all JavaScript engines do: if the value is not
23  `undefined`, the property is read, otherwise an exception is thrown. Modern
24  engines can optimize such checks greatly, but these checks cannot be
25  eliminated completely, which leads to code slowdown. Since the standard TypeScript
26  compiles to JavaScript, the code written in TypeScript has exactly the same issues as
27  described above. ArkTS addresses this problem. Since static typing is
28  enforced, ArkTS compiles the program not to JavaScript, but to some special
29  execution format called bytecode, which is faster to execute and easier to
30  optimize even further.
31
32Below there are a couple of examples that try to explain how ArkTS can help
33improve program stability and performance.
34
35**Explicit Initialization of Fields for Better Stability**
36
37ArkTS requires that all fields are explicitly initialized with some values
38either when the field is declared or in the `constructor`. This is similar
39to `strictPropertyInitialization` mode of the standard TypeScript.
40
41Let’s take a look at the following TypeScript code:
42
43```typescript
44class Person {
45    name: string // Automatically is set to undefined
46
47    setName(n:string): void {
48        this.name = n
49    }
50
51    getName(): string {
52    // Return type "string" hides from the developers the fact
53    // that name can be undefined. The most correct would be
54    // to write the return type as "string | undefined". By doing so
55    // we tell the users of our API about all possible return values.
56        return this.name
57    }
58}
59
60let buddy = new Person()
61// Let's assume that the developer forgets to call setName:
62// buddy.setName("John")
63buddy.getName().length; // runtime exception: name is undefined
64```
65
66Since ArkTS requires explicit initialization, the code looks like this:
67
68```typescript
69class Person {
70    name: string = "" // The field always is defined
71
72    setName(n:string): void {
73        this.name = n
74    }
75
76    // The type is string in all cases, null and undefined are impossible.
77    getName(): string {
78        return this.name
79    }
80}
81
82let buddy = new Person()
83// Let's assume that the developer forgets to call setName:
84// buddys.setName("John")
85buddy.getName().length; // 0, no runtime error
86```
87
88If `name` can be `undefined`, this is also should be specified explicitly:
89
90```typescript
91class Person {
92    name ?: string // The field may be undefined
93
94    setName(n:string): void {
95        this.name = n
96    }
97
98    // Compile-time error:
99    // name can be "undefined", so we cannot say to those who use this API
100    // that it returns only strings:
101    getNameWrong(): string {
102        return this.name
103    }
104
105    getName(): string | undefined { // Return type matches the type of name
106        return this.name
107    }
108}
109
110let buddy = new Person()
111// Let's assume that the developer forgets to call setName:
112// buddy.setName("John")
113
114// Compile-time(!) error: Compiler suspects that we
115// may possibly access something undefined and won't build the code:
116buddy.getName().length; // The code won't build and run
117
118buddy.getName()?.length; // Builds ok, no runtime error
119```
120
121This case demonstrates how we can improve stability and correctness of our
122code by enforcing stricter type checking in ArkTS.
123
124**Null Safety for Better Performance**
125
126Let’s take a look at the following code:
127
128```typescript
129function notify(who: string, what: string) {
130    console.log(`Dear ${who}, a message for you: ${what}`)
131}
132
133notify("Jack", "You look great today")
134```
135
136In most cases, the `notify` function will take two string variables as
137an input and produces a new string. However, what if we pass some “special”
138values to the function, for example `notify(null, undefined)`? The program
139will continue to work, the output will be as expected
140(`Dear undefined, a message for you: null`), so from the first glance
141everything is fine. But please note that the engine that runs our code
142should always check for such special cases to ensure correct behavior. In
143pseudocode, something like this happens:
144
145```typescript
146function __internal_tostring(s: any): string {
147    if (typeof s === "string")
148        return s
149    if (s === undefined)
150        return "undefined"
151    if (s === null)
152        return "null"
153    // ...
154}
155```
156
157Now imagine that our `notify` function is a part of some complex heavy-loaded
158system which sends real notifications instead of just writing to the log. In
159this scenario, executing all these checks from our `__internal_tostring`
160function may turn into a performance problem.
161
162But what if we could somehow guarantee to our exectuion engine that the only
163values that are passed to the `notify` function are “real” strings, but not
164some “special” values like `null` or `undefined`? In this case, checks like
165`__internal_tostring` become redundant because when we execute the program
166we are 100% sure that there will be no corner cases. For this particular case
167this mechanism would be called “null-safety”, i.e. guarantee that `null` is
168not a valid value of the `string` type. If we had such feature, the code
169would not simply build:
170
171```typescript
172function notify(who: string, what: string) {
173    console.log(`Dear ${who}, a message for you: ${what}`)
174}
175
176notify("Jack", "You look great today")
177notify(null, undefined) // Compile-time error
178```
179
180In TypeScript such behavior can be turned on by a special compiler flag called
181`strictNullChecks`. But since the standard TypeScript is compiled to JavaScript, which
182does not have such feature, “strict null checks” work only in compile-time,
183for better type checking. However, ArkTS considers null-safety a very
184important feature from both stability and performance points of view. That’s
185why it is enforced in the language and the example above always produces
186compile-time errors. In exchange, we give our running engine much more
187information and guarantees about possible type values, which helps better
188optimize performance.
189