1# Sendable Development
2
3## Basic Concepts
4
5### Sendable Protocol
6
7The Sendable protocol defines the sendable object system and its specifications of ArkTS. Data that complies with the Sendable protocol (referred to as [sendable data](#sendable-data-types)) can be passed between ArkTS concurrent instances.
8
9By default, sendable data is passed by reference between ArkTS concurrent instances (including the main thread and the worker thread of TaskPool or Worker) and is allocated in the shared heap. Pass-by-copy is also supported. Non-sendable data is allocated in the local heap, which is private.
10
11Data races may occur when multiple concurrent instances attempt to update mutable sendable data at the same time. To address this issue, ArkTS introduces the asynchronous lock.
12
13**Figure 1** Sendable data and shared heap
14
15![Sendable](figures/sendable.png)
16
17**Figure 2** Pass-by-copy of serialized data
18
19![Serialize](figures/serialize.png)
20
21**Example**
22
23```ts
24import { taskpool, worker } from '@kit.ArkTS';
25
26@Sendable
27class A {}
28
29let a: A = new A();
30
31@Concurrent
32function foo(a: A) {}
33let task: taskpool.Task = new taskpool.Task(foo, a)
34
35let w = new worker.ThreadWorker("entry/ets/workers/Worker.ets")
36
37// 1. Implementation of TaskPool pass-by-sharing
38taskpool.execute(task).then(() => {})
39
40// 2. Implementation of Worker pass-by-sharing
41w.postMessageWithSharedSendable(a)
42
43// 3. Implementation of TaskPool pass-by-copy
44task.setCloneList([a])
45taskpool.execute(task).then(() => {})
46
47// 4. Implementation of Worker pass-by-copy
48w.postMessage(a)
49```
50
51
52### Sendable Class
53
54> **NOTE**
55>
56> Since API version 11, the @Sendable decorator can be used to verify the sendable class.
57
58A sendable class must meet the following requirements:
591. Be marked by and only by the [@Sendable decorator](#sendable-decorator-declaring-and-verifying-a-sendable-class).
602. Meet the [sendable usage rules](#sendable-usage-rules).
61
62### Sendable Function
63
64> **NOTE**
65>
66> Since API version 12, the @Sendable decorator can be used to verify the sendable function.
67>
68> To use a sendable function in API version 12, you must configure "compatibleSdkVersionStage": "beta3" in the project. Otherwise, the function does not take effect. For details, see [build-profile.json5](https://developer.huawei.com/consumer/en/doc/harmonyos-guides-V5/ide-hvigor-build-profile-V5).
69
70A sendable function must meet the following requirements:
711. Be marked by and only by the [@Sendable decorator](#sendable-decorator-declaring-and-verifying-a-sendable-function).
722. Meet the [sendable usage rules](#sendable-usage-rules).
73
74### Sendable Interface
75A sendable interface must meet the following requirements:
761. Be [ISendable](#isendable) or inherit from [ISendable](#isendable).
772. Meet the [sendable usage rules](#sendable-usage-rules).
78
79
80### Sendable Data Types
81
82- All basic ArkTS data types: boolean, number, string, bigint, null, and undefined.
83- Container type defined in the ArkTS common library. In this case, [@arkts.collections](../reference/apis-arkts/js-apis-arkts-collections.md) must be explicitly imported.
84- **AsyncLock** object defined in the ArkTS common library. In this case, [@arkts.utils](../reference/apis-arkts/js-apis-arkts-utils.md) must be explicitly imported.
85- Interfaces that inherit [ISendable](#isendable).
86- Class marked with the [@Sendable decorator](#sendable-decorator-declaring-and-verifying-a-sendable-class).
87- Function marked with the [@Sendable decorator](#sendable-decorator-declaring-and-verifying-a-sendable-function).
88- System objects that have accessed the Sendable class. For details, see [Sendable System Objects](arkts-sendable-system-object-list.md).
89- Elements whose union type data is of the sendable type.
90
91> **NOTE**
92>
93> - JS built-in objects are passed between concurrent instances in compliance with the structured clone algorithm, and the semantics is passed by copy. Therefore, the instance of a JS built-in object is not of the sendable type.
94>
95> - Object literals and array literals are passed between concurrent instances in compliance with the structured clone algorithm, and the semantics is passed by copy. Therefore, object literals and array literals are not of the sendable type.
96>
97> - For details about the behavior differences between ArkTS collections APIs and native APIs, see [Behavior Differences](arkts-collections-vs-native-api-comparison.md).
98
99
100### ISendable
101
102The interface **ISendable {}** is introduced to the ArkTS common library [@arkts.lang](../reference/apis-arkts/js-apis-arkts-lang.md) without any necessary method or property. **ISendable** is the parent type of all sendable types except null and undefined. **ISendable** is mainly used when you want to customize the sendable data struct. The class decorator [@Sendable](#sendable-decorator-declaring-and-verifying-a-sendable-class) is the syntax sugar for implementing **ISendable**.
103
104
105##  \@Sendable Decorator: Declaring and Verifying a Sendable Class
106
107### Decorator Description
108| \@Sendable Decorator        | Description                                                                  |
109| ------------------------- | ---------------------------------------------------------------------- |
110| Decorator parameters                | None.                                                                  |
111| Use scenario restrictions              | The decorator can be used only in projects of the stage model. It can be used only in .ets files.                   |
112| Inheritance relationship restrictions for decorated classes       | A sendable class can inherit only from another sendable class. A common class cannot inherit from a sendable class. |
113| Property type restrictions for decorated objects | 1. The following types are supported: string, number, boolean, bigint, null, undefined, Sendable class, collections.Array, collections.Map, and collections.Set.<br>2. Closure variables are not allowed.<br>3. Private properties must be defined using **private**, rather than the number sign (#).<br>4. Computed properties are not supported.          |
114| Other property restrictions for decorated objects| Member properties must be explicitly declared and initialized. They cannot be followed by exclamation marks (!).|
115| Method parameters restrictions for decorated objects | Local variables, input parameters, and variables imported through **import** are supported. Closure variables are not allowed.          |
116| Sendable class restrictions     | Properties cannot be added or deleted, but can be modified. The property types before and after the modification must be the same. Methods cannot be modified.  |
117| Use scenario                 | 1. The class methods can be used in TaskPool or Worker.<br>2. The sendable type is used when a large amount of data needs to be transmitted.        |
118
119
120### Decorator Example
121
122```ts
123@Sendable
124class SendableTestClass {
125  desc: string = "sendable: this is SendableTestClass ";
126  num: number = 5;
127  printName() {
128    console.info("sendable: SendableTestClass desc is: " + this.desc);
129  }
130  get getNum(): number {
131    return this.num;
132  }
133}
134```
135
136##  \@Sendable Decorator: Declaring and Verifying a Sendable Function
137
138### Decorator Description
139| \@Sendable Decorator        | Description                                                                  |
140| ------------------------- | ---------------------------------------------------------------------- |
141| Decorator parameters                | None.                                                                  |
142| Use scenario restrictions              | The decorator can be used only in projects of the stage model. It can be used only in .ets files.                   |
143| Restrictions for decorated function types         | Only common functions and async functions can be decorated by @Sendable. |
144| Restrictions for the decorated function body           | Do not use closure variables, except the sendable class and sendable function defined at the top layer.|
145| Sendable function restrictions   | Properties cannot be added, deleted, or modified.  |
146| Use scenario                 | 1. The sendable function can be used in TaskPool or Worker.<br>2. The sendable type is used when a large amount of data needs to be transmitted.|
147
148
149### Decorator Example
150
151```ts
152@Sendable
153type SendableFuncType = () => void;
154
155@Sendable
156class TopLevelSendableClass {
157  num: number = 1;
158  PrintNum() {
159    console.info("Top level sendable class");
160  }
161}
162
163@Sendable
164function TopLevelSendableFunction() {
165  console.info("Top level sendable function");
166}
167
168@Sendable
169function SendableTestFunction() {
170  const topClass = new TopLevelSendableClass (); // Top-level sendable class.
171  topClass.PrintNum();
172  TopLevelSendableFunction (); // Top-level sendable function.
173  console.info("Sendable test function");
174}
175
176@Sendable
177class SendableTestClass {
178  constructor(func: SendableFuncType) {
179    this.callback = func;
180  }
181  callback: SendableFuncType; // Top-level sendable function.
182
183  CallSendableFunc() {
184    SendableTestFunction (); // Top-level sendable function.
185  }
186}
187
188let sendableClass = new SendableTestClass(SendableTestFunction);
189sendableClass.callback();
190sendableClass.CallSendableFunc();
191```
192
193## Sendable Usage Rules
194
195### 1. A sendable class can inherit only from another sendable class.
196
197> **NOTE**
198>
199> The class here does not include variables. In other words, a sendable class cannot inherit from a variable.
200
201**Positive example:**
202```ts
203@Sendable
204class A {
205  constructor() {
206  }
207}
208
209@Sendable
210class B extends A {
211  constructor() {
212    super()
213  }
214}
215```
216
217**Negative example:**
218```ts
219class A {
220  constructor() {
221  }
222}
223
224@Sendable
225class B extends A {
226  constructor() {
227    super()
228  }
229}
230```
231
232### 2. A non-sendable class can inherit only from a non-sendable class.
233
234**Positive example:**
235```ts
236class A {
237  constructor() {
238  }
239}
240
241class B extends A {
242  constructor() {
243    super()
244  }
245}
246```
247
248**Negative example:**
249```ts
250@Sendable
251class A {
252  constructor() {
253  }
254}
255
256class B extends A {
257  constructor() {
258    super()
259  }
260}
261```
262
263### 3. A non-sendable class can implement only a non-sendable interface.
264
265**Positive example:**
266```ts
267interface I {};
268
269class B implements I {};
270```
271
272**Negative example:**
273```ts
274import { lang } from '@kit.ArkTS';
275
276type ISendable = lang.ISendable;
277
278interface I extends ISendable {};
279
280class B implements I {};
281```
282
283### 4. The member variables of a sendable class or interface must be of a sendable data type.
284
285**Positive example:**
286```ts
287@Sendable
288class A {
289  constructor() {
290  }
291  a: number = 0;
292}
293```
294
295**Negative example:**
296```ts
297@Sendable
298class A {
299  constructor() {
300  }
301  b: Array<number> = [1, 2, 3] // collections.Array must be used.
302}
303```
304
305### 5. The member variables of a sendable class or interface cannot use the exclamation mark (!) for assertion.
306
307**Positive example:**
308```ts
309@Sendable
310class A {
311  constructor() {
312  }
313  a: number = 0;
314}
315```
316
317**Negative example:**
318```ts
319@Sendable
320class A {
321  constructor() {
322  }
323  a!: number;
324}
325```
326
327### 6. The member variables of a sendable class or interface do not support computed property names.
328
329**Positive example:**
330```ts
331@Sendable
332class A {
333    num1: number = 1;
334    num2: number = 2;
335    add(): number {
336      return this.num1 + this.num2;
337    }
338}
339```
340
341**Negative example:**
342```ts
343enum B {
344    b1 = "bbb"
345}
346@Sendable
347class A {
348    ["aaa"]: number = 1; // ["aaa"] is allowed in other classes in ets files
349    [B.b1]: number = 2; // [B.b1] is allowed in other classes in ets files
350}
351```
352
353### 7. The template type of a sendable class, collections.Array, collections.Map, and collections.Set in the generic class must be Sendable.
354
355**Positive example:**
356```ts
357import { collections } from '@kit.ArkTS';
358
359try {
360  let arr1: collections.Array<number> = new collections.Array<number>();
361  let num: number = 1;
362  arr1.push(num)
363} catch (e) {
364  console.error(`taskpool execute: Code: ${e.code}, message: ${e.message}`);
365}
366```
367
368**Negative example:**
369```ts
370import { collections } from '@kit.ArkTS';
371
372try {
373  let arr1: collections.Array<Array<number>> = new collections.Array<Array<number>>();
374  let arr2: Array<number> = new Array<number>()
375  arr2.push(1)
376  arr1.push(arr2)
377} catch (e) {
378  console.error(`taskpool execute: Code: ${e.code}, message: ${e.message}`);
379}
380```
381
382### 8. Variables defined in the context of the current module cannot be used in a sendable class.
383
384Because the context of a sendable object varies among concurrent instances, direct access may cause unexpected behavior. A sendable object cannot use the variables defined in the context of the current module. Otherwise, a compile-time error is reported.
385
386> **NOTE**
387>
388> Since API version 12, a sendable class object of the top level can be used internally by the sendable class itself.
389
390**Positive example:**
391```ts
392import { lang } from '@kit.ArkTS';
393
394type ISendable = lang.ISendable;
395
396interface I extends ISendable {}
397
398@Sendable
399class B implements I {
400  static o: number = 1;
401  static bar(): B {
402    return new B();
403  }
404}
405
406@Sendable
407class C {
408  v: I = new B();
409  u: number = B.o;
410
411  foo() {
412    return B.bar();
413  }
414}
415```
416
417**Negative example:**
418```ts
419import { lang } from '@kit.ArkTS';
420
421type ISendable = lang.ISendable;
422
423interface I extends ISendable {}
424
425@Sendable
426class B implements I {}
427
428function bar(): B {
429  return new B();
430}
431
432let b = new B();
433
434{
435  @Sendable
436  class A implements I {}
437
438  @Sendable
439  class C {
440    u: I = bar(); // bar is not a sendable class object. A compile-time error is reported.
441    v: I = new A(); // A is not defined in the top level. A compile-time error is reported.
442
443    foo() {
444      return b; // b is not a sendable class object but an instance of the sendable class. A compile-time error is reported.
445    }
446  }
447}
448
449```
450
451### 9. A sendable class and sendable function can only use the @Sendable decorator.
452
453If the class decorator is defined in a .ts file, any modification to the class layout causes a runtime error.
454
455**Positive example:**
456```ts
457@Sendable
458class A {
459  num: number = 1;
460}
461```
462
463**Negative example:**
464```ts
465@Sendable
466@Observed
467class C {
468  num: number = 1;
469}
470```
471
472### 10. The Sendable type cannot be initialized using an object literal or array literal.
473
474A sendable data type can be created only by using the **new** expression of the Sendable type.
475
476**Positive example:**
477```ts
478import { collections } from '@kit.ArkTS';
479
480let arr1: collections.Array<number> = new collections.Array<number>(1, 2, 3); // The type is Sendable.
481```
482
483**Negative example:**
484```ts
485import { collections } from '@kit.ArkTS';
486
487let arr2: collections.Array<number> = [1, 2, 3]; // The type is not Sendable. A compile-time error is reported.
488let arr3: number[] = [1, 2, 3]; // The type is not Sendable. No error is reported.
489let arr4: number[] = new collections.Array<number>(1, 2, 3); // A compile-time error is reported.
490```
491
492### 11. A non-sendable type cannot be converted to a sendable type using **as**.
493
494> **NOTE**
495>
496> A sendable type must be compatible with a non-sendable type without violating the sendable usage rules. Therefore, a sendable type can be converted to a non-sendable type using **as**.
497
498**Positive example:**
499```ts
500class A {
501  state: number = 0;
502}
503
504@Sendable
505class SendableA {
506  state: number = 0;
507}
508
509let a1: A = new SendableA() as A;
510```
511
512**Negative example:**
513```ts
514class A {
515  state: number = 0;
516}
517
518@Sendable
519class SendableA {
520  state: number = 0;
521}
522
523let a2: SendableA = new A() as SendableA;
524```
525
526### 12. An arrow function is not sendable.
527An arrow function cannot be decorated by @Sendable.
528
529**Positive example:**
530```ts
531@Sendable
532type SendableFuncType = () => void;
533
534@Sendable
535function SendableFunc() {
536  console.info("Sendable func");
537}
538
539@Sendable
540class SendableClass {
541  constructor(f: SendableFuncType) {
542    this.func = f;
543  }
544  func: SendableFuncType;
545}
546
547let sendableClass = new SendableClass(SendableFunc)
548```
549
550**Negative example:**
551```ts
552@Sendable
553type SendableFuncType = () => void;
554let func: SendableFuncType = () => {}; // A compile-time error is reported.
555
556@Sendable
557class SendableClass {
558  func: SendableFuncType = () => {}; // A compile-time error is reported.
559}
560```
561
562### 13. \@Sendable supports type decoration for functions only.
563The @Sendable decorator supports type decoration for functions only.
564
565**Positive example:**
566```ts
567@Sendable
568type SendableFuncType = () => void;
569```
570
571**Negative example:**
572```ts
573@Sendable
574type A = number; // A compile-time error is reported.
575
576@Sendable
577class C {}
578
579@Sendable
580type D = C; // A compile-time error is reported.
581```
582
583## Precautions
584
585When using **Sendable** in HAR, enable the configuration of generating TS files. For details, see [Building TS Files](../quick-start/har-package.md#building-ts-files).
586
587## Rules for Interaction with TS/JS
588
589### ArkTS General Rules (Only for Sendable Objects Currently)
590
591| Rule Description       |
592| ----------- |
593| When a sendable object is passed to a TS/JS interface, the object layout cannot be operated (adding or deleting properties, or changing property types).|
594| When a sendable object is set to a TS/JS object, the object layout cannot be operated (adding or deleting properties, or changing property types) after the TS/JS object obtains the sendable object.|
595| When a sendable object is placed in a TS/JS container, the object layout cannot be operated (adding or deleting properties, or changing property types) after the TS/JS object obtains the sendable object.|
596
597> **NOTE**
598>
599> Changes of the property types do not include changes of the sendable object types, for example, from Sendable class A to Sendable class B.
600
601
602### Native API Rules (Only for Sendable Objects Currently)
603
604| Rule Description       |
605| ----------- |
606| Do not delete properties. The **napi_delete_property** interface cannot be used.|
607| Do not add properties. The following interfaces cannot be used: **napi_set_property**, **napi_set_named_property**, and **napi_define_properties**.	|
608| Do not modify property types. The following interfaces cannot be used: **napi_set_property**, **napi_set_named_property**, and **napi_define_properties**.|
609| Symbol-related interfaces and types are not supported. The following interfaces cannot be used: **napi_create_symbol**, **napi_is_symbol_object**, and **napi_symbol**.|
610
611
612## When to Use
613
614Sendable objects can be passed by reference between concurrent instances. Compared with serialization, pass-by-reference is more efficient and does not cause the loss of member methods carried in the class. The sendable mode is used in the following scenarios:
6151. Transferring a large amount of data (for example, more than 100 KB) across concurrent instances
6162. Passing a class instance object carrying methods across concurrent instances
617
618### Transferring a Large Amount of Data Across Concurrent Instances
619
620The overhead of serialization across concurrent instances increases linearly with the data volume. When a large amount of data is transmitted (100 KB data takes about 1 ms to transmit), the overhead of data copy across concurrent instances is high, adversely affecting the parallelization performance. On the contrary, passing objects by reference improves performance.
621
622**Example**
623```ts
624// index.ets
625import { taskpool } from '@kit.ArkTS';
626import { testTypeA, testTypeB, Test } from './sendable'
627
628// Simulate data processing in a concurrent function.
629@Concurrent
630async function taskFunc(obj: Test) {
631  console.info("test task res1 is: " + obj.data1.name + " res2 is: " + obj.data2.name);
632}
633
634async function test() {
635  // Use TaskPool for data transfer.
636  let a: testTypeA = new testTypeA("testTypeA");
637  let b: testTypeB = new testTypeB("testTypeB");
638  let obj: Test = new Test(a, b);
639  let task: taskpool.Task = new taskpool.Task(taskFunc, obj);
640  await taskpool.execute(task);
641}
642
643test();
644```
645
646```ts
647// sendable.ets
648// Assemble the data of a large size in a sendable class.
649@Sendable
650export class testTypeA {
651  name: string = "A";
652  constructor(name: string) {
653    this.name = name;
654  }
655}
656
657@Sendable
658export class testTypeB {
659  name: string = "B";
660  constructor(name: string) {
661    this.name = name;
662  }
663}
664
665@Sendable
666export class Test {
667  data1: testTypeA;
668  data2: testTypeB;
669  constructor(arg1: testTypeA, arg2: testTypeB) {
670    this.data1 = arg1;
671    this.data2 = arg2;
672  }
673}
674```
675
676
677### Passing a Class Instance Object Carrying Methods Across Concurrent Instances
678
679Methods will be lost during serialization of instance objects. In scenarios where instance methods must be called, use pass-by-reference. If data needs to be parsed during data processing, use the [ASON tool](../reference/apis-arkts/js-apis-arkts-utils.md#arktsutilsason).
680
681**Example**
682```ts
683// Index.ets
684import { taskpool, ArkTSUtils } from '@kit.ArkTS'
685import { SendableTestClass, ISendable } from './sendable'
686
687// Simulate data processing in a concurrent function.
688@Concurrent
689async function taskFunc(sendableObj: SendableTestClass) {
690  console.info("SendableTestClass: name is: " + sendableObj.printName() + ", age is: " + sendableObj.printAge() + ", sex is: " + sendableObj.printSex());
691  sendableObj.setAge(28);
692  console.info("SendableTestClass: age is: " + sendableObj.printAge());
693
694  // Parse the sendableObj.arr data to generate a JSON string.
695  let str = ArkTSUtils.ASON.stringify(sendableObj.arr);
696  console.info("SendableTestClass: str is: " + str);
697
698  // Parse the data and generate ISendable data.
699  let jsonStr = '{"name": "Alexa", "age": 23, "sex": "female"}';
700  let obj = ArkTSUtils.ASON.parse(jsonStr) as ISendable;
701  console.info("SendableTestClass: type is: " + typeof obj);
702  console.info("SendableTestClass: name is: " + (obj as object)?.["name"]); // output: 'Alexa'
703  console.info("SendableTestClass: age is: " + (obj as object)?.["age"]); // output: 23
704  console.info("SendableTestClass: sex is: " + (obj as object)?.["sex"]); // output: 'female'
705}
706async function test() {
707  // Use TaskPool for data transfer.
708  let obj: SendableTestClass = new SendableTestClass();
709  let task: taskpool.Task = new taskpool.Task(taskFunc, obj);
710  await taskpool.execute(task);
711}
712
713test();
714```
715
716```ts
717// sendable.ets
718// Define a Test class to simulate the transfer of a class carrying methods.
719import { lang, collections  } from '@kit.ArkTS'
720
721export type ISendable = lang.ISendable;
722
723@Sendable
724export class SendableTestClass {
725  name: string = 'John';
726  age: number = 20;
727  sex: string = "man";
728  arr: collections.Array<number> = new collections.Array<number>(1, 2, 3);
729  constructor() {
730  }
731  setAge(age: number) : void {
732    this.age = age;
733  }
734
735  printName(): string {
736    return this.name;
737  }
738
739  printAge(): number {
740    return this.age;
741  }
742
743  printSex(): string {
744    return this.sex;
745  }
746}
747```
748