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 16 17**Figure 2** Pass-by-copy of serialized data 18 19 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