Cangjie Programming Language White Paper
Author: Cangjie Language Team, Compilers & Programming Languages Lab, Huawei Technologies Co., Ltd.
With the advent of the Internet of Everything (IoE) and intelligent era, the form of software will change greatly. On the one hand, mobile applications and mobile Internet are still driving innovations in human-machine interaction, device collaboration, intelligence, and security. On the other hand, AI is also driving software to evolve towards intelligence and device-edge-cloud synergy. The development of application software in new technologies and scenarios poses new requirements and challenges to programming languages.
The Cangjie programming language is a modern programming language oriented to all-scenario application development. It provides developers with friendly development experience and excellent program performance through integration of modern language features, comprehensive compilation optimization, runtime implementation, and out-of-the-box IDE toolchain support. The specific features are as follows:
-
Efficient programming: For application development, the Cangjie language is easy to learn and use, which reduces the entry threshold and workload of developers during development and supports various common development paradigms and programming modes, so that developers can express various service logics in a simple and efficient manner. The Cangjie language is a multi-paradigm programming language that supports multiple paradigms such as functional paradigm, imperative paradigm, and object-oriented paradigm, and features such as value types, classes and interfaces, generics, algebraic data types, pattern matching, and higher-order functions. In addition, the Cangjie language supports type inference, which reduces the workload of type annotation for developers. The Cangjie language has a series of concise and efficient syntax, which reduces redundant writing and improves development efficiency. Various syntax sugar and macros built in the Cangjie language help developers quickly develop domain-specific languages (DSLs) to build domain abstractions.
-
Secure and reliable: As a modern programming language, the Cangjie language pursues real-time coding security. The static type system and automatic memory management are used to ensure programs' type security and memory security such as null safety. In addition, the Cangjie language provides various runtime checks, including array index out-of-bounds check, type conversion check, value calculation overflow check, and character string encoding validity check, to detect errors during program running in a timely manner. In addition, code scanning tools, obfuscation tools, and sterilizers are used to further support cross-language interoperability security and code asset protection.
-
Easy concurrency: Concurrent and asynchronous programming can effectively improve processor utilization and ensure program response speed in interactive applications, which is an indispensable capability in application development. The Cangjie language implements lightweight user-level threads and concurrent object libraries, making efficient concurrency easy. The Cangjie language uses the user-level thread model. Each Cangjie thread is an extremely lightweight execution entity and has an independent execution context but shared memory. For developers, the use of user-level threads is the same as that of traditional system threads, and no extra workload is brought. From the perspective of the runtime state, thread management is completed by the runtime and does not depend on thread management of the operating system. Therefore, operations such as threads' creation, scheduling, and destruction are more efficient, and resource usage of user-level threads is less than that of system threads. To avoid data competition, the Cangjie language provides a concurrent object library. The methods of concurrent objects are thread-safe. Therefore, calling these methods in multiple threads is the same as serial programming. Developers for application logic do not need to pay attention to concurrency management. For some core libraries, the Cangjie language also provides lock-free or fine-grained lock algorithm implementations to further reduce thread blocking and improve concurrency.
-
Excellent performance: The Cangjie compiler and runtime optimize the compilation of the full stack, including the high-level compilation optimization (such as semantic-aware loop optimization and semantic-aware back-end collaboration optimization) based on the Cangjie HighLevel IR (CHIR) for the compiler front-end, compilation optimization (such as SLP vectorization, Intrinsic optimization, InlineCache, interprocedural pointer optimization, and Barrier optimization) for the compiler back-end, and runtime optimization (such as lightweight lock, distributed marking, and concurrent Tracing optimization). The series of optimizations enable the Cangjie language to fully utilize the processor capability and provide excellent performance support for applications. In addition, the Cangjie language implements native lightweight design for the runtime. By modular and layered design of the runtime, the Cangjie common object models and the common basic components of the runtime are defined. Based on the common object models, basic capabilities such as memory management, stack return, exception handling, and cross-language calling during runtime are implemented, the redundant object design between multiple capabilities is greatly reduced, and the volume during runtime is reduced. In addition, the technology of loading packages by demands is used to reduce the memory overhead of redundant packages for starting Cangjie applications. Therefore, for resource-sensitive devices, less resources are occupied and the support is more user-friendly.
In addition, the Cangjie language supports a series of tool chains for application development, including language services (highlighting and association), debugging (cross-language debugging and thread-level visualized debugging), static checks, performance analysis, package management, document generation, mock tools, test frameworks, coverage tools, fuzz tools, and intelligent auxiliary programming tools, further improving software development experience and efficiency. The following describes the main features of the Cangjie language from the preceding aspects, helping readers quickly understand the positioning and main technical features of the Cangjie language.
Efficient Programming
The Cangjie language supports multiple programming paradigms, including object-oriented, functional, and imperative programming paradigms. It not only supports the modularization and flexibility of object-oriented programming, but also the simplicity and high-abstract level expression of functional programming, allowing developers to select the most appropriate paradigm based on their requirements so that they can develop code in a simple and efficient manner.
In addition, the Cangjie language has learned from many excellent language features in modern languages, including various declarative syntaxes and syntax sugars. In addition to making programming in common scenarios simpler, the Cangjie language can also quickly design a domain-specific language (DSL) for specific scenarios to improve domain usability.
Multi-Paradigm
The Cangjie language is a typical multi-paradigm programming language. It provides support for procedural programming, object-oriented programming, and functional programming, covering value types, classes and interfaces, generics, algebraic data types, and pattern matching, and for features such as treating functions as first-class citizens.
Classes and Interfaces
Cangjie supports object-oriented paradigm programming using traditional classes and interfaces. The Cangjie language supports only single inheritance. Each class has only one parent class, but can implement multiple interfaces. Each class is a subclass (direct subclass or indirect subclass) of Object. In addition, all Cangjie types (including Object) implicitly implement the Any interface.
Cangjie provides the open modifier to control whether a class can be inherited or whether an object member function can be overridden by a subclass.
In the following example, class B inherits class A and implements interfaces I1 and I2. The declaration of class A must be modified by open so that class A can be inherited. Function f in class A is also modified by open and can be overridden in class B. For a call of function f, the version to be executed is determined based on the object type, which is called dynamic dispatch.
open class A {
let x: Int = 1
var y: Int = 2
open func f(){
println("function f in A")
}
func g(){
println("function g in A")
}
}
interface I1 {
func h1()
}
interface I2 {
func h2()
}
class B <: A & I1 & I2 {
override func f(){
println("function f in B")
}
func h1(){
println("function h1 in B")
}
func h2(){
println("function h2 in B")
}
}
main() {
let o1: I1 = B()
let o2: A = A()
let o3: A = B()
o1.h1() // "function h1 in B"
o2.f() // "function f in A"
o3.f () // Dynamic dispatch, "function f in B"
o3.g() // "function g in A"
}
Cangjie interfaces can inherit each other and are not restricted by single inheritance. That is, one interface can inherit multiple parent interfaces. In the following example, I3 can inherit both I1 and I2. Therefore, implementations of functions f, g, and h must be provided to implement I3.
interface I1 {
func f(x: Int): Unit
}
interface I2 {
func g(x: Int): Int
}
interface I3 <: I1 & I2 {
func h(): Unit
}
Treating Functions as First-Class Citizens
In Cangjie, a function can be used as a common expression, passed as a parameter, used as a function return value, stored in other data structures, or used to assign a value to a variable.
func f(x: Int) {
return x
}
let a = f
let square = {x: Int = > x * x} // Lambda expression
// Defines nested functions and uses these functions as return values.
func g(x: Int): () -> Int {
func h(){
return f(square(x))
}
return h
}
func h(f: ()->Int) {
f()
}
let b = h(g(100))
In addition to the global functions in the preceding example, member functions of data types such as object or struct can also be used as first-class citizens. In the following example, the member function resetX of object o, as a common expression, is assigned to variable f. The call of f changes the value of member variable x in object o.
class C{
var x = 100
func resetX(n: Int){
x = n
return x
}
}
main(){
let o = C()
let f = o.resetX // Treats the member function as a first-class citizen.
f(200)
print(o.x) // 200
}
Algebraic Data Types and Pattern Matching
An algebraic data type is a composite type that consists of other data types. Two common algebraic types are product type (such as struct and tuple) and sum type (such as tagged union).
The following focuses on the sum type enum in Cangjie and the corresponding pattern matching capability.
In the following example, BinaryTree of the enum type has two constructors: Node and Empty. Empty does not have any parameter, and corresponds to a binary tree with only one empty node. Node requires three parameters to construct a binary tree with one value and left and right subtrees.
enum BinaryTree {
| Node(Int, BinaryTree, BinaryTree)
| Empty
}
Before being accessed, the values of these enum instances must be parsed using pattern matching. Pattern matching is a method for testing whether an expression has a specific feature. Cangjie provides the match expression to implement this method. For a given expression of the enum type, the match expression is used to determine which constructor is used to construct the given expression and to extract the parameters of the corresponding constructor. In the following example, the recursive function sumBinaryTree is used to sum the integers stored in the binary tree node.
func sumBinaryTree(bt: BinaryTree): Int {
match (bt) {
case Node(v, l, r) =>
v + sumBinaryTree(l) + sumBinaryTree(r)
case Empty => 0
}
}
In addition to the enum mode, Cangjie provides the constant mode, binding mode, type mode, and nested use of various modes. The following example describes the use of the modes provided by Cangjie.
- Constant mode: Use multiple literal values, such as integers and strings, for equality check.
- Binding mode: Bind a member at a specified location to a new variable. This mode is mainly used to deconstruct instances of the enum or tuple type. In the preceding example of
sumBinaryTree, the binding mode is used to bind the actual parameters in theNodenode to the three newly declared variablesv,l, andr. - Type mode: Check the subtype relationship between the variable type and target type. This mode is mainly used to convert a type to its subtype.
- Tuple mode: Compare or deconstruct instances of the tuple type.
- Wildcard mode: Match any value.
Cangjie plans to introduce more modes in the future, such as sequence mode and record mode.
// Constant mode: string literal
func f1(x: String) {
match (x) {
case "abc" => ()
case "def" => ()
case _ => () // Wildcard mode
}
}
// tuple mode
func f2(x: (Int, Int)) {
match (x) {
case (_, 0) => 0 // Wildcard mode and constant mode
case (i, j) => i / j // Binding mode, in which the element of **x** is bound to variables **i** and **j**
}
}
// Type mode
func f3(x: ParentClass) {
match (x) {
case y: ChildClass1 => ...
case y: ChildClass2 => ...
case _ => ...
}
}
Generics
In modern software development, generic programming has become a key technology to improve code quality, reusability, and flexibility. As a parameterized and polymorphic technology, generics allows developers to use types as parameters when defining types or functions to create common code structures that apply to different data types. The benefits of generics include:
- Code reuse: Common algorithms and data structures used to perform operations on different types can be defined to reduce code redundancy.
- Type security: More type checks during compilation are supported to prevent type errors during running, thereby enhancing program stability.
- Performance improvement: Program execution efficiency can be improved by avoiding unnecessary type conversion.
Cangjie supports generic programming. Generic variables can be introduced to functions, structs, classes, interfaces, and extends to implement function generalization. The array type is typical generic type application in Cangjie. Its syntax is Array<T>, where T indicates the element type and can be instantiated as any specific type, for example, Array<Int> or Array<String>, or even a nested array Array<Array<Int>>, so that arrays of different element types can be easily constructed.
In addition to types, generic functions can also be defined. For example, a generic function can be used to implement the concat operation on any two arrays of the same type. As shown in the following code, a generic function concat is defined which supports any two array parameters of the Array<T> type. After processing, and a new array is returned. In this way, the concat function can be applied to arrays of any type besides Array<Int>, Array<String>, and Array<Array<Int>>.
func concat<T>(lhs: Array<T>, rhs: Array<T>): Array<T> {
let defaultValue = if (lhs.size > 0) {
lhs[0]
} else if (rhs.size > 0) {
rhs[0]
} else {
return []
}
let newArr = Array<T>(lhs.size + rhs.size, item: defaultValue)
// Copies the entire segment of continuous memory pointed to by the right expression to the entire segment of continuous memory pointed to by the left array slice.
newArr[0..lhs.size] = lhs
newArr[lhs.size..lhs.size+rhs.size] = rhs
return newArr
}
The combination of generics, interfaces, and subtypes enables specific constraints on type variables in generics, thereby limiting the types that can be filled in the type variables. In the following example, the element element needs to be searched for in the array arr. Although the specific types of the array and its elements are not considered, the element type T must support operations such as equality check to check whether any element in the array is equal to the given element. Therefore, in the where clause of the lookup function, T <: Equatable<T>, that is, the type T, must implement the Equatable<T> interface.
func lookup<T>(element: T, arr: Array<T>): Bool where T <: Equatable<T> {
for (e in arr){
if (element == e){
return true
}
}
return false
}
The generic type of Cangjie does not support covariance. For example, arrays containing different types of elements are completely different and do not support value assignment to each other or parent-child relationships between element types. This prevents the type insecurity problem caused by array covariance.
In the following example, Apple is a subclass of Fruit, but value assignment is not supported between variables a and b, and there is no parent-child relationship between Array<Fruit> and Array<Apple>.
open class Fruit {}
class Apple <: Fruit {}
main() {
var a: Array<Fruit> = []
var b: Array<Apple> = []
a = b // Reports a compilation error.
b = a // Reports a compilation error.
}
Type Extension
Cangjie supports type extensions, which allow users to add member functions to a type without changing the original type definition code. Specifically, Cangjie can extend a type by:
- Adding a function
- Adding an attribute
- Adding an overloaded operator
- Implementing an interface
In the following example, the printSize member function is added to the String type. Therefore, the printSize function can be called in the same way as calling other predefined member functions.
extend String {
func printSize() {
print(this.size)
}
}
"123".printSize() // 3
When extensions and interfaces are used together, the language expression capability can be greatly improved. We can even add a new inheritance system to a type.
In the following example, a new interface Integer is defined, and then extend is used to implement the Integer interface for the existing integer types. In this way, the existing integer types become the subtypes of Integer. The sealed modifier indicates that the interface can be implemented (or extended) only in the current package.
sealed interface Integer {}
extend Int8 <: Integer {}
extend Int16 <: Integer {}
extend Int32 <: Integer {}
extend Int64 <: Integer {}
let a: Integer = 123 // ok
Type Inference
Type inference means that the compiler automatically infers the type of a variable or an expression based on the program context, so that a developer does not need to explicitly write the type. As a modern programming language, Cangjie also supports type inference.
In Cangjie, the type of a variable can be inferred based on the type of the initialization expression. In addition to the inference of variable type, Cangjie also supports the inference of the return value type of a function. In Cangjie, the last expression of a function body is regarded as the return value of the function. When the return type is omitted in the function definition, it is inferred based on the return value.
var foo = 123 // foo is 'Int64'.
var bar = 'hello' // bar is 'String'.
func add(a: Int, b: Int) { // add returns Int.
a + b
}
Cangjie also supports the inference of type parameters in a generic function call, including the inference of generic parameters in the Currying function. The following is an example.
func map<T, R>(f: (T)->R): (Array<T>)->Array<R> {
...
}
map({ i => i.toString() })([1, 2, 3]) // Supports the inference of generic parameters in the Currying function.
// The inference result is map<Int, String>({ i => i.toString() })([1, 2, 3]).
Note that the parameter type (T) and return value type (R) of the lambda expression (the first parameter of map) can be inferred, and the inference of the parameter type (T) depends on the inference of the type (Array<T>) of the second parameter of map.
Other Modern Features and Syntactic Sugar
Function Overloading
In the Cangjie language, functions with the same name are supported in the same scope. The compiler determines the function to be executed based on the number and types of parameters. For example, the following absolute value functions provide implementations different numeric types. These implementations have the same function name abs, making function calls easier.
func abs(x: Int64): Int64 { ... }
func abs(x: Int32): Int32 { ... }
func abs(x: Int16): Int16 { ... }
...
Named Parameters
When a function with named parameters is called, in addition to the actual parameter expression, names of the corresponding formal parameters must be provided. Named parameters help improve program readability, reduce the sequence dependency of parameters, and simplify program expansion and maintenance.
In the Cangjie language, developers can define a named parameter by adding ! after the formal parameter name. After a formal parameter is defined as a named parameter, the parameter name must be specified before the actual parameter value when the function is called.
func dateOf(year!: Int, month!: Int, dayOfMonth!: Int) {...}
dateOf(year: 2024, month: 6, dayOfMonth: 21)
Default Value
For functions in Cangjie, default values can be provided for specific formal parameters. When a function is called, if the default value of a parameter is used as the actual parameter, the parameter can be omitted. This feature reduces the need for function overloading or the builder pattern, thereby reducing code complexity.
func dateOf(year!: Int64, month!: Int64, dayOfMonth!: Int64, timeZone!: TimeZone = TimeZone.Local) {
...
}
dateOf(year: 2024, month: 6, dayOfMonth: 21) // ok
dateOf(year: 2024, month: 6, dayOfMonth: 21, timeZone: TimeZone.UTC) // ok
Trailing Lambda
Cangjie supports trailing lambdas, which make it easier to implement specific syntax in DSL. Specifically, many languages provide the following classic built-in conditional judgment or loop code blocks:
if (x > 0) {
x = -x
}
while (x > 0) {
x--
}
Trailing lambda allows DSL developers to customize code block syntax similar to those built in the host language. The following is an example of a function call by using trailing lambda in the Cangjie language:
func unless(condition: Bool, f: ()->Unit) {
if(!condition) {
f()
}
}
let a = f(...)
unless(a > 0) {
print("no greater than 0")
}
The call of the unless function seems to be a special if expression. This syntax effect is implemented by using the trailing lambda syntax. If the last formal parameter of a function is of the function type, when the function is called, a lambda expression can be provided as the actual parameter and written outside the function call parentheses. Especially when the lambda expression is a function without parameters, the double arrows (=>) in the lambda expression can be omitted and represented as code blocks to further reduce the syntactic noise in the corresponding DSL. Therefore, in the preceding example, the second actual parameter in the unless function call becomes the following lambda expression:
{ print("no greater than 0") }
If the function has only one formal parameter which is of the function type, the function call parentheses can be omitted when trailing lambda is used to call the function, making the code simpler and more natural.
func runLater(fn:()->Unit) {
sleep(5 * Duration.Second)
fn()
}
runLater() { // OK
println("I am later")
}
runLater { // The parentheses can be omitted.
println("I am later")
}
Pipeline Operators
Cangjie introduces pipeline operators to simplify the syntax of calling nested functions and to express data flows more intuitively. The following example shows nested function calls and the equivalent expression based on the pipe operator |>. The latter reflects the data flow more intuitively. The value of the expression on the left of |> is transferred as a parameter to the function on the right.
func double(a: Int) {
a * 2
}
func increment(a: Int) {
a + 1
}
double(increment(double(double(5)))) // 42
5 |> double |> double |> increment |> double // 42
Operator Overloading
Cangjie defines a series of operators represented by special characters. Most of the operators can be overloaded and used on types defined by developers, providing simple and intuitive syntax expressions for operations of user-defined types.
In Cangjie, developers only need to define operator overloading functions to implement operator overloading. In the following example, a type Point is defined to represent a point in a two-dimensional plane and the + operator is overloaded to define the addition of the two points.
struct Point {
let x: Int
let y: Int
init(x: Int, y: Int) {...}
operator func +(rhs: Point): Point {
return Point(
this.x + rhs.x,
this.y + rhs.y
)
}
}
let a: Point = ...
let b: Point = ...
let c = a + b
Property
In the object-oriented paradigm, member variables are usually declared as private, and accesses to member variables are encapsulated into two public methods: getter and setter.
In this way, data access details can be hidden, making it easier to implement service policies such as access control, data monitoring, tracing and debugging, and data binding.
Properties, a special kind of syntax, are provided in Cangjie. Like a member variable, a property can be accessed and supports value assignment. In addition, getter and setter methods are provided for various data operations. The access and assignment of values to properties are translated by the compiler into calls of the corresponding getter and setter member functions. Specifically, prop is used to declare a read-only property. A read-only property only supports a getter, and therefore the get implementation must be provided. mut prop is used to declare a mutable property. Mutable properties have a getter and a setter. Therefore, the get and set implementations must be provided.
As shown in the following example, if a developer wants to record accesses to each data member of the Point type, the developer can declare member variables modified by private in the Point type, allow external accesses by declaring the corresponding properties, and use the log system Logger to record access information. For users, using properties of object p is the same as accessing its member variables but with the recording function implemented internally.
In the example, x and y are read-only and therefore only the get implementation is provided. color is declared with mut prop and is variable, therefore both get and set implementations are provided.
class Point {
private let _x: Int
private let _y: Int
private var _color: String
init(x: Int, y: Int, color: String) {...}
prop x: Int {
get() {
Logger.log(level: Debug, "access x")
return _x
}
}
prop y: Int {
get() {
Logger.log(level: Debug, "access y")
return _y
}
}
mut prop color: String {
get() {
Logger.log(level: Debug, "access color")
return _color
}
set(c) {
Logger.log(level: Debug, "reset color to ${c}")
_color = c
}
}
}
main() {
let p = Point(0, 0, "red")
let x = p.x // "access x"
let y = p.y // "access y"
p.color = "green" // "reset color to green"
}
Security and Reliability
The design and implementation of programming languages and the corresponding tools have an important impact on program quality and security. Cangjie uses a static type system, dynamic and static checks, automatic memory management, and tool chain functions to improve program security.
Static Type and Garbage Collection
Cangjie is a statically typed language. The types of all variables and expressions in a program are determined during compilation and do not change during program running. Compared with dynamic type systems, static type systems have more constraints on developers, but they can detect errors in programs as early as possible during compilation, improving program security. In addition, static type systems make behaviors of programs easier to predict, enabling more compilation optimization and improving program performance.
Garbage collection (GC) is an automatic memory management mechanism. It can automatically identify and reclaim objects that are no longer needed, freeing developers from manually releasing memory. This not only improves development efficiency, but also effectively avoids common memory errors, improving program security. Common garbage collection technologies include tracing and reference counting (RC). The Cangjie language uses tracing GC technology to trace reference relationships between objects during run-time to identify active objects and junk objects.
Null Reference Safety
A null reference is a reference with no referent. Null references in code can cause various potential risks. Tony Hoare, a Turing Award winner, calls null references a "billion-dollar mistake".
Null references are one of the most common sources of errors in programming languages. If the language or type system does not guarantee that references are not null, programs may access members of a reference type without ensuring that the reference type is not null, causing errors or exceptions.
Null reference safety aims to eliminate the risk of null references in code.
Cangjie provides null reference safety. In Cangjie, no null value is provided. In other words, the reference types of Cangjie are always non-null. In this way, null references are prevented.
However, the representation of a null value is very useful semantically. In Cangjie, any type T may have a corresponding optional type Option<T>. A variable of type Option<T> may have a null value (None) or correspond to an actual value v of type T (Some(v)).
The optional enum type (Option<T>) is a standard algebraic data type representing a value that may be present or absent.
enum Option<T> {
Some(T) | None
}
var a: Option<Int> = Some(123)
a = None
Note that Option<T> and T are two different types, and values of the two types cannot be converted to each other. Given an expression e of type Option<T>, we can only obtain a value of type T by pattern matching on e and receiving a value v in the Some(v) case. Therefore, any meaningful processing of the expression e needs to be accompanied by pattern matching and a corresponding check for None, so that it is impossible to directly dereference the null value None, thereby avoiding null reference exceptions.
Based on the frequent use of optional types, Cangjie also provides rich syntactic sugar support for them. For example, we can replace Option<T> with ?T, use the optional chaining operator (?.) to simplify member access, and use the null merge operator (??) to merge valid values.
var a: ?Int = None
a?.toString() // None
a ?? 123 // 123
a = Some(321)
a?.toString() // Some("321")
a ?? 123 // 321
Value Type
A value type is a type whose terms are passed by copying. For a variable of value type, the data itself instead of the reference to the data is stored. Due to being passed by copying, value types have simpler semantics with respect to mutation than reference types, making the program more predictable and reliable.
Taking the most common concurrency security problem as an example: When a reference-type object is transferred to a different thread of a program, accessing a field of the object will cause an unpredictable data race. If instead the object has value semantics, it can be ensured that the object is completely copied during transfer, so that each thread accesses the value independently, thereby ensuring concurrency safety.
Cangjie supports value types. In addition to common numeric types, Cangjie also supports implementing user-defined value types via structs.
In the following example, Point is a value type. Therefore, after values are assigned, a and b are independent of each other. The modification of a does not affect b.
struct Point {
var x: Int
var y: Int
init(x: Int, y: Int) { ... }
...
}
var a = Point(0, 0)
var b = a
a.x = 1
print(b.x) // 0
Immutability First
Immutability refers to data that, after being created or assigned, cannot be changed. That is, the data are read-only and unwritable. Therefore, immutable objects are inherently thread-safe, that is, they can be freely accessed on any thread if no special restrictions exist. In addition, unlike with access to mutable objects, access to immutable objects has no side effects. Therefore, in some scenarios, immutable objects make programs easier to understand and provide higher security.
Immutability applies to both variables and types. Immutable variables are variables whose value cannot be changed after being initialized. Immutable types are types whose underlying data cannot be changed after construction.
In Cangjie, variables defined via let are immutable variables, and types such as String and enum-types are immutable types. These are applications of immutable ideas in Cangjie. The use of immutable variables and types can make programs more secure and facilitate understanding and maintenance of programs.
Function Parameters are Immutable
In Cangjie, formal parameters of all functions are immutable, which means that no values can be assigned to formal parameters. Furthermore, if the formal parameter is of a value type, members of the formal parameter cannot be modified.
struct Point {
var x: Int
var y: Int
init(x: Int, y: Int) { ... }
...
}
func f(a: Point) { // **a** is immutable.
a = Point(0, 0) // Error
a.x = 2 // Error
}
New Variables Introduced by Pattern Matching are Immutable
In Cangjie, variables can be bound during pattern matching, but these bound variables are immutable. Furthermore, if the newly bound variable is of a value type, members of the newly bound variable cannot be modified.
func f(a: ?Point) {
match (a) {
case Some(b) => // **b** is immutable.
b = Point(0, 0) // Error
b.x = 2 // Error
case None => ()
}
}
Closures Capturing Mutable Variables Cannot Escape
In Cangjie, a closure is a self-contained function or lambda. A closure can capture variables from its static scope so that those variables can be accessed even when the function is called from a different scope.
In Cangjie, closures can capture mutable variables, but such closures cannot escape their scope. This restriction avoids unexpected behavior caused by modifications of mutable variables.
func f() {
let a = 1
var b = 2
func g() {
print(a) // ok
print(b) // ok
}
return g // Error. **g** captures mutable variable **b**, so **g** cannot be used as an expression.
}
Closed by Default
Although Cangjie fully supports object-orientation and class inheritance, it discourages abuse of inheritance, and in particular does not allow inheritance and overriding by default. Allowing inheritance by default encourages users to use a lot of inheritance and overriding. The mixture of overridden and non-overridden methods results in significant indirection in method definitions, which can make it hard to work out where a particular method is actually defined and what effect changes in base class definitions will have. Ill-thought-out inheritance hierarchies can also impose a rigid taxonomy which is hard to maintain and adapt as requirements and designs change.
For the sake of engineering friendliness, Cangjie adopts a closed-by-default design. That is, one cannot inherit from a class, nor override methods, by default. Developers need to explicitly decide whether their class should be allowed to have subclasses. This constraint reduces the abuse of inheritance.
Class Inheritance not Allowed by Default
In Cangjie, one cannot inherit from classes defined by developers by default. If the developer wants a class to have a subclass, they must explicitly use one of the open, abstract, or sealed modifiers. (These modifiers have slightly different semantics from each other, but all enable inheritance from the modified class.)
class A {}
class B <: A {} // Error. **A** cannot be inherited.
open class C {}
class D <: C {} // OK
Member Method Overriding not Allowed by Default
In Cangjie, one cannot override member methods defined by developers by default. This means that even if a class has a subclass, the subclass cannot modify member methods of the parent class. If you want a member method to be overridable, you must explicitly use open.
open class A {
func f() {}
open func g() {}
}
class B <: A {
override func f() {} // Error. **f** cannot be overridden.
override func g() {} // OK
}
try-with-resources
Cangjie uses try-catch-finally expressions to handle exceptions, as do many common languages. However, Cangjie provides try-with-resources syntax to automatically release non-memory resources.
Unlike with ordinary try-expressions, try-with-resources expressions do not require catch- and finally-blocks. One or more variables can be listed between the try keyword and the subsequent block to make these resource objects be automatically managed in the try-with-resources expression. When a resource exception occurs or control leaves the try-with-resources expression, the resource objects are automatically released to ensure resource security.
In the following example, the input and output variables are automatically managed in the try-with-resources expression. As such, the developer never needs to pay attention to resource release.
try (input = MyResource(),
output = MyResource()) {
while (input.hasNextLine()) {
let lineString = input.readLine()
output.writeLine(lineString)
}
}
The resource object type (MyResource in the preceding example) must implement the Resource interface, and specifically the isClosed and close functions required by the Resource interface. isClosed lets us check whether the resource has been released, and close implements the release of resource operations. When an exception occurs or the try-block ends normally, the compiler calls the corresponding function to automatically release resources.
Dynamic Security Check
In addition to security assurance provided by static types, Cangjie also attaches great importance to runtime security checks. For some scenarios where static types are not suitable, Cangjie provides security assurance via runtime checks.
Overflow Check
Unlike most common languages, Cangjie by default performs overflow checks on integer operations, rather than wrapping.
If contextual information is sufficient, integer overflows can be detected by static analysis during compilation, and the compiler will report an error. Otherwise, if there is not enough information for static analysis, an integer overflow check will be performed at runtime, and a runtime exception will be thrown if an overflow is detected.
With this mechanism, integer overflows can be detected in a timely manner in most cases, preventing business risks.
Runtime checks lead to extra computational overhead, but the computational overhead can be controlled at a relatively low level with optimizations by the Cangjie compiler.
In some sensitive scenarios, it can be better to accept numeric wrapping for the sake of performance. In such cases, an overflow policy can be manually specified to implement the wrapping behavior common to many other languages.
@OverflowWrapping
func test(x: Int8, y: Int8) { // If **x** is 127 and **y** is 3
let z = x + y // **z** is -126
}
Array Out-of-Bounds Check
Similarly, for index accesses to Cangjie arrays, out-of-bounds checks are performed. If information of the context is sufficient, out-of-bounds index accesses can be detected by static analysis in the compiler, and a compilation error will be reported directly. If there is not enough information for static analysis, index access checks are performed at runtime, and a runtime exception is thrown if an overflow is detected.
func f(index: Int) {
let a = [1, 2, 3]
let b = a[-1] // An error is reported during compilation.
let c = a[index] // A check is performed at runtime.
}
Obfuscation
Cangjie provides multiple obfuscation technologies to protect developers' software assets and make it more difficult for attackers to attack Cangjie software. Attackers often use reverse engineering techniques to attack programs and obtain symbol names, path information, line number information, feature strings, feature constants, and control flow information from programs. Cangjie's obfuscation technology can obfuscate and hide this information, making it difficult for attackers to use the information to understand the running logic of programs.
-
Layout obfuscation: Layout obfuscation obfuscates the symbol names, path information, and line number information of Cangjie applications, and rearranges the functions in the Cangjie binary. Once layout obfuscation is used on a program, attackers cannot use the information to understand the running logic of program. Layout obfuscation causes function names and variable names to be replaced by random strings, path names to be replaced by the string "SOURCE", and line numbers to be changed to 0.
-
Data obfuscation: The Cangjie compiler supports string obfuscation and constant obfuscation. String obfuscation identifies plaintext strings in code and encrypts and saves them. During program initialization, the strings are decrypted and then the program is executed according to the code logic. Therefore, external attackers cannot directly obtain plaintext strings from program files and can only view encrypted data. As a result, they cannot guess the code logic based on information from string literals. For known constants used in programs, the Cangjie compiler supports constant obfuscation, which converts code snippets that use these constants into equivalent code snippets that are more difficult to understand.
-
Control flow obfuscation: The Cangjie compiler supports two control flow obfuscation mechanisms: false control flow and control flow flattening. Control flow obfuscation disrupts and rearranges the patterns of jumps between basic blocks without affecting the normal execution of programs, thereby increasing the difficulty of analyzing and understanding the control flow of the program. Meanwhile, false control flow randomly adds a large number of false conditional jump branches to a program, and the condition variables of these conditional jump branches are the results of opaque predicates. The main purpose of control flow flattening is to hide the jump relationship between basic blocks while ensuring that the execution sequence of the basic blocks during actual execution is consistent with that before obfuscation, so that the normal operation of the program is not affected and attackers cannot statically know the execution sequence relationship and jump relationship between the basic blocks based on the control flow information.
Easy Concurrency
The Cangjie language provides a simple and flexible way for concurrent programming. It uses a lightweight thread model and efficient and easy-to-use lock-free concurrent objects to make concurrent programming easy, making developers capable of efficient concurrent processing. This chapter describes the core ideas, designs, and advantages of the two key technologies of Cangjie concurrent programming, and reveals how the Cangjie language implements easy concurrency.
Lightweight Thread Model
The Cangjie language uses the user-level thread model. Each Cangjie thread is an extremely lightweight execution entity with an independent execution context, and all the threads share the same memory. This model not only simplifies concurrent programming, but also brings significant performance advantages.
- Development state: The user-level thread model makes concurrent programming as easy as common programming. Generally, this model may be implemented in two solutions: stackless and stackful. Although the stackless coroutine can reduce the memory usage to a very low level, a new syntax, such as the async or await keyword, is usually required to be used in the Cangjie language. However, the use of a new syntax significantly increases the concurrent programming complexity. Developers need to manually mark functions during programming (for example, mark an asynchronous function as async and its call site as await). Such operation is contagious (that is, all functions containing await must be marked as async) and results in colored functions. Each Cangjie thread has an independent execution context and can be freely switched. Therefore, developers do not need to mark functions during programming.
- Runtime state: Compared with traditional operating system threads, the lightweight thread model has obvious advantages in performance. The lightweight thread model is entirely implemented and managed in user space, fundamentally reducing the overheads of thread creation and destruction and simplifying the thread scheduling process. This design achieves more efficient resource utilization and faster program execution in the Cangjie language, especially in high-concurrency scenarios. On one x86 server, the average time required for creating a Cangjie thread is 700 ns, which is far less than the overhead of creating an operating system thread (generally hundreds of microseconds). Because one Cangjie thread occupies only 8 KB memory, developers can create hundreds of thousands of Cangjie threads in one program at the same time, which is much more than the number of threads that can be created in an operating system.
In general, the lightweight thread model not only reduces the system load, but also enables developers to easily implement thousands or even tens of thousands of concurrent tasks without increasing programming complexity. This model has the following key advantages:
- Simple concurrent programming. The model does not impose too many syntax restrictions on concurrent programming, so that developers can easily use Cangjie threads for service processing.
- Lightweight overhead. Compared with traditional kernel threads, the user-level thread model has much lower thread creation and switching overheads. Therefore, developers can quickly create and destroy a large number of user-level threads in the Cangjie language and easily develop high-concurrency applications.
- Higher concurrency. A large number of concurrent tasks can be executed at the same time, making this model especially suitable for I/O-intensive and high-concurrency network service scenarios.
- Lower context switching costs. Context is switched in the user space, avoiding high costs of frequent switching between the kernel mode and user mode during thread switching.
This design enables developers to easily and quickly execute high-concurrency tasks in the Cangjie language. They can use simple syntax to construct a large number of user-level threads without worrying about common performance bottlenecks in traditional concurrency models. For example, a developer can easily handle multiple network requests by executing the following code:
func fetch_data(url: String) {
let response = http_get(url)
process(response)
}
main() {
let urls = ["https://example.com/data1", "https://example.com/data2", ...]
let futures = ArrayList<Future<Unit>>()
for (url in urls) {
let fut = spawn {fetch_data(url)} // Creates Cangjie threads to send network requests.
futures.append(fut)
}
for (fut in futures) { // Waits for all Cangjie threads to complete.
fut.get()
}
}
In the preceding example, the spawn keyword is used to create a new Cangjie thread. Each thread independently executes the fetch_data function. The runtime environment of the Cangjie language automatically schedules these threads. Therefore, developers can focus on the implementation of service logic. Finally, the developer calls the fut.get() function to wait for and obtain the execution result of the child threads, ensuring that the main thread can obtain the execution result of the child threads synchronously.
With its obvious performance advantages and lightweight design concept, the user-level thread model used by the Cangjie language provides developers with a new and attractive solution for concurrent programming. It makes high-concurrency application coding more direct and efficient. It is not only applicable to high-load network services, but also meets the requirements of various computing-intensive tasks. By using this new concurrency model, the Cangjie language achieves simple concurrent programming and makes full use of the powerful processing capabilities of modern multi-core processors.
Lock-Free Concurrent Object
In concurrency scenarios where multiple threads share the same memory, programmers must control the sequence in which different threads access the same memory unit to prevent data races. Generally, features such as mutex are provided in programming languages to enable multiple processes to access the same memory simultaneously.
However, it is complex for programmers to control the access of threads to the shared memory which may cause poor concurrency performance.

As shown in the preceding figure, a memory block M is shared by multiple threads whose concurrent accesses to the memory block M are synchronized by a mutex. As a result, the optimal development efficiency and running performance are not achieved.
Is it possible to divide the memory block M into multiple areas and lock it in a finer granularity for better performance and enable automatic protection of shared memory by using a mutex to make multithreaded programming as simple as single-threaded programming?
The following figure shows fine-grained concurrency control. The memory block M is divided into multiple areas, and different threads can concurrently access different areas. However, the fine-grained concurrency algorithm is complex. In actual scenarios, the memory block M may represent a data structure. It is not easy to perform fine-grained concurrency control on a complex data structure, and concurrency problems, such as data races or the lack of atomicity in concurrent programming, are likely to occur.

To solve those problems, Cangjie provides concurrent objects implemented based on the fine-grained concurrency algorithm. Users can call the APIs of the concurrent objects to control the concurrent access to the shared memory by multiple threads. In this way, the following functions are implemented:
- Lock-free programming. Users can call APIs to implement efficient concurrent access to the shared memory by multiple threads.
- Concurrency security assurance. The APIs provided by the Cangjie concurrent objects eliminate data races and ensure that the call and execution of all core APIs are completed without interruption.
- Better performance. The fine-grained concurrency algorithm is used to design the Cangjie concurrent objects.
- Atomicity of concurrent programming. The core APIs provided by the Cangjie concurrent objects are "atomic". That is, from users' perspective, the call and execution of these APIs are not interrupted by other threads.
The following table lists the types of concurrent objects shared by multiple threads provided by Cangjie to guarantee concurrency security and performance.
| Type | Data Structure |
|---|---|
| Atomic Integer | AtomicInt8, AtomicInt16, AtomicInt32, AtomicInt64, AtomicUInt8, AtomicUInt16, AtomicUInt32, and AtomicUInt64 |
| Atomic Boolean | AtomicBool |
| Atomic Reference | AtomicReference and AtomicOptionReference |
| Concurrent Hash Map | ConcurrentHashMap |
| Concurrent Queue | BlockingQueue, ArrayBlockingQueue, and NonBlockingQueue |
- Concurrency security
In concurrency scenarios, data races do not occur when a user uses an atom type and calls a concurrent data structure API to operate objects shared by multiple threads. Atom types provide users with operations of AtomicInteger, AtomicBoolean, and AtomicReference in concurrency scenarios. The call and execution of the core APIs of a concurrent data structure are not interrupted by other threads, such as the put method for key-value pair insertion, the remove method for key-value pair deletion, and the replace method for key-value pair replacement in ConcurrentHashMap. In concurrency scenarios, the call and execution of these operations are not interrupted by other threads.
- Better concurrency performance
Concurrent Hash Map and Concurrent Queue are implemented based on the fine-grained concurrency algorithm described above. The following figure shows the performance comparison between ConcurrentHashMap and the using of a mutex to control concurrent access to HashMap by multiple threads (that is, coarse-grained concurrency control). The horizontal coordinate indicates the number of threads and the vertical coordinate indicates the number of ConcurrentHashMap operations completed per millisecond. In the ConcurrentHashMap operations, the put, remove, and get methods account for 10%, 10%, and 80% respectively. The yellow line indicates the test data of the Cangjie ConcurrentHashMap, and the blue line indicates the test data of the coarse-grained concurrency control method. It can be seen that the performance of the Cangjie ConcurrentHashMap using the fine-grained concurrency algorithm is obviously better than that of the coarse-grained concurrency control method, and that the performance is improved as the number of threads increases.

The following figure shows the performance comparison between the Cangjie BlockingQueue and the using of a mutex to control concurrent access to a queue by multiple threads (that is, coarse-grained concurrency control) in the single-producer and single-consumer scenario. We performed the comparison with queue capacity of 128 and 4096, respectively. The vertical coordinate indicates the number of elements enqueued or dequeued per millisecond. The performance of the Cangjie BlockingQueue is obviously better than that of the coarse-grained concurrency control method.

Excellent Performance
The Benchmarks Game test results show that the Cangjie language, with the value type, multi-level static analysis optimization, and ultra-lightweight runtime functions, has obvious performance advantages over similar programming languages in the industry.

Static Compilation Optimization
Cangjie compilation uses modular compilation. IR is used as the carrier between compilation processes. Different compilation optimizations do not affect each other. The adaptation of compilation optimization and the adjustment of compilation processes are more flexible. The Cangjie language uses static compilation methods to compile Cangjie programs and core library code into machine code, accelerating program running.
GC Optimizations
In Cangjie static compilation, many runtime joint optimizations are added. For example, optimization for reading and writing objects on the heap, creating heap objects, and the heap memory management signal mechanism. Static analysis and runtime joint optimization accelerate the running speed of Cangjie programs in terms of object creation, read/write, and member function call.
When objects are read and written, the Cangjie static backend uses vectorized access to guarantee data read/write and computing rates, minimizing the impact of function calls on performance. Analysis of the active scope of heap objects also ensures that the static backend can determine allocation addresses of heap objects. No matter in the heap, stack, or constant area, the static backend can optimize allocation based on characteristics of objects.
The Cangjie language can accelerate GC information collection based on accurate recording of references on the stack. Accurate recording of stack objects reduces the number of garbage collection root sets, avoiding redundant address judgment of object pointers. In the scanning and fixing phases, accurate recording of stack objects guarantees effective running of GC programs.
Based on GC functions, the Cangjie language optimizes fast paths ath for object creation, reading, and writing. As shown in the following figure, when a memory access operation is compiled, a fast path and an instruction for efficiently determining the fast path are generated to reduce performance overheads.

Escape Analysis
For global analysis and optimization, escape analysis of references is added in the Cangjie language. For a reference type, the Cangjie language analyzes the lifecycle of the reference. For a reference that does not escape from the function in which the reference is located, stack allocation optimization can be used. The following code contains some escape analysis results.
class B {}
class A {
var a: Int64 = 0
var b: B = B()
}
var ga: A = A()
func test1(a: A) {
a.a = 10
}
func test2(a: A) {
ga = a // escape to global
}
func test3(a: A, b: B) {
a.b = b
}
main() {
var instance: A = A() // alloca on stack, not escape out this func
instance.a = 10
var instance1: A = A() // alloca on stack, test1 not escape param a
test1(instance1)
var instance2: A = A() // gc malloc in heap, test2 escape param a
test2(instance2)
var instance3: B = B() // alloca on stack, instance3 store into instance1, but instance1 not escaped.
test3(instance1, instance3)
var instance4: B = B() // gc malloc in heap, instance4 store int instance2 and instance2 escaped to global.
test3(instance2, instance4)
}
Stack allocation optimization can directly reduce the GC pressure of automatic memory management, reduce the frequency of memory allocations on the heap, and reduce the garbage collection frequency. The read/write barrier of the heap memory can also change to direct data storage and access due to allocation on the stack, accelerating memory access. After an object is allocated on the stack, optimization measures such as SROA and DSE can be taken for the stack memory to reduce the number of memory read/write times.
Type Analysis and Devirtualization
The Cangjie language supports static analysis of global types and type prediction based on Profile. The Cangjie language supports type inheritance, virtual function calls, and interface function calls. Compared with direct calls, calls of virtual functions and interface functions require extra search and access overheads.
For global, local, and interprocedural references, the Cangjie language changes calls of some virtual functions into direct calls through static analysis to accelerate function calls and improve optimization opportunities such as function inlining.
In PGO mode, the Cangjie language supports statistics on the types and number of virtual function calls. The hot type and hot call parts captured based on the Profile information accelerate function calls and program execution in a conservative devirtualization manner.

Value Type Optimization
Cangjie language introduces value-type objects. Local variables of a value type can be directly accessed without GC-related barriers during memory read/write without being affected by the change of reference information. Proper use of value-type semantics can effectively improve program running efficiency.

Using value types provides more data placement and access modes. Proper data structure design provides excellent spatial/temporal locality in terms of data access, and brings more advantages in operations such as computing and access. As shown in the following figure, for the array of class A, when the member variables of the array are accessed, the load operation needs to be performed twice. For the array of the value type, the load operation needs to be performed only once when the member variables of struct A are accessed.

The On Stack Replacement (OSR) optimization technique is applicable for value types. When the OSR is used properly, some value-type data can be directly distributed to registers, which brings more advantages to data access and calculation. In the following example, an SA object of the value type is split into a and b, both of which can be represented in a register without repeated load. Subsequently, a and b can be directly represented by constants through constant propagation.
struct A {
var a : UInt64 = 10
var b : UInt64 = 100
}
main() {
var SA = A()
var sum: UInt64 = 0
for (i in 0..100) {
sum += SA.a
}
return sum + SA.b
}
After OSR optimization, the preceding source code can be converted into the following form to reduce the operations of access to struct member variables.
main() {
var a: UInt64 = 10
var b: UInt64 = 100
var sum: UInt64 = 0
for (i in 0..100) {
sum += a
}
return sum + b
}
Compared with a reference type, a value type is allocated more quickly and reclaimed efficiently and automatically with the rollback of the stack space.
If a reference type is used, deep copy occurs, which introduces extra memory access overhead. If a value type is used, indirect addressing and deep copy are avoided. This advantage is more obvious in the scenarios where basic types, such as numbers and Boolean values, are processed.
Fully-Concurrent Sorting GC
The Cangjie language provides the fully-concurrent memory mark sorting GC algorithm as the base of its automatic memory management technology. It features low latency, low memory fragmentation rate, and high memory utilization.
Reducing GC Suspension Time
In some latency-sensitive important scenarios, STW GC or approximate concurrent GC cannot meet technical specifications. For example, for the 120 Hz screen refresh rate (expected to be higher in the future) in mobile scenarios, the total time required for drawing a frame should be less than 8 ms. Millisecond-level GC suspension may become the main latency factor. In a high-concurrency scenario with thousands or even tens of thousands of concurrency, the approximate concurrency algorithm needs to scan thousands of call stacks in a single STW. This operation may prolong the STW time to more than 10 ms.
Compared with the existing STW GC and mostly concurrent GC (see the following figure), Cangjie's fully-concurrent GC abandons the STW as the GC synchronization mechanism and uses a lightweight synchronization mechanism with a shorter latency. The average time required for application threads to complete GC synchronization is less than 100 microseconds, and typically, GC synchronization can be completed within tens of microseconds.

The following two key elements are used to achieve efficient GC synchronization:
- Security Point
Concurrent GC needs to process the status synchronization relationship between GC threads and application threads. The security point mechanism is a technical means used by the GC thread to control the application thread to implement GC status synchronization. The security point mechanism consists of two parts. One is the security point check code inserted when the compiler is compiling the Cangjie code, which is usually inserted on an explicit path, such as the function header or tail and loop back edge. The other is the security point synchronization logic implemented in the GC algorithm. When the GC thread needs to synchronize the GC status to a specific application thread, the GC thread first activates the security point check of the application thread. When the security point check code is executed in the application thread, the security point of the application thread is in the active status, and the application thread responds to the GC synchronization request and changes the GC status to a specified status. With the security point mechanism, the GC thread can control the change of the GC status of the application thread and work with the memory barrier to ensure that the concurrent GC can be correctly executed. Different GC statuses require corresponding memory barriers.
- Memory Barrier
The fully-concurrent GC implemented by the Cangjie language also needs to correctly process three types of data competition relationships: (1) Data competition relationships between GC threads and application threads (2) Data competition relationships between GC threads (3) Data competition relationships imported by the GC between application threads. Because the application threads share some work of the GC. The memory barrier mechanism is used to resolve data competition between GC threads and Cangjie threads. In concurrent GC, the most common data competition is between GC threads and application threads. Example: the time when the GC thread wants to move a live object to a new address and the service thread wants to access the live object almost at the same time. The memory barrier mechanism is used to maintain coordination with a GC thread when an application thread accesses the memory.
Reducing Memory Fragments and Memory Peaks
The memory sorting technology used by the Cangjie GC is one of the most cutting-edge technologies for memory reclamation (certainly, the algorithm implementation complexity of the Cangjie GC is relatively increased). Compared with the existing Mark-Sweep algorithm, the memory sorting technology can be used to migrate scattered live objects to a more compact memory layout, greatly reducing memory fragments. Compared with the replication algorithm that copies all live objects in the from-space to the to-space before the memory of the from-space is released, the memory sorting technology can be used to migrate live objects and release the memory blocks that have been sorted at the same time, eliminating the memory peak caused by GC replication.
In the fully-concurrent GC of the Cangjie language, the Cangjie heap memory is divided into small continuous memory blocks, which are called region. The from-region is a region in the from-space, and the to-region is a region in the to-space. During heap memory sorting, live objects in the from-region are migrated to a proper to-region to form a more compact memory layout. After the migration is complete, the from-region can be released for allocation of new objects. When the memory pressure is high, the from-region and to-region can overlap in the memory space to further reduce the memory peak.
Fast Object Allocation Speed
Thanks to the object migration technology used by the Cangjie GC to reclaim memory, Cangjie runtime implements an object allocation mode based on the bumping-pointer technology, which is an existing advanced memory allocation technology. A memory allocation can be completed in about 10 clock cycles on average.
Optimizing GC Overhead
Cangjie's fully-concurrent memory sorting algorithm uses pointer mark to accelerate the identification of fast paths in memory access and storage operations. Pointer mark classifies statuses of reference members in Cangjie objects into three types: (1) Unmarked. (2) Marked: The reference member is marked in the current GC process. The pointer is called current pointer. (3) Marked: The reference member is marked in the last GC process. The pointer is called old pointer. The unmarked pointer is the real address of a Cangjie object. It can be directly used for memory access and storage, which is a fast path for memory access and storage. The old pointer comes from the last GC. The pointer that has not been repaired needs to be updated after the GC thread or memory barrier queries the forwarding table in the enum and trace phases. The current pointer is marked in the enum and trace phases of the current GC to indicate which objects may be moved. When the memory barrier accesses the marked old pointer, the forwarding table needs to be queried to obtain a new address. When the memory barrier accesses the marked current pointer, it needs to determine whether the object has been transferred based on the current GC status. If the object has been transferred, the forwarding table is queried to obtain a new address. Otherwise, the memory barrier needs to transfer the object to a corresponding to-region and update the marked pointer.
In the Cangjie's fully-concurrent memory sorting algorithm, marked pointers are updated in lazy mode. The marked pointers are updated only when they are accessed by a memory barrier. If the marked pointers are not accessed, they are retained and updated in the enum and trace phases of the next GC. This policy can significantly reduce the duration of the GC process.
Adapting Value Type
As described above, value types are introduced into the Cangjie language to provide developers with better memory and performance development choices, but also make the GC implementation more complex. For reference-only programming languages (such as Java, JavaScript, and Kotlin), all types except basic types are reference types. This mode is more friendly to the GC algorithm. Value types make the GC algorithm more complex in two aspects: (1) The data of a value type may be a member of other data, or may be an independent global or local variable. In the two cases, the data of the value type is in different memory areas. However, for member methods of the value type, a unified behavior definition must be provided in the above two cases. (2) The data of the value type belongs to other value types or reference types in the embedded form. The memory layout is changed with the embedded form. During the implementation of Cangjie GC that supports object migration, the complexity of the GC engineering is greatly increased due to features of value types. Considering that value types bring developers more powerful and convenient expression capabilities, better application performance, and better memory performance, the internal complexity increased in implementation of the Cangjie language is worthwhile.
Lightweight Runtime
The Cangjie language provides the ultra-lightweight runtime function, which not only features low distribution overhead, but also achieves application deployment and running at extremely low overheads.
Through software engineering optimization, redundant code in the Cangjie runtime library is deleted, dependency on the C++ runtime library is removed, and definitions of externally invisible symbols are reduced. As a result, the binary size of the Cangjie runtime library is as small as 1 MB. The size of the runtime library with customized optimization for embedded systems completed can be as small as about 500 KB.
The Cangjie lightweight runtime function allows user-level threads to be created, run, and scheduled at extremely low overheads. It takes only hundreds of nanoseconds to create a user-level thread. User code costs only several kilo bytes of stack memory during execution, and a single scheduling takes only hundreds of nanoseconds.
The Cangjie lightweight runtime function achieves calls between the Cangjie language and the C language at nearly zero cost. In terms of underlying implementation, the ABI definition of the Cangjie language is highly compatible with that of the C language. Types compatible with the C language (that is, types modified by the "@C" keyword) in the Cangjie language have the same memory layout as the C language. In typical scenarios, data can be shared between the Cangjie language and the C language without conversion.
The Cangjie lightweight runtime function provides flexible application tailoring technologies to help developers optimize the application package size. The reflection mechanism of the Cangjie language can be enabled on demand, and can be disabled when it is not required. For private methods in the Cangjie package, redundant code can be cleared through on-demand links at the function granularity.
The Cangjie lightweight runtime function helps reduce the deployment and startup overhead of Cangjie applications to an extremely low level. The application startup duration is at the 10 ms level. Memory of applications carrying no service load is at the 1 MB level. In embedded scenarios, memory when no service load is carried is less than 1 MB.
Agile Expansion
The domain-specific language (DSL) plays an important role in modern software development because it is close to domain problems and can reduce the complexity of software development and maintenance. From a perspective of DSL implementation, the embedded DSL (eDSL) uses an existing general programming language as the host language and uses the language features provided by the host language to extend domain-oriented syntax. Compared with the implementation mode of independently constructing the DSL (dedicated syntax parsing, compilation optimization, and auxiliary tools), the eDSL has the following advantages:
- The language features of the host language can be reused, and the expression capability is strong.
- The auxiliary facilities of the host language (such as the library ecosystem, compilation tools, and development environment) can be reused, and the construction threshold is low.
- Because the eDSL is seamlessly embedded into the host language project, data can be efficiently exchanged across domains.
Therefore, the eDSL is widely used in various domains, such as UI layout, database access, cloud infrastructure deployment, and script compilation. Accordingly, the Cangjie programming language provides rich language extension capabilities to support domain-oriented eDSL construction.
This section focuses on the language extension capabilities provided by the Cangjie language, including the extension capability based on the native syntax and the metaprogramming capability that allows developers to build new syntax. Finally, this section uses the declarative UI as an example to describe how to use the preceding capabilities and the effects.
Native Syntax Extension Capability
This section describes the application of some native Cangjie syntax features in eDSL construction. Codes written using these syntaxes constitute not only eDSL programs complying with domain habits and having domain-specific meanings, but also legal Cangjie programs. Most of these syntaxes are described in the Efficient Programming section. Here, we focus on their functions in constructing eDSLs.
Type Extension and Attribute
Type extension allows you to add new functions to the original type without intrusive modification, especially for native types of languages and types defined by external libraries. Such extension improves the usability of types. The attribute mechanism provides getter and setter support for field access and hides data access details. However, getter and setter can be implicitly called using the syntax similar to that for directly accessing fields. With these two features, you can write some programs that can naturally express domain-specific meanings. For example, in the scenario where a book is borrowed from a library, we want to construct an expression similar to the natural language indicating that the book return time is two weeks later. The expected expression is as follows:
var bookReturnDate: DateTime = 2.weeks.later
You can use attributes to extend Int64:
extend Int64 {
prop weeks: Int64 {
get() {
this * 7
}
}
prop later: DateTime {
get() {
DateTime.now() + Duration.day * this
}
}
}
Named Parameters and Default Values
During eDSL construction, parameters need to be configured for some objects. The following may occur:
- There are many parameters, of which the configuration sequence may be incorrect.
- You do not want to set all parameters each time, and need to use the default values in most cases.
In these scenarios, you can solve the problems based on the features of named parameters and default values. For example, to set the size of a rectangular zone on a plane, you need to determine the top, bottom, left, and right positions of the rectangular zone. Generally, the top and left coordinates are 0 by default. The implementation is as follows:
class Rect {
static func zone(top!: Int64 = 0, left!: Int64 = 0, bottom!: Int64, right!: Int64): Rect {
//
}
}
In this way, the rectangular zone can be configured more clearly. For example, the following call modes are allowed:
Rect.zone(bottom: 10, right: 10) // Uses the default values for **top** and **left**.
Rect.zone(top: 5, bottom: 10, right: 10) // Uses the default value for **left**.
Rect.zone(right: 10, bottom: 10) // You do not need to remember the parameter sequence.
Operator Overloading
Operator overloading enables objects of non-numeric types to implement the syntax of arithmetic operators. For example, in the library example, you can write:
DateTime.now() + Duration.day * this
In the Cangjie standard library, the add (+) operation of DateTime and the multiply (*) operation of Duration are reloaded. For example:
//DateTime
public operator func +(r: Duration): DateTime
//Duration
public operator func *(r: Int64): Duration
Trailing Lambda
The concept of trailing lambda is introduced in preceding sections, and its use is described from the perspective of constructing DSL. Here is an example of declarative UI. You can use trailing lambda to express the hierarchical relationship between components and construct an HTML-like expression paradigm.
Column {
Image()
Row {
Text()
Text()
}
}
Column is a call to the Column function, and the braces are the lambda expression of Cangjie, which is the parameter of the Column function call provided in the trailing lambda mode. The same syntax is used for Row.
Keyword Omission
eDSL syntax noise refers to syntaxes introduced by the host language but irrelevant to actual service abstraction in the domain. The syntax noise affects the readability of the eDSL. Cangjie allows omission of the following: new during object construction, ";" at the end of a line, and return in function returns. This further simplifies the eDSL expression and reduces the syntax noise.
Macros
Macros can be seen as a kind of "code abbreviation" or a way to extend language syntax. During compilation or program running, the abbreviation is replaced with the actual code, and this replacement process is called macro expansion. Functions that can be expressed in unified and simple code can be achieved by using macros. Cangjie provides procedural macros for macro expansion in the syntax analysis phase. In the future, more easy-to-use and expressive macro definition modes will be provided, including late-stage macros and template macros.
Procedural Macros
A Cangjie procedural macro processes and transforms an input token sequence and outputs another token sequence. The input token sequence is generated by the lexical analyzer and must comply with the lexical rules of Cangjie. The output token sequence must meet the syntax and semantics of Cangjie and be a valid Cangjie program. The following example shows the working principle of the procedural macros. In this example, we are calling a DebugLog macro with expensiveComputation() as its parameter. This macro will find out (at compile time) whether the program is configured to run in development mode or in production mode. In the development mode, expensiveComputation() is run and the debugging output is printed to help detect and locate problems. In the production mode, not only do we not want to see the debug output, we also do not want to pay the performance cost of running the expensive computation.
@DebugLog( expensiveComputation() )
The macro DebugLog can be implemented like this:
public macro DebugLog(input: Tokens) {
if (globalConfig.mode == Mode.development) {
return quote( println( ${input} ) )
}
else {
return quote()
}
}
The macro definition syntax of Cangjie is similar to the function definition syntax. The parameter can only be a token sequence (that is, the Tokens type), and the return value is a token sequence obtained after conversion. The return value is the code generated by macro call (that is, macro expansion). In the preceding example, in the development mode, the return value is outside the input token sequence and the println function is called. Therefore, the execution result is printed in addition to the input part. If the development mode is not used, an empty sequence is returned. That is, the input part is ignored and no code is generated.
Late-stage Macros and Template Macros
The following describes two types of macros under development, that is, late-stage macros and template macros, which will be released in later versions of Cangjie.
The input token sequence of the preceding procedural macro does not contain the semantic information of the program. In some cases, users may need to perform corresponding processing according to the variable type or the class and interface declaration information in the macro definition. This capability cannot be implemented through the procedural macros. The following program is used as an example:
@FindType
var x1: Employee = Employee("Fred Johnson")
// getting the type info of `x1`: easy, it is right there
@FindType
var x2 = Employee("Bob Houston")
// getting the type info of `x2`: hard, requires type inference
Assume that the macro FindType is used to obtain the types of the variables x1 and x2 and print or add the types to the log. The type of x1, that is, Employee, is shown in the syntax and can be extracted from the input token sequence. However, the type of x2 is not shown in the declaration and therefore cannot be directly obtained from the input token sequence. The type of x2 needs to be obtained through type inference. However, macro expansion occurs in the syntax analysis phase when type inference has not been performed. Therefore, the type of x2 is unavailable. The late-stage macros can be used to obtain and utilize various semantic information of the program, including the type information, through type inference followed by macro expansion.
The late-stage macros can be used to generate code based on type information and non-local definitions in the code. It is a powerful function that extends the processing capability of macros. Any fundamental change to a piece of code of a known type is impossible. Therefore, the late-stage macros have more limited expression capability.
If a macro can be thought of as a structured rewriting from some source code to some target code, then the template macros are a better choice than the ordinary procedural macros:
public template macro unless {
template (cond: Expr, block: Block) {
@unless (cond) block
=>
if (! cond) block
}
}
The preceding template macro definition can be used to write the following program:
@unless (x > 0) {
print("x not greater than 0")
}
During the macro expansion, the system matches the preceding template according to the template macro definition, extracts cond and block, and converts them into the following:
if (! x > 0) {
print("x not greater than 0")
}
The strength of template macros comes from the fact that they describe the intended source code and target code directly, putting the focus on the central transformation. A procedural macro could do the same thing, but it would require tedious and perhaps error-prone code to describe the same transformation that a template macro describes directly.
Agile Extension Case: Declarative UI
Declarative UI is a development paradigm oriented to UI programming. It allows developers to describe only the layout relationship between UI components and the binding relationship between UI components and statuses (data required for rendering), without considering the implementation details of UI rendering and refreshing. Therefore, development efficiency of the developer is improved. In recent years, the eDSL mode is used to build declarative UIs in the UI framework in the industry. In this section, the declarative UI is used as an example to describe how to use the domain extension capability of the Cangjie language to build the UI eDSL.
UI Component Layout
The UI eDSL must have the capacities of describing the layout details of various components on the two-dimensional plane, and clearly expressing the configuration information such as the length and width of components and the hierarchical relationship between components. In addition, it is expected that the UI eDSL can make code structures have some similarities with UIs to achieve the effect of "what you see is what you get.". In addition, the UI eDSL should be very concise to minimize the "noise" beyond UI descriptions.
Assume that the following UI needs to be implemented. The UI consists of a segment of text and a button. The text and button need to be vertically centered. In addition, the click event processing logic needs to be set for the button.

With the UI eDSL defined by Cangjie, the following code describes the expected UI. The Text component displays a segment of text, and the Button component implements the button function. To arrange the two components vertically, the two components are embedded in a Column layout component.
class CustomView {
...
func build() {
Column {
Text("${count} times")
.align( Center )
.margin(top: 50.vp, bottom: 50.vp)
Button("Click")
.align( Center )
.onClick { evt =>
count++
}
}.width(100.percent)
.height(100.percent)
}
...
}
For comparison, if the Cangjie language does not provide the corresponding extension capability, developers may need to write the following code. In terms of readability, the former code is clearer and simpler. In terms of character statistics, the latter code requires developers to write nearly 70% more code than the former code, which is a considerable overhead on more complex pages.
class CustomView {
...
func build() {
new Column ({ =>
new Text("${count} times")
.align(Alignment.Center)
.margin(Length(50, Unit.vp), Length(0, Unit.vp), Length(50, Unit.vp), Length(0, Unit.vp))
new Button("Click")
.align(Alignment.Center)
.onClick ({ evt =>
count++
})
}).width(Length(100, Unit.percent))
.height(Length(100, Unit.percent))
}
...
}
When the Cangjie language is used to define the preceding eDSL, the following features are used:
-
The trailing Lambda is used to describe the hierarchical relationship between components. For example, the Column component is used as the parent component of the Text and Button components, which determines the arrangement mode of the Text and Button components. In addition, "()" can be omitted by using the trailing Lambda to make the syntax simpler.
-
Named parameters and default parameter values are used to make parameter pass clearer and simpler. For example, during the margin setting process, only the values of top and bottom need to be set. For parameters that are not set, the default values are used. In addition, the named parameters enable developers to clearly know which parameters are set, without recording the parameter sequence. This improves code readability and reduces errors.
-
With the type extension capability, the expression capability of carrying a length unit for the integer type is extended. For example, 100.percent is equivalent to 100%, and 50.vp is equivalent to 50 vp. Compared with using only integers, the expression capability provides type verification assurance. Compared with using the Length class, the syntax is simpler and more readable.
-
The Cangjie language supports omitting the keyword "new" during class instantiation. Enumeration prefix omittance is implemented through type inference (for example, use Center instead of Alignment.Center), which further enhances the expression simplicity.
Binding Relationship Between UI Components and States
States are a group of data associated with a UI. In a declarative UI, view = f(state) is usually used to express a relationship between a UI (view) and a state (state), where f is used as a link between view and state, is implemented by the framework, and is hidden from UI developers. Generally, f is implemented as a responsive mechanism, that is:
- Establish the binding relationship between state and the component in the view.
- Capture state changes and trigger the updates of the corresponding components.
A counter is implemented below by the modification of the top example. An @State count is added for the component, and click event processing is added for the button. Each time the button is clicked, the value of count is incremented by 1. In addition, the Text component displays the current number of clicks, that is, the value of count.
class CustomView {
@State var count: Int64 = 0
...
func build() {
Column {
Text("${count} times")
.align( Center )
.margin(top: 50.vp, bottom: 50.vp)
Button("Click")
.align( Center )
.onClick { evt =>
count++
}
}.width(100.percent)
.height(100.percent)
}
...
}
The @State macro is added to the count variable so that the count variable has the responsive capability, that is, the change in the click event can be captured and the refresh of the Text component can be triggered. The above implementation mechanism is hidden in the macro implementation of @State. The following is a schematic macro expansion code logic example (actually, as described above, macro expansion occurs in the compilation phase, and the code exists in the AST form based on the expansion logic):
class CustomView {
private var count_ = State<Int64>(0)
mut prop count: Int64 {
get(): Int64 {
count_.bindToComponent()
count_.get()
}
set(newValue: Int64) {
count_.set(newVaue)
count_.notifyComponentChanges()
}
}
...
func build() {
Column {
Text("${count} times")
.align( Center )
.margin(top: 50.vp, bottom: 50.vp)
Button("Click")
.align( Center )
.onClick { evt =>
count++
}
}.width(100.percent)
.height(100.percent)
}
...
}
To achieve the preceding effect, the following features are used:
- The @State macro for state management is defined. The macro is expanded to generate the corresponding state processing code, which reduces the workload of writing template-based and repetitive code and simplifies state declaration and management.
- The attribute mechanism is used to implement the proxy of the actual status data. The form of count reading and writing retains unchanged externally. In the internal implementation, the get method is used to capture the read operation and establish the binding relationship between the state and the component. The set method is used to capture the write operation and instruct the bound component to update.
The preceding declarative UI case demonstrates that the flexible use of Cangjie's extension capabilities can improve the readability, simplicity, and correctness of code, simplify the workload of developers, lower the threshold for using frameworks or libraries, and facilitate ecosystem promotion.
Tool Support
The Cangjie developer tool is developer-oriented and provides common development tools such as the package manager, debugger, native test framework, and IDE based on the development processes such as compilation and build, debugging, performance analysis, and LLT verification, helping developers improve development and fault locating efficiency. The developer tool improves the development efficiency and reduces the development workload by providing the following tools:
- Package manager: supports automatic dependency management and user-defined build, and provides one-stop compilation and build capabilities.
- Debugger: supports cross-language debugging and multi-thread debugging, improving debugging efficiency.
- Cangjie testing infrastructure: includes the unit test framework, the mocking framework and the benchmarking framework.
- IDE: A developer can install the Cangjie plug-in on the VSCode and Huawei DevEco Studio to use this tool out of the box.
Package Manager
Cangjie Package Manager (CJPM) provides project-level compilation and building capabilities, and automatic dependency management implements analysis and combination of multi-version third-party dependencies. Developers do not need to worry about dependency conflicts between different versions, greatly reducing their workload. It also provides a custom building mechanism based on the native Cangjie language, allowing developers to add pre-processing and post-processing steps in different phases of building. In this way, the building process can be flexibly customized to meet building requirements in different service scenarios.
Automatic Dependency Management
For multi-version dependent modules introduced in a project, CJPM performs dependency analysis and calculates the final dependency to implement automatic dependency management. Developers do not need to manually manage dependency conflicts in the project. After automatic dependency management is implemented, during compilation and building, CJPM scans all dependencies of the project and performs similar item combination for different versions of the same module dependency. In this way, compilation and building errors due to the import of dependencies of multiple versions are prevented. Developers only need to run the cjpm build command to implement project-level building, greatly reducing their workload.

As shown in the preceding figure, the project directly depends on modules A and B. Module A depends on version 1.3 of module C, and module B depends on version 1.4 of module C. If dependency analysis and management are not performed, dependency conflicts occur due to multi-version dependencies during compilation, causing a compilation error. Through dependency management, CJPM performs dependency analysis on module C and performs version dependency combination.
Custom Building
When building a Cangjie project, the developer may have other custom behavior requirements related to the compilation of Cangjie code, such as environment variable configuration, external dependency library copy, and pre-operations for compiling C language files before cffi source code dependency, for example, the Rust language uses Cargo to provide pre-building developer-defined configurations.
CJPM allows developers to add custom pre- and post-building behaviors in any phase of building, helping them solve complex project building problems without using other build tools, thereby achieving one-stop building management of the project.

As shown in the preceding figure, the developer has customized the stagePreBuild task for compiling the cffi module and the stagePostBuild task for deleting the cffi source code. When the build command is executed, CJPM executes the stagePreBuild task first. After execution of the build command is complete, CJPM executes the stagePostBuild task.
Debugger
The debugger cjdb provides source code–level debugging capabilities and supports Cangjie cross-language debugging. For example, you can enter or exit cross-language function code in single-step mode, view the complete call stack in cross-language mode, and use a single debugger to complete debugging of multiple languages. In addition, debugging of Cangjie threads is supported, further improving user debugging experience.
Cross-Language Debugging
The debugger identifies the cross-language interoperation glue code layer in the single-step process, automatically calculates addresses of target functions, and filters out glue code that users do not care about. In this way, single-step entries and exits in cross-language function calls are the same as in common function calls, and call stacks of multiple languages can be automatically combined and displayed, improving developer debugging experience. The following figures show cross-language debugging of C functions called using the Cangjie language in the IDE.
Figure 1: Cangjie -> C cross-language call

Figure 2: Cangjie -> C cross-language single-step access

Figure 3: Cangjie -> C cross-language call stack and single-step debugging in FFI-C functions

Cangjie Thread Debugging
Cangjie supports concurrent programming based on multiple Cangjie threads. When a Cangjie program is executed, Cangjie and system threads are in an M:N relationship, and the number of Cangjie threads is usually very large. Calls among Cangjie threads are asynchronous. As a result, if an exception occurs, the exception cannot be captured and processed as in a common program. The Cangjie debugger supports setting breakpoints for Cangjie threads to view call stacks.

Cangjie Testing Infrastructure
Cangjie standard library offers state-of-the-art testing experience for its users, allowing for both conventional and simple testing techniques and more advanced techniques for more advanced testing scenarios. Cangjie testing infrastructure includes three main components: the unit test framework, the mocking framework and the benchmarking framework.
Cangjie Unit Test Framework
Cangjie unit test framework, as the name suggests, allows users to create unit tests in their Cangjie projects. In addition to simple unit tests that are as simple to write as a single Cangjie function, it provides a variety of more advanced techniques:
- Parameterized test: used to run the test code on multiple inputs.
- Data-driven test: used to read multiple groups of test data from a file and use the data as inputs to test the code.
- Randomized property-based test: used to test the code on structurally-constructed random data. Compared with other programming languages in the industry that can generate only random values of the basic type and character array type for tests, Cangjie can generate various types of random values for randomized property-based test.
- Generic type–parameterized test: Generic library developers can, based on the same test code, test the implementation of a generic function on different data types by passing different types of parameters.
- Death test: Underlying library developers can use the death testing capability to capture unwanted signals, segmentation faults, and other failures that may happen in underlying libraries.
To improve user experience even more, the unit test framework introduces built-in support for power assertions and difference assertions, providing exhaustive insight into the testing data and reasoning behind failures.
All these features are highly configurable and may be used together. For example, when testing a generic function, create randomly-generated generic data types, test the algorithm implementation on the data, and use power assertions and difference assertions to obtain detailed information.
Cangjie Mocking Framework
Cangjie mocking framework allows users to change the behaviour of Cangjie classes used in tests using so-called mocks and spies: objects that can capture and modify the behaviour of particular objects to test how the rest of the program interacts with these objects. Mocking is an advanced technique mainly used for testing bigger applications that are formed from a big number of interacting components.
Users of mocking framework from other languages may find our mocking DSL very similar to what they are used in their previous experience. The DSL allows you to specify, verify and modify the behavior of objects passed to the test code and generate readable error messages. Unlike other mocking frameworks, Cangjie mocking framework is implemented based on a unique instrumentation-based compiler technique, allowing users to mock not only interfaces and open types, but final classes as well.
Cangjie mocking framework is fully integrated with the unit test framework, and any of the features of either can be used together to make the testing capability even more powerful.
Cangjie Benchmarking Framework
Cangjie testing infrastructure provides a state-of-the-art benchmarking experience, including linear regression–based statistical value calculation, warm-up, and precise measurement. Most of the features provided by the unit test framework are also available to the benchmarking framework, allowing the use of benchmark with parameters, random value generation, and generic types.
In addition, the benchmarking framework comes with its own set of features, such as calculations based on a given baseline, getting access to the raw benchmarking data (to make users' own calculations if needed), and accurate error estimation both for micro-benchmarking and macro-benchmarking scenarios.
IDE Plug-in
The Cangjie language supports code development on the VSCode and Huawei DevEco Studio bases. After the Cangjie plug-in is installed on the VSCode and Huawei DevEco Studio bases, the following features are supported:
- Project management: Cangjie projects can be created and opened (Cangjie HarmonyOS projects can be created and opened in the DevEco Studio).
- Coding assistance: Includes code highlighting, code supplementation, syntax diagnosis, floating prompt, definition redirection, reference search, formatting, metaprogramming-related coding assistance, and the like.
- Compilation and building: The HarmonyOS DevEco Studio base supports the capability of pushing Cangjie HAP packages to mobile phones for running.
- Code debugging: Includes breakpoint setting, single-step debugging, and debugging information viewing. The Huawei DevEco Studio base supports the capability of debugging Cangjie apps on mobile phones.
Future Work Plan
The Cangjie language always adheres to the design concepts of efficient programming, high security and reliability, easy concurrency, and excellent performance, bringing friendly programming experience and high-performance running experience to developers. In addition, the forms of AI for PL and PL for AI in the wave of large models are in considering. The following describes some of the exciting language abilities that are already under our planning.
AI Native Application Development
Although AI technologies have been widely used, developers generally need to have deep expertise in AI native application development and face certain challenges, such as steep learning curve and complex integration.
Common AI enablement is implemented by providing an AI application framework. However, if simpler syntax expressions can be provided in languages to lower the threshold for developers to write AI native applications, the development will become simpler and more efficient. Therefore, the Cangjie language is committed to build a declarative paradigm similar to that in the AI domain through DSL capabilities by referring to the development of web and mobile technologies.
Agent DSL is a native AI capability that is in consideration and development in the Cangjie language. It is a domain-specific language designed for AI agent development and multi-agent collaboration and is embedded in the Cangjie language. So the Agent DSL is an eDSL. Developers do not need to learn complex libraries and frameworks and can use AI functions in a simple and intuitive manner through the Agent DSL.
// Definition of the Agent
@agent class Planner {
@prompt[pattern=APE] (
action: "Help users make a travel route.",
purpose: "Allow users to visit scenic spots within a planned time and get adequate rest.",
expectation: "Generate a reasonable travel route, including time, scenic spot, commute, and other information."
)
}
// Usage of the Agent
let agent = Planner()
let result = agent.chat("I want to go to Shanghai.")
Based on the above code snippet, it is clear that declaration and usage syntaxes of the Agent in the Cangjie language is the same as that of Cangjie syntax. In this way, use of the Agent can provide the static check capability of the Cangjie language without bringing extra learning burden to developers, fully utilizing the advantages of efficient programming, security, and reliability of the Cangjie language.
The Agent DSL not only improves the efficiency of AI application development, but also allows the code to accurately correspond to the operations and decision-making processes of the AI Agent. The overall design of the Agent DSL aims to achieve the following effects:
- Advanced abstraction: As a built-in language abstraction in the DSL, the definition and description of the Agent are more natural and intuitive, and are easy to understand and maintain.
- Simplified multi-agent collaboration programming: Different agent collaboration modes are abstracted through streaming symbols, and developers can easily utilize multi-agent collaboration to develop applications with higher intelligence.
- Intelligent development tool chain: On the basis of the Agent DSL, the tool chain provides developers with all-round intelligent support from application development to performance commissioning and optimization.
In addition to the Agent DSL, an AI native application framework is also being built. Through the cooperation between native languages and frameworks, developers can enjoy new application programming experience in the all-scenario intelligent era.
DSL Kit
It is well known that the threshold for compiling macro features is relatively high. DSL can be considered as a larger macro, which requires more attention to details and is more complex.

As the complexity increases, developers need to invest more energy, some of which is necessary (in blue) and some of which is extra (in yellow). Capabilities of the expert compiler master level are not expected to be a must for DSL development.
Therefore, DSL Kit extracts some commonalities created of DSL creation and provides a toolkit to eliminate the extra unnecessary efforts (in yellow).
In the first phase, it is expected to provide an easy declarative BNF syntax and automatically generate a syntax parser for the DSL, eliminating the complexity of manually writing parsers.
In the second phase, it is expected to provide more detailed check, analysis, and optimization capabilities. For example, semantics are added to the declarative syntax by referring to the attribute syntax, and the static check capability is provided with the compiler to help guarantee correctness of the DSL context for developers during compilation.
Actor and Distributed Programming
Concurrent programming and distributed programming are becoming increasingly important in multi-core and many-core hardware environments. Support for these capabilities has been considered since the early stage of Cangjie language design, and the design and prototype jobs have been preliminarily completed. These capabilities will be available in the near future.
With the built-in Actor feature and support for the type system in the Cangjie language, a secure and intuitive concurrent and distributed model can be provided for developers.
Actor is an abstract program concept used for concurrent operations. It is essentially used to create an operation instance and respond to a received message. For example, a newly created Actor sends a message to another Actor, and specifies the behavior to be generated when the next message is received. In this way, communication in concurrent threads is based on policies in these messages, thereby avoiding data race.
In the following simple example, the actor keyword is used to define Account as the Actor type, an instance function performWithdraw, and a receiver function withdraw. The receiver function can receive and process messages, and the instance function can access the internal status of the Actor.
actor Account {
instance var balance: Int64
init(x: Int64) {
this.balance = x
}
instance func performWithdraw(amount: Int64): Unit {
balance -= amount
}
receiver func withdraw(amount: Int64): Bool {
if (this.balance < amount) {
return false
} else {
this.performWithdraw(amount)
return true
}
}
}
It is worth mentioning that Cangjie's Actor is designed to support concurrent programming and distributed programming with a unified language feature. This enables developers to write concurrent or distributed programs using methods they are familiar with, and then easily move the programs to a distributed (for example, cluster) environment.
IDE AI Enablement
In mainstream IDE environments such as IntelliJ IDEA and VS Code, auxiliary development capabilities are provided. During the development by using the Cangjie language, AI-assisted programming capabilities are deployed. In the future, the main exploration will focus on code generation and knowledge Q&A. Currently, the preliminary code generation capability has been pre-researched, as shown in the following:
- Single-line code generation
When "(a:" is entered, code generation of the current line is triggered and the code of the current line can be supplemented by pressing tab.

- Code snippet generation
During the development by using the Cangjie language, if Enter is pressed, the generative model generates subsequent code snippets in the current position based on the preceding content and displays the subsequent code snippets in grayscale. The subsequent code snippets can be added by pressing Tab and canceled by pressing Esc.

In addition, the capabilities of generating code based on the subsequent content and supplementing character-level/token-level code are provided. The Cangjie language is committed to fully release the productivity of each developer and build an immersive coding experience with accurate intent recognition, excellent results, and good interaction.
Visualized Concurrent and Parallel Program Tuning
Cangjie provides excellent concurrent and parallel models. However, when using a concurrent and parallel model for development, a developer often encounters problems such as pseudo-parallelism, parallel failure, and parallel scheduling and spends a lot of time locating problems, resulting in low efficiency. In this case, a visualized concurrent and parallel tuning tool is required to help us quickly locate problems to master parallel scheduling information and find the performance bottleneck of parallel scheduling.
In the future, we will provide a visualized concurrent and parallel tuning tool to display the entire task scheduling period, including task statistics in different concurrency modes and the running status of a single task.
- In the measure lane, you can select different concurrency modes and view the change trend and number of tasks in different states. For example, if you want to know the number of running tasks in a period of time, you can move the pointer to the corresponding lane and view the exact number of tasks at a specified time.

- You can select different concurrency modes in the tasks lane to view the lifecycle information of related tasks and the running status of multiple tasks, helping you quickly detect concurrent and parallel problems.

Lexical Structure
This chapter describes the lexical structure of the Cangjie programming language. For the complete BNF of the lexicon and syntax, see"Cangjie Syntax."
Note: To improve the readability of the document, the syntax definition in the text body is slightly different from that in the appendix. In the text body, symbols and keywords are replaced with their literal representations (rather than names in the lexical structure).
Identifiers and Keywords
Identifiers are classified into common identifiers and raw identifiers. A common identifier starts with an underscore (ASCII code _) or an XID_Start character, followed by XID_Continue characters of any length, and the keyword Cangjie is removed. XID_Start and XID_Continue are properties defined in the Unicode Standard, as detailed in [Unicode Standard Annex #31] (https://www.unicode.org/reports/tr31/tr31-37.html). The current version used by Cangjie is 15.0.0. A raw identifier is a common identifier enclosed by a pair of backquotes (``). Keywords can also be used in within the backquotes.
Identifier
: Ident
| RawIdent
;
fragment RawIdent
: '`' Ident '`'
;
fragment Ident
: XID_Start XID_Continue*
| '_' XID_Continue+
;
In Cangjie, all identifiers are identified in the form of Normalization Form C (NFC). If two identifiers are equal after normalization to NFC, they are considered to be the same. For the definition of NFC, see Unicode tr15.
For example, the following are some valid Cangjie identifiers:
foo
_bar
Cangjie
`if`
Keywords are special character strings that cannot be used as identifiers. The following table lists the Cangjie keywords.
| Keyword | ||
|---|---|---|
| as | break | Bool |
| case | catch | class |
| const | continue | Rune |
| do | else | enum |
| extend | for | from |
| func | false | finally |
| foreign | Float16 | Float32 |
| Float64 | if | in |
| is | init | inout |
| import | interface | Int8 |
| Int16 | Int32 | Int64 |
| IntNative | let | mut |
| main | macro | match |
| Nothing | operator | prop |
| package | quote | return |
| spawn | super | static |
| struct | synchronized | try |
| this | true | type |
| throw | This | unsafe |
| Unit | UInt8 | UInt16 |
| UInt32 | UInt64 | UIntNative |
| var | VArray | where |
| while |
Contextual keywords are special strings that can be used as identifiers. They exist as keywords in some syntaxes, but can also be used as common identifiers.
| Contextual Keyword | ||
|---|---|---|
| abstract | open | override |
| private | protected | public |
| redef | get | set |
| sealed |
Semicolons and Newline Characters
There are two symbols that can indicate the end of an expression or declaration: a semicolon (;) and a newline character. The meaning of ; is fixed. It indicates the end of an expression or declaration regardless of its position, and multiple expressions or declarations can be written on the same line, separated by ;. However, the meaning of a newline character is not fixed. Depending on its position, it can be used as a separator between two tokens like a space character, or indicates the end of an expression or declaration like a ;.
A newline character can be used between any two tokens. Generally, the "longest match" principle (using as many tokens as possible to form a valid expression or declaration) is followed to determine whether to treat the newline character as the separator between tokens or the terminator of the expression or declaration. The newline character encountered before the "longest match" ends is treated as the separator between tokens, and that encountered after the "longest match" ends is treated as the terminator of the expression or declaration. The following shows examples:
let width1: Int32 = 32 // The newline character is treated as a terminator.
let length1: Int32 = 1024 // The newline character is treated as a terminator.
let width2: Int32 = 32; let length2: Int32 = 1024 // The newline character is treated as a terminator.
var x = 100 + // The newline character is treated as a separator.
200 * 300 - // The newline character is treated as a separator.
50 // The newline character is treated as a terminator.
However, the "longest match" principle does not apply to scenarios where a newline character cannot be used as the separator between two tokens, string literals, and multi-line comments. A newline character cannot be used as the separator between two tokens in the following scenarios:
-
Do not use a newline character as the separator between unary operator and operand.
-
In the calling expression, do not use a newline character as the separator between
(and its previoustoken. -
In an index access expression, do not use a newline character as the separator between
[and its previoustoken. -
In
constant pattern, do not use a newline character as the separator between$and the identifier following it.
Note: In the preceding scenarios, the newline character cannot be used as the separator between two tokens. It does not mean that the newline character cannot be used in these scenarios. (If a newline character is used, it will be directly treated as the terminator of the expression or declaration.)
The "longest match" principle does not apply to string literals and multi-line comments.
-
For a single-line string, when a non-escape double quotation mark is encountered for the first time, the matching ends.
-
For a multi-line string, when three non-escaped double quotation marks are encountered for the first time, the matching ends.
-
For a multi-line raw string, when the non-escape double quotation marks and the same number of comment tags (
#) at the beginning are encountered for the first time, the matching ends. -
For a multi-line comment, when the first
*/is encountered, the matching ends.
Literals
A literal is an expression that represents a value that cannot be modified.
Literals also have types. In Cangjie, the types of literals include integer, floating-point, Rune, Boolean, and string. The syntax of literals is as follows:
literalConstant
: IntegerLiteral
| FloatLiteral
| RuneLiteral
| booleanLiteral
| stringLiteral
;
stringLiteral
: lineStringLiteral
| multiLineStringLiteral
| MultiLineRawStringLiteral
;
Literals of the Integer Type
An integer literal can be expressed using four number notations: binary (using the 0b or 0B prefix), octal (using the 0o or 0O prefix), decimal (without a prefix), and hexadecimal (using the 0x or 0X prefix). In addition, you can add an optional suffix to specify the specific type of the integer literal.
The syntax of the literal of the integer type is defined as follows:
IntegerLiteralSuffix
: 'i8' |'i16' |'i32' |'i64' |'u8' |'u16' |'u32' | 'u64'
;
IntegerLiteral
: BinaryLiteral IntegerLiteralSuffix?
| OctalLiteral IntegerLiteralSuffix?
| DecimalLiteral '_'* IntegerLiteralSuffix?
| HexadecimalLiteral IntegerLiteralSuffix?
;
BinaryLiteral
: '0' [bB] BinDigit (BinDigit | '_')*
;
BinDigit
: [01]
;
OctalLiteral
: '0' [oO] OctalDigit (OctalDigit | '_')*
;
OctalDigit
: [0-7]
;
DecimalLiteral
: ([1-9] (DecimalDigit | '_')*) | DecimalDigit
;
DecimalDigit
: [0-9]
;
HexadecimalLiteral
: '0' [xX] HexadecimalDigits
;
HexadecimalDigits
: HexadecimalDigit (HexadecimalDigit | '_')*
;
HexadecimalDigit
: [0-9a-fA-F]
;
The mappings between suffixes and types for IntegerLiteralSuffix are as follows:
| Suffix | Type | Suffix | Type |
|---|---|---|---|
| i8 | Int8 | u8 | UInt8 |
| i16 | Int16 | u16 | UInt16 |
| i32 | Int32 | u32 | UInt32 |
| i64 | Int64 | u64 | UInt64 |
Literals of the Floating-Point Type
A floating-point literal can be expressed in two formats: decimal (without a prefix) and hexadecimal (with a 0x or 0X prefix). In a decimal floating-point number, either the integer part or the fractional part (including the decimal point), or both, must be contained. If there is no decimal part, the exponent part (with an e or E prefix) is required. In a decimal floating-point number, the integer part, the fractional part (including the decimal point), or both, must be contained, and the exponent part (with a p or P prefix) is required. In addition, you can add an optional suffix to specify the specific type of the floating-point literal.
The syntax of the literal of the floating-point type is defined as follows:
FloatLiteralSuffix
: 'f16' | 'f32' | 'f64'
;
FloatLiteral
: (DecimalLiteral DecimalExponent | DecimalFraction DecimalExponent? | (DecimalLiteral DecimalFraction) DecimalExponent?) FloatLiteralSuffix?
| (Hexadecimalprefix (HexadecimalDigits | HexadecimalFraction | (HexadecimalDigits HexadecimalFraction)) HexadecimalExponent)
DecimalFraction
: '.' DecimalFragment
;
DecimalFragment
: DecimalDigit (DecimalDigit | '_')*
;
DecimalExponent
: FloatE Sign? DecimalFragment
;
HexadecimalFraction
: '.' HexadecimalDigits
;
HexadecimalExponent
: FloatP Sign? DecimalFragment
;
FloatE
: [eE]
;
FloatP
: [pP]
;
Sign
: [-]
;
Hexadecimalprefix
: '0' [xX]
;
The mappings between suffixes and types for FloatLiteralSuffix are as follows:
| Suffix | Type |
|---|---|
| f16 | Float16 |
| f32 | Float32 |
| f64 | Float64 |
Literals of the Boolean Type
There are only two boolean type literals: true and false.
booleanLiteral
: 'true'
| 'false'
;
Literals of the String Type
String literals are classified into three types: single-line string literals, multi-line string literals, and multi-line raw string literals.
Single-line string literals are defined using a pair of single or double quotation marks. The content in the quotation marks can be any number of characters. To include a quotation mark or a backslash (\) as part of the string, add a backslash (\) before it. A single-line string literal cannot span multiple lines by including newline characters.
The syntax of single-line string literals is defined as follows:
lineStringLiteral
: '"' (lineStringExpression | lineStringContent)* '"'
;
lineStringExpression
: '${' SEMI* (expressionOrDeclaration (SEMI+ expressionOrDeclaration?)*) SEMI* '}'
;
lineStringContent
: LineStrText
;
LineStrText
: ~["\\\r\n]
| EscapeSeq
;
A multi-line string literal must start and end with three double quotation marks (""") or three single quotation marks ('''). The content in the quotation marks can be any number of characters. To include the three quotation marks (" or ') used to enclose the string or backslashes (\) as part of the string, you must add backslashes (\) before them. If there is no newline character after the three double quotation marks at the beginning, or no non-escape double quotation marks are encountered before the end of the current file, a compilation error is reported. Unlike single-line string literals, multi-line string literals can span multiple lines.
The syntax of multi-line string literals is defined as follows:
multiLineStringLiteral
: '"""' NL (multiLineStringExpression | multiLineStringContent)* '"""'
;
multiLineStringExpression
: '${' end* (expressionOrDeclaration (end+ expressionOrDeclaration?)*) end* '}'
;
multiLineStringContent
: MultiLineStrText
;
MultiLineStrText
: ~('\\')
| EscapeSeq
;
A multi-line raw string literal starts and ends with one or more comment tags (#) and one single quotation mark (') or double quotation mark ("). Both the number of comment tags and the quotation marks at the end are the same as those at the beginning. The literal content can be any number of valid characters. Before the current file ends, if no matching quotation mark and the same number of comment tags are encountered, a compilation error is reported. Like multi-line string literals, a multi-line raw string literal can span multiple lines. The difference is that escape rules do not apply to multi-line raw string literals. The content in the literals remains unchanged (escape characters are not escaped).
The syntax of multi-line raw string literals is defined as follows:
MultiLineRawStringLiteral
: MultiLineRawStringContent
;
fragment MultiLineRawStringContent
: '#' MultiLineRawStringContent '#'
| '#' '"' .*? '"' '#'
;
Literals of the Rune Type
A Rune literal starts with the character r, followed by a single-line string literal (with single or double quotation marks). The string literal must contain exactly one character. The syntax is as follows:
RuneLiteral
: 'r' '\'' (SingleChar | EscapeSeq) '\''
: 'r' '"' (SingleChar | EscapeSeq) '"'
;
fragment SingleChar
: ~['\\\r\n]
;
EscapeSeq
: UniCharacterLiteral
| EscapedIdentifier
;
fragment UniCharacterLiteral
: '\\' 'u' '{' HexadecimalDigit '}'
| '\\' 'u' '{' HexadecimalDigit HexadecimalDigit '}'
| '\\' 'u' '{' HexadecimalDigit HexadecimalDigit HexadecimalDigit '}'
| '\\' 'u' '{' HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit '}'
| '\\' 'u' '{' HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit '}'
| '\\' 'u' '{' HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit '}'
| '\\' 'u' '{' HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit '}'
| '\\' 'u' '{' HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit '}'
;
fragment EscapedIdentifier
: '\\' ('t' | 'b' | 'r' | 'n' | '\'' | '"' | '\\' | 'f' | 'v' | '0' | '$')
;
Operators
The following table lists all operators supported by Cangjie, with higher priority operators appearing at the top. For details about each operator, see [Expressions].
| Operator | Description |
|---|---|
@ | Macro call expression |
. | Member access |
[] | Index access |
() | Function call |
++ | Postfix increment |
-- | Postfix decrement |
? | Question mark |
! | Logic NOT |
- | Unary negative |
** | Power |
* | Multiply |
/ | Divide |
% | Remainder |
+ | Add |
- | Subtract |
<< | Bitwise left shift |
>> | Bitwise right shift |
.. | Range operator |
..= | |
< | Less than |
<= | Less than or equal |
> | Greater than |
>= | Greater than or equal |
is | Type test |
as | Type cast |
== | Equal |
!= | Not equal |
& | Bitwise AND |
^ | Bitwise XOR |
| ` | ` |
&& | Logic AND |
| ` | |
?? | coalescing |
| ` | >` |
~> | Composition |
= | Assignment |
**= | Compound assignment |
*= | |
/= | |
%= | |
+= | |
-= | |
<<= | |
>>= | |
&= | |
^= | |
| ` | =` |
&&= | |
| ` |
Comments
Cangjie supports the following comment formats:
A single-line comment starts with //. The syntax is as follows:
LineComment
: '//' ~[\n\r]*
;
A multi-line comment is enclosed with /* and */ and supports nesting. The syntax is as follows:
DelimitedComment
: '/*' ( DelimitedComment | . )*? '*/'
;
Types
The Cangjie programming language is a statically-typed language. Most type checks that ensure program security occur during compilation. In addition, the Cangjie programming language is a strongly-typed language. Each expression has a type, and the type of an expression determines its value space and supported operations. Statically-typed and strongly-typed mechanisms can help programmers locate a large number of program errors caused by types during compilation.
Types in Cangjie may be classified into the immutable types and mutable types. Immutable types include the numeric (which can be an integer or a floating-point number, see [Numeric]), Rune, Bool, Unit, Nothing, String, Tuple, Range, Function, and enum. Mutable types include Array, VArray, struct, class, and interface.
The difference between the immutable type and the mutable type is that the data value of the immutable type does not change after initialization, and the data value of the mutable type can be changed after initialization.
The following describes each type, values of types, and operations supported by types.
Immutable Types
The following sequentially describes immutable types in the Cangjie programming language.
Numeric
Numeric types include integer and floating-point number types, which are respectively used to represent integers and floating-point numbers. Integer types include signed integer and unsigned integer types. Signed integer types include Int8, Int16, Int32, Int64, and IntNative, indicating signed integers whose encoding length are 8 bits, 16 bits, 32 bits, 64 bits, and platform-dependent sizes, respectively. Unsigned integer types include UInt8, UInt16, UInt32, UInt64, and UIntNative, indicating unsigned integers whose encoding length are 8 bits, 16 bits, 32 bits, 64 bits, and platform-related sizes, respectively. Floating-point number types include Float16, Float32, and Float64, indicating floating-point numbers whose encoding lengths are 16 bits, 32 bits, and 64 bits, respectively.
The lengths of IntNative and UIntNative are the same as the bit width of the current system.
The following table lists all numeric types and their ranges.
| Type | Range |
|---|---|
| Int8 | $-2^7 \sim 2^7-1$ (-128 to 127) |
| Int16 | $-2^{15} \sim 2^{15}-1$ (-32768 to 32767) |
| Int32 | $-2^{31} \sim 2^{31}-1$ (-2147483648 to 2147483647) |
| Int64 | $-2^{63} \sim 2^{63}-1$ (-9223372036854775808 to 9223372036854775807) |
| IntNative | platform dependent |
| UInt8 | $0 \sim 2^8-1$ (0 to 255) |
| UInt16 | $0 \sim 2^{16}-1$ (0 to 65535) |
| UInt32 | $0 \sim 2^{32}-1$ (0 to 4294967295) |
| UInt64 | $0 \sim 2^{64}-1$ (0 to 18446744073709551615) |
| UIntNative | platform dependent |
| Float16 | See IEEE 754 binary16 format |
| Float32 | See IEEE 754 binary32 format |
| Float64 | See IEEE 754 binary64 format |
For ease of use, the Cangjie programming language specifically provides some type aliases (for details about the type aliases, refer to the type alias section below):
Byteis used as the type alias ofUInt8. TheBytetype is equivalent to theUInt8type.IntandUIntare used as the aliases of theInt64andUInt64types, respectively. TheInttype is equivalent to theInt64type, and theUInttype is equivalent to theUInt64type.
let a: UInt8 = 128
let b: Byte = a // ok
let c: Int64 = 9223372036854775807
let d: Int = c // ok
let e: UInt64 = 18446744073709551615
let f: UInt = e // ok
The following describes numeric literals and operations supported by the numeric type.
Numeric Literals
Values such as 5, 24, 2.9, and 3.14 are numeric literals. Literals can only be called by their values, and cannot be changed.
The following describes integer literals and floating-point literals:
Integer literals can be expressed in four forms: binary, octal, decimal, and hexadecimal. The binary value starts with 0b (or 0B), the octal value starts with 0o (or 0O), the hexadecimal value starts with 0x (or 0X), and the decimal value has no prefix. For example, the decimal value 24 may be defined as any one of the following four forms, where the underlined _ is used as a separator to facilitate identification of a quantity of digits of the value.
0b0001_1000 // Binary.
0o30 // Octal.
24 // Decimal.
0x18 // Hexadecimal.
For the syntax definition of integer literals, see [Integer Literals].
Floating-point types comply with the IEEE 754 format. Float16 uses the half-precision format (binary16) of IEEE 754, Float32 uses the single-precision format (binary32) of IEEE 754, and Float64 uses the double-precision format (binary64) of IEEE 754. Generally, a floating-point number contains the integer part, decimal part (including the decimal point), and exponent part. It can be notated in decimal or hexadecimal format. In the decimal format, a floating-point number must contain an integer or a decimal. If there is no decimal, the floating-point literal must contain the exponent part (with e or E as the prefix and 10 as the base number). In the hexadecimal format, a floating-point number must contain an integer or a decimal (with 0x as the prefix) and the exponent part (with p or P as the prefix and 2 as the base number). Pay attention to the following special values in floating-point parameters: positive infinity (POSITIVE_INFINITY), negative infinity (NEGATIVE_INFINITY), Not a Number (NaN), positive 0 (+0.0), and negative 0 (-0.0). Infinity indicates that an operation result exceeds a representation range. For example, when two large floating-point numbers are multiplied, or a non-zero floating-point number is divided by a floating-point zero, the result is infinity, and a sign of infinity is determined by a sign of an operand, complying with the following rule: A positive and a negative make a negative, and two negatives make a positive. NaN indicates that the value is neither a real number nor an infinity. For example, the result of multiplying positive infinity by 0 is NaN. The following is an example of a floating-point literal:
3.14 // decimal Float64 3.14.
2.4e-1 // decimal Float64 0.24.
2e3 // decimal Float64 2000.0.
.8 // decimal Float64 0.8.
.123e2 // decimal Float64 12.3.
0x1.1p0 // hexadecimal Float64 1.0625 (decimal value).
0x1p2 // hexadecimal Float64 4 (decimal value).
0x.2p4 // hexadecimal Float64 2 (decimal value).
For the syntax definition of floating-point literals, see [Floating-Point Literals].
A minimum positive value of a floating-point decimal type in the Cangjie programming language is a subnormal floating-point number.
For the Float32 type, the minimum positive floating-point number is $2^{-149}$, which is about 1.4e-45. The maximum positive floating-point number is $(2 - 2^{-23}) \times 2^{127}$, which is about 3.40282e38.
For the Float64 type, the minimum positive floating-point number is $2^{-1074}$, which is about 4.9e-324. The maximum positive floating-point number is $(2 - 2^{-52}) \times 2^{1023}$, which is about 1.79769e308.
If the face value of a floating-point decimal other than $0$ is rounded to $0$ or infinity because it is too small or too large, the compiler generates an alarm.
Operators Supported by Numeric Types
Numeric types support the following operators: arithmetic operators, bitwise operators, relational operators, increment and decrement operators, unary minus operators, and (compound) assignment operators. The integer type supports all the preceding operators, and the floating-point type supports all operators except bitwise operators. Therefore, the following briefly describes these operators of the integer type. For details, see [Expressions].
Arithmetic operators include addition (+), subtraction (-), multiplication (*), division (/), modulo (%), and power (**). By default, if arithmetic operators are not overloaded (see [Operator Overloading] for details about how to overload operators), the two operands of arithmetic operators must be of the same type. To operate two operands of different types, forcibly convert the type first. For details about the priority and binding of arithmetic operators, see [Arithmetic Expressions]. The following example describes an arithmetic operation on an integer type:
2 + 3 // add result: 5
3 - 1 // sub result: 2
3 * 9 // mul result: 27
24 / 8 // div result: 3
7 % 3 // mod result: 1
2 ** 3 // power result: 8
5 + 15 - 2 * 10 / 4 // result: 15
5 + 10 - 3 * 4 ** 2 / 3 % 5 // result: 14
Bitwise operators include bitwise NOT (!), left shift (<<), right shift (>>), bitwise AND (&), bitwise XOR (^), and bitwise OR (|). For details about bitwise operators, see [Bitwise Operation Expressions]. The following example describes a bit operation on an integer type:
!10 // bitwise logical NOT operator: -11
10 << 1 // left shift operator: 10*2=20
10 >> 1 // right shift operator: 10/2=5
10 & 15 // bitwise logical AND operator: 10
10 ^ 15 // bitwise XOR operator: 5
10 | 15 // bitwise logical OR operator: 15
0b1010 & 0b1110 ^ 0b1111 | 0b0101 // result: 0b0101
Relational operators include less than (<), greater than (>), less than or equal to (<=), greater than or equal to (>=), equal to (==), and not equal to (!=). The result of a relational expression is a value of the Bool type (true or false). For details about relational operators, see [Relational Expressions]. The following example describes a relational operation on an integer type:
2 == 3 // result: false
2 != 3 // result: true
8 < 10 // result: true
9 <= 9 // result: true
24 > 28 // result: false
24 >= 23 // result: true
Increment and decrement operators include increment (++) and decrement (--), which can be considered as special assignment operators (see below) to increase or decrease the value of a variable by 1. Increment and decrement operators can be used only as a suffix operator and can be used only for mutable variables of the integer type, because the values of immutable variables and integer literals cannot be modified. For details about the increment and decrement operators, see [Increment and Decrement Expressions]. The following example describes an increment or decrement operation on an integer type:
main() {
var i: Int32 = 5
var j: Int32 = 6
i++ // i=6
j-- // j=5
return 0
}
A unary minus operator is represented by -, and the result is the negative of its operand. For details about -, see the description of [Arithmetic Expressions]. The following example describes a unary minus operation on an integer type:
var i: Int32 = 5
var j: Int64 = 100
var k: Int32 = -i // k = -5
var l: Int64 = -j // l = -100
(Compound) assignment operators include assignment (=) and compound assignment (op=). op can be any binary operator among arithmetic operators, logical operators, and bitwise operators. The (compound) assignment operation can assign a value of an expression of the numeric type to a variable of the numeric type. For details about (compound) assignment operators, see [Assignment Expressions]. The following example describes a (compound) assignment on an integer type:
main() {
var x: Int64 = 5
var y: Int64 = 10
x = y // assignment: x = 10
x += y // compound assignment: x = 20
x -= y // x = 10
x *= y // x = 100
x /= y // x = 10
x %= y // x = 0
x = 5 // x = 5
x **= 2 // x = 25
x <<= 1 // x = 50
x >>= 2 // x = 12
x &= y // x = 8
x ^= y // x = 2
x |= y // x = 10
return 0
}
Operators Supported by Floating-Point Numbers
Floating-point types support the following operations (except bit operations): arithmetic operations, relational operations, increment and decrement operations, unary positive (negative) operations, conditional operations, and (composite) assignment operations. The calculation of floating-point numbers may use operations with different precisions from their own types. Note the following special cases in floating-point operations: In a relational expression, if the value of an operand is NaN, the result of the expression is false, except that the results of NaN != x and x != NaN are true (x can be any floating-point number including NaN).
let x = NaN
var y = 3.14
var z = x < y // z = false
var v = x != x // v = true
var w = (x < y) == !(x >= y) // w = false
In arithmetic expressions, values containing NaN or infinite expressions comply with the IEEE 754 standard.
Rune
The Cangjie programming language uses the Rune type to represent Unicode code point. These values can be classified into printable characters, non-printable characters (characters that cannot be displayed, such as control characters), and special characters (such as single quotation marks and backslashes).
-
Rune literals
For the syntax definition of
Runeliterals, see [Rune Literals].
A Rune literal consists of a pair of single quotation marks and characters, for example:
'S'
'5'
' ' // blank
Non-printable and special character literals are defined using escape characters (\):
| Escape Character | Character |
|---|---|
\0 | Empty character |
\\ | backslash \ |
\b | Backspace |
\f | Writer |
\n | New line |
\r | Enter |
\t | Horizontal tab |
\v | Vertical tab |
\' | Single quotation mark ' |
\" | Double quotation marks " |
\u{X} | Any Unicode code point, where X is a 1-8 digit hexadecimal number |
-
Operations supported by the
RunetypeThe
Runetype supports only relational operators (compared based on theUnicode code point).main() { 'A'=='A' // result: true 'A'!='A' // result: false 'A'<'a' // result: true 'A'<='A' // result: true 'A'>'a' // result: false 'A'>='A' // result: true return 0 }
Boolean
The Cangjie programming language uses Bool to indicate the Boolean type.
-
BoolliteralThe
Booltype has only two literals:trueandfalse.let bool1: Bool = true let bool2: Bool = false -
Operations supported by the
BooltypeThe Cangjie programming language does not support type conversion between the numeric type and
Bool. Non-Boolvalues cannot be used asBoolvalues. Otherwise, a compilation error is reported. TheBooltype supports the following operations: assignment, partial compound assignment (&&=and||=), partial relation (==and!=), and all logical operations (!,&&, and||). The following is an example:main() { let bool1: Bool = true var bool2: Bool = false bool2 = true // assignment bool2 &&= bool1 // bool2=true bool2 ||= bool1 // bool2=true true == false // return false true != false // return true !false // logical NOT, return true true && false // logical AND, return false false || false // logical OR, return false return 0 }
Unit
The Unit type has only one value: ().
Nothing
Nothing is a special type that does not contain any value, and Nothing is a subtype of all types. Nothing indicates dead code. For example, if a variable is of the Nothing type, it will never be used, and no memory needs to be created for it. If a parameter of a function call is of the Nothing type, the subsequent parameters will not be evaluated, and the function call itself will not be executed. If an expression in a block is of the Nothing type, all expressions and declarations following the expression will not be executed. The Cangjie compiler generates a compilation alarm for the detected dead code.
For details about which expressions have the Nothing type, see [Control Transfer Expressions].
String
The Cangjie programming language uses String to indicate the string type, which is used to express text data and consists of a string of Unicode characters.
String Literals
String literals are classified into three types: single-line string literals, multi-line string literals, and multi-line original string literals.
For details about the syntax definition of string literals, see [String Type Literals].
Single-line string literals are defined using a pair of double quotation marks (for example, "singleLineStringLiteral"). The content in the double quotation marks can be any number of characters (except non-escaped double quotation marks and a separate \). A single-line string literal can be written in only one line.
let s1 = "" // empty string
let s2: String = "Hello Cangjie Lang" // define string s2
var s3 = "\"Hello Cangjie Lang\"" // define string s3 containing character "
var s4: String = "Hello Cangjie Lang\n" // define string s4 containing character \n
// illegal string with character \
let s5 = "hello\"
// illegal string with character "
let s6 = "Hello "Cangjie Lang"
A multi-line string literal starts and ends with three double quotation marks ("""). A new line is required after the double quotation marks at the beginning. Otherwise, an error is reported. The literal starts from the first line after the double quotation marks at the beginning and ends with the first three non-escaped double quotation marks. The content between the literals can be any number of valid characters (except the three non-escaped double quotation marks """ and the separate \). Before the current file ends, if the three non-escaped double quotation marks are not encountered, a compilation error is reported. Unlike single-line string literals, multi-line string literals can span multiple lines.
// empty multi-line string
let s1 = """
"""
// Error: there must be a line terminator after the beginning double quotations.
let errorStr = """abc
"""
/*
The result of s2 is:
This
is a multi-line string
*/
let s2 = """
This
is a multi-line string"""
/*
The result of s3 is:
This
is a multi-line string
*/
let s3 = """
This
is a multi-line string"""
/*
The result of s4 is:
This
is a
multi-line string
*/
let s4 = """
This
is a
multi-line string
"""
/*
The result of s5 is:
This is a
multi-line string
*/
let s5 = """
This is a\n
multi-line string
"""
Multi-line original string literal starts with one or more comment tags (#) and a double quotation mark ("), and ends with a double quotation mark (") and the number of comment tags (#) at the beginning. Note that the matching ends when the string literal value encounters the first matched double quotation mark (") and the number of comment tags (#) at the beginning. The content between the start and end double quotation marks (") can be any number of valid characters (except a double quotation mark and the same number of comment tags (#) at the beginning). Before the current file ends, if no matching quotation mark and the same number of comment tags are encountered, a compilation error is reported. Unlike (common) multi-line string literals, the content in the original multi-line string literal remains unchanged (escape characters are not escaped).
// empty multi-line raw string
let empty1 = #""#
// empty multi-line raw string
let empty2 = ##""##
/*
The result of s2 is:
This
is a multi-line string
*/
let s2 = ##"
This
is a multi-line raw string"##
/*
The result of s3 is:
This is a\n
multi-line string
*/
let s3 = #"This is a\n
multi-line string"#
/*
The result of s4 is:
This is a "#
*/
let s4 = ##" This is a "#
"##
// Error: the beginning and ending numbers of `#` are not matched.
let errorStr1 = ##" error string "#
// Error: the beginning and ending numbers of `#` are not matched.
let errorStr2 = ##" error string "###
// Error: the string literal is terminated when meeting the first matched `"##`.
let errorStr3 = ##" error string "## error "##
The String type can be determined to equality using == (inequality using !=). Two character strings are the same only when their corresponding code point sequences are the same.
Interpolated String
An interpolated string is a string literal that contains one or more interpolation expressions (not applicable to multi-line raw string literals). When an interpolation string is parsed into a result string, the position of each interpolation expression is replaced with the result of the corresponding expression.
Each interpolation expression must be enclosed in {} parentheses and prefixed with $. The expression and declaration sequence in braces can be the same as that in [Block], but cannot be empty. Interpolation expressions in multi-line strings support line breaks.
let obj = "apples"
let count = 10
let interps1 = "There are ${count * count} ${obj}."
// The result of "interps1" is: There are 100 apples.
let error = "Empty sequence is not allowed ${}" // Error
If the $ symbol in the character string is not followed by the { symbol, the character string is processed as a common $ symbol.
If the escape character \ is added before $, no matter whether $ is followed by {, $ is not processed as an interpolation expression.
let d1 = "The $ sign."
// The result of "d1" is: The $ sign.
let d2 = "The \${v}."
// The result of "d2" is: The ${v}.
Interpolation expressions also support user-defined types as long as the types meet the ToString interface restrictions. The preceding types meet the ToString interface requirement.
Tuple
In the Cangjie programming language, a Tuple type is an immutable type formed by combining a plurality of different types, and is represented by (Type1, Type2, ..., TypeN), where N indicates a dimension of the tuple. The tuple types are described as follows:
-
Type1toTypeNcan be of any type (N must be greater than or equal to 2, that is,Tuplemust be at least binary). -
For each dimension of a tuple, for example, the Kth dimension, an instance of any
TypeKsubtype may be stored. -
When
Type1toTypeNin(Type1, Type2, ..., TypeN)use==for value equality (!=for value inequality), theTupletype supports==for value equality (!=is used for value inequality). Otherwise, theTupletype does not support==and!=. In this case, if==and!=are used, an error is reported during compilation. TwoTupleinstances of the same type are equal only when all elements in the same position (index) are equal (indicating that their lengths are equal).
The syntax of the Tuple type is defined as follows:
tupleType
: '(' type (',' type)+ ')'
;
Tuple Literals
A tuple literal is expressed in the format of (expr1, expr2, ..., exprN). Multiple expressions are separated by commas (,), and each expression can have a different type. The syntax of the Tuple literal is defined as follows:
tupleLiteral
: '(' expression (',' expression)+ ')'
;
Example of tuple literals:
(3.14, "PIE")
(2.4, 3.5)
(2, 3, 4)
((2, 3), 4)
Deconstructing a Tuple
A tuple can also be used to deconstruct another tuple value. Elements at different positions in a tuple are bound to different variables. The following example shows how to deconstruct the return value of a multi-return-value function:
func multiValues(a: Int32, b: Int32): (Int32, Int32) {
return (a + b, a - b) // The type of the return value of the function multiValues is (Int32, Int32).
}
main() {
var (x, y) = multiValues(8,24) // Define an anonymous tuple who has two elements, i.e., x and y.
print("${x}") // output: 32
print("${y}") // output: -16
return 0
}
Access Through a Tuple Index
A tuple allows you to access an element in a specific position using tupleName[index]. (index starts from 0 and can only be a literal of the Int64 type.)
main() {
var z = multiValues(8, 24) // the type of z is inferred to be (Int32, Int32)
print("${z[0]}") // output: 32
print("${z[1]}") // output: -16
return 0
}
Defining a Variable of the Tuple Type
When defining a variable of the tuple type, you can omit the type annotation. The compiler infers the specific type based on the program context.
let tuplePIE = (3.14, "PIE") // The type of tuplePIE is inferred to be (Float64, String).
var pointOne = (2.4, 3.5) // The type of pointOne is inferred to be (Float64, Float64).
var pointTwo = (2, 3, 4) // The type of pointTwo is inferred to be (Int64, Int64, Int64).
var pointThree = ((2, 3), 4) // The type of pointThree is inferred to be ((Int64, Int64), Int64).
Range
The Cangjie programming language uses Range<T> to indicate the Range type, and requires that T can be instantiated only to implement the Comparable interface and Countable interface types. The Range type is used to represent a sequence with a fixed step and is an immutable type.
Each Range<T> instance contains the following values: start, end, and step. start and end indicate a start value and an end value of the sequence, respectively. step indicates a difference between two adjacent elements in the sequence.
The Range type can be determined to equality using == (inequality using !=). Two Range instances of the same type are the same only when they are both left-closed and right-open or left-closed and right-closed, the values of start, end, and step are the same.
Creating a Range Instance
There are two Range operators: .. and ..=, which are used to create left-closed and right-open Range instances and left-closed and right-closed Range instances, respectively. They are used in start..end:step and start..=end:step, in which start, end, and step are expressions. The two expressions are described as follows:
-
The types of
startandendmust be the same, and the type ofstepmust beInt64. -
In the expression
start..end:step, whenstep > 0andstart >= endorstep < 0andstart <= end,start..end:stepreturns an emptyRangeinstance (an empty sequence that does not contain any element). If the result ofstart..end:stepis a non-emptyRangeinstance, the number of elements in theRangeinstance is equal to the round-up value of(end-start)/step(that is, greater than or equal to the minimum integer of(end-start)/step). -
In the expression
start..=end:step, whenstep > 0andstart > endorstep < 0andstart < end,start..=end:stepreturns an emptyRangeinstance. If the result ofstart..=end:stepis a non-emptyRangeinstance, the number of elements in theRangeinstance is equal to the round-down value of((end-start)/step)+1(that is, less than or equal to the maximum integer of((end-start)/step)+1).
let range1 = 0..10:1 // Define a half-open range [0,10) (with step = 1) which contains 0, 1, 2, 3, 4, 5, 6, 7, 8 and 9.
let range2 = 0..=10:2 // Define a closed range [0,10] (with step = 2) which contains 0, 2, 4, 6, 8 and 10.
let range3 = 10..0:-2 // Define a half-open range [10,0) (with step = -2) which contains 10, 8, 6, 4 and 2.
let range4 = 10..=0:-1 // Define a closed range [10,0] (with step = -1) which contains 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 and 0.
let range5 = 10..0:1 // Define an empty range.
let range6 = 0..0:1 // Define an empty range.
let range7 = 0..=0:1 // Define a closed range [0,0] (with step = 1) which only contains 0.
let range8 = 0..=10:-1 // Define an empty range.
- In the
start..end:stepandstart..=end:stepexpressions, the value ofstepcannot be0.
let range9 = 0..10: 0 // error: the value of the step should not be zero.
let range10 = 0..=10: 0 // error: the value of the step should not be zero.
- When the
Range<Int64>instance is used in the index operator[],startorendcan be omitted. In other scenarios,startandendare required, and onlystepis optional (step=1is used by default).
let range11 = 1..10 // Define a half-open range [1, 10) with step = 1.
let range12 = 1..=10 // Define a closed range [1, 10] with step = 1.
let range13 = ..10 // error: the start value is required.
let range14 = 1.. // error: the end value is required.
let range15 = .. // error: the start and end value are required.
Using a Range Type
Expressions of the Range type are mainly used in for-in expressions (see [Loop Expressions]) and are used as indexes to truncate segments. Note that:
- When an instance of the
Range<Int64>type is used in the index operator[], bothstartandendare optional. Their values are determined by the context. If the index operator[]is overloaded on a custom type and the parameter type isRange<Int64>, the value ofstartis0whenstartis omitted, and the value ofendis equal to the maximum value ofInt64whenendis omitted.
Defining a Variable of the Range Type
When defining a variable of the Range<T> type, you can explicitly add a type annotation or omit the type annotation (in this case, the compiler infers the type annotation based on the program context).
let range16: Range<Int64> = 0..10 // Define a half-open range [0,10) with step = 1
let range17: Range<Int64> = -10..10:2 // Define a half-open range [-10,10) with step = 2
let range18 = 0..=10 // Define a closed range [0,10] with step = 1
let range19 = -10..=10:2 // Define a closed range [-10,10] with step = 2
Function
A function type represents a type of a specific function, and is immutable. The syntax of the function type is defined as follows:
arrowType
: parameterTypes '->' type
;
parameterTypes
: '(' (type (',' type)*)? ')'
;
parameterTypes (parameter type list) and type (return type) are connected using ->. A pair of () in the parameter type list is required. () can contain zero or more types (multiple types are separated by ,).
() -> Int32 // A function type has an empty parameter type list, and its return value type is 'Int32'.
() -> Unit // A function type has an empty parameter type list, and its return value type is 'Unit'.
(Float32) -> Int32 // A function type has one parameter whose type is 'Float32', and its return value type is 'Int32'
(Int32, Int32, Float32) -> Int32 // A function type has three parameters, and its return value type is 'Int32'
(Int32, Int32, Float32) -> (Int32, Int32) // A function type has three parameters, and its return value type is '(Int32, Int32)'
(Int32, Int32, Float32) -> Unit // A function type has three parameters, and its return value type is 'Unit'.
In the Cangjie programming language, a function is a first-class citizen, which indicates that the function can be used as a parameter of another function, can be used as a return value of another function, or can be directly assigned to a variable.
The function type does not support == or != for equality or inequality, respectively. For more information about functions, see [Functions].
Enum
The enum type is an immutable type used to organize a set of related values (which are called constructor). A value of the enum type can be obtained only from a constructor defined in the enum type at any time.
Defining the Enum Type
The syntax for defining the enum type is as follows:
enumDefinition
: enumModifier? 'enum' identifier typeParameters? ('<:' superInterfaces)? genericConstraints? '{' enumBody '}'
;
enumBody
: '|'? caseBody ('|' caseBody)* (functionDefinition | operatorFunctionDefinition | propertyDefinition | macroExpression)*
;
caseBody
: identifier ('(' type (',' type)* ')')?
;
enumModifier is the modifier (that is, public) of the enum type, enum is the keyword, identifier is the name of the enum type, and typeParameters and genericConstraints are the type variable list and type variable constraints, respectively. For details, see [Generics]. Multiple values of caseBody (constructors) can be defined in enumBody. Each constructor can have no parameter or a group of parameters of different types. Multiple constructors are separated by |. Before the first constructor, | can exist, which is optional. You can define other members of the enum after caseBody, including member functions, operator overloading functions, and member attributes.
The following is an example of the enum type:
/*
Define an enum type 'TimeUnit1' who has four constructors: 'Year', 'Month', 'Day' and 'Hour'.
*/
enum TimeUnit1 {
Year | Month | Day | Hour
}
/*
'TimeUnit2' has four constructors: 'Year(Int32)', 'Month(Int32, Float32)', 'Day(Int32, Float32, Float32)' and 'Hour(Int32, Float32, Float32, Float32)'.
*/
enum TimeUnit2 {
| Year(Float32)
| Month(Float32, Float32)
| Day(Float32, Float32, Float32)
| Hour(Float32, Float32, Float32, Float32)
}
/*
Define a generic enum type 'TimeUnit3<T1, T2>' who has four constructors: 'Year(T1)', 'Month(T1, T2)', 'Day(T1, T2, T2)' and 'Hour(T1, T2, T2, T2)'.
*/
enum TimeUnit3<T1, T2> {
| Year(T1)
| Month(T1, T2)
| Day(T1, T2, T2)
| Hour(T1, T2, T2, T2)
}
Pay attention to the following points about the enum type:
-
The
enumtype can be defined only intop-level. -
The
constructordefinition without parentheses or parameters is not supported. The type of theconstructorwithout parameters is the definedenumtype and is not considered as the function type. Aconstructorwith parameters has a function type, but cannot be used as a first-class citizen. For example:
enum E {
| mkE // OK. The type of mkE is E but not () -> E.
| mkE() // Syntax error.
}
enum E1 {
| A
}
let a = A // ok, a: E1
enum E2 {
| B(Bool)
}
let b = B // error
enum E3 {
| C
| C(Bool)
}
let c = C // ok, c: E3
-
As a user-defined type, the
enumtype does not support==for equality or!=for inequality by default. You can overload the==or!=operator (see [Operator Overloading]) to enable the customenumtype to support==or!=. -
The same
enumsupportsconstructoroverloading, but only the number of parameters is involved in overloading. That is, multipleconstructorswith the same name can be defined in the sameenum, but the number of parameters must be different. (Aconstructorwithout parameters can be overloaded with otherconstructorsalthough it is not a function type.) For example:
enum TimeUnit4 {
| Year
| Year(Int32) // ok
| Year(Float32) // error: redeclaration of 'Year'
| Month(Int32, Float32) // ok
| Month(Int32, Int32) // error: redeclaration of 'Month'
| Month(Int32) // ok
| Day(Int32, Float32, Float32) // ok
| Day(Float32, Float32, Float32) // error: redeclaration of 'Day'
| Day(Float32, Float32) // ok
| Hour(Int32, Float32, Float32, Float32) // ok
| Hour(Int32, Int32, Int32, Int32) // error: redeclaration of 'Hour'
| Hour(Int32, Int32, Int32) // ok
}
- The
enumtype supports recursion and mutual recursion. For example:
// recursive enum
enum TimeUnit5 {
| Year(Int32)
| Month(Int32, Float32)
| Day(Int32, Float32, Float32)
| Hour(Int32, Float32, Float32, Float32)
| Twounit(TimeUnit5, TimeUnit5)
}
// mutually recursive enums
enum E1 {
A | B(E2)
}
enum E2 {
C(E1) | D(E1)
}
-
The
enumtype cannot be inherited. -
The
enumtype can implement interfaces. For details about the interfaces, see [Classes and Interfaces].
Accessing the Enum Value
The first method is to add the enum name to the constructor name. For example:
let time1 = TimeUnit1.Year
let time2 = TimeUnit2.Month(1.0, 2.0)
let time3 = TimeUnit3<Int64, Float64>.Day(1, 2.0, 3.0)
The second method is to omit the enum name. For example:
let time4 = Year // syntax sugar of 'TimeUnit1.Year'
let time5 = Month(1.0, 2.0) // syntax sugar of 'TimeUnit2.Month(1.0, 2.0)'
let time6 = Day<Int64, Float64>(1, 2.0, 3.0) // syntax sugar of 'TimeUnit3<Int64, Float64>.Day(1, 2.0, 3.0)'
Note: The Cangjie language supports type derivation of generic parameters. Therefore, the generic parameter <T> can be omitted when the preceding method 1 and method 2 are used for access.
The second method must meet the following rules:
If there is no conflict with other variable names, function names, type names, or package names, you can omit the type prefix. Otherwise, the variable name, function name, type name, or package name is preferred.
package p
}
func g() {
let a = A // ok, find p.A
let b = E.A // ok
let c = p.A // ok
F(1) // ok, find p.F
E.F(1) // ok
p.F(1) // ok
let x: C // ok, find p.C
let y: p.C // ok
}
When the enum constructor is used without the type prefix, the generic parameters of the enum type can be declared after the constructor name.
enum E<T> {
| A(T)
| B(T)
}
func f() {
let a = A(1) // ok, a: E<Int64>
let b = A<Int32>(2) // ok, b: E<Int32>
}
Deconstructing Enums
The match expression and enum pattern can be used to deconstruct the enum type. For details, see [Patterns].
The following is an example of deconstructing the TimeUnit1 and TimeUnit2 defined in the preceding section:
let time12 = TimeUnit1.Year
let howManyHours = match (time12) {
case Year => 365 * 24 // matched
case Month => 30 * 24
case Day => 24
case Hour => 1
}
let time13 = TimeUnit2.Month(1.0, 1.5)
let howManyHours = match (time13) {
case Year(y) => y * 365.0 * 24.0
case Month(y, m) => y * 365.0 * 24.0 + m * 30.0 * 24.0 // matched
case Day(y, m, d) => y * 365.0 * 24.0 + m * 30.0 * 24.0 + d * 24.0
case Hour(y, m, d, h) => y * 365.0 * 24.0 + m * 30.0 * 24.0 + d * 24.0 + h
}
Other Members of Enum
You can define member functions, operator functions, and member attributes in the enum type.
- For details about how to define a common member function, see [Function Definition].
- For details about the syntax for defining an operator function, see [Operator Overloading].
- For details about the syntax for defining member attributes, see [Attribute Definition].
The following are some simple examples of enum definitions:
enum Foo {
A | B | C
func f1() {
f2(this)
}
static func f2(v: Foo) {
match (v) {
case A => 0
case B => 1
case C => 2
}
}
prop item: Int64 {
get() {
f1()
}
}
}
main() {
let a = Foo.A
a.f1()
Foo.f2(a)
a.item
}
A constructor in the enum type, a static member function, and an instance member function cannot be overloaded. Therefore, the names of constructors in the enum type, static member functions, instance member functions, and member attributes must be unique.
Option
Option type is a generic enum type.
enum Option<T> { Some(T) | None }
Some and None are two constructors. Some(T) indicates a state with a value, and None indicates a state without a value. The type variable T is instantiated into different types, and different Option types, for example, Option<Int32> and Option<String>, are obtained.
Another method of writing the Option type is to add ? before the type name. That is, for any Type, ?Type is equivalent to Option<Type>. For example, ?Int32 is equivalent to Option<Int32>, ?String is equivalent to Option<String>, and so on.
Pay attention to the following points about the Option type:
- Although
TandOption<T>are of different types, you can directly specify a value of theTtype when a value of theOption<T>type is required at a certain position. The compiler encapsulates the value of theTtype intoSome constructorof theOption<T>type. For example, the following definition is valid:
let v1: ?Int64 = 100
let v2: ??Int64 = 100
- For two unequal types
T1andT2, even if there is a subtype relationship between them, there is no subtype relationship betweenOption<T1>andOption<T2>.
The Option type complies with the usage rules of the generic enum type. For example, you can define a series of variables of different Option types.
let opInt32_1 = Some(100) // The type of 'opInt32_1' is 'Option<Int32>'
let opInt32_2 = Option<Int32>.None // The type of 'opInt32_2' is 'Option<Int32>'
let opChar = Some('m') // The type of 'opChar' is 'Option<Rune>'
let opBool = Option<Bool>.None // The type of 'opBool' is 'Option<Bool>'
let opEnum = Some(TimeUnit1.Year) // The type of 'opEnum' is 'Option<TimeUnit1>'
Deconstructing Option Values
Several methods are provided to facilitate the deconstruction of option values: pattern matching, getOrThrow function, coalescing operator (??), and question mark operator (?).
- The Option type is an enum type. Therefore, the enum pattern in the pattern matching expression can be used to deconstruct the
Optionvalue. For details, see [Enum Pattern].
let number1 = match (opInt32_1) {
case Some(num) => num // matched
case None => 0
}
let number2 = match (opInt32_2) {
case Some(num) => num
case None => 0 // matched
}
let enumValue = match (opEnum) {
case Some(tu) => match (tu) {
case Year => "Year" // matched
case Month => "Month"
case Day => "Day"
case Hour => "Hour"
}
case None => "None"
}
- For the expression
eof theOption<T>type, thegetOrThrow()orgetOrThrow(exception: ()->Exception)function is called to deconstructe. If the value ofeis equal to that ofOption<T>.Some(v), the value ofe.getOrThrow()ore.getOrThrow(lambdaArg)is equal to that ofv. If the value ofeis equal to that ofOption<T>.None,e.getOrThrow()throws aNoneValueExceptionexception during running (e.getOrThrow(lambdaArg)throws an exception specified inlambdaArgduring running).
let number1 = opInt32_1.getOrThrow() // number1 = 100
let number2 = opInt32_2.getOrThrow() // throw NoneValueException
let number3 = opInt32_2.getOrThrow{ MyException("Get None value") } // throw MyException
- For the
e1expression of theOption<T>type and thee2expression of theTtype, the type of thee1 ?? e2expression isT. When the value ofe1is equal to that ofOption<T>.Some(v), the value ofe1 ?? e2is equal to that ofv. When the value ofe1is equal to that ofOption<T>.None, the value ofe1 ?? e2is equal to that ofe2. About??For details about operators, see [coalescing Expressions].
let number1 = opInt32_1 ?? 0 // number1 = 100
let number2 = opInt32_2 ?? 0 // number2 = 0
- The question mark operator (
?) is a unary suffix operator.?It must be used together with the suffix operators.,(),{}, or[]so thatOption<T>supports these suffix operators. For an expressioneof theOptiontype,e?.bindicates thatOption<T>.Some(b)is obtained wheneisSome; otherwise,Option<T>.Noneis obtained (T is of the b type). The same rule applies to other operators. About?For details about operators, see [Question Mark Operators].
class C {
var item = 100
}
let c = C()
let c1 = Some(c)
let c2 = Option<C>.None
let r1 = c1?.item // r1 = Option<Int64>.Some(100)
let r2 = c2?.item // r2 = Option<Int64>.None
Mutable Types
The following sequentially describes mutable types in the Cangjie programming language.
Array
The Cangjie programming language uses the generic type Array<T> to represent the Array type. The Array type is used to store a series of elements of the same type (or having a common parent class). The description of Array<T> is as follows:
-
The elements in
Array<T>are ordered and can be accessed by index (starting from0). -
The length of the
Arraytype is fixed. That is, once anArrayinstance is created, the length cannot be changed. -
Arrayis a reference type and is defined as a variable of the reference type. The variable name stores the reference pointing to the data value. Therefore, when a value is assigned or a function specifies parameters, theArraytype copies the reference. -
When the type variable
Tis instantiated into different types, differentArraytypes are obtained. For example,Array<Int32>andArray<Float64>indicateArrayof theInt32type andArrayof theFloat64type, respectively. -
When
TypeinArray<T>supports==for equality and!=for inequality,Array<T>supports==and!=. Otherwise,Array<T>does not support==and!=. If==and!=are used, an error is reported during compilation. Two instance values forArray<T>of the same type are equal only when all elements in the same position (index) are equal (indicating that their lengths are equal). -
A multidimensional
Arrayis defined as anArrayof anArrayand is represented byArray<Array<...>>. For example,Array<Array<Int32>>indicates a two-dimensionalArrayof theInt32type. -
When
ElementTypehas subtypes,Array<ElementType>can store instances of anyElementTypesubtype. For example,Array<Object>can store instances of anyObjectsubtype.
Creating an Array Instance
You can create an Array instance in either of the following ways.
Constructors
// Array<T>()
let emptyArr1 = Array<Int64>() // create an empty array whose type is Array<Int64>
let emptyArr2 = Array<String>() // create an empty array whose type is Array<String>
// Array<T>(size: Int64, initElement: (Int64)->T)
let array3 = Array<Int64>(3) { i => i * 2 } // 'array3' has 3 elements: 0, 2, 4
let array4 = Array<String>(2) { i => "$i" } // 'array4' has 2 elements: "0", "1"
Array Literals
Array literals are in the format of [element1, element2, ..., elementN]. Multiple elements are separated by commas (,). Each element can be a common expression expressionElement. The syntax of an array literal is defined as follows:
arrayLiteral : '[' (elements)? ']' ;
elements : element (',' element)* ;
element : expression ;
Each element of the Array literal is an expression.
let emptyArray: Array<Int64> = [] // empty Array<Int64>
let array0 = [1, 2, 3, 3, 2, 1] // array0 = [1, 2, 3, 3, 2, 1]
let array1 = [1 + 3, 2 + 3, 3 + 3] // array1 = [4, 5, 6]
- When the context does not have specific type requirements, if the minimum common parent type of all
elementsisT, the type of theArrayliteral isArray<T>. - If the context has specific type requirements, all
elementtypes must be subtypes of theelementtype required by the context.
Accessing Elements in an Array
For the arr instance of the Array type, elements in arr can be accessed in the following ways:
Element accessing at a specific position: Access an element at a specific position using arr[index1]...[indexN] (index1, ..., indexN are index expressions of the Int64 type). For example:
let array5 = [0, 1]
let element0 = array5[0] // element0 = 0
array5[1] = 10 // change the value of the second element of 'array5' through index
let array6 = [[0.1, 0.2], [0.3, 0.4]]
let element01 = array6[0][1] // element01 = 0.2
array6[1][1] = 4.0 // change the value of the last element of 'array6' through index
Iterative accessing: Iteratively access elements in arr using the for-in expression (see [for-in Expressions]). For example:
func access() {
let array8 = [1, 8, 0, 1, 0]
for (num in array8) {
print("${num}") // output: 18010
}
}
Size of the Accessed Array
The number of elements in arr can be returned in arr.size mode.
let array9 = [0, 1, 2, 3, 4, 5]
let array10 = [[0, 1, 2], [3, 4, 5]]
let size1 = array9.size // size1 = 6
let size2 = array10.size // size2 = 2
Slice of an Array
When a value of the Range<Int64> type is used as the Array index, a segment (called slicing) of the Array is truncated. Note that:
- The value of
stepmust be1. Otherwise, an exception will be thrown. - The type returned by
slicingis the same as that ofArrayand is the reference of the originalArray. Modifications on elements in a slice affect the original array. - When
start..endis used as the index ofArray, ifstartis omitted, the value ofstartis set to0. Ifendis omitted, the value ofendis set to the length ofArray. - When
start..=endis used as the index ofArray, ifstartis omitted, the value ofstartis set to0.endin thestart..=endformat cannot be omitted. - If the index is an empty
range, an emptyArrayis returned.
let array7 = [0, 1, 2, 3, 4, 5]
func slicingTest() {
array7[0..5] // [0, 1, 2, 3, 4]
array7[0..5:1] // [0, 1, 2, 3, 4]
array7[0..5:2] // runtime exception
array7[5..0:-1] // runtime exception
array7[5..0:-2] // runtime exception
array7[0..=5] // [0, 1, 2, 3, 4, 5]
array7[0..=5:1] // [0, 1, 2, 3, 4, 5]
array7[0..=5:2] // runtime exception
array7[5..=0:-1] // runtime exception
array7[5..=0:-2] // runtime exception
array7[..4] // [0, 1, 2, 3]
array7[2..] // [2, 3, 4, 5]
array7[..] // [0, 1, 2, 3, 4, 5]
array7[..4:2] // error: the 'range step' is not allowed here.
array7[2..:-2] // error: the 'range step' is not allowed here.
array7[..:-1] // error: the 'range step' is not allowed here.
array7[..=4] // [0, 1, 2, 3, 4]
array7[..=4:2] // error: the 'range step' is not allowed here.
array7[0..5:-1] // runtime exception
array7[5..=0] // []
array7[..0] // []
array7[..=-1] // []
let temp: Array<Int64> = array7[..]
temp[0] = 6 // temp == array7 == [6, 1, 2, 3, 4, 5]
}
When slicing is used to assign values, the following usages are supported:
- If the expression on the right of
=is of the array element type, the value of the expression is used as the element that covers the slice range. - If the type of the expression on the right of
=is the same as that of the array, the array will be copied to overwrite the current slice range. In this case, the size of the expression on the right must be the same as that of the slice range. Otherwise, an exception will be thrown during running.
let arr = [1, 2, 3, 4, 5]
arr[..] = 0
// arr = [0, 0, 0, 0, 0]
arr[0..2] = 1
// arr = [1, 1, 0, 0, 0]
arr[0..2] = [2, 2]
// arr = [2, 2, 0, 0, 0]
arr[0..2] = [3, 3, 3] // runtime exception
arr[0..2] = [4] // runtime exception
let arr2 = [1, 2, 3, 4, 5]
arr[0..2] = arr2[0..2] // ok
// arr = [1, 2, 0, 0, 0]
arr[0..2] = arr2 // runtime exception
arr[..] = arr2
VArray
The Cangjie programming language uses the generic type VArray<T, $N> to represent the VArray type. The VArray type is used to store a series of elements of the same type (or having a common parent class). The description of VArray<T, $N> is as follows:
-
The elements in
VArray<T, $N>are ordered and can be accessed by index (starting from0). If the provided index is greater than or equal to its length and the index can be deduced during compilation, a compilation error is reported. Otherwise, an exception is thrown during running. -
The length of the
VArray<T, $N>type is a part of the type.Nindicates the length of VArray. It must be an integer literal and is marked by the fixed syntax$plus a number. If the provided integer literal is a negative number, an error is reported during compilation. -
VArrayis a variable of the value type. The variable name stores the data value. Therefore, when a value is assigned or a function specifies parameters, the value is copied for theVArraytype. -
When the type variable
Tis instantiated into different types or the length of the$Nannotation is different, differentVArraytypes are obtained. For example,VArray<Int32, $5>andVArray<Float64, $5>are different types ofVArray.VArray<Int32, $2>andVArray<Int32, $3>are different types ofVArray. -
When the generic variable
TofVArrayis of theVArraytype, it indicates a multi-dimensionalVArraytype.
Creating a VArray Instance
VArray can also use the Array literal to create an instance. This method can be used only when the literal is of the VArray type in the context. Otherwise, the literal is of the Array type.
The length of VArray must be the literal type of Int64 and must be the same as the length of the provided literal array. Otherwise, a compilation error is reported.
let arr1: VArray<Int64, $5> = [1,2,3,4,5]
let arr2: VArray<Int16, $0> = []
let arr3: VArray<Int16, $0> = [1] // error
let arr4: VArray<Int16, $-1> = [] // error
In addition, VArray can be used to create instances in the form of constructors.
// VArray<T, $N>(initElement: (Int64)->T)
let arr5: VArray<Int64, $5> = VArray<Int64, $5> { i => i } // [0, 1, 2, 3, 4]
// VArray<T, $N>(item!: T)
let arr6: VArray<Int64, $5> = VArray<Int64, $5>(item: 0) // [0, 0, 0, 0, 0]
VArray does not allow the default type parameter <T, $N>.
Accessing Elements in a VArray
For the arr instance of the VArray type, elements in arr can be accessed in the following ways:
Access an element at a specific position using arr[index1]...[indexN] (index1,...,indexN are index expressions of the Int64 type). For example:
Note that the index operation of VArray returns the copy of the specified element. It indicates that if the element is of the value type, the index value will get a new instance that cannot be modified. For multi-dimensional VArray types, the inner VArray cannot be modified by arr[n][m] = e because the inner VArray obtained by arr[n] is a new VArray instance that has been copied.
var arr7: VArray<Int64, $2> = [0, 1]
let element0 = arr7[0] // element0 = 0
arr7[1] = 10 // change the value of the second element of 'arr7' through index
// Get and Set of multi-dimensional VArrays.
var arr8: VArray<VArray<Int64, $2>, $2> = [[1, 2], [3, 4]]
let arr9: VArray<Int64, $2> = [0, 1]
let element1 = arr8[1][0] // element1 = 3
arr8[1][1] = 5 // error: function call returns immutable value
arr8[1] = arr9 // arr8 = [[1, 2], [0, 1]]
Obtaining the VArray Lengths
The number of elements in arr can be returned in arr.size mode.
let arr9: VArray<Int64, $6> = [0, 1, 2, 3, 4, 5]
let size = arr9.size // size = 6
VArray in the Function Signature
When VArray is used as a parameter or return value of a function, the length of VArray must be specified.
func mergeVArray(a: VArray<Int64,$2>, b: VArray<Int64, $3>): VArray<Int64, $5> {
var ret = VArray<Int64, $5>(item: 0)
for(i in 0..2) {
ret[i] = a[i]
}
for (i in 0..3) {
ret[a.size + i] = b[i]
}
return ret
}
Struct
The struct type is a mutable type. A series of member variables and member functions can be defined in the struct type. The syntax for defining the struct type is as follows:
structDefinition
: structModifier? 'struct' identifier typeParameters? ('<:' superInterfaces)? genericConstraints? structBody
;
structBody
: '{'
structMemberDeclaration*
structPrimaryInit?
structMemberDeclaration*
'}'
;
structMemberDeclaration
: structInit
| staticInit
| variableDeclaration
| functionDefinition
| operatorFunctionDefinition
| macroExpression
| propertyDefinition
;
structModifier is the modifier of the struct type, struct is the keyword, identifier is the name of the struct type, and typeParameters and genericConstraints are the type variable list and type variable constraints, respectively. For details, see [Generics].In structBody, you can define member variables (variableDeclaration), member attributes (propertyDefinition), main constructors (structPrimaryInit), constructors (structInit), and member functions (including common member functions and operator functions).
Pay attention to the following points about the struct type:
-
structis a variable of the value type. The variable name stores the data value. Therefore, when a value is assigned or a function specifies parameters, the value is copied for thestructtype. -
The
structtype can be defined only intop-level. -
As a user-defined type, the
structtype does not support==for equality or!=for inequality by default. You can overload the==or!=operator (see [Operator Overloading]) to enable the customstructtype to support==or!=. -
The
structtype cannot be inherited. -
The
structtype can implement the [Interface]. -
If the type of one or more non-static member variables of a struct type references the struct itself, the struct type is called a recursive struct type. For multiple struct types, if the types of their non-static member variables form a circular reference, the struct types form a recursion. The struct type defined by recursion (or mutual recursion) is invalid unless at least one
T_iis encapsulated in the class, interface, enum, or function type on eachT_1, T_2, ..., T_Nof the recursion chain. That is, the class, interface, enum, or function type can be used to implement recursion (or mutual recursion). The struct definition is legalized.
The following is an example of the struct type:
struct Rectangle1 {
let width1: Int32
let length1: Int32
let perimeter1: () -> Int32
init (width1: Int32, length1: Int32) {
this.width1 = width1
this.length1 = length1
this.perimeter1 = { => 2 * (width1 + length1) }
}
init (side: Int32) {
this(side, side)
}
func area1(): Int32 { width1 * length1 }
}
// Define a generic struct type.
struct Rectangle2<T> {
let width2: T
let length2: T
init (side: T) {
this.width2 = side
this.length2 = side
}
init (width2!: T, length2!: T) {
this.width2 = width2
this.length2 = length2
}
}
The following is an example of the struct type definition for recursion and mutual recursion:
struct R1 { // error: 'R1' cannot have a member that recursively contains it
let other: R1
}
struct R2 { // ok
let other: Array<R2>
}
struct R3 { // error: 'R3' cannot have a member that recursively contains it
let other: R4
}
struct R4 { // error: 'R4' cannot have a member that recursively contains it
let other: R3
}
struct R5 { // ok
let other: E1
}
enum E1 { // ok
A(R5)
}
struct Member Variables
The syntax for defining a member variable is as follows:
variableDeclaration
: variableModifier* NL* (LET | VAR) NL* patternsMaybeIrrefutable ((NL* COLON NL* type)? (NL* ASSIGN NL* expression) | (NL* COLON NL* type))
;
When defining member variables, pay attention to the following points:
- A member variable defined outside the primary constructor can have an initial value or not. If there is an initial value, the initial value expression can reference only the initialized member variables defined before it and the static member functions in
struct.
Constructors
In the Cangjie programming language, there are two types of constructors: primary constructor and init constructor (constructor for short).
Primary Constructor
The syntax of the primary constructor is defined as follows:
structPrimaryInit
: (structNonStaticMemberModifier)? structName '('
structPrimaryInitParamLists? ')'
'{'
expressionOrDeclarations?
'}'
;
structName
: identifier
;
structPrimaryInitParamLists
: unnamedParameterList (',' namedParameterList)?
(',' structNamedInitParamList)?
| unnamedParameterList (',' structUnnamedInitParamList)?
(',' structNamedInitParamList)?
| structUnnamedInitParamList (',' structNamedInitParamList)?
| namedParameterList (',' structNamedInitParamList)?
| structNamedInitParamList
;
structUnnamedInitParamList
: structUnnamedInitParam (',' structUnnamedInitParam)*
;
structNamedInitParamList
: structNamedInitParam (',' structNamedInitParam)*
;
structUnnamedInitParam
: structNonStaticMemberModifier? ('let' | 'var') identifier ':' type
;
structNamedInitParam
: structNonStaticMemberModifier? ('let' | 'var') identifier '!' ':' type
('=' expression)?
;
The definition of the primary constructor consists of the following parts:
-
Modifier (Optional): It can be modified by all access modifiers. The default accessibility is
internal. For details, see Access Modifiers in [Packages and Modules]. -
Primary constructor name: same as the type name. Do not use the
funckeyword before the primary constructor name. -
Parameter list: Different from the init constructor, the primary constructor has two types of parameters: ordinary parameters and member variable parameters. The syntax and semantics of ordinary parameters are the same as those of parameters in the function definition.
Member variable parameters are introduced to reduce code redundancy. The definition of a member variable parameter includes the definition of a parameter and a member variable. In addition, it indicates the semantics of assigning a value to a member variable through a parameter. Omitted definitions and expressions are automatically generated by the compiler.
-
The syntax of member variable parameters is the same as that of member variable definition. In addition,
!can be used to indicate whether a member variable parameter is a named parameter. -
The modifiers of the member variable parameter are
public,private,protected, andinternal. For details, see Access Modifiers in [Packages and Modules]. -
Member variable parameters only support non-static member variables. That is, they cannot be modified by
static. -
A member variable parameter cannot have the same name as a member variable outside the primary constructor.
-
A member variable parameter can have no initial value. This is because the compiler generates a corresponding constructor for the primary constructor and assigns values to member variables in the constructor body.
-
A parameter of a member variable can have an initial value. The initial value expression can reference other parameters or member variables (excluding instance member variables defined outside the primary constructor) that have been defined before the member variable is defined, but cannot modify the values of these parameters and member variables. Note that the initial value of the member variable parameter is valid only in the primary constructor and is not included in the member variable definition.
-
Member variable parameters cannot be followed by ordinary parameters. In addition, the parameter sequence must comply with that defined in the function. Parameters of named variables cannot be followed by non-named parameters.
- Main constructor body: The main constructor cannot call other constructors in this struct. Declarations and expressions can be written in the main constructor body. The declarations and expressions must meet the requirements of the init constructor.
The following is an example of the primary constructor definition:
struct Test{
static let counter: Int64 = 3
let name: String = "afdoaidfad"
private Test(
name: String, // regular parameter
annotation!: String = "nnn", // regular parameter
var width!: Int64 = 1, // member variable parameter with initial value
private var length!: Int64, // member variable parameter
private var height!: Int64 = 3 // member variable parameter
) {}
}
The primary constructor is the syntactic sugar of the init constructor. The compiler automatically generates the definitions of the constructor and member variables corresponding to the primary constructor. The constructor is automatically generated as follows:
- Its modifier is the same as that of the primary constructor.
- The sequence of parameters from left to right is the same as that declared in the parameter list of the primary constructor.
- The form of the constructor body is as follows:
- Values are assigned to member variables. The syntax format is
this.x = x, wherexis the member variable name. - Then, other code of the main constructor body is used.
- Values are assigned to member variables. The syntax format is
struct B<X,Y> {
B(
x: Int64, // primary constructor, it's name is the same as the struct
y: X,
v!: Int64 = 1, // regular parameter
private var z!: Y // member variable parameter
) {}
/* The corresponding init constructor with primary constructor auto-generated
by compiler.
private var z: Y // auto generated member variable definition
init( x: Int64, y: X, v!: Int64 = 1, z!: Y) { // auto generated named parameter definition
this.z = z // auto generated assign expression of member variable
}
*/
}
A struct can define only one primary constructor. In addition to the primary constructor, other constructors can be defined as usual, but other constructors and the constructor corresponding to the primary constructor must be overloaded.
init Constructor
In addition to the main constructor, you can also customize a constructor. The constructor is defined by using the keyword init, parameter list, and function body. Multiple constructors can be defined in a struct, but they and the constructor corresponding to the main constructor must form an overload. For details about function overload, see [Function Overload Definition]. Note:
-
The parameters of a constructor can have default values. Do not use the instance member variable
this.variableNameand its syntactic sugarvariableNameas the default values of constructor parameters. -
Before all instance member variables are initialized, the constructor cannot use implicit parameter passing or functions or
lambdathat capturethis. However,this.variableNameor its syntactic sugarvariableNamecan be used to access the initialized member variablevariableName. -
The
lambdaand nested functions in constructors cannot capturethis, andthiscannot be used independently as an expression. -
In a constructor,
thiscan be used to call other constructors. If this function is called, it must be called at the first expression in the constructor body. No expression or declaration is allowed before this function is called. Do not call expressions to call constructors throughthisoutside the constructor. -
If the constructor does not explicitly call other constructors, ensure that all instance member variables declared by the
structare initialized beforereturn. Otherwise, an error is reported during compilation. -
The compiler performs dependency analysis on the calling relationships between all constructors. If a constructor is called cyclically, an error is reported during compilation.
-
The return type of the constructor is
Unit.
If a struct does not define a primary constructor or an init constructor, it attempts to generate a parameterless constructor (public-modified). If the instance member variable of the struct does not have an initial value, an error is reported during compilation.
Other Members of Struct
You can also define member functions, operator functions, member attributes, and static initializers in struct.
- For details about how to define a common member function, see [Function Definition].
- For details about the syntax for defining an operator function, see [Operator Overloading].
- For details about the syntax for defining member attributes, see [Attribute Definition].
- For details about the syntax for defining a static initializer, see [Static Initializers].
Modifiers in the Struct
A struct and its members in a class can be modified using access modifiers. For details, see Access Modifiers in [Packages and Modules].
Member functions and variables can be modified using static. These members are static members of the struct type, not members of the struct instance. Outside the struct definition, instance member variables and instance member functions can be accessed only through the struct instance, and static member variables and static member functions can be accessed only through the name of the struct type.
In addition, a function can be modified by mut, which is a special instance member function. For details about the mut function, see [mut Functions].
The struct constructor and the member variables defined in the main constructor can be modified only by using access modifiers.
Instantiation of Structs
After defining the struct type, you can create a struct instance. The struct instance can be defined in either of the following methods based on whether the instance contains type variables:
- Define an instance of the non-general
struct:StructName(arguments).StructNameindicates the name of thestructtype, andargumentsindicates the argument list.StructName(arguments)calls the corresponding constructor based on the calling rule of overloaded functions (see [Function Overloading Resolution]), and then generates an instance ofStructName. For example:
let newRectangle1_1 = Rectangle1(100, 200) // Invoke the first custom constructor.
let newRectangle1_2 = Rectangle1(300) // Invoke the second custom constructor.
- Define an instance of the generic
struct:StructName<Type1, Type2, ..., TypeK>(labelValue1, labelValue2, ..., labelValueN). The only difference from defining an instance of a non-generalstructis that the generic parameter needs to be instantiated. For example:
let newRectangle2_1 = Rectangle2<Int32>(100) // Invoke the custom constructor.
let newRectangle2_1 = Rectangle2<Int32>(width2: 10, length2: 20) // Invoke another custom constructor.
Note that if the variable structInstance of the struct type is defined using let, the value of the member variable varName cannot be changed using structInstance.varName = expr (even if varName is defined using var). If both structInstance and varName are defined using var, the value of varName can be changed using structInstance.varName = expr.
Class and Interface Types
class and interface are reference types and are defined as variables of the reference type. The variable name stores the reference pointing to the data value. Therefore, when a value is assigned or a function specifies parameters, class and interface copy the reference.
For details, see [Classes and Interfaces].
Type Conversion
As a strongly-typed language, the Cangjie programming language supports only explicit type conversion (also referred to as forcible type conversion). For the value type, valueType(expr) can be used to convert the type of the expression expr to valueType. For class and interface, [as Operators]) can be used to implement static type conversion. For the value type, valueTypeA can be converted to valueTypeB. That is, the conversion rule for converting valueTypeA to valueTypeB is defined. For the two value types that do not have the conversion rule, they cannot be converted. For class and interface, if a parent-child type relationship exists between two types in the inheritance relationship diagram, the two types can be converted (the conversion may fail). Otherwise, the two types cannot be converted.
The following describes the type conversion rules between value types and between class and interface types. For other types that are not mentioned, Cangjie does not support type conversion between them in the preceding two methods.
Conversion Between Value Types
For numeric types, only the following conversions are supported:
-
Conversion from the
Runetype to theUInt32type. -
Conversion from integer types (including
Int8,Int16,Int32,Int64,IntNative,UInt8,UInt16,UInt32,UInt64, andUIntNative) to theRunetype. -
Bidirectional conversion between all numeric types (including
Int8,Int16,Int32,Int64,IntNative,UInt8,UInt16,UInt32,UInt64,UIntNative,Float16,Float32, andFloat64).
The conversion from Rune to UInt32 uses the UInt32(e) mode. e is an expression of the Rune type. The result of UInt32(e) is an integer of the UInt32 type corresponding to the Unicode scalar value of e.
The conversion from the integer type to the Rune type uses the Rune(num) mode. The num type can be any integer type. Only when the value of num is in the range [0x0000,0xD7FF] or [0xE000,0x10FFFF] (that is, Unicode scalar value), the character represented by the corresponding Unicode scalar value is returned. Otherwise, an error is reported during compilation (the value of num can be determined during compilation) or an exception is thrown during running.
main() {
var c: Rune = 'a'
var num: UInt32 = 0
num = UInt32(c) // num = 97
num -= 32 // num = 65
c = Rune(num) // c = `A`
return 0
}
To ensure type security, the Cangjie programming language does not support implicit type conversion between numeric types (the type of a numeric literal is inferred from the context, which is not implicit type conversion). To convert a numeric type to another numeric type, you must use the explicit method NumericType(expr) to forcibly convert the expr type to the NumericType type (NumericType indicates any numeric type). If the conversion is successful, a new value of the NumericType type constructed from the expr type is returned. The syntax for numeric type conversion is defined as follows:
numericTypeConvExpr
: numericTypes '(' expression ')'
;
numericTypes
: 'Int8' | 'Int16' | 'Int32' | 'Int64' | 'IntNative' | 'UInt8' | 'UInt16' | 'UInt32' | 'UInt64' | 'UIntNative' | 'Float16' | 'Float32' | 'Float64'
;
If the size relationship between numeric types is defined based on the number of bits occupied by numeric types (a larger number of bits indicates a larger type, and a smaller number of bits indicates a smaller type), the Cangjie programming language supports the following type conversion:
- Bidirectional conversion between signed integer types: When a small value is converted to a large value, the value result remains unchanged. If the value result exceeds the representation range of the small value type, the overflow processing policy is determined based on the attribute macro in the context. By default, the exception throwing policy is used. For details about different overflow policies, see [Arithmetic Expressions]. The following uses the conversion between
Int8andInt16as an example. When an overflow occurs, the policy of throwing an exception is used.
main() {
var i8Number: Int8 = 127
var i16Number: Int16 = 0
i16Number = Int16(i8Number) // ok: i16Number = 127
i8Number = Int8(i16Number) // ok: i8Number = 127
i16Number = 128
i8Number = Int8(i16Number) // throw an ArithmeticException
return 0
}
- The rule of the bidirectional conversion between unsigned integer types is the same as the preceding rule. The following uses the conversion between
UInt16andUInt32as an example (the same rule applies to other cases):
main() {
var u16Number: UInt16 = 65535
var u32Number: UInt32 = 0
u32Number = UInt32(u16Number) // ok: u32Number = 65535
u16Number = UInt16(u32Number) // ok: u16Number = 65535
u32Number = 65536
u16Number = UInt16(u32Number) // throw an ArithmeticException
return 0
}
- Bidirectional conversion between floating-point types uses the
round-to-nearestmode. The following is an example of the conversion betweenFloat32andFloat64:
main() {
var f32Number: Float32 = 1.1
var f64Number: Float64 = 0.0
f64Number = Float64(f32Number) // f64Number = 1.100000023841858
f32Number = Float32(f64Number) // f32Number = 1.1
f64Number = 1.123456789
f32Number = Float32(f64Number) // f32Number = 1.1234568
f32Number = 4.4E38 // f32Number = POSITIVE_INFINITY
f64Number = Float64(f32Number) // f64Number = POSITIVE_INFINITY
f64Number = 4.4E38
f32Number = Float32(f64Number) // f32Number = POSITIVE_INFINITY
f64Number = Float64(f32Number*0.0)
f32Number = Float32(f64Number) // f32Number = NaN
return 0
}
- Bidirectional conversion between signed integer types and unsigned integer types: Because the representation range of any signed integer type cannot contain the representation range of an unsigned integer type of the same length (or vice versa), the conversion is successful if the value of the expression to be converted is within the range of the target integer type during type conversion. Otherwise, the overflow processing policy is determined based on the attribute macro in the context. By default, the exception throwing policy is used. For details about different overflow processing policies, see [Arithmetic Expression]. The following uses the conversion between
Int8andUInt8as an example. When an overflow occurs, the policy of throwing an exception is used.
main() {
var i8Number: Int8 = 127
var u8Number: UInt8 = 0
u8Number = UInt8(i8Number) // ok: u8Number = 127
u8Number = 100
i8Number = Int8(u8Number) // ok: i8Number= 100
i8Number= -100
u8Number = UInt8(i8Number) // throw an ArithmeticException
u8Number = 255
i8Number = Int8(u8Number) // throw an ArithmeticException
return 0
}
-
Conversion from an integer to a floating-point number: The result is a floating-point number as close as possible to the original integer.
POSITIVE_INFINITYorNEGATIVE_INFINITYis returned if the value is out of the representation range of the target type. -
Conversion from a floating-point number to an integer: The
round-toward-zeromode is used to convert a floating-point number to a signed integer. That is, the integer part is retained and the decimal part is discarded. When the integer part exceeds the representation range of the target integer type, the integer overflow policy in the context is used. If the throwing policy is used, an exception is thrown. Otherwise, the conversion rule is as follows:
NaNreturns0.- If the value is less than the lower limit of the integer value range (including negative infinity), the lower limit of the integer value range is returned.
- If the value is greater than the upper limit of the integer value range (including positive infinity), the upper limit of the integer value range is returned.
main() {
var i32Number: Int32 = 1024
var f16Number: Float16 = 0.0
var f32Number: Float32 = 0.0
f16Number = Float16(i32Number) // ok: f16Number = 1024.0
f32Number = Float32(i32Number) // ok: f32Number = 1024.0
i32Number = 2147483647
f16Number = Float16(i32Number) // f16Number = POSITIVE_INFINITY
f32Number = Float32(i32Number) // precision lost: f32Number = 2.14748365E9
f32Number = 1024.1024
i32Number = Int32(f32Number) // ok: i32Number = 1024
f32Number = 1024e10
i32Number = Int32(f32Number) // throw an Exception
f32Number = 3.4e40 // f32Number = POSITIVE_INFINITY
i32Number = Int32(f32Number) // throw an Exception
f32Number = 3.4e40 * 0.0 // f32Number = NaN
i32Number = Int32(f32Number) // throw an Exception
return 0
}
Conversion Between Class and Interface Types
For an instance obj of the class or interface type, if you need to convert its (static) type to another TargetType of the class or interface type, use obj as TargetType.
For details about how to use the as operator and the type conversion rules between the class and interface types, see [as Operators].
Type Aliases
If the name of a type is complex or not intuitive in a specific scenario, you can use a type alias to obtain a simple and intuitive alias for the type. The syntax for defining a type alias is as follows:
typeAlias
: typeModifier? `type` identifier typeParameters? `=` type
;
typeModifier is an optional accessibility modifier (namely, public), type is a keyword, identifier is any valid identifier, type is any type visible to top-level, and identifier and type are connected by using =. In addition, you can define a generic alias by adding a type parameter (typeParameters) after identifier. For details, see [Generics].Through the preceding statement, an alias named identifier is defined for type, and identifier and type are considered as the same type. For example:
type Point2D = (Float64, Float64)
type Point3D = (Float64, Float64, Float64)
let point1: Point2D = (0.5, 0.8)
let point2: Point3D = (0.5, 0.8, 1.1)
The preceding type definition does not define a new type. It is only used to define another name for an existing type. The alias and the original type are considered as the same type, and the alias does not affect the use of the original type.
Rules for Defining Type Aliases
- The definition of a type alias can be used only in
top-level.
func test() {
type Point2D = (Float64, Float64) // error: type alias can only be defined at top-level
type Point3D = (Float64, Float64, Float64) // error: type alias can only be defined at top-level
}
- When
typeis used to define a type alias, the original type must be visible in the position defined bytype.
class LongNameClassA {
}
type ClassB = LongNameClassB // error: use of undeclared type 'LongNameClassB'
- When a generic alias is defined, if the generic alias introduces a generic parameter that is not used in the original type, the compiler generates a warning.
type Class1<V> = GenericClassA<Int64, V> // ok. ClassA is a generic class
type Class2<Value, V> = GenericClassB<Int64, V> // warning: the type parameter 'Value' in 'Class2<Value, V>' is not used in 'GenericClassB<Int64, V>'
type Int<T> = Int32 // warning: the type parameter 'T' in 'Int<T>' is not used in `Int32`
- When defining a generic alias, you are not allowed to add generic constraints to the alias and the type parameters in the original type. When using a generic alias, you can add generic constraints as required. In addition, existing generic constraints in the original type are passed to the alias.
type Class1<V> where V <: MyTrait = GenericClassA<Int64, V> // error: generic constraints are not allowed here
type Class2<V> = GenericClassB<Int64, V> where V <: MyTrait // error: generic constraints are not allowed here
type Class3<V> = GenericClassC<Int64, V>
func foo<V> (p: Class3<V>) where V <: MyTrait { // add generic constraints when 'Class3<V>' is used
functionBody
}
class ClassWithLongName<T> where T<:MyTrait {
classBody
}
type Class<T> = ClassWithLongName<T> // Class<T> also has the constraint 'where T<:MyTrait'
- Circular references (direct or indirect) are not allowed in one or more
typedefinitions. A manner of determining the circular reference is to determine whether the circular reference exists by using a name instead of using a manner of expanding a type.
type Value = GenericClassAp<Int64, Value> // error: 'Value' references itself
type Type1 = (Int64)->Type1 // error: 'Type1' references itself
type Type2 = (Int64, Type2) // error: 'Type2' references itself
type Type3 = Type4 // error: 'Type3' indirectly references itself
type Type4 = Type3
- A type alias is considered as a type equivalent to the original type. For example, in the following example, a parameter of the
Inttype and a parameter of theInt32type may be directly added.Intis defined as an alias ofInt32. Note that aliases cannot be used to overload functions.
type Int = Int32
let numOne: Int32 = 10
let numTwo: Int = 20
let numThree = numOne + numTwo
func add(left: Int, right: Int32): Int { left + right }
func add(left: Int32, right: Int32): Int32 { left + right } // error: invalid redeclaration of 'add : (Int32, Int32)->Int32'
- The default visibility defined by
typeisdefault. To use the type alias defined in thispackagein otherpackages, the following conditions must be met: (1) The visibility modifier of the original type in thispackageispublic; (2) Thetypedefinition uses thepublicmodifier. In addition, note that the alias can have a different visible range from the original type, but the visible range of the alias cannot be greater than the visible range of the original type.
// a.cj
package A
public class ClassWithLongNameA {
}
class ClassWithLongNameB {
}
public type classA = ClassWithLongNameA // ok
type classAInter = ClassWithLongNameA // ok
/* error: classB can not be declared with modifier 'public', as 'ClassWithLongNameB' is internal */
public type classB = ClassWithLongNameB
// b.cj
package B
import A.*
let myClassA: A.classA = ClassWithLongNameA()
Usage of Type Aliases
A type alias can be used in any position that the original type can use on the right-hand side of the equal sign (=).
-
When it is used as a type, for example:
type A = B class B {} var a: A = B() // Use typealias A as type B -
When the type alias refers to a class or struct, it can be used as the constructor name.
type A = B class B {} func foo() { A() } // Use type alias A as constructor of B -
When the type alias refers to a class, interface, or struct, it can be used as the name to access static members or functions.
type A = B class B { static var b : Int32 = 0; static func foo() {} } func foo() { A.foo() // Use A to access static method in class B A.b } -
When the type alias refers to an enum, it can be used as the type name for declaring the constructor of the enum.
enum TimeUnit { Day | Month | Year } type Time = TimeUnit var a = Time.Day var b = Time.Month // Use type alias Time to access constructors in TimeUnit
Relationship Between Types
There are two types of relationships: equality and subtype.
Type Equality
For any two types T1 and T2, T1 and T2 are considered equal (denoted as $T1 \equiv T2$) if they meet any of the following conditions:
-
The type alias definition
type T1 = T2exists. -
In the
classdefinition andextendofclass,T1is the name ofclass, andT2isThis. -
The names of
T1andT2are the same (reflective). -
$T2 \equiv T1$ (symmetry).
-
The type $Tk$ exists, which meets $T1 \equiv Tk$ and $Tk \equiv T2$ (transitive).
Subtypes
For any two types T1 and T2, T1 and T2 are considered as subtypes (denoted as $T1 <: T2$) if they meet any of the following conditions:
-
$T1 \equiv T2$.
-
T1is of theNothingtype. -
Both
T1andT2are of theTupletype, and the type at each position ofT1is the subtype of the type at the position corresponding toT2. -
Both
T1andT2are of theFunctiontype. The parameter type ofT2is the subtype of theT1parameter type, and the return type ofT1is the subtype of theT2return type. -
T1is of anyclasstype, andT2is of theObjecttype. -
Both
T1andT2are of theinterfacetype, andT1inheritsT2. -
Both
T1andT2are of theclasstype, andT1inheritsT2. -
T2is of theinterfacetype, andT1implementsT2. -
The type $Tk$ exists, which meets $T1 <: Tk$ and $Tk <: T2$ (transitive).
Minimum Common Supertype
In a type system with subtypes, the minimum common parent type of two types may be required. For example, the type of the if expression is the minimum common supertype of the types of the two branches. The match expression is similar.
The minimum common supertype between two types is a subtype of all other common supertypes.
The minimum common supertype is defined as follows: For any two types T1 and T2, if the type LUB meets the following rules, LUB is the minimum common supertype of T1 and T2:
- For any type of
Tthat meets bothT1 <: TandT2 <: T,LUB <: Tis true.
Note that if a type in the common supertype is not larger than other types, it is only an extremely small one and not necessarily minimum one.
Maximum Common Subtype
Inversion exists in the subtype relationship (see [Type Variation] in [Generics] for its definition).For example, if the parameter type of the function type is inversion, the maximum common subtype of the two types is required.
The maximum common subtype between two types is a supertype of all other common subtypes.
The maximum common subtype is defined as follows: For any two types T1 and T2, if the type GLB meets the following rules, GLB is the maximum common subtype of T1 and T2:
- For any type of
Tthat meets bothT <: T1andT <: T2,T <: GLBis true.
Note that if a type in the common subtype is not smaller than other types, it is only an extremely large one and not necessarily maximum one.
Type Security
In the case of no data contention, the compiler ensures memory security and type security.
The following is an example in which type security and memory security cannot be ensured:
class C {
var x = 1
var y = 2
var z = 3
}
enum E {
A(Int64) | B(C)
}
var e = A(1)
main() {
spawn {
while (true) {
e = B(C()) // writing to `e`
e = A(0)
}
}
while (true) {
match (e) { // reading from `e`
case A(n) =>
println(n+1)
case B(c) =>
c.x = 2
c.x = 3
c.x = 4
}
}
}
It cannot be ensured because there is data competition between the thread that assigns a value to the variable e and the thread that reads the variable. For more information about data contention, see [Concurrency].
Names, Scopes, Variables, and Modifiers
This chapter first describes names, scopes, and shadowing, then introduces one of the names—variables, including their definition and initialization, and finally introduces modifiers.
Names
In Cangjie, names are used to identify entities such as variables, functions, types, packages, and modules.
names must be valid [Identifiers].
In Cangjie, keywords, variables, functions, types (including class, interface, struct, enum, and type alias), generic parameters, package names, and module names share the same namespace. That is, entities declared or defined in the same scope must have different names (except the names that constitute overloading). Entities declared or defined in different scopes can have the same name, but this may lead to shadowing.
let f2 = 77
func f2() { // Error, function name is the same as the variable f2
print("${f2}")
}
// Variable, function, type names cannot be the same as keywords
let Int64 = 77 // Error: 'Int64' is a keyword
func class() { // Error: class is a keyword
print("${f2}")
}
main(): Int64 {
print("${f2}") // Print 77
let f2 = { => // Shadowed the global variable f2
print("10")
}
f2()
return 1
}
Scopes
An entity can be accessed by name within the scope of its name without needing a prefix qualifier. A scope can be nested, meaning that a scope contains itself and any nested scopes within it. If a name is not shadowed or overridden within its nested scope, it can also be accessed directly.
Blocks
In Cangjie, a structure consisting of a pair of matching curly braces and an optional expression and declaration sequence in the braces is called a block. Blocks are everywhere in Cangjie. For example, the function body defined by a function, two branches of an if expression, and the loop body of a while expression are all blocks. Blocks lead to new scopes.
The syntax of a block is defined as follows:
block
: '{' expressionOrDeclarations '}'
;
A block has a value. The value of a block is determined by the expression and the declaration sequence within it. When a block is evaluated, the evaluation is performed in the order of the expressions and variable declarations within the block.
If the last item of a block is an expression, the value of that expression is the value of the block once it is evaluated.
{
let a = 1
let b = 2
a + b
} // The value of the block is a + b
If the last item of a block is a declaration, the value of the block is () after the declaration is processed.
{
let a = 1
} // The value of the block is ()
If a block does not contain any expression or declaration, the value of the block is ().
{ } // The value of this empty block is ()
Scope Levels
If duplicate names exist in the nested multi-level scope, the name introduced by the inner scope shadows the name of the outer scope, meaning the inner scope has a higher level than the outer one.
The comparison of scope levels in nested scopes is defined as follows:
-
Names introduced by
importhave the lowest scope level. -
Top-level names in a package have a higher scope level than names in point 1.
-
Names introduced within a type, function definition, or expression, typically defined within a pair of curly braces
{}(that is, in blocks), have a higher scope level than names outside{}. -
For classes and interfaces, names in a subclass have a higher scope level than those in the superclass and may shadow or override the latter.
import p1.a // a has the lowest scope level
var x = 1 // x 's scope level is higher than p1.a
open class A { // A's scope level the same as x at line 3
var x = 3 // This x has higher scope level than the x at line 3
var y = 'a'
func f(a: Int32, b: Float64): Unit {
}
}
class B <: A {
var x = 5 // This x has higher scope level than the x at line 6
func f(x!: Int32 = 7) { // This x's scope level is higher than the x at line 14
}
}
Scope Principles
Based on the location of name introduction, there are three types of scopes: top-level, local-level, and type-internal. The following describes the different principles of the three types of scopes.
Top-level
Names introduced at the top level adhere to the following scope principles:
- The scope of top-level functions and types is the entire package, and their names are visible to the entire package. These types include
class,interface,enum,struct, andtype. - Names of top-level variables, introduced by
let,var, andconst, have a scope that begins after their definition (including initialization) is complete and does not include the range from the start of the file to the variable declaration. These names are visible to other files in the package. However, the initialization process of variables may have side effects. Therefore, variables must be declared and initialized before use.
/* Global variables can be accessed only after defined. */
let x = y //Error: y is used before being defined
let y = 4
let a = b //Error: b is used before being defined
let b = a
let c = c //Error: unresolved identifier 'c' (in the right of '=')
//Function names are visible in the entire package
func test() { test2() } // OK
func f() { test() } // OK
func test2(): Int64 {
var x = 99
return x
}
Local-level
Names declared or defined within a function definition or expression have a local-level scope. Variables defined in a block have a higher scope level than those defined outside the block.
- The scope of a local variable ranges from its declaration to the end of the current scope. A local variable must be defined and initialized before use. The shadowing of a local variable starts after the declaration or definition of the variable name.
- The scope of a local function ranges from its declaration to the end of the current scope. Recursive definition is supported, but mutual recursion is not supported.
- The scope of a parameter or a generic parameter of a function ranges from the parameter name declaration to the end of the function body. The scope level is the same as that of the variables defined in the function body.
- The function definition
func f(x: Int32, y!: Int32 = x) {}is valid. - The function definition
func f(x!: Int32 = x) {}is invalid.
- The function definition
- Generic parameters introduced in generic type declarations or extensions have a scope that starts from the declaration of the parameter names to the end of the type body or extension body. The scope level of the generic parameter is the same as the names defined in the type.
- In the generic type definition
class C<T> {}, the scope ofTranges from its declaration to the end of theclass Cdeclaration. - In the generic type extension
extend<T> C<T> {}, the scope ofTranges from its declaration to the end of the extension definition.
- In the generic type definition
- Similar to a function, the scope of the parameter name of the lambda expression is the lambda expression function body. The scope level can be considered as the same as that of a variable defined in the function body of the lambda expression.
- The parameter names of the main functions and constructors are considered to be introduced by the function body block. Introducing a name that is the same as the parameter name in the function body will trigger a redefinition error.
- Names introduced in the condition of an
if-letexpression are considered to be introduced by theifblock. If the same name is introduced again in theifblock, a redefinition error is triggered. - Names introduced by patterns in the match cases of a match expression have a higher scope level than the surrounding match expression, with a scope ranging from their introduction to the end of that match case. Each match case has an independent scope. Names introduced in the pattern binding of a match case are considered to be introduced by the scope following the fat arrow
=>. If the same name is introduced again after the=>, a redefinition error is triggered. - For all three types of loops, the scope level of the loop condition is the same as that of the loop block, meaning names introduced in them cannot shadow each other. In addition, loop conditions cannot reference variables defined in the loop body. Therefore:
- In a
for-inexpression, the loop body can reference variables introduced in the loop condition. - In
whileanddo-whileexpressions, their loop conditions cannot reference variables introduced in their loop bodies, even if thedo-whilecondition follows the loop body.
- In a
- Variables introduced in the loop condition of a
for-inloop cannot be used in expressions following theinkeyword. - For
tryexception handling, the scope of the block followingtryand that of eachcatchblock are independent of each other. Names introduced bycatchpatterns are viewed as introduced by the block followingcatch. Introducing the same name in thecatchblock will trigger a redefinition error. - In the try-with-resources expression, names introduced between the
trykeyword and the{}are considered to be introduced by thetryblock. Introducing the same name in thetryblock will trigger a redefinition error.
// a: The scope of a local variable begins after the declaration
let x = 4
func f(): Unit {
print("${x}") // Print 4
let x = 99
print("${x}") // Print 99
}
let y = 5
func g(): Unit {
let y = y // 'y' in the right of '=' is the global variable 'y'
print("${y}") // Print 5
let z = z // Error: unresolved identifier 'z' (in the right of '=')
}
// b: The scope of a local function begins after definition
func test1(): Unit {
func test2(): Unit {
print("test2")
test3() // Error, test3's scope begins after definition
}
func test3(): Unit {
test2()
}
test2()
}
let score: Int64 = 90
let good = 70
var scoreResult: String = match (score) { // binding pattern
case 60 => "pass" // constant pattern.
case 100 => "Full" // constant pattern.
case good => "good" // This good has higher scope level than the good at line 2
}
Type-internal
- The scope of members in
class,interface,struct, orenumis the entire definition of thatclass,interface,struct, orenum. - The scope of constructors defined within an
enumis the entireenumdefinition. For specific rules regarding access toconstructornames within anenum, see [Enum Type].
Shadowing
Generally, if the same name is introduced into two overlapping scopes with different levels, shadowing occurs. The name with a higher scope level shadows the name with a lower scope level. As a result, the name with a lower scope level either need to be prefixed with qualifiers or cannot be accessed. Shadowing is removed when the scope of the name with a higher scope level ends. Specifically, when the scope levels are different:
-
If the name
Cwith a higher scope level is of a type, shadowing occurs directly.// == in package a == public class C {} // ver 1 // == in package b == import a.* class C {} // ver 2 let v = C() // will use ver 2 -
If the name
xwith a higher scope level is a variable, shadowing occurs directly. For details about the shadowing rules of member variables, see [Classes and Interfaces].let x = 1 func foo() { let x = 2 println(x) // will print 2 } -
If the name
pwith a higher scope level is a package, shadowing occurs directly.// == in package a == public class b { public static let c = 1 } // == in package a.b == public let c = 2 // == in package test == import a.* import a.b.* let v = a.b.c // will be 1 -
If the name
fwith a higher scope level is a member function, the overloading rules are used to determine whetherfis overloaded. If there is no overloading, it may result in overriding or redefinition; if there is no overloading and overriding or redefinition is not possible, an error is reported. For details, see [Overriding] and [Redefinition].open class A { public open func foo() { println(1) } } class B <: A { public override func foo() { // override println(2) } public func foo() { // error, conflicting definitions println(3) } } -
If the name
fwith a higher scope level is a non-member function, the overloading rules are used to determine whetherfis overloaded. If there is no overloading, it is considered as shadowing.func foo() { 1 } func test() { func foo() { 2 } // shadows func foo(x: Int64) { 3 } // overloads println(foo()) // will print 2 }
The following example shows the shadowing relationship between multiple names (including types and variables) with different scope levels.
func g(): Unit {
f(1, 2) // OK. f is a top-level definition, which is visible in the whole file
}
func f(x: Int32, y: Int32): Unit {
// var x = 1 // Error, x was introduced by parameter
var i = 1 // OK
for (i in 1..3) { // OK, a new i in the block
let v = 1
} // i and v disappear
print("${i}") // OK. i is defined at line 9
// print("${v}") // Error, v disappeared and cannot be found
}
enum Maze {
C1 | C2
// | C1 // Error. The C1 has been used
}
The following example shows the shadowing relationship between names (including types and variables) in different packages.
// File a.cj
package p1
class A {}
var v: Int32 = 10
// File b.cj
package p2
import p1.A // A belongs to the package p1
import p1.v // v belongs to the package p1
// p2 has defined its own v, whose scope level is higher than the v from package p1
var v: Int32 = 20
func displayV1(): Unit {
// According to the scope level, p2.v shadows p1.v, therefore access p2.v here
print("${v}") // output: 20
}
var a = A() // Invoke A in p1
The following example shows the shadowing relationship in inheritance.
var x = 1
open class A {
var x = 3 // this x shadows the top level x
}
class B <: A {
var x = 5 // error: a member of the subtype must not shadow a member of the supertype.
func f(x!: Int32 = 7): Unit { // this x shadows all the previous x
}
}
Variables
As a statically typed language, Cangjie requires that the type of each variable be determined during compilation.
Variables can be classified into three types based on whether they can be modified: immutable variables (whose values cannot be changed once initialized), mutable variables (whose values can be changed), and const variables (which must be initialized during compilation and cannot be changed).
Definition of Variables
The syntax of defining variables is as follows:
variableDeclaration
: variableModifier* ('let' | 'var' | 'const') patternsMaybeIrrefutable (((':' type)? ('=' expression)) | (':' type))
;
patternsMaybeIrrefutable
: wildcardPattern
| varBindingPattern
| tuplePattern
| enumPattern
;
The definition of a variable consists of four parts: modifier, the let, var, or const keywords, patternsMaybeIrrefutable, and variable type, which are described as follows:
-
Modifiers
- The modifiers of the top-level variable are
public,protected,private, andinternal. - Local variables cannot be modified by modifiers.
- The modifiers of the member variables of the class type are
public,protected,private,internal, andstatic. - The modifiers of member variables of the struct type are
public,private,internal, andstatic.
- The modifiers of the top-level variable are
-
Keywords
let,var, andconstlet: defines immutable variables whose values cannot be changed once initialized.var: defines mutable variables.const: defines const variables.
-
patternsMaybeIrrefutable
let(orvar,const) can only be followed by patterns that must or may be irrefutable (see [Classification of Patterns]). During semantic check, the system checks whether the pattern is irrefutable. If the pattern is not irrefutable, a compilation error is reported.- The new variables introduced in the pattern after
let(orvar,const) are all variables modified bylet(orvar). - When defining member variables in a class or struct, you can only use the binding patterns (see [Binding Patterns]).
-
The variable type is optional. If the variable type is not declared, an initial value must be assigned to the variable, and the compiler will attempt to infer the variable type from the initial value.
-
Variables can be defined at the top-level, within expressions, or in the class or struct types.
Note that:
(1) Use a colon (:) to separate the pattern and variable type. The pattern type must match the type after the colon.
(2) The keywords let, var, and const and the pattern are required.
(3) In addition to the preceding syntax definition, local variables are introduced in the following scenarios:
- For details about patterns between
forandinin a for-in loop expression, see [For-in Expression]. - For details about parameters in the function and lambda definition, see [Parameters].
- For details about ResourceSpecifications in the try-with-resource expression, see [Exceptions].
- For details about pattern after case in the match expression, see [Pattern Matching Expressions].
(4) You can use a pair of backquotes () to change the keyword to a valid identifier, such as <idp:inline val="code" displayname="code">open and throw.
The following are some examples of variable definition:
let b: Int32 // Define read-only variable b with type Int32.
let c: Int64 // Define read-only variable c with type Int64.
var bb: String // Define writeable variable bb with type String.
var (x, y): (Int8, Int16) // Define two writeable variable: x with type Int8, x with type Int16.
var `open` = 1 // Define a variable named `open` with value 1.
var `throw` = "throw" // Define a variable named `throw` with value "throw".
const d: Int64 = 0 // Define a const variable named d with value 0.
Initializing Variables
Immutable and Mutable Variables
Both immutable variables and mutable variables can be initialized in either of the following ways: initialization during definition and initialization after definition. Note that each variable must be initialized before being used. Otherwise, a compilation error is reported. The following is an example of variable initialization:
func f() {
let a = 1 // Define and initialize immutable variable a.
let b: Int32 // Define immutable variable b without initialization.
b = 10 // Initialize variable b.
var aa: Float32 = 3.14 // Define and initialize mutable variable aa.
}
An immutable variable defined by let can be assigned a value only once (that is, initialization). If the variable is assigned a value for multiple times, a compilation error is reported. Mutable variables defined by var can be assigned multiple values.
func f() {
let a = 1 // Define and initialize immutable variable a.
a = 2 // error: immutable variable a cannot be reassigned.
var b: Float32 = 3.14 // Define and initialize mutable b.
b = 3.1415 // ok: mutable variable b can be reassigned.
}
class C {
let m1: Int64
init(a: Int64, b: Int64) {
m1 = a
if (b > 0) {
m1 = a * b // OK: immutable variable can be reassigned in constructor.
}
}
}
Global and Static Variables
Global variables are defined at the top level. Static variables include those defined in class or struct.
The initialization of global and static variables must meet the following rules:
-
Global variables must be initialized immediately when they are declared. Otherwise, an error is reported. That is, an initialization expression must be provided during declaration.
-
Static variables must be initialized immediately when they are declared. They can be initialized in the same way as global variables or in the static initializer. For details, see [Static Initializers].
- Note that static variables cannot be initialized in other static variables.
class Foo { static let x: Int64 static let y = (x = 1) // it's forbidden } -
The initialization expression
ecannot depend on uninitialized global variables or static variables. The compiler performs conservative analysis. Ifemay access an uninitialized global variable or static variable, an error is reported. The detailed analysis depends on the implementation of the compiler and is not specified in the specification.
The initialization time and sequence of global/static variables are as follows:
-
All global/static variables are initialized before
main(program entry). -
For global/static variables declared in the same file, the initialization sequence is from top to bottom based on the variable declaration sequence. If a static initializer is used, the initialization sequence is based on the initialization sequence rules of the static initializer. For details, see [Static Initializers].
-
For global/static variables declared in different files of the same package or different packages, their initialization sequence depends on the dependency between the global/static variables in the files or packages.
-
If the global/static variables in the
A.cjfile are directly or indirectly accessed during the initialization of the global/static variables in theB.cjfile, the initialization of the global/static variables in theB.cjfile depends on that of the global/static variables in theA.cjfile. The reverse is also true. -
If the initialization processes of global/static variables in two or more files depend on each other, a cyclic dependency is formed, and the compiler reports an error. If there is no dependency between these files, the initialization sequence is uncertain and determined by the compiler implementation.
-
If the variable, function, or type defined in the
Apackage is directly or indirectly used in theBpackage, theBpackage depends on theApackage. The reverse is also true. -
If there are cyclic dependencies between packages, the compiler reports an error. If there is no dependency between packages, their initialization sequence is uncertain and determined by the compiler implementation.
/* The initialization of the global variable cannot depend on the global variables defined in other files of the same package. */ // a.cj let x = 2 let y = z // OK, b.cj does not depend on this file directly or indirectly. let a = x // OK. let c = A() /* c.f is an open function, the compiler cannot statically determine whether the function meets the initialization rules of global variables, and an error may be reported. */ let d = c.f() open class A { // static var x = A.z // Error, A.z is used before its initialization. // static var y = B.f // Error, B.f is used before its initialization. static var z = 1 public open func f(): Int64 { return 77 } } class B { static var e = A.z // OK. static var f = x // OK. } // b.cj let z = 10 // let y = 10 // Error, y is already defined in a.cj. // main.cj main(): Int64 { print("${x}") print("${y}") print("${z}") return 1 }
const Variables
For details, see [Constant Evaluation].
Modifiers
Cangjie provides many modifiers, which are classified into the following types:
- Access modifier
- Non-access modifier
Modifiers are usually placed at the beginning of a definition to indicate that the definition has certain features.
Access Modifier
For details, see Access Modifiers in [Packages and Modules].
Non-access Modifier
Cangjie provides many non-access modifiers to support various functionalities.
- open: The instance member can be overridden by a subclass, or the class can be inherited by a subclass. For details, see [Classes].
- override: The member overrides that of the superclass. For details, see [Classes].
- redef: The static member redefines that of the superclass. For details, see [Classes].
- static: the member is a static member and cannot be accessed through an instance object. For details, see [Classes].
- abstract: The class is an abstract class. For details, see [Classes].
- foreign: The member is an external member. For details, see [Cross-Language Interoperability].
- unsafe: The context for interoperability with the C language. For details, see [Cross-Language Interoperability].
- sealed: The class or interface can be inherited or implemented only in the current package. For details, see [Classes].
- mut: The member has variable semantics. For details, see [Functions].
For details about these modifiers, see the corresponding sections.
Expressions
An expression consists of one or more operands. Multiple operands are connected by operators. Each expression has a type. The process of calculating the expression value is called evaluation.
In the Cangjie programming language, expressions are almost ubiquitous. There are expressions that represent various calculations (such as arithmetic expressions and logical expressions), and expressions that represent branches and loops (such as if expressions and loop expressions). For expressions that contain multiple operators, the precedence, associativity, and operand evaluation sequence of each operator must be specified. The precedence and associativity specify the combination mode of operands and operators. The evaluation sequence of operands specifies the evaluation sequence of operands of binary and ternary operators. Both of them affect the value of an expression.
The following describes expressions in Cangjie in sequence.
Note: The operand types of each operator in this chapter are specified on the premise that the operator is not overloaded.
Literals
A literal is an expression with a fixed syntax. For a literal that does not contain other expressions (see [Literals]), its value is the value of the literal itself, and its type can be determined by its syntax or context.When the literal type cannot be determined, an integer literal is of the Int64 type, and a floating-point literal is of the Float64 type. For a set literal or a tuple literal (see [Tuple]) that can contain other expressions internally, its value is equal to the value of the literal obtained after all expressions inside it are evaluated.Its type is determined by its syntax.
Example of literals:
main(): Int64 {
10u8 // UInt8 literal
10i16 // Int16 literal
1024u32 // UInt32 literal
1024 // Int64 literal
1024.512_f32 // Float32 literal
1024.512 // Float64 literal
'a' // Rune literal
true // Bool literal
"Cangjie" // String literal
() // Unit literal
[1, 2, 3] // Array<Int64> literal
(1, 2, 3) // (Int64, Int64, Int64) literal
return 0
}
Variable Names and Function Names
Variable names and function names (including variables or functions pointed to by package names) are also expressions. For a variable name, its value is equal to the evaluated value of the variable, and its type is that of the variable. For a function name, its value is a closure (see [Closures]), and its type is that of the function.
Examples of variable names and function names:
let intNum: Int64 = 100 // 'intNum' is the name of a variable, whose value and type are '100' and 'Int64', respectively.
/* 'add' is the name of a function, whose value and type are '(p1: Int64, p2: Int64) => {p1 + p2}' and '(Int64, Int64) -> Int64', respectively. */
func add(p1: Int64, p2: Int64) {
p1 + p2
}
let value = p1.x // x is a variable defined in package p1.
For variable names, the variables declared by var are always mutable. A value can be assigned to a variable declared by let only once (during or after declaration). The variable is mutable before the value is assigned and immutable after the value is assigned.
Generic Function Name as Expression
In Cangjie, functions (see [Functions]) can be used as the first member, and generic functions (see [Generics]) that declare type parameters are also supported.For a generic function, the type argument of the generic function must be provided when the function name is used as an expression. Example:
func identity<T>(a: T) { // identity is a generic function
return a
}
var b = identity // error: generic function 'identity' needs type arguments
var c = identity<Int32> // ok: Int32 is given as a type argument
identity is a generic function. Therefore, identity is not a valid expression. Only identity<Int32> that provides the type argument is a valid expression.
If a function is overloaded in the current scope and contains multiple optional functions with complete types, it is ambiguous to directly use the name of this type as an expression. For example:
interface Add<T> {
operator func +(a: T): T
}
func add<T>(i: T, j: Int64): Int64 where T <: Add<Int64> { // f1
return i + j;
}
func add<T>(i: T, j: T): T where T <: Add<T> { // f2
return i + j;
}
main(): Int64 {
var plus = add<Int64> // error: ambiguous use of 'add'
return 0
}
Condition Expressions
A conditional expression is an if expression. You can determine the code branch to be executed based on whether the conditions are met to implement the branch control logic.
The syntax of if expressions is defined as follows:
ifExpression
: 'if' '(' ('let' deconstructPattern '<-')? expression ')' block ('else' ( ifExpression | block))?
;
if is the keyword, followed by an expression enclosed in parentheses, a block, and an optional else branch in sequence. The else branch starts with the else keyword and is followed by a new if expression or a block.
The following is an example of if expressions:
main(): Int64 {
let x = 100
// if expression without else branch
if (x > 0) {
print("x is larger than 0")
}
// if expression with else branch
if (x > 0) {
print("x is larger than 0")
} else {
print("x is not larger than 0")
}
// if expression with nested if expression
if (x > 0) {
print("x is larger than 0")
} else if (x < 0) {
print("x is lesser than 0")
} else {
print("x equals to 0")
}
return 0
}
The expression following if (the expression type must be Bool) is evaluated first. If the value of the expression is true, the block following the expression is executed. Otherwise, the if expression or block (if any) following else is executed. The value of the if expression is equal to the value of the expression in the execution branch.
An if expression that contains let is called an if-let expression. You can use the if-let expression to perform some simple deconstruction operations.
The following is an example of a basic if-let expression:
main(): Int64 {
let x: Option<Int64> = Option<Int64>.Some(100)
// if-let expression without else branch
if (let Some(v) <- x) {
print("x has value")
}
// if-let expression with else branch
if (let Some(v) <- x) {
print("x has value")
} else {
print("x has not value")
}
return 0
}
In the if-let expression, the expression following <- (the expression type can be any type) is first evaluated. If the value of the expression matches the pattern following let, the block following the expression is executed. Otherwise, the if expression or block (if any) following else is executed. The value of the if-let expression is equal to the value of the expression in the execution branch.
The pattern following let supports the constant, wildcard, binding, tuple, and enum patterns.
Types of the if expression
For an if expression without an else branch, its type is Unit, and its value is (), because if expr1 {expr2} is the syntactic sugar of if expr1 {expr2; ()} else {()}.
For an if expression that contains an else branch:
-
If the value of the
ifexpression is not read or returned, the type of theifexpression is Unit, and the two branches do not need to have a common supertype. Otherwise, see the following rules. -
If there is no specific type requirement in the context and the two branch types of
ifare set toT1andT2, the type of theifexpression isT, the minimum common supertype ofT1andT2. If the minimum common supertypeTdoes not exist, an error is reported during compilation. -
If the context specifies type requirements, this supertype is the type of the
ifexpression. In this case, the types of the two branches ofifmust be the subtypes of the type required by the context.
For example:
struct S1 { }
struct S2 { }
interface I1 {}
class C1 <: I1 {}
class C2 <: I1 {}
interface I2{}
class D1 <: I1 & I2 {}
class D2 <: I1 & I2 {}
func test12() {
if (true) { // OK. The type of this if expression is Unit.
S1()
} else {
S2()
}
if (true) { // OK. The type of this if expression is Unit.
C1()
} else {
C2()
}
return if (true) { // Error. The `if` expression is returned. There is no least common supertype of `D1` and `D2`.
D1()
} else {
D2()
}
}
Note: To normalize the code format, improve the code maintainability, and avoid the dangling else problem, Cangjie requires that the execution part (even if there is only one expression) in each if branch and else branch use a pair of curly braces to enclose a block. (The dangling else problem refers to the problem that whether else expr2 in the code such as if cond1 if cond2 expr1 else expr2 belongs to the inner or the outer if cannot be determined. If else expr2 belongs to the inner if, the code should be interpreted as if cond1 (if cond2 expr1 else expr2). If it belongs to the outer if, the code should be interpreted as if cond1 (if cond2 expr1)expr2. However, if the branch is forced to use braces, this problem does not occur.)
Pattern Matching Expression
In Cangjie, match expressions can be used to implement pattern matching, and developers are allowed to use simpler code to describe complex branch control logic. Intuitively, a pattern is a structure that defines a set of instances that match the pattern. Pattern matching is to determine whether a given instance belongs to the instance set defined by the pattern. Obviously, there are only two matching results: success and failure. match expressions are classified into two types: match expressions with and without selector.
The syntax of match expressions is defined as follows:
matchExpression
: 'match' '(' expression ')' '{' matchCase+ '}'
| 'match' '{' ('case' (expression | '_') '=>' expressionOrDeclaration+)+ '}'
;
matchCase
: 'case' pattern ('|' pattern)* patternGuard? '=>' expressionOrDeclaration+
;
patternGuard
: 'where' expression
;
For a match expression with selector, expression following the keyword match is the selector to be matched. Multiple matchCases can be defined in {} after selector. Each matchCase starts with the keyword case, followed by a pattern or multiple patterns of the same type separated by | (For details about the definitions of different patterns, see [Patterns]), an optional pattern guard, a fat arrow =>, and a series of (at least one) declarations or expressions (separated by semicolons or newline characters).
During the execution of the match expression, a selector matches a pattern in the sequence defined by case. Once a selector matches the current pattern (and meets the pattern guard requirement), the code following the => is executed and the selector does not need to match the next pattern. If the selector does not match the current pattern, the system continues to match the next pattern. The same rule applies to the rest. The following example shows how to use constant patterns for branch control in a match expression:
let score: Int64 = 90
var scoreResult: String = match (score) {
case 0 => "zero"
case 10 | 20 | 30 | 40 | 50 => "fail"
case 60 => "pass"
case 70 | 80 => "good"
case 90 | 100 => "excellent" // matched
case _ => "not a valid score"
}
To ensure security and completeness, Cangjie requires that the combination of all patterns defined in case expressions and the corresponding patternGuards (if any) must be exhaustive, covering all possible values of selector. If the compiler determines that the combinations are not exhaustive, an error is reported. To implement complete coverage, you can use the wildcard _ in the last case to process the values that other cases fail to cover. In addition, it is not required that space defined by each pattern is mutually exclusive, that is, space covered by different patterns may overlap.
For a match expression without selector, the keyword match is not followed by expression. In each case within {}, only one expression of the Bool type (or the wildcard _, indicating that the value is always true) can be used between the keyword case and =>.
During the execution, the values of the expressions following case are checked in sequence. If the value of an expression is true, the code following => is executed, and all cases following => do not need to be checked. A match expression without selector is a concise expression for a series of nested if-else if expressions.
Similarly, the match expression without selector must be exhaustive (that is, at least one case is met in any case). The compiler performs exhaustive check if possible. If the check fails, an error is reported and the system prompts you to add case _.
let score = 80
var result: String = match {
case score < 60 => "fail"
case score < 70 => "pass"
case score < 90 => "good" // matched
case _ => "excellent"
}
Similar to an if expression, the type of a match expression complies with the following rules regardless of whether the match expression contains selector:
-
If the value of the
matchexpression is not read or returned, the type of thematchexpression is Unit, and all branches do not need to have a common supertype. Otherwise, see the following rules. -
If there is no specific type requirement in the context and all branch types of
matchareT1, ..., Tn, the type of thematchexpression isT, the minimum common supertype ofT1, ..., Tn. If the minimum common supertypeTdoes not exist, an error is reported. -
If the context has specific type requirements, this supertype is the type of the
matchexpression. In this case, the type of the expression following=>in eachcasemust be the subtype of the type required by the context.
Patterns
Changjie provides various patterns, including:
-
Constant patterns
-
Wildcard patterns
-
Binding patterns
-
Tuple patterns
-
Type patterns
-
Enum patterns
The syntax of patterns is defined as follows:
pattern
: constantPattern
| wildcardPattern
| varBindingPattern
| tuplePattern
| typePattern
| enumPattern
;
Constant Patterns
Constant patterns can be integer literals, byte literals, floating-point literals, Rune literals, Boolean literals, string literals (string interpolation is not supported), and unit literals. The type of a literal in the constant pattern must be the same as that of selector. The condition for successful matching between selector and a constant pattern is that selector is the same as the literal in the constant pattern.
The syntax of constant patterns is defined as follows:
constantPattern
: literalConstant
;
The following is an example of using constant patterns:
func f() {
let score: Int64 = 90
var scoreResult: String = match (score) {
case 0 => "zero"
case 10 | 20 | 30 | 40 | 50 => "fail"
case 70 | 80 => "good"
case 90 => "excellent" // matched
case _ => "not a valid score"
}
}
Note that floating-point literal matching complies with the floating-point equality comparison rules in constant patterns, which has the same precision problem as those encountered in other equality comparisons.
Wildcard Patterns
A wildcard pattern is represented by an underscore (_), which can match any value. It is usually used for partial matching (for example, as a placeholder) or as the last pattern of a match expression to match values that are not covered by other cases.
The syntax of wildcard patterns is defined as follows:
wildcardPattern
: '_'
;
The following is an example of using wildcard patterns:
let score: Int64 = 90
var scoreResult: String = match (score) {
case 60 => "pass"
case 70 | 80 => "good"
case 90 | 100 => "excellent" // matched
case _ => "fail" // wildcard pattern: used for default case
}
Binding Patterns
A binding pattern can also match any value. However, different from a wildcard pattern, a binding pattern binds the matched value to the variable defined in binding pattern so that the value can be accessed in the expression following =>.
The syntax of binding patterns is defined as follows:
varBindingPattern
: identifier
;
Variables defined in a binding pattern are immutable.
The following is an example of using binding patterns:
let score: Int64 = 90
var scoreResult: String = match (score) {
case 60 => "pass"
case 70 | 80 => "good"
case 90 | 100 => "excellent" // matched
case failScore => // binding pattern
let passNeed = 60 - failScore
"failed with ${failScore}, and ${passNeed} need to pass"
}
For a variable defined in the binding pattern, its scope starts from the position where the variable appears for the first time and ends before the next case. Note that | is used to connect multiple patterns, the binding pattern cannot be used and cannot be nested in other patterns. Otherwise, an error is reported.
let opt = Some(0)
match (opt) {
case x | x => {} // error: variable cannot be introduced in patterns connected by '|'
case Some(x) | Some(x) => {} // error: variable cannot be introduced in patterns connected by '|'
case x: Int64 | x: String => {} // error: variable cannot be introduced in patterns connected by '|'
}
Tuple Patterns
A tuple pattern is used to match the values of Tuple. It is defined as multiple patterns enclosed in parentheses and separated by commas (,): (pattern_1, pattern_2, ... pattern_k). For example, (x, y, z) is a tuple pattern including three binding patterns, and (1, 0, 0) is a tuple pattern including three constant patterns. The number of sub-patterns in a tuple pattern must be the same as the dimension of selector. If the sub-patterns are constant patterns or enum patterns, their type must be the same as the type of selector dimension.
The syntax of tuple patterns is defined as follows:
tuplePattern
: '(' pattern (',' pattern)+ ')'
;
The following is an example of using tuple patterns:
let scoreTuple = ("Allen", 90)
var scoreResult: String = match (scoreTuple) {
case ("Bob", 90) => "Bob got 90"
case ("Allen", score) => "Allen got ${score}" // matched
case ("Allen", 100) | ("Bob", 100) => "Allen or Bob got 100"
case (_, _) => ""
}
Type Patterns
The type check and type cast can be easily implemented using type patterns. The syntax of type patterns is defined as follows:
typePattern
: (wildcardPattern | varBindingPattern) ':' type
;
For the type pattern varBindingPattern : type (or wildcardPattern : type): Check whether the runtime type of the value to be matched is the type defined by type on the right of : or its subtype. If the type is matched successfully, convert the value type to the defined type, and then bind the value of the new type to varBindingPattern on the left of :. (There is no binding for wildcardPattern : type.) The matching is successful only when the type is matched. Otherwise, the matching fails. Therefore, varBindingPattern : type (or wildcardPattern : type) can implement both type test and type cast.
The following is an example of type pattern matching:
open class Point {
var x: Int32 = 1
var y: Int32 = 2
init(x: Int32, y: Int32) {
this.x = x
this.y = y
}
}
class ColoredPoint <: Point {
var color: String = "green"
init(x: Int32, y: Int32, color: String) {
super(x, y)
this.color = color
}
}
let normalPt = Point(5,10)
let colorPt = ColoredPoint(8,24,"red")
var rectangleArea1: Int32 = match (normalPt) {
case _: Point => normalPt.x * normalPt.y // matched
case _ => 0
}
var rectangleArea2: Int32 = match (colorPt) {
case cpt: Point => cpt.x * cpt.y // matched
case _ => 0
}
Enum Patterns
An enum pattern is used together with the enum type.
An enum pattern is used to match the enum constructor. The format is constructorName (parameterless constructor) or constructorName(pattern_1, pattern_2, ..., pattern_k) (parameterized constructor). Multiple patterns, separated by commas (,) in parentheses, match each parameter in sequence. The patterns can be of any other type and can be nested.
The syntax of enum patterns is defined as follows:
enumPattern
: (userType '.')? identifier enumPatternParameters?
;
enumPatternParameters
: '(' pattern (',' pattern)* ')'
;
The following is an example of enum pattern matching:
enum TimeUnit {
| Year(Float32)
| Month(Float32, Float32)
| Day(Float32, Float32, Float32)
| Hour(Float32, Float32, Float32, Float32)
}
let oneYear = TimeUnit.Year(1.0)
var howManyHours: Float32 = match (oneYear) {
case Year(y) => y * Float32(365 * 24) // matched
case Month(y, m) => y * Float32(365 * 24) + m * Float32(30 * 24)
case Day(y, m, d) => y * Float32(365 * 24) + m * Float32(30 * 24) + d * Float32(24)
case Hour(y, m, d, h) => y * Float32(365 * 24) + m * Float32(30 * 24) + d * Float32(24) + h
}
let twoYear = TimeUnit.Year(2.0)
var howManyYears: Float32 = match (twoYear) {
case Year(y) | Month(y, m) => y // error: variable cannot be introduced in patterns connected by '|'
case Year(y) | Month(x, _) => y // error: variable cannot be introduced in patterns connected by '|'
case Year(y) | Month(y, _) => y // error: variable cannot be introduced in patterns connected by '|'
...
}
In the scope of pattern matching, if the identifier in a pattern is an enum constructor, the identifier is always matched as an enum pattern. Otherwise, the identifier is matched as a binding pattern.
enum Foo {
A | B | C
}
func f() {
let x = Foo.A
match (x) {
case A => 0 // enum pattern
case B => 1 // enum pattern
case C => 2 // enum pattern
case D => 3 // binding pattern
}
}
Note that the type of the enum pattern must be the same as that of the selector during matching. In addition, the compiler checks whether each constructor (including the values of the constructor parameters) of the enum type is completely overridden. If not, the compiler reports an error.
enum TimeUnit {
| Year(Float32)
| Month(Float32, Float32)
| Day(Float32, Float32, Float32)
| Hour(Float32, Float32, Float32, Float32)
}
let oneYear = TimeUnit.Year(1.0)
var howManyHours: Float32 = match (oneYear) { // error: match must be exhaustive
case Year(y) => y * Float32(365 * 24)
case Month(y, m) => y * Float32(365 * 24) + m * Float32(30 * 24)
}
Classification of Patterns
Generally, if a pattern does not match the value to be matched, the pattern is called refutable pattern. If a pattern always matches the value to be matched, the pattern is called irrefutable pattern. For the preceding patterns, the following rules are defined:
- Constant patterns are always refutable patterns.
- Wildcard patterns are always irrefutable patterns.
- Binding patterns are always irrefutable patterns.
- A tuple pattern is an irrefutable pattern only when all of its patterns are irrefutable patterns.
- Type patterns are always refutable patterns.
- An enum pattern is an irrefutable pattern only when the corresponding enum type has only one parameterized constructor, and other patterns (if any) contained in the enum pattern are irrefutable patterns.
Matching Rules of Character Strings, Bytes, and Rune
When the target of pattern matching is a value whose static type is Rune, both the Rune literal and the single-character string literal can be used as constant patterns representing Rune literals.
When the target of pattern matching is a value whose static type is Byte, a string literal representing an ASCII character can be used as a constant pattern representing the Byte literal.
Pattern Guards
To further determine the matched value, Cangjie supports pattern guard. pattern guard can be used in match expressions or for-in expressions. This section describes how to use pattern guard in match expressions. For details about how to use pattern guard in for-in expressions, see [for-in Expressions].
In match expressions, pattern guard is supported to provide a more powerful and accurate matching pattern. That is, where boolExpression is added between pattern and => (boolExpression is an expression whose value is of the Boolean type). The matching is successful only when the value matches the pattern and the boolExpression following the where is met. Otherwise, the matching fails.
The syntax of pattern guard is defined as follows:
patternGuard
: 'where' expression
;
The following is an example of using pattern guards:
let oneYear = Year(1.0)
var howManyHours: Float32 = match (oneYear) {
case Year(y) where y > 0.0f32 => y * Float32(365 * 24) // matched
case Year(y) where y <= 0.0f32 => 0.0
case Month(y, m) where y > 0.0f32 && m > 0.0f32 => y * Float32(365 * 24) + m * Float32(30 * 24)
case Day(y, m, d) where y > 0.0f32 && m > 0.0f32 && d > 0.0f32 => y * Float32(365 * 24) + m * Float32(30 * 24) + d * Float32(24)
case Hour(y, m, d, h) where y > 0.0f32 && m > 0.0f32 && d > 0.0f32 && h > 0.0f32 => y * Float32(365 * 24) + m * Float32(30 * 24) + d * Float32(24) + h
case _ => 0.0
}
Loop Expressions
Cangjie supports three types of loop expressions: for-in, while, and do-while.
The syntax of loop expressions is defined as follows:
loopExpression
: forInExpression
| whileExpression
| doWhileExpression
;
for-in Expressions
A complete for-in expression has the following form:
for (p in e where c) {
s
}
pattern guard where c is optional. Therefore, a simpler format of for-in expressions is as follows:
for (p in e) {
s
}
The syntax of for-in expressions is defined as follows:
forInExpression
: 'for' '(' patternsMaybeIrrefutable 'in' expression patternGuard? ')' block
;
patternsMaybeIrrefutable
: wildcardPattern
| varBindingPattern
| tuplePattern
| enumPattern
;
patternGuard
: 'where' expression
;
In the preceding syntax definition, the keyword for can be followed only by patterns that must or may be irrefutable (see [Classification of Patterns]). In semantic check, the system checks whether the patterns following for are irrefutable. If not, an error is reported during compilation. In addition, if the patterns after for contain any binding pattern, it is equivalent to declaring one (or more) let variables. The scope of each variable starts from the position where the variable appears for the first time to the end of the loop body.
for-in evaluates expression and then calls its iterator() function to obtain a value of the Iterator<T> type. The program starts to execute the loop by calling the next() function of Iterator<T>. You can use patterns to match the iteration elements. If the matching is successful (if patternGuard exists, its conditions must also be met), the loop body block is executed, and then next() is called again at the beginning to continue the loop, when next() returns None, the loop ends.
You can query Iterable<T> and Iterator<T> in the standard library.
main(): Int64 {
let intArray: Array<Int32> = [0, 1, 2, 3, 4]
for (item in intArray) {
print(item) // output: 01234
}
let intRange = 0..5
for (number in intRange where number > 2) {
print(number) // output: 34
}
return 0
}
while Expressions
The syntax of while expressions is defined as follows:
whileExpression
: 'while' '(' ('let' deconstructPattern '<-')? expression ')' block
;
The syntax includes the keyword while, parentheses that enclose an expression or a deconstruction match declared by let, and a block.
The following is an example of a basic while expression:
main(): Int64 {
var hundred = 0
while (hundred < 100) { // until hundred = 100
hundred++
}
return 0
}
In the while expression, the expression following while (the expression type must be Bool) is first evaluated. If the value of the expression is true, the block following the expression is executed. Then, the expression value is recalculated and whether to execute the loop again is determined. If the value of the expression is false, the loop is terminated.
A while expression that contains let is called a while-let expression. You can use the while-let expression to perform some simple deconstruction operations.
The following is an example of a basic while-let expression:
main(): Int64 {
var x: Option<Int64> = Option<Int64>.Some(100)
// while-let expression
while (let Some(v) <- x) {
print("x has value")
x = ...
}
return 0
}
In the while-let expression, the expression following <- (the expression type can be any type) is first evaluated. If the value of the expression matches the pattern following let, the block following the expression is executed. Then, the value of the expression is recalculated and matched again to determine whether to execute a loop again. If the matching fails, the current while loop is terminated.
The patterns following let can be constant, wildcard, binding, tuple, or enum patterns.
do-while Expressions
The syntax of do-while expressions is defined as follows:
doWhileExpression
: 'do' block 'while' '(' expression ')'
;
Different from the while expression, if the value of expression is false during the first loop iteration of the while expression, the loop body is not executed. However, for the do-while expression, during the first loop iteration, the loop body block is executed first, and then whether to execute the loop body again is determined based on the value of expression. That is, the loop body in the do-while expression is executed at least once. Example:
main(): Int64 {
var hundred = 0
do {
hundred++
} while (hundred < 100)
return 0
}
Summary of Loop Expressions
The expression capabilities of the for-in, while, and do-while expressions are equivalent. Generally, if the number of loops is known or all elements in a sequence are traversed, for-in expressions are used. If the number of loops is unknown but the loop termination condition is known, while or do-while expressions are used.
The three loop expressions are of the Unit type.
The break and continue expressions must have their loop bodies. Therefore, for the three types of loop expressions, break or continue in the loop condition is bound to the nearest outer loop. If the outer loop does not exist, an error is reported. For example:
while (true) {
println("outer") // printed once
do {
println("inner") // printed once
} while (break) // stop the execution of the outer loop
println("unreached") // not printed
}
try Expressions
The try expressions are classified into ordinary try expressions that do not involve automatic resource management and try-with-resources expressions that involve automatic resource management.
The syntax of try expressions is as follows:
tryExpression
: 'try' block 'finally' block
| 'try' block ('catch' '(' catchPattern ')' block)+ ('finally' block)?
| 'try' '(' resourceSpecifications ')' block ('catch' '(' catchPattern ')' block)* ('finally' block)?
;
Ordinary try expressions are used for error handling. For details, see chapter [Exceptions].
The try-with-resources expression is used to automatically release non-memory resources. For details, see chapter [Exceptions].
Control Transfer Expressions
Control transfer expressions change the execution sequence of programs. The type of control transfer expressions is Nothing, which is a subtype of any type. Cangjie provides the following control transfer expressions:
breakcontinuereturnthrow
Like any other expression, a control transfer expression can be used as a subexpression to become a part of a complex expression, but may cause unreachable code (a compilation alarm will be generated for the unreachable part).
main(): Int64 {
return return 1 // warning: the left return expression is unreachable
}
In the control transfer expression, break and continue must have their surrounding loop bodies, and the loop bodies cannot cross the function boundary. return must have its surrounding function body, and the function body cannot cross the function boundary. There is no requirement on throw.
A surrounding loop body "cannot cross" the function boundary. In the following example, break appears in the f function, and the outer while loop body is not considered as the loop body that surrounds break. continue appears in the lambda expression, and the outer while loop body is not considered as the loop body that surrounds continue.
while (true) {
func f() {
break // Error: break must be used directly inside a loop
}
let g = { =>
continue // Error: continue must be used directly inside a loop
}
}
The syntax of control transfer expressions is as follows:
jumpExpression
: 'break'
| 'continue'
| 'return' expression?
| 'throw' expression
;
break Expressions
A break expression can be used only in the loop body of a loop expression, and the execute permission of the program is granted to the expression after the terminated loop expression. For example, the following code uses a break expression in the while loop body to calculate the least common multiple of 4 and 6 in the interval [1,49].
main(): Int64 {
var index: Int32 = 0
while (index < 50) {
index = index + 1
if ((index % 4 == 0) && (index % 6 == 0)) {
print("${index} is divisible by both 4 and 6") // output: 12
break
}
}
return 0
}
Note that when break appears in a nested loop expression, only the loop expression that directly surrounds it can be terminated. The outer loop is not affected. For example, the following program outputs 12 is divisible by both 4 and 6 for five times and outputs the value of i each time:
main(): Int64 {
var index: Int64 = 0
for (i in 0..5) {
index = i
while (index < 20) {
index = index + 1
if ((index % 4 == 0) && (index % 6 == 0)) {
print("${index} is divisible by both 4 and 6")
break
}
}
print("${i}th test")
}
return 0
}
continue Expressions
A continue expression can be used only in the loop body of a loop expression. It ends the current iteration of the closest loop expression in advance and then start a new round of loop (the loop expression is not terminated). For example, in the following code output range [1,49], all numbers (12, 24, 36, and 48) that can be exactly divided by both 4 and 6 are output. Other numbers that do not meet the requirements are also explicitly output.
main(): Int64 {
var index: Int32 = 0
while (index < 50) {
index = index + 1
if ((index % 4 == 0) && (index % 6 == 0)) {
print("${index} is divisible by both 4 and 6")
continue
}
print("${index} is not what we want")
}
return 0
}
return Expressions
A return expression can be used only in the function body. It can terminate the execution of a function at any position and return a value, transferring the control flow from the called function to the calling function. A return statement can be in the following two formats: return and return expr (expr indicates an expression).
- If an expression is in
return exprformat, the value ofexpris the return value of the function. Therefore, the type ofexprmust be the same as the return type in the function definition.
// return expression
func larger(a: Int32, b: Int32): Int32 {
if (a >= b) {
return a
} else {
return b
}
}
- If an expression is in
returnformat, it is considered as the syntactic sugar ofreturn(). Therefore, the return type of the function must also beUnit.
// return expression
func equal(a: Int32, b: Int32): Unit {
if (a == b) {
print("a is equal to b")
return
} else {
print("a is not equal to b")
}
}
It should be noted that, the type of the return expression as a whole is not determined by its following expression (the expression following return is ()), but is of the Nothing type.
throw Expressions
The throw expressions throw exceptions. When a code block that contains a throw expression is called, if the throw expression is executed, the corresponding exception is thrown. The predefined exception handling logic captures and processes the exception, changing the program execution process.
In the following example, an arithmetic exception is thrown when the divisor is 0:
func div(a: Int32, b: Int32): Int32 {
if (b != 0) {
return a / b
} else {
throw ArithmeticException()
}
}
This section provides only the simplest examples of the return and throw expressions. For details, see chapters [Functions] and [Exceptions].
Numeric Type Conversion Expressions
A numeric type conversion expression implements conversion between numeric types. It adopts the value and the target type (the type of the original expression is not affected by the target type) after type conversion. For details about the conversion rules, see [Type Conversion].
The syntax of numeric type conversion expressions is defined as follows:
numericTypeConvExpr
: numericTypes '(' expression ')'
;
numericTypes
: 'Int8'
| 'Int16'
| 'Int32'
| 'Int64'
| 'UInt8'
| 'UInt16'
| 'UInt32'
| 'UInt64'
| 'Float16'
| 'Float32'
| 'Float64'
;
this and super Expressions
The this and super expressions are represented by this and super respectively. this can appear in all instance member functions and constructors, indicating the current instance. super can appear only in the class definitions, indicating the instance of the direct superclass of the currently defined type (For details, see [Classes]). Do not use an independent super expression.
The syntax of this and super expressions is defined as follows:
thisSuperExpression
: 'this'
| 'super'
;
spawn Expressions
A spawn expression creates and starts a thread. For details, see [Concurrency].
synchronized Expressions
The synchronized expressions are used in the synchronization mechanism. For details, see [Concurrency].
Parenthesized Expressions
A parenthesized expression is an expression enclosed in parentheses. The subexpression enclosed in parentheses is considered as a separate calculation unit and is preferentially calculated.
The syntax of parenthesized expressions is defined as follows:
parenthesizedExpression
: '(' expression ')'
;
Example of a parenthesized expression:
1 + 2 * 3 - 4 // The result is 3.
(1 + 2) * 3 - 4 // The result is 5.
Postfix Expressions
A postfix expression consists of an expression and a postfix operator. Based on operators, postfix expressions are classified into member access expressions, function call expressions, and index access expressions. When the optional ? operator is used before their operators, the Option type can support these operators. For details about the ? operator, see the following description.
The syntax of postfix expressions is defined as follows:
postfixExpression
: atomicExpression
| type '.' identifier
| postfixExpression '.' identifier typeArguments?
| postfixExpression callSuffix
| postfixExpression indexAccess
| postfixExpression '.' identifier callSuffix? trailingLambdaExpression
| identifier callSuffix? trailingLambdaExpression
| postfixExpression ('?' questSeperatedItems)+
;
Member Access Expressions
The syntax of member access expressions is defined as the third item of the preceding postfix expression syntax:
postfixExpression '.' identifier typeArguments?
Member access expressions can be used to access members of a class, interface, and struct.
A member access expression is in the format of T.a. T indicates a specific instance or type name, which is called the body of the member access expression. a indicates the name of a member.
-
If
Tis an instantiated object of a class, non-static members in the class or interface can be accessed in this way. -
If
Tis an instance ofstruct, non-static members instructcan be accessed by instance name. -
If
Tis the name of a class, interface, orstruct, its static members can be accessed directly by type name.
Note that the access subject of static members of the class, interface, and struct can only be type names.
-
Tisthis: In the scope of a class or interface, thethiskeyword can be used to access non-static members. -
Tissuper: In the scope of a class or interface, thesuperkeyword can be used to access the non-static members of the superclass of the current class object.
For a member access expression e.a, if e is a type name:
- When
ais a mutable static member variable ofe,e.ais mutable. In other cases,e.ais immutable.
If e is an expression (assuming that the type of e is T):
-
When
Tis of the reference type, ifais a mutable instance member variable ofT,e.ais mutable. Otherwise,e.ais immutable. -
When
Tis of the value type, ifeis mutable andais a mutable instance member variable ofT,e.ais mutable. Otherwise,e.ais immutable.
Function Call Expressions
The syntax of function call expressions is defined as the fourth item of the preceding postfix expression syntax. The syntax of callSuffix and valueArgument is defined as follows:
callSuffix
: '(' (valueArgument (',' valueArgument)*)? ')'
;
valueArgument
: identifier ':' expression
| expression
| refTransferExpression
;
refTransferExpression
: 'inout' (expression '.')? identifier
;
Function call expressions are used to call functions. For details about functions, see [Functions].
For the function call expression f(x), assume that the type of f is T. If T is of the function type, the function named f is called. Otherwise, if T overloads the function call operator (), f(x) calls its operator overloading function () (see [Operators That Can Be Overloaded]).
Index Access Expressions
The syntax of index access expressions is defined as the fifth item of the preceding postfix expression syntax. The syntax of indexAccess is defined as follows:
indexAccess
: '[' (expression | rangeElement) ']'
;
rangeElement
: '..'
| ('..=' | '..' ) expression
| expression '..'
;
Index access expressions are used for types that support index access (including the Array and Tuple types) to access elements in specific locations through indexes. For details, see [Array] and [Tuple] in [Types].
For the index access expression e[a] (assuming that the type of e is T):
-
If
Tis of the Tuple type,e[a]is immutable. -
If
Tis not of the Tuple type and it overloads the[]operator in set form (see [Operators That Can Be Overloaded]),e[a]is mutable. Otherwise,e[a]is immutable.
For the index access expression e1[e2], the Cangjie language always evaluates e1 to v1, then evaluates e2 to v2, and finally selects the corresponding value based on the index v2 or calls the corresponding overloaded [] operator.
Question Mark Operators
The question mark operator ? is a unary postfix operator. It must be used together with and before the postfix operators ., (), {}, or [] described above to enable the Option type to support these postfix operators, such as a?.b, a?(b), and a?[b]. () is used for function call. When the last argument of the function call is lambda, the tailing closure syntax a?{b} can be used. An expression that contains ?., ?(), ?{}, or ?[] is called an optional chaining expression.
The syntax of optional chaining expressions is defined as the last item of the preceding postfix expression syntax. The syntax of questSeperatedItems is defined as follows:
questSeperatedItems
: questSeperatedItem+
;
questSeperatedItem
: itemAfterQuest (callSuffix | callSuffix? trailingLambdaExpression | indexAccess)?
;
itemAfterQuest
: '.' identifier typeArguments?
| callSuffix
| indexAccess
| trailingLambdaExpression
;
The rules for the optional chaining expressions are as follows:
-
For the expression
e, delete all?ine, change the type of the expression right before?fromOption<T>toT, and obtain the expressione1. If the type ofe1is Option, add?betweeneand.,(),{}, or[]when using these operators aftere. Otherwise, do not add?. -
The type of an optional chaining expression is
Option<T>(That is, no matter how many?operators exist, the type has only one layer of Option). The typeTis that of the last expression (variable or function name, function call expression, or index access expression) in the optional chaining expression. -
If the value of an expression of the Option type in the optional chaining expression is
None, the value of the entire optional chaining expression isNone. If the value of each expression of the Option type in the optional chaining expression is equal to aSomevalue, the value of the entire expression isSome(v)(the type ofvis that of the last expression).
The following examples use the expressions a?.b, c?(d), and e?[f]:
-
The expression
amust be of anOption<T1>type, andT1must contain the instance memberb. The expressioncmust be of anOption<(T2)->U2>type, and the type ofdmust beT2. The expressionemust be of anOption<T3>type, andT3supports index operators. -
The types of expressions
a?.b,c?(d), ande?[f]areOption<U1>,Option<U2>, andOption<U3>, whereU1is the type of the instance memberbinT1,U2is the return value type of the function type(T2)->U2, andU3is the return type of the index operation performed byT3. -
When the values of
a,c, andeareSome(v1),Some(v2), andSome(v3), respectively, the values ofa?.b,c?(d), ande?[f]areOption<U1>.Some(v1.b),Option<U2>.Some(v2(d)), andOption<U3>.Some(v3[f]), respectively. When the values ofa,c, andeareNone, the values ofa?.b,c?(d), ande?[f]areOption<U1>.None,Option<U2>.None, andOption<U3>.None, respectively. (Note thatb,d, andfare not evaluated.)
The expressions a?.b, c?(d), and e?[f] are equivalent to the following match expressions respectively:
// a?.b is equivalent to the following match expression.
match (a) {
case Some(v) => Some(v.b)
case None => None<U1>
}
// c?(d) is equivalent to the following match expression.
match (c) {
case Some(v) => Some(v(d))
case None => None<U2>
}
// e?[f] is equivalent to the following match expression.
match (e) {
case Some(v) => Some(v[f])
case None => None<U3>
}
The next example contains multiple ? in the multi-layer access expression a?.b.c?.d (?. is an example that can be applied in other operations in similar ways.)
-
The
aexpression must be of anOption<Ta>type, andTamust contain the instance memberb. The type ofbmust contain the instance member variablec, andcmust be of anOption<Tc>type.Tcmust contain the instance memberd. -
The type of the expression
a?.b.c?.disOption<Td>, whereTdis the type of the instance memberdofTc. -
When the value of
ais equal toSome(va)and that ofva.b.cis equal toSome(vc), the value ofa?.b.c?.dis equal toOption<Td>.Some(vc.d). When the value ofais equal toSome(va)and that ofva.b.cis equal toNone, the value ofa?.b.c?.dis equal toOption<Td>.None(dis not evaluated). When the value ofais equal toNone, the value ofa?.b.c?.dis equal toOption<Td>.None(b,c, anddare not evaluated).
The expression a?.b.c?.d is equivalent to the following match expression:
// a?.b.c?.d is equivalent to the following match expression.
match (a) {
case Some(va) =>
let x = va.b.c
match (x) {
case Some(vc) => Some(vc.d)
case None => None<Td>
}
case None =>
None<Td>
}
Optional chaining expressions can also be used as lvalue expressions (see [Assignment Expressions]), such as a?.b = e1, a?[b] = e2, and a?.b.c?.d = e3.
If an optional chaining expression is on the left of an assignment expression, the former must be mutable (For details, see [Assignment Expressions]). Because the function type is immutable, only ?. and ?[] need to be considered. Both of them fall into two basic scenarios: a?.b = c and a?[b] = c (assuming that the type of a is Option<T>). The rules are as follows:
-
a?.bis mutable only whenTis of the reference type andbis mutable. In other cases,a?.bis immutable. -
a?[b]is mutable only whenTis of the reference type and[]in set mode is overloaded. In other cases,a?[b]is immutable.
When a?.b (or a?[b]) is mutable, if the value of a is equal to Option<T>.Some(v), assign the value of c to v.b (or v[b]); if the value of a is equal to Option<T>.None, do not perform any operation (b and c are not evaluated).
Similarly, the expressions a?.b = e1, a?[b] = e2, and a?.b.c?.d = e3 are equivalent to the following match expressions:
// a?.b = e1 is equivalent to the following match expression.
match (a) {
case Some(v) => v.b = e1
case None => ()
}
// a?[b] = e2 is equivalent to the following match expression.
match (a) {
case Some(v) => v[b] = e2
case None => ()
}
// a?.b.c?.d = e3 is equivalent to the following match expression.
match (a) {
case Some(va) =>
match (va.b.c) {
case Some(vc) => vc.d = e3
case None => ()
}
case None =>
()
}
The following example is how the ? operator is used:
// The usuage of ?.
class C {
var item: Int64 = 100
}
let c = C()
let c1 = Option<C>.Some(c)
let c2 = Option<C>.None
let r1 = c1?.item // r1 = Option<Int64>.Some(100)
let r2 = c2?.item // r2 = Option<Int64>.None
func test1() {
c1?.item = 200 // c.item = 200
c2?.item = 300 // no effect
}
// The usuage of ?()
let foo = {i: Int64 => i + 1}
let f1 = Option<(Int64) -> Int64>.Some(foo)
let f2 = Option<(Int64) -> Int64>.None
let r3 = f1?(1) // r3 = Option<Int64>.Some(2)
let r4 = f2?(1) // r4 = Option<Int64>.None
// The usuage of ?[] for tuple access
let tuple = (1, 2, 3)
let t1 = Option<(Int64, Int64, Int64)>.Some(tuple)
let t2 = Option<(Int64, Int64, Int64)>.None
let r7 = t1?[0] // r7 = Option<Int64>.Some(1)
let r8 = t2?[0] // r8 = Option<Int64>.None
func test3() {
t1?[0] = 10 // error: 't1?[0]' is immutable
t2?[1] = 20 // error: 't2?[0]' is immutable
}
Increment and Decrement Expressions
Increment and decrement expressions are expressions that contain increment operators (++) or decrement operators (--). a++ and a-- are syntactic sugars of a+=1 and a-=1, respectively. The increment and decrement operators add 1 to and subtract 1 from values, and can be used only as postfix operators. ++ and -- are non-associative. Therefore, it is (syntactically) forbidden that an expression contains two or more ++/-- operators, such as a++-- but does not use parentheses to specify the calculation sequence.
The syntax of increment and decrement expressions is defined as follows:
incAndDecExpression
: postfixExpression ('++' | '--' )
;
The rules for expr++ (or expr--) expression are as follows:
-
The type of
exprmust be integer. -
Because
expr++(orexpr--) is the syntactic sugar ofexpr += 1(orexpr -= 1),exprmust also be assignable (see [Assignment Expressions]). -
The type of
expr++(orexpr--) isUnit.
The following examples are the increment and decrement expressions:
var i: Int32 = 5
i++ // i = 6
i-- // i = 5
i--++ // syntax error
var j = 0
j = i-- // semantics error
Arithmetic Expressions
An arithmetic expression is an expression that contains arithmetic operators. Cangjie supports the following arithmetic operators: unary minus sign (-), addition (+), subtraction (-), multiplication (*), division (/), modulo (%), and exponentiation (**). Except that the unary minus sign is a unary prefix operator, other operators are binary infix operators. Their precedence and associativity are described below.
The syntax of arithmetic expressions is defined as follows:
prefixUnaryExpression
: prefixUnaryOperator* incAndDecExpression
;
prefixUnaryOperator
: '-'
| ...
;
additiveExpression
: multiplicativeExpression (additiveOperator multiplicativeExpression)*
;
multiplicativeExpression
: exponentExpression (multiplicativeOperator exponentExpression)*
;
exponentExpression
: prefixUnaryExpression (exponentOperator prefixUnaryExpression)*
;
additiveOperator
: '+' | '-'
;
multiplicativeOperator
: '*' | '/' | '%'
;
exponentOperator
: '**'
;
The operand of the unary minus sign (-) must be an expression of the numeric type. The value of the unary prefix minus sign expression is equal to the negated value of the operand. The type is the same as that of the operand.
let num1: Int64 = 8
let num2 = -num1 // num2 = -8, with 'Int64' type
let num3 = -(-num1) // num3 = 8, with 'Int64' type
For binary operators *, /, %, +, and -, the two operands must be of the same type. The operand of % can only be an integer. The operands of *, /, +, and - can be of any numeric type.
let a = 2 + 3 // add: 5
let b = 3 - 1 // sub: 2
let c = 3 * 4 // multi: 12
let d = 6.6 / 1.1 // division: 6
let e = 4 % 3 // mod: 1
In particular, when the operand of the division (/) is an integer, the non-integer value is rounded to an integer, rounding toward 0. The value of the integer modulo operation a % b is defined as a - b * (a / b).
let q1 = 7 / 3 // integer division: 2
let q2 = -7 / 3 // integer division: -2
let q3 = 7 / -3 // integer division: -2
let q4 = -7 / -3 // integer division: 2
let r1 = 7 % 3 // integer remainder: 1
let r2 = -7 % 3 // integer remainder: -1
let r3 = 7 % -3 // integer remainder: 1
let r4 = -7 % -3 // integer remainder: -1
** indicates the exponentiation operation. For example, x**y indicates that the y exponent of the base x is calculated. The left operand of ** must be of the Int64 or Float64 type.
-
When the left operand is of the
Int64type, the right operand must be of theUInt64type, and the expression type must beInt64. -
When the left operand is of the
Float64type, the right operand must be of theInt64orFloat64type, and the expression type must beFloat64.
let p1 = 2 ** 3 // p1 = 8
let p2 = 2 ** UInt64(3 ** 2) // p2 = 512
let p3 = 2.0 ** 3 // p3 = 8.0
let p4 = 2.0 ** 3 ** 2 // p4 = 512.0
let p5 = 2.0 ** 3.0 // p5 = 8.0
let p6 = 2.0 ** 3.0 ** 2.0 // p6 = 512.0
When the left operand type is Float64 and the right operand type is Int64, the value of the exponentiation expression needs to be specified in some special cases as follows:
x ** 0 = 1.0 // for any x
0.0 ** n = POSITIVE_INFINITY // for odd n < 0
-0.0 ** n = NEGATIVE_INFINITY // for odd n < 0
0.0 ** n = POSITIVE_INFINITY // for even n < 0
-0.0 ** n = POSITIVE_INFINITY // for even n < 0
0.0 ** n = 0.0 // for even n > 0
-0.0 ** n = 0.0 // for even n > 0
0.0 ** n = 0.0 // for odd n > 0
-0.0 ** n = -0.0 // for odd n > 0
POSITIVE_INFINITY ** n = POSITIVE_INFINITY // for n > 0
NEGATIVE_INFINITY ** n = NEGATIVE_INFINITY // for odd n > 0
NEGATIVE_INFINITY ** n = POSITIVE_INFINITY // for even n > 0
POSITIVE_INFINITY ** n = 0.0 // for n < 0
NEGATIVE_INFINITY ** n = -0.0 // for odd n < 0
NEGATIVE_INFINITY ** n = 0.0 // for even n < 0.
Note: In addition to the preceding special cases, when the value of the left operand is
NaN, the value of the exponentiation expression is equal toNaNregardless of the value of the right operand.
When the left operand type is Float64 and the right operand type is Float64, the value of the exponentiation expression needs to be specified in some special cases as follows:
x ** 0.0 = 1.0 // for any x
x ** -0.0 = 1.0 // for any x
0.0 ** y = POSITIVE_INFINITY // for the value of y is equal to an odd integer < 0
-0.0 ** y = NEGATIVE_INFINITY // for the value of y is equal to an odd integer < 0
0.0 ** NEGATIVE_INFINITY = POSITIVE_INFINITY
-0.0 ** NEGATIVE_INFINITY = POSITIVE_INFINITY
0.0 ** POSITIVE_INFINITY = 0.0
-0.0 ** POSITIVE_INFINITY = 0.0
0.0 ** y = 0.0 // for finite y > 0.0 and its value is equal to an odd integer
-0.0 ** y = -0.0 // for finite y > 0.0 and its value is equal to an odd integer
-1.0 ** POSITIVE_INFINITY = 1.0
-1.0 ** NEGATIVE_INFINITY = 1.0
1.0 ** y = 1.0 // for any y
x ** POSITIVE_INFINITY = 0.0 // for -1.0 < x < 1.0
x ** POSITIVE_INFINITY = POSITIVE_INFINITY // for any x < -1.0 or for any x > 1.0
x ** NEGATIVE_INFINITY = POSITIVE_INFINITY // for -1.0 < x < 1.0
x ** NEGATIVE_INFINITY = 0.0 // for any x < -1.0 or for any x > 1.0
POSITIVE_INFINITY ** y = 0.0 // for y < 0.0
POSITIVE_INFINITY ** y = POSITIVE_INFINITY // for y > 0.0
NEGATIVE_INFINITY ** y = -0.0 // for finite y < 0.0 and its value is equal to an odd integer
NEGATIVE_INFINITY ** y = NEGATIVE_INFINITY // for finite y > 0.0 and its value is equal to an odd integer
NEGATIVE_INFINITY ** y = 0.0 // for finite y < 0.0 and its value is not equal to an odd integer
NEGATIVE_INFINITY ** y = POSITIVE_INFINITY // for finite y > 0.0 and its value is not equal to an odd integer
0.0 ** y = POSITIVE_INFINITY // for finite y < 0.0 and its value is not equal to an odd integer
-0.0 ** y = POSITIVE_INFINITY // for finite y < 0.0 and its value is not equal to an odd integer
0.0 ** y = 0.0 // for finite y > 0.0 and its value is not equal to an odd integer
-0.0 ** y = 0.0 // for finite y > 0.0 and its value is not equal to an odd integer
x ** y = NaN // for finite x < 0.0 and finite y whose value is not equal to an integer
Note: In addition to the special cases listed above, if the value of an operand is
NaN, the value of the exponentiation expression is equal toNaN.
If the result of an arithmetic expression is of the integer type, integer overflow may occur. Cangjie provides three attribute macros and compilation options to control the processing behavior of integer overflow (hereinafter referred to as behavior). They are shown in the following table.
| attributes | Options | behavior | explaining for behavior |
|---|---|---|---|
| @OverflowThrowing | --int-overflow throwing | throwing | throwing an exception |
| @OverflowWrapping | --int-overflow wrapping | wrapping | wrapping around at the numeric bounds of the type |
| @OverflowSaturating | --int-overflow saturating | saturating | saturating at the numeric bounds of the type |
Note: 1. The default behavior is throwing. 2. If an attribute macro and a compilation option are used in a range at the same time and represent different behaviors, the behavior represented by the attribute macro prevails.
Behavior example:
@OverflowThrowing
func test1(x: Int8, y: Int8) { // if x equals to 127 and y equals to 3
let z = x + y // throwing OverflowException
}
@OverflowWrapping
func test2(x: Int8, y: Int8) { // if x equals to 127 and y equals to 3
let z = x + y // z equals to -126
}
@OverflowSaturating
func test3(x: Int8, y: Int8) { // if x equals to 127 and y equals to 3
let z = x + y // z equals to 127
}
The following is an example of the conflict between the scope of an attribute macro and that of a compilation option:
// Compile with cjc --int-overflow saturating test.cj
// this file's name is test.cj
@OverflowWrapping
func test2(x: Int8, y: Int8) {
let z = x + y // the behavior is wrapping
}
func test3(x: Int8, y: Int8) {
let z = x + y // the behavior is saturating
}
In particular, for INT_MIN * -1, INT_MIN / -1, and INT_MIN % -1, the specified behaviors are as follows:
| Expression | Throwing | Wrapping | Saturating |
|---|---|---|---|
| INT_MIN * -1 or -1 * INT_MIN | throwing OverflowException | INT_MIN | INT_MAX |
| INT_MIN / -1 | throwing OverflowException | INT_MIN | INT_MAX |
| INT_MIN % -1 | 0 | 0 | 0 |
Note that in the scenario where the integer overflow behavior is throwing, if the integer overflow can be detected in advance in the compilation phase, the compiler directly reports an error.
Relational Expressions
A relational expression is an expression that contains relational operators. There are six relational operators: equality (==), inequality (!=), less than (<), greater than (<=), less than or equal to (>), and greater than or equal to (>=). Relational operators are binary operators, and the types of the two operands must be the same. A relational expression is of the Bool type. That is, its value can only be true or false. Precedence and associativity of relational operators are described below.
The syntax of relational expressions is defined as follows:
equalityComparisonExpression
: comparisonOrTypeExpression (equalityOperator comparisonOrTypeExpression)?
;
comparisonOrTypeExpression
: shiftingExpression (comparisonOperator shiftingExpression)?
| ...
;
equalityOperator
: '!=' | '=='
;
comparisonOperator
: '<' | '>' | '<=' | '>='
;
The following examples are relational expressions:
main(): Int64 {
3 < 4 // return true
3 <= 3 // return true
3 > 4 // return false
3 >= 3 // return true
3.14 == 3.15 // return false
3.14 != 3.15 // return true
return 0
}
It should be noted that a relational operator is non-associative, that is, an expression similar to a < b < c cannot be written.
main(): Int64 {
3 < 4 < 5 // error: `<` is non-associative
3 == 3 != 4 // error: `==` and `!=` are non-associative
return 0
}
type test and type cast Expressions
A type test expression is an expression that contains the operator is, and a type cast expression is an expression that contains the operator as. The precedence and associativity of is and as are described below.
The syntax of type test and type cast expressions is defined as follows:
comparisonOrTypeExpression
: ...
| shiftingExpression ('is' type)?
| shiftingExpression ('as' userType)?
;
is Operators
e is T is an expression used for type checking. The type of e is T is Bool. e can be any type of expression, and T can be any type.
When the runtime type R of e is a subtype of T, the value of e is T is true; otherwise, the value is false.
The following are examples of is operators:
open class Base {
var name: String = "Alice"
}
class Derived1 <: Base {
var age: UInt8 = 18
}
class Derived2 <: Base {
var gender: String = "female"
}
main(): Int64 {
var testVT = 1 is Int64 // testVT = true
testVT = 1 is String // testVT = false
testVT = true is Int64 // testVT = false
testVT = [1, 2, 3] is Array<Int64> // testVT = true
let base1: Base = Base()
let base2: Base = Derived1()
let base3: Base = Derived2()
let derived1: Derived1 = Derived1()
let derived2: Derived2 = Derived2()
var test = base1 is Base // test = true
test = base1 is Derived1 // test = false
test = base1 is Derived2 // test = false
test = base2 is Base // test = true
test = base2 is Derived1 // test = true
test = base2 is Derived2 // test = false
test = base3 is Base // test = true
test = base3 is Derived1 // test = false
test = base3 is Derived2 // test = true
test = derived1 is Base // test = true
test = derived1 is Derived1 // test = true
test = derived1 is Derived2 // test = false
test = derived2 is Base // test = true
test = derived2 is Derived1 // test = false
test = derived2 is Derived2 // test = true
return 0
}
as Operators
e as T is an expression used for type conversion. The type of e as T is Option<T>. e can be any type of expression, and T can be any specific type.
When the runtime type R of e is a subtype of T, the value of e as T is Some(e); otherwise, the value is None.
The following are examples of as operators:
open class Base {
var name: String = "Alice"
}
class Derived1 <: Base {
var age: UInt8 = 18
}
class Derived2 <: Base {
var gender: String = "female"
}
main(): Int64 {
let base1: Base = Base()
let base2: Base = Derived1()
let base3: Base = Derived2()
let derived1: Derived1 = Derived1()
let derived2: Derived2 = Derived2()
let castOP1 = base1 as Base // castOP = Option<Base>.Some(base1)
let castOP2 = base1 as Derived1 // castOP = Option<Derived1>.None
let castOP3 = base1 as Derived2 // castOP = Option<Derived2>.None
let castOP4 = base2 as Base // castOP = Option<Base>.Some(base2)
let castOP5 = base2 as Derived1 // castOP = Option<Derived1>.Some(base2)
let castOP6 = base2 as Derived2 // castOP = Option<Derived2>.None
let castOP7 = base3 as Base // castOP = Option<Base>.Some(base3)
let castOP8 = base3 as Derived1 // castOP = Option<Derived1>.None
let castOP9 = base3 as Derived2 // castOP = Option<Derived2>.Some(base3)
let castOP10 = derived1 as Base // castOP = Option<Base>.Some(derived1)
let castOP11 = derived1 as Derived1 // castOP = Option<Derived1>.Some(derived1)
let castOP12 = derived1 as Derived2 // castOP = Option<Derived2>.None
let castOP13 = derived2 as Base // castOP = Option<Base>.Some(derived2)
let castOP14 = derived2 as Derived1 // castOP = Option<Derived1>.None
let castOP15 = derived2 as Derived2 // castOP = Option<Derived2>.Some(derived2)
return 0
}
Bitwise Operation Expression
A bitwise expression is an expression that contains bitwise operators. Cangjie supports one unary prefix bitwise operation operator bitwise NOT (!) and five binary infix bitwise operation operators, including left shift (<<), right shift (>>), bitwise AND (&), and bitwise XOR (^), and bitwise OR (|). The operands of bitwise operators must be of the integer type. The operands are considered as binary sequences, and then logical operations (0 is considered as false and 1 is considered as true) or shift operations are performed on each bit to implement bitwise operations. In operations with &, ^, and |, logical operations are performed between bits (For details, see [Logical Expressions]). The precedence and associativity of bitwise operators are described below.
The syntax of bitwise operation expressions is defined as follows:
prefixUnaryExpression
: prefixUnaryOperator* incAndDecExpression
;
prefixUnaryOperator
: '!'
| ...
;
bitwiseDisjunctionExpression
: bitwiseXorExpression ( '|' bitwiseXorExpression)*
;
bitwiseXorExpression
: bitwiseConjunctionExpression ( '^' bitwiseConjunctionExpression)*
;
bitwiseConjunctionExpression
: equalityComparisonExpression ( '&' equalityComparisonExpression)*
;
shiftingExpression
: additiveExpression (shiftingOperator additiveExpression)*
;
shiftingOperator
: '<<' | '>>'
;
The following are example of bitwise operation expressions:
func foo(): Unit {
!10 // The result is -11
!20 // The result is -21
10 << 1 // The result is 20
10 << 1 << 1 // The result is 40
10 >> 1 // The result is 5
10 & 15 // The result is 10
10 ^ 15 // The result is 5
10 | 15 // The result is 15
1 ^ 8 & 15 | 24 // The result is 25
}
For a shift operator, its operand must be of the integer type (but the types of the two operands can be different). Regardless of whether the operator is left or right shift, the right operand cannot be a negative number. (If such an error is detected during compilation, an error is reported. If this error occurs during running, an exception is thrown.)
For a shift operation of an unsigned number, the shift and padding rules are as follows: left shift pads 0s for low bits and discards high bits, and right shift pads 0s for high bits and discards low bits. For a shift operation of a signed number, the shift and padding rules are as follows:
- The shift padding rules for positive numbers and unsigned numbers are the same.
- If negative numbers are shifted left, 0s are padded to the low bits and high bits are discarded.
- If negative numbers are shifted right, 1s are padded to the high bits and low bits are discarded.
let p: Int8 = -30
let q = p << 2 // q = -120
let r = p >> 2 // r = -8
let r = p >> -2 // error
let x: UInt8 = 30
let b = x << 3 // b = 240
let b = x >> 1 // b = 15
In addition, if the number of bits (right operand) shifted right or left is greater than or equal to the operand width, this is an overshift. If the overshift can be detected during compilation, an error is reported. Otherwise, an exception is thrown during running.
let x1 : UInt8 = 30 // 0b00011110
let y1 = x1 >> 11 // compilation error
Range Expressions
A range expression is an expression that contains interval operators. A range expression is used to create Range instances. The syntax of range expressions is defined as follows:
rangeExpression
: bitwiseDisjunctionExpression ('..=' | '..') bitwiseDisjunctionExpression (':' bitwiseDisjunctionExpression)?
| bitwiseDisjunctionExpression
;
There are two types of range operators: .. and ..=, which are used to create "left-closed and right-open" and "left-closed and right-closed" Range instances respectively. For details, see [Range].
Logical Expressions
A logical expression is an expression that contains logical operators. The operand of a logical operator must be an expression of the Bool type. Cangjie supports three logical operators: logical NOT (!), logical AND (&&), and logical OR (||). Their precedence and associativity are described below.
The syntax of logical expressions is defined as follows:
prefixUnaryExpression
: prefixUnaryOperator* incAndDecExpression
;
prefixUnaryOperator
: '!'
| ...
;
logicDisjunctionExpression
: logicConjunctionExpression ( '||' logicConjunctionExpression)*
;
logicConjunctionExpression
: rangeExpression ( '&&' rangeExpression)*
;
The logical NOT (!) is a unary operator, which is used to negate the Boolean value of its operand: The value of !false is true. The value !true is false.
The logical AND (&&) and logical OR (||) are binary operators. For the expression expr1 && expr2, its value is equal to true only when the values of expr1 and expr2 are equal to true. For the expression expr1 || expr2, its value is equal to false only when the values of expr1 and expr2 are equal to false.
Short-circuit evaluation is used for && and ||. When expr1 && expr2 is calculated, expr2 does not need to be evaluated if expr1=false, and the value of the entire expression is false. When expr1 || expr2 is calculated, expr2 does not need to be evaluated if expr1=true, and the value of the entire expression is true.
main(): Int64 {
let expr1 = false
let expr2 = true
!true // Logical NOT, return false.
1 > 2 && expr1 // Logical AND, return false without computing the value of expr1.
1 < 2 || expr2 // Logical OR, return true without computing the value of expr2.
return 0
}
coalescing Expressions
The coalescing expression is an expression that contains coalescing operators. The coalescing operator is a binary infix operator represented by ??. Its precedence and associativity are described below.
The syntax of coalescing expressions is defined as follows:
coalescingExpression
: logicDisjunctionExpression ('??' logicDisjunctionExpression)*
;
The coalescing operator is used to deconstruct the Option type. Assume that the type of the expression e1 is Option<T>. For the expression e1 ?? e2:
-
The expression
e2has the typeT. -
The expression
e1 ?? e2has the typeT. -
When the value of
e1is equal toOption<T>.Some(v), the value ofe1 ?? e2is equal tov(in this case,e2is not evaluated, that is, the short-circuit evaluation condition is met). When the value ofe1is equal toOption<T>.None, the value ofe1 ?? e2is equal toe2.
The expression e1 ?? e2 is the syntactic sugar of the following match expression:
// when e1 is Option<T>
match (e1) {
case Some(v) => v
case None => e2
}
The following are examples of using the coalescing expressions:
main(): Int64 {
let v1 = Option<Int64>.Some(100)
let v2 = Option<Int64>.None
let r1 = v1 ?? 0
let r2 = v2 ?? 0
print("${r1}") // output: 100
print("${r2}") // output: 0
return 0
}
Flow Expressions
A flow expression is an expression that contains flow operators. There are two types of flow operators: |> infix operator (called pipeline) that represents the data flow direction and ~> infix operator (called composition) that represents a combination of functions. The precedence of |> is the same as that of ~>, and is between || and =. |> and ~> are both left-associative. For details, see the following information. The syntax of flow expressions is defined as follows:
flowExpression
: logicDisjunctionExpression (flowOperator logicDisjunctionExpression)*
;
flowOperator
: '|>' | '~>'
;
pipeline Operators
The pipeline expression is the syntactic sugar of a single-parameter function call. For example, e1 |> e2 is the syntactic sugar of let v = e1; e2(v) (that is, e1 on the left of the |> operator is evaluated first). e2 is an expression of the function type, and the type of e1 is a subtype of the parameter type of e2. Alternatively, the type of e2 overloads the function call operator () (see [Operators That Can Be Overloaded]).
Note: The f cannot be an init or super constructor.
func f(x: Int32): Int32 { x + 1 }
let a: Int32 = 1
var res = a |> f // ok
var res1 = a |> {x: Int32 => x + 1} // ok
func h(b: Bool) { b }
let res3 = a < 0 || a > 10 |> h // Equivalence: (a < 0 || a > 10) |> h
func g<T>(x: T): T { x }
var res4 = a |> g<Int32> // ok
class A {
let a: Int32
let b: Int32
init(x: Int32) {
a = x
b = 0
}
init(x: Int32, y: Int32) {
x |> init // error: `init` is not a valid expression
b = y
}
}
// PIPELINE with operator `()` overloading
class A {
operator func ()(x: Int32) {
x
}
}
let obj = A()
let a: Int32 = 1
let res = a |> obj // Equivalence: obj(a)
composition Operators
A composition expression indicates a combination of two single-parameter functions. For example, the composition expression e1 ~> e2 is the syntactic sugar of let f = e1; let g = e2; {x = > g(f(x))} (that is, e1 on the left of the ~> operator is evaluated first). If f and g are expressions of the function type or their type overloads the function call operator () (see [Operators That Can Be Overridden]) of a single parameter, the following four situations may occur:
e1 ~> e2 | The lambda expression |
|---|---|
e1 and e2 are function types, and the return value type of e1 is a subtype of the argument type of e2 | let f = e1; let g = e2; {x => g(f(x))} |
The type f implements the single-parameter operator () overloading function, and g is a function type, and the return value type of f.operator() is a subtype of the argument type of g | let f = e1; let g = e2; {x => g(f.operator()(x))} |
f is a function type, and the type of g implements the the single-parameter operator () overloading function, and the return value type of f is a subtype of the argument type of g.operator(). | let f = e1; let g = e2; {x => g.operator()(f(x))} |
The types of f and g both implement the single-parameter operator () overloading function, and the return value type of f.operator() is a subtype of the argument type of g.operator() | let f = e1; let g = e2; {x => g.operator()(f.operator()(x))} |
Note: The evaluated values of e1 and e2 cannot be init or super.
func f(x: Int32): Float32 { Float32(x) }
func g(x: Float32): Int32 { Int32(x) }
var fg = f ~> g // Equivalence: {x: Int32 => g(f(x))}
let lambdaComp = {x: Int32 => x} ~> f // ok
func h1<T>(x: T): T { x }
func h2<T>(x: T): T { x }
var hh = h1<Int32> ~> h2<Int32> // ok
// COMPOSITION with operator `()` overloading
class A {
operator func ()(x: Int32): Int32 {
x
}
}
class B {
operator func ()(x: Float32): Float32 {
x
}
}
let objA = A()
let objB = B()
let af = objA ~> f // ok
let fb = f ~> objB // ok
let aa = objA ~> objA // ok
Assignment Expressions
An assignment expression is an expression that contains assignment operators. It is used to change the value of a left operand to the value of a right operand. The type of the right operand must be a subtype of the type of the left operand. When an assignment expression is evaluated, the expression on the right of = is evaluated first, and then the expression on the left of = is evaluated.
When a compound assignment expression is used, the left value of the expression on the left of = is calculated first, and then the right value is obtained based on the left value. Then, the right value is used to calculate the expression on the right of = (if there is a short-circuit rule, the rule is followed). Finally, a value is assigned.
Except for the value that can be assigned as defined by the subtype, if the right operand is a string literal that contains only a single character and the type of the left operand is Byte or Rune, the type of the string value is forcibly converted to Byte or Rune and assigned to the left operand. If the type conversion fails, the compiler reports an error.
Assignment operators are classified into ordinary assignment operators and compound assignment operators. The syntax of assignment expressions is defined as follows:
assignmentExpression
: leftValueExpressionWithoutWildCard assignmentOperator flowExpression
| leftValueExpression '=' flowExpression
| tupleLeftValueExpression `=` flowExpression
| flowExpression
;
tupleLeftValueExpression
: `(` (leftValueExpression | tupleLeftValueExpression) (`,` (leftValueExpression | tupleLeftValueExpression))+ `,`? `)`
;
leftValueExpression
: leftValueExpressionWithoutWildCard
| '_'
;
leftValueExpressionWithoutWildCard
: identifier
| leftAuxExpression '?'? assignableSuffix
;
leftAuxExpression
: identifier typeArguments?
| type
| thisSuperExpression
| leftAuxExpression ('?')? '.' identifier typeArguments?
| leftAuxExpression ('?')? callSuffix
| leftAuxExpression ('?')? indexAccess
;
assignableSuffix
: fieldAccess
| indexAccess
;
fieldAccess
: '.' identifier
;
assignmentOperator
: '=' | '+=' | '-=' | '**=' | '*=' | '/=' | '%=' | '&&=' | '||='
| '&=' | '|=' | '^=' | '<<=' | '>>='
;
The expression that appears on the left of a (compound) assignment operator is called a lvalue expression (leftValueExpression in the preceding definition).
Syntax: The lvalue expression can be an identifier, _, or leftAuxExpression followed by a assignableSuffix (including fieldAccess and indexAccess). There can be optional ? operators (syntactic sugar for assigning values to instances of Option Type) between leftAuxExpression and assignableSuffix. The leftAuxExpression may be in the following syntax form: 1. an identifier that includes an optional type of argument (typeArguments); 2. this or super; 3. a leftAuxExpression is followed by a . (there can be optional ? operators between them) and an identifier with optional type arguments; 4. a leftAuxExpression is followed by a function call postfix callSuffix or an index access postfix indexAccess (there can be optional ? operators before callSuffix or indexAccess).
The semantics of lvalue expression can only be one of the following:
-
Variables indicated by
identifier(see [Variable Names and Function Names]). -
The wildcard _ indicates that the evaluation result of the expression on the right of = is ignored. (Wildcards are not allowed in compound assignment expressions.)
-
Member access expression
e1.aore2?.a(see [Member Access Expressions]) -
Index access expression
e1[a]ore2?[a](see [Index Access Expressions])
Note:
e1ande2must be expressions that comply with theleftAuxExpressionsyntax.
Left value expression is valid only when Left value expression is mutable. For details about the variability of the preceding expressions, see the corresponding chapters.
The type of assignment expressions is Unit, and the value is (). In this way, problems such as incorrectly using an assignment expression as a judgment expression can be avoided. In the following example, if (a = b) is executed first, the return value is (). However, () cannot be displayed on the left of =. Therefore, an error is reported when ()=0 is executed. Similarly, the expression following if must be of the Bool type. Therefore, an error is also reported for the if expression in the following example. In addition, = is non-associative. Therefore, an expression such as a = b = 0 that contains more than two ='s cannot pass the syntax check.
main(): Int64 {
var a = 1
var b = 1
a = (b = 0) // semantics error
if (a = 5) { // semantics error
}
a = b = 0 // syntax error
return 0
}
The compound assignment expression a op = b cannot be simply regarded as a = a op b, a combination of an assignment expression and other binary operators (op can be any binary operator among arithmetic operators, logical operators, and bitwise operators, and the types of operands a and b are the types required by the operator op). In Cangjie, a in a op = b is evaluated only once (the side effect occurs only once), and a in a = a op b is evaluated twice (the side effect occurs twice). A compound assignment expression is also an assignment expression, so compound assignment operators are also non-associative. A compound assignment expression also requires that the two operands be of the same type.
The following examples describe how to use compound assignment expressions:
a **= b
a *= b
a /= b
a %= b
a += b
a -= b
a <<= b
a >>= b
a &&= b
a ||= b
a &= b
a ^= b
a |= b
Finally, if you overload the **, *, /, %, +, -, <<, >>, &, ^, or | operator, Cangjie provides the default implementation of the corresponding compound assignment operator **=, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, or |=. However, some additional requirements should be met. Otherwise, the value assignment semantics cannot be provided for a = a op b.
-
The return type of an overloaded operator must be the same as the type of a left operand or its subtype. That is,
a,b, andopina op = bmust pass the type check ofa = a op b. For example, when there is a subtype relationshipA <: B <: C, if a type of+overloaded by the user is(B, Int64) -> Bor(B, Int64) -> A, Cangjie can provide a default implementation. If a type of+overloaded by the user is(B, Int64) -> C, Cangjie does not provide a default implementation. -
The value of
aina op= bmust be assignable, for example, a variable.
A multiple assignment expression is a special assignment expression. In such expression, there must be a tuple on the left and right of the equal sign (=) respectively. All elements in the left tuple must be left values, and the type of each element in the right tuple must be the subtype of the lvalue type in the corresponding position. Note: If _ is displayed in the tuple on the left, the evaluation result at the position corresponding to the tuple on the right of the equal sign is ignored (that is, the type check at this position can always be passed).
The multiple assignment expression can assign the value of the right tuple type to the corresponding left value in the left tuple at a time, so that code for assigning values one by one is not needed.
main(): Int64 {
var a: Int64
var b: Int64
(a, b) = (1, 2) // a == 1, b == 2
(a, b) = (b, a) // swap, a == 2, b == 1
(a, _) = (3, 4) // a == 3
(_, _) = (5, 6) // no assignment
return 0
}
A multiple assignment expression can be considered as a syntactic sugar in the following form: The expression on the right of the assignment expression is evaluated first, and then the left value is assigned one by one from left to right.
main(): Int64 {
var a: Int64
var b: Int64
(a, b) = (1, 2)
// desugar
let temp = (1, 2)
a = temp[0]
b = temp[1]
return 0
}
Lambda Expressions
A Lambda expression is a value of the function type. For details, see [Functions].
Quote Expressions
Quote expressions are used to reference code and represent it as operable data objects. They are mainly used for metaprogramming. For details, see [Metaprogramming].
Macro Call Expressions
Macro call expressions call macros defined by Cangjie and are mainly used for metaprogramming. For details, see [Metaprogramming].
Reference Value Transfer Expressions
Reference value transfer expressions can be used only when CFunc is called during C interoperability. For details, see the description of the inout parameter in [Cross-Language Interoperability].
Precedence and Associativity of Operators
For an expression that contains two or more operators, its value is determined by the grouping and combination mode of the operators and operands. The grouping and combination mode depends on the precedence and associativity of the operators. To put it simply, the precedence specifies the evaluation sequence of different operators, and the associativity specifies the evaluation sequence of operators with the same precedence.
If an expression contains multiple operators with different precedence, its subexpressions with the operators of higher precedence is evaluated first, followed by those of lower precedence. If a subexpression contains multiple operators of the same precedence, the sequence depends on the associativity of the operators.
The following table lists the precedence, associativity, feature description, usage, and expression type of each operator. The closer to the top of the table, the higher the precedence of the operator.
| Operator | Associativity | Description | Usage | Expression type |
|---|---|---|---|---|
@ | Right associative | macro call expression | @expr1 @expr2 | Unit |
. | Left associative | Member access | Name.name | The type of name |
[] | Index access | varName[expr] | The type of the element of varName | |
() | Function call | funcName(expr) | Return type of funcName | |
++ | None | Postfix increment | varName++ | Unit |
-- | Postfix decrement | varName-- | Unit | |
? | Question mark | expr1?.expr2 etc. | Option<T> (T is the type of expr2) | |
! | Right associative | Bitwise Logic NOT | !expr | The type of expr |
- | Unary negative | -expr | ||
** | Right associative | Power | expr1 ** expr2 | The type of expr1 |
* | Left associative | Multiply | expr1 * expr2 | The type of expr1 or expr2, since expr1 and expr2 have the same type |
/ | Divide | expr1 / expr2 | ||
% | Remainder | expr1 % expr2 | ||
+ | Left associative | Add | expr1 + expr2 | The type of expr1 or expr2, since expr1 and expr2 have the same type |
- | Subtract | expr1 - expr2 | ||
<< | Left associative | Bitwise left shift | expr1 << expr2 | The type of expr1, where expr1 and expr2 can have different types |
>> | Bitwise right shift | expr1 >> expr2 | ||
.. | None | Range operator | expr1..expr2:expr3 | Range type |
..= | expr1..=expr2:expr3 | |||
< | None | Less than | expr1 < expr2 | Except the type of 'expr as userType' is Option<userType>, other expressions have Bool type |
<= | Less than or equal | expr1 <= expr2 | ||
> | Greater than | expr1 > expr2 | ||
>= | Greater than or equal | expr1 >= expr2 | ||
is | Type check | expr is type | ||
as | Type cast | expr as userType | ||
== | None | Equal | expr1 == expr2 | Bool |
!= | Not equal | expr1 != expr2 | ||
& | Left associative | Bitwise AND | expr1 & expr2 | The type of expr1 or expr2, since expr1 and expr2 have the same type |
^ | Left associative | Bitwise XOR | expr1 ^ expr2 | The type of expr1 or expr2, since expr1 and expr2 have the same type |
| ` | ` | Left associative | Bitwise OR | `expr1 |
&& | Left associative | Logic AND | expr1 && expr2 | Bool |
| ` | ` | Left associative | Logic OR | |
?? | Right associative | coalescing | expr1 ?? expr2 | The type of expr2 |
| ` | >` | Left associative | Pipeline | `expr1 |
~> | Composition | expr1 ~> expr2 | The type of expr1 ~> expr2 is the type of the lambda expression {x=>expr2(expr1(x))} | |
= | None | Assignment | leftValue = expr | Unit |
**= | Compound assignment | leftValue **= expr | ||
*= | leftValue *= expr | |||
/= | leftValue /= expr | |||
%= | leftValue %= expr | |||
+= | leftValue += expr | |||
-= | leftValue -= expr | |||
<<= | leftValue <<= expr | |||
>>= | leftValue >>= expr | |||
&= | leftValue &= expr | |||
^= | leftValue ^= expr | |||
| ` | =` | `leftValue | ||
&&= | leftValue &&= expr | |||
| ` | =` |
Note: When
?is used together with.,(),{}, or[], it indicates a syntactic suger and evaluation does not strictly follow their inherent precedence and associativity. For details, see [Question Mark Operators].
Evaluation Sequence of Expressions
The evaluation sequence of expressions specifies the sequence in which the values of operands are calculated. Obviously, only expressions containing binary operators have the concept of evaluation sequence. The default evaluation sequence of Cangjie is as follows:
-
For an expression that contains logical AND (
&&), logical OR (||), andcoalescing(??), the right operand of an operator is evaluated only when it affects the value of the entire expression. Otherwise, only the left operand is evaluated. Therefore, the evaluation sequence of&&,||, and??is as follows: The left operands are evaluated first, followed by the right operands. -
For an optional chaining expression, the
?operators separate it into several subitems and the subitems are evaluated from left to right in sequence (based on the evaluation sequence of the used operators). -
Other expressions (such as arithmetic expressions, relational expressions, and bitwise expressions) are also evaluated from left to right.
Functions
A function is an independent code snippet that completes a specific task. It can be identified by a function name, which can be used for calling a function. In Cangjie, functions are first-class citizens. Functions support variable assignment, and can be used as parameters or return values.
Function Definition
In Cangjie, function definition must comply with the following syntax rules:
functionDefinition
: functionModifierList? 'func'
identifier
typeParameters?
functionParameters
(':' type)?
(genericConstraints)?
block
;
The summary is as follows:
- The keyword
funcis used to define a function. funccan be preceded by a function modifier.funcmust be followed by the function name.- The optional type parameter list is enclosed by
<>. Multiple type parameters are separated by,. - The function parameters are enclosed by
(). Multiple parameters are separated by,. The parameter type of each parameter must be specified. For details, see [Parameters]. - The default function return type is specified by
:type. - When a function is defined, a function body, which is a block (excluding function parameters), must be specified.
The following example shows all elements of a complete function definition. The access modifier public is not used, indicating that the function can be accessed in the package. The function is named foo, has a parameter a of the Int64 type, a return type Int64, and a function body.
func foo(a: Int64): Int64 { a }
A function name cannot be assigned a value. That is, the function name cannot appear in the program as the lvalue of an expression.
The operation in the following example is forbidden.
func f(a: Int64): Int64 { a }
// f = {a: Int64 => a + 1} // compile-time error
Function Modifiers
Modifier of Global Function
Global functions can be modified by all access modifiers. The default accessibility is internal. For details, see Access Modifiers in [Packages and Modules].
Modifiers of Local Functions
No modifier is available for the local function.
Modifiers of Member Functions
The modifiers of class member functions include public, protected, private, internal, static, open, override, and redef. For details, see [Members of a Class] and Access Modifiers in [Packages and Modules].
The modifiers of interface member functions include static and mut. For details, see [Interface Members].
The modifiers of struct member functions include mut, public, private, internal, and static. For details, see [Struct Type].
The modifiers of enum member functions include public, private, internal, and static. For details, see [Enum Type].
If no access modifier is provided, member functions other than interface member functions can be accessed in the current package and subpackages. Interface member functions contain the semantics of public by default.
Parameters
When a function is defined, the sequence of parameters in the parameter list is non-named parameters followed by named parameters (including named parameters with and without default values). The syntax of the parameter list is defined as follows:
functionParameters
: ('(' (unnamedParameterList (',' namedParameterList)? )? ')')
| ('(' (namedParameterList)? ')')
;
nondefaultParameterList
: unnamedParameter (',' unnamedParameter)* (',' namedParameter)*
| namedParameter (',' namedParameter)*
;
namedParameterList
: (namedParameter | defaultParameter) (',' (namedParameter | defaultParameter))*
;
namedParameter
: identifier '!' ':' type
;
defaultParameter
: identifier '!' ':' type '=' expression
;
unnamedParameterList
: unnamedParameter (',' unnamedParameter)*
;
unnamedParameter
: (identifier | '_') ':' type
;
For non-named parameters, you can use a _ to replace the parameters that are not used in a function body.
func bar(a: Int64 , b!: Float64 = 1.0, s!: String) {} // OK
func bar2(a: Int64 = 1, b!: Float64 = 1.0, s: String = "Hello") {} // Error
func foo(a: Int64, b: Float64)(s: String = "Hello") {} // Error
func f1(a: Int64, _: Int64): Int64 {
return a + 1
}
func f2(_: String): Unit {
print("Hello Cangjie")
}
All function parameters are immutable variables, that is, they are modified by let and cannot be assigned values in a function definition.
func foo(a: Int64, b: Float64) {
a = 1 // Error: the parameter 'a' is immutable, and cannot be assigned.
b = 1.0 // Error: the parameter 'b' is immutable, and cannot be assigned.
}
The parameter type of a function is not affected by whether the parameter is a named parameter or whether the parameter has a default value. In addition, when the parameter type is discussed, a type and its alias are considered to be the same type.
Naming Parameters
When defining a function, add ! to the end of a parameter name to define a named parameter.
namedParameter
: identifier '!' ':' type
;
- During function definition, non-named parameters are not allowed after named parameters.
func add1(a: Int32, b!: Int32): Int32 { a + b } // ok
func add2(a!: Int32, b: Int32): Int32 { a + b } // error
- When a parameter is defined as a named parameter and this function is called, you must use the
parameter name:prefix before the argument value to specify the parameter corresponding to the argument. Otherwise, a compilation error is reported.
func add(a: Int32, b!: Int32): Int32 { a + b }
add(1, b: 2) // ok
add(1, 2) // error
-
If an abstract function or a function modified by
openhas a named parameter, the implementation function or the function modified byoverridemust retain the same named parameter.open class A { public open func f(a!: Int32): Int32 { return a + 1 } } class B <: A { public override func f(a!: Int32): Int32 { // ok return a + 1 } } class C <: A { public override func f(b!: Int32): Int32 { // error return b + 1 } }
Default Values of Parameters
Function parameters can have default values. You can use = to define default values for parameters. After the default value is defined for a parameter, it can be ignored when that function is called. The function body uses the default value. For better understanding, parameters with default values are called optional parameters.
When a function is defined, an optional parameter is a named parameter. The ! must be added to the end of the optional parameter name. Otherwise, an error is reported during compilation.
defaultParameter
: identifier '!' ':' type '=' expression
;
In the following example, an add function is defined, and its parameter type list is (Int32, Int32). When the function is defined, b has the default value 1. Therefore, when the add function is called and only the value 3 is passed, 3 is assigned to a, and the result 4 is returned.
If 3 and 2 are passed, the value of b is 2.
func add(a: Int32, b!: Int32 = 1): Int32 { a + b }
add(3) // invoke add(3, 1), return 4
add(3, b: 2) // return 5
-
Functions that are modified by the
openkeyword in a class or interface cannot have optional parameters. -
The operator function cannot contain optional parameters.
-
Anonymous functions (lambda expressions) do not allow optional parameters.
-
The name introduced in the default value of a function parameter is obtained from the static scope. That is, the introduced name is a name that can be accessed when the function is defined.
-
The name introduced in the default value of a function parameter can be accessed when the function is defined, and does not need to be consistent with the accessibility of the function itself.
-
The function parameter and its default value do not belong to the function body.
-
The default value of a parameter is evaluated when the function is called, not when the function is defined.
-
When a function is called, parameters are evaluated from left to right based on the definition sequence. The default value of a function parameter can reference the parameters defined before it.
-
When a function is called using its function name, the default value can be used. When a function is called using its variable name, the default value cannot be used.
// Compile-time error. // func f(a: Int32, b!: Int32 = 2, c: Int32): Int32 { ... } // OK. func f1(a: Int32, b: Int32, c!: Int32 = 3, d!: Int32 = 4): Int32 { a + b + c + d } func test() { f1(1, 2) // 10, f1(1, 2, 3, 4) f1(1, 2, c: 5) // 12, f1(1, 2, 5, 4) }/* The names introduced in the default value, does not need to have the same or least restrictive accessibility of the function. */ var x = 10 var y = 10 func g() {} public func f2(a!: Int64 = x * 2 + y, b!: ()->Unit = g) {} // OK. class AAA { static private var x = 10 func f(a!: Int64 = x) { // OK, public method can use private static field. print("${a}") x = x + 10 print("${x}") } }/* When a function is called, the name in the function declaration can use the default value. When a function is called by using a variable name, arguments cannot be optional. */ func f1(): (Int64) -> Unit { g1 } func g1(a!: Int64 = 42) { print("g1: ${a}") } let gg1 = f1() let x = gg1() // Error, cannot ommit the argument. let gg3 = g1 let a = gg3() // Error, cannot ommit the argument.
The parameters of a function and their default values do not belong to the function body. Therefore, the return expression in the following example does not contain the function body that surrounds the expression. That is, the return expression does not belong to the outer function f (because the definition of the inner function g has taken effect) or the function body of the inner function g.
func f() {
func g(x! :Int64 = return) { // Error: return must be used inside a function body
0
}
1
}
Function Body
The function body consists of a block.
Local Variables
In Cangjie, variables can be defined in the function body, which are called local variables.
A variable can be modified as a mutable variable by using var or as an immutable variable by using let.
func foo(): Unit {
var a = 1
let b = 1
}
Nested Functions
In Cangjie, functions can be defined in the function body, which is called nested functions. Nested functions can capture variables defined in external functions or other nested functions. Nested functions support recursion.
func foo(): Unit {
func add(a: Int32, b: Int32) { a + b }
let c = 1
func nest(): Unit {
print("${c}") // 1
var b = add(1, 2) // b = 3
}
}
Return Type of Functions
The return type of a function can be one of the following:
-
Any type (see [Types]).
-
Functions returning a tuple: The tuple type can be used as the return type of a function, allowing multiple values to be returned as a composite value. In the following example, the return value is a tuple
(a, b), and the return type is(Int32, Int32).func returnAB(a: Int32, b: Int32): (Int32, Int32) { (a, b) } -
Function type as the return type: You can use a function type as the return type of another function. In the following example ,the
:is followed by theaddfunction type(Int32, Int32) -> Int32.func returnAdd(a: Int32, b: Int32): (Int32, Int32) -> Int32 { return {a, b => a + b} // Return a lambda expression. }
To specify the return type of a function, use :Type after the parameter list of the function's definition. In this case, the type of the function body and the type of e in all return e expressions in the function body must be subtypes of the specified type (Type). Otherwise, a compilation error is reported.
class A {}
class B <: A {}
// Return is not written.
func add(a: Int32, b: Int32): B {
var c = a + b
if (c > 100) {
return B()
} else {
return A() // Compilation error since A is not a subtype of B.
}
}
Specifically, if the return type is specified as Unit (for example, func f(x:Bool):Unit { x}), the compiler automatically inserts the expression return () at all possible return points in the function body so that the return type of the function is always Unit. The following is an example:
func Column(c: (Data) -> Unit): Unit { 2 } // return () is automatically inserted
func Column(c: (Data) -> Unit) { 2 } // return type is Int64
If the return type of a function is not specified, the compiler infers the return type of the function based on the function body and all return expressions in the function body. This process is incomplete. For example, if the function is (mutually) recursive and its return type cannot be inferred, a compilation error is reported. (Note: The return type cannot be inferred for a function without a function body.)
The rules for inferring the return type of a function are as follows: The function body is a sequence of expressions and declarations. We denote the type of the last item in the sequence as T0. (If the last item of a block is an expression, the return type of the function is the type of that expression. If the last item is a declaration, then T0 = Unit.) Then, we denote the type of e in all return e expressions (including those in all subexpressions) in the function body as T1... Tn. The return type of the function is the minimum common supertype of T0, T1, ..., Tn. If the minimal common supertype does not exist, a compilation error occurs. The following is an example:
open class Base {}
class Child <: Base {}
func f(a: Rune) {
if (false) {
return Base()
}
return Child()
}
- The type of the function body is the type of the last item in the block, that is, the type of
return Child(), which isNothing. - In the first
return eexpressionreturn Base(), the type ofeisBase. - In the second
return eexpressionreturn Child(), the type ofeisChild. - The minimum common supertype of
Nothing,Base, andChildisBase. Therefore, the return type of this function isBase.
Note: The return value of a function has the semantics of let.
Function Declarations
In Cangjie, the difference between function declaration and function definition is that the former does not have a function body. The syntax for function declaration is as follows:
functionDeclaration
: functionModifierList? 'func'
identifier
typeParameters?
functionParameters
(':' type)?
genericConstraints?
;
Function declarations can appear in abstract classes and interfaces.
Function Redefinition
For non-general functions, functions with the same name and parameter type in the same scope are considered redefined, and a compilation error occurs. The following situations should be noted:
- Functions with the same name are considered redefined even if their return types are different.
- A generic function and a non-generic function with the same name never constitutes a redefinition.
- During inheritance, if a function in a subclass has the same name and parameter types as a function in the superclass and its return type is the subtype of the function in the superclass, this constitutes overriding, but not a redefinition. (This is because the scope of the subclass is different from that of the superclass.)
For two generic functions, after one function's generic parameter is renamed, if the non-generalized part of this function and that of the other function constitute a redefinition, the two generic functions constitute a redefinition. An example is as follows:
-
The following two generic functions constitute a redefinition because the renaming of
[T1 |-> T2]applies to the first function, causing the non-generic parts of both functions to constitute a redefinition.func f<T1>(a: T1) {} func f<T2>(b: T2) {} -
The following two generic functions do not constitute a redefinition because the previously-mentioned renaming cannot be found.
func f<X,Y>(a:X, b:Y) {} func f<Y,X>(a:X, b:Y) {} -
The following two generic functions constitute a redefinition because there is a renaming of
[X |-> Y, Y |-> X], causing the non-generic parts of both functions to constitute a redefinition.func f<X,Y>(a:X, b:Y) {} func f<Y,X>(a:Y, b:X) {}
Function Types
The function type consists of the parameter type and return type, which are connected using ->.
functionType:
: '(' (type (, type)*)? ')' '->' type
The following are some examples:
-
Example 1: There is no parameter, and the return type is
Unit.func hello(): Unit { print("Hello!") } // function type: () -> Unit -
Example 2: The parameter type is
Int32, and the return type isUnit.func display(a: Int32): Unit { print("${a}") } // function type: (Int32) -> Unit -
Example 3: The two parameters are of the
Int32type, and the return type isInt32.func add(a: Int32, b: Int32): Int32 { a + b } // function type: (Int32, Int32) -> Int32 -
Example 4: The parameter type is
(Int32, Int32) -> Int32,Int32andInt32, and the return type isUnit.func printAdd(add: (Int32, Int32) -> Int32, a: Int32, b: Int32): Unit { print("${add(a, b)}") } // function type: ((Int32, Int32) -> Int32, Int32, Int32) -> Unit -
Example 5: The two parameters are of the
Int32type, and the return type is the function type(Int32, Int32) -> Int32.func returnAdd(a: Int32, b: Int32): (Int32, Int32) -> Int32 { {a, b => a + b} } // function type: (Int32, Int32) -> (Int32, Int32) -> Int32 -
Example 6: If both parameters are of the
Int32type, the tuple type(Int32, Int32)is returned.func returnAB(a: Int32, b: Int32): (Int32, Int32) { (a, b) } // function type: (Int32, Int32) -> (Int32, Int32)
Function Calls
For details about the syntax of function call expressions, see [Function Call Expressions].
Named Arguments
When a function is called, the parameter name: prefix is used before the argument value to specify the parameter corresponding to this argument.
Only parameters defined by ! in the function definition can use the syntax for named arguments.
When a function is called, all named parameters must be passed using named arguments. Otherwise, an error is reported.
In a function call expression, non-named arguments are not allowed after named arguments. When named arguments are used to specify argument values, the sequence of the arguments does not need to match that of the parameter list.
func add(a!: Int32, b!: Int32): Int32 {
a + b
}
var sum1 = add(1, 2) // error
var sum2 = add(a: 1, b: 2) // OK, 3
var sum3 = add(b: 2, a: 1) // OK, 3
Function Call Type Check
This section describes the type check required for a given call expression. If the called function involves overloading, the type check and overloading resolution must be based on the rules of [Function Overloading].
- If a type parameter is specified in the function call expression, the type check can be passed only when the number of type arguments is the same as the number of type parameters. For example, if the function call expression is
f<T1, ..., Tm>(A1, ..., An)and m type arguments are specified, the number of function type parameters must be m.
open class Base {}
class Sub <: Base {}
func f<X, Y>(a: X, b: Y) {} // f1
func f<X>(a: Base, b: X) {} // f2
f<Base>(Base(), Sub()) // f2 may pass the type checking
- Type check of a function must be based on the arguments in the call expression and the return type
Rspecified in the type check context.
Assume that the function is defined as follows:
$$
f_i<T_{i1},...,T_{ip}>(A_{i1}, ..., A_{ik}): R_i \ \ where \ \ C_{i1}, ..., C_{iq_i}
$$
(1) If the call expression contains the type argument, that is, fi<T1, ..., Tp>(A1, ..., Ak), the rules for the type check of the fi function are as follows:
(a) Type argument constraint check: The type argument `<T1, ..., Tp>` must meet the type constraint of the `fi` function.
$$
\sigma = [T_1 \mapsto T_{i1}, ..., T_p \mapsto T_{ip}]
$$
$$
\Delta \vdash \sigma \ \ solves \ \ C_{i1}, ..., C_{iq_i}
$$
(b) Parameter type check: After the type arguments are substituted into the parameters of the function fi, the argument types (A1, ..., Ak) are the subtypes of the type after the type argument is substituted into the parameter.
$$
\sigma = [T_1 \mapsto T_{i1}, ..., T_p \mapsto T_{ip}]
$$
$$
\Delta \vdash (A1, ..., Ak) <: \sigma (A_{i1},...,A_{ik})
$$
(c) Return type check: If the context of the call expression requires a specific type R, type check needs to be performed based on the return type. After the type argument is substituted into the return type Ri of the function fi, the return type is the subtype of R.
$$
\sigma = [T_1 \mapsto T_{i1}, ..., T_p \mapsto T_{ip}]
$$
$$
\Delta \vdash \sigma R_i <: R
$$
(2) If the call expression does not contain the type argument, that is, f(A1, ..., An), the rules for the type check of the fi function are as follows:
(a) If `fi` is a non-generic function, the type check is performed based on the following rules:
(i) Parameter type check: The argument types `(A1, ..., Ak)` are subtypes of the parameter types.
$$
\Delta \vdash (A1, ..., Ak) <: (A_{i1},...,A_{ik})
$$
(ii) Return type check: If the context of the called expression requires a specific type R, the return type Ri of the checked function fi is the subtype of R.
$$ \Delta \vdash R_i <: R $$
open class Base {}
class Sub <: Base {}
func f(a: Sub) {1} // f1
func f(a: Base) {Base()} // f2
let x: Base = f(Sub()) // f2 can pass the type checking
(b) If `fi` is a generic function, the type check is performed based on the following rules:
(i) Parameter type check: Substitution exists so that the argument types `(A1, ..., Ak)` are the subtypes of the types after parameter type substitution.
$$
\sigma = [T_1 \mapsto T_{i1}, ..., T_p \mapsto T_{ip}]
$$
$$
\Delta \vdash (A1, ..., Ak) <: \sigma (A_{i1},...,A_{ik})
$$
(ii) Return type check: If the context of the call expression requires a specific type R, type check needs to be performed based on the return type. After the type argument in (i) is substituted into the return type Ri of the function fi, the return type is the subtype of R.
$$ \sigma = [T_1 \mapsto T_{i1}, ..., T_p \mapsto T_{ip}] $$ $$ \Delta \vdash \sigma R_i <: R $$
Note that:
- If a function has a default value, the default value is padded before type check.
- If a function has named parameters, the sequence of the named parameters may be different from that of the parameters. During type check, the named arguments must correspond to the matching named parameters.
Trailing Lambda
When the last parameter of a function is the function type, and the argument corresponding to the function call is lambda, you can use the trailing lambda syntax to place lambda at the end of the function call outside the parentheses ().
func f(a: Int64, fn: (Int64)->Int64) { fn(a) }
f(1, { i => i * i }) // normal function call
f(1) { i => i * i } // trailing lambda
func g(a!: Int64, fn!: (Int64)->Int64) { fn(a) }
g(a: 1, fn: { i => i * i }) // normal function call
g(a: 1) { i => i * i } // trailing lambda
If a function call has only one lambda as an argument, you can omit () and write only lambda.
func f(fn: (Int64)->Int64) { fn(1) }
f{ i => i * i }
If the trailing lambda does not contain parameters, => can be omitted.
func f(fn: ()->Int64) { fn() }
f{ i * i }
Note that the trailing lambda syntax can be used only for function calls with function name/variable name, and the lambda expression that is trailing lambda interprets it only as the parameter of the function corresponding to function name/variable name. This means that the following two call examples are invalid:
func f(): (()->Unit)->Unit {
{a => }
}
f() {} // error, the lambda expression is not argument for f.
func g(a: ()->Unit) {}
if (true) { g } else { g } () {} // error, illegal trailing lambda syntax
The preceding expression must be assigned to a variable first. The trailing lambda syntax can be used only when the variable name is used for calling. The code is as follows:
let f2 = f()
f2 {} // ok
let g2 = if (true) { g } else { g }
g2() {} // ok
This syntax can be used for both common function calls and constructor calls, including this() and super().
this(1, { i => i * i } )
this(1) { i => i * i }
super(1, { i => i * i } )
super(1) { i => i * i }
Variable-Length Parameters
Variable-length parameters are special syntactic sugar for function calls. When the last non-named parameter is of the Array type, the parameter sequence can be directly passed to the corresponding position of the argument to replace the Array literal.
- Variable-length parameters do not have special declaration syntax. It only requires the last non-named parameter in the function declaration is of the
Arraytype. - When a function is called, multiple elements of
Arraycan be passed one by one in the form of a common parameter list. - Among non-named parameters, only the last parameter can use variable-length parameters. This syntactic sugar cannot be used for named parameters.
- Variable-length parameters are applicable to global functions, static member functions, instance member functions, local functions, constructors, function variables, lambda, function call operator overloading, and index operator overloading. Other operator overloading, compose, and pipeline calling modes are not supported.
- There may be zero or more variable-length parameters.
- Variable-length parameters take effect only when function overloading does not exist. The priority is the lowest.
func f1(arr: Array<Int64>) {}
func f2(a: Int64, arr: Array<Int64>) {}
func f3(arr: Array<Int64>, a: Int64) {}
func f4(arr1!: Array<Int64>, a!: Int64, arr2!: Array<Int64>) {}
func g() {
let li = [1, 2, 3]
f1(li)
f1(1, 2, 3) // using variable length argument
f1() // using variable length argument
f2(4, li)
f2(4, 1, 2, 3) // using variable length argument
f3(1, 2, 3) // error, Array is not the last parameter
f4(arr1: 1,2,3, a: 2, arr2: 1,2,3) // error, named parameters cannot use variable length argument
}
The function overloading resolution always preferentially considers the functions that can be matched without using variable-length parameters. Variable-length parameters are used for parsing only when no function can be matched.
If the compiler cannot make a resolution, an error is reported.
open class A {
func f(v: Int64): Unit { // f1
}
}
class B <: A {
func f(v: Array<Int64>): Unit { // f2
}
}
func p1() {
let x = B()
x.f(1) // call the f1
}
func g<T>(arg: T): Unit { // g1
}
func g(arg: Array<Int64>): Unit { // g2
}
func p2() {
g(1) // call the g1
}
func h(arg: Any): Unit { // h1
}
func h(arg: Array<Int64>): Unit { // h2
}
func p3() {
h(1) // call the h1
}
Function Scopes
In Cangjie, a function can be defined at the top level of the source program or inside the function.
-
Global Functions
A function defined at the top level of a source program is called a global function, and its scope is global. In the following example, the
globalFunctionfunction is a global function. Its scope is global.func globalFunction() {} -
Nested Functions
A function defined in a function body is a nested function, and its scope is local. For details, see [Scopes]. In the following example, the
nestedFunctionfunction is a nested function, and its scope ranges from its definition to the end of theglobalFunctionfunction body.func globalFunction() { func nestedFunction() {} } -
Member Functions
Member functions can be declared or defined in the type definition. The scope of a member function is the entire type and its extensions.
interface Myinterface { func foo(): Unit static func bar(): Unit } class MyClass { func foo() {} static func bar() {} } -
Member Functions of Extensions
Additional member functions can be declared in an extension. Its scope is all extensions of the extended type and is restricted by access modifiers.
extend MyType { func foo(): Unit {} }
Lambda Expressions
A lambda expression is an anonymous function.
The syntax of the lambda expression is as follows:
lambdaExpression
: '{' NL* lambdaParameters? '=>' NL* expressionOrDeclarations '}'
;
lambdaParameters
: lambdaParameter (',' lambdaParameter)* ','?
;
lambdaParameter
: (identifier | '_') (':' type)?
;
The lambda expression has two forms: one is with parameters, for example, {a: Int64 => e1; e2}, and the other one is without parameters, for example, { => e1; e2}. (e1 and e2 are expressions or declaration sequences).
let f1: (Int64, Int64)->Int64 = {a: Int64, b: Int64 => a + b}
var f2: () -> Int32 = { => 123 }
For a lambda expression with parameters, you can use a _ to replace a parameter. A _ indicates the parameters that are not used in the function body of the lambda expression.
let f2 = {n: Int64, _: Int64 => return n * n}
let f3: (Int32, Int32) -> Int32 = {n, _ => return n * n}
let f4: (String) -> String = {_ => return "Hello"}
The lambda expression does not support the declaration of the return type.
-
If the return type of a lambda expression is explicitly specified in the context, its return type is the type specified in the context. If the specified return type is
Unit, the Cangjie compiler insertsreturn ()at all possible return points in the function body of the lambda expression so that the return type of the function is alwaysUnit. The following is an example of specifying the return type asUnit:func column(c: (Data) -> Unit) {...} func row(r: (Data) -> Unit) {...} func build():Unit { column { _ => row { _ => buildDetail() buildCalendar() } // OK. Well typed since 'return' is inserted. width(750) height(700) backgroundColor("#ff41444b") } // OK. Well typed since 'return' is inserted. } -
If such context does not exist, the type of the expression on the right of
=>is considered as the return type of the lambda expression. Similar to functions, if the return type cannot be inferred, a compilation error is reported.
The type annotation of the parameter in the lambda expression can be left empty. The compiler attempts to infer the type from the context. If the compiler cannot infer the type, a compilation error is reported.
var sum1: (Int32, Int32) -> Int32 = {a, b => a + b}
var sum2: (Int32, Int32) -> Int32 = {a: Int32, b => a + b}
var display = { => print("Hello") }
var a = { => return 1 }
The rules for the content on the right of => is the same as that of a common function body. You can also omit return. If the right side of => is empty, the return value is ().
sum1 = {a, b => a + b}
sum2 = {a, b => return a + b} // Same as that in the previous line.
A lambda expression can be called immediately. The following is an example:
let r1 = {a: Int64, b: Int64 => a + b}(1, 2) // r1 = 3
let r2 = { => 123 }() // r2 = 123
Closures
In Cangjie, a closure is a self-contained function or lambda. A closure can capture variables from the static scope that defines it. Even if a call to a closure is not in the defined scope, the captured variables can still be accessed. Variable capture occurs when a closure is defined.
Not all variable accesses within a closure are considered captures. The following cases are not considered captures:
- A local variable defined inside a function or lambda is accessed in the function or lambda.
- A parameter of a function or lambda is accessed in the function or lambda.
- Global variables and static member variables are accessed in functions or lambdas.
- An instance member variable is accessed in an instance member function. As the instance member function passes
thisas a parameter, all instance member variables are accessed throughthisin the instance member function.
There are two cases for capturing variables:
- Capturing variables declared by
let: The values of these variables cannot be modified in closures. If the captured variable is of the reference type, you can change the value of its mutable instance member variable. Functions or lambdas that capture only local variables declared byletcan be used as first-class citizens. That is, they can be assigned to variables, used as arguments or return values, and used as expressions. - Capturing variables declared by
var: Functions or lambdas that capture mutable variables can only be called and cannot be used as first-class citizens. For example, they cannot be assigned to variables, used as arguments or return values, or used as expressions.
Note that capturing is transitive. If the
ffunction calls thegfunction that captures thevarvariable which is not defined inside theffunction, theffunction also captures thevarvariable and cannot be used as a first-class citizen.
In the following example, h captures only the variable y declared by let. h can be used as a first-class citizen.
func f(){
let y = 2
func h() {
print(y) // OK, captured an immutable variable.
}
let d = h // OK, h can be assigned to variable
return h // OK, h can be a return value
}
In the following example, g captures the variable x declared by var. g cannot be used as a first-class citizen and can only be called.
func f() {
var x = 1
func g() {
print(x) // OK, captured a mutable variable.
}
let b = g // Error, g cannot be assigned to a variable
g // Error, g cannot be used as an expression
g() // OK, g can be invoked
// Lambda captured a mutable variable, cannot be assigned to a variable
let e = { => print("${x}") } // Error
let i = { => x*x }() // OK, lambda captured a mutable variable, can be invoked.
return g // Error, g cannot be used as a return value.
}
In the following example, g captures the variable x declared by var, f calls g, and x captured by g is not defined in f. f cannot be used as a first-class citizen.
func h(){
var x = 1
func g() { x } // captured a mutable variable
func f() {
g() // invoked g
}
return f // error
}
In the following example, g captures the x variable declared by var, and f calls g. However, x captured by g is defined inside f, and f does not capture other variables declared by var. Therefore, f is still used as a first-class citizen.
func h(){
func f() {
var x = 1
func g() { x } // captured a mutable variable
g()
}
return f // ok
}
Functions or lambdas that access global variables, static member variables, and instance member variables modified by var can still be used as first-class citizens.
class C {
static var a: Int32 = 0
static func foo() {
a++ // OK
return a
}
}
var globalV1 = 0
func countGlobalV1() {
globalV1++
C.a = 99
let g = C.foo // OK
}
func g(){
let f = countGlobalV1 // OK
f()
}
The captured variables must meet the following rules:
- A captured variable must be visible when a closure is defined. Otherwise, an error is reported during compilation.
- Variables must have been initialized before being captured. Otherwise, an error is reported during compilation.
- If a function contains a local variable with the same name as a variable outside the function, when the closure in the function captures the variable outside the function because the scope of the local variable does not start, a warning is reported to avoid misuse.
// 1. The captured variable must be defined before the closure.
let x = 4
func f() {
print("${x}") // Print 4.
let x = 99
func f1() {
print("${x}")
}
let f2 = { =>
print("${x}")
}
f1() // Print 99.
f2() // Print 99.
}
// 2. The variable must be initialized before being captured.
let x = 4
func f() {
print("${x}") // Print 4.
let x: Int64
func f1() {
print("${x}") // Error: x is not initialized yet.
}
x = 99
f1()
}
// 3. If there is a local variable in a block, closures capture variables of the same name in the outer scope will report a warning.
let x = 4
func f() {
print("${x}") // Print 4.
func f1() {
print("${x}") // warning
}
let f2 = { =>
print("${x}") // warning
}
let x = 99
f1() // print 4
f2() // print 4
}
Function Overloading
Definition of Function Overloading
In Cangjie, function overloading occurs when multiple function definitions with the same function name exist in the same scope, but they do not constitute redefinition. When function overloading exists, the correct function definition to be used is determined during the function call based on the types of the arguments in the call expression and the context.
Rules for Function Overloading
-
The function name must be the same and meet one of the following conditions:
- The function name is introduced by the
funckeyword. - The function is a constructor defined in a class or struct, including the main constructor and the
initconstructor.
- The function name is introduced by the
-
The parameter types must be different. That is, one of the following conditions must be met:
-
The number of function parameters is different.
-
The number of function parameters is the same, but the parameter types in the corresponding positions are different.
-
-
The functions must be visible in the same scope.
Note that the parameter type of a function is not affected by whether the parameter is a named parameter or whether the parameter has a default value. In addition, when the parameter type is discussed, a type and its alias are considered to be the same type. For example, the parameter types of the four functions in the following example are the same:
type Boolean = Bool
func f(a : Bool) {}
func f(a! : Bool) {}
func f(a! : Bool = false) {}
func f(a! : Boolean) {}
Example 1: The two functions defined at the top level of the source file have different parameter types. f constitutes overloading.
// f overloading
func f() {...}
func f(a: Int32) {...}
Example 2: The f1 function in the I interface, C1 class, and C2 class constitutes overloading.
interface I {
func f1() {...}
}
open class C1 {
func f1(a: Int32) {...}
}
class C2 <: C1 & I {
// f1 overloading
func f1(a: Int32, b: String) {...}
}
Example 3: Constructors of a type constitute overloading.
class C {
var name: String = "abc"
// constructor overloading
init(){
print(name)
}
init(name: String){
this.name = name
}
}
Example 4: In the following example, the number of function parameters is the same, the types at corresponding positions are the same, and only the constraints of the type variables contained in the parameter types are different. This does not constitute overloading.
interface I1{}
interface I2{}
func f<T>(a: T) where T <: I1 {}
func f<T>(a: T) where T <: I2 {} // Error, not overloading
mut Functions
The mut function is a special instance member function. In the mut member function of the struct type, member variables can be modified through this. In the non-mut member function of the struct type, member variables cannot be modified through this.
Definition of the mut Function
The mut function is modified by the mut keyword and can be defined only in the interface, struct, and struct extensions. In addition, it can be used only for instance member functions (static member functions are not supported).
struct A {
mut func f(): Unit {} // ok
mut static func g(): Unit {} // error
mut operator func +(rhs: A): A { // ok
return A()
}
}
extend A {
mut func h(): Unit {} // ok
}
class B {
mut func f(): Unit {} // error
}
interface I {
mut func f(): Unit // ok
}
In the mut function, you can assign values to the fields of the struct instance. The values will modify the instance and take effect immediately. Like instance member functions, this is not required and can be inferred by the compiler.
struct Foo {
var i = 0
mut func f() {
this.i += 1 // ok
i += 1 // ok
}
}
main() {
var a = Foo()
print(a.i) // 0
a.f()
print(a.i) // 2
a.f()
print(a.i) // 4
return 0
}
this in the mut function has the following restrictions:
- It cannot be captured (meaning that the fields of the current instance cannot be captured).
- It cannot be used as an expression.
struct Foo {
var i = 0
mut func f(): Foo {
let f1 = { => this } // error
let f2 = { => this.i = 2 } // error
let f3 = { => this.i } // error
let f4 = { => i } // error
return this // error
}
}
mut Function in Interfaces
The struct type must be modified by the same mut modifier when implementing an interface function. When a type other than struct implements an interface function, the mut modifier cannot be used.
interface I {
mut func f1(): Unit
func f2(): Unit
}
struct A <: I {
public mut func f1(): Unit {} // ok
public func f2(): Unit {} // ok
}
struct B <: I {
public func f1(): Unit {} // error
public mut func f2(): Unit {} // error
}
class C <: I {
public func f1(): Unit {} // ok
public func f2(): Unit {} // ok
}
Note that when a struct instance is assigned to an interface type, the copy semantics is used. Therefore, the mut function of the interface cannot change the value of the struct instance.
interface I {
mut func f(): Unit
}
struct Foo <: I {
var v = 0
public mut func f(): Unit {
v += 1
}
}
main() {
var a = Foo()
var b: I = a
b.f()
print(a.v) // 0
return 0
}
Access Rules
If a variable is declared by let and the type may be struct (including the static type being struct, or the type variable might be of the struct type), the variable cannot access the function that is modified by mut. In other cases, the access is allowed.
interface I {
mut func f(): Unit
}
struct Foo <: I {
var i = 0
public mut func f(): Unit {
i += 1
}
}
class Bar <: I {
var i = 0
public func f(): Unit {
i += 1
}
}
main() {
let a = Foo()
a.f() // error
var b = Foo()
b.f() // ok
let c: I = Foo()
c.f() // ok
return 0
}
func g1<T>(v: T): Unit where T <: I {
v.f() // error
}
func g2<T>(v: T): Unit where T <: Bar & I {
v.f() // ok
}
If the type of a variable may be struct (including the static type being struct, or the type variable might be of the struct type), then the variable cannot use functions modified by mut of this type as high-order functions. It can only call those mut functions.
interface I {
mut func f(): Unit
}
struct Foo <: I {
var i = 0
public mut func f(): Unit {
i += 1
}
}
class Bar <: I {
var i = 0
public func f(): Unit {
i += 1
}
}
main() {
var a = Foo()
var fn = a.f // error
var b: I = Foo()
fn = b.f // ok
return 0
}
func g1<T>(v: T): Unit where T <: I {
let fn = v.f // error
}
func g2<T>(v: T): Unit where T <: Bar & I {
let fn = v.f // ok
}
Non-mut instance member functions (including lambda expressions) cannot access the mut function of this, while the reverse is allowed.
struct Foo {
var i = 0
mut func f(): Unit {
i += 1
g() // ok
}
func g(): Unit {
f() // error
}
}
interface I {
mut func f(): Unit {
g() // ok
}
func g(): Unit {
f() // error
}
}
Classes and Interfaces
Classes
Defining Classes
In the Cangjie programming language, the keyword class is used to define a class. The class definition includes the following parts:
- Optional modifiers.
- Keyword
class. - Class name, which must be a valid identifier.
- Optional type parameters.
- Optional superclasses or superinterfaces (write them after
<:and use&to separate them) that are specified. If a superclass exists, it must be written first. Otherwise, an error is reported during compilation. - Optional generic constraints.
- Class body.
A class can be defined only at the top level of a source file. The syntax for defining a class is as follows:
classDefinition
: classModifierList? 'class' identifier
typeParameters?
('<:' superClassOrInterfaces)?
genericConstraints?
classBody
;
superClassOrInterfaces
: classType ('&' superInterfaces)?
| superInterfaces
;
The following is an example of class definition:
interface I1<X> {}
interface I2 {}
open class A{}
// The following class B inherits class A and implements interface I2.
open class B <: A & I2 {}
/* The following class C declares 1 type parameters U. It inherits B and implements interfaces I1<U> and I2. Also, its type parameters have constraints U <: A */
class C<U> <: B & I1<U> & I2 where U <: A {}
Class Modifiers
In this section, we will introduce the modifiers that can be used to define classes.
Access Modifiers
Classes can be modified by all access modifiers. The default accessibility is internal. For details, see Access Modifiers in [Packages and Modules].
Inheritance Modifiers
-
open: If a class is modified byopen, other classes can inherit this class./* The following class is declared with modifier `open`, indicating that it can be inherited. */ open class C1 { func foo(): Unit { return } } class C2 <: C1 {}
Note that:
A non-abstract class that is not modified by
opencannot be inherited by any class.
-
sealed: The class can be inherited only in the package where the class is defined.-
sealedcan only modify abstract classes. -
sealedcontains the semantics ofpublic. Therefore,publicis optional when the sealed class is defined. -
The subclasses of
sealedcan be non-sealedclasses, and can still be modified byopenorsealed, or do not use any inheritance modifier. If the subclasses ofsealedare modified by bothpublicandopen, the subclasses can be inherited outside the package. -
The subclasses of
sealedmay not be modified bypublic.
// package A package A public sealed class C1 {} // OK sealed class C2 {} // OK, 'public' is optional when 'sealed' is used class S1 <: C1 {} // OK public open class S2 <: C1 {} // OK public sealed class S3 <: C1 {} // OK open class S4 <: C1 {} // OK // package B package B import A.* class SS1 <: S2 {} // OK class SS2 <: S3 {} // Error, S3 is sealed class, cannot be inherited here. -
Note that:
A non-abstract class that is not modified by
openorsealedcannot be inherited by any class.
Abstract Class Modifiers
-
abstract: belongs to the abstract class. Different from an ordinary class, an abstract class can define ordinary functions and declare abstract functions. Only the class modified by this modifier is an abstract class. A function without a function body is called an abstract function.Note that:
- The
abstractmodifier of the abstract class contains the semantics that can be inherited. Therefore, theopenmodifier is optional when the abstract class is defined. You can also use thesealedmodifier for the abstract class, indicating that the abstract class can be inherited only in its package. - Do not define abstract functions of
privatein abstract classes. - Instances cannot be created for abstract classes.
- The abstract subclasses of an abstract class are allowed not to implement abstract functions in the class.
- The non-abstract subclasses of an abstract class must implement all abstract functions in the class.
- The
Class Inheritance
Classes support only single inheritance. A class specifies the direct superclass of the current class with <: superClass (The superclass is a defined class).
The following example shows the syntax of how the C2 class inherits the C1 class:
open class C1 {}
class C2 <: C1 {}
The superclass can be a generic class. You only need to provide a valid type during inheritance. The following example shows the non-generic class C2 and the generic class C3 inherit the generic class C1:
open class C1<T> {}
class C2 <: C1<Int32> {}
class C3<U> <: C1<U> {}
Except for `Object`, every class has its superclass. If a class has no superclass defined, its superclass is `Object` by default.
```cangjie
class Empty {} // Inherit from Object implicitly: class Empty <: Object {}
Classes support only single inheritance. The syntax in the following example will cause a compilation error.
open class C1 {}
open class C2 {}
class C3 <: C1 & C2 {} // Error: Multiple inheritance is not supported.
When a class inherits another class, the latter is called a superclass, and the former is called a subclass.
open class C1 {} // C1 is superclass
class C2 <: C1 {} // C2 is subclass
A subclass inherits all members of its superclass, except for private members and constructors.
A class can directly access the members of its superclass. However, during overwriting, an overwritten instance member of the superclass cannot be directly accessed by its name. In this case, you can use super to specify the member (super points to the direct superclass of the current class object) or create an object and access the member through the object.
Interface Implementation
A class can implement one or more interfaces. You can use <: I1 & I2 &... & Ik to declare the interfaces to be implemented by the current class. Multiple interfaces are separated by &. If a superclass is also specified by the current class, place the interfaces after the superclass. Example:
interface I1 {}
interface I2 {}
// Class C1 implements interface I1
open class C1 <: I1 {}
// Class C2 inherits class C1 and implements interface I1, I2.
class C2 <: C1 & I1 & I2 {}
The interfaces can also be generic. In this case, valid type parameters need to be provided when the generic interfaces are implemented. Example:
interface I1<T> {}
interface I2<U> {}
class C1 <: I1<Int32> & I2<Bool> {}
class C2<K, V> <: I1<V> & I2<K> {}
When a type implements an interface, a non-generic interface cannot be directly implemented multiple times, while a generic interface cannot be directly implemented multiple times with the same type parameters. For example:
interface I1 {}
class C1 <: I1 & I1 {} // error
interface I2<T> {}
class C2 <: I2<Int32> & I2<Int32> {} // error
class C3<T> <: I2<T> & I2<Int32> {} // ok
If the type parameter Int32 is used when the generic class C3 is defined, two interfaces of the same type are implemented. As a result, the compiler reports an error at the position where the type is used.
interface I1<T> {}
open class C3<T> <: I1<T> & I1<Int32> {} // ok
var a: C3<Int32> // error
var b = C3<Int32>() // error
class C4 <: C3<Int32> {}// error
For details about the interfaces, see chapter [Interfaces].
Class Body
Class body indicates the content included in the current class. It is enclosed in braces and contains the following content:
- Optional static initializers
- Optional primary constructors
- Optional constructors
- Definitions of optional member variables
- Definitions or declarations of optional member functions and member operator functions
- Definitions or declarations of optional member properties
- Optional macro call expressions
- Optional class finalizers
The syntax of the class body is defined as follows:
classBody
: '{'
classMemberDeclaration*
classPrimaryInit?
classMemberDeclaration*
'}'
;
classMemberDeclaration
: classInit
| staticInit
| variableDeclaration
| functionDefinition
| operatorFunctionDefinition
| macroExpression
| propertyDefinition
| classFinalizer
;
The syntax definition of the preceding class body includes the following content:
staticInit: definition of a static initializer. Only one static initializer can be defined for a class.
classPrimaryInit: definition of the primary constructor. Only one can be defined for a class.
classInit: definition of the init constructor.
variableDeclaration: declaration of a member variable.
operatorFunctionDefinition: definition of an overloaded member function of an operator.
macroExpression: macro call expression. After the macro is expanded, it must comply with the syntax definition of classMemberDeclaration.
propertyDefinition: property definition.
classFinalizer: definition of a class finalizer.
The definitions or declarations introduced in the class body are members of the class. For details, see chapter [Members of a Class].
Members of a Class
The members of a class are as follows:
- Members inherited from the superclass (if any).
- If a class implements an interface, its members also include those inherited from the interface.
- Members declared or defined in the class body, including static initializers, primary constructor,
initconstructor, static member variables, instance member variables, static member functions, instance member functions, static member properties, and instance member properties.
Class members can be categorized by different dimensions:
Members can be classified into static members and instance members based on whether they are modified by static. Static members refer to members that can be accessed without instantiating class objects. Instance members refer to members that can be accessed through objects only after class objects are instantiated.
Members are classified into static initializers, constructors, member functions, member variables, and member properties.
Note that: All static members cannot be accessed by their names.
Constructors
In the Cangjie programming language, there are two types of constructors: primary constructor and init constructor (constructor for short).
Primary Constructor
The syntax of the primary constructor is defined as follows:
classPrimaryInit
: classNonStaticMemberModifier? className '(' classPrimaryInitParamLists? ')'
'{'
superCallExression?
( expression
| variableDeclaration
| functionDefinition)*
'}'
;
className
: identifier
;
classPrimaryInitParamLists
: unnamedParameterList (',' namedParameterList)? (',' classNamedInitParamList)?
| unnamedParameterList (',' classUnnamedInitParamList)?
(',' classNamedInitParamList)?
| classUnnamedInitParamList (',' classNamedInitParamList)?
| namedParameterList (',' classNamedInitParamList)?
| classNamedInitParamList
;
classUnnamedInitParamList
: classUnnamedInitParam (',' classUnnamedInitParam)*
;
classNamedInitParamList
: classNamedInitParam (',' classNamedInitParam)*
;
classUnnamedInitParam
: classNonStaticMemberModifier? ('let'|'var') identifier ':' type
;
classNamedInitParam
: classNonStaticMemberModifier? ('let'|'var') identifier'!' ':' type ('=' expression)?
;
classNonStaticMemberModifier
: 'public'
| 'protected'
| 'internal'
| 'private'
;
The definition of the primary constructor consists of the following parts:
1. Modifier: optional. The primary constructor can be modified by public, protected, or private. If none of them is used, the primary constructor is visible in the package. For details, see [Access Modifiers].
2.Primary constructor name: same as the type name. Do not use the func keyword before the primary constructor name.
3. Parameter list: Different from the init constructor, the primary constructor has two types of parameters: ordinary parameters and member variable parameters. The syntax and semantics of ordinary parameters are the same as those of parameters in the function definition.
Member variable parameters are introduced to reduce code redundancy. The definition of a member variable parameter includes the definition of a parameter and a member variable. In addition, it indicates the semantics of assigning a value to a member variable through a parameter. Omitted definitions and expressions are automatically generated by the compiler.
-
The syntax of member variable parameters is the same as that of member variable definition. In addition,
!can be used to indicate whether a member variable parameter is a named parameter. -
The modifiers of member variables include
public,protected,private. For details, see [Access Modifiers]. -
Member variable parameters only support instance member variables. That is, they cannot be modified by
static. -
A member variable parameter cannot have the same name as a member variable outside the primary constructor.
-
A member variable parameter can have no initial value. This is because the compiler generates a corresponding constructor for the primary constructor and assigns values to member variables in the constructor body.
-
A member variable parameter can also have initial value. The initial value is used only as the default value of constructor parameter. The initial value expression of a member variable parameter can reference other parameters or member variables (excluding instance member variables defined outside the primary constructor) that have been defined before the member variable is defined, but cannot modify the values of these parameters and member variables. Note that the initial value of the member variable parameter is valid only in the primary constructor and is not included in the member variable definition.
-
Member variable parameters cannot be followed by ordinary parameters. In addition, the parameter sequence must comply with that defined in the function. Parameters of named variables cannot be followed by non-named parameters.
4. Primary constructor body: If the constructor of the superclass is explicitly called, the first expression in the function body must be the expression that calls the constructor of the superclass. In addition, this cannot be used to call other constructors in the same class as the primary constructor. After the superclass constructor is called, expressions, local variable declarations, and local function definitions can be written in the primary constructor body. The declarations, definitions, and expressions must meet the rules for using this and super in the init constructor. For details, see [init Constructor].
The following is an example of the primary constructor definition:
class Test{
static let counter: Int64 = 3
let name: String = "afdoaidfad"
private Test(
name: String, // regular parameter
annotation!: String = "nnn", // regular parameter
var width!: Int64 = 1, // member variable parameter with initial value
private var length!: Int64, // member variable parameter
private var height!: Int64 = 3 // member variable parameter
) {
}
}
When the primary constructor is defined, ordinary parameters are not allowed after the parameters of member variables. The following is an example:
class Test{
static let counter: Int64 = 3
let name: String = "afdoaidfad"
private Test(
name: String, // regular parameter
annotation!: String = "nnn", // regular parameter
var width!: Int64 = 1, // member variable parameter with initial value
length!: Int64 // Error: regular parameters cannot be after member variable parameters
) {
}
}
The primary constructor is the syntactic sugar of the init constructor. The compiler automatically generates the definitions of the constructor and member variables corresponding to the primary constructor. The constructor is automatically generated as follows:
- Its modifier is the same as that of the primary constructor.
- The sequence of parameters from left to right is the same as that declared in the parameter list of the primary constructor.
- The form of the constructor body is as follows:
- Values are assigned to member variables in sequence. The syntax format is
this.x = x, wherexis the member variable name. - Code in the primary constructor body.
- Values are assigned to member variables in sequence. The syntax format is
open class A<X> {
A(protected var x: Int64, protected var y: X) {
this.x = x
this.y = y
}
}
class B<X> <: A<X> {
B( // primary constructor, it's name is the same as the class
x: Int64, // regular parameter
y: X, // regular parameter
v!: Int64 = 1, // regular parameter
private var z!: Int64 = v // member variable parameter
) {
super(x, y)
}
/* The corresponding init constructor with primary constructor auto-generated
by compiler.
private var z: Int64 // auto generated member variable definition
init( x: Int64,
y: X,
v!: Int64 = 1,
z!: Int64 = v) { // auto generated named parameter definition
super(x, y)
this.z = z // auto generated assign expression of member variable
}
*/
}
A class can define only one primary constructor. In addition to the primary constructor, other constructors can be defined as usual, but other constructors and the constructor corresponding to the primary constructor must be overloaded.
init Constructor
The constructor is specified using the init keyword and cannot contain the func keyword. The return type cannot be explicitly defined for the constructor, and the function body is required. The return type of the constructor is Unit.
The syntax of the constructor is as follows:
Init
: nonSMemberModifier? 'init' '(' InitParamLists? ')'
'{'
(superCallExression | initCallExpression)?
( expression
| variableDeclaration
| functionDefinition)*
'}'
;
InitParamLists
: unnamedParameterList (',' namedParameterList)?
| namedParameterList
;
You can add an access modifier before init to limit the access scope of the constructor. For details, see [Access Modifiers].
When an object of a class is constructed, the constructor of this class is called. If there is no accessible constructor that matches the parameter type, an error is reported during compilation.
In a class, you can provide multiple init constructors for the class. These constructors must meet the requirements of function overloading. For details, see [Function Overloading].
class C {
init() {}
init(name: String, age: Int32) {}
}
The constructor called when creating an instance of a class executes the expressions in the class in the following sequence:
-
Initialize the variables that are defined outside the primary constructor and have default values.
-
If the constructor does not explicitly call the superclass constructor or other constructors of the class, the parameterless constructor
super()constructor of the superclass is called. If the superclass does not have a parameterless constructor, an error is reported. -
Execute the code in the constructor body.
If a class does not define a primary constructor or an init constructor, it attempts to generate a parameterless constructor (public-modified). If the superclass does not have a parameterless constructor or the instance member variables of the class do not have initial values, an error is reported during compilation.
The rules for using constructors, this, and super are as follows:
- Do not use the instance member variable
this.variableNameand its syntactic sugarsvariableNameandsuper.variableNameas the default values of constructor parameters. - The
initconstructor can call either the superclass constructor or other constructors of the current class, but only one of them can be called. If this function is called, it must be called at the first expression in the constructor body. No expression or declaration is allowed before this function is called. - If the constructor does not explicitly call other constructors or the superclass constructor, the compiler inserts the parameterless constructor of the direct superclass at the beginning of the constructor body. If the superclass does not have a parameterless constructor, a compilation error is reported.
- After the constructor of the superclass or other constructors of the class are called in the constructor body,
super.xcan be used to access the instance member variablexof the superclass. - If the constructor does not explicitly call other constructors, ensure that all instance member variables declared by the class are initialized before return. Otherwise, an error is reported during compilation.
- Do not call instance member functions or instance member properties in the constructors of a class that can be inherited.
- Do not allow
thisescape in the constructors of a class that can be inherited. - Before all instance member variables are initialized, constructors are forbidden to use implicit parameter transfer, functions or
lambdathat capturethis,super.fto access the instance member methodfof the superclass, or independentthisexpressions. However,this.xor its syntaxxcan be used to access the initialized member variablex. - Do not call the constructors of this class through
thisoutside the constructor body. - Circular dependency between constructors is not allowed. Otherwise, a compilation error will be reported.
var b: Int64 = 1
class A {
var a: Int64 = 1
var b: ()->Int64 = { 3 } // OK
/* Cannot use lambda which captured `this` before all of the instance member
variables are initialized. */
var c: ()->Int64 = { a } // Error
/* Cannot use function which captured `this` before all of the instance member variables are initialized. */
var d: ()->Int64 = f // Error
var e: Int64 = a + 1 // OK
func f(): Int64 {
return a
}
}
class B {
var a: Int64 = 1
var b: ()->Int64
init() {
b = { 3 }
}
init(p: Int64) {
this()
b = { this.a } // OK
b = f // OK
}
func f(): Int64 {
return a
}
}
var globalVar: C = C()
func f(c: C) {
globalVar = c
}
open class C {
init() {
globalVar = this // Error, `this` cannot escape out of constructors of `open` class
f(this) // Error, `this` cannot escape out of constructors of `open` class
m() // Error: calling instance function is forbidden in constructors of `open` class
}
func m() {}
}
Static Initializers
Static variables in a class or structure can also be initialized by using assignment expressions in a static initializer. Static initializers cannot be used in enumerations and interfaces.
The syntax of a static initializer is as follows:
staticInit
: 'static' 'init' '(' ')'
'{'
expressionOrDeclarations?
'}'
;
The rules of a static initializer are as follows:
-
The static initializer is automatically called, but cannot be explicitly called by developers.
-
The static initializer is called when the package to which it belongs is loaded, which is similar to the initialization expression of a static variable.
-
A class or structure can have only one static initializer.
-
For a non-generic class or structure, the static initializer is called only once.
-
For a generic class or structure, the static initializer is called only once for instantiation of each different type.
- Note that the static initializer will not be called at all if the generic class or structure is not instantiated.
-
The static initializer is called after all static member variables in the class or structure have been directly initialized, just as the constructor is called after all instance fields have been directly initialized.
-
This means that further declared static member variables can be referenced in the static initializer.
-
This also means that the static initializer can be located anywhere in the class or structure, which does not matter much.
-
-
In the same file, the static initializer is called across classes in a top-down order even if there is an inheritance relationship between the classes.
- This means that there is no guarantee that all static member variables of the superclass must be initialized before the current class is initialized.
class Foo <: Bar { static let y: Int64 static init() { // called first y = x // error: not yet initialized variable } } open class Bar { static let x: Int64 static init() { // called second x = 2 } } -
Static member variables must be initialized in only one way, either directly through the expression on the right or in the static initializer.
-
Although a variable static variable can be initialized by assigning a value directly and in the static initializer at the same time, the variable initialization in this case is only a direct assignment, and the assignment in the static initializer is considered as a simple re-assignment. This means that a value is directly assigned to the variable before the static initializer is called.
-
If an immutable static variable is assigned a value directly and in the static initializer at the same time, the compiler reports an error about re-assignment.
- This error is also reported if multiple values are assigned to an immutable static variable in the static initializer.
-
If a static variable is neither initialized directly nor in the static initializer, the compiler reports an error about the uninitialized variable.
-
The above can be detected by a special initialization analysis, depending on the implementation.
-
-
The static initializer cannot have any parameters.
-
The
returnexpression cannot be used in the static initializer. -
Throwing an exception in the static initializer causes the program to terminate, just like throwing an exception in the expression on the right of a static variable.
-
Instance member variables or uninitialized static member variables not cannot be used in the static initializer.
-
The code of the static initializer is synchronous to prevent leakage of partially initialized classes or structures.
-
Static properties, including
getterandsetter, must be declared completely. -
Unlike static functions, static initializers cannot be used in extensions (within
extend). -
Because the static initializer is called automatically and cannot be called explicitly, visibility modifiers (that is,
publicandprivate) cannot be used to modify the static initializer.
The following is an example of the initialization analysis rules:
class Foo {
static let a: Int64
static var c: Int64
static var d: Int64 // error: uninitialized variable
static var e: Int64 = 2
static let f: Int64 // error: uninitialized variable
static let g: Int64 = 1
let x = c
static init() {
a = 1
b = 2
Foo.c // error: not yet initialized variable
let anotherFoo = Foo()
anotherFoo.x // error: not yet initialized variable
c = 3
e = 4
g = 2 // error: reassignment
}
static let b: Int64
}
Member Variables
Declaring Member Variables
Variables declared in classes and interfaces are called member variables. A member variable can be declared immutable by using the keyword let or mutable by using the keyword var.
Instance member variables outside the primary constructor can be declared with or without initial values. If there is an initial value, the initial value expression can use this variable to declare the previous member variable. These member variables are initialized before the constructor of the superclass is called. Therefore, the qualified name with super cannot be used to access the member variables of the superclass in the initial value expression.
The following is a code example of variables:
open class A {
var m1: Int32 = 1
}
class C <: A {
var a: Int32 = 10
let b: Int32 = super.m1 // Error
}
Variable Modifiers
Variables in a class can be modified by access modifiers. For details, see Access Modifiers in [Packages and Modules].
In addition, if a variable in a class is modified by static, it is a static variable of the class. static can be used together with other access modifiers. A static variable is inherited by a subclass. The static variable of the subclass is the same as that of the superclass.
class C {
static var a = 1
}
var r1 = C.a // ok
Class Member Functions
Declaring and Defining Class Member Functions
You can define functions in a class and declare functions in an abstract class. The difference between definition and declaration is whether the function has a function body.
Class member functions are classified into instance member functions and static member functions.
The syntax for defining or declaring a class member function is as follows:
functionDefinition : modifiers 'func' identifier typeParameters? functionParameters (':' returnType)? genericConstraints? (('=' expression) | block)? ;
Instance Member Functions
The first implicit parameter of an instance member function is this. Each time an instance member function is called, a complete object needs to be transferred first. Therefore, do not call an instance member function before the object is created, but the type of the function will not include the implicit parameter. The criterion for determining whether a class object is created is that the constructor of the class has been called.
Instance member functions can be classified into abstract member functions and non-abstract member functions.
Abstract Member Functions
An abstract member function can be declared only in an abstract class or interface. It does not have a function body.
abstract class A {
public func foo(): Unit // abstract member function
}
Non-abstract Member Functions
A non-abstract member function can be defined in any class and must have a function body.
class Test {
func foo(): Unit { // non-abstract member function
return
}
}
By default, abstract instance member functions have the semantics of open. When defining an abstract instance member function in an abstract class, the open modifier is optional, but public or protected must be explicitly specified as its visibility modifier.
Static Member Functions
A static member function is modified by the static keyword. It does not belong to an instance but belongs to its type. In addition, a static function must have a function body.
Static member functions cannot use instance member variables, call instance member functions, or call the keyword
superorthis.A static member function can reference other static member functions or static member variables.
Static member functions can be modified by
private,protected,public, orinternal. For details, see [Access Modifiers].When a static member function is inherited by another subclass, the static member function is not copied to the original subclass.
Static member functions in both abstract and non-abstract classes must have implementations.
Example:
class C<T> {
static let a: Int32 = 0
static func foo(b: T): Int32 {
return a
}
}
main(): Int64 {
print("${C<Int32>.foo(3)}")
print("${C<Bool>.foo(true)}")
return 0
}
This program has its own static member variable a and static function foo for C<Int32> and C<Bool> respectively.
Static functions in a class can declare new type variables, which can also have constraints. When calling a type variable, you only need to provide a valid type for a class and then a valid type for a static function.
class C<T> {
static func foo<U>(a: U, b: T): U { a }
}
var a: Bool = C<Int32>.foo<Bool>(true, 1)
var b: String = C<Bool>.foo<String>("hello", false)
func f<V>(a: V): V { C<Int32>.foo<V>(a, 0) }
Modifiers of Class Member Functions
Class member functions can be modified by all access modifiers. For details, see [Access Modifiers].
Other modifiable non-access modifiers are as follows:
-
open: If a member function needs to be overridden, use theopenmodifier. It conflicts with thestaticmodifier. When an instance member withopenis inherited by a class,openis also inherited. If a class has members modified byopenbut the current class is not modified byopenor does not contain theopensemantics,openis not effective for these members. In this case, the compiler reports a warning. (No warning is reported for inheritedopenmembers oroverridemembers.)A function modified by
openmust be modified bypublicorprotected.// case 1 open class C1 { // In this case, the 'open' modifier before 'class C1' is required. public open func f() {} } class C2 <: C1 { public override func f() {} } // case 2 open class A { public open func f() {} } open class B <: A {} class C <: B { public override func f() {} // ok } // case 3 interface I { func f() {} } open class Base <: I {} // The function f Inherits the open modifier. class Sub <: Base { public override func f() {} // ok } -
override: When a function overrides another function that can be overridden,overridecan be used to modify the function. (overridedoes not have the semantics ofopen. If a function modified byoverrideneeds to be overridden, you need to useopento modify the function.) The example is provided above. For details about function coverage rules, see chapter [Overriding]. -
static: The function modified bystaticis a static member function and must have a function body. Static member functions cannot be modified byopen.Instance members of the class to which a static member function belongs cannot be accessed within the function. Static members of the class to which an instance member function belongs can be accessed within the function.
class C { static func f() {} // Cannot be overwritten and must have a function body. } -
redef: When a static function redefines a static function inherited from the supertype,redefis an optional modifier for the static function.open class C1 { static func f1() {} static func f2() {} } class C2 <: C1 { redef static func f1() {} redef static func f2() {} }
Class Finalizer
A class finalizer is an instance member function of a class. It is called when an instance of the class is collected as garbage.
class C {
// below is a finalizer
~init() {}
}
The finalizer syntax is as follows:
classFinalizer
: '~' 'init' '(' ')' block
;
- A finalizer has no parameters, return types, generic type parameters, or modifiers, and cannot be called by users.
- Classes with finalizers cannot be modified by
open. Only non-openclasses can have finalizers. - Only one finalizer can be defined for a class.
- Finalizers cannot be defined in extensions.
- The time when a finalizer is triggered is uncertain.
- A finalizer may be executed on any thread.
- The execution sequence of multiple finalizers is uncertain.
- The behavior of a finalizer throwing an uncaught exception is determined by the implementation.
- The behavior of creating threads or using thread synchronization in a finalizer is determined by the implementation.
- After a finalizer is executed, if the object can still be accessed, the consequences are determined by the implementation.
- Do not use
thisto escape from a finalizer. - Instance members cannot be called in a finalizer.
For example:
class SomeType0 {
~init() {} // OK
}
class SomeType1 {
~init(x: Int64) {} // Error, finalizer cannot have parameters
}
class SomeType2 {
private ~init() {} // Error, finalizer cannot have accessibility modifiers
}
class SomeType3 {
open ~init() {} // Error, finalizer cannot have open modifier
}
open class SomeType4 {
~init() {} // Error, open class can't have a finalizer
}
var GlobalVar: SomeType5 = SomeType5()
class SomeType5 {
~init() {
GlobalVar = this // do not escape `this` out of finalizer, otherwise, unexpected behavior may happen.
}
}
Class Member Properties
You can also define member properties in a class. For details about the syntax for defining member properties, see chapter [Properties].
Instantiating Classes
After defining a non-abstract class type, you can create a class instance. There are two methods of creating a class instance based on whether the instance contains type variables:
- Create an instance of the non-general type
class:ClassName.ClassNameindicates the name of theclasstype, andargumentsindicates the argument list. TheClassName(arguments)function calls the corresponding constructor based on the calling rule of overloaded functions (see [Function Overloading]), and then generates an instance of theClassNamefunction. For example:
class C {
var a: Int32 = 1
init(a: Int32) {
this.a = a
}
init(a: Int32, b: Int32) {
this.a = a + b
}
}
main() : Int64 {
var myC = C(2) // invoke the first constructor
var myC2 = C(3, 4) // invoke the second constructor
return 0
}
2.Create an instance of the generic class: ClassName<Type1, Type2, ..., TypeK>(arguments). The only difference between creating an instance of a generic class and creating an instance of a non-generic class is whether generic parameters need to be instantiated. Generic arguments can be explicitly specified or omitted (in this case, the compiler infers the specific type based on the program context). For example:
class C<T, U> {
var a: T
var b: U
init(a: T, b: U) {
this.a = a
this.b = b
}
}
main() : Int64 {
var myC = C<Int32, Int64>(3, 4)
var myC2 = C(3,4) // The type of myC2 is inferred to C<Int64, Int64>.
return 0
}
Object Class
The Object class is the superclass of all class types (excluding the interface type). The Object class does not contain any member. That is, the Object class is an empty class. There are parameterless constructors modified by public in the Object class.
This Type
In a class, the This type placeholder is supported. It can be used only as the return type of the instance member function. During compilation, it is replaced with the type of the class to which the function belongs for type check.
- If the return type of a function is
This, the function can return only the expression of theThistype. - The expression of the
Thistype containsthisand other functions that returnThis. - The
Thistype is the subtype of the current type. TheThistype can be automatically cast to the current type, but the latter cannot be cast to the former. - The
Thistype cannot be explicitly used in the function body. If aThistype expression is not used in return values, the current type is inferred. - If an instance member function only has the
Thisexpression without declaring the return type, its return type is inferred asThis. - When an open function that contains
Thisis overridden, the return type must remainThis. - If the open function in the superclass returns the type of the superclass, the subclass can use
Thisas the return type when it is overridden.
open class C1 {
func f(): This { // its type is `() -> C1`
return this
}
func f2() { // its type is `() -> C1`
return this
}
public open func f3(): C1 {
return this
}
}
class C2 <: C1 {
// member function f is inherited from C1, and its type is `() -> C2` now
public override func f3(): This { // ok
return this
}
}
var obj1: C2 = C2()
var obj2: C1 = C2()
var x = obj1.f() // During compilation, the type of x is C2
var y = obj2.f() // During compilation, the type of y is C1
Interfaces
An interface is used to define an abstract type. It does not contain data but can define the behavior of the type. If a type declares that it implements an interface and all members of the interface, it is considered that the interface is implemented.
The members of an interface can include instance member functions, static member functions, operator overloading functions, instance member properties, and static member properties. These members are abstract, but the default implementations can be defined for functions and properties.
Defining Interfaces
Syntax for Defining Interfaces
An interface is defined using the keyword interface in the following sequence: modifier (default or not), interface keyword, interface name, optional type parameter, whether to specify a superinterface, optional generic constraint, and interface body.
The following are some interface definitions:
interface I1 {}
public interface I2<T> {}
public interface I3<U> {}
public interface I4<V> <: I2<V> & I3<Int32> {}
The syntax for interfaces is defined as follows:
interfaceDefinition
: interfaceModifierList? 'interface' identifier
typeParameters?
('<:' superInterfaces)?
genericConstraints?
interfaceBody
;
The interface can be defined only at the top level.
The {} of the interface body cannot be omitted.
interface I {} // {} not allowed to be omitted
Modifiers of an Interface
In this section, we will introduce the modifiers that can be used to define interfaces.
Access Modifiers
-
By default, if the access modifier is not used, the access can be performed only inside a package. You can also use the
publicmodifier so that the package can be accessed externally.public interface I {} // can be accessed outside the package interface I2 {} // can only be accessed inside the package
Inheritance Modifiers
- By default, if the inheritance modifier is not used, an interface has the semantics modified by
open. The interface can be inherited, implemented, or extended at any position where the interface can be accessed. Certainly, theopenmodifier may also be used explicitly. In addition, you can use thesealedmodifier to indicate that the interface can be inherited, implemented, or extended only in the package where the interface is defined. sealedcontains the semantics ofpublic. Therefore,publicis optional when the sealed interface is defined.- Interfaces that inherit or classes that implement the
sealedinterface can still be modified bysealedoptionally. If the subinterface of thesealedinterface is modified bypublicand not bysealed, the subinterface can be inherited, implemented, or extended outside the package. - The type that inherits and implements the sealed interface may not be modified by
public.
// package A
package A
public sealed interface I1 {} // OK
sealed interface I2 {} // OK, 'public' is optional when 'sealed' is used
open interface I3 {} // OK
interface I4 {} // OK, 'open' is optional
class C1 <: I1 {} // OK
public open class C2 <: I1 {} // OK
public sealed class C3 <: I1 {} // OK
extend Int64 <: I1 {} // OK
// package B
package B
import A.*
class S1 <: C2 {} // OK
class S2 <: C3 {} // Error, C3 is sealed class, cannot be inherited here.
Interface Members
An interface has the following members:
-
Members declared in the interface body (that is, in
{}): static member functions, instance member functions, operator overloading functions, static member properties, and instance member properties. -
Members inherited from other interfaces. In the following example, the members of
I2include the members that can be inherited fromI1:interface I1 { func f(): Unit } interface I2 <: I1 {}
The BNF of interface members is as follows:
interfaceMemberDeclaration
: (functionDefinition|macroExpression|propertyDefinition) end*
;
Functions in an Interface
Declaring and Defining Functions in an Interface
An interface can contain instance member functions and static member functions. These functions are compiled in the same way as ordinary instance member functions and static member functions, but may not be implemented. These functions are called abstract functions.
An abstract function with an implementation is called a function with a default implementation.
The following is an example of an abstract function:
interface MyInterface {
func f1(): Unit // Default implementation not included
static func f2(): Unit // Default implementation not included
func f3(): Unit { // Default implementation included
return
}
static func f4(): Unit { // Default implementation included
return
}
}
An abstract function can have named parameters without default values.
interface MyInterface {
func f1(a!: Int64): Unit // OK
func f2(a!: Int64 = 1): Unit // Error, cannot have parameter default values
}
Modifiers of Functions and Properties in an Interface
If a function or property defined in an interface contains the public semantics and is modified by public, a compilation alarm is generated. Do not use the protected, internal, or private modifier to modify the functions or properties defined in an interface.
The following is an incorrect example:
interface MyInterface {
public func f1(): Unit // Access modifiers cannot be used
private static func f2(): Unit // Access modifiers cannot be used
}
A function modified by static is called a static member function, which can have no function body. The static function without a function body cannot be directly called using an interface type. The static function with a function body can be called using an interface type. When the type name of an interface is used to directly call its static member function, if the function directly or indirectly calls other static functions that are not implemented in the interface (or other interfaces), an error is reported during compilation.
interface I {
static func f1(): Unit
static func f2(): Unit {}
static func f3(): Unit {
f1()
}
}
main() {
I.f1() // Error, cannot directly call
I.f2() // OK
I.f3() // Error, f1 not implemented
}
By default, the instance member functions in the interface have the semantics of open. The open modifier is optional in defining instance member functions in an interface.
interface I {
open func foo1() {} // ok
func foo2() {} // ok
}
A function modified by mut is a special instance member function, which can be used to abstract the variable behavior of the struct type.
interface I {
mut func f(): Unit
}
Member Properties in an Interface
You can also define member properties in an interface. For details about the syntax for defining member properties, see [Properties].
Default Implementations of an Interface
Abstract functions and abstract properties in an interface can have default implementations.
When an interface is inherited or implemented by another interface or type, if it is not re-implemented, its default implementations are copied to its subtype.
- In the default implementation of an instance member function,
thiscan be used. The type ofthisis that of the current interface. - Default implementations, like non-abstract member functions, can access all accessible elements in the current scope.
- Default implementations are a type of syntax sugar that provides a default behavior for the implementation type. An interface can use the default implementations of its superinterface.
- The default implementation does not belong to the inheritance semantics. Therefore, override, redef, or
supercannot be used. - If the subtype of an inherited interface is a class, the
opensemantics is retained by default and can be overridden by the subclasses of the class.
interface I {
func f() { // f: () -> I
let a = this // a: I
return this
}
}
Interface Inheritance
An interface can inherit one or more interfaces.
interface I1<T> {}
interface I2 {}
interface I3<U> <: I1<U> {} // inherit a generic interface.
interface I4<V> <: I1<Int32> & I2 {} // inherit multiple interfaces.
When a subinterface inherits its superinterface, it inherits all members of the superinterface.
A non-generic interface cannot be directly inherited for multiple times, and a generic interface cannot be directly inherited for multiple times using the same type of parameters. For example:
interface I1 {}
interface I2 <: I1 & I1 {} // error
interface I3<T> {}
interface I4 <: I3<Int32> & I3<Int32> {} // error
interface I5<T> <: I3<T> & I3<Int32> {} // ok
If the type parameter of the generic interface I3 is set to Int32, the compiler reports an error at the position where the type is used.
interface I1<T> {}
interface I2<T> <: I1<T> & I1<Int32> {} // ok
interface I3 <: I2<Int32> {} // error
main() {
var a: I2<Int32> // error
}
Default Implementations of a Subinterface
If an interface inherits a function or property without a default implementation from its superinterface, only the declaration of the function or property can be written in the interface (the default implementation can also be defined). In addition, the override or redef modifier before the function declaration or definition is optional. Example:
interface I1 {
func f1(): Unit
static func f2(): Unit
}
interface I2 <: I1 {
func f1(): Unit // ok
static func f2(): Unit // ok
}
interface I3 <: I1 {
override func f1(): Unit // ok
redef static func f2(): Unit // ok
}
interface I4 <: I1 {
func f1(): Unit {} // ok
static func f2(): Unit {} // ok
}
interface I5 <: I1 {
override func f1(): Unit {} // ok
redef static func f2(): Unit {} // ok
}
If an interface inherits a function or property with a default implementation from its superinterface, it is not allowed to write only the declaration of the function or property in the interface without implementation. If a new default implementation is provided in the interface, the override or redef modifier before the definition is optional. Example:
interface I1 {
func f1(): Unit {}
static func f2(): Unit {}
}
interface I2 <: I1 {
func f1(): Unit // error, 'f1' must has a new implementation
static func f2(): Unit // error, 'f2' must has a new implementation
}
interface I3 <: I1 {
override func f1(): Unit {} // ok
redef static func f2(): Unit {} // ok
}
interface I4 <: I1 {
func f1(): Unit {} // ok
static func f2(): Unit {} // ok
}
If an interface inherits the default implementations with the same signature member from its superinterfaces, the interface must provide new default implementations of its own version. Otherwise, a compilation error is reported.
interface I1 {
func f() {}
}
interface I2 {
func f() {}
}
interface I3 <: I1 & I2 {} // error, I3 must implement f: () -> Unit
Interface Implementation
Overriding and Overloading During Interface Implementation
When a type implements one or more interfaces, the rules are as follows:
- When a type that is not of the abstract class implements an interface, it must implement all functions and properties.
- When an abstract class implements an interface, it is allowed not to implement the functions and properties in the interface.
- The name and parameter list of the implementation function must be the same as those of the corresponding function in the interface.
- The return type of the implementation function must be the same as or a subtype of the corresponding function in the interface.
- For a generic function in an interface, the type variable constraint of the function must be looser or the same as that of the corresponding function in the interface.
- The
mutmodifier of the implementation property must be the same as the corresponding property in the interface. - The type of the implementation property must be the same as the corresponding property in the interface.
- If multiple interfaces have only one default implementation of the same function or property, it is allowed not to implement the function or property but use the default implementation.
- If multiple interfaces contain multiple default implementations of the same function or property, the function or property must be implemented. The default implementation cannot be used.
- If the same function or property in the interface already has the implementation type (inherited from the superclass or defined by the current class), the default implementation in any interface will not be used.
- When a type implements an interface, the
overridemodifier (orredefmodifier) before the definition of a function or property is optional, regardless of whether the function or property in the interface has a default implementation.
In the following example: when a type that is not of the abstract class implements an interface, the abstract functions and abstract properties in the interface must be implemented, like f1 and f3; the default implementation of a function in the interface can be omitted, like f2; the abstract class is allowed not to implement the instance member functions in the interface, like the abstract class C1 that does not implement f1 in the interface I.
interface I {
func f1(): Unit
func f2(): Unit {
return
}
static func f3(): Int64
}
class C <: I {
public func f1(): Unit {}
public func f2(): Unit {
return
}
public static func f3(): Int64 {
return 0
}
}
abstract class C1 <: I {
public static func f3(): Int64 {
return 1
}
}
Example: f and g in the I interface are generic functions and the E and F classes meet the requirement that the type variable constraints of the implementation functions are looser than or same as those of the implemented functions, so the compilation is successful. Class D does not meet the requirement, so an error is reported for the compilation.
// C <: B <: A
interface I {
static func f<T>(a: T): Unit where T <: B
static func g<T>(): Unit where T <: B
}
class D <: I {
public static func f<T>(a: T) where T <: C {} // Error, stricter constraint
public static func g<T>() where T <: C {} // Error, stricter constraint
}
class E <: I {
public static func f<T>(a: T) where T <: A {} // OK, looser constraint
public static func g<T>() where T <: A {} // OK, looser constraint
}
class F <: I {
public static func f<T>(a: T) where T <: B {} // OK, same constraint
public static func g<T>() where T <: B {} // OK, same constraint
}
More examples:
// case 1
interface I1 {
func f(): Unit
}
interface I2 {
func f(): Unit
}
class A <: I1 & I2 {
public func f(): Unit {} // ok
}
// case 2
interface I1 {
func f(): Unit
}
interface I2 {
func f(): Unit {}
}
open class A {
public open func f(): Unit {} // ok
}
class B <: A & I1 & I2 {
public override func f(): Unit {} // ok
}
// case 3
interface I1 {
func f(): Unit
}
interface I2 {
func f(): Unit {}
}
class A <: I1 & I2 {} // ok, f from I2
// case 4
interface I1 {
func f(): Unit {}
}
interface I2 {
func f(): Unit {}
}
class A <: I1 & I2 {} // error
class B <: I1 & I2 { // ok,
public func f(): Unit {}
}
// case 5
interface I1 {
func f(a: Int): Unit {}
}
interface I2 {
func f(a: Int): Unit {}
}
open class A {
public open func f(a: Int): Unit {}
}
open class B <: A & I1 & I2{ // ok, f from A
}
Rules for Overloading Functions During Interface Implementation
The functions in the parent and child scope must use the same names but different parameter lists.
The following examples show some cases of function overloading when a type implements an interface. Note that when a type implements an interface, implementation needs to be provided for the overloaded function declaration.
Example 1: In I1 and I2, the function f is declared with different parameter lists respectively. During class C implementation, fs whose parameter type is Unit and Int32 are implemented at the same time.
interface I1 {
func f(): Unit
}
interface I2 {
func f(a: Int32): Unit
}
class C <: I1 & I2 {
public func f(): Unit {} // The f in I1 needs to be implemented.
public func f(a: Int32): Unit {} // The f in I2 needs to be implemented.
}
Example 2: In I1 and I2, the default function f is defined with different parameter lists respectively. f does not need to be implemented in C.
interface I1 {
func f() {}
}
interface I2 {
func f(a: Int32) {}
}
class C <: I1 & I2 {
}
Example 3: In I1, a function whose name is f and parameter type is Unit is declared. In I2, a function whose name is f and parameter type is Int32 is defined. In class C, the f function whose parameter type is Unit must be implemented.
interface I1 {
func f(): Unit
}
interface I2 {
func f(a: Int32):Unit {
return
}
}
class C <: I1 & I2 {
public func f(): Unit {
return
}
}
Any Interface
The Any interface is an empty interface built in the language. By default, all interface types inherit the Any interface, and all non-interface types implement the Any interface. Therefore, all types can be used as subtypes of the Any type.
class A {}
struct B {}
enum C { D }
main() {
var i: Any = A() // ok
i = B() // ok
i = C.D // ok
i = (1, 2) // ok
i = { => 123 } // ok
return 0
}
The Any interface can be explicitly declared in the type definition. If the Any interface is not explicitly declared, it will be implicitly implemented by the compiler. However, the Any interface cannot be re-implemented through extension.
class A <: Any {} // ok
class B {} // Implicit implement Any
extend B <: Any {} // error
Overriding, Overloading, Hiding, and Redefinition
Overriding
Definition of Overriding
When you define a non-abstract instance function for a type with the same name and open semantics as that of its supertype, the optional override can be used as the modifier to override the function of the supertype. Comply with the following rules when overriding functions:
-
The name of the function must be the same as that of the function to be overridden.
-
The parameter list of the function must be the same as that of the function to be overridden.
The same parameter list means that the functions have the same parameter types and number of parameters.
-
The return type of the function is the same as or its subtype of that of the function to be overridden.
-
If functions in multiple parent scopes are overridden by the same function, the overriding rule for each function is determined by the other rules above.
Example:
-
If the function
fin theIinterface has the same parameter list and return type for theC1andC2classes, the overriding requirements are met. -
If
f1has the same parameter list for theC1andC2classes, the return type inC1isFather, and the return type inC2isChild, the overriding requirements are met becauseChildis a subtype ofFather.
open class Father {}
class Child <: Father {}
open class C1 {
public open func f() {}
public open func f1(): Father { Father() }
}
interface I {
func f() {}
}
class C2 <: C1 & I {
public override func f() {} // OK.
public override func f1(): Child { Child() } // OK.
}
Some of the details to note include:
Functions modified by
privatein a class are not inherited and cannot be accessed in subclasses.Static functions cannot override instance functions.
Calling Overriding Functions
If a function of a type overrides a function of its supertype and the function is called in the program, the compiler selects the version of the function to be executed based on the type to which the runtime object points.
In the following example, the f function is defined in the C1 class. The subclass C2 of C1 overrides f. In addition, the a and b variables of the C1 type are defined, the object myC1 of C1 is assigned to a, and the object myC2 of C2 is assigned to b. When a and b are used to call f, the corresponding function is selected based on the actual type at runtime.
open class C1 {
public open func f(): Unit {
return
}
}
class C2 <: C1 {
public override func f(): Unit {
return
}
}
var myC1 = C1()
var myC2 = C2()
// Assign the object of the superclass C1 to the variable of the C1 type.
var a: C1 = myC1
// Assign the object of the superclass C2 to the variable of the C1 type.
var b: C1 = myC2
// Invokes f of C1 based on the object type of at runtime
var c = a.f()
// Invokes f of C2 based on the object type of at runtime
var d = b.f()
Overloading
For details about the definition and calling of function overloading, see chapter [Function Overloading].
Overloading is not allowed between static member functions and instance member functions of classes or interfaces. If a static member function and an instance member function of a class or interface (such as a member function defined by the class or interface and inherited from the superclass or superinterface) have the same name, a compilation error is reported.
open class Base {}
class Sub <: Base {}
open class C{
static func foo(a: Base) {
}
}
open class B <: C {
func foo(a: Sub) { // Error
C.foo(Sub())
}
}
class A <: B {
// Static and instance functions cannot be overloaded.
static func foo(a: Sub) {} // Error
}
During overloading resolution, the functions defined in a type and its subtype are treated in the same scope priority.
Hiding
Members of a type cannot hide members of its supertype. Otherwise, a compilation error is reported.
In the following example, both the C1 and C2 classes have the instance variable x with the same name. As a result, an error is reported during compilation.
open class C1 {
let x = 1
}
class C2 <: C1 {
let x = 2 // error
}
Redefinition
Redefining a Function
When you define a non-abstract static function for a type with the same name as that of its supertype, the optional redef can be used as the modifier to redefine the function of the supertype. Comply with the following rules when redefining functions:
-
The name of the function must be the same as that of the function to be redefined.
-
The parameter list of the function must be the same as that of the function to be redefined.
The same parameter list means that the functions have the same parameter types and number of parameters.
-
The return type of the function is the same as or its subtype of that of the function to be redefined.
-
If the function to be redefined is a generic function, the type variable constraints of the redefining function must be looser or the same as those of the function to be redefined.
-
If functions in multiple parent scopes are redefined by the same function, the redefinition rule for each function is determined by the other rules above.
Example:
-
If the
ffunction has the same parameter list and return types for theC1andC2classes, the redefinition requirements are met. -
If
f1has the same parameter list for theC1andC2classes, and the return type inC1isFather, and the return type inC2isChild, the redefinition requirements are met becauseChildis a subtype ofFather.
open class Father {}
class Child <: Father {}
open class C1 {
public static func f() {}
public static func f1(): Father { Father() }
}
interface I {
static func f() {}
}
class C2 <: C1 & I {
public redef static func f() {} // OK.
public redef static func f1(): Child { Child() } // OK.
}
Example: If the f and g functions in the Base class are generic functions, and the subclasses E and F meet the requirements that a redefining function has looser or the same type variable constraints as the function to be redefined, the compilation is successful. If the subclass D does not meet the requirements, an error is reported during the compilation.
// C <: B <: A
open class Base {
static func f<T>(a: T): T where T <: B {...}
static func g<T>(): T where T <: B {...}
}
class D <: Base {
redef static func f<T>(a: T): T where T <: C {...} // Error, stricter constraint
redef static func g<T>(): T where T <: C {...} // Error, stricter constraint
}
class E <: Base {
redef static func f<T>(a: T): T where T <: A {...} // OK, looser constraint
redef static func g<T>(): T where T <: A {...} // OK, looser constraint
}
class F <: Base {
redef static func f<T>(a: T): T where T <: B {...} // OK, same constraint
redef static func g<T>(): T where T <: B {...} // OK, same constraint
}
The redef modifier cannot be used for a static initializer (because static initializers cannot be explicitly called). Otherwise, the compiler reports an error.
Calling a Redefined Function
If a function of a type redefines that of its supertype and the function is called in a program, the compiler selects which version of the function to execute based on the type.
In the following example, the f function defined in the C1 class is redefined in its subclass C2. When C1 and C2 are used to call f, the corresponding function is selected based on their types during compilation.
open class C1 {
static func f(): Unit {
return
}
}
class C2 <: C1 {
redef static func f(): Unit {
return
}
}
// Invokes f of C1
var c = C1.f()
// Invokes f of C2
var d = C2.f()
Access Control Level Restriction
Access modifiers within types are ranked at different levels based on their access scopes as follows:
public > protected > default > private
In this context, the behavior across access levels is specified as follows:
-
When a class inherits another class, if an instance member function of the subclass overrides that of the superclass, or a static member function of the subclass redefines that of the superclass, the access level of the subclass member function cannot be lower than that of the superclass member function.
-
When a type implements an interface, if a member function of the type implements an abstract function in the interface, the access level of the member function of the type cannot be lower than that of the abstract function.
The following is a code example of access level restriction:
open class A {
protected open func f() {}
}
interface I {
func m() {} // public by default
}
class C <: A & I {
private override func f() {} // Error: the access control of override function is lower than the overriden function
protected func m() {} // Error: the access control of function which implements abstract function is lower than the abstract function
}
Access Modifiers of a Non-top-level Member
The semantics of different access modifiers for non-top-level members are as follows:
private: visible only to the current type or extended definition.internal: visible only in the current package and its subclasses (including nested subclasses).protected: visible in the current module and the subclasses of the current class.public: visible in and out of the module.
| Type/Extend | Package & Sub-Packages | Module & Sub-Classes | All Packages | |
|---|---|---|---|---|
private | Y | N | N | N |
internal | Y | Y | N | N |
protected | Y | Y | Y | N |
public | Y | Y | Y | Y |
The access modifier of a type member can be different from that of the type itself. The default modifier for a type member except interface is internal. (Default modifiers specify the modifier semantics when modifiers are omitted. These default modifiers can also be explicitly written.) The member functions and properties in interfaces cannot write access modifiers. Their access level is public.
Restrictions on the Use of Generics in Classes and Interfaces
Duplicate Function Signatures Due to Instantiation Types
When you define a generic class, the following definitions of the C1 class and member functions are valid because functions can be overloaded.
open class C1<T> {
public func c1(a: Int32) {} // ok
public func c1(a: T) {} // ok
}
interface I1<T> {
func i1(a: Int32): Unit // ok
func i1(a: T): Unit // ok
}
var a = C1<Int32>() // error
class C2 <: C1<Int32> {...} // error
var b: I1<Int32> // error
class C3 <: I1<Int32> {...} // error
However, when the C1<T> class needs to be instantiated as the C1<Int32> class, the signatures of the two functions are the same. In this case, an error is reported where the C1<Int32> type is used. Similarly, when the I1<Int32> interface needs to be instantiated, the two function signatures declared in the interface are duplicate. In this case, an error is reported.
Generic Member Functions of Classes and Interfaces
In Cangjie, generic parameters cannot be declared for non-static abstract functions and functions modified by the open keyword in classes.
interface Bar {
func bar<T>(a: T): Unit // error
}
abstract class Foo {
func foo<T>(a: T): Unit // error
public open func goo<T>(a: T) { } // error
}
class Boo {
public open func Boo<T>(a: T) { } // error
}
For more information, see [Generics].
Properties
A property is a special syntax. It does not store values like a field. Instead, it provides a getter and an optional setter to indirectly retrieve and set values.
By using properties, data operations can be encapsulated into access functions. The use of properties is the same as that of common fields, which means that you can perform data operations without being aware of the underlying implementation. In this way, mechanisms such as access control, data monitoring, tracing and debugging, and data binding can be implemented easily.
Properties have the same syntax as fields and can be used as expressions or assigned values.
The following is a simple example where b is a typical property that encapsulates external access to a.
class Foo {
private var a = 0
mut prop b: Int64 {
get() {
print("get")
a
}
set(value) {
print("set")
a = value
}
}
}
main() {
var x = Foo()
let y = x.b + 1 // get
x.b = y // set
}
Property Syntax
The syntax rules of properties are as follows:
propertyDefinition
: propertyModifier* 'prop' identifier ':' type propertyBody?
;
propertyBody
: '{' propertyMemberDeclaration+ '}'
;
propertyMemberDeclaration
: 'get' '(' ')' block end*
| 'set' '(' identifier ')' block end*
;
propertyModifier
: 'public'
| 'private'
| 'protected'
| 'internal'
| 'static'
| 'open'
| 'override'
| 'redef'
| 'mut'
;
Properties without the mut modifier require a getter implementation. Properties declared by the mut modifier require separate getter and setter implementations.
In particular, you cannot define properties modified by mut or implement interfaces that have mut properties within extensions or definition bodies of the numeric, Bool, Unit, Nothing, Rune, String, Range, Function, Enum, and Tuple types.
In the following example, a is a property not declared by mut, and b is a property declared by mut.
class Foo {
prop a: Int64 {
get() {
0
}
}
mut prop b: Int64 {
get() {
0
}
set(v) {}
}
}
Properties not declared by mut do not have setters. Like fields declared by let, they cannot be assigned values.
class A {
prop i: Int64 {
get() {
0
}
}
}
main() {
var x = A()
x.i = 1 // error
}
Specifically, when a struct instance is declared by let, you cannot assign values to properties in the struct, just like fields declared by let.
struct A {
var i1 = 0
mut prop i2: Int64 {
get() {
i1
}
set(value) {
i1 = value
}
}
}
main() {
let x = A()
x.i1 = 2 // error
x.i2 = 2 // error
}
Properties differ from fields in that they cannot have initial values assigned and must have their types declared.
Property Definition
Properties can be defined in interfaces, classes, structs, enums, and extends.
class A {
prop i: Int64 {
get() {
0
}
}
}
struct B {
prop i: Int64 {
get() {
0
}
}
}
enum C {
prop i: Int64 {
get() {
0
}
}
}
extend A {
prop s: String {
get() {
""
}
}
}
You can declare an abstract property in an interface and abstract class, and its definition body can be omitted. When an abstract property is implemented in an implementation type, its name, type, and mut modifier must remain unchanged.
interface I {
prop a: Int64
}
class A <: I {
public prop a: Int64 {
get() {
0
}
}
}
Just as abstract functions in an interface can have default implementations, abstract properties in an interface can also have default implementations.
When an abstract property has a default implementation, the implementation type is not required to provide its own implementation (as long as it complies with the usage rules of the default implementation).
interface I {
prop a: Int64 { // ok
get() {
0
}
}
}
class A <: I {} // ok
Properties are classified into instance member properties and static member properties. Instance member properties can be accessed only by instances. You can use this expression in the getter or setter implementation of the property to access other instance members and static members. You cannot access instance members in the implementation of static member properties.
class A {
var x = 0
mut prop X: Int64 {
get() {
x + y
}
set(v) {
x = v + y
}
}
static var y = 0
static mut prop Y: Int64 {
get() {
y
}
set(v) {
y = v
}
}
}
Properties do not support overloading or overriding, and they cannot have the same name as other members at the same level.
open class A {
var i = 0
prop i: Int64 { // error
get() {
0
}
}
}
class B <: A {
prop i: Int64 { // error
get() {
0
}
}
}
Property Implementation
The getter and setter of a property correspond to two different functions.
- The getter function has the type
()->T, where T is the type of the property. When the property is used as an expression, the getter function is executed. - The setter function has the type
(T)->Unit, where T is the type of the property, and the parameter name must be explicitly specified. The setter function is executed when the property is assigned a value.
The implementation rules of properties are the same as those of functions. Properties can contain declarations and expressions, return can be omitted, and the return value must comply with the return type.
class Foo {
mut prop a: Int64 {
get() { // () -> Int64
"123" // error
}
set(v) { // (Int64) -> Unit
123
}
}
}
The behavior of accessing a property is consistent both inside and outside the property. Therefore, recursive access to a property may cause an infinite loop, which is the same as that of a function.
class Foo {
prop i: Int64 {
get() {
i // dead loop
}
}
}
Note that the setter of struct is a mut function. Therefore, you can modify the values of other fields in the setter, and this is restricted by the mut function.
Modifiers for Properties
Similar to functions, properties can be modified using modifiers. However, only the entire property can be modified. The getter or setter cannot be modified independently.
class Foo {
public mut prop a: Int64 { // ok
get() {
0
}
set(v) {}
}
mut prop b: Int64 {
public get() { // error
0
}
public set(v) {} // error
}
}
Access control modifiers private, protected, and public can be used for properties.
class Foo {
private prop a: Int64 { // ok
get() { 0 }
}
protected prop b: Int64 { // ok
get() { 0 }
}
public static prop c: Int64 { // ok
get() { 0 }
}
}
Like an instance function, an instance property can be modified using open and override.
For properties modified by open, a subtype can use override to override the implementation of the supertype (override is optional).
open class A {
public open mut prop i: Int64 {
get() { 0 }
set(v) {}
}
}
class B <: A {
override mut prop i: Int64 {
get() { 1 }
set(v) {}
}
}
Static properties, like static functions, can be modified using redef (redef is optional), allowing a subtype to re-implement the static properties from the supertype.
open class A {
static mut prop i: Int64 {
get() { 0 }
set(v) {}
}
}
class B <: A {
redef static mut prop i: Int64 {
get() { 1 }
set(v) {}
}
}
When a subtype uses override or redef on properties that are declared by let, it must re-implement the getter.
When a subtype uses override or redef on properties that are declared by the mut modifier in the supertype, it is allowed to re-implement only the getter or the setter, or both.
open class A {
public open mut prop i1: Int64 {
get() { 0 }
set(v) {}
}
static mut prop i2: Int64 {
get() { 0 }
set(v) {}
}
}
// case 1
class B <: A {
public override mut prop i1: Int64 {
get() { 1 } // ok
}
redef static mut prop i2: Int64 {
get() { 1 } // ok
}
}
// case 2
class B <: A {
public override mut prop i1: Int64 {
set(v) {} // ok
}
redef static mut prop i2: Int64 {
set(v) {} // ok
}
}
// case 3
class B <: A {
override mut prop i1: Int64 {} // error
redef static mut prop i2: Int64 {} // error
}
When a subtype uses override or redef on properties, it must retain the same mut modifier and the same type as that in the supertype.
class P {}
class S {}
open class A {
open prop i1: P {
get() { P() }
}
static prop i2: P {
get() { P() }
}
}
// case 1
class B <: A {
override mut prop i1: P { // error
set(v) {}
}
redef static mut prop i2: P { // error
set(v) {}
}
}
// case 2
class B <: A {
override prop i1: S { // error
get() { S() }
}
redef static prop i2: S { // error
get() { S() }
}
}
When a subtype uses override on a supertype's property, it can use super to call the instance property of the supertype.
open class A {
open prop v: Int64 {
get() { 1 }
}
}
class B <: A {
override prop v: Int64 {
get() { super.v + 1 }
}
}
Extensions
Extensions can be used to add new functionalities to any type that is visible to the current package, except functions, tuples, and interfaces.
You can add the following functionalities:
- Instance member function
- Static member function
- Operator overloading
- Instance member property
- Static member property
- Implementation interface
Extensions can add a functionality after a type is defined, but cannot damage the encapsulation of the original type. Therefore, the following functionalities are prohibited:
- Extensions cannot add fields.
- Extensions cannot add abstract members.
- Extensions cannot add
openmembers. - Extensions cannot use
overrideorredefon existing members. - Extensions cannot access private members of the original type.
Extension Syntax
A simple extension example is as follows:
extend String {
func printSize() {
print(this.size)
}
}
"123".printSize() // 3
The syntax of extension definition is as follows:
extendDefinition
: 'extend' extendType
('<:' superInterfaces)? genericConstraints?
extendBody
;
extendType
: (typeParameters)? (identifier NL* DOT NL*)* identifier (NL* typeArguments)?
| INT8
| INT16
| INT32
| INT64
| INTNATIVE
| UINT8
| UINT16
| UINT32
| UINT64
| UINTNATIVE
| FLOAT16
| FLOAT32
| FLOAT64
| CHAR
| BOOLEAN
| NOTHING
| UNIT
;
extendBody
: '{' extendMemberDeclaration* '}'
;
extendMemberDeclaration
: (functionDefinition
| operatorFunctionDefinition
| propertyDefinition
| macroExpression
) end*
;
The extend keyword is used to define an extension. The extension definition includes the extend keyword, optional generic parameters, the type being extended, optional implemented interfaces, optional generic constraints, and the body of the extension. {} cannot be omitted in the definition of an extension body.
Extensions can be defined only at the top level.
Extensions are classified into direct extensions and interface extensions. Direct extensions do not require the declaration of an additional interface.
Direct Extensions
Direct extensions do not require the declaration of an additional interface and can be used to directly add new functionalities to existing types.
class Foo {}
extend Foo {
func f() {}
}
main() {
let a = Foo()
a.f() // call extension function
}
Interface Extensions
Interface extensions can be used to add new functionalities to existing types and implement interfaces to enhance abstraction flexibility. When using interface extension, you must declare the interface being implemented.
interface I {
func f(): Unit
}
class Foo {}
extend Foo <: I {
public func f() {}
}
Using interface extension functionalities to implement interface I for a type is equivalent to implementing interface I during type definition, but the scope is subject to extension import and export limitations, as detailed in [Importing and Exporting Extensions].
func g(i: I) {
i.f()
}
main() {
let a = Foo()
g(a)
}
You can implement multiple interfaces within the same extension, separating them with &. The order of the interfaces does not matter.
interface I1 {
func f1(): Unit
}
interface I2 {
func f2(): Unit
}
interface I3 {
func f3(): Unit
}
class Foo {}
extend Foo <: I1 & I2 & I3 {
public func f1() {}
public func f2() {}
public func f3() {}
}
If the type being extended has already implemented an interface, it cannot be re-implemented through an extension, including any interfaces implemented through extensions.
interface I {
func f(): Unit
}
class Foo <: I {
func f(): Unit {}
}
extend Foo <: I {} // error, can not repeat the implementation of the interface
class Bar {}
extend Bar <: I {
func f(): Unit {}
}
extend Bar <: I {} // error, already implemented through the extension can not repeat the implementation
If the type being extended has directly implemented a non-generic interface, it cannot re-implement that interface through an extension. If the type has directly implemented a generic interface, it cannot re-implement that interface with the same type parameters through an extension.
interface I1 {}
class Foo <: I1 {}
extend Foo <: I1 {} // error
interface I2<T> {}
class Goo<T> <: I2<Int32> {}
extend<T> Goo<T> <: I2<Int32> {} // error
extend<T> Goo<T> <: I2<T> {} // ok
If the type being extended already contains the functions required by the interface, the interface extension cannot re-implement these functions, nor does it use the default implementations from the interface.
class Foo {
public func f() {}
}
interface I {
func f(): Unit
}
extend Foo <: I {} // ok
extend Foo {
public func g(): Unit {
print("In extend!")
}
}
interface I2 {
func g(): Unit {
print("In interface!")
}
}
extend Foo <: I2 {} // ok, default implementation of g in I2 is no longer used
Orphan extensions are prohibited. An orphan extension is an interface extension that is defined neither in the same package as the interface (including all interfaces in the interface inheritance chain) nor in the same package as the type being extended.
That is, interface extension allows only the following two cases:
- The interface extension and the type definition are in the same package.
- The interfaces implemented by the interface extension, along with all interfaces in the inheritance chain that have not been implemented by the type being extended, must all be in the same package.
In other cases, interface extension cannot be defined.
// package pkg1
public class Foo {}
public class Goo {}
// package pkg2
public interface Bar {}
extend Goo <: Bar {}
// package pkg3
import pkg1.Foo
import pkg2.Bar
extend Foo <: Bar {} // error
interface Sub <: Bar {}
extend Foo <: Sub {} // error
extend Goo <: Sub {} // ok, 'Goo' has implemented the interface 'Bar' on the inheritance chain in pkg2.
Members of Extensions
The members of extensions include static member functions, instance member functions, static member properties, instance member properties, and operator overloading functions.
Functions
Extensions can add functions to the type being extended. These functions can be generic and support generic constraints, overloading, default parameters, and named parameters. However, these functions cannot be abstract.
For example:
interface I {}
extend Int64 {
func f<T>(a: T, b!: Int64 = 0) where T <: I {}
func f(a: String, b: String) {}
}
Modifiers
Function definitions within an extension support the use of private, internal, protected, or public modifiers.
Functions modified by private can be used within the extension and are not visible externally.
Member functions modified by protected can be accessed in this module (restricted by export rules). When the type being extended is class, the functions can also be accessed within the subclass of that class.
The accessibility modifier of a function within an extension is internal by default.
// file1 in package p1
package p1
public open class Foo {}
extend Foo {
private func f1() {} // ok
public func f2() {} // ok
protected func f3() {} // ok
func f4() {} // visible in the package
}
main() {
let a = Foo()
a.f1() // error, can not access private function
a.f2() // ok
a.f3() // ok
a.f4() // ok
}
// file2 in package p2
package p2
import p1.*
class Bar <: Foo {
func f() {
f1() // error, can not access private function
f2() // ok
f3() // ok
f4() // error, can not access default function
}
}
Functions in an extension can be modified using static.
class Foo {}
extend Foo {
static func f() {}
}
Extensions of the struct type can define the mut function.
struct Foo {
var i = 0
}
extend Foo {
mut func f() { // ok
i += 1
}
}
The function definition in the extension cannot be modified by open, override, or redef.
class Foo {
public open func f() {}
static func h() {}
}
extend Foo {
public override func f() {} // error
public open func g() {} // error
redef static func h() {} // error
}
Properties
Extensions can add properties to the type being extended. These properties cannot be abstract.
For example:
extend Int64 {
mut prop i: Int64 {
get() {
0
}
set(value) {}
}
}
Modifiers
Property definitions within an extension support the use of private, internal, protected, or public modifiers.
Properties modified by private can be used within the extension and are not visible externally.
Properties modified by protected can be accessed in this module (restricted by export rules). When the type being extended is class, the functions can also be accessed within the subclass of that class.
The accessibility modifier of a property within an extension is internal by default.
// file1 in package p1
package p1
public open class Foo {}
extend Foo {
private prop v1: Int64 { // ok
get() { 0 }
}
public prop v2: Int64 { // ok
get() { 0 }
}
protected prop v3: Int64 { // ok
get() { 0 }
}
prop v4: Int64 { // visible in the package
get() { 0 }
}
}
main() {
let a = Foo()
a.v1 // error, can not access private property
a.v2 // ok
a.v3 // ok
a.v4 // ok
}
// file2 in package p2
package p2
import p1.*
class Bar <: Foo {
func f() {
v1 // error, can not access private function
v2 // ok
v3 // ok
v4 // error, can not access default function
}
}
Properties in an extension can be modified using static.
class Foo {}
extend Foo {
static prop i: Int64 {
get() { 0 }
}
}
The property definition in the extension cannot be modified by open, override, or redef.
class Foo {
open prop v1: Int64 {
get() { 0 }
}
static prop v2: Int64 {
get() { 0 }
}
}
extend Foo {
override prop v1: Int64 { // error
get() { 0 }
}
open prop v3: Int64 { // error
get() { 0 }
}
redef static prop v2: Int64 { // error
get() { 0 }
}
}
Generic extensions
When the type being extended is a generic type, there are two syntaxes available for extending its functionalities.
One is the non-generic extension described above. For generic types, a non-generic extension can be applied to specific instantiated generic types.
Any fully instantiated generic type is allowed after extend. The functionalities added for these types can be used only when the types are fully matched.
extend Array<String> {} // ok
extend Array<Int> {} // ok
In the extension, the type parameters of the generic type must comply with the constraints defined for the generic type. Otherwise, a compilation error is reported.
class Foo<T> where T <: ToString {}
extend Foo<Int64> {} // ok
class Bar {}
extend Foo<Bar> {} // error
The other is to introduce a generic extension of a generic parameter after extend. Generic extensions can be used to extend generic types that are not instantiated or partially instantiated.
Generic parameters can be declared after extend, and they must be directly or indirectly used in the extended generic type. The functionalities added for these types can be used only when the types and constraints are fully matched.
extend<T> Array<T> {} // ok
The generic variant introduced by the generic extension must be used in the type being extended. Otherwise, an error is reported, indicating that the generic variant is not used.
extend<T> Array<T> {} // ok
extend<T> Array<Option<T>> {} // ok
extend<T> Array<Int64> {} // error
extend<T> Int64 <: Equatable<T> { // error
...
}
Regardless of generic extensions or non-generic extensions, extensions for generic types cannot redefine members or re-implement interfaces.
When a generic variant of a generic extension is directly used in the type parameter of the type being extended, the corresponding generic variant implicitly introduces the generic constraint defined by the type being extended.
class Foo<T> where T <: ToString {}
extend<T> Foo<T> {} // T <: ToString
Generic parameters introduced by generic extension cannot be used for type being extended or interface being implemented. Otherwise, a compilation error is reported.
extend<T> T {} // error
extend<T> Unit <: T {} // error
Additional generic constraints can be used in the generic extension. Members or interfaces added in this way can be used only when instances of this type meet the generic constraints of the extension. Otherwise, an error is reported.
class Foo<T> {
var item: T
init(it: T) {
item = it
}
}
interface Eq<T> {
func equals(other: T): Bool
}
extend<T> Foo<T> <: Eq<Foo<T>> where T <: Eq<T> {
public func equals(other: Foo<T>) {
item.equals(other.item)
}
}
class A {}
class B <: Eq<B> {
public func equals(other: B) { true }
}
main() {
let a = Foo(A())
a.equals(a) // error, A has not implement Eq
let b = Foo(B())
b.equals(b) // ok, B has implement Eq
}
A generic type cannot re-implement the same interface. For the same generic type, whether fully instantiated or not, re-implementing the same interface is not allowed. Otherwise, a compilation error is reported.
interface I {}
extend Array<String> <: I {} // error, can not repeatedly implement the same interface
extend<T> Array<T> <: I {} // error, can not repeatedly implement the same interface
interface Bar<T> {}
extend Array<String> <: Bar<String> {} // error, can not repeatedly implement the same interface
extend<T> Array<T> <: Bar<T> {} // error, can not repeatedly implement the same interface
For the same generic type, whether fully instantiated or not, defining members with the same type or signature is not allowed. Otherwise, a compilation error is reported.
// case 1
extend Array<String> {
func f() {} // error, cannot be repeatedly defined
}
extend<T> Array<T> {
func f() {} // error, cannot be repeatedly defined
}
// case 2
extend Array<String> {
func g(a: String) {} // error, cannot be repeatedly defined
}
extend<T> Array<T> {
func g(a: T) {} // error, cannot be repeatedly defined
}
// case 3
extend<T> Array<T> where T <: Int {
func g(a: T) {} // error, cannot be repeatedly defined
}
extend<V> Array<V> where V <: String {
func g(a: V) {} // error, cannot be repeatedly defined
}
// case 4
extend Array<Int> {
func g(a: Int) {} // ok
}
extend Array<String> {
func g(a: String) {} //ok
}
Access and Hiding in Extensions
Instance members of an extension can use this, whose meaning remains consistent with that in the type definition. You can also omit this when accessing members.
However, instance members of an extension cannot use super.
class A {
var v = 0
}
extend A {
func f() {
print(this.v) // ok
print(v) // ok
}
}
The extension cannot access the private member of the type being extended. The members modified by other modifiers comply with the visibility principle.
class A {
private var v1 = 0
protected var v2 = 0
}
extend A {
func f() {
print(v1) // error
print(v2) // ok
}
}
Extensions cannot hide any members of the type being extended.
class A {
func f() {}
}
extend A {
func f() {} // error
}
Extensions also cannot hide any members of the type being extended added by other extensions.
class A {}
extend A {
func f() {}
}
extend A {
func f() {} // error
}
You can extend the same type multiple times within the same package.
In an extension, you can directly use (without any prefix) members that are not modified by private from other extensions of the same type.
class Foo {}
extend Foo { // OK
private func f() {}
func g() {}
}
extend Foo { // OK
func h() {
g() // OK
f() // Error
}
}
When extending generic types, you can use additional generic constraints.
In addition to the preceding accessibility rules, the following constraints must be met to determine whether members in other extensions of the same type can be directly used in the extension of a generic type:
- If two extensions have the same constraints, they can directly use each other's members.
- If two extensions have different constraints, and there is an inclusion relationship between the two, the extension with the stricter constraint can directly use members from the extension with the looser constraint, but not the other way around.
- If two extensions have different constraints and there is no inclusion relationship, then neither extension can directly use members from the other.
For example: Assume that there are two extensions of the same type E<X>, where the constraints on X in extension 1 are stricter than those in extension 2. In this case, extension 1 can directly use members in extension 2, but extension 2 cannot directly use those in extension 1.
// B <: A
class E<X> {}
interface I1 {
func f1(): Unit
}
interface I2 {
func f2(): Unit
}
extend<X> E<X> <: I1 where X <: B { // extension 1
public func f1(): Unit {
f2() // OK
}
}
extend<X> E<X> <: I2 where X <: A { // extension 2
public func f2(): Unit {
f1() // Error
}
}
Inheritance of Extensions
If the type being extended is class, the members being extended are inherited by its subclass.
open class A {}
extend A {
func f() {}
}
class B <: A {
func g() {
f() // ok
}
}
main() {
let x = B()
x.f() // ok
}
Note that if members are extended in the superclass, due to inheritance rules, the subclass cannot define members with the same name, nor can it override or re-implement them (function overloading is allowed).
open class A {}
extend A {
func f() {}
func g() {}
}
class B <: A {
func f() {} // error
override func g() {} // error
}
If the superinterface and subinterface are extended for the same type in the same package, the compiler checks the extension of the superinterface and then that of the subinterface.
class Foo {}
interface I1 {
func f() {}
}
interface I2 <: I1 {
func g() {}
}
extend Foo <: I1 {} // first check
extend Foo <: I2 {} // second check
Importing and Exporting Extensions
No modifier is allowed before extend. Extensions can be imported or exported only with the types or interfaces being extended.
Exporting Direct Extensions
When a direct extension and the type being extended are defined in the same package, if the extended type is exported, the extension is also exported; otherwise, the extension is not exported.
package pkg1
public class Foo {}
extend Foo {
public func f() {}
}
///////
package pkg2
import pkg1.*
main() {
let a = Foo()
a.f() // ok
}
When a direct extension and the type being extended are not defined in the same package, the extension is never exported and can only be used within the current package.
package pkg1
public class Foo {}
///////
package pkg2
import pkg1.*
extend Foo {
public func f() {}
}
func g() {
let a = Foo()
a.f() // ok
}
///////
package pkg3
import pkg1.*
import pkg2.*
main() {
let a = Foo()
a.f() // error
}
Exporting Interface Extensions
When an interface extension and the type being extended are in the same package, only the externally visible interface can be extended for the externally visible type.
package pkg1
public class Foo {}
interface I1 {
func f(): Unit
}
extend Foo <: I1 { // error
public func f(): Unit {}
}
public interface I2 {
func g(): Unit
}
extend Foo <: I2 { // ok
public func g(): Unit {}
}
///////
package pkg2
import pkg1.*
main() {
let a = Foo()
a.g() // ok
}
When an interface extension and the type being extended are not in the same package, the access level of the extension is the same as that of the corresponding interface. If multiple interfaces are extended, the extension's access level is public only when all interfaces are public.
package pkg1
public class Foo {}
public class Bar {}
///////
package pkg2
import pkg1.*
interface I1 {
func f(): Unit
}
public interface I2 {
func g(): Unit
}
extend Foo <: I1 & I2 { // not external
public func f(): Unit {}
public func g(): Unit {}
}
extend Bar <: I2 { // external
public func g(): Unit {}
}
Importing Extensions
An extension is imported together with the type being extended and the interface it implements. The imported extension cannot be specified.
package pkg1
public class Foo {}
extend Foo {
public func f() {}
}
///////
package pkg2
import pkg1.Foo // import Foo
main() {
let a = Foo()
a.f() // ok
}
In particular, because extensions cannot hide any members of the type being extended, an error is reported when the imported extension is redefined.
package pkg1
public class Foo {}
///////
package pkg2
import pkg1.Foo
public interface I1 {
func f(): Unit {}
}
extend Foo <: I1 {} // ok, external
///////
package pkg3
import pkg1.Foo
public interface I2 {
func f(): Unit {}
}
extend Foo <: I2 {} // ok, external
///////
package pkg4
import pkg1.Foo
import pkg2.I1 // error
import pkg3.I2 // error
Generics
If a declaration uses angle brackets to declare type parameters, it is called a generic declaration. When generic declarations are used, type parameters can be replaced with other types. You can define a generic function by declaring type parameters in a function signature. You can define a generic type by declaring type parameters in the definitions of class, interface, struct, enum, or type alias.
Type Parameters and Type Variables
In Cangjie, type parameters are represented by identifiers enclosed in <>. You can provide multiple type parameters by separating them with , inside the <>, such as<T1, T2, T3>, where T1, T2, T3 are type parameters.
Once type parameters are declared, they can be used as types.
When identifiers are used to reference declared type parameters, these identifiers are called type variables.
The syntax of type parameters is as follows:
typeParameters
: '<' identifier (',' identifier)* '>'
;
Generic Constraints
In Cangjie, <: can be used to indicate that one type is a subtype of another. By declaring this relationship, you can impose constraints on generic type parameters, ensuring they can only be replaced with types that meet specific constraints.
Generic constraints are declared by the operator <: following where and consists of a lower bound and an upper bound. The part on the left of <: is referred to as the lower bound of the constraint, which can only be a type variable. The part on the right of <: is referred to as the upper bound of the constraint, which can be a type. When the upper bound is a type, the constraint is a subtype constraint. The upper bound can be of any type.
A type variable may be subject to multiple upper bound constraints at the same time. Multiple upper bounds of the same type parameter must be connected using &, which simplifies cases where a type parameter has several upper bounds. In essence, the type variable has multiple generic constraints. Constraints for different type variables should be separated by ,.
The syntax for declaring a constraint is as follows:
upperBounds
: type ('&' type)*
;
genericConstraints
: 'where' identifier '<:' upperBounds (',' identifier '<:' upperBounds)*
;
The following example shows how to declare a generic constraint.
interface Enumerable<U> where U <: Bounded {...}
interface Comparable<T> {...}
func collectionCompare<T>(a: T, b: T) where T <: Comparable<T> & Seqence {...}
func sort<T, V>(input: T)
where T <: Enumerable<V>, V <: Object {...}
If the constraints of type variables X and Y are the same, it means that all types that meet the constraints of X meet those of Y, and all types that meet the constraints of Y also meet those of X.
If the constraints of the type variable X are stricter than those of Y, it means that all types that meet the constraints of X meet those of Y, but not the other way around.
If the constraints of X are stricter than those of Y, the constraints of Y are looser than those of X.
If two generic types have the same constraints, it means that they have the same number of type variables and all corresponding type variable constraints are identical.
If the constraint of a generic type A is stricter than that of another generic type B, it means that the number of type variables of A is the same as that of B, but the constraints of all type variables of A are stricter than those in B.
If the constraint of a generic type A is stricter than that of another generic type B, the constraint of B is looser than that of A.
For example, in the following two generics C and D, if I1 <: I2, then the constraint of C is stricter than that of D:
class C<X, Y> where X <: I1, Y <: I1 and class D<X, Y> where X <: I2, Y <: I2
Type Variance
Before moving on to generic functions and generic types, let's learn about the following type variance to comprehend the subtype relationships of generic types in Cangjie.
Definition
If A and B are types, and T is a type constructor with a type parameter X, then:
-
When
T(A) <: T(B)if and only ifA <: B,Tis covariant at X. -
When
T(A) <: T(B)if and only ifB <: A,Tis contravariant at X. -
When
T(A) <: T(B)if and only ifA = B,Tis invariant.
Generic Invariance
In Cangjie, all generics are invariant. This means that if A is a subtype of B, there is no subtype relationship between ClassName<A> and ClassName<B>. The purpose is to ensure runtime safety.
Variance of Function Types
The parameter types of functions are contravariant, while the return types of functions are covariant. Suppose there is a function f1 with the type S1 -> T1, and another function f2 with the type S2 -> T2. If S2 <: S1 and T1 <: T2, then the type of f1 is a subtype of the type of f2.
Covariance of Tuple Types
There is a subtype relationship between tuples. If each element of one tuple is a subtype of the corresponding element in another tuple, then the first tuple is a subtype of the second one. Suppose there are tuples Tuple1 and Tuple2, with types (A1, A2, ..., An) and (B1, B2, ..., Bn). If for all i, it holds that Ai <: Bi, then Tuple1 <: Tuple2.
Restrictions on Variance
Currently, variance relationships are prohibited in two scenarios:
- Interfaces implemented by types other than class. The subtype relationship between such types and their interfaces cannot serve as a basis for covariance and contravariance.
- Interfaces implemented by the implementation types through extensions. The subtype relationship between such types and their interfaces cannot serve as a basis for covariance and contravariance.
These restrictions affect not only variance relationships but also the determination of override for subtype.
A type that is not applicable to the type variance relationship cannot be used as the basis for subtypes when overriding occurs.
interface I {
func f(): Any
}
class Foo <: I {
func f(): Int64 { // error
...
}
}
Constraints on Upper Bounds
For a constraint L <: T<T1..Tn>, its upper bound is T<T1..Tn>. The declaration of T's type parameters may need to meet some constraints. After the argument Ti is replaced, these constraints must be implicitly introduced into the current context of the declaration. For example:
interface Eq<T> {
func eq(other: T): Bool
}
interface Ord<T> where T <: Eq<T> {
func lt(other: T): Bool
}
func foo<T>(a: T) where T <: Ord<T> {
a.eq(a)
a.lt(a)
}
For the foo function, even though only T is constrained by Ord, if Ord's T type is constrained by Eq, then the eq function from Eq can be used within the foo function. In this way, the constraint of the foo function is actually T <: Eq & Ord. Therefore, when a generic parameter meeting a constraint is declared, the constraints on the upper bounds are also introduced.
This rule of implicitly introducing constraints on upper bounds is also applicable to other generic declarations. For example:
interface A {}
class B<T> where T <: A {}
class C
Note: Although the constraints of the upper bound in the current declaration are implicitly introduced, the current declaration can still explicitly write these constraints.
## Definitions of Generic Functions and Generic Types
### Generic Functions
If a function declares one or more type parameters, it is called a generic function. In terms of syntax, the type parameters follow the function name and are enclosed in `<>`. If there are multiple type parameters, they are separated by `,`.
```cangjie
func f<T>() {...}
func f1<T1, T2, T3, ...>() {...}
The syntax of a generic function is as follows:
functionDefinition
: functionModifierList? 'func' identifier
typeParameters functionParameters
(':' type)? genericConstraints?
block?
;
Note that:
- When
<and>are used, they are parsed as generics first. If they are parsed successfully, they are generic expressions. Otherwise, they are comparison operators. For example:
(c <d , e> (f))
This expression is parsed as a function call expression.
Generic Types
If a class, interface, struct, enum, or type alias definition declares one or more type parameters, it is called a generic type. In syntax, type parameters follow the type name (such as class name or interface name) and are enclosed by <>. If there are multiple type parameters, they are separated by ,.
class C<T1, T2> {...} // generic class
interface I<T1> {...} // generic interface
type BinaryOperator<T> = (T, T) -> T // generic typealias
For the syntax of generic declarations, see the corresponding sections.
Generic Type Check
Checking Generic Declarations
Sanity Check for Generic Constraints
For all type parameters in a declaration, the upper bound of each type parameter can be classified into two cases:
-
The upper bound is also a type variable, which may be itself or another type variable.
-
When the upper bound is of a specific type, it can be further divided into two situations:
-
The first situation involves upper bounds that are class or interface types, which are referred to as class-related types.
-
The second situation involves upper bounds that are not class or interface types, which are referred to as class-independent types.
In Cangjie, the upper bounds of one or more specific types for a type variable must meet the following rules:
-
All upper bounds can only be the same case; they must either all be class-related types or class-independent types. For example,
T <: Object & Int32is invalid. -
When the upper bound is a class-related type, if there are multiple upper bounds of classes, these classes must be on the same inheritance chain. This restriction does not apply to interfaces. Conflicting member definitions are not allowed in multiple generic upper bounds of a type variable. Specifically, conflicts refer to functions with the same name or operators that do not constitute overloads and there is no subtype relationship between return types.
-
When the upper bound is a class-independent type, only one class-independent specific type can be included. Two different types are not allowed. For example,
T <: Int32 & Boolis invalid. -
Recursive constraints cannot exist when the upper bound of a type variable is a class-independent type. A recursive generic constraint is one where the upper bound's type parameter directly or indirectly depends on the lower bound type variable. For example, the recursive generic constraint
T <: Option<T>is invalid becauseOptionis declared using theenumkeyword. Similarly,T <: U, U <: (Int32) -> Tis invalid because the function is of the value type and theTtype indirectly depends on itself throughU.
-
Type Compatibility Check
The purpose of type checking for generic declarations is to ensure that the generic type is compatible with its surrounding type context and the access to member functions and variables is valid. For example:
open class C {
func coo() {...}
}
class D <: C {...}
interface Tr {
func bar(): Int64
}
func foo<T>(a: T) {
var b: C = a // error, T is not a subtype of C
a.coo() // error, T has no member function coo
a.bar() // error, T did not implement Tr
}
Three errors are reported in the foo function body of the preceding sample code. The causes are as follows:
-
The expected type of the variable
bdeclared in thefoofunction isC. Therefore, you need to check whetherTis a subtype ofD, that is,T <: C. However, this constraint does not exist in the context ofT. As a result, an error is reported during compilation of the variable declaration. -
The generic type
Tis irrelevant toCin the current context. Therefore, the member functioncooofCcannot be accessed. -
Similarly, the
Ttype does not have the constraint ofTr. Therefore, the member functionbarofTrcannot be accessed.
To pass the type check, add a generic constraint before the declaration body.
open class C {
func coo() {...}
}
interface Tr {
func bar(): Int64
}
func foo<T>(a: T) where T <: C & Tr {
var b: C = a // OK, T is a sub type of C now
a.coo() // OK, T is a sub type of C, so it has coo member function
a.bar() // OK, T is constrained by Tr
}
In particular, if a generic upper bound of a type variable T includes a function type or a type that overloads the function call operator (), a value of type T may be considered as a function call. When the upper bound is a function type, the return type of the call is a return type of an upper bound of T. When the upper bound is a type that overloads the function call operator (), the return type of the call is a return type of a matched function call operator in the upper bound type.
Checking the Use of Generic Declarations
The primary purpose of checking the use of generic declarations is to substitute the arguments into the generic declaration's type parameters, and then verify whether the constraints are valid.
If the C type is used to call the foo function defined in the previous section:
main(): Int64 {
foo<C>(C()) // error C does not implement Tr
return 0
}
In this case, an error is reported indicating that type C does not implement Tr. This is because the constraints in the foo function specify T <: C & Tr. When T is substituted with C, C <: C is valid, but C <: Tr is invalid.
If the declaration of implementing Tr is added to the C type, the T <: Tr constraint can be met.
extend C <: Tr {
func bar(): Int64 {...}
}
In particular, when an interface is used as a generic constraint, the type instantiated for the generic variable must fully implement the interface static function in all upper bound constraints.
This means that if a static function exists in an interface that is used as a generic constraint, the interface or abstract class that does not implement the corresponding static function cannot be used as the type instantiated for the generic variable.
interface I {
static func f(): Unit
}
func g<T>(): Unit where T <: I {}
main() {
g<I>() // error
return 0
}
Depth of Generic Instantiation
To prevent infinite loops or memory exhaustion during generic instantiation, the number of instantiation layers is limited during compilation. For example:
class A<T>{
func test(a: A<(A<T>, A<T>)>): Bool {true}
}
main(): Int64 {
var a : A<Int32> = A<Int32>()
return 0
}
This code throws an infinite instantiation error.
Generic Instantiation
The process of forming a corresponding non-generic language structure from a generic declaration after all type parameters are determined is called generic instantiation.
Instantiation of Generic Functions
func show<T>(a: T) where T <: ToString {
a.toString()
}
After T is substituted with Int32, the following instance is generated (assuming that show$Int32 is the internal representation after compiler instantiation; similar representation is used in the following):
func show$Int32(a: Int32) {
a.toString()
}
Restrictions on Instantiating Generic Functions
In Cangjie, generic functions cannot be declared in the following cases:
- Non-static abstract functions in interfaces and abstract classes
- Instance member functions in classes and abstract classes marked with the open keyword
- Operator overloading functions
For example, the declaration and definition of the following functions are invalid.
abstract class AbsClass {
public func foo<T>(a: T): Unit // error: abstract generic function in abstract class
public open func bar<T>(a: T) { // error: open generic function in abstract class
...
}
}
interface IF {
func foo<T>(a: T): Unit // error: abstract generic function in interface
}
open class Foo {
public open func foo<T>(a: T): Unit { // error: open generic function in class
...
}
}
The following generic functions are valid.
class Foo {
static func foo<T>(a: T) {...} // generic static function in class
func bar<T>(a: T) {...} // generic non-open function in class
}
abstract class Bar {
func bar<T>(a: T) {...} // generic non-open function in abstract class
}
struct R {
func foo<T>(a: T) {...} // generic function in struct
}
enum E {
A | B | C
func e<T>(a: T) {...} // generic function in enum
}
Instantiation of Classes and Interfaces
class Foo<T> <: IBar<T>{
var a: T
init(a: T) {
this.a = a
}
static func foo(a: T) {...}
public func bar(a: T, b: Int32): Unit {...}
}
interface IBar<T> {
func bar(a: T, b: Int32): Unit
}
When T=Int32 is specified, the declaration of the following instance is generated:
class Foo$Int32 <: IBar$Int32 {
var a: Int32
static func foo(a: Int32) {...}
func bar(a: Int32) {...}
}
interface IBar$Int32 {
func bar(a: Int32, b: Int32)
}
Instantiation of Structs
The instantiation of a struct is very similar to that of a class.
struct Foo<T> {
func foo(a: T) {...}
}
When T=Int32 is specified, the declaration of the following instance is generated:
struct Foo$Int32 {
func foo(a: Int32) {...}
}
Instantiation of Enums
enum Either<T,R> {
Left(T)
| Right(R)
}
When Either is given the parameters Int32 and Bool, the type is instantiated as follows:
enum Either$Int32$Bool {
Left(Int32)
| Right(Bool)
}
When a generic declaration is used, for example, a generic function is called or a value of a generic type is constructed, what actually take effect are instances with all type parameters determined during compilation. That is, instantiation occurs only after all generic parameters are of a specific type.
Generic Function Overloading
Cangjie supports overloading between generic functions as well as between generic functions and non-generic functions. For details about overloading, see [Function Overloading].
When a function is called, overloading is processed as follows:
Step 1: Construct a candidate set for function calls. Functions included in this set must pass type checks and are callable. For details, see [Candidate Set of Overloaded Functions]. There are additional rules for generic functions, which will be detailed below.
Step 2: Select the best matching function based on the scope priority rules (see [Scope Priority]) and the best matching rules (see [Best Matching Rules]). If the unique best matching function is not determined, an error is reported.
Step 3: If there are multiple argument types, determine the parameter types based on the best matching function. If the unique argument type is not determined, an error is reported.
When constructing the candidate set for function calls, pay attention to the following points for generic functions:
1. When a function is called, for example, generic function f, the candidate set may include either a partially instantiated generic function or a fully instantiated function. Which form enters the candidate set depends on the form of the call expression.
-
The call expression is in the format of
C<TA>.f(A), that is,fis a static member function of a generic type. The type is instantiated first, and then the type check of function call for the static member function of the instantiated type is performed. The function enters the candidate set after it passes the check. IfChas a type parameterX, the function that enters the candidate set isf', whereXis replaced withTAinf.$$ \sigma = [X \mapsto TA] $$ $$ f' = \sigma f $$
// The context contains the following types: Base, Sub, and Sub <: Base. class F<X> { static func foo<Y>(a: X, b: Y) {} // foo1 static func foo<Z>(a: Sub, b: Z) {} // foo2 } /* The functions that enter the candidate set are foo1 and partial instantiated foo2: foo<Y>(a:Base, b: Y) and foo<Z>(a: Sub, b: Z) */ var f = F<Base>.foo(Sub(), Base()) // foo2 -
The format of the call expression is
obj.f(A), andobjis an instance of the instantiated type of the generic type. That is,fis a non-static member function of a generic type.In the expression, the type of
objneeds to be determined first, and then the candidate set function is chosen based on the type ofobj. The type ofobjis the instantiated type. The type check of function call for the static member function of the instantiated type is performed. The function enters the candidate set after it passes the check.// The context contains the following types: Base, Sub, and Sub <: Base. class C<T, U>{ init (a: T, b: U) {} func foo(a: T, b: U) {} // foo1 func foo(a: Base, b: U) {} // foo2 } /* It is inferred that the type of obj is C<Sub, Rune>. The functions that enter the candidate set are instantiated foo1, foo2: foo(a:Sub, b:Rune) and foo(a: Base, b: Rune) */ main() { C(Sub(), 'a').foo(Sub(), 'a') // choose foo1 return 0 }
2. If no type parameter is provided when the function is called, that is, the function is called in the form of f(a), the generic function f that enters the candidate set must meet the following requirements:
-
Assuming
fis a generic function in the format off<X_1,...,X_m>(p1: T_1, ..., pn: T_n): R. No type parameter is provided in the call expression, so the format isf(a_1, ..., a_n).fcan infer a group of type parametersTA_1, ...,TA_mbased on the parameter type(A1, ...,An), which meet all generic constraints off. In addition, whenX_1, ...,X_mare replaced withTA_1, ...,TA_minf, it can pass the type check of function call. The check rules are as follows:- After the inferred type parameter
TA_1, ...,TA_mare substituted into the function parameter(T1, ...,Tn)off,(A1, ...,An)are the subtype of the substituted parameter type in the context where the call expression is located.
$$ \sigma = [X_1 \mapsto TA_1, ..., X_m \mapsto TA_m] $$ $$ \Delta \vdash (A1, ..., An) <: \sigma (T_{1},...,T_{n}) $$
- If the call expression provides the return type
RA, type check needs to be performed based on the return type. AfterX_1, ...,X_min the return typeRoffare replaced withTA_1, ...,TA_m, the substituted return type is the subtype ofRAin the context where the call expression is located.
- After the inferred type parameter
$$ \sigma = [X_1 \mapsto TA_1, ..., X_m \mapsto TA_m] $$ $$ \Delta \vdash \sigma R <: RA $$
3. If type parameters are provided during function call, that is, the function call format is f<TA>(a), the f that enters the candidate set must meet the following requirements:
- The number of type parameters of
fis the same as that ofTA. The type parameterTAmeets the generic constraint off. After the type parameters are substituted, the function can pass the type check of function call.
Overloading
Function Overloading
Definition of Function Overloading
In Cangjie, function overloading refers to the situation where a function name corresponds to multiple function definitions with different parameter types in a scope.
For details about the definition of function overloading, see Definition of Function Overloading.
Note that:
-
A static member function of the class, interface, or struct type and an instance member function cannot be overloaded.
-
Static member functions and instance member functions in extensions of the same type cannot be overloaded, except when both functions are private in different extensions of the same type.
-
A constructor of the enum type, a static member function, and an instance member function cannot be overloaded.
In the following example, the instance member function f and static member function f in class A are overloaded. As a result, a compilation error is reported.
class A {
func f() {}
//Static member function can not be overloaded with instance member function.
static func f(a: Int64) {} // Error
}
In the following example, the instance member function g and static member function g in the extension of class A are overloaded. As a result, a compilation error is reported.
class A {}
extend A {
func g() {}
static func g(a: Int64) {} // Error
}
In the following example, the instance member function h and static member function h are in different extensions of class A and are both private. No compilation error is reported.
extend A {
private func h() {}
}
extend A {
private static func h(a: Int64) {} // OK
}
In the following example, the constructor f, instance member function f, and static member function f of enum E are overloaded. As a result, a compilation error is reported.
enum E {
f(Int64) // constructor
// Instance member function can not be overloaded with constructor.
func f(a: Float64) {} // Error
// Static member function can not be overloaded with instance member function or constructor.
static func f(a: Bool) {} // Error
}
When making a function call, the function definition to be used must be determined based on the types of the arguments and the context in the function call expression. The steps are as follows:
Step 1: Construct a function candidate set.
Step 2: Resolve function overloading.
Step 3: Determine the argument types.
Candidate Set of Overloading Functions
When the function f is called, it is necessary to first determine which functions can be called. A set of functions that can be called is referred to as a candidate set of overloading functions (referred to as "candidate set"), and is used for function overloading resolution.
To construct a function candidate set, perform the following steps:
- Search for a visible function set. Based on the form of the call expression and the context, identify all the visible functions.
- Perform a type check of function call on functions in the visible function set. Functions that pass the type check (that is, functions that can be called) are added to the candidate set.
Visible Function Set
The visible function set must meet the following rules:
-
Functions are visible in the scope.
-
The visible function set is determined based on whether
fis a common function or a constructor.2.1. If
fis a constructor, the visible function set is determined according to the following rules:
-
If
fis the name of a type with a constructor, the visible function set includes only the constructor defined inf. -
If
fis the name of anenumconstructor, the visible function set includes only the constructor namedfin the specifiedenum. -
If
fissuper, the call expression is within a class or interface, andfincludes only the direct superclass constructor of the class or interface where the call expression is located. -
If
fis a type name without a constructor, the visible function set is empty.2.2. If
fis a common function, the visible function set is determined based on whether there is qualified prefix. -
If
f(...)is directly called by its name without a qualified prefix, the visible function set includes the following functions namedf:(1) Local functions visible in the scope are included.
(2) If the function call occurs in the static context of a
class,interface,struct,enum, orextend, the static member functions of the type are included.(3) If the function call occurs in the non-static context of a
class,interface,struct,enum, orextend, the static and non-static member functions of the type are included.(4) Global functions defined in the package where the function call occurs are included.
(5) Functions declared in the extension defined in the package where the function call occurs are included.
(6) Functions imported in the package through
importwhere the function call occurs are included. -
For a function call
c.f(...)with a qualified prefix, the visible function set is determined based on the qualified prefix.(1) If
cis a package name, the visible function includes only the global functionfdefined inpackage c, including the functions re-exported throughpublic importinc, but not the functions imported only throughimportinc.(2) If
cis a type name defined byclass,interface,struct, orenum, the visible function set includes only the static member methodfofc.(3) If
cisthis, that is,this.f(...), the call expression occurs in the definition or extension ofclass,interface,struct, orenum. If it appears in the type definition, the visible function set includes only the non-static member methodfin the current type (including the inherited method but excluding the method in the extension). If it appears in a type extension, the visible function set contains the non-static member methodfin the type and the non-static member methodfin the extension.(4) If
cissuper, that is,super.f(...), it indicates that the call expression occurs in aclassorinterface, and the visible function set includes only the non-static member methodfof the superclass or superinterface of the current type.(5) If the function call is in the format of
object name.f (...):If the object type contains the member method `f`, the visible function set includes only the member methods named `f`.
2.3. If f is a type instance, the visible function set is determined based on the () operator overloading function defined in its type or type extension.
Assuming that the type of `f` is T, the visible function set includes:
(1) The `()` operator overloading function defined within T.
(2) The `()` operator overloading function defined in the extension of T (visible in the current scope).
(3) If T has a superclass, it also includes the `()` operator overloading function inherited from the superclass.
(4) If T implements an interface, the `()` operator overloading function with default implementations inherited from the interface is also included.
- For the generic function
f, the generic function that enters the visible function set may be a partially instantiated generic function or a fully instantiated function. The form of the call expression determines which kind of generic functions can enter the visible function set. For details, see [Generic Function Overloading].
Type Check
Type check is performed on functions in the visible function set. Only functions that pass the function call type check can enter the candidate set.
open class Base {}
class Sub <: Base {}
func f<X, Y>(a: X, b: Y) {} // f1, number of type parameters is not matched
func f<X>(a: Base, b: X) where X <: Sub {} // f2
func test() {
f<Sub>(Base(), Sub()) // candidate set: { f2 }
}
Note that:
- If an argument has multiple types, and one of those types can pass the type check, it is considered that the argument can pass the type check of the candidate function.
open class A {}
open class B <: A {}
func g(a: A): B { //g1
B()
}
func g(a: B): B { //g2
B()
}
func g(a: Int64): Unit {} //g3
// (A)->B <: (B)->B <: (B)->A
func f(a: (A)->B) {} //f1, g1 can pass the type check
func f(a: (B)->B) {} //f2, g1, g2 can pass the type check
func f(a: (B)->A) {} //f3, g1, g2 can pass the type check
func f(a: Bool) {} //f4, no g can pass the type check
func test() {
f(g) // candidate set: { f1, f2, f3 }
}
Function Overloading Resolution
If the candidate set is empty, that is, there is no matching item, a compilation error is reported.
If there is only one function in the candidate set, that is, there is only one matching item, the matched function is selected for calling.
If there are multiple functions in the candidate set, there are multiple matching items. The function with the highest scope level in the candidate set is selected based on the rules in [Scope Priority]. If there is only one function with the highest scope level, this function is selected. Otherwise, the best matching item is selected according to the [Best Matching Rules]. If the best matching item cannot be determined, a compilation error is reported.
Scope Priority
The higher the scope level, the higher the priority a function has during function overloading resolution. That is, if two functions are in the candidate set, the one with a higher scope level is selected. If two functions have the same scope level, the best matching item is selected based on the rules outlined in [Best Matching Rules].
The following should be noted regarding scope priority:
-
Functions defined in the superclasses and subclasses in the candidate set are treated as having the same scope priority during function overloading resolution.
-
Functions defined in a type and its extension in the candidate set are treated as having the same scope priority during function overloading resolution.
-
Functions defined in different extensions of the same type are treated as having the same scope priority during function overloading resolution.
-
Operator overloading functions defined in extensions or types and built-in operators are treated as having the same scope priority during function overloading resolution.
-
Apart from the preceding type scope levels, the scope levels of other situations are determined based on the rules in [Scope Levels].
/* According to the scope-level precedence principle, two functions in the candidate set, with different scope-levels, are preferred to the one with higher scope-level. */
func outer() {
func g(a: B) {
print("1")
}
func g(a: Int32) {
print("3")
}
func inner() {
func g(a: A) { print("2") }
func innermost() {
g(B()) // Output: 2
g(1) // Output: 3
}
g(B()) // Output: 2
innermost()
}
inner()
g(B()) // Output: 1
}
In the preceding example, the g function is called in the innermost function, and the argument B() is passed. According to the scope priority rules, the function with a higher scope level is preferentially selected. Therefore, the function g defined in line 7 is selected.
/* The inherited names are at the same scope level as the names defined or declared in the class. */
open class Father {
func f(x: Child) { print("in Father") }
}
class Child <: Father {
func f(x: Father) { print("in Child") }
}
func display() {
var obj: Child = Child()
obj.f(Child()) // in Father
}
In the preceding example, the display function calls the f function and the argument Child() is passed. The functions in the superclasses and subclasses that constitute overloading has the same scope level. The f(x: Child) {...} defined in the Father class is selected based on the best matching rules.
In the following example, the f function defined in the C type and the f function defined in the extension of the C type are treated as having the same scope priority during function overloading.
open class Base {}
class Sub <: Base {}
class C {
func f(a: Sub): Unit {} // f1
}
extend C {
func f(a: Base): Unit {} // f2
func g() {
f(Sub()) // f1
}
}
var obj = C()
var x = obj.f(Sub()) // f1
Best Matching Rules
The candidate set has multiple functions with the highest priority: { f_1, ..., f_n}. These functions are called matching items. If there is one matching item f_m that is a better match than other matching items, f_m is the best matching function.
For comparing two matching items and determining which one is a better match, the comparison is based on the parameters of the two matching items and is performed in two steps:
Step 1: Determine the number and sequence of parameters to be compared.
-
If a function parameter has a default value, optional parameters without specified arguments are not compared.
open class Base {} class Sub <: Base {} func f(a!: Sub = Sub(), b!: Int32 = 2) {} // This is f1, func f(a!: Base = Base()) {} // This is f2. var x1 = f(a: Sub()) // parameters involved in comparison in f1 is only a -
If a function has named parameters, the sequence of arguments may be different from that of parameters. In this case, the sequence of parameters used for comparison must be the same as that of arguments, so that the parameters of each candidate function used for comparison correspond correctly.
Step 2: Compare parameters of the two matching items to determine which one is a better match.
For two matching items f_i and f_j, f_i is considered a better match than f_j if the following conditions are met:
For a function call expression: e<T1, ..., T_p>(e_1, ...,e_m, a_m+1:e_m+1, a_k:e_k), if the number of arguments is k, the number of parameters used for comparison is k.
For the comparison of f_i and f_j, the parameters (a_i1, ..., a_ik) and (a_j1, ..., a_jk) are compared, and the corresponding parameter types are (A_i1, ..., A_ik) and (A_j1, ..., A_jk).
If passing the parameters (a_i1, ..., a_ik) of f_i to f_j as arguments allows f_j to pass the function call type check, while passing the parameters (a_j1, ..., a_jk) of f_j to f_i as arguments does not allow f_i to pass the function call type check, then f_i is considered a better match than f_j. The following is an example:
func f_i<X1,..., Xp>(a_i1: A_i1,..., a_ik: A_ik) {// f_i may not have type parameters
f_j(a_i1, ..., a_ik) // If this call expression can pass the type checking
}
func f_j<X1,..., Xq>(a_j1: A_j1,..., a_jk: A_jk) {// f_j may not have type parameters
f_i(a_j1, ..., a_jk) // And this expression cannot pass the type checking
}
The following are some examples of function overloading resolutions:
interface I3 {}
interface I1 <: I2 & I3 {}
interface I2 <: I4 {}
interface I4 <: I3 {}
func f(x: I4) {} // f1
func f(x: I3) {} // f2
class C1 <: I1 {}
var obj = C1()
var result = f(obj) // choose f1, because I4 <: I3
open class C1 {}
open class C2 <: C1 {}
class C3 <: C2 {}
func f(a: C1, b: C2, c: C1) {} // f1
func f(a: C3, b: C3, c: C2) {} // f2
func f(a: C3, b: C2, c: C1) {} // f3
// function call
var x = f(C3(), C3(), C3()) // f2
open class A {}
class B <: A {}
func foo<X>(a: X, b: X): Int32 {} // foo1
func foo(a: A, b: B): Int32 {} // foo2
func foo<X>(a: A, b: X): Int32 {} // foo3
foo(A(), A()) // Error: cannot resolve.
foo(A(), 1) // foo3. foo3 is the only function in candidate set.
Determining Argument Types
If there are multiple types for the arguments:
After the best matching function is determined, if only one type T among the argument types can pass the type check of the function, the type of the argument is T. Otherwise, a compilation error is reported.
// Sub <: Base
func f(a: (Base)->Int64, b : Sub) {} //f1
func f(a: (Sub)->Int64, b: Base) {} //f2
func g(a: Base): Int64 { 0 } // g1
func g(a: Sub): Int64 { 0 } // g2
func test() {
f(g, Base()) // Error, both of g can pass f2's type check.
f(g, Sub()) // OK, only g1 passes f1's type check.
}
Operator Overloading
Cangjie defines a series of operators represented by special characters (for details, see [Expressions]), such as arithmetic operators (+, -, *, and /), logical operators (!, &&, ||), and function call operators (()). By default, the operands of these operators can only be of specific types. For example, the operands of arithmetic operators can only be of the numeric type, and the operands of logical operators can only be of the Bool type. If you want to extend some operand types supported by operators or allow custom types to use these operators, you can use operator overloading.
If you need to overload an operator opSymbol on a type Type, you can define an operator function named opSymbol for Type. In this way, when an instance of Type uses opSymbol, the operator function named opSymbol is automatically called.
The syntax for defining an operator function is as follows:
operatorFunctionDefinition
: functionModifierList? 'operator' 'func'
overloadedOperators typeParameters?
functionParameters (':' type)?
(genericConstraints)? ('=' expression | block)?
;
The definition of an operator function is similar to that of a common function. The differences are as follows:
- When defining an operator function, add the
operatormodifier before thefunckeyword. overloadedOperatorsis the operator function name. It must be an operator, and only fixed operators can be overloaded. For details about the operators that can be overloaded, see [Operators That Can Be Overloaded].- The number of parameters of the operator function must be the same as the number of operands required by the operator.
- An operator function can be defined only in class, interface, struct, enum, and extend.
- An operator function has the semantics of an instance member function. Therefore, the
staticmodifier cannot be used. - An operator function cannot be a generic function.
In addition, pay attention to the following:
- The inherent priority and law of associativity of an operator is not changed after it is overloaded. For details, see [Expressions].
- Whether a unary operator is used as a prefix operator or a suffix operator is the same as the default usage of this operator. There is no ambiguity because there is no operator in Cangjie that can be used as both a prefix and a suffix.
- The operator function is called in the inherent way of the operator. (That is, the operator function to be called is determined by the number and type of operands.)
If you want to overload an operator opSymbol for a type Type, you need to define an operator function named opSymbol on the type. You can define operator functions in either of the following ways:
-
Use
extendto add operator functions to types so that operators can be overloaded for these types. This method is required for types that cannot directly contain function definitions (types other thanstruct,class,enum, andinterface). -
For types that can directly contain function definitions (including class, interface, enum, and struct), define operator functions in the types directly.
Defining Operator Functions
An operator function implements an operator on a specific type. Therefore, the difference between defining an operator function and defining a common instance member function lies in the parameter type convention.
-
For unary operators, operator functions have no parameter, and there is no requirement on the return value type.
For example, assuming that
opSymbol1is a unary operator, the operator functionopSymbol1is defined as follows:
operator func opSymbol1(): returnType1 {
functionBody1
}
-
For binary operators, operator functions have only one parameter
right, and there is no requirement on the return value type.For example, assuming that
opSymbol2is a binary operator, the operator functionopSymbol2may be defined as follows:
operator func opSymbol2(right: anyType): returnType2 {
functionBody2
}
Similarly, for a type TypeName that defines an operator function, these operators may be used on an instance of the TypeName type like common unary or binary operators (retaining the inherent usage of each operator). In addition, the operator function is an instance function. Therefore, using the overloaded operator opSymbol on the instance A of the TypeName type is actually the syntactic sugar of the function call A.opSymbol(arguments) (different operator functions are called based on the operator type, number of parameters, and type).
The following example describes how to define an operator function in the class type to overload a specific operator for the class type.
Suppose we want to implement the unary minus (-) and binary addition (+) operations on a class type named Point (containing two member variables x and y of the Int32 type). - obtains negative values of two member variables x and y in a Point instance, and then return a new Point object. + sums up the two member variables x and y in each Point instance, and then return a new Point object.
First, define a class named Point, and define operator functions named - and + in the class, as shown in the following:
class Point {
var x: Int32 = 0
var y: Int32 = 0
init (a: Int32, b: Int32) {
x = a
y = b
}
operator func -(): Point {
return Point(-x, -y)
}
operator func +(right: Point): Point {
return Point(x + right.x, y + right.y)
}
}
Then, the - unary operator and the + binary operator can be used directly in a Point instance.
main(): Int64 {
let p1 = Point(8, 24)
let p2 = -p1 // p2 = Point(-8, -24)
let p3 = p1 + p2 // p3 = Point(0, 0)
return 0
}
Scopes of Operator Functions and Search Strategy for Calling Operator Functions
This section describes the scope of the operator function (see [Names, Scopes, Variables, and Modifiers]) and the search strategy when the operator function is called.
Scopes of Operator Functions
An operator function has the same scope level as a common function defined or declared in the same position.
Search Strategy for Calling Operator Functions
This section describes the search strategy when the operator function is called (that is, the operator is used). Only the search strategy of the binary operator (denoted as op) is described here, because the search of the unary operator function is a sub-case of the search of the binary operator function and follows the same policy.
Step 1: Determine types of the left operand lOperand and the right operand rOperand (assuming that their types are lType and rType respectively).
Step 2: In the current scope of the call expression lOperand op rOperand, search for all operator functions whose names are op and whose right operand type is rType that are associated with lType. If there is only one such operator function, the expression call is converted into a call to this operator function. If no such function is found, move on to step 3.
Step 3: Repeat step 2 in a scope with a lower priority. If no matching operator function is found in the lowest-priority scope, the search is terminated and a compilation error ("function not defined") is generated.
Operators That Can Be Overloaded
The following table lists all operators that can be overloaded (in descending order of priority).
| Operator | Description |
|---|---|
() | Function call |
[] | Indexing |
! | NOT: unary |
- | Negative: unary |
** | Power: binary |
* | Multiply: binary |
/ | Divide: binary |
% | Remainder: binary |
+ | Add: binary |
- | Subtract: binary |
<< | Bitwise left shift: binary |
>> | Bitwise right shift: binary |
< | Less than: binary |
<= | Less than or equal: binary |
> | Greater than: binary |
>= | Greater than or equal: binary |
== | Equal: binary |
!= | Not equal: binary |
& | Bitwise AND: binary |
^ | Bitwise XOR: binary |
| ` | ` |
Note that:
-
Apart from the operators listed in the preceding table, other operators (see [Operators] for the complete operator list) cannot be overloaded.
-
If a binary operator other than a relational operator (
<,<=,>,>=,==, or!=) is overloaded for a type, and the return type of the operator function is the same as the type of a left operand or its subtype, the type supports the corresponding compound assignment operator. If the return type of an operator function is different from the type of a left operand or its subtype, a type mismatch error is reported when the corresponding compound assignment operator is used. -
Cangjie does not support custom operators. That is, only
operatorsin the preceding table can be overloaded. -
There are no specific type requirements for the input parameters or return value when overloading the function call operator (
()). -
If the
Ttype already supports an operator in the preceding table by default, a redefinition error is reported when an operator function with the same signature is implemented for theTtype through extension. For example, overloading arithmetic operators, bitwise operators, or relational operators with the same signature and are already supported by numeric types, overloading relational operators with the same signature forRune, or overloading logical operators, equal-to operators, or not-equal-to operators with the same signature for the Bool type, will all result in a redefinition error.
Special scenarios are as follows:
-
The
()operator overloading function cannot be called usingthisorsuper. -
For the enum type, the constructor form is preferentially matched when both constructor form and the
()operator overloading function form are met.
// Scenario for `this` or `super`.
open class A {
init(x: Int64) {
this() // error, missing argument for call with parameter list: (Int64)
}
operator func ()(): Unit {}
}
class B <: A {
init() {
super() // error, missing argument for call with parameter list: (Int64)
}
}
// Scenario for enum constructor.
enum E {
Y | X | X(Int64)
operator func ()(a: Int64){a}
operator func ()(a: Float64){a}
}
main() {
let e = X(1) // ok, X(1) is to call the constructor X(Int64).
X(1.0) // ok, X(1.0) is to call the operator () overloading function.
let e1 = X
e1(1) // ok, e1(1) is to call the operator () overloading function.
Y(1) // oK, Y(1) is to call the operator () overloading function.
}
Index Operator Overloading
Index operators ([]) have two forms: let a = arr[i] (for obtaining a value) and arr[i] = a (for assigning a value). They can be distinguished based on whether they contain the special named parameter value. You are not required to use both forms at the same time for index operator overloading. You can use only either of them as required.
In let a = arr[i], a sequence of one or more non-named parameters of any type of the corresponding overloaded operator is enclosed in brackets ([]). Other named parameters are not allowed. The return type can be any type.
class A {
operator func [](arg1: Int64, arg2: String): Int64 {
return 0
}
}
func f() {
let a = A()
let b: Int64 = a[1, "2"]
// b == 0
}
In arr[i] = a, a sequence of one or more non-named parameters of any type of the corresponding overloaded operator is enclosed in brackets ([]). The expression on the right of = corresponds to the named parameter of the overloaded operator. There can be only one named parameter, which must be named as value, cannot have a default value, and can be of any type. The return type must be Unit.
Note that value is only a special mark and does not need to be called as a named parameter when an index operator is used to assign a value.
class A {
operator func [](arg1: Int64, arg2: String, value!: Int64): Unit {
return
}
}
func f() {
let a = A()
a[1, "2"] = 0
}
In particular, the numeric, Bool, Unit, Nothing, Rune, String, Range, Function, and tuple types do not support overloading index operators.
Packages and Modules
In Cangjie, a program is built as a package, which is the minimum unit for compilation. A package can define subpackages to form a tree structure. A package without a superpackage is called a root package. The entire tree consisting of the root package and its subpackages (including subpackages of subpackages) is called a module. The name of the module is the same as that of the root package. A module is the minimum release unit of Cangjie.
A package consists of one or more source code files. The source code files of the same package must be stored in the same directory, and the source code files in the same directory must belong to the same package. The directory of a subpackage is a subdirectory of its superpackage's directory.
Packages
Package Declaration
The package declaration starts with the keyword package, followed by the names of all packages in the path from the root package to the current package, and the names are separated by . (the path itself is not the package name).
The syntax for package declaration is as follows:
packageHeader : packageModifier? (MACRO NL*)? PACKAGE NL* fullPackageName end+ ; fullPackageName : (packageNameIdentifier NL* DOT NL*)* packageNameIdentifier ; packageNameIdentifier : Ident | contextIdent ; packageModifier : PUBLIC | PROTECTED | INTERNAL ;
Each package has a package name, which is a unique identifier of the package.
Except for the root package, the package name must match the name of the directory it resides in.
The package declaration must be in the first line of the file (excluding comments and whitespace characters). Each file can have only one package declaration. In particular, files in the root package can omit the package declaration. For files without a package declaration, default is used as the package name.
// ./src/main.cj
// Leaving package declaration out is equivalent to 'package default'
main() {
println("Hello World")
}
package can be modified by internal, protected, or public. The default modifier of package is public. (Default modifiers can be explicitly specified, and are used when no access modifiers are specified) The package declaration in different files of the same package must use the same access modifier. In particular, the root package cannot be modified by internal or protected.
internal: Members are visible only in the current package, its superpackage (only the upper-level superpackage), and its subpackages (including subpackages of subpackages). The package or its members can be imported to the superpackage (only the upper-level superpackage) and the subpackages (including subpackages of subpackages) of the current package.protected: Members are visible only in the current module. Other packages in the same module can import the package or its members, but packages from other modules cannot access them.public: Members are visible both inside and outside the module. Other packages can import this package or its members.
Package Members
Package members are classes, interfaces, structs, enums, type aliases, global variables, extensions, and functions declared at the top level. For details about the content included in the top-level declaration, see the corresponding section.
The superpackages and subpackages of the current package are not its members, and accessing them requires the package import mechanism. The names of the packages that are not imported are not in the top-level scope.
In the following example, package a.b is a subpackage of package a.
// src/a.cj
package a
let a = 0 // ok
// src/b/b.cj
package a.b
let a = 0 // ok
let b = 0 // ok
In the following example, package a.b is a subpackage of package a.
// src/a.cj
package a
let u = 0 // ok
let _ = b.x // error: undeclared identifier 'b'
let _ = a.u // error: undeclared identifier 'a'
let _ = a.b.x // error: undeclared identifier 'a'
// src/b/b.cj
package a.b
let x = 1 // ok
let _ = a.u // error: undeclared identifier 'a'
let _ = a.b.x // error: undeclared identifier 'a'
let _ = b.x // error: undeclared identifier 'b'
In particular, a subpackage cannot have the same name as a member in the current package to ensure that the name in the access path is unique.
Access Modifiers
In Cangjie, access modifiers can be used to protect access to elements such as types, variables, and functions. Cangjie has four access modifiers.
privateinternalprotectedpublic
Modifying Top-level Members
The semantics of different access modifiers when modifying top-level members are as follows:
private: Members are visible only in the current file and cannot be accessed from other files.internal: Members are visible only in the current package and its subpackages (including subpackages of subpackages). These members can be accessed from the same package without being imported or from subpackages (including subpackages of subpackages) of the package through imports.protected: Members are visible only in the current module. Files in the same package can access these members without imports. Packages in the same module can access them through imports, but packages in different modules cannot access them.public: Members are visible both inside and outside the module. Files in the same package can access these members without imports, and other packages can access them through imports.
| File | Package & Sub-Packages | Module | All Packages | |
|---|---|---|---|---|
private | Y | N | N | N |
internal | Y | Y | N | N |
protected | Y | Y | Y | N |
public | Y | Y | Y | Y |
The access modifiers and default modifiers supported by different top-level declarations are specified as follows:
package: supportsinternal,protected, andpublic, withpublicas the default modifier. In particular, whenpackageis modified byinternal, it is also visible to its superpackage (only the upper-level superpackage).import: supports all access modifiers, withprivateas the default modifier.- Other top-level declarations support all access modifiers, with
internalas the default modifier.
Modifying Non-top-level Members
The semantics of different access modifiers when modifying non-top-level members are as follows:
private: Members are visible only to the current type or extended definition.internal: Members are visible only in the current package and its subpackages (including subpackages of subpackages).protected: Members are visible in the current module and subclasses of the current class.public: Members are visible both inside and outside the module.
| Type/Extend | Package & Sub-Packages | Module & Sub-Classes | All Packages | |
|---|---|---|---|---|
private | Y | N | N | N |
internal | Y | Y | N | N |
protected | Y | Y | Y | N |
public | Y | Y | Y | Y |
The access modifier of a type member can be different from that of the type itself. The default modifier for a type member except interface is internal. (Default modifiers can be explicitly specified, and are used when no access modifiers are specified) The member functions and properties in interfaces cannot write access modifiers. Their access level is public.
Validity Check of Access Modifiers
The hierarchy of access levels in Cangjie is as follows: public > protected > internal > private.
Type access levels are detailed as follows:
- The access level of a non-general type is determined by the access modifier specified in its type declaration.
- The access level of an instantiated generic type is the same as the lowest access level between the generic type and an argument of the generic type.
The level of the access modifier of a declaration cannot be higher than that of the class used in the declaration. Specifically:
- The access level of a variable or property declaration cannot be higher than that of its type.
- The access level of a function declaration cannot be higher than that of the parameter type, return value type, and type upper bound in the
whereconstraint. - The access level of the type alias cannot be higher than that of the original type.
- The access level of a type declaration cannot be higher than that of the type upper bound in the
whereconstraint. - The access level of a subpackage cannot be higher than that of its superpackage.
- The access modifier of
importcannot have a higher access level than its import declaration.
private open class A {}
protected let a = A() // error: 'protected' declaration 'a' uses 'private' type 'A'
let (a, b) = (A(), 1) // error: 'internal' declaration 'a' uses 'private' type 'A'
func f(_: A) {} // error: 'internal' declaration 'f' uses 'private' type 'A'
func f() { A() } // error: 'internal' declaration 'f' uses 'private' type 'A'
func f<T>() where T <: A {} // error: 'internal' declaration 'f' uses 'private' type 'A'
public type X = A // error: 'public' declaration 'X' uses 'private' type 'A'
public type ArrayA = Array<A> // error: 'public' declaration 'ArrayA' uses 'private' type 'A'
protected struct S<T> where T <: A {} // error: 'protected' declaration 'S' uses 'private' type 'A'
// src/a.cj
public package a
// src/a/b/b.cj
protected package a.b // ok
// src/a/b/c/c.cj
public package a.b.c // error
In particular, the subclass access level and superclass access level during class inheritance, and the subtype access level and superinterface access level during type implementation or interface inheritance are not restricted by the preceding rules.
private open class A {}
public enum E { U | V }
interface I {}
public class C <: A {} // ok
public interface J <: I {} // ok
extend E <: I {} // ok
Package Import
Import is a mechanism used to introduce other packages or members of other packages to the current Cangjie program.
If the source code does not contain the import declaration, the current file can access only the members in the current package and the members imported by the compiler by default. The import declaration allows the compiler to find the required external name when compiling the Cangjie file.
The import statement must be placed after the package declaration and before other declarations or definitions in the file.
The syntax related to import is as follows:
importList : importModifier? NL* IMPORT NL* importContent end+ ; importSingle : (packageNameIdentifier NL* DOT NL*)* (identifier | packageNameIdentifier) ; importSpecified : (identifier '.')+ identifier ; importAlias : importSingle NL* AS NL* identifier ; importAll : (packageNameIdentifier NL* DOT NL*)+ MUL ; importMulti : (packageNameIdentifier NL* DOT NL*)* LCURL NL* (importSingle | importAlias | importAll) NL* (COMMA NL* (importSingle | importAlias | importAll))* NL* COMMA? NL* RCURL ;
The import syntax has the following forms:
- Single import
- Alias import
- Full import
- Batch import
You can use import to import one or more packages or members of other packages. You can also use the as syntax to define an alias for the imported name. If the imported name is a package, you can use it to access members of the package (the subpackage is not a member of the package), but the package name itself cannot be used as an expression.
package a
public let x = 0
package demo
import a
main() {
println(a.x) // ok, prints 0
}
Cyclic dependencies between any two packages are not allowed, even within the same module. For any two packages p1 and p2, if p2 or members of p2 are imported to p1, p1 and p2 have a dependency relationship, and p1 depends on p2. The dependency is transitive. If p1 depends on p2 and p2 depends on p3, p1 depends on p3. Cyclic dependency of packages refers to the situation where packages depend on each other.
package p.a
import p.b // error
pacakge p.b
import p.a // error
Do not use import to import the current package or members in the current package.
package a
import a // error
import a.x // error
public let x = 0
The scope level of the imported member is lower than that of the member declared in the current package. An imported non-function member is shadowed by a member with the same name in the current package. If an imported function member can constitute overloading with a function with the same name in the current package, the function resolution is performed based on the rules of [Generic Function Overloading] and [Function Overloading] during function call. If they do not constitute overloading, the function member is shadowed.
package a
public let x = 0
public func f() {}
import a.x // warning: imported 'x' is shadowed
import a.f
let x = 1
func f(x: Int64) { x }
let _ = f() // ok, found 'a.f'
let _ = f(1) // ok, found 'f' defined in this package
Single Import
The single import syntax is used to import a single member. The target member must be visible to the current package. The imported member name is used as the name that can be accessed in the current scope.
The last name of the path in the import syntax indicates the specified member. The name can be a top-level variable, function, type, or package.
The following is an example of importing a top-level variable, function, type, and package. There are two packages: a and b. Import the members of the a package to the b package.
package a
public let x = 0
public func f() { 0 }
public class A {}
import a.x
import a.f
import a.A
private func g(_: A) { x + f() } // ok
In the following example, c is a subpackage of a.
package a.c
public let y = 1
import a
private func g(_: a.A) { a.x + a.f() } // ok
privage func h(_: A) { // error: undeclared identifier 'A'
x + f() // error: undeclared identifier 'x' and 'f'
}
let _ = a.c.y // error: 'c' is not a member of 'a'
let _ = a // error: undeclared identifier 'a'
import a.c
let _ = c.y // ok
If a member imported through single import is shadowed by a member in the current package, the compiler displays an alarm indicating that the import is useless.
import a.x // warning: imported 'x' is shadowed
import a.f // warning: imported 'f' is shadowed
func f() { 1 }
let x = 1
let _ = f() // ok, call 'f' defined in this package, value is 1
Alias Import
You can use the as syntax to rename imported members during alias import. The content imported by alias is imported to the scope in the current package as an alias, not the original name. (However, the original name and alias can be imported separately.) The imported content can be a package or a member of a package.
package a
public let x = 0
public let y = 1
public func f() { 0 }
import a as pkgA
import a.x as x1
import a.x as x2 // ok
let _ = x // error: undeclared identifier 'x'
let _ = a.x // error: undeclared identifier 'a'
let _ = x1 // ok
let _ = x2 // ok
let _ = pkgA.x // ok
let _ = pkgA.x1 // error: 'x1' is not a member of 'pkgA'
Full Import
The * syntax is used to import all top-level members (excluding subpackages) that are visible to the current package from other packages.
Example:
package a
public let x = 0
public func f() { 0 }
public class A {}
import a.*
private func g(_: A) { x + f() } // ok
Unlike single import, the compiler does not display an alarm when an imported member is shadowed by a member in the current package during full import.
import a.*
let x = 1
func f() { x } // ok, 'x' defined in this package
let _ = f() // ok, call 'f' defined in this package, value is 1
If an imported member is not shadowed by a member in the current package, but the names of multiple imported members are the same, the compiler does not display an alarm. However, if the imported members with the same name do not constitute overloading, the name is unavailable in the current package. When this name is used, the compiler reports an error because it cannot find a unique name.
package b
public let x = 1
public func f(x: Int64) { x }
import a.*
import b.*
let _ = x // error: ambiguous 'x'
If the imported members with the same name constitute function overloading, the function resolution is performed based on the rules of [Generic Function Overloading] and [Function Overloading].
import a.*
import b.*
func f(b: Bool) { b }
let _ = f() // ok, call 'a.f'
let _ = f(1) // ok, call 'b.f'
let _ = f(true) // ok, call 'f' defined in this package
A full import with access modifiers does not import declarations with lower access level.
package a
protected import a.b.*
let _ = x // ok
let _ = y // ok
let _ = z // error: undeclared identifier 'z'
package a.b
public let x = 0
protected let y = 1
internal let z = 2
Batch Import
The {} syntax is used for importing multiple members in a import declaration during batch import. It is usually used to omit duplicate package path prefixes.
The curly braces ({}) imported in batches support single import, alias import, and full import, but do not support nested batch import.
import std.{
time,
fs as fileSystem,
io.*,
collection.{HashMap, HashSet} // syntax error
}
The prefix of {} can be left empty.
import {
std.time,
std.fs as fileSystem,
std.io.*,
}
The batch import syntax is equivalent to the syntax of using independent import syntax for multiple times.
import std.{
os.process,
time,
io.*,
fs as fileSystem
}
The preceding is equivalent to:
import std.os.process
import std.time
import std.io.*
import std.fs as fileSystem
Import Name Conflict Check
If the names of multiple single imports are the same (including repeated imports) and do not constitute function overloading, and the name is not shadowed in the package, the compiler displays a name conflict alarm, indicating that the name is unavailable in the package. When this name is used, the compiler reports an error because it cannot find a unique name. If the name is shadowed by a member in the current package, the compiler displays an alarm indicating that the import is useless.
package b
public let x = 1
public func f(x: Int64) { x }
package c
public let f = 0
import a.x // warning: imported 'x' is shadowed
import a.x // warning: imported 'x' is shadowed
import b.x // warning: imported 'x' is shadowed
let x = 0
let y = x // y = 0
import a.x
import a.x // warning: 'x' has been imported
import b.x // warning: 'x' has been imported
let _ = x // error: ambiguous 'x'
If the imported members with the same name constitute function overloading or an imported member can constitute overloading with a function with the same name in the current package, the function resolution is performed based on the rules of [Generic Function Overloading] and [Function Overloading].
import a.f
import b.f
func f(b: Bool) { b }
let _ = f() // ok, call 'a.f'
let _ = f(1) // ok, call 'b.f'
let _ = f(true) // ok, call 'f' defined in this package
The handling rules for multiple alias imports of the same name, or for alias imports that conflict with a name defined in the current package, are the same as those for single import.
import a.x as x1 // warning: imported 'x1' is shadowed
let x1 = 10
let _ = x1 // ok, 'x1' defined in this package
package b
public let x = 1
public func f(x: Int64) { x }
import a.x as x1
import a.x as x1 // warning: 'x1' has been imported
import b.x as x1 // warning: 'x1' has been imported
let _ = x1 // error: ambiguous 'x1'
import a.f as g
import b.f as g
func g(b: Bool) { b }
let _ = g() // ok, call 'a.f'
let _ = g(1) // ok, call 'b.f'
let _ = g(true) // ok, call 'g' defined in this package
If one of the conflicting imports comes from a full import, the compiler does not display an alarm, but the conflicting declarations are unavailable.
Name conflict check is performed based on the equivalent single imports, alias imports, and multiple imports.
Access Modifiers of import
import can be modified by the access modifiers private, internal, protected, and public. The import modified by public, protected, or internal can re-export the imported members (unless the imported members are unavailable in the package due to name conflicts or being shadowed). Other packages can import these re-exported objects through import according to the access rules of [Access Modifiers]. Specifically:
private import: The imported content can be accessed only in the current file.privateis the default modifier ofimport. Animportwithout an access modifier is equivalent to aprivate import.internal import: The imported content can be accessed in the current package and its subpackages (including subpackages of subpackages). Explicitimportis required for non-current packet access.protected import: The imported content can be accessed in the current module. Explicitimportis required for non-current packet access.public import: The imported content can be accessed externally. Explicitimportis required for non-current packet access.
In the following example, b is a subpackage of a, and a re-exports the f function that is defined in b through public import:
package a
public let x = 0
public import a.b.f
internal package a.b
public func f() { 0 }
import a.f // ok
let _ = f() // ok
//// case 1
package demo
public import std.time.Duration // warning: imported 'Duration' is shadowed
struct Duration {}
//// case 2
// ./a.cj
package demo
public import std.time.Duration
// ./b.cj
package demo
func f() {
let a: Duration = Duration.second // ok, access the re-exported 'Duration'
}
//// case 3
// ./a/a.cj
package demo.a
public let x = 0
// ./b/b.cj
package demo.b
public import demo.a.* // warning: imported 'x' is shadowed, will not re-export 'demo.a.x'
var x = 0
//// case 4
// ./a/a.cj
package demo.a
public let x = 0
// ./b/b.cj
package demo.b
public let x = 0
// ./c/c.cj
package demo.c
public import demo.a.* // warning, because there are duplicate names, will not re-export 'demo.a.x'
public import demo.b.* // warning, because there are duplicate names, will not re-export 'demo.b.x'
It is worth noting that packages cannot be re-exported. If a package is imported by an import, the import cannot be modified by public, protected, or internal.
public import a.b // error: cannot re-export package
Program Entry
The syntax of the program entry is as follows:
mainDefinition
: 'main' functionParameters (':' type)? block
;
The entry of the Cangjie program is main, which is not a function. Each package can have at most one program entry main which can be defined only at the top level. When a package is compiled into a library, main is ignored by the compiler and is not recognized as a program entry.
If the package is compiled by generating an executable file (specified by the user), the compiler searches for main at the top level of the package. If no main is found or multiple main entries are found, the compiler reports an error. If only one main is found, the compiler checks its parameters and return value types.
A main may have no parameters or have parameters of the Array<String> type, and the return value type can be Unit or integer.
Exceptions
When developing software systems, detecting and handling errors in the program is often quite challenging. To ensure the correctness and robustness of the system, many software systems contain a large amount of code dedicated to error detection and handling. An exception is a special type of error that can be captured and handled by programmers. It is a general term for a series of abnormal behaviors that occur during program execution, such as out-of-range index, divide-by-zero error, calculation overflow, and invalid input.
An exception is not part of the normal functionality of a program. Once an exception occurs, the program must handle the exception immediately. That is, the control right of the program is transferred from the execution of the normal functionality to the exception handling part. Cangjie provides an exception handling mechanism to handle various exceptions that may occur during program running, including the following:
-
try expression: including ordinary try expression and try-with-resources expression.
-
throw expression: consists of the keyword
throwand a trailing expression whose type must be inherited from theExceptionorErrorclass.
The following describes the try and throw expressions.
try Expressions
The try expressions are classified into ordinary try expressions that do not involve automatic resource management and try-with-resources expressions that involve automatic resource management. The syntax of the try expression is defined as follows:
tryExpression
: 'try' block 'finally' block
| 'try' block ('catch' '(' catchPattern ')' block)+ ('finally' block)?
| 'try' '(' ResourceSpecifications ')' block ('catch' '(' catchPattern ')' block)* ('finally' block)?
;
catchPattern
: wildcardPattern
| exceptionTypePattern
;
exceptionTypePattern
: ('_' | identifier) ':' type ('|' type)*
;
ResourceSpecifications
: ResourceSpecification (',' ResourceSpecification)*
;
ResourceSpecification
: identifier (':' classType)? '=' expression
;
The following describes the ordinary try expression and try-with-resources expression.
Ordinary try Expressions
An ordinary try expression (the try expression mentioned in this section refers to an ordinary try expression) consists of three parts: try block, catch block, and finally block.
-
A try block starts with the keyword
tryand is followed by a block enclosed in curly braces that contains any expressions and declarations (defining a new local scope). The block following try can throw an exception, which is caught and handled by the catch block. (If no catch block exists or the exception is not caught, after the finally block is executed, the exception is thrown to the calling function.) -
Zero or more catch block can be contained in a try expression. (The finally block is required when there is no catch block.) Each catch block starts with the keyword
catch, followed by a(catchPattern)and a block consisting of expressions and declarations.catchPatternmatches exceptions to be caught using pattern matching. Once a match is found, the exception is handled by the block consisting of expressions and declarations, and all subsequent catch blocks are ignored. When all exception types that can be captured by a catch block can also be captured by another catch block defined before it, a warning indicating that the catch block is unreachable is displayed at that catch block. -
The finally block starts with the keyword
finallyand is followed by a block consisting of expressions and declarations enclosed in curly braces. In principle, the finally block is used to perform "cleanup" tasks, such as releasing resources. Throwing exceptions in the finally block should be avoided. The content in the finally block is executed regardless of whether an exception occurs (that is, whether an exception is thrown in the try block). If the exception is not handled, the exception is thrown after the finally block is executed. In addition, a try expression can contain one finally block or no finally block (in this case, at least one catch block must be present).
The catchPattern has two patterns:
-
Wildcard pattern ("_") captures any type of exceptions thrown in the try block at the same level. This pattern is equivalent to the
e: Exceptionpattern, that is, capturing the exceptions defined by Exception and its subclasses. Example:// Catch with wildcardPattern. let arrayTest: Array<Int64> = Array<Int64>([0, 1, 2]) try { let lastElement = arrayTest[3] } catch (_) { print("catch an exception!") } -
Type pattern catches exceptions of a specified type (or its subclass). There are two main syntaxes:
identifier : ExceptionClass: This format can be used to capture exceptions of the ExceptionClass type and its subclasses, convert the captured exception instances to ExceptionClass, and bind the exception instances to the variables defined byidentifier. Then, you can access the captured exception instances through the variables defined byidentifierin the catch block.identifier : ExceptionClass_1 | ExceptionClass_2 | ... | ExceptionClass_n| : | ... | This format uses the|connector to combine multiple exception classes.|The connector|indicates the OR relationship.|You can capture exceptions of theExceptionClass_1type and its subclasses, exceptions of theExceptionClass_2type and its subclasses, and similarly, exceptions of theExceptionClass_ntype and its subclasses (assuming that n is greater than 1). When the type of the exception to be captured belongs to any class or subclass in the OR relationship, the exception is captured. However, because the type of the caught exception cannot be statically determined, the type of the caught exception is converted to the smallest common superclass of all types connected by|.|Then, the exception instance is bound to the variable defined byidentifier. Therefore, in the type pattern, within the catch block, you can only access the member variables and member functions from the minimum common superclass ofExceptionClass_i (1 <= i <= n)through the variables defined byidentifier. You can also use wildcards to replaceidentifierin the type pattern. The only difference is that no binding will occur.
Examples of using type patterns are as follows:
// The first situation. main() { try { throw ArithmeticException() } catch (e: Exception) { // Caught. print("Exception and its subtypes can be caught here") } }// The second situation. // User defined exceptions. open class Father <: Exception { var father: Int64 = 0 func whatFather() { print("I am Father") } } class ChildOne <: Father { var childOne: Int64 = 1 func whatChildOne() { print("I am ChildOne") } func whatChild() { print("I am method in ChildOne") } } class ChildTwo <: Father { var childTwo: Int64 = 2 func whatChildTwo() { print("I am ChildTwo") } func whatChild() { print("I am method in ChildTwo") } } // Function main. main() { var a = 1 func throwE() { if (a == 1) { ChildOne() } else { ChildTwo() } } try { throwE() } catch (e: ChildOne | ChildTwo) { e.whatFather() // ok: e is an object of Father //e.whatChildOne() // error: e is an object of Father //e.whatChild() // error: e is an object of Father print(e.father) // ok: e is an object of Father //print(e.childOne) // error: e is an object of Father //print(e.childOTwo) // error: e is an object of Father } return 0 }
An example of using the finally block is as follows:
// Catch with exceptionTypePattern.
try {
throw IndexOutOfBoundsException()
} catch (e: ArithmeticException | IndexOutOfBoundsException) {
print("exception info: " + e.toString())
} catch (e: Exception) {
print("neither ArithmeticException nor IndexOutOfBoundsException, exception info: " + e.toString())
} finally {
print("the finally block is executed")
}
Types of try Expressions
Similar to if expressions:
- If the value of the
tryexpression is not read or returned, the type of the entiretryexpression is Unit. The try block and catch block do not require a common supertype. Otherwise, see the following rules. - When there is no explicit type requirement in the context, the try block and all catch blocks (if any) are required to have a minimum common supertype. The type of the entire try expression is the minimum common supertype.
- When the context has specific type requirements, the type of the try block and any catch block (if any) must be a subtype of the type required by the context. In this case, the try block and any catch block are not required to have a minimum common supertype.
Note that although the finally block is executed after the try block and catch block, it does not affect the type of the entire try expression. In addition, the type of the finally block is always Unit (even if the type of the expression in the finally block is not Unit).
Evaluation Order of try Expressions
Additional rules for executing the try {e1} catch (catchPattern) {e2} finally {e3} expression are as follows:
-
If the
return eexpression is reached before entering the finally block, the value ofeis evaluated tov, and then the finally block is executed immediately. If thebreakorcontinueexpression is reached before entering the finally block, the finally block is executed immediately.- If the finally block does not contain the return expression, the cached result
vis returned (or an exception is thrown) after the finally block is processed. That is, even if the finally block assigns a value to the variable referenced ine, thevthat has already been evaluated is not affected. The following is an example:
func f(): Int64 { var x = 1; try { return x + x; // Return 2. } catch (e: Exception) { // Caught. print("Exception and its subtypes can be caught here") } finally { x = 2; } // The return value is 2 but not 4.- If
return e2orthrow e2is executed in the finally block, the value ofe2is evaluated to the resultv2, andv2is returned or thrown immediately. Ifbreakorcontinueis executed in the finally block, the execution of the finally block is terminated and the loop exits immediately. Example:
func f(): Int64 { var x = 1; try { return x + x; // Return 2. } catch (e: Exception) { // Caught. print("Exception and its subtypes can be caught here") } finally { x = 2; return x + x; // Return 4 } // The return value is 4 but not 2. } - If the finally block does not contain the return expression, the cached result
In a word, the finally block is always executed. If any control transfer expression exists in the finally block, it overrides any control transfer expression encountered before entering the finally block.
The handling of throw in the try expression is more complex. For details, see the next section.
Exception Handling Logic of try Expressions
Rules for throwing an exception when the try {e1} catch (catchPattern) {e2} finally {e3} expression is executed are as follows:
-
No exception is thrown during the execution of
e1(in this case,e2is not executed):- If no exception is thrown during the execution of
e3, the entire try expression does not throw an exception. - If the
E3exception is thrown during the execution ofe3, the entire try expression throws theE3exception.
- If no exception is thrown during the execution of
-
If the
E1exception is thrown during the execution ofe1and theE3exception is thrown during the execution ofe3, the entire try expression throws theE3exception (regardless of whether theE1is captured by the catch block). -
E1is thrown during the execution ofe1and no exception is thrown during the execution ofe3:- If
E1can be captured by the catch block and no exception is thrown during the execution ofe2, no exception is thrown in the entire try expression. - If
E1can be captured by the catch block and the exceptionE2is thrown during the execution ofe2, the exceptionE2is thrown in the entire try expression. - If
E1is not captured by the catch block, the entire try expression throws the exceptionE1.
- If
try-with-resources Expressions
The try-with-resources expression is used to automatically release non-memory resources. Different from ordinary try expressions, the catch block and finally block in the try-with-resources expression are optional. Between the try keyword and the block following it, one or more ResourceSpecifications can be inserted to request for a series of resources (ResourceSpecifications do not affect the type of the entire try expression). The resource here refers to objects. Therefore, ResourceSpecification is to instantiate a series of objects (with multiple instantiations separated by commas). The following is an example of using the try-with-resources expression:
class MyResource <: Resource {
var flag = false
public func isClosed() { flag }
public func close() { flag = true }
public func hasNextLine() { false }
public func readLine() { "line" }
public func writeLine(_: String) {}
}
main() {
try (input = MyResource(),
output = MyResource()) {
while (input.hasNextLine()) {
let lineString = input.readLine()
output.writeLine(lineString)
}
} catch (e: Exception) {
print("Exception happened when executing the try-with-resources expression")
} finally {
print("end of the try-with-resources expression")
}
}
In the try-with-resources expression, the type of ResourceSpecification must implement the Resource interface.
interface Resource {
func isClosed(): Bool
func close(): Unit
}
The try-with-resources expression first requests the series of resources required for instantiation in the order they are declared. (In the preceding example, the input object is instantiated before the output object). If a resource fails to be allocated (for example, the output object fails to be instantiated), all resources that have been successfully allocated (for example, the input object) are released. (Any exception thrown during the release is ignored.) In addition, an exception is thrown, indicating that the resource (output object) fails to be allocated.
If all resources are successfully allocated, the block following try continues to be executed. During block execution, resources are automatically released in the reverse order of resource allocation regardless of whether an exception occurs. (In the preceding example, the output object is released before the input object.) During resource release, if an exception occurs when a resource is released, the release of other resources is not affected. In addition, the exception thrown by the try expression complies with the following principles: (1) If an exception is thrown in the block following try, the exception thrown during resource release is ignored. (2) If no exception is thrown in the block following try, the first exception thrown during resource release is thrown (exceptions thrown during subsequent resource release will be ignored).
Note that the try-with-resources expression does not need to contain the catch block and finally block, and you are advised not to manually release resources. During the execution of the try block, all allocated resources are automatically released regardless of whether an exception occurs, and all exceptions generated during the execution are thrown. However, if you need to explicitly capture and handle exceptions that may be thrown in the try block or during resource allocation and release, you can still include the catch block and finally block in the try-with-resources expression.
try (input = MyResource(),
output = MyResource()) {
while (input.hasNextLine()) {
let lineString = input.readLine()
output.writeLine(lineString)
}
} catch (e: Exception) {
print("Exception happened when executing the try-with-resources expression")
} finally {
print("end of the try-with-resources expression")
}
The preceding try-with-resources expression is equivalent to the following ordinary try expressions:
try {
var freshExc = None<Exception> // A fresh variable that could store any exceptions
let input = MyResource()
try {
var freshExc = None<Exception>
let output = MyResource()
try {
while (input.hasNextLine()) {
let lineString = input.readLine()
output.writeLine(lineString)
}
} catch (e: Exception) {
freshExc = e
} finally {
try {
if (!output.isClosed()) {
output.close()
}
} catch (e: Exception) {
match (freshExc) {
case Some(v) => throw v // Exception raised from the user code will be thrown
case None => throw e
}
}
match (freshExc) {
case Some(v) => throw v
case None => ()
}
}
} catch (e: Exception) {
freshExc = e
} finally {
try {
if (!input.isClosed()) {
input.close()
}
} catch (e: Exception) {
match (freshExc) {
case Some(v) => throw v
case None => throw e
}
}
match (freshExc) {
case Some(v) => throw v
case None => ()
}
}
} catch (e: Exception) {
print("Exception happened when executing the try-with-resources expression")
} finally {
print("end of the try-with-resources expression")
}
If an exception is thrown in the try block (that is, user code), the exception is recorded in the freshExc variable and is finally thrown layer by layer. The priority of the exception is higher than that of the exception that may occur during resource release. The type of the try-with-resources expression is Unit.
throw Expressions
The syntax of the throw expression is defined as follows:
throwExpression
: 'throw' expression
;
A throw expression consists of the keyword throw and an expression. It is used to throw an exception. The type of the throw expression is Nothing. Note that the expression following the keyword throw can only be an object of the type inherited from Exception or Error. The throw expression changes the execution logic of the program. When the throw expression is executed, an exception is thrown. The code block that captures the exception is executed instead of the remaining expression after the throw expression is executed.
The following is an example of using the throw expression:
// Catch with exceptionTypePattern.
let listTest = [0, 1, 2]
try {
throw ArithmeticException()
let temp = listTest[0] + 1 // Will never be executed.
} catch (e: ArithmeticException) {
print("an arithmeticException happened: " + e.toString())
} finally {
print("the finally block is executed")
}
After the throw expression throws an exception, it must be able to capture and handle the exception. The sequence of searching for the exception capture code is the reverse sequence of the function call chain. When an exception is thrown, the function that throws the exception is searched for the matching catch block. If the catch block is not found, the function execution is terminated, and the function that calls this function is searched for the matching catch block. If the catch block is still not found, the function execution is also terminated, and the function that calls this function is searched in the same way until a matching catch block is found. However, if no matching catch block is found in all functions in the call chain, the program executes the terminate function in the exception. As a result, the program exits abnormally.
The following example shows the scenario where exceptions are captured at different locations:
// Caught by catchE().
func catchE() {
let listTest = [0, 1, 2]
try {
throwE() // caught by catchE()
} catch (e: IndexOutOfBoundsException) {
print("an IndexOutOfBoundsException happened: " + e.toString())
}
}
// Terminate function is executed.
func notCatchE() {
let listTest = [0, 1, 2]
throwE()
}
// func throwE()
func throwE() {
throw IndexOutOfBoundsException()
}
Cross-Language Interoperability
C Language Interoperability
unsafe Context
Because C language is prone to cause insecurity, Cangjie stipulates that all functionalities that interoperate with C language can only occur in the unsafe context. The unsafe context is introduced using the unsafe keyword.
The unsafe keyword can be used in the following ways:
- Modifying a code block. The type of the
unsafeexpression is the type of the code block. - Modifying a function.
All unsafe functions and CFunc functions must be called in the unsafe context.
All unsafe functions cannot be used as first-class citizens. For example, they cannot be assigned to variables, used as arguments or return values, or used as expressions. They can be called only in the unsafe context.
The syntax is defined as follows:
unsafeExpression
: 'unsafe' '{' expressionOrDeclarations '}'
;
unsafeFunction
: 'unsafe' functionDefinition
;
Calling C Functions
foreign Keyword and @C
To call a C function in Cangjie, you need to declare the function in the Cangjie code and use the foreign keyword to modify the function. The foreign function exists only in the top-level scope and is visible only in the package. Therefore, no other function modifiers can be used.
@C supports only the foreign function, non-general functions in the top-level scope, and the struct type. When the foreign function is modified, @C can be omitted. Unless otherwise specified, all foreign functions in the C language interoperability section are considered to be foreign functions modified by @C.
Modified by @C, the foreign keyword can only be used to modify non-general functions in the top-level scope. The foreign function is only a declaration and does not have a function body. Its parameters and return types cannot be omitted. Functions modified by foreign use the native C application binary interface (ABI) and do not have name modification.
foreign func foo(): Unit
foreign var a: Int32 = 0 // compiler error
foreign func bar(): Unit { // compiler error
return
}
Multiple foreign function declarations can be grouped together using a foreign block. A foreign block is a sequence of declarations enclosed in curly braces after the foreign keyword. The foreign block can contain only functions. Adding annotations to the foreign block is equivalent to adding the annotation to each member in the foreign block.
foreign {
func foo(): Unit
func bar(): Unit
}
The foreign function must be able to link to the C function with the same name, and the parameters and return types must be the same. Only types that meet the CType constraint can be used for the parameters and return types of the foreign function. For the definition of CType, see "CType Interface."
The foreign function does not support named parameters or default parameter values. The foreign function allows variable-length parameters, which are expressed by ... and can be used only at the end of the parameter list. Variable-length parameters must meet the CType constraint, but they do not need to be of the same type.
CFunc
In Cangjie, CFunc refers to the function that can be called by C language code. There are three forms:
foreignfunction modified by@C.- Cangjie function modified by
@C. lambdaexpression of theCFunctype.- Different from common lambda expressions,
CFunc lambdacannot capture variables.
- Different from common lambda expressions,
// Case 1
foreign func free(ptr: CPointer<Int8>): Unit
// Case 2
@C
func callableInC(ptr: CPointer<Int8>) {
print("This function is defined in Cangjie.")
}
// Case 3
let f1: CFunc<(CPointer<Int8>) -> Unit> = { ptr =>
print("This function is defined with CFunc lambda.")
}
The type of functions declared or defined in the preceding three forms is CFunc<(CPointer<Int8>) -> Unit>. CFunc corresponds to the function pointer type of the C language. This type is a generic type. Its generic parameter indicates the type of the CFunc input parameter and return value. The usage is as follows:
foreign func atexit(cb: CFunc<()->Unit>)
Similar to the foreign function, the parameters and return types of other CFunc functions must meet the CType constraint and do not support named parameters and default parameter values.
When CFunc is called in Cangjie code, it must be in the unsafe context.
Cangjie can convert a variable of the CPointer<T> type to a specific CFunc. The generic parameter T of CPointer can be any type that meets the CType constraint. The method is as follows:
main() {
var ptr = CPointer<Int8>()
var f = CFunc<() -> Unit>(ptr)
unsafe { f() } // core dumped when running, because the pointer is nullptr.
}
The CFunc parameters and return types cannot depend on external generic parameters.
func call<T>(f: CFunc<(T) -> Unit>, x: T) where T <: CType { // error
unsafe { f(x) }
}
func f<T>(x: T) where T <: CType {
let g: CFunc<(T) -> T> = { x: T => x } // error
}
class A<T> where T <: CType {
let x: CFunc<(T) -> Unit> // error
}
inout Parameter
When CFunc is called in Cangjie, the parameter can be modified by the inout keyword to form a reference value transfer expression. In this case, the parameter is transferred by reference. The type of the referenced value transfer expression is CPointer<T>, where T is the type of the expression modified by inout.
The value transfer expression by reference has the following restrictions:
- It can only be used to call
CFunc. - The type of the modifier object must meet the
CTypeconstraint, but cannot beCString. - The modifier object must be a variable defined by
var. - The pointer transferred to the C side by using the value transfer expression on the Cangjie side is valid only during function calling. That is, in this scenario, the C side should not save the pointer for future use.
Variables modified by inout can be variables defined in top-level scope, local variables, and member variables in struct, but cannot be directly or indirectly derived from instances of class.
foreign func foo1(ptr: CPointer<Int32>): Unit
@C
func foo2(ptr: CPointer<Int32>): Unit {
let n = unsafe { ptr.read() }
println("*ptr = ${n}")
}
let foo3: CFunc<(CPointer<Int32>) -> Unit> = { ptr =>
let n = unsafe { ptr.read() }
println("*ptr = ${n}")
}
struct Data {
var n: Int32 = 0
}
class A {
var data = Data()
}
main() {
var n: Int32 = 0
unsafe {
foo1(inout n) // OK
foo2(inout n) // OK
foo3(inout n) // OK
}
var data = Data()
var a = A()
unsafe {
foo1(inout data.n) // OK
foo1(inout a.data.n) // Error, n is derived indirectly from instance member variables of class A
}
}
Calling Conventions
Function calling conventions describe how the caller and callee call functions (for example, how parameters are transferred and who clears the stack). The caller and callee must use the same calling conventions to run properly. Cangjie uses @CallingConv to indicate various calling conventions. The supported calling conventions are as follows:
-
CDECL: The default calling conventions used by the C compiler of Clang on different platforms.
-
STDCALL: The calling conventions used by the Win32 API.
If a C function is called using the C language interoperability mechanism, the default CDECL calling conventions is used when no calling convention is specified. The following is an example of calling the clock function in the C standard library:
@CallingConv[CDECL] // Can be omitted in default.
foreign func clock(): Int32
main() {
println(clock())
}
@CallingConv can only be used to modify the foreign block, a single foreign function, and a CFunc function in the top-level scope. When @CallingConv modifies the foreign block, the same @CallingConv modification is added to each function in the foreign block.
Type Mapping
When a foreign function is declared In Cangjie, the types of parameters and return values must be the same as those of the C function to be called. The Cangjie programming language type is different from the C language type. Some simple value types, such as the int32_t type of the C language, can correspond to Int32 of the Cangjie programming language. However, some complex types, such as structs, need to be declared with the same memory layout on the Cangjie side. The types that can be used by Cangjie to interact with C meet the CType constraint. They can be classified into basic types and complex types. Basic types include integer, floating-point, Bool, CPointer, and Unit. Complex types include the struct and CFunc types modified by @C.
Base Types
When parameters are transferred between Cangjie and C, the basic value types, such as int and short, are copied. The following table lists the mapping of basic types between Cangjie and C.
| Cangjie Type | C type | Size |
|---|---|---|
Unit | void | 0 |
Bool | bool | 1 |
Int8 | int8_t | 1 |
UInt8 | uint8_t | 1 |
Int16 | int16_t | 2 |
UInt16 | uint16_t | 2 |
Int32 | int32_t | 4 |
UInt32 | uint32_t | 4 |
Int64 | int64_t | 8 |
UInt64 | uint64_t | 8 |
IntNative | ssize_t | platform dependent |
UIntNative | size_t | platform dependent |
Float32 | float | 4 |
Float64 | double | 8 |
Note:
- Due to the uncertainty of the
intandlongtypes on different platforms, the corresponding Cangjie programming language type need to be specified. - In C interoperability scenarios, the
IntNativeandUIntNativeare the same as thessize_tandsize_tin the C language, respectively. - In C interoperability scenarios, similar to the C language, the
Unittype can only be used as the return type inCFuncand the generic parameter ofCPointer.
In Cangjie, the types of the parameters and return values of the foreign function must correspond to those of the C function. For types that have clear type mappings and are irrelevant to the platform (see the mapping of basic types), you can directly use the corresponding basic types of the Cangjie programming language. For example, in the C language, an add function is declared as follows:
int64_t add(int64_t X, int64_t Y) { return X+Y; }
Call the add function In Cangjie. The sample code is as follows:
foreign func add(x: Int64, y: Int64): Int64
main() {
let x1: Int64 = 42
let y1: Int64 = 42
var ret1 = unsafe { add(x1, y1) }
...
}
Pointer
Cangjie provides the CPointer<T> type that corresponds to the T* type of the C language. T must meet the CType constraint.
The CPointer type must meet the following requirements:
- Its size and alignment depend on the platform.
- The addition and subtraction operations and memory read and write operations need to be performed in an unsafe context.
- The
CPointer<T1>can be forcibly converted to theCPointer<T2>type in the unsafe context.
The CPointer has the following member methods:
func isNull() : bool
// operator overloading
unsafe operator func + (offset: int64) : CPointer<T>
unsafe operator func - (offset: int64) : CPointer<T>
// read and write access
unsafe func read() : T
unsafe func write(value: T) : Unit
// read and write with offset
unsafe func read(idx: int64) : T
unsafe func write(idx: int64, value: T) : Unit
The CPointer can use a type name to construct an instance. The value of the CPointer corresponds to the NULL in the C language.
func test() {
let p = CPointer<Int64>()
let r1 = p.isNull() // r1 == true
}
Cangjie can convert a variable of the CFunc type to a CPointer type. The generic parameter T of CPointer can be any type that meets the CType constraint. The method is as follows:
foreign func rand(): Int32
main() {
var ptr = CPointer<Int8>(rand)
0
}
Character String
In the C language, a character string is actually a one-dimensional character array terminated with '\0'. Cangjie provides CString to match the C language character string. For a C language character string created using the constructor of CString or mallocCString of LibC, to release it on the Cangjie end, call the free method of LibC.
When declaring a foreign function, you need to determine the function name, parameter types, and return value types based on the declaration of the C language function to be called. The declaration of the printf function of the C language standard library is as follows:
int printf(const char *format, ...)
The const char * type corresponds to the CString type of Cangjie. The return type Int32 corresponds to the int type of Cangjie. The following is an example of creating a character string and calling the printf function:
package demo
foreign func printf(fmt: CString, ...): Int32
main() {
unsafe {
let str: CString = LibC.mallocCString("hello world!\n")
printf(str)
LibC.free(str)
}
}
Array Type
The Array type of Cangjie does not meet the CType constraint. Therefore, it cannot be used for the parameters and return values of the foreign function. However, when the internal element type of Array meets the CType constraint, Cangjie can use the following two functions to obtain and release the pointers pointing to the internal elements of the array.
unsafe func acquireArrayRawData<T>(arr: Array<T>): CPointerHandle<T> where T <: CType
unsafe func releaseArrayRawData<T>(h: CPointerHandle<T>): Unit where T <: CType
struct CPointerHandle<T> {
let pointer: CPointer<T>
let array: Array<T>
}
For example, to write an Array<UInt8> to a file, do as follows:
foreign func fwrite(buf: CPointer<UInt8>, size: UIntNative, count: UIntNative, stream: CPointer<Unit>): UIntNative
func writeFile(buffer: Array<UInt8>, file: CPointer<Unit>) {
unsafe {
let h = acquireArrayRawData(buffer)
fwrite(h.pointer, 1, buffer.size, file)
releaseArrayRawData(h)
}
}
VArray Type
Cangjie uses the VArray type to map to the array type of C. When the element type T in VArray<T, $N> meets the CType constraint, the VArray<T, $N> type also meets the CType constraint.
struct A {} // A is not a CType.
let arr1: VArray<A, $2> // arr1 is not a CType.
let arr2: VArray<Int64, $2> // arr2 is a CType.
VArray can be used as the parameter type of the CFunc signature, but cannot be the return type.
If the parameter type in the CFunc signature is declared as VArray<T, $N>, the corresponding argument can only be an expression of the VArray<T, $N> type modified by inout. However, the parameter is still passed as CPointer<T>.
If the parameter type in the CFunc signature is declared as CPointer<T>, the corresponding argument can be an expression of the VArray<T, $N> type modified by inout. When the parameter is passed, the type is still CPointer<T>.
CPointer<VArray<T, $N>> is equivalent to CPointer<T>.
foreign func foo1(a: VArray<Int32, $3>): Unit
foreign func foo2(a: CPointer<Int32>): Unit
var a: VArray<Int32, $3> = [1, 2, 3]
unsafe {
foo1(inout a) // Ok.
foo2(inout a) // Ok.
}
Structure
If the signature of the foreign function contains the structure type, you need to define the struct with the same memory layout on the Cangjie side and use @C to modify it.
As shown in the following example, a C graphics library (libskialike.so) has a function distance for calculating the distance between two points. The related structure and function declaration in the C language header file are as follows:
struct Point2D {
float x;
float y;
};
float distance(struct Point2D start, struct Point2D end);
When declaring a foreign function, you need to determine the function name, parameter types, and return value types based on the declaration of the C language function to be called. When creating a structure on the C side, you need to determine the name and type of each member of the structure. The sample code is as follows:
package demo
@C
struct Point2D {
var x: Float32
var y: Float32
}
foreign func distance(start: Point2D, end: Point2D): Float32
The struct modified by @C must meet the following requirements:
- The type of a member variable must meet the
CTypeconstraint. interfacescannot be implemented or extended.- To be used as an associated value type of
enumis not allowed. - Closure capture is not allowed.
- Generic parameters are not allowed.
The struct modified by @C automatically meets the CType constraint.
Ensure that the memory layout of the VArray member variables in @C struct is the same as that of the array in C.
For example, for the following C structure types:
struct S {
int a[2];
int b[0];
}
In Cangjie, the following structure can be declared to correspond to the C code:
@C
struct S {
var a: VArray<Int32, $2> = VArray<Int32, $2>(item: 0)
var b: VArray<Int32, $0> = VArray<Int32, $0>(item: 0)
}
Note that in the C language, the last field of a structure can be an array whose length is not specified. The array is called a flexible array. Cangjie does not support the mapping of structures that contain flexible arrays.
Function
The function type in Cangjie does not meet the CType constraint. Therefore, CFunc is provided as the mapping of the function pointer in the C language. The function pointer type defined in the following C language code can be mapped to CFunc<() -> Unit> in Cangjie.
// Function pointer in C.
typedef void (*FuncPtr) ();
For details about CFunc, see the preceding section on CFunc.
CType Interface
The CType interface is a built-in empty interface of the language. It is the specific implementation of the CType constraint. All types supporting interoperability with the C language implicitly implement this interface. Therefore, all types supporting interoperability with the C language can be used as subtypes of the CType type.
@C
struct Data {}
@C
func foo() {}
main() {
var c: CType = Data() // ok
c = 0 // ok
c = true // ok
c = CString(CPointer<UInt8>()) // ok
c = CPointer<Int8>() // ok
c = foo // ok
}
The CType interface is an interface type in Cangjie and does not meet the CType constraint. In addition, the CType interface cannot be inherited, explicitly implemented, or extended.
The CType interface does not break the usage restrictions of subtypes.
@C
struct A {} // implicit implement CType
class B <: CType {} // error
class C {} // error
extend C <: CType {} // error
class D<T> where T <: CType {}
main() {
var d0 = D<Int8>() // ok
var d1 = D<A>() // ok
}
Java Interoperability
Interoperability Modes
Cangjie Calling Java
In Cangjie, you can directly use the import statement to import the top-level types of Java packages, including classes and interfaces (such as enumerations and annotations). Only Java types, member variables, or methods that are visible outside the package (public or protected) can be used in Cangjie.
When a Java type is being imported, the following syntaxes are supported.
- Use
import packageName.*to import all types in theJavapackage. - Use
import packageName.nameto import a specific type in theJavapackage. - Use
import packageName.name as newNameto rename the file to avoid conflicts or simplify the writing.
The contents of the Java standard library are obtained from the java8 module in Cangjie. Import java.lang.Math to Cangjie. The sample code is as follows:
// Cangjie code
from java8 import java.lang.Math
main(){
Math.sin(Math.PI/2.0) // invoke static method and access static field
0
}
The imported Java classes and interfaces support the following usages in Cangjie.
- Create class instances, access class member variables, and call class methods.
- Inherit the class or implement the interface through
<:(the@Javaannotation is required).
When Cangjie calls Java code, the called Java code is executed on a Java thread. There is a one-to-one correspondence between Cangjie thread and Java thread, and the correspondence does not change during running of the Cangjie program. If Java interoperability cannot be performed in the current execution environment, the exception JavaNotSupportedException is thrown when Java code is executed for the first time.
The imported Java classes and interfaces must comply with certain mapping rules (such as type and modifier mapping) and usage restrictions. For details, see the following sections.
Java Calling Cangjie
In Java, the import statement can be used to import the classes and interface types modified by @Java on the Cangjie side. (For details about how to use @Java, see [@Java Classes and Interfaces].)
Assume that a Cangjie class is defined as follows:
// Cangjie code
package cangjie.example
import std.ffi.java.*
@Java
public class CJClass {
public func foo(str: JString): Unit {
// do something
}
}
To import the Cangjie class to Java using the import statement, do as follows:
// Java code
package com.company;
import cangjie.example.CJClass;
public class Main {
public static void main(String[] args) {
CJClass obj = new CJClass();
obj.foo("this is a java string");
}
}
Java also supports access to classes and interface types modified by @Java on the Cangjie side through reflection (Class.forName or ClassLoader.loadClass). The preceding Cangjie class is used in the following example of using the reflection mechanism in Java:
// Java code
package com.company;
import java.lang.reflect.Method;
public class Main {
public static void main(String[] args) throws Exception {
Class<?> clz = Class.forName("cangjie.example.CJClass"); // Get the class through forName
Method method = clz.getMethod("foo", String.class); // Get the method
method.invoke(clz.newInstance(), "this is a string"); // Create instance and invoke the method
}
}
Type Mapping
The types of member variables, method parameters, and return values in imported Java classes or interfaces must follow specific type mapping rules when used in Cangjie. The mapping types are as follows:
-
Types that are similar between
Javaand Cangjie, with minimal differences, for example, the basic typebyteinJava.For details about these
Javatypes, see the mapping table. -
Types that exist in both
Javaand Cangjie, but with significant semantic differences, such asJavacharacter strings and arrays, which are greatly different from the built-in character strings and arrays of Cangjie.These
Javatypes are supported by providing additional built-in types, such asffi.java.JStringandffi.java.JArray. -
Types that exist in
Javabut not in Cangjie, which may be supported by some built-in special usages. -
Types that are unique to Cangjie, such as
tupleandstruct. These type cannot be used as member variables, method parameters, or return value types of classes modified by@Java, but can be used in methods of those classes.
For details about the mapping rules and restrictions of each type and the usage of common classes, interfaces, and generic types on the Java side, see the following sections.
Java Basic Types and Their Wrapper Classes
When Java basic types are used as class member variables, method parameters, and return value types, they can be used based on the types in the mapping table. The following table describes the mapping.
| Java | Cangjie |
|---|---|
| byte | Int8 |
| short | Int16 |
| char | UInt16 |
| int | Int32 |
| long | Int64 |
| float | Float32 |
| double | Float64 |
| boolean | Bool |
The Cangjie numeric types that are not supported by Java cannot be used as the member variables, method parameters, and return value types of the class modified by @Java. These types include UInt8, UInt32, UInt64, and Float16.
The wrapper type corresponding to each basic type in Java is regarded as a common Java class in Cangjie and does not provide additional mapping and automatic packing and unpacking operations. When using Java code whose input parameter or return value type is wrapper in Cangjie, you need to import the corresponding wrapper class and manually create an instance.
The sample code is as follows:
// Java code
package com.example;
public class BoxedExample {
// foo receive the packing type of the basic type.
public void foo(Integer i){
System.out.println(i.toString());
}
}
Import BoxedExample to Cangjie and create an instance to call the foo function. The code is as follows:
import com.example.*
from java8 import java.lang.Integer;
main(){
var instance = BoxedExample()
instance.foo(1) // compile error
var i = Integer(1)
instance.foo(i)
}
@Java Classes and Interfaces
@Java can be used to modify class and interface. By default, the types modified by @Java are the subtypes of java.lang.Object. Only types modified by @Java can be used in Java. These types can also be used in classes or interfaces that are not modified by @Java.
Note that types modified by @Java have the following restrictions:
-
For types modified by
@Java, the types of its member variables, input parameters of member functions, and return values cannot contain types that are unique to Cangjie. Types that are unique to Cangjie includeTuple,Array,enum,struct, function type (except CFunc),Range,String,Nothing,Rune,UInt8,UInt32,UInt64,Float16, andUnit. (Unitcan be used as the return value type. For details, see [Java void].) -
The class or interface modified by
@Javacan inherit and implement the following:- Imported
javaclasses and interfaces - Other types modified by
@Java interfacetype of Cangjie
- Imported
open class A{}
@Java
class B <: A {} // compile error, A is neither modified by @Java nor an imported java type.
If no superclass is specified for a class modified by @Java, the superclass is java.lang.Object. The instance of the class modified by @Java can directly call the java.lang.Object member method. The sample code is as follows:
@Java
class Foo{}
main(){
var instance = Foo()
instance.hashCode() // Call java.lang.Object method
}
In Java, class loaders are responsible for dynamically loading Java classes into VMs. By default, the class modified by @Java is loaded by Java Application Classloader, which is equivalent to @Java["app"]. If @Java["ext"] is used, the class will be loaded by the custom Classloader.
The usage of @Java["ext"] and @Java["app"] is the same. The only difference is that classes modified by @Java["ext"] can be referenced only by other classes modified by @Java["ext"]. The function in the class can reference other Cangjie code normally. Classes modified by @Java["ext"] and @Java["app"] can be accessed through reflection in Java.
Java Object
In Cangjie, Object is the superclass of java.lang.Object of Java.
Java void
When a Java method is called in Cangjie, the return value of void is of the Unit type. The value of Unit is allocated by the Cangjie calling side. If a Cangjie class inherits the imported Java class and rewrites the method of the Java class (the method returns void), the Unit type is not created when the rewritten method is called and executed on the Java side.
Unit cannot be used in the member variables and member function parameters of the type modified by @Java except that it is used as the return type of a function.
Note: If the value of
Unitis allocated on the calling side,var a: Unit = JObject.callJMethod()is equivalent toJObject.callJMethod(); var a: Unit = ().
@Java
class UnitExample <: SomeJClass {
overrride func foo():Unit{
// other code
return () // When the foo function is called on the Java side,
} // the Unit will not be created.
}
main(){
var instance = UnitExample()
var a = instance.foo() // Same as instance.foo(); var a: Unit = ()
}
Java String
Cangjie provides the ffi.java.JString type mapping java.lang.String. This type has all methods of java.lang.String. The two types are the same during running. In the imported Java type, if the member variables and input parameters and return value types of member methods are java.lang.String, they are mapped to ffi.java.JString. The native String type of Cangjie cannot be used as the type of member variables, member method input parameter or return value of the class modified by @Java.
The ffi.java.JString literal supports only single-line character literals. It is defined by double quotation marks starting with an uppercase letter J (for example, J"singleLineStringLiteral"). The content in the double quotation marks can be any number of characters and can be written in only one line.
// Cangjie code
import std.ffi.java.JString
@Java
class JStrExample {
var a:String = "Cangjie string" // compiler error
var b:JString = J"JString" // Single line literal
}
main(){
var obj = Foo()
var jstr: JString = J"Java String"
jstr.equal(J"Java String") // Call the equal method to determine whether the string content is equal
}
In addition to all methods of java.lang.String, ffi.java.JString also supports judgment (== and !=) and concatenation (+).
Cangjie provides the conversion between the native String type and ffi.java.JString type. The conversion functions are as follows:
public func toJString(str: String) : JString
public func toString(jstr: JString) : String
Java Array
Cangjie provides the ffi.java.JArray<T> type to map the built-in array type of Java. The ffi.java.JArray<T> type is a generic type of Cangjie. The type variable T must be a type that can be mapped to Java, including basic types (Int8, Int16, UInt16, Int32, Int64, Float32, Float64, and Bool), type modified by @Java, JString type, and JArray<T> type. All the preceding types implement the JType interface, and T has the constraint where T <: JType.
You can create ffi.java.JArray<T> in either of the following ways:
-
Use the
Array<T>extension functiontoJArray.let a: JArray<Int64> = [1, 2, 3, 3, 2, 1].toJArray() -
Use
ffi.java.JArray<T>()orffi.java.JArray<T>(arrayExpr: Array<T>).let a: JArray<Int64> = JArray<Int64>([0, 1, 2, 3, 4, 5])
Similar to Array, for the arr instance of the ffi.java.JArray<T> type, the array length is n. The arr[i] method can be used to access the element in a specific location. The i is the Int32 type from 0 to the array length n-1.
Note: The type of the
iindex ofJArrayisInt32, which is consistent with theintindex ofJava.
Members of the ffi.java.JArray<T> type are the same as those of the Java built-in array type, including the length variable, clone method, and other methods inherited from java.lang.Object.
In Java, the direct supertype of Integer[] is Number[]. However, when Integer[] is used in Cangjie, ffi.java.JArray<Integer> and ffi.java.JArray<Number> have no supertype-subtype relationship. For details, see [Generics].
Java Enum
The enumeration type of Java is a special class. In Cangjie, the enumeration type of Java is directly mapped to the subclass of java.lang.Enum. The use of this class complies with the same mapping rules and restrictions as those of common Java classes.
The enumeration class Day on the Java side is defined as follows:
// Java code
package com.example;
public enum Day {
MONDAY, TUESDAY, WEDNESDAY,
THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
The classes mapped by the Day enumeration type on the Cangjie side have the following features:
-
By default, this class inherits the
Java.lang.Enum<E>abstract class, whereEis a generic type variable. For example, if the enumeration classDayis used,Eis theDayclass. -
All enumeration members are of the
Daytype and havepublicandstaticmember variables. (opencorresponds tofinalon theJavaside, therefore, it is not included.) -
By default, this class implements the following member functions with
publicandstatic:public static func values(): JArray<E>
The
valuesfunction returns all constant values in the enumeration as an array.public static func valueOf(name: JString): E
The
valueOffunction returns enumeration constants with specified names. (These constants are initialized asMONDAY = new Day("MONDAY", 0)inJava.)
Import the Day enumeration class to Cangjie. The example is as follows:
// Cangjie code
import com.example.*
main(){
var day = Day.MONDAY
var values = Day.values()
day = values[0] // day's value is Day.MONDAY, values
day = Day.valueOf("MONDAY") // day's value is Day.MONDAY
}
Java lambda
The type of the lambda expression on the Java side is a specific functional interface type. A functional interface in Java refers to an interface that has only one abstract method (except the Object method). In Java, you can create an instance of the functional interface by declaring and instantiating the class and lambda expression.
In Cangjie, you can directly import the functional interface on the Java side. You can also declare an interface with only one abstract method and add the @Java modifier to use the interface as the functional interface on the Java side. In Cangjie, instances of functional interfaces can be created only by class instantiation. The class must be modified by @Java and the corresponding functional interface must be implemented.
In Cangjie, when calling a method whose input parameter is of the java lambda type, you need to pass the corresponding function interface instance.
// Java code
package com.example;
public interface MathOperation {
int operation(int a, int b);
}
public class LambdaExample{
public MathOperation add = (int a, int b) -> a + b // The Java side can be created directly using a lambda expression.
public int foo(int a, int b, MathOperation op){
return op.operation(a, b);
}
}
The sample code for accessing add and foo in Cangjie is as follows:
// Cangjie code
import com.example.*
@Java
class Sub <: MathOperation {
func operation(a: Int32,b: Int32): Int32{
return a - b
}
}
main(){
var instance = LambdaExample()
var add = instance.add // Direct access to Java-side functional interface type properties.
instance.foo(1,2,add) // Transfer the instance obtained from the Java side.
var sub = Sub() // Create an instance.
instance.foo(2,1,sub) // Result is 1.
}
Note: The native
lambdatype in Cangjie does not directly map tolambdainJava.
Java Variable-length Arguments (varargs)
In Cangjie, the varargs of Java are mapped to the ffi.java.JArray<T> array type of the corresponding T type. When calling the vararrgs, you need to manually create the corresponding ffi.java.JArray<T> array instance and pass it.
When calling, the code for creating the parameter array and passing it is as follows:
// Java code
package com.example;
public class JavaVarargsExample{
public void foo(int... ele){
// some code
}
}
The code for calling in Cangjie is as follows:
// Cangjie code
import com.example.*
import std.ffi.java
main(){
var varargsExample = JavaVarargsExample()
var array64: Array<Int64> = [0, 1, 2, 3, 4, 5]
var array32: Array<Int32> = [0, 1, 2, 3, 4, 5]
var argsArray = ffi.java.JArray<Int32>([0, 1, 2, 3, 4, 5])
varargsExample.foo(argsArray) // The compiler needs to pass this type as a variable type.
}
Java Modifiers
When the imported Java classes, interfaces, and their members are used in Cangjie, their modifiers are mapped according to the rules in the following table. For example, when a class member modified by protected on the Java side is imported to Cangjie, the class member can be accessed only in its subclasses.
| Modifier kind | Java | Cangjie |
|---|---|---|
| class/interface/method/field | public | public |
| method/field | protected | protected |
| class | abstract | abstract (class) |
| method/field | static | static |
| class/method | final/(non final) | (non open)/open |
| field | final/(non final) | let/var |
| method | @Override | override |
Note: The strictfp modifier is not supported currently. By default, the precision of the floating-point result in Java depends on the hardware. Using the strictfp to modify classes, interfaces or methods can ensure platform-independent floating-point computation.
Java can use transient to declare member variables of a class. These member variables will be ignored in the persistence (serialization) operation. In Cangjie, a member variable cannot be explicitly marked as transient. However, fields inherited from Java that are marked as transient will retain their original features in Cangjie. For example, when the serialization method on the Java side is called in Cangjie, the member variables are ignored in the same way as they are in Java. Similarly, the original semantics of the synchronized and native methods on the Java side are retained when the methods are called in Cangjie. However, Cangjie does not support explicit declaration of a member method as synchronized or native.
Note that Cangjie does not support the access to volatile member variables. An error will be reported during compilation for the access to such variables. To access such variables, the corresponding operation method must be encapsulated on the Java side for use in Cangjie.
Nullable Types
For any Java type that may be null, you can use it in Cangjie in either of the following ways:
-
Directly use it as non-empty types in Cangjie.
When the nullable variable obtained from
Javais stored in any non-nullable variable, if the value isnull,JavaExceptionis thrown during running. This exception encapsulates the underlyingNullPointerExceptionthat occurred.For a reference variable whose value is
null,JavaExceptionis thrown during running when you directly access its members or calls its member methods. The nullable variables obtained fromJavarefer to imported member variables or method parameters of theJavatype. -
Store it in a variable of the
Optiontype.The compiler automatically encapsulates the value into the
Optiontype. If the value isnullduring running, the value is mapped toNoneof theOptiontype. Otherwise, the value is mapped toSome constructor.
// Java code
package com.example;
import java.lang.Integer;
public class JavaClass {
public Integer a = null;
public Integer foo(Integer a) {
Integer b = 100 + a;
return b;
}
}
// Cangjie code
import com.example.JavaClass
from java8 import java.lang.Integer
main(){
var obj = JavaClass()
obj.a.toString() // The value of obj.a is null at runtime. The `JavaException` will be thrown at runtime.
var a1: Integer = obj.a // The value of obj.a is null at runtime. The null value is assigned to a non-Option variable. In this case, the `JavaException` will be thrown.
var a2: ?Integer = obj.a // The compiler automatically encapsulates obj.a as an optional type. The actual value of a2 is Option<Integer>.None.
a2?.toString() // a2 = Option<Integer>.None, the `toString()` method will not be invoked.
var a3: ?Integer = Option<Integer>.None
obj.foo(a3.getOrThrow()) // `a3.getOrThrow()` will throw an `NoneValueException` exception.
var ret: ?Integer = obj.foo(obj.a) // The value of obj.a is null at runtime, `JavaException` will be thrown at runtime.
}
Exceptions
When Java code is called on the Cangjie side, all exceptions thrown by Java are mapped to the Cangjie class JavaException and can be captured by Cangjie. Similarly, when the Cangjie code is executed on the Java side, all exception classes thrown by the Cangjie side are mapped to the Java class CangjieException, which can be captured on the Java side. The following table lists their mapping relationships.
| Cangjie Type | Java Type |
|---|---|
| Exception or Error and their subclasses | CangjieException |
| JavaException | Throwable and its subclasses |
The try/catch statement can be used to capture mapped exceptions on both the Cangjie and Java sides. When an exception thrown by Java is captured on the Cangjie side, the getCause method can be used to obtain the exception class thrown by the exception and then determine and process the exception. See the following example:
// Cangjie Code
from java8 import java.lang.Integer
from java8 import java.lang.Throwable
from java8 import java.lang.NumberFormatException
from java8 import java.lang.ArrayIndexOutOfBoundsException
main() {
try {
var s = J"abc"
var n = Integer.parseInt(s) // It will throw exception.
let array = JArray<Int64>([0, 1, 2, 3, 4, 5])
var el = array[n]
} catch (e: JavaException) {
var cause: Throwable = e.getCause()
match (cause) {
case _: NumberFormatException => print("Wrong parseInt input!")
case _: ArrayIndexOutOfBoundsException => print("Out of Bounds!")
case _ => ()
}
}
}
Generics
In Cangjie, you can directly import Java generic types to create instances, call methods, inherit generic classes, and implement generic interfaces. The imported Java generic types and generic types modified by @Java are erased during compilation (consistent with Java).
The sample code for calling a generic type in Cangjie is as follows:
// Cangjie code
from java8 import java.util.ArrayList as JArrayList
from java8 import java.lang.Integer
main(){
var arrayList = JArrayList<Integer>()
arrayList.add(Integer(1))
arrayList.add(Integer(3))
arrayList.add(Integer(5))
var iter = arrayList.iterator()
while (iter.hasNext()) {
iter.next().toString()
}
}
Most Java generics can be directly used in Cangjie, but must comply with certain mapping rules and usage restrictions. For details, see the following sections.
Constraints on Java Parameters
In Java, the upper bound of a generic parameter can be specified only by extends (the lower bound cannot be specified). There can be multiple upper bounds. The first upper bound must be a class, and the subsequent upper bounds must be interfaces. The syntax of the type parameter constraint is as follows, where T indicates the type parameter, C1 indicates the class name, and I1, I2, ..., and In indicate the interface name. The upper bounds are connected by the & symbol.
T extends C1 & I1 & I2 & ... &In
T extends C1
T extends I1
The preceding syntax can be directly mapped to the following syntax:
where T <: C1 & I1 & I2 & ... &In
where T <: C1
where T <: I1
Note that the type parameters of the generic classes and interfaces modified by @Java implicitly contain the constraint where T <: java.lang.Object (except T in ffi.java.JArray<T>, which may also be the basic type that meets the JType constraint).
Wildcards in Java
In Java, wildcards are used to represent a series of types and can be used as type parameters (not used in generic methods). There are three types of wildcards: unbounded, upper bound, and lower bound.
In Java, wildcards can be used as type parameters when non-wildcard type constraints are too strict. A compilation error occurs when the sort method is called in the following code:
// Java code
class Person implements Comparable<Person> {}
class Student extends Person {}
class Utilities {
public static <T extends Comparable<T>> void sort(List<T> list) {}
}
List<Student> list = new ArrayList<Student>();
Utilities.sort(list); // error
If wildcards are used as type parameters, sort can be called properly as follows:
// Java code
class Utilities {
public static <T extends Comparable <? super T > > void sort(List<T> list) {
}
}
In Cangjie, the wildcard type is not supported, but the mapping can be performed based on certain rules. All wildcard types that need to be mapped are as follows:
- Imported member variables, method input parameters, and method return values of the
Javatype. - The Cangjie type modified by
@Javainherits or overrides the input parameters and return values of the method of theJavatype.
The mapping rules are as follows:
| Java | Cangjie |
|---|---|
List<? super T> | List<java.lang.Object> |
List<? extends T> | List<T> |
List<?> | List<java.lang.Object> |
Generic Instance Member Functions
In Cangjie, when inheriting or implementing the imported Java type, you can use the generic member function to override superclass member function. Note that:
-
The syntax requirements of generic member functions are the same as those of global generic member functions.
-
The class or interface where the generic member function is located must be modified by
@Java. -
Generic member functions must be modified by
override.Note that the return type must be the same as the return type of the overridden method or the subtype of the return type.
The sample code is as follows:
// Cangjie code
package example
import java.GenericClassExample // Importing Java Generic Types.
@Java
class B <: GenericClassExample {
override public foo<T>(t:T) { // Overrides super class member functions only.
// do something
}
}
main(){
var p = B()
p.foo(p)
}
In Cangjie, a subclass member cannot shadow a superclass member, but Java allows. When the two Java classes that constitute shadowing are used in Cangjie, the access to the shadowed variables at run-time are the same as that on the Java side. If an imported or @Java-modified type is used as the upper bound of a generic constraint in a pure Cangjie generic function or generic class, do not use the Java subtype that constitute shadowing with this type as the type argument of the generic function or generic class. This restriction does not apply to other Java subtypes that do not constitute shadowing with this type.
Assume that the following Java class exists:
// Java code
package com.example;
public class Parent {
public int data = 1;
}
public class Child extends Parent {
public String data = "child"; // shadowing with super class
}
public class House extends Parent {
public int price = 100; // no shadowing
}
The import and usage in Cangjie is as follows:
// Cangjie code
import com.example.*
import std.ffi.java.*
func f<T>(t: T) where T <: Parent {
t.data // The t.data type is Int32 during compilation.
}
class A<T> where T <: Parent {
public func method(t: T) {
t.data // The t.data type is Int32 during compilation.
}
}
main() {
let p = Parent()
let c = Child()
let h = House()
f<Parent>(p) // ok, return type is Int32
f<Parent>(c) // ok, return type is Int32
f<Child>(c) // compile error
f<House>(h) // ok, return type is Int32
let obj1 = A<Parent>() // ok
obj1.method(p) // ok, return type is Int32
obj1.method(c) // ok, return type is Int32
obj1.method(h) // ok, return type is Int32
let obj2 = A<Child>() // compile error
let obj3 = A<House>() // ok
obj3.method(h) // ok, return type is Int32
}
Java Raw Type
The Raw type on the Java side is mapped to the generic type of Cangjie according to the following table. Note that if the type of a member variable in a Java type, the parameter type of a member method, or the return value type uses the Raw type that contains generic constraints with multiple upper bounds, Cangjie does not support access to its member variables or member methods.
| Java Generic Type | Java Raw Type | Cangjie |
|---|---|---|
C0<T> | C0 | C0<java.lang.Object> |
C1<T extends Bound1> | C1 | C1<Bound1> |
C2<T extends Bound1 & Bound2 ...> | C2 | Not support |
The sample code is as follows:
// Java Code
package com.example;
// no upper bound.
public class C0<T> { ... }
// has one upper bound.
public class C1<T extends Number> { ... }
// has more then one upper bounds.
public class C2<T extends Number & Clonable> { ... }
public class RawTypeExample {
public C0 a; // C0 is a raw type
public C1 b; // C1 is a raw type
public C2 c; // C2 is a raw type
public C2 createC2() {...}
}
The sample code of its usage in Cangjie is as follows:
// Cangjie code
import com.example.*
from java8 import java.lang.Object as JObject
from java8 import java.lang.Number as JNumber
main() {
var obj = RawTypeExample()
let a: ?C0<JObject> = obj.a // ok
let b: ?C1<JNumber> = obj.b // ok
let c = obj.c // compile error
let d = obj.createC2() // compile error
}
Java Annotations
Java annotation is a special interface type. Some user-defined annotation types on the Java side are mapped to the Cangjie annotation type. The annotation types can be imported and used on the Cangjie side, but can be used only in the types modified by @Java.
The sample code in which an annotation type is defined in Java is as follows:
// Java code
package com.example;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface JavaAnno {
String value();
}
Import the preceding annotations to Cangjie and use them. The sample code is as follows:
// Cangjie code
import com.example.*
// pure cangjie class
class CangjieClass {
@JavaAnno[J"value"] // compile error, annotation types from java can only be used in @Java-modified types.
func a(): Unit{}
}
@Java
class JavaClass {
@JavaAnno[J"value"] // OK
func a():Unit {}
}
Java built-in annotation types cannot be imported. Java 8 built-in annotation types include @Override, @Deprecated, @SuppressWarnings, @Retention, @Documented, @Target, @Inherited, @SafeVarargs, @FunctionalInterface, @Repeatable, and @Native.
The annotation type whose @Retention attribute value is RetentionPolicy.SOURCE in Java cannot be imported.
When the imported Java annotation type is used on the Cangjie side, the usage position restrictions of the Cangjie annotation must be met. For details, see the description of the target parameter in [Annotations]. Java uses the @Target annotation (the received parameter is a ElementType[]) to specify the positions where the modified annotation types can be used. The function of the @Target annotation is the same as that of the target parameter in the Cangjie annotation (the received parameter is an Array<AnnotationKind>). For an imported Java annotation type:
- If the
@Targetannotation is used to restrict its usage location, the@Targetattribute value is mapped to thetargetparameter value of the Cangjie annotation according to the following table. - If the
@Targetannotation is not used, thetargetparameter value of the Cangjie annotation is mapped to[Type, Parameter, Init, MemberFunction, MemberVariable].
| Java ElementType | Cangjie AnnotationKind |
|---|---|
| TYPE | Type |
| FIELD | MemberVariable |
| METHOD | MemberFunction |
| PARAMETER | Parameter |
| CONSTRUCTOR | Init |
| LOCAL_VARIABLE | - |
| ANNOTATION_TYPE | - |
| PACKAGE | - |
| TYPE_PARAMETER | - |
| TYPE_USE | - |
Unsupported Scenarios
- Java identifiers support the Unicode character set, but Cangjie identifiers do not. Cangjie does not support the import of Java packages, types, member methods, or member variables that do not comply with the Cangjie identifier naming rules.
| Comparison | Java identifier | Cangjie identifier |
|---|---|---|
| Starting Character | Any Unicode character that is a "Java letter", includes uppercase and lowercase ASCII Latin letters A-Z (\u0041-\u005a), and a-z (\u0061-\u007a), the ASCII underscore (_,or \u005f) and dollar sign ($, or \u0024), and other Unicode characters(such as Chinese, Japanese, and Korean, etc.) | Uppercase and lowercase ASCII Latin letters A-Z and a-z, or ASCII underscore (_). Digits 0-9 (\u0030-\u0039) are not allowed. |
| Following Character | Any Unicode character that is a "Java letter-or-digit". | Uppercase and lowercase ASCII Latin letters A-Z and a-z, ASCII underscore (_), ASCII digits 0-9. NOTE: If the identifier begins with one or more underscores, the first subsequent character cannot be a digit. |
Examples of identifiers are as follows:
| Identifier | Valid in Java? | Valid in Cangjie? |
|---|---|---|
中文 | Yes | No |
0中文 | No | No |
0a | No | No |
a中文 | Yes | No |
_中文 | Yes | No |
_a | Yes | Yes |
_0 | Yes | No |
$中文 | Yes | No |
$a | Yes | No |
$0 | Yes | No |
\u0061 | Yes ('\u0061' == 'a') | No |
\u0030 | No ('\u0030' == '0') | No |
- Java supports nested types (including inner classes, nested interfaces, and nested enumerations), but Cangjie does not. Currently, Cangjie does not support the import of nested types on the Java side. If a Java member variable, or the input parameter or return value type of a member method uses the Java nested type, Cangjie cannot access the corresponding Java member variable or member method.
In the following Java code, the OuterClass class can be imported to Cangjie, but the nested types defined in the OuterClass class cannot be imported, and the value member variables and foo member methods cannot be accessed.
// Java code
public class OuterClass {
public class InnerClass {
// ...
}
public static class StaticInnerClass {
// ...
}
public interface InnerInterface {
// ...
}
public enum InnerEnum {
// ...
}
public StaticInnerClass value;
public InnerEnum foo(InnerInterface arg) {
// ...
}
}
- Java allows member variables to have the same name as member methods, but Cangjie does not. Cangjie can access only the member methods with the same name, but cannot access the corresponding member variables.
The following Java code is used as an example:
// Java code
package com.company;
public class Example {
public int foo = 10;
public int foo() { // method has the same name as field
}
}
After it is imported to Cangjie, only the foo member method can be accessed. The foo member variable cannot be accessed. The following is an example:
// Cangjie code
import com.company.*
main() {
let obj = Example()
let a: Int32 = obj.foo // compile error, type mismatch
obj.foo() // ok
let f: () -> Int32 = obj.foo // ok
}
- Java supports generic constructors, but Cangjie does not. Cangjie does not support calling Java generic constructors.
In the following Java code, Cangjie cannot call the following Java generic constructors:
// Java code
package com.company;
public class Example {
public <T> Example(T a) {
// ...
}
}
public class Example2<T> {
public <E> Example2(E a) {
// ...
}
}
Metaprogramming
Metaprogramming allows code to be represented as operable data objects that can be added, deleted, modified, and queried. To support this, Cangjie provides compilation tags for metaprogramming.
Compilation tags are classified into macros and annotations. The macro mechanism supports code transformation during compilation based on the Tokens type, and supports basic operations such as converting code into data and concatenating code.
quote Expression and Tokens Type
Cangjie uses the quote expression to reference specific code, representing it as an operable data object. The syntax of the quote expression is defined as follows:
quoteExpression
: 'quote' quoteExpr
;
quoteExpr
: '(' quoteParameters ')'
;
quoteParameters
: (quoteToken | quoteInterpolate | macroExpression)+
;
quoteToken
: '.' | ',' | '(' | ')' | '[' | ']' | '{' | '}' | '**' | '*' | '%' | '/' | '+' | '-'
| '|>' | '~>'
| '++' | '--' | '&&' | '||' | '!' | '&' | '|' | '^' | '<<' | '>>' | ':' | ';'
| '=' | '+=' | '-=' | '*=' | '**=' | '/=' | '%='
| '&&=' | '||=' | '&=' | '|=' | '^=' | '<<=' | '>>='
| '->' | '=>' | '...' | '..=' | '..' | '#' | '@' | '?' | '<:' | '<' | '>' | '<=' | '>='
| '!=' | '==' | '_' | '\\' | '`' | '$'
| 'Int8' | 'Int16' | 'Int32' | 'Int64' | 'UInt8' | 'UInt16' | 'UInt32' | 'UInt64' | 'Float16'
| 'Float32' | 'Float64' | 'Rune' | 'Bool' | 'Unit' | 'Nothing' | 'struct' | 'enum' | 'This'
| 'package' | 'import' | 'class' | 'interface' |'func' | 'let' | 'var' | 'type'
| 'init' | 'this' | 'super' | 'if' | 'else' | 'case' | 'try' | 'catch' | 'finally'
| 'for' | 'do' | 'while' | 'throw' | 'return' | 'continue' | 'break' | 'as' | 'in' | '!in'
| 'match' | 'from' | 'where' | 'extend' | 'spawn' | 'synchronized' | 'macro' | 'quote' | 'true' | 'false'
| 'sealed' | 'static' | 'public' | 'private' | 'protected'
| 'override' | 'abstract' | 'open' | 'operator' | 'foreign'
| Identifier | DollarIdentifier
| literalConstant
;
quoteInterpolate
: '$' '(' expression ')'
;
The syntax rules of the quote expression are as follows:
- The
quotekeyword is used to define thequoteexpression. - The
quoteexpression is followed by(), where it can reference values of the Token type, code interpolation, and macro call expressions. - The
quoteexpression is of theTokenstype.Tokensis a type provided by the Cangjie standard library. It is a sequence consisting of lexical units (tokens).
In the preceding syntax definition, quoteToken refers to any valid token supported by the Cangjie compiler, except for tokens that cannot be parsed by Lexer, such as comments and terminators. However, when a newline character is used as the separator between two expressions, it is not ignored and is parsed as a quoteToken. In the following example, only the newline character between two assignment expressions is parsed as quoteToken, and other newline characters in the quote expression are ignored.
// The newline character between assignment expression is preserved, others are ignored.
quote(
var a = 3
var b = 4
)
Consecutive quotes without code interpolation are not allowed. For details about code interpolation, see the next section. When the quote expression references the following tokens, escape is required:
- Unpaired parentheses are not allowed in the
quoteexpression. However, parentheses escaped by\are not counted in the matching rule. - When
@indicates a commontokeninstead of a macro call expression,\needs to be used for escape. - When
$indicates a commontokeninstead of code interpolation,\needs to be used for escape.
Note: The token (in lower case) mentioned in this chapter refers to the lexical unit parsed by Cangjie Lexer.
The following are some quote expression examples that use Tokens or code interpolation as parameters:
let a0: Tokens = quote(==) // ok
let a1: Tokens = quote(2+3) // ok
let a2: Tokens = quote(2) + quote(+) + quote(3) // ok
let a3: Tokens = quote(main(): Int64 {
0
}) // ok
let a4: Tokens = quote(select * from Users where id=100086) // ok
let b0: Tokens = quote(() // error: unmatched `(`
let b1: Tokens = quote(quote(x)) // ok -- `b1.size == 4`
The quote expression can also reference a macro call expression. For example:
quote(@SayHi("say hi")) // a quoted, un-expanded macro -- macro expansion happens later
Cangjie provides the Tokens type to indicate the token sequence parsed from the original text information. Tokens supports the use of operator + to concatenate the token results of two objects into a new object. In the following example, a1 and a2 are basically equivalent.
let a1: Tokens = quote(2+3) // ok
let a2: Tokens = quote(2) + quote(+) + quote(3) // ok
Code Interpolation
In a quote expression, $ is used as the code interpolation operator. The operator is followed by an expression, indicating that the value of the expression is converted into tokens. This operator is a unary prefix operator and can be used only in quote expressions. It has a higher priority than other operators.
Code interpolation can be applied to all valid Cangjie expressions. Code interpolation is not an expression and does not have a type.
var rightOp: Tokens = quote(3)
quote(2 + $rightOp) // quote(2 + 3)
For an expression to be eligible for code interpolation, it must implement the ToTokens interface. The format of the ToTokens interface is as follows:
interface ToTokens {
func toTokens(): Tokens
}
- Most value types in Cangjie, including the numeric type,
Runetype,Booltype, andStringtype, have default implementations. - The
Tokenstype implements theToTokensinterface by default, and thetoTokensfunction returns this instance. - The user-defined data structure must proactively implement the
ToTokensinterface. The Cangjie standard library provides various interfaces for generatingTokens. For example, for the variablestrof theStringtype, you can directly usestr.toTokens()to obtain theTokenscorresponding tostr.
quote Expression Evaluation Rules
The rules for references within the parentheses of the quote expression are as follows:
- Code interpolation: The result of the interpolated expression
.toTokens()is used. - Common
tokens: The correspondingTokensresult is used.
Based on the preceding conditions, the quote expression then concatenates all the Tokens according to the order in which they appear in the expression.
The following are some quote expression evaluation examples. The comments indicate the returned Tokens results.
var x: Int64 = 2 + 3
// tokens in the quote are obtained from the corresponding Tokens.
quote(x + 2) // quote(x + 2)
// The Tokens type can only add with Tokens type.
quote(x) + 1 // error! quote(x) is Tokens type, cannot add with integer
// The value of code interpolation in quote equals to the tokens result corresponding to the value of the interpolation expression.
quote($x) // quote(5)
quote($x + 2) // quote(5 + 2)
quote($x + (2 + 3)) // quote(5 + (2 + 3))
quote(1 + ($x + 1) * 2) // quote(1 + (5 + 1) * 2)
quote(1 + $(x + 1) * 2) // quote(1 + 6 * 2)
var t: Tokens = quote(x) // quote(x)
// without interpolation, the `t` is the token `t`
quote(t) // quote(t)
// with interpolation, `t` is evaluated and expected to implement ToTokens
quote($t) // quote(x)
quote($t+1) // quote(x+1)
// quote expressions can be used inside of interpolations, and cancel out
quote($(quote(t))) // quote(t)
quote($(quote($t))) // quote(x)
quote($(t+1)) // error! t is Tokens type, cannot add with integer
public macro PlusOne(input: Tokens): Tokens {
quote(($input + 1))
}
// Macro invocations are preserved, unexpanded, until they are re-inserted into the code by
// the macro expander. However, interpolation still happens, including among the arguments
// to the macro
quote(@PlusOne(x)) // quote(@PlusOne(x))
quote(@PlusOne($x)) // quote(@PlusOne(5))
quote(@PlusOne(2+3)) // quote(@PlusOne(2+3))
quote(1 + @PlusOne(x) * 2) // quote(1 + @PlusOne(x) * 2)
// When the macro invocation is outside the quote, the macro expansion happens early
var y: Int64 = @PlusOne(x) // 5 + 1
quote(1 + $y * 2 ) // quote(1 + 6 * 2)
Macros
Macros are an essential technology for metaprogramming. Similar to functions, macros can be called and have inputs and outputs. The difference is that the macro code is expanded during compilation. Cangjie replaces the macro call expression with the expanded code. You can use macros to compile code templates (codes for generating code). In addition, macros provide the capability to define custom grammars, allowing you to flexibly define your own DSL grammars. Finally, Cangjie provides various code operation interfaces for you to easily complete code transformation.
Macros are classified into two types: non-attribute macros and attribute macros. Compared with a non-attribute macro, an attribute macro can analyze and transform the macro input based on different attributes to obtain different output results.
Macro Definition
In Cangjie, macro definition must comply with the following syntax rules:
macroDefinition
: 'public' 'macro' identifier
(macroWithoutAttrParam | macroWithAttrParam)
(':' identifier)?
('=' expression | block)
;
macroWithoutAttrParam
: '(' macroInputDecl ')'
;
macroWithAttrParam
: '(' macroAttrDecl ',' macroInputDecl ')'
;
macroInputDecl
: identifier ':' identifier
;
macroAttrDecl
: identifier ':' identifier
;
The summary is as follows:
-
The keyword
macrois used to define a macro. -
macromust be preceded bypublic, indicating that themacrois visible to the outside of the package. -
The
macromust be followed by the macro name. -
Macro parameters are enclosed by
(). For a non-attribute macro, one parameter of theTokenstype corresponds to the input of the macro. For an attribute macro, two parameters of theTokenstype correspond to the attribute and input of the macro respectively. -
The default return type function is fixed to
Tokens.
The following is an example of a non-attribute macro. It contains all elements of the macro definition: public indicates that the macro is visible to the outside of the package; macro is the keyword; foo is the identifier of the macro; x is the parameter and its type is Tokens; the return value and its type are the same as that of the input.
public macro foo(x: Tokens): Tokens { x }
public macro bar(x: Tokens): Tokens {
return quote($x) // or just `return x`
}
The following is an example of an attribute macro. Compared with the non-attribute macro, the attribute macro has an additional input of the Tokens type. More flexible operations can be performed in the macro definition body.
public macro foo(attr: Tokens, x: Tokens): Tokens { attr + x }
public macro bar(attr: Tokens, x: Tokens): Tokens {
return quote($attr + $x)
}
Once a macro is defined, the macro name cannot be assigned a value. In addition, macros have strict requirements on the parameter type and number of parameters.
Macro Call
The macro call expression complies with the following syntax rules:
macroExpression
: '@' identifier macroAttrExpr?
(macroInputExprWithoutParens | macroInputExprWithParens)
;
macroAttrExpr
: '[' quoteToken* ']'
;
macroInputExprWithoutParens
: functionDefinition
| operatorFunctionDefinition
| staticInit
| structDefinition
| structPrimaryInit
| structInit
| enumDefinition
| caseBody
| classDefinition
| classPrimaryInit
| classInit
| interfaceDefinition
| variableDeclaration
| propertyDefinition
| extendDefinition
| macroExpression
;
macroInputExprWithParens
: '(' macroTokens ')'
;
macroTokens
: (quoteToken | macroExpression)*
;
The rules for macro call expressions are as follows:
- The
@keyword is used to define the macro call expression. - A macro call is enclosed in
(). The value in the parentheses can be any validtokens, but cannot be blank. - When an attribute macro is called, the macro attributes are enclosed in
[]. The value in the square brackets can be any validtokens, but cannot be blank.
When the macro call expression references the following tokens, escape is required:
- Unpaired parentheses, such as
@ABC(we have two (( and one )), are not allowed in macro call expression parameters. However, parentheses escaped by\are not counted in the matching rule. - Unpaired square brackets, such as
@ABC[we have two [[ and one ]](), are not allowed in attribute macros. However, square brackets escaped by\are not counted in the matching rule. - When
@is referenced in macro call expression parameters,\needs to be used for escape.
When a macro call is used before some declarations or expressions, parentheses can be omitted, and its semantics is different from that of the macro call without parentheses. The macro call parameter with parentheses can be any valid tokens. The macro call parameter without parentheses must be one of the following declarations or expressions:
- Function declaration
structdeclarationenumdeclarationenum constructor- Class declaration
- Static initializer
- Class and
structconstructor and primary constructor - API declaration
- Variable declaration
- Property declaration
- Extension declaration
- Macro call expression
In addition, the macro call parameters without parentheses must meet the following requirements:
- If the parameter is a declaration, the macro call can only appear in the position where the declaration is allowed.
The following are examples of calling non-attribute macros, attribute macros, and macros without parentheses.
func foo()
{
print("In foo\n")
}
// Non-attribute macros
public macro Twice(input: Tokens): Tokens
{
print("Compiling the macro `Twice` ...\n")
quote($input; $input)
}
@Twice(foo()) // After Macro expand: foo(); foo()
@Twice() // error, parameters in macro invocation can not be empty.
// Attributed macros
public macro Joint(attr: Tokens, input: Tokens): Tokens
{
print("Compiling the macro `Joint` ...\n")
quote($attr; $input)
}
@Joint[foo()](foo()) // After Macro expand: foo(); foo()
@Joint[foo()]() // error, parameters in macro invocation can not be empty.
@Joint[](foo()) // error, attribute in macro invocation can not be empty.
// Non-attribute macros
public macro MacroWithoutParens(input: Tokens): Tokens
{
print("Compiling the macro `MacroWithoutParens` ...\n")
quote(func foo() { $input })
}
@MacroWithoutParens
var a: Int64 = 0 // After Macro expand: func foo() { var a: Int64 = 0 }
public macro echo(input: Tokens) {
return input
}
@echo class A {} // ok, class can only be defined in top-level, so is current macro invocation
func goo() {
@echo func tmp() {} // ok, function can be defined in another function body,
// so is current macro invocation
@echo class B {} // error, class can only be defined in top-level, so is current macro invocation
}
As an expression, a macro call can appear at any position where an expression is allowed. In addition, macro call can appear at positions of the following declarations: function declaration, struct declaration, enum declaration, class declaration, interface declaration, variable declaration (except function parameters), property declaration, and extension declaration.
Macros are visible only during compilation. During compilation, the macro call expression is replaced by the code after macro expansion. Macro expansion indicates that the macro definition is executed during code compilation. The execution result is parsed into a Cangjie syntax tree to replace the macro call expression. After semantic analysis, the replaced node has corresponding type information, and the type may be considered as a type of a macro call expression. In the preceding example, when you call macros such as @Twice, @Joint, and @MacroWithoutParens, the code in the macro definition is compiled and executed, and the Compiling the macro... is printed. The execution result is used as a new syntax tree node to replace the original macro call expression.
When macro call occurs in different contexts, the following rules must be complied:
-
If a macro call appears in the context of the expected expression or declaration, the macro call is expanded into program text during compilation.
-
If a macro call appears in the context of the expected token sequence (as a parameter of the macro call expression or
quoteexpression), the macro call is called at the time when the token sequence is evaluated, and the return value (token sequence) of the macro call is directly used without being expanded into the program text.
Importing Macro Scopes and Packages
The macro must be defined at the top level of the source file and the scope is the entire package.
The package where the macro definition is located must be declared using macro package. For packages specified by macro package, only the macro definition declaration is visible to the outside of the package. Other declarations are visible only in the package. If other declarations are modified to be visible to the outside of the package, an error is reported.
//define.cj
macro package define // modify package with macro
import std.ast.*
// public func A(){} // error: func A can not be modified by `public`
public macro M(input:Tokens): Tokens{ // only macros can be modified by `public`
return input
}
// call.cj
package call
import define.*
main(){
@M()
return 0
}
The macro import complies with the general package import rules of Cangjie.
Note that macro package can be re-exported only by macro package.
// A.cj
macro package A
public macro M1(input:Tokens):Tokens{
return input
}
// B.cj
package B
//public import A.* // error: macro packages can only be `public import` in macro packages
public func F1(input:Int64):Int64{
return input
}
// C.cj
macro package
public import A.* // only macro packages can be public import in macro packages
// public import B.* // error: normal packages can not be public import in macro packages
import B.*
public macro M2(input:Tokens):Tokens{
return @M1(input) + Token(TokenKind.ADD) + quote($(F1(1)))
}
In the same package, the conventions for macros with the same name are the same as those of functions. The following table lists the rules for attribute macros and non-attribute macros.
| Same name, Same package | attribute macros | non-attribute macros |
|---|---|---|
| attribute macros | NO | YES |
| non-attribute macros | YES | NO |
Nested Macros and Recursive Macros
Macros allow for nested calls to other macros.
If a macro call expression contains macro call, for example, @Outer @Inner(2+3), the inner macro is executed first, followed by the outer macro. The Tokens result returned by the inner macro is concatenated with other Tokens and passed to the outer macro for calling. The inner macro and the outer macro can be different macros or the same macro.
An inner macro can call the AssertParentContext library function to ensure it is nested in a specific outer macro call. If the call of this function by the inner macro is not nested within the given outer macro call, the function throws an error. The second function InsideParentContext returns true only when the inner macro call is nested in the given outer macro call.
public macro Inner(input: Tokens): Tokens {
AssertParentContext("Outer")
// ...or...
if (InsideParentContext("Outer")) {
// ...
}
}
The inner macros can communicate with the outer macro by sending key/value pairs. When an inner macro is executed, the standard library function SetItem is called to send a message. When an outer macro is executed, the standard library function GetChildMessages is called to receive the message (a key/value pair mapping) sent by each inner macro.
public macro Inner(input: Tokens): Tokens {
AssertParentContext("Outer")
SetItem("key1", "value1")
SetItem("key2", "value2")
// ...
}
public macro Outer(input: Tokens): Tokens {
let messages = GetChildMessages("Inner")
for (m in messages) {
let value1 = m.getString("key1")
let value2 = m.getString("key2")
// ...
}
}
When the macro definition body contains macro calls, if the macro calls appear in the context of the expected token sequence, the two macros can be different macros or the same macro (that is, recursion is supported). Otherwise, the nested macro cannot be the same as the called macro. For details, see the following two examples.
In the following example, the nested macro appears in the quote expression, indicating that recursive call is supported.
public macro A(input: Tokens): Tokens {
print("Compiling the macro A ...\n")
let tmp = A_part_0(input)
if cond {
return quote($tmp)
}
let bb: Tokens = quote(@A(quote($tmp))) // ok
A_part_1()
}
main():Int64 {
var res: Int64 = @A(2+3) // ok, @A will be treated as Int64 after macro expand
return res
}
In this example, when macro A is not called by external systems, it is not executed (even if macro A is called internally), that is, Compiling the macro A... is not printed. if cond is the recursive termination condition. Note that macro recursion and function recursion have similar constraints. A termination condition is required; otherwise, an infinite loop occurs and the compilation cannot be terminated.
In the following example, the nested macro is not in the quote expression, therefore, recursive call is not supported.
public macro A(input: Tokens): Tokens {
let tmp = A_part_0(input)
if cond {
return quote($tmp)
}
let bb: Tokens = @A(quote($tmp)) // error, recursive macro expression not in quote
A_part_1()
}
main():Int64 {
var res: Int64 = @A(2+3) // error, type mismatch
return res
}
The rules for nested macro call and recursive macro call are as follows:
- The macro call expression allows nested call.
- A macro definition allows nested call of other macros, but recursive call of itself is allowed only in the
quoteexpression.
Restrictions
-
Macros conditionally support recursive call of themselves. For details, see the preceding sections.
-
Except for recursive macro call, macro definition and macro call must be located in different
packages. The location where a macro is called mustimportthepackagewhere the macro definition is located to ensure that the macro definition is compiled before the macro call point. Import is not allowed for macros with cyclic dependency. For example, the following usage is invalid:pkgAimportspkgB, andpkgBimportspkgA, creating a cyclic import dependency.// ======= file A.cj macro package pkgA import pkgB.* public macro A(..) { @B(..) // error } // ======= file B.cj macro package pkgB import pkgA.* public macro B(..) { @A(..) // error } -
Macros allow for nested calls to other macros. The called macro also requires that the definition point and call point be located in different
packages.
Built-in Compilation Flags
Source Code Location
Cangjie offers several built-in compilation tags to obtain the location of the source code during compilation.
- After
@sourcePackage()is expanded, it becomes a literal of theStringtype, representing the package name of the source code where the current macro is located. - After
@sourceFile()is expanded, it becomes a literal of theStringtype, representing the file name of the source code where the current macro is located. - After
@sourceLine()is expanded, it becomes a literal of theInt64type, representing the code line of the source code where the current macro is located.
These compilation tags can be used in any expressions, as long as they meet the type check rules. Example:
func test1() {
let s: String = @sourceFile() // The value of `s` is the current source file name
}
func test2(n!: Int64 = @sourceLine()) { /* at line 5 */
// The default value of `n` is the source file line number of the definition of `test2`
println(n) // print 5
}
@Intrinsic
The @Intrinsic tag can be used to modify global functions. The functions modified by @Intrinsic are special functions provided by the compiler.
- Functions modified by @Intrinsic cannot have function bodies.
- Functions modified by @Intrinsic are a list determined by the compiler and released with the standard library. If any function not on the list is modified by @Intrinsic, an error is reported.
- The @Intrinsic tag is visible only in the std module. Outside the std module, users can name their own macros or annotations as
Intrinsicwithout name conflicts. - Functions modified by @Intrinsic cannot be used as first-class citizens.
The sample code is as follows:
@Intrinsic
func invokeGC(heavy: Bool):Unit
public func GC(heavy!: Bool = false): Unit {
unsafe { return invokeGC (heavy) } // CJ_MCC_InvokeGC(heavy)
}
@FastNative
To improve performance when interoperating with the C language, Cangjie provides @FastNative to optimize C function calls. Note that @FastNative can be used only for functions declared by foreign.
When using @FastNative to modify the foreign function, ensure that the corresponding C function meets the following requirements:
- The overall execution time of the function should not be too long. For example, the function should not contain large loops or produce blocking, such as calling functions like
sleepandwait. - The Cangjie method cannot be called in the function.
Conditional Compilation
Conditional compilation is a technology that selectively compiles different code segments in program code based on specific conditions. The main uses of conditional compilation include:
- Platform adaptation: Enables selective code compilation based on the current compilation environment, facilitating cross-platform compatibility.
- Function selection: Allows selective enabling or disabling of certain features based on different requirements, providing flexible feature configuration. For example, selectively compiling code to include or exclude certain functionalities.
- Debugging support: Supports compiling code in debug mode to improve program performance and security. For example, compiling debug information or logging code in debug mode, while excluding them in release versions.
- Performance optimization: Enables selective compilation based on predefined conditions to improve program performance.
Conditional compilation complies with the following syntax rules:
{{conditionalCompilationDefinition|pretty}}
The syntax rules for conditional compilation are summarized as follows:
- The built-in tag
@Whencan only be used to declare and import nodes. - Compilation conditions are enclosed by
[]. You can enter one or more groups of compilation conditions in[]. For details, see [Multi-condition Compilation].
@When[...] is a built-in compilation tag and is processed before import. If the code generated by expanding the macro contains @When[...], a compilation error is reported.
As a builtin compiler directive, @When[...] is processed before import. If the code generated by macro expansion contains @When[...], a compilation error is reported.
Compilation Conditions
A compilation condition mainly consists of relational or logical expressions. The compiler obtains a Boolean value based on the compilation condition to determine which code segment is to be compiled. Condition variables are used by the compiler to calculate compilation conditions. Condition variables can be classified into built-in condition variables and user-defined condition variables based on whether they are provided by the compiler. In addition, the scope of a condition variable is limited to [] of @When. If an undefined condition variable identifier is used in other scopes, an undefined error is triggered.
Built-in Condition Variables of the Compiler
The compiler provides five built-in condition variables for conditional compilation: os, backend, cjc_version, debug, and test, which are used to obtain the corresponding values from the current build environment. The built-in condition variables support comparison and logical operations. Among them, os, backend, and cjc_version support comparison operations, in which condition variables can only be used as left operands of binary operators. The right operand of a binary operator must be a literal value of the String type. Logical operations apply only to condition variables debug and test.
os indicates the OS where the current compilation environment is located. It is used to obtain the specific type of the OS where the compiler is located in real time, and then form a compilation condition with the literal value of the target OS. If you want to generate code for the Windows OS, compare the variable os with the literal value Windows. Similarly, if you want to generate code for Linux, you can compare os with the literal value Linux.
@When[os == "Linux"]
func foo() {
print("Linux")
}
@When[os == "Windows"]
func foo() {
print("Windows")
}
main() {
foo() // Compiling and running the code will print "Linux" or "Windows" on Linux or Windows
return 0
}
backend indicates the backend used by the current compiler. It is used to obtain the backend type currently used by the compiler in real time, and then form a compilation condition with the literal value of the target backend. If you want to compile code for the cjnative backend, you can compare the backend with the literal value cjnative.
The following backends are supported: cjnative, cjnative-x86_64, cjnative-aarch64, cjvm, cjvm-x86_64, and cjvm-aarch64.
@When[backend == "cjnative"]
func foo() {
print("cjnative backend")
}
@When[backend == "cjvm"]
func foo() {
print("cjvm backend")
}
main() {
foo() // Compile and execute with the cjnative and cjvm backend version, and print "llvm backend" and "cjvm backend" respectively.
}
cjc_version indicates the version number of the current compiler. The version number is a literal value of the String type in the X.Y.Z format, where X, Y, and Z are non-negative integers and cannot contain leading zeros, for example, "0.18.8". It is used to obtain the current version number of the compiler in real time and compare it with the target version number to ensure that the compiler can compile code based on a specific version. Six types of comparison operations are supported: ==, !=, >, <, >=, and <=. The result of the condition is determined by the first difference encountered when comparing these fields from left to right. For example, 0.18.8 < 0.18.11 and 0.18.8 = = 0.18.8.
debug is a conditional compilation identifier, indicating whether the code being compiled is a debug version. It is used to switch between the debug version and the release version during code compilation. The code modified by @When[debug] is compiled only in the debug version, and the code modified by @When[!debug] is compiled only in the release version.
test is a conditional compilation identifier used to mark test code. The test code is usually in the same file as the common source code. The code modified by @When[test] is compiled only when the --test option is used. The code is excluded during normal build.
User-defined Condition Variables
You can define condition variables as required and use them in code to control code compilation. User-defined condition variables are essentially similar to built-in variables. The only difference is that the value of a user-defined condition variable is set by the user, while the value of a built-in variable is determined by the compiler based on the current compilation environment. User-defined condition variables comply with the following rules:
- User-defined condition variables must be valid [Identifiers].
- User-defined condition variables support only the equality and inequality comparison operations.
- The user-defined compilation condition variable must be of the
Stringtype.
The following is an example of a user-defined condition variable:
//source.cj
@When[feature == "lion"] // "feature" is user custom conditional variable.
func foo() {
print("feature lion, ")
}
@When[platform == "dsp"] // "platform" is user custom conditional variable.
func fee() {
println("platform dsp")
}
main() {
foo()
fee()
}
Configuring User-defined Condition Variables
You can configure user-defined condition variables in two ways: through compilation options and configuration files. The compilation option --cfg allows a character string to be received to configure the value of a user-defined condition variable. The rules are as follows:
--cfgcan be used multiple times.- Multiple conditional assignment statements can be used and are separated by commas (,).
- The value of a condition variable cannot be specified multiple times.
- The left side of the
=operator must be a valid identifier. - The right side of the
=operator must be a literal.
Use --cfg to configure the user-defined condition variables feature and platform.
cjc --cfg "feature = lion, platform = dsp" source.cj // ok
cjc --cfg "feature = lion" --cfg "platform = dsp" source.cj // ok
cjc --cfg "feature = lion, feature = dsp" source.cj // error
The .toml file is used as the configuration file of user-defined condition variables. The configuration file is named cfg.toml.
- The configuration uses key-value pairs, with the key-value separator being
=. Each key-value pair occupies a line. - Key names must be valid [Identifiers].
- A key value is a literal value enclosed in double quotation marks.
By default, the current directory is used as the search path of the configuration file for conditional compilation. You can use --cfg to set the search path of the configuration file.
cjc --cfg "/home/cangjie/conditon/compile" source.cj // ok
Multi-condition Compilation
Multiple compilation conditions can be combined using && and ||. The precedence and associativity of the conditions are the same as those of logical expressions. For details, see [Logical Expressions]. Compilation conditions can be enclosed in parentheses. In this case, they are considered as separate computing units and are preferentially calculated.
@When[(backend == "cjnative" || os == "Linux") && cjc_version >= "0.40.1"]
func foo() {
print("This is Multi-conditional compilation")
}
main() {
foo() // Conditions for compiling source code: cjc_version greater than 0.40.1; compiler backend is cjnative or os is Linux.
return 0
}
Concurrency
Cangjie Threads
Cangjie provides a preemptive concurrency model, in which the Cangjie thread is a basic execution unit. Cangjie threads are managed by Cangjie at runtime and are not underlying native threads (such as operating system threads). In unambiguous contexts, we simply refer to "Cangjie threads" as "threads." Each thread has the following properties:
- A thread may be preempted by another thread at any time during execution.
- Multiple threads can execute concurrently.
- When a thread is blocked, it is suspended.
- Threads can share memory (explicit synchronization is required).
Cangjie program execution begins with the initialization of global variables, then the program entry main is called. When main exits, the entire program exits without waiting for other threads to complete execution.
Creating Threads
You can create and start a thread using the spawn keyword, a default parameter of the ThreadContext type (see below for an introduction to ThreadContext), and a lambda expression without parameters. The expression returns an instance of Future<T>. (For details about Future<T>, see [Future<T> Generic Class].) The BNF of the spawn expression is as follows:
spawnExpression
: 'spawn' ( '(' expression ')' )? trailingLambdaExpression
;
The default parameter of spawn is of the ThreadContext type. An example of a spawn expression with a default parameter of the ThreadContext type is as follows:
func add(a: Int32, b: Int32): Int32 {
println("This is a new thread")
return a + b
}
main(): Int64 {
println("This is main")
// Create a thread.
let fut: Future<Int32> = spawn {
add(1, 2)
}
println("main waiting...")
// Waiting for the results of thread execution.
let res: Int32 = fut.get()
// Print the result.
println("1 + 2 = ${res}")
}
// OUTPUT maybe:
// This is main
// main waiting...
// This is a new thread
// 1 + 2 = 3
During the execution of the spawn expression, the closure is encapsulated into a runtime task and submitted to the scheduler. The scheduler policies determine the execution time of the task. Once the spawn expression is executed, the thread corresponding to the task is in the executable state. Note that the local variables declared by var cannot be captured in the closure of the spawn expression. For details about the closure, see [Closure].
Future<T> Generic Class
The return value of the spawn expression is a Future<T> object that can be used to obtain the calculation result of a thread. The type of T depends on the return value type of the closure in the spawn expression.
func foo(): Int64 {...}
func bar(): String {...}
// The return type of foo() is Int64.
let f1: Future<Int64> = spawn {
foo()
}
// The return type of bar() is String.
let f2: Future<String> = spawn {
bar()
}
// Waiting for the threads' execution results.
let r1: Int64 = f1.get()
let r2: String = f2.get()
A Future<T> object represents an unfinished calculation or task. Future<T> is a generic class. Its definition is as follows:
class Future<T> {
... ...
/**
* Blocking the current thread,
* waiting for the result of the thread corresponding to this Future<T> object.
* @throws Exception or Error if an exception occurs in the corresponding thread.
*/
func get(): T
/**
* Blocking the current thread,
* waiting for the result of the thread corresponding to this Future<T> object.
* If the corresponding thread has not completed execution within `ns` nanoseconds,
* the method will return `Option<T>.None`.
* If `ns <= 0`, same as `get()`.
* @throws Exception or Error if an exception occurs in the corresponding thread.
*/
func get(ns: Int64): Option<T>
/**
* Non-blocking method that immediately returns None if thread has not finished execution.
* Returns the computed result otherwise.
* @throws Exception or Error if an exception occurs in the corresponding thread.
*/
func tryGet(): Option<T>
// Get the associated thread object.
prop thread: Thread
}
If a thread is terminated due to an exception, it transfers the exception to the Future<T> object and prints the exception information by default before the thread is terminated. When the Future<T> object corresponding to the thread calls get(), the exception is thrown again. For example:
main(args:Array<String>) {
let fut: Future<Int64> = spawn {
if (args.size != -1) {
throw IllegalArgumentException()
}
return 100
}
try {
let res: Int64 = fut.get()
print("val = ${res}\n")
} catch (e: IllegalArgumentException) {
print("Exception occured\n")
}
}
// OUTPUT:
// An exception has occurred:
// IllegalArgumentException
// ...
// Exception occurred
Thread Class
Each Future<T> object has an associated thread object of the Thread type, which can be obtained through the thread property of Future<T>. The thread class Thread is used to obtain thread information, such as the thread ID. Some of its definitions are as follows:
class Thread {
... ...
// Get the currently running thread
static prop currentThread: Thread
// Get the unique identifier (represented as an integer) of the thread object
prop id: Int64
// Get or set the name of the thread
mut prop name: String
}
The static property currentThread can be used to obtain the thread object that is being executed. The following sample code can be used to print the identifier of the currently executing thread. Note: A thread may be assigned a different thread identifier each time it is executed.
main() {
let fut: Future<Unit> = spawn {
let tid = Thread.currentThread.id
println("New thread id: ${tid}")
}
fut.get()
}
// OUTPUT:
// New thread id: 2
Thread Sleep
The sync package in the Cangjie standard library provides the sleep function to enable threads to sleep for a specified period. If the sleep duration is zero, that is, the parameter is duration.Zero, the current thread only releases execution resources and does not enter the sleep state.
func sleep(duration: Duration)
Thread Termination
During normal execution, if execution of a closure corresponding to a thread is completed, execution of the thread ends. In addition, a termination request may be sent to a corresponding thread by using a cancel() method of a Future<T> object. This method only sends a request and does not affect execution of the thread. The hasPendingCancellation property of the thread class is used to check whether the current thread has a termination request. In this way, you can determine whether to terminate a thread in advance and how to do so.
class Future<T> {
... ...
// Send a termination request to its executing thread.
public func cancel(): Unit
}
class Thread {
... ...
// Check whether the thread has any cancellation request
prop hasPendingCancellation: Bool
}
The following example shows how to terminate a thread.
main(): Unit {
let future = spawn { // Create a new thread
while (true) {
//...
if (Thread.currentThread.hasPendingCancellation) {
return // Terminate when having a request
}
//...
}
}
//...
future.cancel() // Send a termination request
future.get() // Wait for thread termination
}
Thread Context
Threads are always executed within a specific context, and the thread context can influence the behavior of the thread at runtime. When a thread is created, besides the default spawn expression input parameter, instances of the ThreadContext type can be passed to select different thread contexts, thereby controlling concurrency to some extent.
ThreadContext Interface
The ThreadContext interface type is defined as follows:
- The
endmethod is used to send a termination request to the current context. (For details, see [Closing Thread Context] below.) - The
hasEndedmethod is used to check whether the current context has ended.
interface ThreadContext {
func end(): Unit
func hasEnded(): Bool
}
Currently, you are not allowed to implement the ThreadContext interface by yourself. Cangjie provides a thread context type based on its application scenario.
- The thread context
MainThreadContextcan be used in terminal application development.
For details, see the terminal framework library.
Closing Thread Context
When closing a ThreadContext object, you can send a termination request to the corresponding context using the end method provided by the ThreadContext object. This method sends a termination request to all threads running in the context (see [Thread Termination]) and returns immediately.After all Cangjie threads bound to this context are complete, the context is closed.
Similarly, the termination request does not affect the execution of all threads in this context. Users can use hasPendingCancellation to decide whether to terminate threads early and how to do so.
Thread Local Variables
The ThreadLocal<T> type can be used to define thread local variables. Compared with common variables, thread local variables have different access semantics. When multiple threads share the same thread local variable, each thread has its own copy of the value. When a thread accesses a variable, the thread reads and writes the local value of the variable without affecting the values of variables in other threads. Therefore, the ThreadLocal<T> class is thread-safe. The ThreadLocal<T> class is defined as follows:
- The constructor method
initis used to construct thread local variables. When the variable is constructed but the variable value is not set, the thread reads the variable and obtains the null valueNone. - The read and write methods
getandsetare used to access the value of a thread local variable. After a thread sets the value of a variable toNone, the variable value in the current thread is cleared.
class ThreadLocal<T> {
// Construct a thread-local variable contains None.
public init()
// Get the value of the thread-local variable of the current executing thread.
public func get(): ?T
// Set a value to the thread-local variable.
public func set(value: ?T): Unit
}
The following example shows how to use thread local variables.
let tlv = ThreadLocal<Int64>() // Define a thread-local variable
main(): Unit {
for (i in 0..3) { // Spawn three threads
spawn {
tlv.set(i) // Each thread sets a different value
// ...
println("${tlv.get()}") // Each thread prints its own value
}
}
// ...
println("${tlv.get()}") // Print `None`
// since the current thread does not set any value.
}
Synchronization Mechanism
Atomic Operations
Atomic operations ensure that instructions are executed atomically, that is, the execution process is not interrupted. A write operation on an atomic variable is always visible to subsequent read operations on the same atomic variable. In addition, atomic operations are non-blocking actions and do not cause thread blocking. Cangjie provides atomic operations for integer types (including Int8, Int16, Int32, Int64, UInt8, UInt16, UInt32, and UInt64), Boolean types (Bool), and reference types.
- For the integer type, basic read, write, swap, and arithmetic operations are provided.
load: readstore: writeswap: swapcompareAndSwap: compare and exchangefetchAdd: addfetchSub: subtractfetchAnd: andfetchOr: orfetchXor: exclusive OR
// Signed Integers.
class AtomicInt8 {
... ...
init(val: Int8)
public func load(): Int8
public func store(val: Int8): Unit
public func swap(val: Int8): Int8
public func compareAndSwap(old: Int8, new: Int8): Bool
public func fetchAdd(val: Int8): Int8
public func fetchSub(val: Int8): Int8
public func fetchAnd(val: Int8): Int8
public func fetchOr(val: Int8): Int8
public func fetchXor(val: Int8): Int8
... ... // Operator overloading, etc.
}
class AtomicInt16 {...}
class AtomicInt32 {...}
class AtomicInt64 {...}
// Unsigned Integers.
class AtomicUInt8 {...}
class AtomicUInt16 {...}
class AtomicUInt32 {...}
class AtomicUInt64 {...}
- For the Boolean type, only the basic read, write and swap operations are provided, and arithmetic operations are not provided.
load: readstore: writeswap: swapcompareAndSwap: compare and exchange
// Boolean.
class AtomicBool {
... ...
init(val: Bool)
public func load(): Bool
public func store(val: Bool): Unit
public func swap(val: Bool): Bool
public func compareAndSwap(old: Bool, new: Bool): Bool
... ... // Operator overloading, etc.
}
- For the reference type, only the basic read, write and swap operations are provided, and arithmetic operations are not provided.
load: readstore: writeswap: swapcompareAndSwap: compare and exchange
class AtomicReference<T> where T <: Object {
... ...
init(val: T)
public func load(): T
public func store(val: T): Unit
public func swap(val: T): T
public func compareAndSwap(old: T, new: T): Bool
}
- In addition, for a nullable reference type, a "null reference" (represented by
None) may be stored by usingAtomicOptionReference.
class AtomicOptionReference<T> where T <: Object {
public init(val: Option(T))
public func load(): Option<T>
public func store(val: Option<T>): Unit
public func swap(val: Option<T>): Option<T>
public func compareAndSwap(old: Option<T>, new: Option<T>): Bool
}
Each of the preceding methods contains a hidden parameter
memory order. Currently, only the Sequential Consistency memory model is supported. In the future, looser memory models, such as the acquire or release memory order, may be added.
IllegalSynchronizationStateException
IllegalSynchronizationStateException is a runtime exception thrown by built-in concurrency primitives when an illegal action occurs, such as when a thread attempts to release a mutex that it has not acquired.
IReentrantMutex
IReentrantMutex is a public interface of reentrant mutex concurrency primitives. It provides the following three methods, which need to be implemented:
lock(): Unit: acquires the lock. If the lock cannot be acquired, the current thread is blocked.tryLock(): Bool: attempts to acquire the lock.unlock(): Unit: releases the lock.
interface IReentrantMutex {
// Locks the mutex, blocks the current thread if the mutex is not available.
public func lock(): Unit
// Tries to lock the mutex, returns false if the mutex is not available, otherwise locks the mutex and returns true.
public func tryLock(): Bool
// Unlocks the mutex. If the mutex was locked repeatedly N times, this method should be invoked N times to
// fully unlock the mutex. When the mutex is fully unlocked, unblocks one of the threads waiting on its `lock`
// (no particular admission policy implied).
// Throws ISSE("Mutex is not locked by the current thread") if the current thread does not hold this mutex.
public func unlock(): Unit
}
Note:
- When implementing this interface, ensure that the underlying mutex supports nested locks.
- When implementing this interface, ensure that
IllegalSynchronizationStateExceptionis thrown when the lock status is abnormal.
ReentrantMutex
ReentrantMutex provides the following methods:
lock(): Unit: acquires the lock. If the lock cannot be acquired, the current thread is blocked.tryLock(): Bool: attempts to acquire the lock.unlock(): Unit: releases the lock.
ReentrantMutex is a built-in lock that can be held by only one thread at a time. If the given ReentrantMutex has been held by another thread, the lock method blocks the current thread until the mutex is released, and the tryLock method immediately returns false.
ReentrantMutex is a reentrant lock. That is, if a thread attempts to acquire a ReentrantMutex lock that it already holds, the thread immediately acquires the ReentrantMutex. To successfully release the lock, the number of times that unlock is called must match the number of times that lock is called.
Note: ReentrantMutex is a built-in mutex and you cannot inherit it.
// Base class for built-in reentrant mutual exclusion concurrency primitives.
sealed class ReentrantMutex <: IReentrantMutex {
// Constructor.
init()
// Locks the mutex, blocks current thread if the mutex is not available.
public func lock(): Unit
// Tries to lock the mutex, returns false if the mutex is not available, otherwise locks the mutex and returns true.
public func tryLock(): Bool
// Unlocks the mutex. If the mutex was locked repeatedly N times, this method should be invoked N times to
// fully unlock the mutex. Once the mutex is fully unlocked, unblocks one of the threads waiting in its `lock` method, if any
// (no particular admission policy implied).
// Throws ISSE("Mutex is not locked by the current thread") if the current thread does not hold this mutex.
public func unlock(): Unit
}
synchronized
The synchronized keyword and a ReentrantMutex object are used to protect the modified code block so that only one thread is allowed to execute the code in the code block at a time. An instance of ReentrantMutex or its derived classes can be passed as a parameter to the synchronized keyword, which results in the following conversion:
//=======================================
// `synchronized` expression
//=======================================
let m: ReentrantMutex = ...
synchronized(m) {
foo()
}
//=======================================
// is equivalent to the following program.
//=======================================
let m: ReentrantMutex = ...
m.lock()
try {
foo()
} finally {
m.unlock()
}
Note: The synchronized keyword is incompatible with the IReentrantMutex interface.
- Before entering the code block modified by
synchronized, a thread must first acquires the lock corresponding to theReentrantMutexinstance. If the lock cannot be acquired, the current thread is blocked. - After a thread exits the code block modified by
synchronized, the lock of theReentrantMutexobject is automatically released. Only oneunlockoperation is performed, allowing for nestedsynchronizedcode blocks using the same mutex. - After the
return eexpression in the code block modified bysynchronizedis reached, the value ofeis evaluated tov,m.unlock()is called, and thenvis returned. - If the code block modified by
synchronizedcontains abreakorcontinueexpression that would cause the program to exit the block, them.unlock()method is automatically called. - When an exception occurs in the code block modified by
synchronizedand causes the program to exit the block, them.unlock()method is automatically called.
The BNF of the synchronized expression is as follows:
synchronizedExpression
: 'synchronized' '(' expression ')' block
;
Here, expression is a ReentrantMutex object.
Monitor
Monitor is a built-in data structure that binds a mutex to a single related condition variable (wait queue). Monitor can block a thread and wait for a signal from another thread to resume execution. This mechanism uses shared variables to synchronize threads. The following methods are provided:
wait(timeout!: Duration = Duration.Max): Boolwaits for a signal and blocks the current thread.notify(): Unit: wakes up a thread waiting on theMonitor(if any).notifyAll(): Unit: wakes up all threads waiting on theMonitor(if any).
Before calling the wait, notify, or notifyAll method of the Monitor object, ensure that the current thread has held the corresponding Monitor lock. The wait method contains the following actions:
- Add the current thread to the waiting queue corresponding to the
Monitor. - Block the current thread, release the
Monitorlock, and record the number of acquisition times. - Wait for another thread to use the
notifyornotifyAllmethod of the sameMonitorinstance to send a signal to the thread. - Wake up the current thread, acquire the
Monitorlock, and restore the acquisition times recorded in step 2.
Note: The wait method accepts one default parameter timeout. It should be noted that many common OSs in the industry do not ensure real-time scheduling. Therefore, it cannot be ensured that a thread is blocked for an "exact duration". There may be system-related inaccuracies. In addition, the current language specification explicitly allows implementations to produce false wake-ups. In this case, the return value of wait is implementation-determined, possibly true or false. Therefore, developers are encouraged to always wrap wait in a loop.
synchronized (obj) {
while (<condition is not true>) {
obj.wait();
}
}
Monitor is defined as follows:
class Monitor <: ReentrantMutex {
// Constructor.
init()
// Blocks until either a paired `notify` is invoked or `timeout` pass.
// Returns `true` if the monitor was signalled by another thread or `false` on timeout. Spurious wakeups are allowed.
// Throws ISSE("Mutex is not locked by the current thread") if the current thread does not hold this mutex.
func wait(timeout!: Duration = Duration.Max): Bool
// Wakes up a single thread waiting on this monitor, if any (no particular admission policy implied).
// Throws ISSE("Mutex is not locked by the current thread") if the current thread does not hold this mutex.
func notify(): Unit
// Wakes up all threads waiting on this monitor, if any (no particular admission policy implied).
// Throws ISSE("Mutex is not locked by the current thread") if the current thread does not hold this mutex.
func notifyAll(): Unit
}
MultiConditionMonitor
MultiConditionMonitor is a built-in data structure that binds a mutex to a group of dynamically created condition variables. This class should be used only when the Monitor class cannot implement advanced concurrency algorithms.
The following methods are provided:
newCondition(): ConditionID: creates a waiting queue, associates it with the current object, and returns a specificConditionID.wait(id: ConditionID, timeout!: Duration = Duration.Max): Bool: waits for a signal and blocks the current thread.notify(id: ConditionID): Unit: wakes up a thread waiting on theMonitor(if any).notifyAll(id: ConditionID): Unit: wakes up all threads waiting on theMonitor(if any).
During initialization, the MultiConditionMonitor does not have a related ConditionID instance. Each time newCondition is called, a new waiting queue is created and associated with the current object, returning a unique identifier of the following type:
external struct ConditionID {
private init() { ... } // constructor is intentionally private to prevent
// creation of such structs outside of MultiConditionMonitor
}
Note that users cannot pass a ConditionID returned by a MultiConditionMonitor instance to other instances or manually create a ConditionID (for example, using unsafe). Because the data contained in the ConditionID (such as the index of the internal array, the direct address of the internal queue, or any other type of data) is related to the MultiConditionMonitor that created it, passing an "external" conditonID to the MultiConditionMonitor will result in IllegalSynchronizationStateException.
class MultiConditionMonitor <: ReentrantMutex {
// Constructor.
init()
// Returns a new ConditionID associated with this monitor. May be used to implement
// "single mutex -- multiple wait queues" concurrent primitives.
// Throws ISSE("Mutex is not locked by the current thread") if the current thread does not hold this mutex.
func newCondition(): ConditionID
// Blocks until either a paired `notify` is invoked or `timeout` pass.
// Returns `true` if the specified condition was signalled by another thread or `false` on timeout.
// Spurious wakeups are allowed.
// Throws ISSE("Mutex is not locked by the current thread") if the current thread does not hold this mutex.
// Throws ISSE("Invalid condition") if `id` was not returned by `newCondition` of this MultiConditionMonitor instance.
func wait(id: ConditionID, timeout!: Duration = Duration.Max): Bool
// Wakes up a single thread waiting on the specified condition, if any (no particular admission policy implied).
// Throws ISSE("Mutex is not locked by the current thread") if the current thread does not hold this mutex.
// Throws ISSE("Invalid condition") if `id` was not returned by `newCondition` of this MultiConditionMonitor instance.
func notify(id: ConditionID): Unit
// Wakes up all threads waiting on the specified condition, if any (no particular admission policy implied).
// Throws ISSE("Mutex is not locked by the current thread") if the current thread does not hold this mutex.
// Throws ISSE("Invalid condition") if `id` was not returned by `newCondition` of this MultiConditionMonitor instance.
func notifyAll(id: ConditionID): Unit
}
Example: The following describes how to use MultiConditionMonitor to implement a "bounded FIFO queue with a fixed length". When the queue is empty, get() is blocked. When the queue is full, put() is blocked.
class BoundedQueue {
// Create a MultiConditionMonitor, two Conditions.
let m: MultiConditionMonitor = MultiConditionMonitor()
var notFull: ConditionID
var notEmpty: ConditionID
var count: Int64 // Object count in buffer.
var head: Int64 // Write index.
var tail: Int64 // Read index.
// Queue's length is 100.
let items: Array<Object> = Array<Object>(100, {i => Object()})
init() {
count = 0
head = 0
tail = 0
synchronized(m) {
notFull = m.newCondition()
notEmpty = m.newCondition()
}
}
// Insert an object, if the queue is full, block the current thread.
public func put(x: Object) {
// Acquire the mutex.
synchronized(m) {
while (count == 100) {
// If the queue is full, wait for the "queue notFull" event.
m.wait(notFull)
}
items[head] = x
head++
if (head == 100) {
head = 0
}
count++
// An object has been inserted and the current queue is no longer
// empty, so wake up the thread previously blocked on get()
// because the queue was empty.
m.notify(notEmpty)
} // Release the mutex.
}
// Pop an object, if the queue is empty, block the current thread.
public func get(): Object {
// Acquire the mutex.
synchronized(m) {
while (count == 0) {
// If the queue is empty, wait for the "queue notEmpty" event.
m.wait(notEmpty)
}
let x: Object = items[tail]
tail++
if (tail == 100) {
tail = 0
}
count--
// An object has been popped and the current queue is no longer
// full, so wake up the thread previously blocked on put()
// because the queue was full.
m.notify(notFull)
return x
} // Release the mutex.
}
}
Memory Model
The memory model is mainly used to solve the memory visibility issue in concurrent programming. It specifies when a write operation performed by a thread on a variable can be observed by a read operation performed by another thread on the same variable.
- If there is data contention, the behavior is undefined.
- If there is no data contention, the value read by a read operation is the value written by the nearest preceding write operation in the happens-before order.
It mainly addresses the issue of memory visibility in concurrent programming, specifically when a write operation by one thread becomes visible to another thread.
Data Race
If two threads access the same data, at least one of them is a write operation, and there is no happens-before relationship (defined in section 15.4.2) between the two operations, a data race occurs.
Definition of "accessing the same data":
- The access to the same field of the struct or class type or the same variable of the primitive, enum, or array type is regarded as the access to the same data.
- The access to different fields of the struct or class type is regarded as the access to different data.
Happens-Before
- Program order rule: Each operation in a thread happens before any subsequent operation in the thread.
var a: String
main(): Int64 {
a = "hello, world"
println(a)
return 0
}
// OUTPUT:
// hello, world
- Thread startup rule: If thread A creates thread B using
spawn, thespawnoperation of thread A happens before any operation of thread B.
var a: String = "123"
func foo(): Unit {
println(a)
}
main(): Int64 {
a = "hello, world"
let fut: Future<Unit>= spawn {
foo()
}
fut.get()
return 0
}
// OUTPUT:
// hello, world
- Thread termination rule: If thread A calls
futureB.get()and it returns successfully, any operation in thread B happens beforefutureB.get()called in thread A. If thread A callsfutureB.cancel()and thread B accesseshasPendingCancellationafter that, the two calls form a happens-before relationship.
var a: String = "123"
func foo(): Unit {
a = "hello, world"
}
main(): Int64 {
let fut: Future<Unit> = spawn {
foo()
}
fut.get()
println(a)
return 0
}
// OUTPUT:
// hello, world
-
Thread synchronization rule: Operations on the same thread synchronization object (such as a mutex or semaphore) have a total order. An operation performed by a thread on a synchronization object (such as unlocking a mutex) happens before any subsequent operations on that synchronization object in this total order (such as locking the mutex).
-
Atomic variable rule: all operations on atomic variables are performed in a total order. The operation of a thread on an atomic variable happens before all subsequent operations on that atomic variable in this total order.
-
Transitivity rule: If A happens before B and B happens before C, then A happens before C.
Constant Evaluation
const Variables
A const variable is a special variable that defines a variable that is evaluated during compilation and cannot be changed during running.
A const variable differs from a variable declared by let or var in that it must be initialized at the time of definition and must be assigned a const expression. Therefore, the type of a const variable can only be of types supported by const expressions.
Similar to let and var, const variables also support type omission.
The definition of a const expression is as follows:
const a: Int64 = 0 // ok
const b: Int64 // error, b is uninitialized
const c = f() // error, f() is not const expression
const d = 0 // ok, the type of d is Int64
func f(): Unit {}
After being defined, a const variable can be used like a variable declared by let or var. Unlike variables declared by let or var, const can significantly reduce the computation required at runtime because its value can be obtained during compilation.
const a = 0
main(): Int64 {
let b: Int64 = a // ok
print(a) // ok
let c: VArray<Int64, $0> = [] // ok
return 0
}
A const variable can be a global variable, local variable, or static member variable. It cannot be defined in the extension.
const a = 0 // ok
class C {
const b = 0 // error, const member field must be modified by static
static const c = 0 //ok
var v: Int64
init() {
const d = 0 // ok
v = b + c + d
}
}
extend C {
const e = 0 // error, const cannot be defined in extend
}
const variables can access all instance members of the corresponding type or call all non-mut instance member functions of the corresponding type.
struct Foo {
let a = 0
var b = 0
const init() {}
func f1() {}
const func f2() {}
mut func f3() {
b = 123
}
}
main(): Int64 {
const v = Foo()
print(v.a) // ok
print(v.b) // ok
v.f1() // ok
v.f2() // ok
v.f3() // error, f3 is mut function
return 0
}
After a const variable is initialized, all members of instances of this type belong to const (including the members of members of the deep const), and therefore cannot be used as lvalues.
struct Foo {
let a = 0
var b = 0
const init() {}
}
func f() {
const v = Foo()
v.a = 1 // error
v.b = 1 // error
}
Const Expression
Certain forms of expressions, known as const expressions, have the ability to be evaluated at compile time. In the const context, these are the only allowed expressions and are always evaluated at compile time. In non-const contexts, const expressions do not guarantee evaluation at compile time.
The following are const expressions.
- Literals of the numeric, Bool, Unit, Rune, and String types (excluding interpolated strings)
- Array literals (not of Array type) and tuple literals where all elements are const expressions
- const variables, const function parameters, and local variables of const functions
- const functions, including functions whose names are declared using const, lambda expressions that meet the requirements of const functions, and function expressions returned by these functions
- const function calls (including const constructors) whose expressions and arguments are all const expressions
- enum constructor calls where all parameters are const expressions, and enum constructors without parameters
- Arithmetic expressions, relational expressions, and bitwise operation expressions of the numeric, Bool, Unit, Rune, and String types, whose operands are all const expressions
- if, match, try, is, and as expressions and control transfer expressions (including return, break, continue, and throw), whose expressions are all const expressions
- Member access expressions (excluding those for attribute access) and index access expressions of the tuple type in const expressions
- this and super expressions in the const init and const functions
- Function calls of const instance member functions of const expressions, where all arguments are const expressions
const Context
The const context is a specific type of context where all expressions must be const expressions, and these expressions are always evaluated at compile time.
The const context refers to the initialization expressions of const variables.
const Functions
A const function is a special function that can be evaluated during compilation. When being called in the const context, it performs calculation during compilation. In non-const contexts, it is executed at runtime, which is the same as normal functions.
The difference between const functions and regular functions is that the const function restricts some functionalities that affect the evaluation during compilation. const function can contain only declarations, const expressions, and a limited subset of assignment expressions.
- The declaration of a const function must be modified by const.
- Global const and static const functions can access only the external variables declared by const, including global const variables and static const member variables. const init functions and const instance member functions can access the external variables declared by const as well as the instance member variables of the current type.
- All expressions in const functions except const init functions must be const expressions.
- In const functions, let and const can be used to declare new local variables. However, var is not supported.
- There is no special requirement on parameter types and return types in const functions. If the argument of a function call does not meet the requirements of a const expression, the function call cannot be used as a const expression, but can still be used as a common expression.
- const functions are not necessarily executed during compilation. For example, they can be called in non-const functions during running.
- The overloading rules of const functions are the same as those of non-const functions.
- The numeric, Bool, Unit, Rune, String, and enum types can be used to define const instance member functions.
- For struct and class, const instance member functions can be defined only after a const init function is defined. const instance member functions in class cannot be open. const instance member functions in struct cannot be mut.
const func f(a: Int64): Int64 { // ok
let b = 6
if (a > 5 && (b + a) < 15 ) {
return a * a
}
return a
}
class A {
var a = 0
}
const func f1(a: A): Unit { // ok
return
}
const func f2(): A {
return A() // error, A did not contains const init
}
const Function in Interfaces
const functions can be defined in interfaces. The rules are as follows:
- The implementation type of a const function in an interface must also be a const function.
- For a non-const function in an interface, the implementation type can be a const or non-const function.
- Similar to a static function, a const function in an interface can be used by constrained generic variables only when the interface is used as a generic constraint.
interface I {
const func f(): Int64
const static func f2(): Int64
}
const func g<T>(i: T) where T <: I {
return i.f() + T.f2()
}
const init
The existence of a const init function determines which custom struct or class can be used in a const expression. Whether a const init function can be defined for a type depends on the following conditions:
- If the current type is class, an instance member variable declared by var cannot be used. Otherwise, a const init function cannot be defined. If the current type has a superclass, the current const init function must call the const init function of the superclass. (A const init function without parameters can be called explicitly or implicitly.) If the superclass does not have a const init function, an error is reported.
- An init without parameters of the Object type is also a const init function. Therefore, the subtypes of the Object type can use this const init function.
- If an instance member variable of the current type has an initial value, the initial value must be a const expression. Otherwise, a const init function cannot be defined.
- Only assignment expressions can be used to assign values to instance member variables in a const init function.
The difference between const init functions and const functions is that values can be assigned to instance member variables in const init functions (assignment expressions are required).
struct R1 {
var a: Int64
let b: Int64
const init() { // ok
a = 0
b = 0
}
}
struct R2 {
var a = 0
let b = 0
const init() {} // ok
}
func zero(): Int64 {
return 0
}
struct R3 {
let a = zero()
const init() {} // error, Initialization of a is not const expression
}
class C1 {
var a = 0
const init() {} // error, a cannot be var binding
}
struct R4 {
var a = C1()
const init() {} // error, Initialization of a is not const expression
}
open class C2 {
let a = 0
let b = R2()
const init() {} // ok
}
class C3 <: C2 {
let c = 0
const init() {} // ok
}
Annotation
Annotation is a special syntax used only in declaration. It is used to provide additional information to the compiler or at runtime to implement specific functionalities.
A basic syntax example of annotations is as follows:
@Annotation1[arg1, arg2]
@Annotation2
class Foo {}
Annotations can be used in different declarations.
The syntax specifications are defined as follows:
annotationList: annotation+;
annotation
: '@' (identifier '.')* identifier ('[' annotationArgumentList ']')?
;
annotationArgumentList
: annotationArgument (',' annotationArgument)* ','?
;
annotationArgument
: identifier ':' expression
| expression
;
Annotations and macro calls share the same syntax. Because macros are processed at an earlier stage than annotations, the compiler first attempts to parse the syntax as a macro. If that fails, it then tries to process the syntax as an annotation. If both processing methods fail, a compilation error should be reported.
Custom Annotations
The custom annotation mechanism enables reflection to obtain the annotation content. This mechanism aims to provide more useful information apart from the type metadata to support more complex logic.
Custom annotations can be used in type declarations, member variable declarations, member property declarations, member function declarations, constructor declarations, and function parameter declarations (for the above-mentioned functions).
You can customize annotations through @Annotation.
@Annotation can only modify a class that is not modified by abstract, open, or sealed.
When a class declares that it is labeled with @Annotation, it must provide at least one const init function. Otherwise, the compiler reports an error.
An example of a custom annotation is as follows:
@Annotation
public class CustomAnnotation {
let name: String
let version: Int64
public const init(name: String, version!: Int64 = 0) {
this.name = name
this.version = version
}
}
// use annotation
@CustomAnnotation["Sample", version: 1]
class Foo {}
Annotations need to be generated during compilation and bound to classes. const init must be used in annotation customization to construct valid instances.
The specifications are as follows:
- The declaration syntax of an annotation is the same as that of a macro. Parameters in
[]must be passed by sequence or naming rule and must be const expressions. - Annotation classes with non-parameterized constructors can omit brackets in declaration.
@Annotation
public class MyAnnotation { ... }
@MyAnnotation // ok
class Foo {}
An annotation class cannot be declared for multiple times for an annotation target. That is, the annotation class must be unique.
The compiler does not guarantee that the sequence of the multiple Annotation metadata generated matches the sequence of Annotation in the code.
@MyAnnotation
@MyAnnotation // error
class Foo {}
@MyAnnotation
@MyAnnotation2
class Bar {}
Annotation is not inherited. Therefore, the annotation metadata of a class comes only from the declared annotations when it is defined. If the annotation metadata of the superclass is required, you need to query the metadata through the reflection interface.
@BaseAnno
open class Base {}
@InterfaceAnno
interface I {}
@SubAnno
class Sub <: Base & I {} // Sub has only SubAnno annotation information.
Custom annotations can also restrict their application scopes to reduce misuse. To this aim, you need to add the target parameter when declaring @Annotation.
The target parameter needs to be passed as a variable-length parameter to the location that the custom annotation is expected to support. The parameter received by target is an Array<AnnotationKind>.
The following application scopes can be restricted:
- Type declaration (class, struct, enum, interface)
- Parameters in a member function or constructor
- Constructor declaration
- Member function declaration
- Member variable declaration
- Member property declaration
public enum AnnotaitionKind {
| Type
| Parameter
| Init
| MemberProperty
| MemberFunction
| MemberVariable
}
@Annotation[target: [Type, MemberFunction]]
class CustomAnnotation{}
@Annotation
class SubCustomAnnotation{}
@Annotation[target: []]
class MyAnno{}
If no target is specified, the custom annotations can be used in all the preceding scopes. When the target is specified, it can be used only in the declared list.
Cangjie Syntax
Lexicon
Comments
DelimitedComment
: '/*' ( DelimitedComment | . )*? '*/'
;
LineComment
: '//' ~[\u000A\u000D]*
;
Whitespace and Newline
WS
: [\u0020\u0009\u000C]
;
NL: '\u000A' | '\u000D' '\u000A' ;
Symbols
DOT: '.' ;
COMMA: ',' ;
LPAREN: '(' ;
RPAREN: ')' ;
LSQUARE: '[' ;
RSQUARE: ']' ;
LCURL: '{' ;
RCURL: '}' ;
EXP: '**' ;
MUL: '*' ;
MOD: '%' ;
DIV: '/' ;
ADD: '+' ;
SUB: '-' ;
PIPELINE: '|>' ;
COMPOSITION: '~>' ;
INC: '++' ;
DEC: '--' ;
AND: '&&' ;
OR: '||' ;
NOT: '!' ;
BITAND: '&' ;
BITOR: '|' ;
BITXOR: '^' ;
LSHIFT: '<<' ;
RSHIFT: '>>' ;
COLON: ':' ;
SEMI: ';' ;
ASSIGN: '=' ;
ADD_ASSIGN: '+=' ;
SUB_ASSIGN: '-=' ;
MUL_ASSIGN: '*=' ;
EXP_ASSIGN: '**=' ;
DIV_ASSIGN: '/=' ;
MOD_ASSIGN: '%=' ;
AND_ASSIGN: '&&=' ;
OR_ASSIGN: '||=' ;
BITAND_ASSIGN: '&=' ;
BITOR_ASSIGN: '|=' ;
BITXOR_ASSIGN: '^=' ;
LSHIFT_ASSIGN: '<<=' ;
RSHIFT_ASSIGN: '>>=' ;
ARROW: '->' ;
BACKARROW: '<-' ;
DOUBLE_ARROW: '=>' ;
ELLIPSIS: '...' ;
CLOSEDRANGEOP: '..=' ;
RANGEOP: '..' ;
HASH: '#' ;
AT: '@' ;
QUEST: '?' ;
UPPERBOUND: '<:';
LT: '<' ;
GT: '>' ;
LE: '<=' ;
GE: '>=' ;
NOTEQUAL: '!=' ;
EQUAL: '==' ;
WILDCARD: '_' ;
BACKSLASH: '\\' ;
QUOTESYMBOL: '`';
DOLLAR: '$';
QUOTE_OPEN: '"' ;
TRIPLE_QUOTE_OPEN: '"""' NL;
QUOTE_CLOSE: '"' ;
TRIPLE_QUOTE_CLOSE: '"""' ;
StrExprStart: '${' ;
Keywords
INT8: 'Int8' ;
INT16: 'Int16' ;
INT32: 'Int32' ;
INT64: 'Int64' ;
INTNATIVE: 'IntNative' ;
UINT8: 'UInt8' ;
UINT16: 'UInt16' ;
UINT32: 'UInt32' ;
UINT64: 'UInt64' ;
UINTNATIVE: 'UIntNative' ;
FLOAT16: 'Float16' ;
FLOAT32: 'Float32' ;
FLOAT64: 'Float64' ;
RUNE: 'Rune' ;
BOOLEAN: 'Bool' ;
UNIT: 'Unit' ;
Nothing: 'Nothing' ;
STRUCT: 'struct' ;
ENUM: 'enum' ;
THISTYPE: 'This';
PACKAGE: 'package' ;
IMPORT: 'import' ;
CLASS: 'class' ;
INTERFACE: 'interface' ;
FUNC: 'func';
MAIN: 'main';
LET: 'let' ;
VAR: 'var' ;
CONST: 'const' ;
TYPE_ALIAS: 'type' ;
INIT: 'init' ;
THIS: 'this' ;
SUPER: 'super' ;
IF: 'if' ;
ELSE: 'else' ;
CASE: 'case' ;
TRY: 'try' ;
CATCH: 'catch' ;
FINALLY: 'finally' ;
FOR: 'for' ;
DO: 'do' ;
WHILE: 'while' ;
THROW: 'throw' ;
RETURN: 'return' ;
CONTINUE: 'continue' ;
BREAK: 'break' ;
IS: 'is' ;
AS: 'as' ;
IN: 'in' ;
MATCH: 'match' ;
FROM: 'from' ;
WHERE: 'where';
EXTEND: 'extend';
SPAWN: 'spawn';
SYNCHRONIZED: 'synchronized';
MACRO: 'macro';
QUOTE: 'quote';
TRUE: 'true';
FALSE: 'false';
STATIC: 'static';
PUBLIC: 'public' ;
PRIVATE: 'private' ;
PROTECTED: 'protected' ;
OVERRIDE: 'override' ;
REDEF: 'redef' ;
ABSTRACT: 'abstract' ;
OPEN: 'open' ;
OPERATOR: 'operator' ;
FOREIGN: 'foreign';
INOUT: 'inout';
PROP: 'prop';
MUT: 'mut';
UNSAFE: 'unsafe';
GET: 'get';
SET: 'set';
Literals
IntegerLiteralSuffix
: 'i8' |'i16' |'i32' |'i64' |'u8' |'u16' |'u32' | 'u64'
;
IntegerLiteral
: BinaryLiteral IntegerLiteralSuffix?
| OctalLiteral IntegerLiteralSuffix?
| DecimalLiteral '_'* IntegerLiteralSuffix?
| HexadecimalLiteral IntegerLiteralSuffix?
;
BinaryLiteral
: '0' [bB] BinDigit (BinDigit | '_')*
;
BinDigit
: [01]
;
OctalLiteral
: '0' [oO] OctalDigit (OctalDigit | '_')*
;
OctalDigit
: [0-7]
;
DecimalLiteral
: (DecimalDigitWithOutZero (DecimalDigit | '_')*) | DecimalDigit
;
fragment DecimalFragment
: DecimalDigit (DecimalDigit | '_')*
;
fragment DecimalDigit
: [0-9]
;
fragment DecimalDigitWithOutZero
: [1-9]
;
HexadecimalLiteral
: '0' [xX] HexadecimalDigits
;
HexadecimalDigits
: HexadecimalDigit (HexadecimalDigit | '_')*
;
HexadecimalDigit
: [0-9a-fA-F]
;
FloatLiteralSuffix
: 'f16' | 'f32' | 'f64'
;
FloatLiteral
: (DecimalLiteral DecimalExponent | DecimalFraction DecimalExponent? | (DecimalLiteral DecimalFraction) DecimalExponent?) FloatLiteralSuffix?
| ( Hexadecimalprefix (HexadecimalDigits | HexadecimalFraction | (HexadecimalDigits HexadecimalFraction)) HexadecimalExponent)
;
fragment DecimalFraction : '.' DecimalFragment ;
fragment DecimalExponent : FloatE Sign? DecimalFragment ;
fragment Sign : [-] ;
fragment Hexadecimalprefix : '0' [xX] ;
DecimalFraction : '.' DecimalLiteral ;
DecimalExponent : FloatE Sign? DecimalLiteral ;
HexadecimalFraction : '.' HexadecimalDigits ;
HexadecimalExponent : FloatP Sign? DecimalFragment ;
FloatE : [eE] ;
FloatP : [pP] ;
Sign : [-] ;
Hexadecimalprefix : '0' [xX] ;
RuneLiteral
: '\'' (SingleChar | EscapeSeq ) '\''
;
SingleChar
: ~['\\\r\n]
;
EscapeSeq
: UniCharacterLiteral
| EscapedIdentifier
;
UniCharacterLiteral
: '\\' 'u' '{' HexadecimalDigit '}'
| '\\' 'u' '{' HexadecimalDigit HexadecimalDigit '}'
| '\\' 'u' '{' HexadecimalDigit HexadecimalDigit HexadecimalDigit '}'
| '\\' 'u' '{' HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit '}'
| '\\' 'u' '{' HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit '}'
| '\\' 'u' '{' HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit '}'
| '\\' 'u' '{' HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit '}'
| '\\' 'u' '{' HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit '}'
;
EscapedIdentifier
: '\\' ('t' | 'b' | 'r' | 'n' | '\'' | '"' | '\\' | 'f' | 'v' | '0' | '$')
;
ByteLiteral
: 'b' '\'' (SingleCharByte | ByteEscapeSeq) '\''
;
ByteEscapeSeq
: HexCharByte
| ByteEscapedIdentifier
;
SingleCharByte
// ASCII 0x00~0x7F without \n \r \' \" \\
// +-------+-----+-----+
// | Rune | Hex | Dec |
// +-------+-----+-----+
// | \n | 0A | 10 |
// | \r | 0D | 13 |
// | \" | 22 | 34 |
// | \' | 27 | 39 |
// | \\ | 5C | 92 |
// +-------+-----+-----+
: [\u0000-\u0009\u000B\u000C\u000E-\u0021\u0023-\u0026\u0028-\u005B\u005D-\u007F]
;
fragment ByteEscapedIdentifier
: '\\' ('t' | 'b' | 'r' | 'n' | '\'' | '"' | '\\' | 'f' | 'v' | '0')
;
fragment HexCharByte
: '\\' 'u' '{' HexadecimalDigit '}'
| '\\' 'u' '{' HexadecimalDigit HexadecimalDigit '}'
;
ByteStringArrayLiteral
: 'b' '"' (SingleCharByte | ByteEscapeSeq)* '"'
;
JStringLiteral
: 'J' '"' (SingleChar | EscapeSeq)* '"'
;
LineStrText
: ~["\\\r\n]
| EscapeSeq
;
TRIPLE_QUOTE_CLOSE
: MultiLineStringQuote? '"""' ;
MultiLineStringQuote
: '"'+
;
MultiLineStrText
: ~('\\')
| EscapeSeq
;
MultiLineRawStringLiteral
: MultiLineRawStringContent
;
fragment MultiLineRawStringContent
: HASH MultiLineRawStringContent HASH
| HASH '"' .*? '"' HASH
;
Identifiers
identifier
: Identifier
| PUBLIC
| PRIVATE
| PROTECTED
| OVERRIDE
| ABSTRACT
| OPEN
| REDEF
| GET
| SET
;
Identifier
: '_'* Letter (Letter | '_' | DecimalDigit)*
| '`' '_'* Letter (Letter | '_' | DecimalDigit)* '`'
;
Letter
: [a-zA-Z]
;
DollarIdentifier
: '$' Identifier
;
Syntax
Translation Unit
translationUnit
: NL* preamble end* topLevelObject* (end+ mainDefinition)? NL* (topLevelObject (end+ topLevelObject?)*)? EOF
;
end
: NL | SEMI
;
Package Definition and Import
preamble
: packageHeader? importList*
;
packageHeader
: packageModifier? (MACRO NL*)? PACKAGE NL* fullPackageName end+
;
fullPackageName
: (packageNameIdentifier NL* DOT NL*)* packageNameIdentifier
;
packageNameIdentifier
: Ident
| contextIdent
;
packageModifier
: PUBLIC
| PROTECTED
| INTERNAL
;
importList
: importModifier? NL* IMPORT NL* importContent end+
;
importModifier
: PUBLIC
| PROTECTED
| INTERNAL
| PRIVATE
;
importContent
: importSingle
| importAlias
| importAll
| importMulti
;
importSingle
: (packageNameIdentifier NL* DOT NL*)* (identifier | packageNameIdentifier)
;
importAlias
: importSingle NL* AS NL* identifier
;
importAll
: (packageNameIdentifier NL* DOT NL*)+ MUL
;
importMulti
: (packageNameIdentifier NL* DOT NL*)* LCURL NL*
(importSingle | importAlias | importAll) NL*
(COMMA NL* (importSingle | importAlias | importAll))* NL*
COMMA? NL* RCURL
;
Top-Level Definition
topLevelObject
: classDefinition
| interfaceDefinition
| functionDefinition
| variableDeclaration
| enumDefinition
| structDefinition
| typeAlias
| extendDefinition
| foreignDeclaration
| macroDefinition
| macroExpression
;
Class Definition
classDefinition
: (classModifierList NL*)? CLASS NL* identifier
(NL* typeParameters NL*)?
(NL* UPPERBOUND NL* superClassOrInterfaces)?
(NL* genericConstraints)?
NL* classBody
;
superClassOrInterfaces
: superClass (NL* BITAND NL* superInterfaces)?
| superInterfaces
;
classModifierList
: classModifier+
;
classModifier
: PUBLIC
| PROTECTED
| INTERNAL
| PRIVATE
| ABSTRACT
| OPEN
;
typeParameters
: LT NL* identifier (NL* COMMA NL* identifier)* NL* GT
;
superClass
: classType
;
classType
: (identifier NL* DOT NL*)* identifier (NL* typeParameters)?
;
typeArguments
: LT NL* type (NL* COMMA NL* type)* NL* GT
;
superInterfaces
: interfaceType (NL* BITAND NL* interfaceType )*
;
interfaceType
: classType
;
genericConstraints
: WHERE NL* (identifier | THISTYPE) NL* UPPERBOUND NL* upperBounds (NL* COMMA NL* (identifier | THISTYPE) NL* UPPERBOUND NL* upperBounds)*
;
upperBounds
: type (NL* BITAND NL* type)*
;
classBody
: LCURL end*
classMemberDeclaration* NL*
classPrimaryInit? NL*
classMemberDeclaration* end* RCURL
;
classMemberDeclaration
: (classInit
| staticInit
| variableDeclaration
| functionDefinition
| operatorFunctionDefinition
| macroExpression
| propertyDefinition
) end*
;
classInit
: (classNonStaticMemberModifier | CONST NL*)? INIT NL* functionParameters NL* block
;
staticInit
: STATIC INIT LPAREN RPAREN
LCURL
expressionOrDeclarations?
RCURL
;
classPrimaryInit
: (classNonStaticMemberModifier | CONST NL*)? className NL* LPAREN NL*
classPrimaryInitParamLists
NL* RPAREN NL*
LCURL NL*
(SUPER callSuffix)? end
expressionOrDeclarations?
NL* RCURL
;
className
: identifier
;
classPrimaryInitParamLists
: unnamedParameterList (NL* COMMA NL* namedParameterList)? (NL* COMMA NL* classNamedInitParamList)?
| unnamedParameterList (NL* COMMA NL* classUnnamedInitParamList)? (NL* COMMA NL* classNamedInitParamList)?
| classUnnamedInitParamList (NL* COMMA NL* classNamedInitParamList)?
| namedParameterList (NL* COMMA NL* classNamedInitParamList)?
| classNamedInitParamList
;
classUnnamedInitParamList
: classUnnamedInitParam (NL* COMMA NL* classUnnamedInitParam)*
;
classNamedInitParamList
: classNamedInitParam (NL* COMMA NL* classNamedInitParam)*
;
classUnnamedInitParam
: (classNonSMemberModifier NL*)? (LET | VAR) NL* identifier NL* COLON NL* type
;
classNamedInitParam
: (classNonSMemberModifier NL*)? (LET | VAR) NL* identifier NL* NOT NL* COLON NL* type (NL* ASSIGN NL* expression)?
;
classNonStaticMemberModifier
: PUBLIC
| PRIVATE
| PROTECTED
| INTERNAL
;
Interface Definition
interfaceDefinition
: (interfaceModifierList NL*)? INTERFACE NL* identifier
(NL* typeParameters NL*)?
(NL* UPPERBOUND NL* superInterfaces)?
(NL* genericConstraints)?
(NL* interfaceBody)
;
interfaceBody
: LCURL end* interfaceMemberDeclaration* end* RCURL
;
interfaceMemberDeclaration
: (functionDefinition
| operatorFunctionDefinition
| macroExpression
| propertyDefinition) end*
;
interfaceModifierList
: (interfaceModifier NL*)+
;
interfaceModifier
: PUBLIC
| PROTECTED
| INTERNAL
| PRIVATE
| OPEN
;
Function Definition
functionDefinition
:(functionModifierList NL*)? FUNC
NL* identifier
(NL* typeParameters NL*)?
NL* functionParameters
(NL* COLON NL* type)?
(NL* genericConstraints)?
(NL* block)?
;
operatorFunctionDefinition
: (functionModifierList NL*)? OPERATOR NL* FUNC
NL* overloadedOperators
(NL* typeParameters NL*)?
NL* functionParameters
(NL* COLON NL* type)?
(NL* genericConstraints)?
(NL* block)?
;
functionParameters
: (LPAREN (NL* unnamedParameterList ( NL* COMMA NL* namedParameterList)? )?
NL* RPAREN NL*)
| (LPAREN NL* (namedParameterList NL*)? RPAREN NL*)
;
nondefaultParameterList
: unnamedParameter (NL* COMMA NL* unnamedParameter)*
(NL* COMMA NL* namedParameter)*
| namedParameter (NL* COMMA NL* namedParameter)*
;
unnamedParameterList
: unnamedParameter (NL* COMMA NL* unnamedParameter)*
;
unnamedParameter
: (identifier | WILDCARD) NL* COLON NL* type
;
namedParameterList
: (namedParameter | defaultParameter)
(NL* COMMA NL* (namedParameter | defaultParameter))*
;
namedParameter
: identifier NL* NOT NL* COLON NL* type
;
defaultParameter
: identifier NL* NOT NL* COLON NL* type NL* ASSIGN NL* expression
;
functionModifierList
: (functionModifier NL*)+
;
functionModifier
: PUBLIC
| PRIVATE
| PROTECTED
| INTERNAL
| STATIC
| OPEN
| OVERRIDE
| OPERATOR
| REDEF
| MUT
| UNSAFE
| CONST
;
Variable Definition
variableDeclaration
: variableModifier* NL* (LET | VAR | CONST) NL* patternsMaybeIrrefutable ( (NL* COLON NL* type)? (NL* ASSIGN NL* expression)
| (NL* COLON NL* type)
)
;
variableModifier
: PUBLIC
| PRIVATE
| PROTECTED
| INTERNAL
| STATIC
;
Enum Definition
enumDefinition
: (enumModifier NL*)? ENUM NL* identifier (NL* typeParameters NL*)?
(NL* UPPERBOUND NL* superInterfaces)?
(NL* genericConstraints)? NL* LCURL end* enumBody end* RCURL
;
enumBody
: (BITOR NL*)? caseBody (NL* BITOR NL* caseBody)*
(NL*
( functionDefinition
| operatorFunctionDefinition
| propertyDefinition
| macroExpression
))*
;
caseBody
: identifier ( NL* LPAREN NL* type (NL* COMMA NL* type)* NL* RPAREN)?
;
enumModifier
: PUBLIC
| PROTECTED
| INTERNAL
| PRIVATE
;
Struct Definition
structDefinition
: (structModifier NL*)? STRUCT NL* identifier (NL* typeParameters NL*)?
(NL* UPPERBOUND NL* superInterfaces)?
(NL* genericConstraints)? NL* structBody
;
structBody
: LCURL end*
structMemberDeclaration* NL*
structPrimaryInit? NL*
structMemberDeclaration*
end* RCURL
;
structMemberDeclaration
: (structInit
| staticInit
| variableDeclaration
| functionDefinition
| operatorFunctionDefinition
| macroExpression
| propertyDefinition
) end*
;
structInit
: (structNonStaticMemberModifier | CONST NL*)? INIT NL* functionParameters NL* block
;
staticInit
: STATIC INIT LPAREN RPAREN
LCURL
expressionOrDeclarations?
RCURL
;
structPrimaryInit
: (structNonStaticMemberModifier | CONST NL*)? structName NL* LPAREN NL* structPrimaryInitParamLists? NL* RPAREN NL*
LCURL NL*
expressionOrDeclarations?
NL* RCURL
;
structName
: identifier
;
structPrimaryInitParamLists
: unnamedParameterList (NL* COMMA NL* namedParameterList)? (NL* COMMA NL* structNamedInitParamList)?
| unnamedParameterList (NL* COMMA NL* structUnnamedInitParamList)? (NL* COMMA NL* structNamedInitParamList)?
| structUnnamedInitParamList (NL* COMMA NL* structNamedInitParamList)?
| namedParameterList (NL* COMMA NL* structNamedInitParamList)?
| structNamedInitParamList
;
structUnnamedInitParamList
: structUnnamedInitParam (NL* COMMA NL* structUnnamedInitParam)*
;
structNamedInitParamList
: structNamedInitParam (NL* COMMA NL* structNamedInitParam)*
;
structUnnamedInitParam
: (structNonStaticMemberModifier NL*)? (LET | VAR) NL* identifier NL* COLON NL* type
;
structNamedInitParam
: (structNonStaticMemberModifier NL*)? (LET | VAR) NL* identifier NL* NOT NL* COLON NL* type (NL* ASSIGN NL* expression)?
;
structModifier
: PUBLIC
| PROTECTED
| INTERNAL
| PRIVATE
;
structNonStaticMemberModifier
: PUBLIC
| PROTECTED
| INTERNAL
| PRIVATE
;
Type Alias Definition
typeAlias
: (typeModifier NL*)? TYPE_ALIAS NL* identifier (NL* typeParameters)? NL* ASSIGN NL* type end*
;
typeModifier
: PUBLIC
| PROTECTED
| INTERNAL
| PRIVATE
;
Extension Definition
extendDefinition
: EXTEND NL* extendType
(NL* UPPERBOUND NL* superInterfaces)? (NL* genericConstraints)?
NL* extendBody
;
extendType
: (typeParameters)? (identifier NL* DOT NL*)* identifier (NL* typeArguments)?
| INT8
| INT16
| INT32
| INT64
| INTNATIVE
| UINT8
| UINT16
| UINT32
| UINT64
| UINTNATIVE
| FLOAT16
| FLOAT32
| FLOAT64
| RUNE
| BOOLEAN
| NOTHING
| UNIT
;
extendBody
: LCURL end* extendMemberDeclaration* end* RCURL
;
extendMemberDeclaration
: (functionDefinition
| operatorFunctionDefinition
| macroExpression
| propertyDefinition
) end*
;
Foreign Declaration
foreignDeclaration
: FOREIGN NL* (foreignBody | foreignMemberDeclaration)
;
foreignBody
: LCURL end* foreignMemberDeclaration* end* RCURL
;
foreignMemberDeclaration
: (classDefinition
| interfaceDefinition
| functionDefinition
| macroExpression
| variableDeclaration) end*
;
Annotation
annotationList: annotation+;
annotation
: AT (identifier NL* DOT)* identifier (LSQUARE NL* annotationArgumentList NL* RSQUARE)?
;
annotationArgumentList
: annotationArgument (NL* COMMA NL* annotationArgument)* NL* COMMA?
;
annotationArgument
: identifier NL* COLON NL* expression
| expression
;
Macro Declaration
macroDefinition
: PUBLIC NL* MACRO NL* identifier NL*
(macroWithoutAttrParam | macroWithAttrParam) NL*
(COLON NL* identifier NL*)?
(ASSIGN NL* expression | block)
;
macroWithoutAttrParam
: LPAREN NL* macroInputDecl NL* RPAREN
;
macroWithAttrParam
: LPAREN NL* macroAttrDecl NL* COMMA NL* macroInputDecl NL* RPAREN
;
macroInputDecl
: identifier NL* COLON NL* identifier
;
macroAttrDecl
: identifier NL* COLON NL* identifier
;
Property Definition
propertyDefinition
: propertyModifier* NL* PROP NL* identifier NL* COLON NL* type NL* propertyBody?
;
propertyBody
: LCURL end* propertyMemberDeclaration+ end* RCURL
;
propertyMemberDeclaration
: GET NL* LPAREN RPAREN NL* block end*
| SET NL* LPAREN identifier RPAREN NL* block end*
;
propertyModifier
: PUBLIC
| PRIVATE
| PROTECTED
| INTERNAL
| STATIC
| OPEN
| OVERRIDE
| REDEF
| MUT
;
Main Program Entry Definition
mainDefinition
: MAIN
NL* functionParameters
(NL* COLON NL* type)?
NL* block
;
Type
type
: arrowType
| tupleType
| prefixType
| atomicType
;
arrowType
: arrowParameters NL* ARROW NL* type
;
arrowParameters
: LPAREN NL* (type (NL* COMMA NL* type)* NL*)? RPAREN
;
tupleType
: LPAREN NL* type (NL* COMMA NL* type)+ NL* RPAREN
;
prefixType
: prefixTypeOperator type
;
prefixTypeOperator
: QUEST
;
atomicType
: charLangTypes
| userType
| parenthesizedType
;
charLangTypes
: numericTypes
| RUNE
| BOOLEAN
| Nothing
| UNIT
| THISTYPE
;
numericTypes
: INT8
| INT16
| INT32
| INT64
| INTNATIVE
| UINT8
| UINT16
| UINT32
| UINT64
| UINTNATIVE
| FLOAT16
| FLOAT32
| FLOAT64
;
userType
: (identifier NL* DOT NL*)* identifier ( NL* typeArguments)?
;
parenthesizedType
: LPAREN NL* type NL* RPAREN
;
Expression Syntax
expression
: assignmentExpression
;
assignmentExpression
: leftValueExpressionWithoutWildCard NL* assignmentOperator NL* flowExpression
| leftValueExpression NL* ASSIGN NL* flowExpression
| tupleLeftValueExpression NL* ASSIGN NL* flowExpression
| flowExpression
;
tupleLeftValueExpression
: LPAREN NL* (leftValueExpression | tupleLeftValueExpression) (NL* COMMA NL* (leftValueExpression | tupleLeftValueExpression))+ NL* COMMA? NL* RPAREN
;
leftValueExpression
: leftValueExpressionWithoutWildCard
| WILDCARD
;
leftValueExpressionWithoutWildCard
: identifier
| leftAuxExpression QUEST? NL* assignableSuffix
;
leftAuxExpression
: identifier (NL* typeArguments)?
| type
| thisSuperExpression
| leftAuxExpression QUEST? NL* DOT NL* identifier (NL* typeArguments)?
| leftAuxExpression QUEST? callSuffix
| leftAuxExpression QUEST? indexAccess
;
assignableSuffix
: fieldAccess
| indexAccess
;
fieldAccess
: NL* DOT NL* identifier
;
flowExpression
: coalescingExpression (NL* flowOperator NL* coalescingExpression)*
;
coalescingExpression
: logicDisjunctionExpression (NL* QUEST QUEST NL* logicDisjunctionExpression)*
;
logicDisjunctionExpression
: logicConjunctionExpression (NL* OR NL* logicConjunctionExpression)*
;
logicConjunctionExpression
: rangeExpression (NL* AND NL* rangeExpression)*
;
rangeExpression
: bitwiseDisjunctionExpression NL* (CLOSEDRANGEOP | RANGEOP) NL* bitwiseDisjunctionExpression (NL* COLON NL* bitwiseDisjunctionExpression)?
| bitwiseDisjunctionExpression
;
bitwiseDisjunctionExpression
: bitwiseXorExpression (NL* BITOR NL* bitwiseXorExpression)*
;
bitwiseXorExpression
: bitwiseConjunctionExpression (NL* BITXOR NL* bitwiseConjunctionExpression)*
;
bitwiseConjunctionExpression
: equalityComparisonExpression (NL* BITAND NL* equalityComparisonExpression)*
;
equalityComparisonExpression
: comparisonOrTypeExpression (NL* equalityOperator NL* comparisonOrTypeExpression)?
;
comparisonOrTypeExpression
: shiftingExpression (NL* comparisonOperator NL* shiftingExpression)?
| shiftingExpression (NL* IS NL* type)?
| shiftingExpression (NL* AS NL* type)?
;
shiftingExpression
: additiveExpression (NL* shiftingOperator NL* additiveExpression)*
;
additiveExpression
: multiplicativeExpression (NL* additiveOperator NL* multiplicativeExpression)*
;
multiplicativeExpression
: exponentExpression (NL* multiplicativeOperator NL* exponentExpression)*
;
exponentExpression
: prefixUnaryExpression (NL* exponentOperator NL* prefixUnaryExpression)*
;
prefixUnaryExpression
: prefixUnaryOperator* incAndDecExpression
;
incAndDecExpression
: postfixExpression (INC | DEC )?
;
postfixExpression
: atomicExpression
| type NL* DOT NL* identifier
| postfixExpression NL* DOT NL* identifier (NL* typeArguments)?
| postfixExpression callSuffix
| postfixExpression indexAccess
| postfixExpression NL* DOT NL* identifier callSuffix? trailingLambdaExpression
| identifier callSuffix? trailingLambdaExpression
| postfixExpression (QUEST questSeperatedItems)+
;
questSeperatedItems
: questSeperatedItem+
;
questSeperatedItem
: itemAfterQuest (callSuffix | callSuffix? trailingLambdaExpression | indexAccess)?
;
itemAfterQuest
: DOT identifier (NL* typeArguments)?
| callSuffix
| indexAccess
| trailingLambdaExpression
;
callSuffix
: LPAREN NL* (valueArgument (NL* COMMA NL* valueArgument)* NL*)? RPAREN
;
valueArgument
: identifier NL* COLON NL* expression
| expression
| refTransferExpression
;
refTransferExpression
: INOUT (expression DOT)? identifier
;
indexAccess
: LSQUARE NL* (expression | rangeElement) NL* RSQUARE
;
rangeElement
: RANGEOP
| ( CLOSEDRANGEOP | RANGEOP ) NL* expression
| expression NL* RANGEOP
;
atomicExpression
: literalConstant
| collectionLiteral
| tupleLiteral
| identifier (NL* typeArguments)?
| unitLiteral
| ifExpression
| matchExpression
| loopExpression
| tryExpression
| jumpExpression
| numericTypeConvExpr
| thisSuperExpression
| spawnExpression
| synchronizedExpression
| parenthesizedExpression
| lambdaExpression
| quoteExpression
| macroExpression
| unsafeExpression
;
literalConstant
: IntegerLiteral
| FloatLiteral
| RuneLiteral
| ByteLiteral
| booleanLiteral
| stringLiteral
| ByteStringArrayLiteral
| unitLiteral
;
booleanLiteral
: TRUE
| FALSE
;
stringLiteral
: lineStringLiteral
| multiLineStringLiteral
| MultiLineRawStringLiteral
;
lineStringContent
: LineStrText
;
lineStringLiteral
: QUOTE_OPEN (lineStringExpression | lineStringContent)* QUOTE_CLOSE
;
lineStringExpression
: StrExprStart SEMI* (expressionOrDeclaration (SEMI+ expressionOrDeclaration?)*) SEMI* RCURL
;
multiLineStringContent
: MultiLineStrText
;
multiLineStringLiteral
: TRIPLE_QUOTE_OPEN (multiLineStringExpression | multiLineStringContent)* TRIPLE_QUOTE_CLOSE
;
multiLineStringExpression
: StrExprStart end* (expressionOrDeclaration (end+ expressionOrDeclaration?)*) end* RCURL
;
collectionLiteral
: arrayLiteral
;
arrayLiteral
: LSQUARE (NL* elements)? NL* RSQUARE
;
elements
: element ( NL* COMMA NL* element )*
;
element
: expressionElement
| spreadElement
;
expressionElement
: expression
;
spreadElement
: MUL expression
;
tupleLiteral
: LPAREN NL* expression (NL* COMMA NL*expression)+ NL* RPAREN
;
unitLiteral
: LPAREN NL* RPAREN
;
ifExpression
: IF NL* LPAREN NL* (LET NL* deconstructPattern NL* BACKARROW NL*)? expression NL* RPAREN NL* block
(NL* ELSE (NL* ifExpression | NL* block))?
;
deconstructPattern
: constantPattern
| wildcardPattern
| varBindingPattern
| tuplePattern
| enumPattern
;
matchExpression
: MATCH NL* LPAREN NL* expression NL* RPAREN NL* LCURL NL* matchCase+ NL* RCURL
| MATCH NL* LCURL NL* (CASE NL* (expression | WILDCARD) NL* DOUBLE_ARROW NL* expressionOrDeclaration (end+ expressionOrDeclaration?)*)+ NL* RCURL
;
matchCase
: CASE NL* pattern NL* patternGuard? NL* DOUBLE_ARROW NL* expressionOrDeclaration (end+ expressionOrDeclaration?)*
;
patternGuard
: WHERE NL* expression
;
pattern
: constantPattern
| wildcardPattern
| varBindingPattern
| tuplePattern
| typePattern
| enumPattern
;
constantPattern
: literalConstant NL* ( NL* BITOR NL* literalConstant)*
;
wildcardPattern
: WILDCARD
;
varBindingPattern
: identifier
;
tuplePattern
: LPAREN NL* pattern (NL* COMMA NL* pattern)+ NL* RPAREN
;
typePattern
: (WILDCARD | identifier) NL* COLON NL* type
;
enumPattern
: NL* ((userType NL* DOT NL*)? identifier enumPatternParameters?) (NL* BITOR NL* ((userType NL* DOT NL*)? identifier enumPatternParameters?))*
;
enumPatternParameters
: LPAREN NL* pattern (NL* COMMA NL* pattern)* NL* RPAREN
;
loopExpression
: forInExpression
| whileExpression
| doWhileExpression
;
forInExpression
: FOR NL* LPAREN NL* patternsMaybeIrrefutable NL* IN NL* expression NL* patternGuard? NL* RPAREN NL* block
;
patternsMaybeIrrefutable
: wildcardPattern
| varBindingPattern
| tuplePattern
| enumPattern
;
whileExpression
: WHILE NL* LPAREN NL* (LET NL* deconstructPattern NL* BACKARROW NL*)? expression NL* RPAREN NL* block
;
doWhileExpression
: DO NL* block NL* WHILE NL* LPAREN NL* expression NL* RPAREN
;
tryExpression
: TRY NL* block NL* FINALLY NL* block
| TRY NL* block (NL* CATCH NL* LPAREN NL* catchPattern NL* RPAREN NL* block)+ (NL* FINALLY NL* block)?
| TRY NL* LPAREN NL* resourceSpecifications NL* RPAREN NL* block
(NL* CATCH NL* LPAREN NL* catchPattern NL* RPAREN NL* block)* (NL* FINALLY NL* block)?
;
catchPattern
: wildcardPattern
| exceptionTypePattern
;
exceptionTypePattern
: (WILDCARD | identifier) NL* COLON NL* type (NL* BITOR NL* type)*
;
resourceSpecifications
: resourceSpecification (NL* COMMA NL* resourceSpecification)*
;
resourceSpecification
: identifier (NL* COLON NL* classType)? NL* ASSIGN NL* expression
;
jumpExpression
: THROW NL* expression
| RETURN (NL* expression)?
| CONTINUE
| BREAK
;
numericTypeConvExpr
: numericTypes LPAREN NL* expression NL* RPAREN
;
thisSuperExpression
: THIS
| SUPER
;
lambdaExpression
: LCURL NL* lambdaParameters? NL* DOUBLE_ARROW NL* expressionOrDeclarations? RCURL
;
trailingLambdaExpression
: LCURL NL* (lambdaParameters? NL* DOUBLE_ARROW NL*)? expressionOrDeclarations? RCURL
;
lambdaParameters
: lambdaParameter (NL* COMMA NL* lambdaParameter)*
;
lambdaParameter
: (identifier | WILDCARD) (NL* COLON NL* type)?
;
spawnExpression
: SPAWN (LPAREN NL* expression NL* RPAREN)? NL* trailingLambdaExpression
;
synchronizedExpression
: SYNCHRONIZED LPAREN NL* expression NL* RPAREN NL* block
;
parenthesizedExpression
: LPAREN NL* expression NL* RPAREN
;
block
: LCURL expressionOrDeclarations RCURL
;
unsafeExpression
: UNSAFE NL* block
;
expressionOrDeclarations
: end* (expressionOrDeclaration (end+ expressionOrDeclaration?)*)?
;
expressionOrDeclaration
: expression
| varOrfuncDeclaration
;
varOrfuncDeclaration
: functionDefinition
| variableDeclaration
;
quoteExpression
: QUOTE quoteExpr
;
quoteExpr
: LPAREN NL* quoteParameters NL* RPAREN
;
quoteParameters
: (NL* quoteToken | NL* quoteInterpolate | NL* macroExpression)+
;
quoteToken
: DOT | COMMA | LPAREN | RPAREN | LSQUARE | RSQUARE | LCURL | RCURL | EXP | MUL | MOD | DIV | ADD | SUB
| PIPELINE | COMPOSITION
| INC | DEC | AND | OR | NOT | BITAND | BITOR | BITXOR | LSHIFT | RSHIFT | COLON | SEMI
| ASSIGN | ADD_ASSIGN | SUB_ASSIGN | MUL_ASSIGN | EXP_ASSIGN | DIV_ASSIGN | MOD_ASSIGN
| AND_ASSIGN | OR_ASSIGN | BITAND_ASSIGN | BITOR_ASSIGN | BITXOR_ASSIGN | LSHIFT_ASSIGN | RSHIFT_ASSIGN
| ARROW | BACKARROW | DOUBLE_ARROW | ELLIPSIS | CLOSEDRANGEOP | RANGEOP | HASH | AT | QUEST | UPPERBOUND | LT | GT | LE | GE
| NOTEQUAL | EQUAL | WILDCARD | BACKSLASH | QUOTESYMBOL | DOLLAR
| INT8 | INT16 | INT32 | INT64 | INTNATIVE | UINT8 | UINT16 | UINT32 | UINT64 | UINTNATIVE | FLOAT16
| FLOAT32 | FLOAT64 | RUNE | BOOL | UNIT | NOTHING | STRUCT | ENUM | THIS
| PACKAGE | IMPORT | CLASS | INTERFACE | FUNC | LET | VAR | CONST | TYPE
| INIT | THIS | SUPER | IF | ELSE | CASE | TRY | CATCH | FINALLY
| FOR | DO | WHILE | THROW | RETURN | CONTINUE | BREAK | AS | IN
| MATCH | FROM | WHERE | EXTEND | SPAWN | SYNCHRONIZED | MACRO | QUOTE | TRUE | FALSE
| STATIC | PUBLIC | PRIVATE | PROTECTED
| OVERRIDE | ABSTRACT | OPEN | OPERATOR | FOREIGN
| Identifier | DollarIdentifier
| literalConstant
;
quoteInterpolate
: DOLLAR LPAREN NL* expression NL* RPAREN
;
macroExpression
: AT Identifier macroAttrExpr? NL* (macroInputExprWithoutParens | macroInputExprWithParens)
;
macroAttrExpr
: LSQUARE NL* quoteToken* NL* RSQUARE
;
macroInputExprWithoutParens
: functionDefinition
| operatorFunctionDefinition
| staticInit
| structDefinition
| structPrimaryInit
| structInit
| enumDefinition
| caseBody
| classDefinition
| classPrimaryInit
| classInit
| interfaceDefinition
| variableDeclaration
| propertyDefinition
| extendDefinition
| macroExpression
;
macroInputExprWithParens
: LPAREN NL* macroTokens NL* RPAREN
;
macroTokens
: (quoteToken | macroExpression)*
;
assignmentOperator
: ASSIGN
| ADD_ASSIGN
| SUB_ASSIGN
| EXP_ASSIGN
| MUL_ASSIGN
| DIV_ASSIGN
| MOD_ASSIGN
| AND_ASSIGN
| OR_ASSIGN
| BITAND_ASSIGN
| BITOR_ASSIGN
| BITXOR_ASSIGN
| LSHIFT_ASSIGN
| RSHIFT_ASSIGN
;
equalityOperator
: NOTEQUAL
| EQUAL
;
comparisonOperator
: LT
| GT
| LE
| GE
;
shiftingOperator
: LSHIFT | RSHIFT
;
flowOperator
: PIPELINE | COMPOSITION
;
additiveOperator
: ADD | SUB
;
exponentOperator
: EXP
;
multiplicativeOperator
: MUL
| DIV
| MOD
;
prefixUnaryOperator
: SUB
| NOT
;
overloadedOperators
: LSQUARE RSQUARE
| NOT
| ADD
| SUB
| EXP
| MUL
| DIV
| MOD
| LSHIFT
| RSHIFT
| LT
| GT
| LE
| GE
| EQUAL
| NOTEQUAL
| BITAND
| BITXOR
| BITOR
;
Getting Started with Cangjie
Cangjie is a versatile, all-purpose programming language designed to optimize both application development efficiency and runtime performance, while providing an exceptional programming experience. Below are some of its key features:
- Clear and efficient syntax: Cangjie offers a streamlined syntax that enhances development efficiency and readability. Features such as string interpolation, primary constructors, flow expressions, pattern matching, and re-export enable developers to write concise, expressive code with minimal effort, making it easier to implement complex logic quickly.
- Multi-paradigm programming: Cangjie embraces a multi-paradigm approach, supporting functional, imperative, and object-oriented programming styles. It incorporates advanced functional features like higher-order functions, algebraic data types, pattern matching, and generics. At the same time, it integrates object-oriented concepts such as encapsulation, interfaces, inheritance, and subtype polymorphism, facilitating modular development. Additionally, Cangjie offers simple and efficient imperative features, including value types and global functions. This flexibility allows developers to choose the most appropriate paradigm for their development needs and application scenarios.
- Secure types: Cangjie is a statically and strongly-typed language that catches potential errors early through comprehensive type checks at compile time, reducing runtime risks and simplifying code maintenance. Its advanced type inference system further enhances productivity by minimizing the need for explicit type annotations, allowing developers to focus more on logic and less on type management.
- Secure memory management: Cangjie offers automatic memory management and includes built-in safeguards such as array index bounds checks and overflow detection to ensure memory safety. These features help prevent common memory-related errors, enhancing the stability and security of applications.
- Efficient concurrency: Cangjie leverages lightweight user-mode threads (native coroutines) and intuitive concurrency mechanisms to enable efficient development and execution in multi-threaded environments. This approach simplifies concurrent programming while ensuring optimal performance in concurrent scenarios.
- Cross-language compatibility: Cangjie supports seamless interoperability with popular programming languages, including C, and embraces a declarative programming paradigm. This enables efficient reuse of existing code and smooth integration with libraries from other language ecosystems, enhancing overall compatibility and flexibility.
- Scaling to new domains: Cangjie supports lexical macro-based metaprogramming, enabling code transformation at compile time. Combined with features such as trailing lambda, properties, operator overloading, and keyword omission, it enables developers to construct embedded domain-specific languages (EDSLs) with ease.
- Optimized UI development: UI development is a core aspect of device-side applications, and Cangjie streamlines this process with the powerful metaprogramming features mentioned above. These capabilities enable the creation of declarative UI frameworks, enhancing both development efficiency and the overall user experience.
- Comprehensive built-in libraries: Cangjie offers an extensive set of built-in libraries, covering a wide range of functionality including data structures, common algorithms, numerical functions, regular expression matching, system interactions, file handling, network communication, database access, logging, compression and decompression, encoding and decoding, as well as encryption-decryption and serialization-deserialization.
Installing the Cangjie Toolchain
One of the essential tools used in developing a Cangjie program is the Cangjie compiler, which can compile the Cangjie source code into an executable binary file. The auxiliary tools of this modern programming language offer far beyond this. Cangjie provides developers with a comprehensive development toolchain, including the compiler, debugger, package manager, static checking tool, formatting tool, and coverage measurement tool. It also offers user-friendly installation and usage modes, with functions available right out of the box.
Currently, the Cangjie toolchain has been adapted to some Linux and Windows versions. However, a complete function test has been performed only on some Linux distributions. For details, see Installation and Support of the Tool Chain for Linux. The function integrity of the Cangjie toolchain is not guaranteed on platforms that have not been fully tested. In addition, the Cangjie compiler on Windows is implemented based on MinGW. This indicates that some functions may be unavailable compared to those on Linux. For details about the differences, see the release notes of the corresponding version.
Linux
Environment Setup
The environment requirements for installing the Cangjie toolchain on Linux are as follows:
| Architecture | Environment Requirements |
|---|---|
| x86_64 | glibc 2.22, Linux Kernel 4.12 or later, and libstdc++ 6.0.24 or later |
| aarch64 | glibc 2.27, Linux Kernel 4.15 or later, and libstdc++ 6.0.24 or later |
In addition, you need to install the following dependencies for Ubuntu 18.04:
$ apt-get install binutils libc-dev libc++-dev libgcc-7-dev
For details about the dependency installation commands of Linux distributions, see Installation and Support of the Tool Chain for Linux in the appendix.
The Cangjie toolchain also depends on the OpenSSL 3 component, which may fail to be installed from the default software sources of the preceding distributions and require manual installation. For details, see Installation and Support of the Tool Chain for Linux.
Installation Guide
Go to the official release channel of Cangjie and download the installation package that adapts to your platform architecture.
Cangjie-x.y.z-linux_x64.tar.gz: Cangjie toolchain for x86_64 LinuxCangjie-x.y.z-linux_aarch64.tar.gz: Cangjie toolchain for AArch64 Linux
Assume that Cangjie-x.y.z-linux_x64.tar.gz is selected. After downloading the package to the local PC, decompress it.
tar xvf Cangjie-x.y.z-linux_x64.tar.gz
After the decompression is complete, the cangjie directory that stores all contents of the Cangjie toolchain is displayed in the working directory. Install and configure the toolchain.
source cangjie/envsetup.sh
Check whether the installation is successful.
cjc -v
cjc is the executable file name of the Cangjie compiler. If the compiler version is returned in the command output, the Cangjie toolchain has been successfully installed. It is worth noting that the envsetup.sh script configures the environment variables related to the toolchain only in the current shell environment. Therefore, the Cangjie toolchain is available only in the shell environment. If you open a new shell environment, run the envsetup.sh script again to configure the environment.
To make the environment variable configuration of the Cangjie toolchain automatically take effect during shell startup, add the following command to the end of the shell initialization configuration file such as $HOME/.bashrc or $HOME/.zshrc, depending on the shell type:
# Assume that the Cangjie installation package is extracted to /home/user/cangjie.
source /home/user/cangjie/envsetup.sh # Absolute path of the envsetup.sh file
After the configuration is complete, the Cangjie compilation toolchain will be ready for use when the shell starts.
Uninstallation and Update
To uninstall the Cangjie toolchain, delete the installation package directory of the Cangjie toolchain and remove the preceding environment variables on Linux. A simple solution is to open a new shell environment.
$ rm -rf <path>/<to>/cangjie
To update the Cangjie toolchain, uninstall the current version and then install the latest Cangjie toolchain according to the preceding instructions.
Windows
This section describes how to install the Cangjie toolchain on Windows 10.
Installation Guide
For Windows, Cnagjie provide developers with installation packages in EXE and ZIP formats. Go to the official release channel of Cangjie and download the Windows installation package that adapts to your platform architecture.
If you select an installation package in EXE format (for example, Cangjie-x.y.z-windows_x64.exe), execute the file, and follow the installation wizard to complete the installation.
If you select an installation package in ZIP format (for example, Cangjie-x.y.z-windows_x64.zip), decompress it to an appropriate directory. In the installation package, there are three installation scripts in different formats: envsetup.bat, envsetup.ps1, and envsetup.sh. Select one of them based on your preferences and environment configurations.
If Windows Command Prompt (CMD) is deployed, run the following command:
path\to\cangjie\envsetup.bat
If PowerShell is deployed, run the following command:
. path\to\cangjie\envsetup.ps1
If the MSYS shell or Bash is deployed, run the following command:
source path/to/cangjie/envsetup.sh
To check whether the installation is successful, run the cjc -v command in the corresponding environment. If the Cangjie compiler version is output, the Cangjie toolchain has been successfully installed.
Note:
The installation of the
ZIPinstallation package and execution script is similar to that on Linux. The environment variables configured by theenvsetupscript are valid only in the current CLI. If you open a new CLI, run theenvsetupscript again to configure the environment.
Uninstallation and Update
Run the executable unins000.exe file in the Cangjie installation directory and follow the uninstallation wizard to complete the uninstallation.
To update the Cangjie toolchain, uninstall the current version and then install the latest Cangjie toolchain according to the preceding instructions.
Running the First Cangjie Program
With everything in place, let's compile and run the first Cangjie program!
First, create a text file named hello.cj in an appropriate directory and enter the following Cangjie code into the file:
// hello.cj
main() {
println ("Hello, Cangjie")
}
This code uses the Cangjie comment syntax. You can write a single line of comments after // or multiple lines of comments between /* and */ . The syntax is the same as that of other languages such as C and C++. The contents of the comments do not affect program compilation and running.
Then, run the following command in the directory:
cjc hello.cj -o hello
The Cangjie compiler compiles the source code in hello.cj to an executable file hello on the platform. Run the file in the CLI. The following program output is displayed:
Hello, Cangjie
Note:
The preceding compilation command applies to Linux. If you use Windows, change the compilation command to
cjc hello.cj -o hello.exe.
Identifiers
In Cangjie, developers can assign names to various program elements, known as identifiers. Identifiers are categorized into two types: common identifiers and raw identifiers, each with its own set of naming rules.
A common identifier cannot be a keyword in Cangjie. It must be formed from one of the following two types of character sequences:
- Starting with an XID_Start character, followed by XID_Continue characters of any length.
- Starting with
_, followed by at least one XID_Continue character.
For definitions of XID_Start and XID_Continue, see Unicode Standard. Cangjie uses the Unicode standard 15.0.0.
In Cangjie, all identifiers are identified as Normalization Form C (NFC). If two identifiers are equal after normalization to NFC, they are considered to be the same.
For example, all of the following strings are valid common identifiers:
abc
_abc
abc_
a1b2c3
a_b_c
a1_b2_c3
仓颉
__こんにちは
The following character strings are invalid common identifiers:
ab&c // The invalid character "&" is used.
3abc // An identifier cannot start with a digit.
while // An identifier cannot be a keyword in Cangjie.
A raw identifier is a common identifier or a Cangjie keyword enclosed in backticks (`). It is primarily used when a keyword needs to be treated as an identifier.
For example, all of the following strings are valid raw identifiers:
`abc`
`_abc`
`a1b2c3`
`if`
`while`
`à֮̅̕b`
In each of the following character strings, the part enclosed in backticks is an invalid common identifier. Therefore, they are all invalid raw identifiers.
`ab&c`
`3abc`
Program Structure
Cangjie programs are typically written as .cj text files, know collectively as source code. During the final stage of development, the program's source code is compiled into binary files in a specific format, ready for execution.
The top-level scope of a Cangjie program can include definitions of variables, functions, and user-defined types such as struct, class, enum, and interface. These variables and functions are referred to as global variables and global functions, respectively. To compile a Cangjie program into an executable, a main function must be defined as the program's entry point within the top-level scope. The main function may either accept a parameter of type Array<String> or have no parameters at all. Its return type can be either an integer or Unit.
Note:
The definition of the
mainfunction does not require thefuncmodifier. Command line parameters when the program is started are obtained via anArray<String>type parameter ofmain.
For example, in the following program, global variable a, global function b, user-defined types C, D, and E, and the main function that serves as the program entry point are all defined in the top-level scope.
// example.cj
let a = 2023
func b() {}
struct C {}
class D {}
enum E { F | G }
main() {
println(a)
}
The user-defined types mentioned earlier cannot be defined in a non-top-level scope. However, local variables and local functions can be defined within such scopes. Variables and functions defined within user-defined types are referred to as member variables and member functions, respectively.
Note:
enumandinterfacepermit only the definition of member functions but not member variables.
For example, in the following program, the global function a and user-defined type A are defined in the top-level scope, the local variable b and local function c are defined in the function a, and the member variable b and member function c are defined in the user-defined type A.
// example.cj
func a() {
let b = 2023
func c() {
println(b)
}
c()
}
class A {
let b = 2024
public func c() {
println(b)
}
}
main() {
a()
A().c()
}
Running the preceding program outputs:
2023
2024
Variables
In Cangjie, a variable consists of a variable name, data (value), and several attributes. Developers can access the data corresponding to the variable through the variable name. The access operation must comply with the constraints imposed by the associated attributes (such as the data type, mutability, and visibility).
The form of variable definition is as follows:
Modifier Variable name: Variable type = Initial value
Modifier is used to set various attributes of the variable. There can be one or more modifiers. Common modifiers are as follows:
- Mutability modifiers:
letandvar, which correspond to the immutable and mutable attributes, respectively. Mutability determines whether the value of a variable can be modified after initialization. Therefore, Cangjie variables are classified into immutable variables and mutable variables. - Visibility modifiers: such as
privateandpublic, which affect the reference scope of global variables and member variables. For details, see subsequent sections. - Static modifier:
static, which affects the storage and reference modes of member variables. For details, see subsequent sections.
Mutability modifiers are mandatory in Cangjie variable definition. You can add other modifiers as required.
- Variable name must be a valid Cangjie identifier.
- Variable type specifies the type of data held by the variable. When the initial value has an explicit type, a variable type is not required, as the compiler can automatically infer it.
- Initial value is a Cangjie expression used for variable initialization. If the variable type is specified, the initial value type must have the same type as the variable type. When defining a global variable or a static member variable, an initial value is mandatory. When defining a local variable or an instance member variable, the initial value is optional. However, the variable type and value must be in place before the variable can be referenced. Otherwise, an error will be reported during compilation.
For example, in the following program, an immutable variable a and a mutable variable b are defined, both of the Int64 type. Then, the value of b is modified and the println function is called to print the values of a and b.
main() {
let a: Int64 = 20
var b: Int64 = 12
b = 23
println("${a}${b}")
}
The following output is produced after the program is compiled and executed:
2023
If the value of an immutable variable is attempted to be modified, an error will be reported during compilation. For example:
main() {
let pi: Float64 = 3.14159
pi = 2.71828 // Error, cannot assign to immutable value
}
When the initial value is of an explicit type, the variable type is not required. For example:
main() {
let a: Int64 = 2023
let b = a
println("a - b = ${a - b}")
}
The type of the variable b can be automatically inferred as Int64 from the type of its initial value a. Therefore, the program can be compiled and executed without errors, and the following output is produced:
a - b = 0
A local variable may be left uninitialized. However, an initial value must be assigned before the variable is referenced. For example:
main() {
let text: String
text = "The invention of Chinese characters by Cangjie"
println(text)
}
The following output is produced when the program is compiled and executed:
The invention of Chinese characters by Cangjie
Global variables and static member variables must be initialized when they are defined. Otherwise, an error will be reported during compilation. For example:
// example.cj
let global: Int64 // Error, variable in top-level scope must be initialized
// example.cj
class Player {
static let score: Int32 // Error, static variable 'score' needs to be initialized when declaring
}
Value-type and Reference-type Variables
During program execution, only the flow of instructions and data transformations occur, while the identifiers used in the program no longer exist in a tangible form. This indicates that the compiler employs a mechanism to bind names to the underlying data entities or memory spaces used during execution.
From the perspective of compiler implementation, a variable is always associated with a value (generally through a memory address or register). A variable whose value is directly used is a value-type variable. A variable whose value is used as an index to retrieve the data represented by the index is a reference-type variable. Variables of value type are usually allocated on the thread stack, with each variable having its own data copy. Variables of the reference type are usually allocated on the process heap, and multiple variables can reference the same data object. In this case, operations performed on a reference-type variable may affect other variables.
From the perspective of the language, a variable of value type exclusively occupies the data or storage space bound to it, whereas a variable of reference type shares the data or storage space bound to it with other variables of reference type.
Based on the preceding principles, there are some behavioral differences to note when value-type variables and reference-type variables are used:
- When a value is assigned to a value-type variable, a copy operation is usually performed, and the originally bound data or storage space is overwritten. When a value is assigned to a reference-type variable, only the reference is modified, and the originally bound data or storage space is not overwritten.
- Variables defined by
letcannot be assigned values after being initialized. For a reference-type variable, this means that the reference itself cannot be modified, but the referenced data can be modified.
In Cangjie, reference-type variables include class and Array, and value-type variables include other basic data types and struct.
For example, the following program demonstrates the behavioral differences between struct and class variables:
struct Copy {
var data = 2012
}
class Share {
var data = 2012
}
main() {
let c1 = Copy()
var c2 = c1
c2.data = 2023
println("${c1.data}, ${c2.data}")
let s1 = Share()
let s2 = s1
s2.data = 2023
println("${s1.data}, ${s2.data}")
}
Running the program produces the following output:
2012, 2023
2023, 2023
The above shows that, for a value-type Copy variable, a copy of the Copy instance is always obtained during value assignment, for example, in c2 = c1. Subsequent modifications to the value of c2 will not affect the value of c1. For a reference-type Share variable, a reference between the variable and the instance is established during value assignment, for example, in s2 = s1. Subsequent modifications to the value of s2 will affect the value of s1.
If var c2 = c1 in the preceding programs is changed to let c2 = c1, an error will be reported during compilation. For example:
struct Copy {
var data = 2012
}
main() {
let c1 = Copy()
let c2 = c1
c2.data = 2023 // Error, cannot assign to immutable value
}
Scopes
In the previous section, we discussed how to name Cangjie program elements. In addition to variables, both functions and user-defined types can also be named. These names are then used to reference and access the corresponding program elements within the code.
In actual applications, however, the following special cases need to be considered:
- When a program is large, short names are more likely to be used repeatedly, causing name conflicts.
- Considering runtime factors, certain program elements may be invalid in specific code snippets, and referencing them can lead to runtime errors.
- In some logical constructs, to express the inclusion relationship between elements, a child element should not be accessed directly by its name, but indirectly by its parent element name.
To address these issues, modern programming languages introduce the concept of scope, which limits the binding of names to program elements within a specific range. Scopes can be parallel, unrelated, nested, or enclosed. A scope defines the set of names that can be accessed within a given context. The rules governing scope are as follows:
- The binding relationship between a program element and a name defined in a scope is valid in the scope and its inner scope. The name can be used to directly access the corresponding program element.
- The binding relationship between a program element and a name defined in an inner scope is invalid in an outer scope.
- An inner scope can use the name in an outer scope to redefine the binding relationship. According to rule 1, the name in the inner scope covers the definition of the same name in the outer scope. Therefore, the level of the inner scope is higher than that of the outer scope.
In Cangjie, a pair of braces ({}) is used to enclose a segment of Cangjie code. In this way, a scope is constructed. Furthermore, nested scopes can be constructed by enclosing the scope with braces. These scopes comply with the preceding rules. Specifically, in a Cangjie source file, the scope to which the code that is not enclosed by any braces belongs is called the top-level scope, that is, the outermost scope in the file. According to the preceding rules, its scope level is the lowest.
Note:
When braces are used to enclose code segments and define a scope, functions and user-defined types can be declared, in addition to expressions.
For example, in the following Cangjie source file (test.cj), the name element is defined in the top-level scope, which is bound to the string "Cangjie". The name element is also defined in the code blocks led by main and if, corresponding to the integer 9 and integer 2023, respectively. According to the preceding scope rules, the value of element is "Cangjie" in line 4, 2023 in line 8, and 9 in line 10.
// test.cj
let element = "Cangjie"
main() {
println(element)
let element = 9
if (element > 0) {
let element = 2023
println(element)
}
println(element)
}
Running the preceding program produces the output:
Cangjie
2023
9
Expressions
In many programming languages, an expression consists of operands and operators, always implying a calculation process with a result. If an expression contains only operands, the result is the operand itself. If it includes operators, the result is the value derived from applying the operators to the operands. Such expressions are also known as arithmetic expressions.
In Cangjie, the definition of expressions is both simplified and extended: all evaluable language elements are considered expressions. This means that, in addition to arithmetic expressions, Cangjie includes conditional expressions, loop expressions, and try expressions, all of which can be evaluated and used as values—such as function arguments or initial variable assignments. Furthermore, as a strongly-typed language, every Cangjie expression is not only evaluable but also has a well-defined type, which is the same as that of its result.
The expressions of Cangjie will be described in the subsequent sections. This section describes the most commonly used condition expressions, loop expressions, and some control transfer expressions (break and continue).
The execution process of programs involves only three basic structures: sequential structure, branching structure, and loop structure. The branching structure and loop structure are achieved through instructions that control jumps in the current sequential execution flow, allowing programs to express more complex logic. In Cangjie, the language elements used to control the execution flow are condition expressions and loop expressions.
In Cangjie, condition expressions are classified into if and if-let expressions. Their values and types are determined based on application scenarios. There are four types of loop expressions: for-in, while, do-while, and while-let. Their type is always Unit, which as its unique value (). Among the four types, if-let and while-let are related to pattern matching. For details, see if-let Expression and while-let Expression. This section focuses on the other two types of expressions.
In Cangjie, a group of expressions enclosed in braces ({}) is called a code block. A code block represents a sequential flow of execution, with expressions being evaluated in the order they appear. If the code block contains one or more expressions, its value and type are determined by the last expression. If the code block is empty, its type is Unit, so its value is ().
Note:
A code block itself is not an expression and cannot be used independently. It depends on the execution and evaluation of functions, condition expressions, and loop expressions.
if Expressions
The basic form of if expressions is as follows:
if (Condition) {
Branch 1
} else {
Branch 2
}
In the preceding, "Condition" is a Boolean expression, and "Branch 1" and "Branch 2" are code blocks. An if expression is executed as follows:
- Evaluate the "Condition" expression. If the value is
true, go to step 2. If the value isfalse, go to step 3. - Perform "Branch 1" and go to step 4.
- Perform "Branch 2" and go to step 4.
- Continue to execute the code following the
ifexpression.
In some scenarios, we may only focus on what to do when the condition is met, so else and the corresponding code block can be omitted.
The following program demonstrates the basic usage of if expressions:
import std.random.*
main() {
let number: Int8 = Random().nextInt8()
println(number)
if (number % 2 == 0) {
println("even")
} else {
println("odd")
}
}
In this program, we use the random package of the standard library to generate a random integer. We then use the if expression to determine whether the integer can be exactly divided by 2, and print "even" or "odd" in different condition branches.
Cangjie is strongly typed. The condition of the if expression can only be of the Boolean type and cannot be an integer or floating-point number. Different from the C language, the if expression does not select a branch based on whether the condition value is 0. For example, the following program will report a compilation error:
main() {
let number = 1
if (number) { // Error, mismatched types
println("nonzero")
}
}
In many scenarios, when a condition is not met, one or more conditions may need to be determined before the corresponding action is executed. A new if expression can be followed after else. In this way, multi-level condition judgment and branch execution are supported. For example:
import std.random.*
main() {
let speed = Random().nextFloat64() * 20.0
println("${speed} km/s")
if (speed > 16.7) {
Println("Third cosmic speed, meeting on the magpie bridge across the Milky Way")
} else if (speed > 11.2) {
Println("Second cosmic speed, flying to the moon")
} else if (speed > 7.9) {
println("First cosmic speed, riding clouds")
} else {
println("Down to earth, looking up to the starry sky")
}
}
The value and type of an if expression are determined based on the usage form and scenario.
-
When an
ifexpression containing one or moreelsebranches is evaluated, the type of theifexpression needs to be determined based on the evaluation context.- If the context requires that the value type be
T, the type of the code block in each branch in theifexpression must be the subtype ofT. In this case, the type of theifexpression is determined asT. If the subtype constraint is not met, an error is reported during compilation. - If the context does not have specific type requirements, the type of the
ifexpression is the minimum common parent type of the code block type of each branch. If the minimum common parent type does not exist, an error is reported during compilation.
If the compilation is successful, the value of the
ifexpression is the value of the code block of the executed branch. - If the context requires that the value type be
-
If the
ifexpression containing one or moreelsebranches is not evaluated, developers may only wish to perform different operations in different branches and do not pay attention to the value and type of the last expression in each branch. In this scenario, theifexpression type isUnit, the value is(), and each branch is not subject to the preceding type check. -
For an
ifexpression that does not contain anyelsebranches, theifbranch may not be executed. Therefore, the type of suchifexpressions isUnitand the value is().
For example, the following program calculates a simple analog-to-digital conversion process based on if expression evaluation:
main() {
let zero: Int8 = 0
let one: Int8 = 1
let voltage = 5.0
let bit = if (voltage < 2.5) {
zero
} else {
one
}
}
In the preceding program, the if expression is used as the initial value of variable definition. Because the variable bit is not marked with a type and its type needs to be deduced from the initial value, the type of the if expression is the smallest common parent type of the code block types of the two branches. According to the preceding description about code blocks, the code block type of both branches is Int8. Therefore, the type of the if expression is Int8, and the value is the value of the executed branch, that is, the value of the else branch code block. Therefore, the type of the variable bit is Int8, and the value is 1.
while Expressions
The basic form of while expressions is as follows:
while (Condition) {
Loop body
}
In the preceding, "Condition" is a Boolean expression, and "Loop body" is a code block. A while expression is executed as follows:
- Evaluate the "Condition" expression. If the value is
true, go to step 2. If the value isfalse, go to step 3. - Execute "Loop body" and go to step 1.
- End the loop and continue to execute the code following the
whileexpression.
For example, the following program uses a while expression to approximate the square root of 2 based on the bisection method:
main() {
var root = 0.0
var min = 1.0
var max = 2.0
var error = 1.0
let tolerance = 0.1 ** 10
while (error ** 2 > tolerance) {
root = (min + max) / 2.0
error = root ** 2 - 2.0
if (error > 0.0) {
max = root
} else {
min = root
}
}
println("The square root of 2 is approximately equal to: ${root}")
}
Running the preceding program produces the output:
The square root of 2 is approximately equal to: 1.414215.
do-while Expressions
The basic form of do-while expressions is as follows:
do {
Loop body
} while (Condition)
In the preceding, "Condition" is a Boolean expression, and "Loop body" is a code block. A do-while expression is executed as follows:
- Execute "Loop body" and go to step 2.
- Evaluate the "Condition" expression. If the value is
true, go to step 1. If the value isfalse, go to step 3. - End the loop and continue to execute the code following the
do-whileexpression.
For example, the following program uses a do-while expression to approximate the value of pi based on the Monte Carlo algorithm:
import std.random.*
main() {
let random = Random()
var totalPoints = 0
var hitPoints = 0
do {
// Randomly select a point in the square ((0, 0), (1, 1)).
let x = random.nextFloat64()
let y = random.nextFloat64()
// Determine whether it falls on an inscribed circle in the square.
if ((x - 0.5) ** 2 + (y - 0.5) ** 2 < 0.25) {
hitPoints++
}
totalPoints++
} while (totalPoints < 1000000)
let pi = 4.0 * Float64(hitPoints) / Float64(totalPoints)
println("The value of pi is approximately equal to: ${pi}")
}
Running the preceding program produces the output:
The value of pi is approximately equal to: 3.141872
NOTE
The algorithm involves random numbers. Therefore, the output value may be different each time the program is executed, but the output value is approximately equal to 3.14.
for-in Expressions
A for-in expression can traverse type instances that extend the iterator interface Iterable<T>. The basic form of for-in expressions is as follows:
for (Iteration variable in Sequence) {
Loop body
}
In the preceding, "Loop body" is a code block. "Iteration variable" is a single identifier or a tuple consisting of multiple identifiers. It is used to bind the data pointed to by the iterator in each round of traversal and can be used as a local variable in "Loop body". "Sequence" is an expression that is evaluated only once. The traversal is performed based on the value of the expression. The type of "Sequence" must extend the iterator interface Iterable<T>. A for-in expression is executed as follows:
- Evaluate the "sequence" expression, take its value as the traversal object, and initialize the iterator of the traversal object.
- Update the iterator. If the iterator terminates, go to step 4. Otherwise, go to step 3.
- Bind the data pointed to by the current iterator to "Iteration variable", execute the loop body, and go to step 2.
- End the loop and continue to execute the code following the
for-inexpression.
NOTE
The
Iterable<T>interface has been extended by the built-in interval and array types.
For example, the following program uses a for-in expression to traverse the array noumenonArray consisting of the 12 Chinese earthly branches. The heavenly stem and earthly branch for each month of the lunar year 2024 are output.
main() {
let metaArray = [r'甲', r'乙', r'丙', r'丁', r'戊',
r'己', r'庚', r'辛', r'壬', r'癸']
let noumenonArray = [r'寅', r'卯', r'辰', r'巳', r'午', r'未',
r'申', r'酉', r'戌', r'亥', r'子', r'丑']
let year = 2024
// Heavenly stem index corresponding to the first month of the year
let metaOfYear = ((year % 10) + 10 - 4) % 10
// Heavenly stem index corresponding to the first month of the year
var index = (2 * metaOfYear + 3) % 10 - 1
println("Heavenly stem and earthly branch for each month of the lunar year 2024:")
for (noumenon in noumenonArray) {
print("${metaArray[index]}${noumenon} ")
index = (index + 1) % 10
}
}```
Running the program outputs:
```text
Heavenly stem and earthly branch for each month of the lunar year 2024:
丙寅 丁卯 戊辰 己巳 庚午 辛未 壬申 癸酉 甲戌 乙亥 丙子 丁丑
Traversing the Interval Type
A for-in expression can traverse interval type instances. For example:
main() {
var sum = 0
for (i in 1..=100) {
sum += i
}
println(sum)
}
Running the program outputs:
5050
For details about the interval type, see Range.
Traversing Sequences Composed of Tuples
If the elements of a sequence are of the tuple type, the iteration variable can be written in the tuple form when the for-in expression is used for traversal to deconstruct the sequence elements. For example:
main() {
let array = [(1, 2), (3, 4), (5, 6)]
for ((x, y) in array) {
println("${x}, ${y}")
}
}
Run the preceding program and the following information will be displayed:
1, 2
3, 4
5, 6
Iteration Variables Cannot Be Modified
In the loop body of the for-in expression, the iteration variable cannot be modified. For example, the following program reports an error during compilation:
main() {
for (i in 0..5) {
i = i * 10 // Error, cannot assign to value which is an initialized 'let' constant
println(i)
}
}
Using a Wildcard (_) to Replace the Iteration Variable
In some application scenarios, if you need to perform certain operations cyclically without using an iteration variable, you can use a wildcard _ to replace the iteration variable. For example:
main() {
var number = 2
for (_ in 0..5) {
number *= number
}
println(number)
}
Running the program outputs:
4294967296
Note:
In this scenario, if you use a common identifier to define an iteration variable, the "unused variable" warning will be generated during compilation. You can use the wildcard
_to prevent receiving this warning.
where Condition
In some loop traversal scenarios, you may need to skip iteration variables with specific values and enter the next loop. Although you can use the if expression and continue expression to implement this logic in the loop body, the where keyword can be used to introduce a Boolean expression after the traversed sequence. In this way, the expression is evaluated each time before the loop body is executed. If the value is true, the loop body is executed, otherwise, the next cycle starts. The following is an example:
main() {
for (i in 0..8 where i % 2 == 1) { // The loop body is executed only if i is an odd number.
println(i)
}
}
Run the preceding program and the following information will be displayed:
1
3
5
7
break and continue Expressions
In programs with loop structures, there are situations where it is necessary to exit a loop early or skip an iteration based on specific conditions. To address this, Cangjie introduces the break and continue expressions, which can be used within the body of a loop. The break expression immediately terminates the loop and transfers control to the code following the loop. On the other hand, the continue expression skips the current iteration and proceeds to the next iteration of the loop. Both break and continue expressions have the Nothing type.
For example, the following program uses the for-in and break expressions to find the first number that is divisible by 5 in a given integer array:
main() {
let numbers = [12, 18, 25, 36, 49, 55]
for (number in numbers) {
if (number % 5 == 0) {
println(number)
break
}
}
}
When for-in iterates to the third number (25) of the numbers array, println followed by break in the if branch are executed, because 25 is divisible by 5. break terminates the for-in loop, and the subsequent numbers in numbers are not traversed. Therefore, the preceding program will output the following information:
25
The following program uses the for-in and continue expressions to print the odd numbers in a given integer array:
main() {
let numbers = [12, 18, 25, 36, 49, 55]
for (number in numbers) {
if (number % 2 == 0) {
continue
}
println(number)
}
}
In the loop iteration, when the value of number is even, the continue expression is triggered. This causes the current iteration to end immediately, and the loop proceeds to the next iteration. As a result, the println statement is not executed for even values of number. Therefore, the program will output the following:
25
49
55
Functions
In Cangjie, the keyword func is used to indicate the start of a function definition, followed by the function name, parameter list, function return value type (optional), and function body. A function name can be any valid identifier. A parameter list is defined in a pair of parentheses (()), where a comma (,) is used to separate parameters. A colon (:) is used to separate the parameter list and function return value type (if specified). A function body is defined in a pair of braces ({}).
The following is an example of function definition:
func add(a: Int64, b: Int64): Int64 {
return a + b
}
In the preceding example, a function named add is defined. Its parameter list consists of two parameters of the Int64 type: a and b. The return value type of the function is Int64. In the function body, a and b are added and then the result is returned.
For details, see Function Definition.
Integer
The integer types are classified into signed integer types and unsigned integer types.
The signed integer types include Int8, Int16, Int32, Int64, and IntNative, which are used to indicate the signed integer types with the encoding length of 8-bit, 16-bit, 32-bit, 64-bit, and platform-related size, respectively.
The unsigned integer types include UInt8, UInt16, UInt32, UInt64, and UIntNative, which are used to indicate the unsigned integer types whose encoding lengths are 8-bit, 16-bit, 32-bit, 64-bit, and platform-related size, respectively.
For the signed integer type whose encoding length is N, the representation range is $-2^{N-1} \sim 2^{N-1}-1$. For the unsigned integer type whose encoding length is N, the representation range is $0 \sim 2^{N}-1$. The following table lists the representation ranges for all integer types:
| Type | Representation Range |
|---|---|
| Int8 | $-2^7 \sim 2^7-1 (-128 \sim 127)$ |
| Int16 | $-2^{15} \sim 2^{15}-1 (-32,768 \sim 32,767)$ |
| Int32 | $-2^{31} \sim 2^{31}-1 (-2,147,483,648 \sim 2,147,483,647)$ |
| Int64 | $-2^{63} \sim 2^{63}-1 (-9,223,372,036,854,775,808 \sim 9,223,372,036,854,775,807)$ |
| IntNative | platform dependent |
| UInt8 | $0 \sim 2^8-1 (0 \sim 255)$ |
| UInt16 | $0 \sim 2^{16}-1 (0 \sim 65,535)$ |
| UInt32 | $0 \sim 2^{32}-1 (0 \sim 4,294,967,295)$ |
| UInt64 | $0 \sim 2^{64}-1 (0 \sim 18,446,744,073,709,551,615)$ |
| UIntNative | platform dependent |
The integer type used by a program depends on the property and range of the integer that needs to be processed in the program. If the Int64 type is appropriate, the Int64 type is used preferentially because the representation range of the Int64 type is large enough. In addition, the type of Literals of the Integer Type is inferred as the Int64 type by default when there is no type context, avoiding unnecessary type conversion.
Literals of the Integer Type
An integer literal can be expressed using four number notations: binary (using the 0b or 0B prefix), octal (using the 0o or 0O prefix), decimal (without a prefix), and hexadecimal (using the 0x or 0X prefix). For example, the decimal number 24 can be represented as 0b00011000 (or 0B00011000) in binary notation, 0o30 (or 0O30) in octal notation, and 0x18 (or 0X18) in hexadecimal notation.
In each number notation, the underscore _ can be used as a separator to identify the number of digits in a value, for example, 0b0001_1000.
If the value of a literal of the integer type exceeds the representation range of the integer type required by the context, the compiler reports an error.
let x: Int8 = 128 // Error, 128 out of the range of Int8
let y: UInt8 = 256 // Error, 256 out of the range of UInt8
let z: Int32 = 0x8000_0000 // Error, 0x8000_0000 out of the range of Int32
When an integer literal is used, a suffix can be added to specify the type of the integer literal. The correspondences between suffixes and types are as follows:
| Suffix | Type | Suffix | Type |
|---|---|---|---|
| i8 | Int8 | u8 | UInt8 |
| i16 | Int16 | u16 | UInt16 |
| i32 | Int32 | u32 | UInt32 |
| i64 | Int64 | u64 | UInt64 |
Integer literals with suffixes can be used as follows:
var x = 100i8 // x is 100 with type Int8
var y = 0x10u64 // y is 16 with type UInt64
var z = 0o432i32 // z is 282 with type Int32
Character Byte Literals
The Cangjie programming language supports character byte literals, so that ASCII codes can be used to represent values of the UInt8 type. A character byte literal consists of the character b, a pair of single quotation marks identifying the beginning and end, and an ASCII character. The following shows examples:
var a = b'x' // a is 120 with type UInt8
var b = b'\n' // b is 10 with type UInt8
var c = b'\u{78}' // c is 120 with type UInt8
b'x' indicates a literal of the UInt8 type whose value is 120. In addition, b'\u{78}' (with an escape character) can be used to represent a literal value whose type is UInt8 and whose value is 0x78 in hexadecimal notation or 120 in decimal notation. Note that \u contains a maximum of two hexadecimal digits and the value must be less than 256 (decimal notation).
Operations Supported by the Integer Type
By default, the following operators are supported by the integer type: arithmetic operators, bitwise operators, relational operators, increment operators, decrement operators, assignment operators, and compound assignment operators. For details about the priorities of operators, see Operators in the appendix.
-
Arithmetic operators include the unary minus sign (
-), addition sign (+), subtraction sign (-), multiplication sign (*), division sign (/), modulo sign (%), and exponentiation sign (**).-
Except the unary minus sign (
-) and exponentiation sign (**), other operators require that the left and right operands be of the same type. -
The operands of
*,/,+, and-can be of the integer or floating point type. -
The operands of
%can only be integers. -
The left operand of
**must be of theInt64orFloat64type.- When the left operand is of the
Int64type, the right operand must be of theUInt64type, and the expression type must beInt64. - When the left operand is of the
Float64type, the right operand must be of theInt64orFloat64type, and the expression type must beFloat64.
- When the left operand is of the
The following are examples of the exponentiation operation:
let p1 = 2 ** 3 // p1 = 8 let p2 = 2 ** UInt64(3 ** 2) // p2 = 512 let p3 = 2.0 ** 3.0 // p3 = 8.0 let p4 = 2.0 ** 3 ** 2 // p4 = 512.0 let p5 = 2.0 ** 3.0 // p5 = 8.0 let p6 = 2.0 ** 3.0 ** 2.0 // p6 = 512.0 -
-
Bitwise operators include bitwise NOT (
!), left shift (<<), right shift (>>), bitwise AND (&), bitwise XOR (^), and bitwise OR (|). Note that the bitwise AND, bitwise XOR, and bitwise OR operators require that the left and right operands be of the same integer type. -
Relational operators include less than (
<), greater than (>), less than or equal to (<=), greater than or equal to (>=), equal to (==), and not equal to (!=). The left and right operands of a relational operator must be of the same integer type. -
The increment and decrement operators include increment (
++) and decrement (--). Note that the increment and decrement operators in Cangjie can be used only as unary suffix operators. -
The assignment operator is
=. Compound assignment operators include+=,-=,*=,/=,%=,**=,<<=,>>=,&=,^=, and|=.
Conversions are possible between integer types, as well as between integer types and floating-point types. Integer types can also be converted to character types. For details about the conversion syntax and rules, see Conversions Between Numeric Types.
Note:
The operations supported by a certain type mentioned in this section refer to the operations without Operator Overloading.
Floating Point
The floating-point types, denoted by Float16, Float32, and Float64, can be used to represent floating-point numbers (i.e., numbers with a decimal point, such as 3.14159, 8.24, and 0.1). The encoding sizes are 16-bit, 32-bit, and 64-bit, which correspond respectively to the half-precision (binary16), single-precision (binary32), and double-precision (binary64) formats in IEEE 754 standard.
The precision of Float64 is to the 15th decimal place, Float32 to the 6th decimal place, and Float16 to the 3rd decimal place. The floating-point type to be used depends on the nature and range of the floating-point number. If multiple types are suitable, the floating-point type with higher precision is preferred, as low-precision types tend to accumulate greater calculation errors and their ability to accurately represent integers is limited.
Literals of the Floating Point Type
A literal of floating point type can be expressed in either decimal or hexadecimal notation. In decimal notation, a floating-point literal must contain either an integer or a decimal point number. If there is no decimal point, the literal must include an exponent part, with e or E as the prefix and 10 as the base. In hexadecimal notation, a floating-point literal must contain an integer or decimal point, with 0x or 0X as the prefix, and an exponent part with p or P as the prefix and 2 as the base.
The following example demonstrates the use of floating-point literals with different precision.
let a: Float32 = 3.14
let b: Float32 = 2e3
let c: Float32 = 2.4e-1
let d: Float64 = .123e2
let e: Float64 = 0x1.1p0
let f: Float64 = 0x1p2
let g: Float64 = 0x.2p4
When a decimal floating-point literal is used, a suffix can be added to specify the type of the floating-point literal. The correspondence between suffixes and types is as follows:
| Suffix | Type |
|---|---|
| f16 | Float16 |
| f32 | Float32 |
| f64 | Float64 |
Floating-point literals with suffixes can be used as follows:
let a = 3.14f32 // a is 3.14 with type Float32
let b = 2e3f32 // b is 2e3 with type Float32
let c = 2.4e-1f64 // c is 2.4e-1 with type Float64
let d = .123e2f64 // d is .123e2 with type Float64
Operations Supported by the Floating Point Type
By default, the floating point type supports the following operators: arithmetic, relational, assignment, and compound assignment. The floating point type does not support the increment and decrement operators.
Conversions are possible between floating-point types, as well as between floating-point types and integer types. For details about the conversion syntax and rules, see Conversions Between Numeric Types.
Boolean
The Boolean type, denoted by Bool, can be used to represent true or false in logic.
Literals of the Boolean Type
There are only two literals of the Boolean type: true and false.
The following example demonstrates the use of Boolean literals.
let a: Bool = true
let b: Bool = false
Operations Supported by the Boolean Type
The Boolean type supports the following operators: logical operators (logical NOT !, logical AND &&, and logical OR ||), relational operators (== and !=), assignment operators, and compound assignment operators (&&= and ||=).
Character
The character type, denoted by Rune, can be used to represent any character in the Unicode character set.
Literals of the Character Type
Literals of the character type can take one of three forms: single character, escape character, and universal character. A Rune literal begins with the character r, and is followed by a character enclosed in single or double quotation marks.
The following are examples of single character literals:
let a: Rune = r'a'
let b: Rune = r"b"
An escape character indicates that the subsequent character requires special interpretation. It is denoted by the symbol \, and is followed by the character to be interpreted. The following are examples of the use of escape character:
let slash: Rune = r'\\'
let newLine: Rune = r'\n'
let tab: Rune = r'\t'
A universal character begins with \u and is followed by one to eight hexadecimal digits enclosed in braces, representing the character corresponding to the Unicode value. The following example demonstrates the declaration of universal character literals:
main() {
let he: Rune = r'\u{4f60}'
let llo: Rune = r'\u{597d}'
print(he)
print(llo)
}
Compiling and executing the code above produces the following output:
Hello
Operations Supported by the Character Type
The character type supports only relational operators: less than (<), greater than (>), less than or equal to (<=), greater than or equal to (>=), equal to (==), and not equal to (!=). These operators compare the Unicode values of the characters.
Rune can be converted to UInt32, and integers can be converted to Rune. For details about the conversion syntax and rules, see Conversions from Rune to UInt32 and from Integers to Rune.
String
The string type, denoted by String, can be used to represent text data consisting of a sequence of Unicode characters.
String Literals
String literals are classified into three types: single-line, multi-line, and multi-line raw string literals.
The content of a single-line string literal is enclosed in either single or double quotation marks and must be written in a single line. It can be of any size and may contain any character (except for unescaped double quotation marks and standalone backslashes \). The following are examples of single-line string literals:
let s1: String = ""
let s2 = 'Hello Cangjie Lang'
let s3 = "\"Hello Cangjie Lang\""
let s4 = 'Hello Cangjie Lang\n'
A multi-line string literal must start and end with three double quotation marks (""") or three single quotation marks ('''). The literal content starts from the next first line following the three quotation marks at the beginning and continues until the first occurrence of three unescaped quotation marks. The content in between can be any number of characters, except for a single backslash (\). Unlike single-line string literals, multi-line string literals can span multiple lines. The following are examples of multi-line string literals:
let s1: String = """
"""
let s2 = '''
Hello,
Cangjie Lang'''
A multi-line raw string literal starts with one or more hash signs (#) followed by a single quotation mark (') or a double quotation mark ("), and ends with the same type of quotation mark (' or ") followed by the same number of hash signs (#). The number of hash signs and the type of quotation marks used at the beginning and end must match. If a multi-line raw string literal is not properly closed before the end of the file, a compilation error will be reported. The literal content may contain any characters. Like multi-line string literals, a multi-line raw string literal can span multiple lines. The key difference is that escape rules do not apply to multi-line raw string literals, and the content remains unchanged (escape sequences like \n will not be processed). In the following examples, \n in s2 is not interpreted as a newline character, but as the string \n, consisting of the backslash \ and n characters. The following are examples of multi-line raw string literals:
let s1: String = #""#
let s2 = ##'\n'##
let s3 = ###"
Hello,
Cangjie
Lang"###
For assignment operations of the form left = right, if the type of the left operand is Byte (an alias for the built-in type UInt8), and the right operand is a string literal representing an ASCII character, the string literal will be explicitly converted to the corresponding Byte value before the assignment. Similarly, if the type of the left operand is Rune, and the right operand is a single-character string literal, the string literal will be explicitly converted to the corresponding Rune value before the assignment. The following code is valid:
main() {
var b: Byte = "0"
print(b)
b = "1"
print(b)
var r: Rune = "0"
print(r)
r = "1"
print(r)
}
Compiling and executing the code above produces the following output:
484901
Interpolated String
An interpolated string is a string literal that contains one or more expressions within it (note that this does not apply to multi-line raw string literals). By embedding an expression directly into a string, we can avoid the need for string concatenation. Although this is the first time we are formally introducing interpolated strings, they have been shown in previous examples. For instance, we often output variable values of non-string types using the println function, as in println("${x}").
An interpolated expression must be enclosed in braces {} and prefixed with a dollar sign $. The contents inside {} can include one or more declarations or expressions.
When an interpolated string is evaluated, each interpolated expression is replaced by the value of the last item inside {}. The entire interpolated string remains a string.
The following is a simple example of an interpolated string:
main() {
let fruit = "apples"
let count = 10
let s = "There are ${count * count} ${fruit}"
println(s)
let r = 2.4
let area = "The area of a circle with radius ${r} is ${let PI = 3.141592; PI * r * r}"
println(area)
}
Compiling and executing the code above produces the following output:
There are 100 apples
The area of a circle with radius 2.400000 is 18.095570
Operations Supported by the String Type
Strings can be compared using relational operators and concatenated with the + operator. The following example demonstrates string equality checks and string concatenation:
main() {
let s1 = "abc"
var s2 = "ABC"
let r1 = s1 == s2
println("The result of 'abc' == 'ABC' is: ${r1}")
let r2 = s1 + s2
println("The result of 'abc' + 'ABC' is: ${r2}")
}
Compiling and executing the code above produces the following output:
The result of 'abc' == 'ABC' is: false
The result of 'abc' + 'ABC' is: abcABC
Strings also support other common operations, such as splitting and replacing text.
Tuple
A tuple can combine multiple (and possibly different) types to form a new composite type. The tuple type is represented as (T1, T2, ..., TN), where T1, T2, ..., TN can be any type. The types within the tuple type are separated by commas (,) and must contain at least two elements. For example, (Int64, Float64) represents a tuple type with two elements (a pair), while (Int64, Float64, String) represents a tuple with three elements (a triplet).
The length of a tuple is fixed, meaning that once a tuple instance is defined, its length cannot be changed.
The tuple is an immutable type, meaning that once a tuple instance is defined, its content cannot be changed. The following example results in a compilation error:
var tuple = (true, false)
tuple[0] = false // Error, 'tuple element' cannot be assigned
Literals of the Tuple Type
A literal of the tuple type is represented as (e1, e2, ..., eN), where e1, ..., eN are expressions. The expressions within the tuple are separated by comma (,). In the following example, two variables are declared and initialized with tuple literals: variable x is a tuple of type (Int64, Float64) and variable y is a tuple of type (Int64, Float64, String).
let x: (Int64, Float64) = (3, 3.141592)
let y: (Int64, Float64, String) = (3, 3.141592, "PI")
The elements of a tuple can be accessed using their indices with the notation t[index], where t is a tuple, and index is a non-negative integer that is smaller than the length of the tuple.
If the index does not satisfy these conditions, a compilation error will be reported. In the following example, the first and second elements of the tuple pi are accessed using pi[0] and pi[1] respectively.
main() {
var pi = (3.14, "PI")
println(pi[0])
println(pi[1])
}
Compiling and executing the code above produces the following output:
3.140000
PI
In an assignment expression, a tuple literal can be used to deconstruct the value on the right-hand side of the expression. This requires a tuple literal on the left side of the assignment where all elements are lvalue expressions or other tuple literals. An lvalue is an expression on the left side of assignment operator that represents a variable and can store values. For more details, refer to the description of the assignment operation in the respective chapter. When a tuple literal contains an underscore (_), the value at the corresponding position on the right-hand side of the assignment is ignored. In other words, that value is not assigned to the left-hand side. The expression on the right-hand side of the assignment must be of the tuple type, and the type of each element in the tuple on the right must be a subtype of the corresponding element type on the left. In terms of evaluation order, the value of the expression on the right-hand side of the assignment is evaluated first, followed by the assignment of values to the left-hand side, from left to right. The following example demonstrates how tuples can be deconstructed:
var a: Int64
var b: String
var c: Unit
func f() { ((1, "abc"), ()) }
((a, b), c) = f() // value of a is 1, value of b is "abc", value of c is '()'
((a, b), _) = ((2, "def"), 3.0) // value of a is 2, value of b is "def", 3.0 is ignored
Type Parameters of a Tuple
The fields of a tuple can be named as shown in the following example. Function getFruitPrice returns a tuple in which the first element is named name and the second element is named price.
func getFruitPrice (): (name: String, price: Int64) {
return ("banana", 10)
}
Additionally, either all type parameters must be specified, or none at all. The following example results in a compilation error:
let c: (name: String, Int64) = ("banana", 5) // Error
Array
Array
The Array type can be used to represent ordered sequences of elements of a single type. It is denoted as Array<T>, where T represents the type of the array elements. T can be any type. The following example demonstrates how array types can be used.
var a: Array<Int64> = ... // Array whose element type is Int64
var b: Array<String> = ... // Array whose element type is String
If the element type of one array differs from that of another array, they are considered to be of different types. Therefore, values cannot be assigned between them. The following example, where a and b are the arrays from the previous example, is invalid:
b = a // Type mismatch
Arrays can be initialized using literals which consist of a comma-separated list of values enclosed in square brackets.
The compiler can automatically infer the type of an array literal based on its context. For example:
let a: Array<String> = [] // Created an empty Array whose element type is String
let b = [1, 2, 3, 3, 2, 1] // Created an Array whose element type is Int64, containing elements 1, 2, 3, 3, 2, 1
An array of a specified type can also be created using the Array constructor.
Note that the constructor with the item parameter does not perform a deep copy of item. If item is a reference type, each element in the constructed array will point to the same reference.
let a = Array<Int64>() // Created an empty Array whose element type is Int64
let b = Array<Int64>(a) // Use another Array to initialize b
let c = Array<Int64>(3, item: 0) // Created an Array whose element type is Int64, length is 3 and all elements are initialized as 0
let d = Array<Int64>(3, {i => i + 1}) // Created an Array whose element type is Int64, length is 3 and all elements are initialized by the initialization function
In the example, let d = Array<Int64>(3, {i = > i + 1}) uses a [lambda expression] (../function/lambda.md) as the initialization function to initialize each element in the array, that is, {i = > i + 1}.
Accessing Array Members
A for-in loop can be used to iterate over each element of the array.
Array elements are arranged in the order in which they were inserted. Therefore, the order in which arrays are traversed is deterministic.
main() {
let arr = [0, 1, 2]
for (i in arr) {
println("The element is ${i}")
}
}
Compiling and executing the code above produces the following output:
The element is 0
The element is 1
The element is 2
The size property can be used to retrieve the number of elements in an array.
main() {
let arr = [0, 1, 2]
if (arr.size == 0) {
println("This is an empty array")
} else {
println("The size of array is ${arr.size}")
}
}
Compiling and executing the code above produces the following output:
The size of array is 3
The square bracket index operator ([]) can be used to access an element at a specified position (the index must be of type Int64). The first element of a non-empty array is at position 0, and the last element is at position size - 1, where size represents the number of elements in the array. The index value cannot be negative or greater than or equal to the size of the array. If an invalid index is detected during compilation, a compilation error is reported. If the index is invalid at runtime, an exception is thrown.
main() {
let arr = [0, 1, 2]
let a = arr[0] // a == 0
let b = arr[1] // b == 1
let c = arr[-1] // array size is '3', but access index is '-1', which would overflow
}
If you want to obtain a segment of an array, you can pass a value of type Range (more about the Range type in the next section) instead of an index to retrieve all the elements corresponding to that range at once.
let arr1 = [0, 1, 2, 3, 4, 5, 6]
let arr2 = arr1[0..5] // arr2 contains the elements 0, 1, 2, 3, 4
When a range literal is used, either the start or end value can be omitted. If the start is omitted, 0 is used by default. If the end is omitted, size - 1 is used by default.
let arr1 = [0, 1, 2, 3, 4, 5, 6]
let arr2 = arr1[..3] // arr2 contains elements 0, 1, 2
let arr3 = arr1[2..] // arr3 contains elements 2, 3, 4, 5, 6
Modifying an Array
An array is a collection type with a fixed length, meaning that its size cannot be changed after creation. As a result, arrays do not provide member functions for adding or removing elements.
Nonetheless, the elements in the array can be modified, using the index operator ([]). Consider the following example:
main() {
let arr = [0, 1, 2, 3, 4, 5]
arr[0] = 3
println("The first element is ${arr[0]}")
}
When compiled and executed, produces the following result:
The first element is 3
An array is a reference type, so no copies are made when it is used in an expression. All references to the same array instance share the same data. Therefore, modifying an array element affects all references to that instance.
let arr1 = [0, 1, 2]
let arr2 = arr1
arr2[0] = 3
// arr1 contains elements 3, 1, 2
// arr2 contains elements 3, 1, 2
VArray
In addition to the reference type Array, Cangjie also introduces the value type array VArray<T, $N>. T indicates the element type of the value type array. $N is a fixed syntax. The length of the value type array is represented by $ plus a literal of an Int64 value. Note that <T, $N> cannot be omitted in VArray<T, $N>, and the VArray keyword and its generic parameters cannot be split when a type alias is used.
Compared to frequently using the reference type Array, using the value type VArray can reduce the pressure of memory allocation and garbage collection on the heap. Note that the copy of the value type during passing and assignment causes extra performance overhead. Therefore, you are advised not to use a long VArray in performance-sensitive scenarios. For details about the features of the value type and reference type, see Value-type and Reference-type Variables.
type varr1 = VArray<Int64, $3> // Ok
type varr2 = VArray // Error
Note:
Due to backend restrictions, the element type
TofVArray<T, $N>, or any members ofT, cannot contain reference types, enumeration types, lambda expressions (exceptCFunc), or uninstantiated generic types.
VArray can be created with an array literal. In this case, the generic types of VArray must be specified by annotating the left-hand side with a type.
var a: VArray<Int64, $3> = [1, 2, 3]
VArray can also be created using its constructors. The following example demonstrates two of the available constructors of VArray.
// VArray<T, $N>(initElement: (Int64) -> T)
let b = VArray<Int64, $5>({ i => i}) // [0, 1, 2, 3, 4]
// VArray<T, $N>(item!: T)
let c = VArray<Int64, $5>(item: 0) // [0, 0, 0, 0, 0]
VArray provides [] and size methods:
-
The index operator
[]can be used to access and modify elements as follows:var a: VArray<Int64, $3> = [1, 2, 3] let i = a[1] // i is 2 a[2] = 4 // a is [1, 2, 4]The index value must be of type
Int64. -
The
sizeproperty can be used to obtain the number of elements in theVArrayas follows:var a: VArray<Int64, $3> = [1, 2, 3] let s = a.size // s is 3The type of the value returned by size is
Int64.
In addition, VArray also supports interoperability between Cangjie and C language. For details, see Array.
Range
A range is used to represent a sequence with a fixed step and is denoted by Range<T>. T can be any type that supports relational operators and addition with values of type Int64. Instantiating T in Range<T> with different types results in distinct range types. For example, Range<Int64> (the most commonly used) represents an integer range.
Instances of a range Range<T> contain three values: start, end, and step. Both start and end are of type T and represent the start and end values of the sequence, respectively. Step is of type Int64, must be non-zero, and represents the difference between adjacent elements in the sequence.
The following example declares three instances of Range<Int64>. For details about the definition and attributes of the range type, see Cangjie Programming Language Library API.
// Range<T>(start: T, end: T, step: Int64, hasStart: Bool, hasEnd: Bool, isClosed: Bool)
let r1 = Range<Int64>(0, 10, 1, true, true, true) // r1 contains 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
let r2 = Range<Int64>(0, 10, 1, true, true, false) // r2 contains 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
let r3 = Range<Int64>(10, 0, -2, true, true, false) // r3 contains 10, 8, 6, 4, 2
Literals of the Range Type
There are two types of literals for the range type: left-closed and right-open ranges, and left-closed and right-closed ranges.
- The format of a left-closed and right-open range is
start..end : step, which represents a range starting fromstartand ending atend(excludingend), with a step ofstep. - The format of a left-closed and right-closed range is
start..=end : step, which represents a range starting fromstartand ending atend(includingend), with a step ofstep.
The following example demonstrates the use of both right-open and right-closed range types.
let n = 10
let r1 = 0..10 : 1 // r1 contains 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
let r2 = 0..=n : 1 // r2 contains 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
let r3 = n..0 : -2 // r3 contains 10, 8, 6, 4, 2
let r4 = 10..=0 : -2 // r4 contains 10, 8, 6, 4, 2, 0
In a range literal, the step value can be omitted, in which case it defaults to 1. Note that the value of step cannot be 0. In addition, a range may be empty (i.e., an empty sequence that does not contain any elements). Both of these situations are shown in the following example.
let r5 = 0..10 // the step of r5 is 1, and it contains 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
let r6 = 0..10 : 0 // Error, step cannot be 0
let r7 = 10..0 : 1 // r7 to r10 are empty ranges
let r8 = 0..10 : -1
let r9 = 10..=0 : 1
let r10 = 0..=10 : -1
Note:
- In the expression
start..end : step, whenstep > 0andstart >= end, orstep < 0andstart <= end,start..end : stepis an empty range.- In the expression
start..=end : step, whenstep > 0andstart > end, orstep < 0andstart < end,start..=end : stepis an empty range.
Unit
The type of an expression that performs only side effects and does not produce a meaningful value is Unit. For example, the type of the print function, assignment expression, compound assignment expression, increment expression, decrement expression, and loop expression is Unit.
The Unit type has only one value, represented as (). Only assignment, equality, and inequality operations are allowed on values of type Unit.
Nothing
Nothing is a special type that contains no values, and it is a subtype of all other types.
The type of the break, continue, return, and throw expressions is Nothing. These expressions alter the control flow of execution, and as a result, the code that follows them is not executed. The break and continue statements can only be used within the body of a loop, while the return statement can only be used within the body of a function.
while (true) {
func f() {
break // Error, break must be used directly inside a loop
}
let g = { =>
continue // Error, continue must be used directly inside a loop
}
}
Since the formal parameters and default values of a function are not part of the function body, the return expression in the following example is not part of the function body that surrounds it. It does not belong to the outer function f (since the inner function g has already begun its definition) nor is it part of the body of the inner function g.
func f() {
func g(x!: Int64 = return) { // Error, return must be used inside a function body
0
}
1
}
Note:
Currently, the compiler does not allow the Nothing type to be explicitly used.
Function Definition
In Cangjie, the func keyword indicates the start of a function definition. func is followed, by the function name, parameter list, an optional return value type, and the function body, in this order. Any valid identifier can be a function name. The parameter list is a comma (,) separated list enclosed in parentheses (). If the return value type is present, it is separated from the parameter list with a colon (:). The function body is enclosed in braces ({}).
The following is an example of function definition:
func add(a: Int64, b: Int64): Int64 {
return a + b
}
The preceding example defines a function named add. The parameter list consists of the two parameters a and b of type Int64. The return value type is also Int64. The function body returns the result of adding together a and b.
Below is a further description of the parameter list, return value type, and function body in a function definition.
Parameter List
A function can have zero or more parameters, which are defined in the parameter list. Parameters in the parameter list are classified into non-named parameters and named parameters, based on whether their names need to be specified when the function is called.
A non-named parameter is defined by writing p: T, where p indicates the parameter name and T indicates the parameter type. A colon (:) separates the parameter name and type. In the example above, the two parameters a and b of the add function are non-named parameters.
A named parameter is defined by writing p!: T. Unlike non-named parameters, an exclamation mark (!) is added after p (parameter name). The two non-named parameters of the add function in the preceding example can be made named parameters as follows:
func add(a!: Int64, b!: Int64): Int64 {
return a + b
}
A named parameter may have a default value. For example, writing p!: T = e sets the default value of p to the value of the expression e. In the following example, the default values of the two parameters of the add function are both set to 1:
func add(a!: Int64 = 1, b!: Int64 = 1): Int64 {
return a + b
}
Note:
Only named parameters may have default values.
A parameter list may contain both named and non-named parameters. Note that all non-named parameters must appear before named parameters. In the following example, the parameter list definition of the add function is invalid:
func add(a!: Int64, b: Int64): Int64 { // Error, named parameter 'a' must be defined after non-named parameter 'b'
return a + b
}
The main difference between named and non-named parameters concerns the function call syntax. For more details, see Function Call.
Function parameters are immutable variables and therefore cannot be assigned to in the function body.
func add(a: Int64, b: Int64): Int64 {
a = a + b // Error
return a
}
The scope of a function parameter starts from its definition and ends with the function body.
func add(a: Int64, b: Int64): Int64 {
var a_ = a // OK
var b = b // Error, redefinition of declaration 'b'
return a
}
Return Value Type
The return value type of a function is the type of the value obtained from calling the function. An explicit return value type may be optionally specified in the function definition, and appears between the parameter list and function body. The compiler automatically determines the return value type if it is not specified in the function declaration.
When the return value type of a function is explicitly defined, the function body type or the type of e in all return e statements in the function body must be a subtype of the return value type. For details about how to determine the function body type, see Function Body. In the preceding example, the return value type of the add function is explicitly defined as Int64. If return a + b in the function body is changed to return (a, b), an error is reported due to type mismatch.
// Error, the type of the expression after return does not match the return type of the function
func add(a: Int64, b: Int64): Int64 {
return (a, b)
}
If the return value type is not explicitly defined, the compiler will deduce it based on both the type and return statements of the function body. In the following example, although the return value type of the add function is omitted, the compiler can still deduce that the return value type is Int64 based on the statement return a + b:
func add(a: Int64, b: Int64) {
return a + b
}
Note:
The return value types of functions cannot be deduced sometimes. If the return value type of a function fails to be deduced, the compiler reports an error.
If the return value type is defined as Unit, the compiler automatically inserts the expression return () where a value is possibly returned in the function body so that the return value type of the function is always Unit.
Function Body
A function body contains the operations to be performed when a function is called. It usually includes a number of variable definitions and expressions. It can also contain new function definitions (that is, nested functions). In the following example, the body of the add function defines the r variable of type Int64 (with an initial value of 0), assigns the value of a + b to r, and then returns the value of r:
func add(a: Int64, b: Int64) {
var r = 0
r = a + b
return r
}
A return statement can appear anywhere in a function body to terminate the execution of the function and return a result. A return statement can be in two forms: return and return expr (where expr indicates an expression).
For the form return expr, the type of expr must be a subtype of the return value type specified in the function definition. In the following example, an error is reported because the type of 100 (Int64) in return 100 differs from the return value type (String) of the function foo:
// Error, cannot convert an integer literal to type 'Struct-String'
func foo(): String {
return 100
}
When writing return, which is equivalent to return (), the return value type of a function must be Unit.
func add(a: Int64, b: Int64) {
var r = 0
r = a + b
return r
}
func foo(): Unit {
add(1, 2)
return
}
Note:
The type of a
returnstatement as a whole isNothinginstead of an expression that follows it.
A variable defined in a function body is a local variable (such as the r variable in the preceding example). Its scope starts from the definition and ends with the function body.
A local variable may have the same name as other variables that are defined outer scopes. In this case, using the shared name in the function body refers to the local variable, as shown in the example below.
let r = 0
func add(a: Int64, b: Int64) {
var r = 0
r = a + b
return r
}
In the add function, the global variable r of type Int64 is defined in the outer scope, and the local variable r is defined in the function body. In the body of add, the name r refers to the local variable and not the global one.
As mentioned in Return Value Type, the function body also has a type. The function body type is the type of the last item in the function body. If the last item is an expression, the function body type is the expression type. If the last item is a variable definition or function declaration, or the function body is empty, the function body type is Unit. The following is an example:
func add(a: Int64, b: Int64): Int64 {
a + b
}
In the preceding example, the last item in the function body is an expression of the Int64 type (a + b). Therefore, the function body type is also Int64, which matches the return value type in the function definition. In the following example, the last item in the function body is a call to the function print. Therefore, the function body type is Unit, which matches the return value type in the function definition.
func foo(): Unit {
let s = "Hello"
print(s)
}
Function Call
A function call has the form f(arg1, arg2, ..., argn). f indicates the name of the function to be called. arg1 to argn are the arguments used in the function call. The type of each argument must be a subtype of the corresponding parameter type. There can be zero or more arguments. When there are no arguments, a function call has the form f().
The way arguments are passed in function calling depends on whether parameters in the function definition are named or non-named parameters. The argument of a non-named parameter is an expression. The argument of a named parameter must be in the form p: e, where p is the parameter name and e is an expression (that is, value passed to p).
The following is an example of non-named parameters usage in a function call:
func add(a: Int64, b: Int64) {
return a + b
}
main() {
let x = 1
let y = 2
let r = add(x, y)
println("The sum of x and y is ${r}")
}
The execution result is as follows:
The sum of x and y is 3
The following is an example of named parameters usage in a function call:
func add(a: Int64, b!: Int64) {
return a + b
}
main() {
let x = 1
let y = 2
let r = add(x, b: y)
println("The sum of x and y is ${r}")
}
The execution result is as follows:
The sum of x and y is 3
If there are multiple named parameters, they can be passed in an order that differs from the order of these parameters in the function definition. In the following example, b can appear before a when the add function is called:
func add(a!: Int64, b!: Int64) {
return a + b
}
main() {
let x = 1
let y = 2
let r = add(b: y, a: x)
println("The sum of x and y is ${r}")
}
The execution result is as follows:
The sum of x and y is 3
If a named parameter that has a default value is omitted in a function call, that default value is used as the argument. In the following example, if no argument is passed to the b parameter when the add function is called, the default value 2 is used as the argument of b:
func add(a: Int64, b!: Int64 = 2) {
return a + b
}
main() {
let x = 1
let r = add(x)
println("The sum of x and y is ${r}")
}
The execution result is as follows:
The sum of x and y is 3
Alternatively, if a named parameter that has a default value is supplied with a value in a function call, then that value is used as the argument and not the default value. In the following example, the value 20 is passed to the b parameter when the add function is called, and therefore the value of b is 20:
func add(a: Int64, b!: Int64 = 2) {
return a + b
}
main() {
let x = 1
let r = add(x, b: 20)
println("The sum of x and y is ${r}")
}
The execution result is as follows:
The sum of x and y is 21
Function Type
In Cangjie, a function is a first-class citizen. It can be used as a parameter or return value of a function and assigned to a variable. Therefore, the function type can be defined.
The function type consists of the parameter type and return type, which are connected using ->. The parameter type is enclosed in parentheses (()). There can be no or multiple parameters. If there are more than one parameter, parameter types are separated by commas (,).
The following is an example:
func hello(): Unit {
println("Hello!")
}
The preceding example defines a function named hello whose function type is () -> Unit, indicating that the function has no parameter and its return type is Unit.
The following are some other examples:
-
This example defines a function named
displaywhose function type is(Int64) -> Unit, indicating that the function has a parameter of theInt64type and its return type isUnit.func display(a: Int64): Unit { println(a) } -
This example defines a function named
addwhose function type is(Int64, Int64) -> Int64, indicating that the function has two parameters of theInt64type and its return type isInt64.func add(a: Int64, b: Int64): Int64 { a + b } -
This example defines a function named
returnTuplewhose function type is(Int64, Int64) -> (Int64, Int64), indicating that the function has two parameters of theInt64type, and its return type is the tuple(Int64, Int64).func returnTuple(a: Int64, b: Int64): (Int64, Int64) { (a, b) }
Type Parameter
You can use explicit type parameter names in the function type, such as the name and price in the following example:
func showFruitPrice(name: String, price: Int64) {
println("fruit: ${name} price: ${price} yuan")
}
main() {
let fruitPriceHandler: (name: String, price: Int64) -> Unit
fruitPriceHandler = showFruitPrice
fruitPriceHandler("banana", 10)
}
In addition, you need to specify either all type parameter names or no type parameter names in the function type.
let handler: (name: String, Int64) -> Int64 // Error
Function Type as a Parameter Type
For example, if the type of the printAdd function is ((Int64, Int64) -> Int64, Int64, Int64) -> Unit, the function has three parameters, among which one is of the (Int64, Int64) -> Int64 type and two are of the Int64 type, and its return type is Unit.
func printAdd(add: (Int64, Int64) -> Int64, a: Int64, b: Int64): Unit {
println(add(a, b))
}
Function Type as a Return Type
A function type can be used as the return type of another function.
In the following example, the type of the returnAdd function is () -> (Int64, Int64) -> Int64, indicating that the function has no parameter, and its return type is (Int64, Int64) -> Int64: Note that -> is right associative.
func add(a: Int64, b: Int64): Int64 {
a + b
}
func returnAdd(): (Int64, Int64) -> Int64 {
add
}
main() {
var a = returnAdd()
println(a(1,2))
}
Function Type as a Variable Type
If the name of a function is an expression, its type is the function type of the expression.
func add(p1: Int64, p2: Int64): Int64 {
p1 + p2
}
let f: (Int64, Int64) -> Int64 = add
In the preceding example, the type of the add function is (Int64, Int64) -> Int64, the type of the f variable is the same as that of add, and add is used to initialize f.
If a function is overloaded in the current scope (for details, see Function Overloading), using its function name as an expression may cause ambiguity, which may result in an error reported by the compiler. The following is an example:
func add(i: Int64, j: Int64) {
i + j
}
func add(i: Float64, j: Float64) {
i + j
}
main() {
var f = add // Error, ambiguous function 'add'
var plus: (Int64, Int64) -> Int64 = add // OK
}
Nested Function
A function defined at the top layer of a source file is called a global function. A function defined in a function body is called a nested function.
In the following example, the nested function nestAdd is defined in the foo function, and therefore nestAdd can be called inside foo, or it can be returned as a return value and called outside foo:
func foo() {
func nestAdd(a: Int64, b: Int64) {
a + b + 3
}
println(nestAdd(1, 2)) // 6
return nestAdd
}
main() {
let f = foo()
let x = f(1, 2)
println("result: ${x}")
}
The result is as follows:
6
result: 6
Lambda Expression
Definition
The syntax of a lambda expression is { p1: T1, ..., pn: Tn => expressions | declarations }.
The content before => is a parameter list. Multiple parameters are separated by commas (,). The parameter name and parameter type are separated by colons (:). There can be no parameter before =>. In addition, => is followed by the lambda expression body, which is a group of expressions or declarations. Similar to a function, the scope of the parameter name of the lambda expression is the lambda expression function body. The scope level can be considered as the same as that of a variable defined in the function body of the lambda expression.
let f1 = { a: Int64, b: Int64 => a + b }
var display = { => // Parameterless lambda expression.
println("Hello")
println("World")
}
=> cannot be omitted in a lambda expression regardless of whether the expression has parameters, unless it is used as the trailing lambda. The following is an example:
var display = { => println("Hello") }
func f2(lam: () -> Unit) { }
let f2Res = f2{ println("World") } // OK to omit the =>
The type annotation of a parameter can be omitted in a lambda expression. In the following cases, if the parameter type is omitted, the compiler attempts to infer the type. If the compiler cannot infer the type, a compilation error is reported:
- When a lambda expression is assigned to a variable, its parameter type is inferred based on the variable type.
- When a lambda expression is used as the argument of a function call expression, its parameter type is inferred based on the parameter type of the function.
// The parameter types are inferred from the type of the variable sum1
var sum1: (Int64, Int64) -> Int64 = { a, b => a + b }
var sum2: (Int64, Int64) -> Int64 = { a: Int64, b => a + b }
func f(a1: (Int64) -> Int64): Int64 {
a1(1)
}
main(): Int64 {
// The parameter type of lambda is inferred from the type of function f
f({ a2 => a2 + 10 })
}
A lambda expression does not support the declaration of the return type. The return type is always inferred from the context. If the return type cannot be inferred, an error is reported.
-
If the return type of a lambda expression is explicitly specified in the context, its return type is the type specified in the context.
-
When a lambda expression is assigned to a variable, its return type is determined based on the variable type.
let f: () -> Unit = { ... } -
When a lambda expression is used as a parameter, its return type is inferred based on the parameter type of the function call where the lambda expression is used.
func f(a1: (Int64) -> Int64): Int64 { a1(1) } main(): Int64 { f({ a2: Int64 => a2 + 10 }) } -
When a lambda expression is used as a return value, its return type is inferred based on the return type of the function where the lambda expression is used.
func f(): (Int64) -> Int64 { { a: Int64 => a } }
-
-
If the type is not specified in the context, the compiler deduces the return type of a lambda expression based on the type of xxx in all return expressions
return xxxin the lambda expression body and the type of the lambda expression body.-
Similar to a common function body, the return type of the content on the right of
=>isInt64.let sum1 = { a: Int64, b: Int64 => a + b } -
If the content on the right of
=>is empty, the return type isUnit.let f = { => }
-
Lambda Expression Call
A lambda expression can be called immediately. The following is an example:
let r1 = { a: Int64, b: Int64 => a + b }(1, 2) // r1 = 3
let r2 = { => 123 }() // r2 = 123
A lambda expression can also be assigned to a variable and called using the variable name. The following is an example:
func f() {
var g = { x: Int64 => println("x = ${x}") }
g(2)
}
Closure
When a function or lambda expression captures a variable from the static scope that defines it, the function or lambda expression and the captured variable form a closure. The closure can run properly even if it is out of the scope where the closure definition is located.
Variable capture refers to any of the following scenarios where a variable is accessed in the definition of a function or lambda expression:
-
A local variable defined outside a function is accessed in the default value of a parameter in the function.
-
A local variable defined outside a function or lambda expression is accessed in the function or lambda expression.
-
An instance member variable or
thisis accessed in a function or lambda expression, which is defined insideclassorstructand is not a member function.
Variable access in the following cases is not variable capture:
-
A local variable defined inside a function or lambda expression is accessed in the function or lambda expression.
-
A parameter of a function or lambda expression is accessed in the function or lambda expression.
-
A global variable or static member variable is accessed.
-
An instance member variable is accessed in an instance member function or attribute. Because the instance member function or attribute passes
thisas a parameter, all instance member variables are accessed throughthisin the instance member function or attribute.
A variable is captured when a closure is defined. Therefore, the rules for capturing a variable are as follows:
-
A captured variable must be visible when a closure is defined. Otherwise, an error is reported during compilation.
-
A captured variable must have been initialized when a closure is defined. Otherwise, an error is reported during compilation.
Example 1: The add closure captures the num local variable declared by let and returns a value outside the scope defined by num. When add is called, num can still be accessed.
func returnAddNum(): (Int64) -> Int64 {
let num: Int64 = 10
func add(a: Int64) {
return a + num
}
add
}
main() {
let f = returnAddNum()
println(f(10))
}
The result is as follows:
20
Example 2: A captured variable must be visible when a closure is defined.
func f() {
let x = 99
func f1() {
println(x)
}
let f2 = { =>
println(y) // Error, cannot capture 'y' which is not defined yet
}
let y = 88
f1() // Print 99.
f2()
}
Example 3: A captured variable must have been initialized before a closure is defined.
func f() {
let x: Int64
func f1() {
println(x) // Error, x is not initialized yet.
}
x = 99
f1()
}
If the captured variable is of the reference type, you can change the value of its mutable instance member variable.
class C {
public var num: Int64 = 0
}
func returnIncrementer(): () -> Unit {
let c: C = C()
func incrementer() {
c.num++
}
incrementer
}
main() {
let f = returnIncrementer()
f() // c.num increases by 1
}
Closures that capture variables declared by var can only be called and cannot be used as first-class citizens to prevent escaping closures, including not being assigned to variables, not being used as arguments or return values, and the names of these closures not being directly used as expressions.
func f() {
var x = 1
let y = 2
func g() {
println(x) // OK, captured a mutable variable.
}
let b = g // Error, g cannot be assigned to a variable
g // Error, g cannot be used as an expression
g() // OK, g can be invoked
g // Error, g cannot be used as a return value.
}
Note that capturing is transitive. If the f function calls the g function that captures the var variable which is not defined inside the f function, the f function also captures the var variable and cannot be used as a first-class citizen either.
In the following example, g captures the x variable declared by var, f calls g, and x captured by g is not defined inside f. In this case, f cannot be used as a first-class citizen either.
func h(){
var x = 1
func g() { x } // captured a mutable variable
func f() {
g() // invoked g
}
return f // Error
}
In the following example, g captures the x variable declared by var, and f calls g. However, x captured by g is defined inside f, and f does not capture other variables declared by var. Therefore, f is still used as a first-class citizen.
func h(){
func f() {
var x = 1
func g() { x } // captured a mutable variable
g()
}
return f // Ok
}
Accessing a static member variable or global variable is not a variable capture. Therefore, a global variable, a function of a static member variable, or a lambda expression modified by var can still be used as a first-class citizen.
class C {
static public var a: Int32 = 0
static public func foo() {
a++ // OK
return a
}
}
var globalV1 = 0
func countGlobalV1() {
globalV1++
C.a = 99
let g = C.foo // OK
}
func g(){
let f = countGlobalV1 // OK
f()
}
Syntactic Sugar in a Function Call
Trailing Lambda
The trailing lambda makes a function call look like the built-in syntax of the language, increasing the extensibility of the language.
When the last parameter of a function is the function type, and the argument corresponding to the function call is lambda, you can use the trailing lambda syntax to place lambda outside the parentheses () at the end of the function call.
The following example defines a myIf function whose first parameter is of the Bool type and second parameter is the function type. When the value of the first parameter is true, the value of the second parameter is returned. Otherwise, 0 is returned. myIf can be called in the same way as a common function or in trailing lambda mode.
func myIf(a: Bool, fn: () -> Int64) {
if(a) {
fn()
} else {
0
}
}
func test() {
myIf(true, { => 100 }) // General function call
myIf(true) { // Trailing closure call
100
}
}
If a function call has only one lambda as an argument, you can omit () and write only lambda.
Example:
func f(fn: (Int64) -> Int64) { fn(1) }
func test() {
f { i => i * i }
}
Flow Expressions
There are two types of flow operators: |> infix operator (called pipeline) that represents the data flow direction and ~> infix operator (called composition) that represents a combination of functions.
Pipeline Expressions
When you need to process the input data, you can use a pipeline expression to simplify the description. The syntax of the pipeline expression is e1 |> e2. It is equivalent to the syntax sugar in the following format: let v = e1; e2(v).
e2 is the expression of the function type, and the type of e1 is the subtype of the parameter type of e2.
Example:
func inc(x: Array<Int64>): Array<Int64> { // Increasing the value of each element in the array by '1'
let s = x.size
var i = 0
for (e in x where i < s) {
x[i] = e + 1
i++
}
x
}
func sum(y: Array<Int64>): Int64 { // Get the sum of elements in the array.
var s = 0
for (j in y) {
s += j
}
s
}
let arr: Array<Int64> = Array<Int64>([1, 3, 5])
let res = arr |> inc |> sum // res = 12
Composition Expressions
A composition expression indicates a combination of two single-parameter functions. The syntax of the composition expression is f ~> g. It is equivalent to { x => g(f(x)) }.
f or g is the expression of the function type with only one parameter.
If f and g are combined, the return type of f(x) must be the subtype of the parameter type of g(...).
Example 1:
func f(x: Int64): Float64 {
Float64(x)
}
func g(x: Float64): Float64 {
x
}
var fg = f ~> g // The same as { x: Int64 => g(f(x)) }
Example 2:
func f(x: Int64): Float64 {
Float64(x)
}
let lambdaComp = ({x: Int64 => x}) ~> f // The same as { x: Int64 => f({x: Int64 => x}(x)) }
Example 3:
func h1<T>(x: T): T { x }
func h2<T>(x: T): T { x }
var hh = h1<Int64> ~> h2<Int64> // The same as { x: Int64 => h2<Int64>(h1<Int64>(x)) }
Note:
In the expression f ~> g, f is evaluated first, then g is evaluated, and finally the functions are combined.
In addition, flow operators and named parameter functions with no default values cannot be used together directly. This is because named parameter functions with no default values can be called only after the arguments of the named parameters are provided. The following is an example:
func f(a!: Int64): Unit {}
var a = 1 |> f // Error
If necessary, you can use a lambda expression to pass the argument of the named parameter of the f function.
func f(a!: Int64): Unit {}
var x = 1 |> { x: Int64 => f(a: x) } // Ok
Likewise, when the parameter of f has a default value, it is incorrect to use it together with a flow operator. The following is an example:
func f(a!: Int64 = 2): Unit {}
var a = 1 |> f // Error
However, when all named parameters have default values, a function can be called even though the arguments of the named parameters are not provided. Only non-named parameters need to be passed. Flow operators and functions that meet the preceding requirements can be used together. The following is an example:
func f(a: Int64, b!: Int64 = 2): Unit {}
var a = 1 |> f // Ok
If you want to pass other parameters to the parameter b when calling f, you also need to use a lambda expression.
func f(a: Int64, b!: Int64 = 2): Unit {}
var a = 1 |> {x: Int64 => f(x, b: 3)} // Ok
Variable-Length Parameters
A variable-length parameter is special syntactic sugar in a function call. When the last non-named parameter of a parameter is of the Array type, a sequence of parameters can be directly passed to the position of the corresponding argument to replace the Array literal (there can be no or multiple parameters). The following is an example:
func sum(arr: Array<Int64>) {
var total = 0
for (x in arr) {
total += x
}
return total
}
main() {
println(sum())
println(sum(1, 2, 3))
}
The result is as follows:
0
6
Note that only the last non-named parameter can be used as a variable-length parameter. This syntax sugar is not supported for named parameters.
func length(arr!: Array<Int64>) {
return arr.size
}
main() {
println(length()) // Error, expected 1 argument, found 0
println(length(1, 2, 3)) // Error, expected 1 argument, found 3
}
Variable-length parameters can be used in global functions, static member functions, instance member functions, local functions, constructors, function variables, lambda expressions, overloaded function call operators, and overloaded index operator function calls. They are not supported for the function calls of composition, pipeline, and other overloaded operators. The following is an example:
class Counter {
var total = 0
init(data: Array<Int64>) { total = data.size }
operator func ()(data: Array<Int64>) { total += data.size }
}
main() {
let counter = Counter(1, 2)
println(counter.total)
counter(3, 4, 5)
println(counter.total)
}
The result is as follows:
2
5
The function overloading resolution always preferentially considers the functions that can be matched without using variable-length parameters. Variable-length parameters are used for parsing only when no function can be matched. The following is an example:
func f<T>(x: T) where T <: ToString {
println("item: ${x}")
}
func f(arr: Array<Int64>) {
println("array: ${arr}")
}
main() {
f()
f(1)
f(1, 2)
}
The result is as follows:
array: []
item: 1
array: [1, 2]
If the compiler cannot make a resolution, the following error is reported:
func f(arr: Array<Int64>) { arr.size }
func f(first: Int64, arr: Array<Int64>) { first + arr.size }
main() {
println(f(1, 2, 3)) // Error
}
Function Overloading
Definition
In Cangjie, function overloading refers to the situation where a function name corresponds to multiple function definitions in a scope.
-
Overloaded functions have the same name but differ in the number or type of their parameters. The following is an example:
// Scenario 1 func f(a: Int64): Unit { } func f(a: Float64): Unit { } func f(a: Int64, b: Float64): Unit { } -
When two generic functions have the same name, all the generic parameters of one of themn are renamed to be the same as the other. If the parameter types of the resulting functions are different (including the renamed generic types as well as any non-generic types), then they are overloaded functions. Otherwise, a duplicate definition error is reported (constraints of type variables are not taken into account). The following is an example:
interface I1{} interface I2{} func f1<X, Y>(a: X, b: Y) {} func f1<Y, X>(a: X, b: Y) {} // Ok: after renaming generic type parameters, it will be 'func f1<X, Y>(a: Y, b: X)' func f2<T>(a: T) where T <: I1 {} func f2<T>(a: T) where T <: I2 {} // Error, not overloading -
If two constructors in the same class have different parameters, they are overloaded constructors. The following is an example:
// Scenario 2 class C { var a: Int64 var b: Float64 public init(a: Int64, b: Float64) { this.a = a this.b = b } public init(a: Int64) { b = 0.0 this.a = a } } -
If a primary constructor and the
initconstructor in the same class have different parameters, they are overloaded constructors (the primary constructor and theinitconstructor are considered to have the same name). The following is an example:// Scenario 3 class C { C(var a!: Int64, var b!: Float64) { this.a = a this.b = b } public init(a: Int64) { b = 0.0 this.a = a } } -
Two functions defined in different scopes can be overloaded in a scope that is visible to both of them. The following is an example:
// Scenario 4 func f(a: Int64): Unit { } func g() { func f(a: Float64): Unit { } } -
Two functions defined in a parent class and a child class respectively can be overloaded in a scope that is visible to both of them. The following is an example:
// Scenario 5 open class Base { public func f(a: Int64): Unit { } } class Sub <: Base { public func f(a: Float64): Unit { } }
Only function declarations are allowed to introduce overloading, with the following exceptions:
- In a class, interface, enum or struct type, a member function cannot have both static and non-static overloads.
- In an enum type, a constructor and a member function (static or non-static) cannot be overloaded.
Variable declarations cannot introduce function overloading, even if they are of function type, so declaring multiple variables with the same name in the same scope is not allowed. In the following example, two variables with the same name are functions with different parameter types, but they are not introduced by function declarations. Therefore, they cannot be overloaded and a compilation error (redefinition error) is reported.
main() {
var f: (Int64) -> Unit
var f: (Float64) -> Unit
}
In the following example, although the variable f is of function type, a compilation error (redefinition error) is reported because a variable and a function cannot have the same name:
main() {
var f: (Int64) -> Unit
func f(a: Float64): Unit { // Error, functions and variables cannot have the same name.
}
}
In the following example, although the f static member function and the f instance member function have different parameter types, a compilation error is reported because a static member function and an instance member function in the same class cannot be overloaded:
class C {
public static func f(a: Int64): Unit {
}
public func f(a: Float64): Unit {
}
}
Function Overloading Resolution
When encountering a function call, all functions that can be called (functions that are visible in the current scope and can pass the type check) form a candidate set. As there may be multiple functions in the candidate set, function overloading resolution is required to select a function from it. The rules are as follows:
-
A function in a higher-level scope is preferred. In functions with nested expressions or functions, the inner scopes are of higher level.
In the following example, when
g(Sub())is called in the function body ofinner, the candidate set includesgdefined ininnerandgdefined outsideinner. The definition ofgininneris selected during function resolution because it is in a higher-level scope.open class Base {} class Sub <: Base {} func outer() { func g(a: Sub) { print("1") } func inner() { func g(a: Base) { print("2") } g(Sub()) // Output: 2 } } -
If there are still multiple functions in a higher-level scope, the most specific function is selected. Assume that there are functions f and g and given arguments. If g can be called when f is called but the reverse is not true, f is a more specific function than g. If there is no unique function that is most specific, an error is reported.
In the following example, the two functions both named
gare defined in the same scope, and the more specific functiong(a: Sub): Unitis selected:open class Base {} class Sub <: Base {} func outer() { func g(a: Sub) { print("1") } func g(a: Base) { print("2") } g(Sub()) // Output: 1 } -
Child classes and parent classes are considered to be in the same scope. In the following example, a function
gis defined in the parent class, and another functiongis defined in the child class. Whens.g(Sub())is called, the two functionsgare considered to be in the same scope during resolution, and the better matched functiong(a: Sub): Unitdefined in the parent class is selected.open class Base { public func g(a: Sub) { print("1") } } class Sub <: Base { public func g(a: Base) { print("2") } } func outer() { let s: Sub = Sub() s.g(Sub()) // Output: 1 }
Operator Overloading
Operator overloading enables you to allow a type to support an operator that is not supported by this type by default.
To overload an operator for a type, you must define a member function named after the operator. In this way, when the operator is called with an instance of this type, the operator function is automatically called.
The definition of an operator function is similar to that of a normal function. The differences are as follows:
- When defining an operator function, add the
operatormodifier before thefunckeyword. - The number of parameters of an operator function must meet the requirements of the corresponding operator. For details, see Operators in the appendix.
- An operator function can be defined only in class, interface, struct, enum, and extend.
- An operator function has the semantics of an instance member function. Therefore, the
staticmodifier cannot be used. - An operator function cannot be a generic function.
Note that the inherent priority and associativity of an operator is not changed after it is overloaded. For details, see Operators in the appendix.
Definition and Usage of Operator Functions
You can define operator functions in either of the following ways:
- For types that can directly contain function definitions (including
struct,enum,class, andinterface), operator functions can be added in the type definition. - Use
extendto add operator functions to types so that operators can be overloaded for them. For types that cannot directly contain function definitions (types other thanstruct,class,enum, andinterface) or whose implementation cannot be changed, such asstruct,class,enum, andinterfacedefined by third parties, only this method can be used. For details, see Extension Overview.
The conventions on parameter types for operator functions are as follows:
-
For unary operators, operator functions have no parameter, and there is no requirement on the return value type.
-
For binary operators, operator functions have only one parameter, and there is no requirement on the return value type.
The following examples show how to define and use unary and binary operators.
-is used to negate both member variablesxandyin aPointinstance, returning a newPointobject.+is used to add up the values of the two member variablesxandyrespectively in twoPointinstances, returning a newPointobject.open class Point { var x: Int64 = 0 var y: Int64 = 0 public init (a: Int64, b: Int64) { x = a y = b } public operator func -(): Point { Point(-x, -y) } public operator func +(right: Point): Point { Point(this.x + right.x, this.y + right.y) } }Then, the
-unary operator and the+binary operator can be used directly forPointinstances.main() { let p1 = Point(8, 24) let p2 = -p1 // p2 = Point(-8, -24) let p3 = p1 + p2 // p3 = Point(0, 0) } -
Index operators (
[]) have two forms:let a = arr[i](for obtaining a value) andarr[i] = a(for assigning a value). They can be distinguished based on whether they contain the special named parameter value. Index operator overloading does not require that both forms be used at a time. You can use either one as required.In the expression
let a = arr[i, j, k...], the sequencei, j, k...is used as the parameters of the overloaded operator[]. Named parameters are not allowed. The parameter types of this form of the index operator, as well as the return type, are unrestricted.class A { operator func [](arg1: Int64, arg2: String): Int64 { return 0 } } func f() { let a = A() let b: Int64 = a[1, "2"] // b == 0 }In
arr[i, j, k...] = a, the sequencei, j, k...is used as the parameters of the overloaded operator[], and the expressionaon the right of=is passed as a special named parameter. This named parameter can have any type, but its name must be value and it is not allowed to specify a default value. The return type of the assignment operator[]must be Unit.Note that the use of the named value parameter is only as a marker and one does not need to pass it as a named parameter when an index operator is used to assign a value.
class A { operator func [](arg1: Int64, arg2: String, value!: Int64): Unit { return } } func f() { let a = A() a[1, "2"] = 0 }Immutable types except
enumcannot overload index assignmentarr[i] = a. The compiler will report an error if the user provides an overload of index assignment in an immutable type other thanenum. -
When the function call operator
()is overloaded, the input parameters and return value can be of any type. The following is an example:open class A { public init() {} public operator func ()(): Unit {} } func test1() { let a = A() // Ok, A() calls the constructor of A. a() // Ok, a() is to call the operator () overloading function. }The overloaded
()operator cannot be called usingthisorsuper. The following is an example:open class A { public init() {} public init(x: Int64) { this() // Ok, this() calls the constructor of A. } public operator func ()(): Unit {} public func foo() { this() // Error, this() calls the constructor of A. super() // Error } } class B <: A { public init() { super() // Ok, super() calls the constructor of the super class. } public func goo() { super() // Error } }For
enumtypes, the constructor form has priority when a constructor and an overloaded()operator function are candidates. The following is an example:enum E { Y | X | X(Int64) public operator func ()(p: Int64) {} public operator func ()(p: Float64) {} } main() { let e = X(1) // Ok, X(1) is to call the constructor X(Int64). X(1.0) // Ok, X(1.0) is to call the operator () overloading function. let e1 = X e1(1) // Ok, e1(1) is to call the operator () overloading function. Y(1) // Ok, Y(1) is to call the operator () overloading function. }
Operators That Can Be Overloaded
The following table lists all operators that can be overloaded (in descending order of priority):
| Operator | Description |
|---|---|
() | Function call |
[] | Indexing |
! | NOT |
- | Negative |
** | Power |
* | Multiply |
/ | Divide |
% | Remainder |
+ | Add |
- | Subtract |
<< | Bitwise left shift |
>> | Bitwise right shift |
< | Less than |
<= | Less than or equal |
> | Greater than |
>= | Greater than or equal |
== | Equal |
!= | Not equal |
& | Bitwise AND |
^ | Bitwise XOR |
| | Bitwise OR |
Note:
- If a binary operator other than a relational operator (
<,<=,>,>=,==, or!=) is overloaded for a type, and the return type of the operator function is the same as the type of a left operand or its subtype, the type supports the corresponding compound assignment operator. If the return type of an operator function is different from the type of a left operand or its subtype, a type mismatch error is reported when the corresponding compound assignment operator is used. - Cangjie does not support custom operators. That is, only operators in the preceding table can be overloaded.
- If a type
Talready supports an overloaded operator, a redefinition error is reported when a new operator function with the same signature is implemented forTthrough an extension. For example, a redefinition error is reported when you overload an arithmetic operator, a bitwise operator, a relational operator, or other operators that are already supported by the number type with the same signature for the number type, when you overload a relational operator with the same signature for theRunetype, or when you overload a logical operator, the equal-to operator, or the not-equal-to operator with the same signature for theBooltype.
const Functions and Constant Evaluation
Constant evaluation allows some specific forms of expressions to be evaluated during compilation, reducing the calculations required during program execution. This section describes the usage and rules of constant evaluation.
const Variables
A const variable is a special variable that is introduced with the const keyword, which defines a variable that is evaluated during compilation and cannot be changed during execution. In the following example, the gravitational constant G is defined:
const G = 6.674e-11
The type annotation can be omitted for const variables, but the initialization expression cannot be omitted. A const variable can be a global variable, local variable, or static member variable. However, it cannot be defined in an extension. It can access all instance members and call all non-mut instance member functions of the corresponding type.
In the following example, a struct is defined to record the mass and radius of a planet, and a const member function gravity calculates the gravitational force of the planet on an object with a mass of m at a distance of r:
struct Planet {
const Planet(let mass: Float64, let radius: Float64) {}
const func gravity(m: Float64, r: Float64) {
G * mass * m / r**2
}
}
main() {
const myMass = 71.0
const earth = Planet(5.972e24, 6.378e6)
println(earth.gravity(myMass, earth.radius))
}
The gravitational force of the Earth on an adult with a mass of 71 kg on the ground is calculated during compilation.
695.657257
After a const variable is initialized, all of its instance members are considered const (transitively including all instance members reachable through it), and therefore cannot be assigned to.
main() {
const myMass = 71.0
myMass = 70.0 // Error, cannot assign to immutable value
}
const Context and const Expressions
The const context refers to initialization expressions of const variables, which are always evaluated during compilation. Only a restricted set of expressions are allowed in the const context to avoid side effects such as global state and I/O and to ensure that they can be evaluated during compilation.
const expressions are those that can be evaluated during compilation and therefore are allowed to appear in a const context. The following are const expressions:
- Literals of the numeric,
Bool,Unit,Rune, andStringtypes (excluding interpolated strings) Arrayliterals whose elements are allconstexpressions (the elements cannot be of theArraytype but can be of theVArraytype) andtupleliterals whose elements are allconstexpressionsconstvariables, parameters ofconstfunctions, and local variables ofconstfunctionsconstfunctions, including functions whose names are declared usingconst,lambdaexpressions that meet the requirements ofconstfunctions, and function expressions returned by these functions- calls to
constfunctions (includingconstconstructors) whose expressions and arguments are allconstexpressions - calls to
enumconstructors whose parameters are allconstexpressions, andenumconstructors without parameters - Arithmetic expressions, relational expressions, and bitwise operation expressions of the numeric,
Bool,Unit,Rune, andStringtypes, whose operands are allconstexpressions if,match,try,is, andasexpressions and control transfer expressions (includingreturn,break,continue, andthrow), whose sub-expressions are allconstexpressions- Member access expressions (excluding those for attribute access) and index access expressions of the
tupletype inconstexpressions thisandsuperexpressions inconst initandconstfunctions- Function calls of
constinstance member functions ofconstexpressions, where all arguments areconstexpressions
const Functions
A const function is a special function that can be evaluated during compilation. When called in a const context, it is evaluated during compilation. In non-const contexts, it is executed during program execution time the same as a normal function.
In the following example, the const function distance calculates the distance between two points on a plane, using let to define two local variables dx and dy:
struct Point {
const Point(let x: Float64, let y: Float64) {}
}
const func distance(a: Point, b: Point) {
let dx = a.x - b.x
let dy = a.y - b.y
(dx**2 + dy**2)**0.5
}
main() {
const a = Point(3.0, 0.0)
const b = Point(0.0, 4.0)
const d = distance(a, b)
println(d)
}
The result is as follows:
5.000000
Note:
- The declaration of a
constfunction must be modified byconst. - Global
constandstatic constfunctions can only access those external variables that are declared byconst, including globalconstvariables and staticconstmember variables.const initfunctions andconstinstance member functions can access the external variables declared byconstas well as the instance member variables of the current type. - All expressions in
constfunctions exceptconst initfunctions must beconstexpressions. - In
constfunctions,letandconstcan be used to declare new local variables. However,varis not supported. - There are no special requirements on parameter types and return types in
constfunctions. If the actual parameter of a function call does not meet the requirements of aconstexpression, the function call cannot be used as aconstexpression, but can still be used as a common expression. constfunctions are not necessarily executed during compilation. For example, they can be called in non-constfunctions during running.- The overloading rules of
constfunctions are the same as those of non-constfunctions. - The numeric,
Bool,Unit,Rune,String, andenumtypes can be used to defineconstinstance member functions. - For
structandclass,constinstance member functions can be defined only afterconst initis defined.constinstance member functions inclasscannot beopen.constinstance member functions instructcannot bemut.
In addition, const functions can be defined in APIs. The rules are as follows:
- The implementation type of a
constfunction in an API must also be aconstfunction. - For a non-
constfunction in an API, the implementation type can be aconstor non-constfunction. - Similar to a
staticfunction, aconstfunction in an API can be used by constrained generic variables only when the API is used as a generic constraint.
In the following example, two const functions are defined in the I API implemented by the A class, and the upper bound of the parameter type of the generic function g is I:
interface I {
const func f(): Int64
const static func f2(): Int64
}
class A <: I {
public const func f() { 0 }
public const static func f2() { 1 }
const init() {}
}
const func g<T>(i: T) where T <: I {
return i.f() + T.f2()
}
main() {
println(g(A()))
}
The result is as follows:
1
const init Functions
If a struct or class defines a const constructor, the struct or class instance can be used in a const expression.
- For
classtypes, aconst initfunction can only be defined if there are novarmember variables. If the current type has a parent class, anyconst initfunctions in it must call aconst initfunction of the parent class (explicitly or implicitly if aconst initfunction without parameters is available). If the parent class does not have aconst initfunction, an error is reported. - If an instance member variable of the current type has an initial value, the initial value must be a
constexpression. Otherwise, aconst initfunction cannot be defined. - Only assignment expressions can be used to assign values to instance member variables in a
const initfunction.
The difference between const init functions and const functions is that values can be assigned to instance member variables in const init functions (assignment expressions are required).
Defining a struct Type
The definition of a struct type starts with the keyword struct, followed by the struct name and the struct definition body defined in braces. The struct definition body can define a series of member variables, member properties (see Properties), static initializers, constructors, and member functions.
struct Rectangle {
let width: Int64
let height: Int64
public init(width: Int64, height: Int64) {
this.width = width
this.height = height
}
public func area() {
width * height
}
}
The preceding example defines a struct type named Rectangle. It has two member variables width and height of the Int64 type, a constructor with two parameters of the Int64 type (with the constructor defined by the keyword init, and the member variables initialized in the function body), as well as a member function area (returning the product of width and height).
Note:
structcan be defined only on top of a source file.
struct Member Variables
struct member variables can be grouped into instance member variables and static member variables (modified by static modifiers and must have initial values). The difference lies in that instance member variables can be accessed only through struct instances (If a is an instance of the T type, a is a value of the T type), whereas static member variables can be accessed only through the struct type names.
When you define instance member variables, you are not required to set initial values but must specify the types, such as width and height in the preceding example. However, you can also set initial values as follows:
struct Rectangle {
let width = 10
let height = 20
}
struct Static Initializers
struct allows you to define a static initializer and initialize static member variables with assignment expressions in the static initializer.
A static initializer starts with static init, followed by a parameter list without parameters and a function body. It cannot be modified by an access modifier. All static member variables must be initialized in the function body. Otherwise, an error is reported during compilation.
struct Rectangle {
static let degree: Int64
static init() {
degree = 180
}
}
A struct defines a maximum of one static initializer. In other cases, a redefinition error is reported.
struct Rectangle {
static let degree: Int64
static init() {
degree = 180
}
static init() { // Error, redefinition with the previous static init function
degree = 180
}
}
struct Constructors
struct supports two types of constructors: common constructors and primary constructors.
A common constructor starts with the keyword init, followed by the parameter list and function body. All instance member variables must be initialized in the function body. Otherwise, an error is reported during compilation. If a member variable name cannot be distinguished from a parameter name, you can add this before the member variable name to indicate the current instance of the struct.
struct Rectangle {
let width: Int64
let height: Int64
public init(width: Int64, height: Int64) { // Error, 'height' is not initialized in the constructor
this.width = width
}
}
A struct can define multiple common constructors, but they must be overloaded (see Function Overloading). Otherwise, a redefinition error is reported.
struct Rectangle {
let width: Int64
let height: Int64
public init(width: Int64) {
this.width = width
this.height = width
}
public init(width: Int64, height: Int64) { // Ok: overloading with the first init function
this.width = width
this.height = height
}
public init(height: Int64) { // Error, redefinition with the first init function
this.width = height
this.height = height
}
}
In addition to defining several common constructors named init, a struct can also define a maximum of one primary constructor. The primary constructor has the same name as the struct type. The parameter list of the primary constructor can contain two types of parameters: common parameters and member variable parameters (with let or var added before the parameter names). Member variable parameters define member variables and constructor parameters.
The definition of a struct can be simplified by using a primary constructor. For example, the Rectangle struct that contains an init constructor can be simplified as follows:
struct Rectangle {
public Rectangle(let width: Int64, let height: Int64) {}
}
Common parameters can also be defined in the parameter list of a primary constructor. For example:
struct Rectangle {
public Rectangle(name: String, let width: Int64, let height: Int64) {}
}
If the definition of a struct does not contain a custom constructor (including the primary constructor) and all instance member variables have initial values, a parameterless constructor is automatically generated (Calling the parameterless constructor creates an object whose instance member variable values equal to their initial values). Otherwise, the parameterless constructor is not automatically generated. The following struct definition displays an automatically generated parameterless constructor:
struct Rectangle {
let width: Int64 = 10
let height: Int64 = 10
/* Auto-generated memberwise constructor:
public init() {
}
*/
}
struct Member Functions
struct member functions are classified into instance member functions and static member functions (modified by the static modifier). The difference lies in that the former can be accessed only through struct instances, whereas the latter can be accessed only through struct type names. Static member functions cannot access instance member variables or call instance member functions. In contrast, instance member functions can access static member variables and static member functions.
In the following example, area and typeName are an instance member function and a static member function, respectively.
struct Rectangle {
let width: Int64 = 10
let height: Int64 = 20
public func area() {
this.width * this.height
}
public static func typeName(): String {
"Rectangle"
}
}
An instance member function can access its member variables through this. For example:
struct Rectangle {
let width: Int64 = 1
let height: Int64 = 1
public func area() {
this.width * this.height
}
}
Access Modifiers of a struct Member
The members of a struct (including member variables, member properties, constructors, member functions, and operator functions (see Operator Overloading)) are modified by four access modifiers: private, internal (default), protected, and public.
private: A member is visible only in a definedstruct.internal: A member is visible only in a package and its subpackages (including all nested subpackages). For details, see Package.protected: A member is visible only in a module. For details, see Package.public: A member is visible both inside and outside the module.
In the following example, width is modified by public and can be accessed outside the class. height is modified by the default access modifier and is visible only in the package and its subpackages.
package a
public struct Rectangle {
public var width: Int64
var height: Int64
private var area: Int64
...
}
func samePkgFunc() {
var r = Rectangle(10, 20)
r.width = 8 // Ok: public 'width' can be accessed here
r.height = 24 // Ok: 'height' has no modifier and can be accessed here
r.area = 30 // Error, private 'area' can't be accessed here
}
package b
import a.*
main() {
var r = Rectangle(10, 20)
r.width = 8 // Ok: public 'width' can be accessed here
r.height = 24 // Error, no modifier 'height' can't be accessed here
r.area = 30 // Error, private 'area' can't be accessed here
}
Disabling Recursive structs
Both recursive and mutually recursive structs are invalid. For example:
struct R1 { // Error, 'R1' recursively references itself
let other: R1
}
struct R2 { // Error, 'R2' and 'R3' are mutually recursive
let other: R3
}
struct R3 { // Error, 'R2' and 'R3' are mutually recursive
let other: R2
}
Creating a struct Instance
After defining the struct type, you can create a struct instance by calling the constructor of struct. You can also call the constructor by the struct type name outside the struct definition. The following example defines an r variable of the Rectangle type.
let r = Rectangle(10, 20)
After the struct instance is created, you can access its member variables (modified by public) and member functions through it. In the following example, r.width and r.height can be used to access the values of width and height in r, and r.area() can be used to call the member function area of r.
let r = Rectangle(10, 20)
let width = r.width // width = 10
let height = r.height // height = 20
let a = r.area() // a = 200
If you want to change the value of a member variable through a struct instance, use var to define both the variables of the struct type and the modified member variables as mutable variables. For example:
struct Rectangle {
public var width: Int64
public var height: Int64
public init(width: Int64, height: Int64) {
this.width = width
this.height = height
}
public func area() {
width * height
}
}
main() {
var r = Rectangle(10, 20) // r.width = 10, r.height = 20
r.width = 8 // r.width = 8
r.height = 24 // r.height = 24
let a = r.area() // a = 192
}
When a value is assigned or a parameter is passed, the struct instance is copied to generate a new instance. The modification of one instance does not affect the other. As described in the following example, after r1 is assigned to r2, changing the values of width and height in r1 does not affect those in r2.
struct Rectangle {
public var width: Int64
public var height: Int64
public init(width: Int64, height: Int64) {
this.width = width
this.height = height
}
public func area() {
width * height
}
}
main() {
var r1 = Rectangle(10, 20) // r1.width = 10, r1.height = 20
var r2 = r1 // r2.width = 10, r2.height = 20
r1.width = 8 // r1.width = 8
r1.height = 24 // r1.height = 24
let a1 = r1.area() // a1 = 192
let a2 = r2.area() // a2 = 200
}
mut Function
A struct is a value type whose instance member functions cannot modify the instance. In the following example, the value of the member variable i cannot be changed by the member function g:
struct Foo {
var i = 0
public func g() {
i += 1 // Error, the value of an instance member variable cannot be modified in an instance member function
}
}
The mut function is a special instance member function that can modify the struct instance. In the mut function, this contains special semantics that allows it to modify fields in place.
Note:
The
mutfunction can be defined only in an interface, struct, and struct extension. (A class is a reference type. Instance member functions can modify instance member variables without addingmut. Therefore, themutfunction cannot be defined in a class.)
Definition
Compared with common instance member functions, the mut function has an additional modifier mut.
In the following example, the mut modifier is added before the g function, which allows the value of the member variable i to be changed in the function body:
struct Foo {
var i = 0
public mut func g() {
i += 1 // Ok
}
}
mut can be used to modify instance member functions only.
struct A {
public mut func f(): Unit {} // Ok
public mut operator func +(rhs: A): A { // Ok
A()
}
public mut static func g(): Unit {} // Error, static member functions cannot be modified with 'mut'
}
this in the mut function cannot be captured or used as an expression. The instance member variables of a struct cannot be captured in the mut function.
Example:
struct Foo {
var i = 0
public mut func f(): Foo {
let f1 = { => this } // Error, 'this' in mut functions cannot be captured
let f2 = { => this.i = 2 } // Error, instance member variables in mut functions cannot be captured
let f3 = { => this.i } // Error, instance member variables in mut functions cannot be captured
let f4 = { => i } // Error, instance member variables in mut functions cannot be captured
this // Error, 'this' in mut functions cannot be used as expressions
}
}
mut Function in Interfaces
Instance member functions in interfaces can also be modified by mut.
The struct type must be modified by the same mut modifier when implementing an interface function. When a type other than struct implements an interface function, the mut modifier cannot be used.
Example:
interface I {
mut func f1(): Unit
func f2(): Unit
}
struct A <: I {
public mut func f1(): Unit {} // Ok: as in the interface, the 'mut' modifier is used
public func f2(): Unit {} // Ok: as in the interface, the 'mut' modifier is not used
}
struct B <: I {
public func f1(): Unit {} // Error, 'f1' is modified with 'mut' in interface, but not in struct
public mut func f2(): Unit {} // Error, 'f2' is not modified with 'mut' in interface, but did in struct
}
class C <: I {
public func f1(): Unit {} // Ok
public func f2(): Unit {} // Ok
}
When a struct instance is assigned to an interface type, the copy semantics is used. Therefore, the mut function of the interface cannot change the value of the struct instance.
Example:
interface I {
mut func f(): Unit
}
struct Foo <: I {
public var v = 0
public mut func f(): Unit {
v += 1
}
}
main() {
var a = Foo()
var b: I = a
b.f() // Calling 'f' via 'b' cannot modify the value of 'a'
println(a.v) // 0
}
The program output is as follows:
0
Constraints on the mut Function
Since a struct is a value type, if a variable of the struct type is declared using let, the mut function of this type cannot be accessed through this variable.
Example:
interface I {
mut func f(): Unit
}
struct Foo <: I {
public var i = 0
public mut func f(): Unit {
i += 1
}
}
main() {
let a = Foo()
a.f() // Error, 'a' is of type struct and is declared with 'let', the 'mut' function cannot be accessed via 'a'
var b = Foo()
b.f() // Ok
let c: I = Foo()
c.f() // Ok
}
To avoid escape, if the type of a variable is struct, the variable cannot use functions modified by mut as the first-class citizens, but it can still call these mut functions.
Example:
interface I {
mut func f(): Unit
}
struct Foo <: I {
var i = 0
public mut func f(): Unit {
i += 1
}
}
main() {
var a = Foo()
var fn = a.f // Error, mut function 'f' of 'a' cannot be used as a first class citizen.
var b: I = Foo()
fn = b.f // Ok
}
To avoid escape, non-mut instance member functions (including lambda expressions) cannot directly access mut functions of the corresponding type, while the reverse is allowed.
Example:
struct Foo {
var i = 0
public mut func f(): Unit {
i += 1
g() // Ok
}
public func g(): Unit {
f() // Error, mut functions cannot be invoked in non-mut functions
}
}
interface I {
mut func f(): Unit {
g() // Ok
}
func g(): Unit {
f() // Error, mut functions cannot be invoked in non-mut functions
}
}
Enum
This section describes the enum type in Cangjie. The enum type provides a way to define a type by enumerating all possible values of the type.
Many programming languages feature an enum type (sometimes referred to as an enumerated type), but the usage and expressive capabilities of the enum type vary across languages. In Cangjie, the enum type may be understood as an algebraic data type in a functional programming language.
The following describes how to define and use enum types, how to use pattern matching to perform different operations when an enum is set to different values, and how to use a common enum type named Option to indicate that an instance of a type may or may not contain a value.
Defining an Enum
An enum type is defined by listing all possible values. These values are called the constructors of the enum type.
enum RGBColor {
| Red | Green | Blue
}
An enum definition starts with the keyword enum, followed by a type name, and then an enum body in braces. The enum body contains several constructors which are separated by | (the | before the first constructor is optional). In the preceding example, an enum type named RGBColor is defined. It has three constructors: Red, Green, and Blue, representing the colors in the RGB color model.
The constructors in the above enum can also carry one or more parameters, making them parameterized constructors. For example, you can set a parameter of the UInt8 type for Red, Green, and Blue to represent the brightness level of each color.
enum RGBColor {
| Red(UInt8) | Green(UInt8) | Blue(UInt8)
}
Cangjie allows multiple constructors with the same name within the same enum, provided the number of parameters is different (considering that a constructor with no parameters has a parameter count of 0). For example:
enum RGBColor {
| Red | Green | Blue
| Red(UInt8) | Green(UInt8) | Blue(UInt8)
}
enum definitions can be recursive. In the following example, enum is used to define a type of expressions (Expr). An expression can take only three forms: a single number Num (with a parameter of the Int64 type), an addition expression Add (with two parameters of the Expr type), or a subtraction expression Sub (with two parameters of the Expr type). The Add and Sub constructors recursively use Expr itself in their parameters.
enum Expr {
| Num(Int64)
| Add(Expr, Expr)
| Sub(Expr, Expr)
}
In addition, a series of member functions, operator functions (for details, see Operator Overloading), and member properties (for details, see Properties) can be defined in the enum body. However, the names of constructors, member functions, and member properties must be unique. For example, the following example defines a function named printType in RGBColor, which outputs the string RGBColor:
enum RGBColor {
| Red | Green | Blue
public static func printType() {
print("RGBColor")
}
}
Note:
enumdefinitions can only appear at the top level of a source file.- When there is a mutually recursive relationship between
enumandstructtypes, and theenumtype is used as a type parameter ofOption, compilation errors may occur.
Using an Enum
After defining an enum type, instances of it can be created through one of its constructors, either directly or qualifying it with the type name as TypeName.Constructor. Unlike struct and class types, an enum type name cannot be used as a constructor. For parameterized constructors, all the parameters must be provided.
In the following example, RGBColor defines three constructors: two without parameters (Red and Green) and one with a parameter (Blue(UInt8)). main defines three variables r, g, and b of the RGBColor type. The value of r is initialized using RGBColor.Red, the value of g is initialized using Green, and the value of b is initialized using Blue(100).
enum RGBColor {
| Red | Green | Blue(UInt8)
}
main() {
let r = RGBColor.Red
let g = Green
let b = Blue(100)
}
When the type name is omitted, the names of enum constructors may conflict with type names, variable names, or function names. In this case, you must add the enum type name to specify the enum constructor. Otherwise, only type, variable, and function definitions with the same name are used.
In the following example, only the constructor Blue(UInt8) can be used without the type name. Red and Green(UInt8) cannot be directly used due to name conflict and must be prefixed with the type name RGBColor.
let Red = 1
func Green(g: UInt8) {
return g
}
enum RGBColor {
| Red | Green(UInt8) | Blue(UInt8)
}
let r1 = Red // Will choose 'let Red'
let r2 = RGBColor.Red // Ok: constructed by enum type name
let g1 = Green(100) // Will choose 'func Green'
let g2 = RGBColor.Green(100) // Ok: constructed by enum type name
let b = Blue(100) // Ok: can be uniquely identified as an enum constructor
In the following example, only the constructor Blue cannot be directly used due to name conflicts and must be prefixed with the type name RGBColor.
class Blue {}
enum RGBColor {
| Red | Green(UInt8) | Blue(UInt8)
}
let r = Red // Ok: constructed by enum type name
let g = Green(100) // Ok: constructed by enum type name
let b = Blue(100) // Will choose constructor of 'class Blue' and report an error
Option Type
The Option type is defined using enum, which contains two constructors: Some and None. Some carries a parameter, indicating that there is a value. None carries no parameter, indicating that there is no value. The Option type can be used to indicates that a type may or may not have a value.
The Option type is defined as a generic enum type, as follows (note that the angle bracketed T is a type parameter, and different T types yield different Option types. For details about generics, see Overview:
enum Option<T> {
| Some(T)
| None
}
The parameter type of the Some constructor is the type parameter T. When T is instantiated into different types, different Option types are obtained, for example, Option<Int64> and Option<String>.
There is also a shorthand for the Option type: prefixing the type name with a ?. That is, for any type Ty, ?Ty is equivalent to Option<Ty>. For example, ?Int64 is equivalent to Option<Int64>, ?String is equivalent to Option<String>, and so on.
The following example shows how to define a variable of the Option type:
let a: Option<Int64> = Some(100)
let b: ?Int64 = Some(100)
let c: Option<String> = Some("Hello")
let d: ?String = None
In addition, although T and Option<T> are different types, if you know that a value of the Option<T> type is required at a certain position, you can directly provide a value of the T type. The compiler uses the Some constructor of the Option<T> type to encapsulate the value of the T type into a value of the Option<T> type. (Note: This is not a type conversion.) For example, the following definitions are valid (equivalent to the definitions of variables a, b, and c in the preceding example):
let a: Option<Int64> = 100
let b: ?Int64 = 100
let c: Option<String> = "100"
If the context does not have specific type requirements, None cannot be used to directly construct the required type. In this case, you should use the None<T> syntax to construct data of the Option<T> type. For example:
let a = None<Int64> // a: Option<Int64>
let b = None<Bool> // b: Option<Bool>
For details about how to use Option, see Using Options.
Pattern Overview
For match expressions that contain values to be matched, the patterns supported after case determine the expressiveness of the match expression. In this section, we will introduce the patterns supported by Cangjie, including: constant patterns, wildcard patterns, binding patterns, tuple patterns, type patterns, and enum patterns.
Constant Pattern
Constant patterns can be integer literals, floating-point literals, character literals, Boolean literals, string literals (string interpolation is not supported), and unit literals.
When a constant pattern is used in the match expression that contains a value to be matched, the type of the value represented by the constant pattern must be the same as that of the value to be matched. The matching is successful only when the value to be matched is equal to the value represented by the constant pattern.
In the following example, the exam score level is output based on the value of score (assuming score is an integer multiple of 10 ranging from 0 to 100):
main() {
let score = 90
let level = match (score) {
case 0 | 10 | 20 | 30 | 40 | 50 => "D"
case 60 => "C"
case 70 | 80 => "B"
case 90 | 100 => "A" // Matched.
case _ => "Not a valid score"
}
println(level)
}
The result is as follows:
A
-
When the target of pattern matching is a value whose static type is
Rune, both theRuneliteral and the single-character string literal can be used as constant patterns representingRuneliterals.func translate(n: Rune) { match (n) { case "A" => 1 case "B" => 2 case "C" => 3 case _ => -1 } } main() { println (translate (r"C")) }The result is as follows:
3 -
When the target of pattern matching is a value whose static type is
Byte, a string literal representing an ASCII character can be used as a constant pattern representing theByteliteral.func translate(n: Byte) { match (n) { case "1" => 1 case "2" => 2 case "3" => 3 case _ => -1 } } main() { println(translate(51)) // UInt32(r'3') == 51 }The result is as follows:
3
Wildcard Pattern
A wildcard pattern is represented by _ and can match any value. The wildcard pattern is typically used as a pattern in the last case to match situations not covered by other cases. In the example of matching the value of score in Constant Pattern, _ in the last case is used to match invalid score values.
Binding Pattern
A binding pattern is represented by id, which is a valid identifier. Similar to wildcard patterns, binding patterns can also match any value, but the matched value is bound to id, allowing access to its bound value after the =>.
In the following example, the binding pattern is used in the last case to bind a non-zero value:
main() {
let x = -10
let y = match (x) {
case 0 => "zero"
case n => "x is not zero and x = ${n}" // Matched.
}
println(y)
}
The result is as follows:
x is not zero and x = -10
When | is used to connect multiple patterns, the binding pattern cannot be used and cannot be nested in other patterns. Otherwise, an error is reported.
main() {
let opt = Some(0)
match (opt) {
case x | x => {} // Error, variable cannot be introduced in patterns connected by '|'
case Some(x) | Some(x) => {} // Error, variable cannot be introduced in patterns connected by '|'
case x: Int64 | x: String => {} // Error, variable cannot be introduced in patterns connected by '|'
}
}
The binding pattern id is equivalent to defining an immutable variable named id (whose scope starts from the introduction point to the end of the case). Therefore, the id cannot be modified after =>. In the following example, the modification of n in the last case is not allowed:
main() {
let x = -10
let y = match (x) {
case 0 => "zero"
case n => n = n + 0 // Error, 'n' cannot be modified.
"x is not zero"
}
println(y)
}
For each case branch, the scope level of variables after => is the same as that of variables introduced before =>. Introducing a variable with the same name again after => will trigger a redefinition error. Example:
main() {
let x = -10
let y = match (x) {
case 0 => "zero"
case n => let n = 0 // Error, redefinition
println(n)
"x is not zero"
}
println(y)
}
Note:
When the identifier of a pattern is an enum constructor, the pattern is matched as an enum pattern instead of a binding pattern. For details about the enum pattern, see Enum Pattern.
enum RGBColor {
| Red | Green | Blue
}
main() {
let x = Red
let y = match (x) {
case Red => "red" // The 'Red' is enum mode here.
case _ => "not red"
}
println(y)
}
The result is as follows:
red
Tuple Pattern
Tuple patterns are used to match tuple values, defined similarly to tuple literals: (p_1, p_2, ..., p_n), where p_1 to p_n (with n greater than or equal to 2) are patterns (which can be any pattern discussed in this chapter, separated by commas) rather than expressions.
For example, (1, 2, 3) is a tuple pattern that contains three constant patterns, while (x, y, _) is a tuple pattern that contains two binding patterns and one wildcard pattern.
If a tuple value tv and a tuple pattern tp are given, the tp can match the tv only when each value at the corresponding position in tv matches the pattern at that position in tp. For example, (1, 2, 3) can match only the tuple value (1, 2, 3), and (x, y, _) can match any three-element tuple value.
The following example shows how to use the tuple pattern:
main() {
let tv = ("Alice", 24)
let s = match (tv) {
case ("Bob", age) => "Bob is ${age} years old"
case ("Alice", age) => "Alice is ${age} years old" // Matched, "Alice" is a constant pattern, and 'age' is a variable pattern.
case (name, 100) => "${name} is 100 years old"
case (_, _) => "someone"
}
println(s)
}
The result is as follows:
Alice is 24 years old
Multiple binding patterns with the same name cannot be introduced to the same tuple pattern. In the following example, case (x, x) in the last case is invalid.
main() {
let tv = ("Alice", 24)
let s = match (tv) {
case ("Bob", age) => "Bob is ${age} years old"
case ("Alice", age) => "Alice is ${age} years old"
case (name, 100) => "${name} is 100 years old"
case (x, x) => "someone" // Error, Cannot introduce a variable pattern with the same name, which will be a redefinition error.
}
println(s)
}
Type Pattern
A type pattern is used to determine whether the runtime type of a value is a subtype of a specific type. There are two type patterns: _: Type (nesting a wildcard pattern _) and id: Type (nesting a binding pattern id). The difference is that the latter pattern will be bound to variables, while the former pattern will not.
For a value v to be matched and a type pattern id: Type (or _: Type), it is first determined whether a runtime type of v is a subtype of Type. If it is such subtype, the match is considered successful; otherwise, it is deemed a failure. If the match is successful, the type of v is converted to Type and bound to id (for _: Type, binding does not occur).
Assume that there are two classes: Base and Derived, where Derived is a subclass of Base. In the parameterless constructor of Base, a is set to 10. In the parameterless constructor of Derived, a is set to 20.
open class Base {
var a: Int64
public init() {
a = 10
}
}
class Derived <: Base {
public init() {
a = 20
}
}
The following code shows the successful use of a type pattern:
main() {
var d = Derived()
var r = match (d) {
case b: Base => b.a // Matched.
case _ => 0
}
println("r = ${r}")
}
The result is as follows:
r = 20
The following code shows a failed match using a type pattern:
open class Base {
var a: Int64
public init() {
a = 10
}
}
class Derived <: Base {
public init() {
a = 20
}
}
main() {
var b = Base()
var r = match (b) {
case d: Derived => d.a // Type pattern match failed.
case _ => 0 // Matched.
}
println("r = ${r}")
}
The result is as follows:
r = 0
Enum Pattern
Enum patterns are used to match instances of the enum type, defined similarly to the constructors of an enum: the C constructor without parameters or the C(p_1, p_2, ..., p_n) constructor with parameters, where the type prefix of the constructor can be omitted. The difference is that the p_1 to p_n (n is greater than or equal to 1) are patterns. For example, Some(1) is an enum pattern containing a constant pattern, and Some(x) is an enum pattern containing a binding pattern.
If an enum instance ev and an enum pattern ep are given, the ep can match the ev only when the constructor names of ev and ep are the same, and every value in the parameter list of ev matches the corresponding pattern in ep. For example, Some("one") can match only the Some constructor Option<String>.Some("one") of the Option<String> type, and Some(x) can match the Some constructor of any Option type.
The following example shows the use of the enum pattern. Because the constructor of x is Year, it matches the first case:
enum TimeUnit {
| Year(UInt64)
| Month(UInt64)
}
main() {
let x = Year(2)
let s = match (x) {
case Year(n) => "x has ${n * 12} months" // Matched.
case TimeUnit.Month(n) => "x has ${n} months"
}
println(s)
}
The result is as follows:
x has 24 months
Use | to connect multiple enum patterns.
enum TimeUnit {
| Year(UInt64)
| Month(UInt64)
}
main() {
let x = Year(2)
let s = match (x) {
case Year(0) | Year(1) | Month(_) => "Ok" // Ok
case Year(2) | Month(m) => "invalid" // Error, Variable cannot be introduced in patterns connected by '|'
case Year(n: UInt64) | Month(n: UInt64) => "invalid" // Error, Variable cannot be introduced in patterns connected by '|'
}
println(s)
}
When the match expression is used to match enum values, the patterns after case must cover all constructors of the enum type to be matched. If they are not fully covered, the compiler will raise an error.
enum RGBColor {
| Red | Green | Blue
}
main() {
let c = Green
let cs = match (c) { // Error, Not all constructors of RGBColor are covered.
case Red => "Red"
case Green => "Green"
}
println(cs)
}
To achieve full coverage, we can add case Blue, or we can use case _ at the end of the match expression to cover any unmatched cases.
enum RGBColor {
| Red | Green | Blue
}
main() {
let c = Blue
let cs = match (c) {
case Red => "Red"
case Green => "Green"
case _ => "Other" // Matched.
}
println(cs)
}
The execution result of the preceding code is as follows:
Other
Nested Combinations of Patterns
Tuple patterns and enum patterns can be nested with any patterns. The following code shows the use of different nested combinations:
enum TimeUnit {
| Year(UInt64)
| Month(UInt64)
}
enum Command {
| SetTimeUnit(TimeUnit)
| GetTimeUnit
| Quit
}
main() {
let command = SetTimeUnit(Year(2022))
match (command) {
case SetTimeUnit(Year(year)) => println("Set year ${year}")
case SetTimeUnit(Month(month)) => println("Set month ${month}")
case _ => ()
}
}
The result is as follows:
Set year 2022
Refutability of Patterns
There are two types of patterns: refutable and irrefutable. On the premise of type matching, when a pattern may not match the value to be matched, the pattern is referred to as a refutable pattern; on the contrary, when a pattern always matches the value, the pattern is referred to as an irrefutable pattern.
The patterns described above are specified as follows:
Constant patterns are refutable. In the following example, 1 in the first case and 2 in the second case may be different from the value of x.
func constPat(x: Int64) {
match (x) {
case 1 => "one"
case 2 => "two"
case _ => "_"
}
}
Wildcard patterns are irrefutable. In the following example, _ can always match the value of x.
func wildcardPat(x: Int64) {
match (x) {
case _ => "_"
}
}
Binding patterns are irrefutable. In the following example, the binding pattern a can always match the value of x.
func varPat(x: Int64) {
match (x) {
case a => "x = ${a}"
}
}
Tuple patterns are irrefutable only when each pattern contained in the tuple pattern is irrefutable. In the following example, (1, 2) and (a, 2) may not match the value of x. Therefore, they are refutable. (a, b) can match any value of x. Therefore, it is irrefutable.
func tuplePat(x: (Int64, Int64)) {
match (x) {
case (1, 2) => "(1, 2)"
case (a, 2) => "(${a}, 2)"
case (a, b) => "(${a}, ${b})"
}
}
Type patterns are refutable. In the following example (assuming that Base is the parent class of Derived and Base implements interface I), the runtime type of x may be neither Base nor Derived. Therefore, both a: Derived and b: Base are refutable.
interface I {}
open class Base <: I {}
class Derived <: Base {}
func typePat(x: I) {
match (x) {
case a: Derived => "Derived"
case b: Base => "Base"
case _ => "Other"
}
}
Enum patterns are irrefutable only when the corresponding enum type has only one constructor with parameters, and each pattern contained in the enum pattern is irrefutable. For the definitions of E1 and E2 in the following example, A(1) in the function enumPat1 is refutable, and A(a) is irrefutable; while B(b) and C(c) in the function enumPat2 are refutable.
enum E1 {
A(Int64)
}
enum E2 {
B(Int64) | C(Int64)
}
func enumPat1(x: E1) {
match (x) {
case A(1) => "A(1)"
case A(a) => "A(${a})"
}
}
func enumPat2(x: E2) {
match (x) {
case B(b) => "B(${b})"
case C(c) => "C(${c})"
}
}
match Expression
Definition
In Cangjie, a match expression may contain or not contain a value to be matched.
A match expression with a value is as follows:
main() {
let x = 0
match (x) {
case 1 => let r1 = "x = 1"
print(r1)
case 0 => let r2 = "x = 0" // Matched.
print(r2)
case _ => let r3 = "x != 1 and x != 0"
print(r3)
}
}
The match expression starts with the keyword match, followed by the value to be matched (for example, x in the preceding example, which can be any expression), and then several case branches defined in a pair of braces.
Each case branch starts with the keyword case, which is followed by one or multiple patterns of the same type connected by | (1, 0, and _ in the preceding example are patterns. For details, see Pattern Overview). A pattern can be followed by an optional pattern guard, indicating additional conditions that must be satisfied after the case is successfully matched. Then, there is a =>, followed by the operations to be executed if this case branch matches. The operations can be a series of expressions, variables, and function definitions (the scope of a newly defined variable or function starts from the definition and ends before the next case), for example, the variable definitions and print function calls in the preceding example.
During execution, the match expression sequentially matches the expression following match with the patterns in each case. Once a match is found (if there is a pattern guard, the expression following where must also evaluate to true; if there are multiple patterns connected by |, matching against any one of them counts as a successful match), the code following => is executed, and the execution of the match expression exits (meaning it will not match against any subsequent cases). If no match is found, it continues to match against the patterns in the following cases until a match is successful (the match expression guarantees that there will always be a matching case).
In the above example, since the value of x is 0, it will match with the second case branch (here, the constant pattern is used to check whether the values are the same. For details, see Constant Pattern), resulting in the output: x = 0.
Compile and execute the preceding code. The output is as follows:
x = 0
The match expression requires that all matches be exhaustive, which means that all possible values of the expression to be matched must be considered. If the match expression is not exhaustive or the compiler cannot determine whether the expression is exhaustive, a compilation error is reported. In other words, the union set of the value ranges covered by all case branches (including pattern guards) should contain all possible values of the expression to be matched. A common way to ensure that the match expression is exhaustive is to use the wildcard pattern _ in the last case branch, because _ can match any value.
The exhaustiveness of the match expression ensures that there must be a case branch that matches the value. In the following example, an error is reported during compilation because all cases do not cover all possible values of x:
func nonExhaustive(x: Int64) {
match (x) {
case 0 => print("x = 0")
case 1 => print("x = 1")
case 2 => print("x = 2")
}
}
After the patterns in the case branches, a pattern guard can be used to further evaluate the matched results. The pattern guard is represented by where cond. The expression cond must be of the Bool type.
In the following example (the enum pattern is used. For details, see Enum Pattern), when the parameter values of the RGBColor constructor are greater than or equal to 0, their values are printed. When the parameter values are less than 0, they are considered to be equal to 0.
enum RGBColor {
| Red(Int16) | Green(Int16) | Blue(Int16)
}
main() {
let c = RGBColor.Green(-100)
let cs = match (c) {
case Red(r) where r < 0 => "Red = 0"
case Red(r) => "Red = ${r}"
case Green(g) where g < 0 => "Green = 0" // Matched.
case Green(g) => "Green = ${g}"
case Blue(b) where b < 0 => "Blue = 0"
case Blue(b) => "Blue = ${b}"
}
print(cs)
}
The result is as follows:
Green = 0
A match expression without a value is as follows:
main() {
let x = -1
match {
case x > 0 => print("x > 0")
case x < 0 => print("x < 0") // Matched.
case _ => print("x = 0")
}
}
In contrast to a match expression with a value, there is no expression to match after the match keyword, and the cases do not contain patterns but rather expressions of the Bool type (such as x > 0 and x < 0 in the code above) or _ (which represents true). Additionally, there are no pattern guards in the cases.
When a match expression without a value is executed, the values of the expressions following case are checked in sequence until a case branch whose value is true is found. If the value of the expression following a case is true, the code following the => in that case is executed, and the execution of the match expression is exited (meaning it will not evaluate any subsequent cases).
In the preceding example, since the value of x is -1, the value of the expression (x < 0) in the second case branch is true. In this case, print("x < 0") is executed.
Compile and execute the preceding code. The output is as follows:
x < 0
Types of the match Expression
For match expressions (regardless of whether there is a value):
-
When there is a clear type requirement in the context, the type of the code block following
=>in eachcasebranch must be a subtype of the type required by the context. -
When there is no explicit type requirement in the context, the type of the
matchexpression is the minimum common parent type of the code blocks following=>in eachcasebranch. -
When the value of the
matchexpression is not used, its type isUnit, and there is no requirement for the branches to have the minimum common parent type.
Here are examples to illustrate these points.
let x = 2
let s: String = match (x) {
case 0 => "x = 0"
case 1 => "x = 1"
case _ => "x != 0 and x != 1" // Matched.
}
In this example, the variable s is explicitly annotated with the type String, which is a case where the type information in the context is clear. Therefore, each case's code block following => must have a type that is a subtype of String. Clearly, the string literals after => in the above example satisfy this requirement.
Another example without context type information is as follows:
let x = 2
let s = match (x) {
case 0 => "x = 0"
case 1 => "x = 1"
case _ => "x != 0 and x != 1" // Matched.
}
In this example, the variable s is not explicitly annotated with a type. However, since the type of the code blocks following => in each case is String, the type of the match expression is also String, which means the type of s can be determined to be String as well.
if-let Expression
The if-let expression first evaluates the expression on the right of <- in the condition. If the value matches the pattern on the left of <-, the if branch is executed. Otherwise, the else branch is executed (which can be omitted). Example:
main() {
let result = Option<Int64>.Some(2023)
if (let Some(value) <- result) {
println("Operation successful, return value: ${value}")
} else {
println("Operation failed")
}
}
Run the preceding program and the following information will be displayed:
Operation successful, return value: 2023
In the above program, if the initial value of result is changed to Option<Int64>.None, the if-let pattern matching will fail, and the else branch will be executed.
main() {
let result = Option<Int64>.None
if (let Some(value) <- result) {
println("Operation successful, return value: ${value}")
} else {
println("Operation failed")
}
}
Run the preceding program and the following information will be displayed:
Operation failed
while-let Expression
The while-let expression evaluates the expression on the right of <- in the condition. If the value matches the pattern on the left of <-, the loop body is executed and the process is repeated. If the pattern matching fails, the loop ends and the code following the while-let expression continues to execute. Example:
import std.random.*
// This function simulates receiving data in communication, which may fail.
func recv(): Option<UInt8> {
let number = Random().nextUInt8()
if (number < 128) {
return Some(number)
}
return None
}
main() {
// Simulate a loop to receive communication data. The loop ends if it fails.
while (let Some(data) <- recv()) {
println(data)
}
println("receive failed")
}
After the preceding program is run, the possible output is as follows:
73
94
receive failed
Other Places to Use Patterns
In addition to match expressions, the pattern can also be used in variable definitions (the pattern is on the left of the equal sign) and for in expressions (the pattern is between the for keyword and the in keyword).
However, not all patterns can be used in variable definitions and for in expressions. Only the irrefutable pattern can be used in these two contexts. Therefore, only the wildcard pattern, binding pattern, irrefutable tuple pattern, and irrefutable enum pattern are allowed.
-
The following is an example of using the wildcard pattern in variable definitions and
for inexpressions:main() { let _ = 100 for (_ in 1..5) { println("0") } }In the preceding example, the wildcard pattern is used in the variable definition, indicating that an unnamed variable is defined (the variable cannot be accessed later). The wildcard pattern is used in the
for inexpression, indicating that the elements in1..5are not bound to any variable (the element values in1..5cannot be accessed in the loop body). The result is as follows:0 0 0 0 -
The following is an example of using the binding pattern in variable definitions and
for inexpressions:main() { let x = 100 println("x = ${x}") for (i in 1..5) { println(i) } }In the preceding example, both
xin the variable definition andiin thefor inexpression are binding patterns. The result is as follows:x = 100 1 2 3 4 -
The following is an example of using the
irrefutabletuple pattern in variable definitions and for in expressions:main() { let (x, y) = (100, 200) println("x = ${x}") println("y = ${y}") for ((i, j) in [(1, 2), (3, 4), (5, 6)]) { println("Sum = ${i + j}") } }In the preceding example, the tuple pattern is used in the variable definition, indicating that
(100, 200)is deconstructed and bound toxandyrespectively. The effect is equivalent to defining two variablesxandy. Thefor inexpression uses a tuple pattern to extract the tuple elements from[(1, 2), (3, 4), (5, 6)], destructing them and binding the values toiandjrespectively, and the loop body outputs the value ofi + j. The result is as follows:x = 100 y = 200 Sum = 3 Sum = 7 Sum = 11 -
The following is an example of using the
irrefutableenum pattern in variable definitions and for in expressions:enum RedColor { Red(Int64) } main() { let Red(red) = Red(0) println("red = ${red}") for (Red(r) in [Red(10), Red(20), Red(30)]) { println("r = ${r}") } }In the preceding example, the enum pattern is used in the variable definition, indicating that
Red(0)is deconstructed and the parameter value (that is,0) of the constructor is bound tored. The enum pattern is used in thefor inexpression, indicating that the elements in[Red(10), Red(20), Red(30)]are obtained in sequence, the constructor parameter values are deconstructed and bound tor, and the value ofris output in the loop body. The result is as follows:red = 0 r = 10 r = 20 r = 30
Classes
The class type is a typical concept in object-oriented programming. Cangjie supports object-oriented programming using the class type. The differences between a class and a struct are as follows: a class is a reference type, and a struct is a value type. They behave differently when assigning values or transferring parameters. A class can inherit from another class, but a struct cannot inherit from another struct.
This section describes how to define the class type, create an object, and inherit a class.
Defining Classes
The definition of the class type starts with the keyword class, followed by the class name, and then a class body defined in a pair of braces. The class body can define a series of member variables, member properties, static initializers, constructors, member functions, and operator functions. For details about member properties, see Properties. For details about operator functions, see Operator Overloading.
class Rectangle {
let width: Int64
let height: Int64
public init(width: Int64, height: Int64) {
this.width = width
this.height = height
}
public func area() {
width * height
}
}
In the preceding example, the class type named Rectangle is defined. The class type has two Int64 member variables width and height, a constructor with two Int64 parameters, and a member function area (returning the product of width and height).
Note:
A
classcan be defined only at the top layer of the source file.
Class Member Variables
Member variables of a class are classified into instance member variables and static member variables. Static member variables are modified by static and must have initial values. Static member variables can be accessed only by type names. The following is an example:
class Rectangle {
let width = 10
static let height = 20
}
let l = Rectangle.height // l = 20
When defining an instance member variable, you do not need to set the initial value (but you need to mark the type). You can also set the initial value, but it can be accessed only through an object (an instance of a class). The following is an example:
class Rectangle {
let width = 10
let height: Int64
init(h: Int64){
height = h
}
}
let rec = Rectangle(20)
let l = rec.height // l = 20
Class Static Initializers
A class supports the definition of static initializers in which static member variables are initialized through assignment expressions.
A static initializer starts with the keyword combination static init, followed by an empty parameter list and a function body, and cannot be modified by an access modifier. All uninitialized static member variables must be initialized in the function body. Otherwise, a compilation error is reported.
class Rectangle {
static let degree: Int64
static init() {
degree = 180
}
}
A class can define only one static initializer. Otherwise, a redefinition error is reported.
class Rectangle {
static let degree: Int64
static init() {
degree = 180
}
static init() { // Error, redefinition with the previous static init function
degree = 180
}
}
Class Constructors
Like a struct, a class supports the definition of normal constructors and main constructors.
A common constructor starts with the keyword init, followed by a parameter list and a function body. In the function body, all uninitialized instance member variables must be initialized. Otherwise, a compilation error is reported.
class Rectangle {
let width: Int64
let height: Int64
public init(width: Int64, height: Int64) { // Error, 'height' is not initialized in the constructor
this.width = width
}
}
Multiple common constructors can be defined in a class, but they must be overloaded. Otherwise, a redefinition error is reported. For details about function overloading, see Function Overloading.
class Rectangle {
let width: Int64
let height: Int64
public init(width: Int64) {
this.width = width
this.height = width
}
public init(width: Int64, height: Int64) { // Ok: overloading with the first init function
this.width = width
this.height = height
}
public init(height: Int64) { // Error, redefinition with the first init function
this.width = height
this.height = height
}
}
In addition to defining several common constructors named init, you can define (at most) one main constructor within a class. The name of the main constructor is the same as that of the class type. The parameter list of the main constructor can contain two types of formal parameters: common formal parameters and formal parameters of member variables (let or var must be added before the parameter name). Formal parameters of member variables can define member variables and be used as constructor parameters.
The definition of a class can be simplified by using the main constructor. For example, the preceding Rectangle containing one init constructor can be simplified as follows:
class Rectangle {
public Rectangle(let width: Int64, let height: Int64) {}
}
Common formal parameters can also be defined in the parameter list of the main constructor. For example:
class Rectangle {
public Rectangle(name: String, let width: Int64, let height: Int64) {}
}
The constructor called when an instance of a class is created executes the expressions in the class in the following sequence:
- Initialize the variables that are defined outside the primary constructor and have default values.
- If the constructor does not explicitly call the superclass constructor or other constructors of the class, the parameterless constructor
super()of the superclass is called. If the superclass does not have a parameterless constructor, an error is reported. - Execute the code in the constructor body.
func foo(x: Int64): Int64 {
println("I'm foo, got ${x}")
x
}
open class A {
init() {
println("I'm A")
}
}
class B <: A {
var x = foo(0)
init() {
x = foo(1)
println("init B finished")
}
}
main() {
B()
0
}
In the preceding example, when the constructor of B is called, the variable x with a default value is initialized, and foo(0) is called. Then, the parameterless constructor of the superclass is called, triggering the call to the constructor of A. Next, the code inside the constructor body is executed, and foo(1) is called, printing the string. Therefore, the output of the preceding example is as follows:
I'm foo, got 0
I'm A
I'm foo, got 1
init B finished
If no custom constructor (including the main constructor) exists in the class definition and all instance member variables have initial values, parameterless constructor is automatically generated. (If this parameterless constructor is called, an object is created in which the values of all instance member variables are equal to the initial values.) Otherwise, the parameterless constructor is not automatically generated. For example, the compiler automatically generates a parameterless constructor for the following class definition:
class Rectangle {
let width = 10
let height = 20
/* Auto-generated parameterless constructor:
public init() {
}
*/
}
// Invoke the auto-generated parameterless constructor
let r = Rectangle() // r.width = 10, r.height = 20
Class Finalizers
A class can define a finalizer which is called when an instance of a class is garbage-collected. The function name of finalizers is fixed to ~init. Finalizers are used to release system resources.
class C {
var p: CString
init(s: String) {
p = unsafe { LibC.mallocCString(s) }
println(s)
}
~init() {
unsafe { LibC.free(p) }
}
}
Developers need to pay attention to the following restrictions when using finalizers:
- Finalizers do not have parameters, return types, generic type parameters, or modifiers, and cannot be explicitly called.
- Classes with finalizers cannot be modified by
open. Only classes that are notopencan have finalizers. - A class can define at most one finalizer.
- A finalizer cannot be defined in extensions.
- The timing when a finalizer is triggered is uncertain.
- A finalizer may be executed on any thread.
- Multiple finalizers are executed in a random sequence.
- It is an undefined behavior that a finalizer throws an uncaptured exception.
- It is an undefined behavior to create a thread in a finalizer or use the thread synchronization function.
- It is an undefined behavior if the object can still be accessed after the finalizer is executed.
- If an object throws an exception during initialization, the finalizer of the object, which has not been fully initialized, will not be executed.
Class Member Functions
Member functions of a class are classified into instance member functions and static member functions (modified by static). Instance member functions can be accessed only through objects, and static member functions can be accessed only through class type names. Static member functions cannot access instance member variables or call instance member functions. However, static member variables and static member functions can be accessed in instance member functions.
In the following example, area is an instance member function, and typeName is a static member function.
class Rectangle {
let width: Int64 = 10
let height: Int64 = 20
public func area() {
this.width * this.height
}
public static func typeName(): String {
"Rectangle"
}
}
Instance member functions can be classified into abstract and non-abstract member functions based on whether there is a function body. Abstract member functions have no function bodies and can be defined only in abstract classes or interfaces. For details, see Interfaces. In the following example, the abstract function foo is defined in the abstract class AbRectangle (modified by the keyword abstract).
abstract class AbRectangle {
public func foo(): Unit
}
Note that abstract instance member functions have the semantics of open by default. The open modifier is optional and the public or protected modifier is mandatory.
A non-abstract function must have a function body. In the function body, instance member variables can be accessed through this. For example:
class Rectangle {
let width: Int64 = 10
let height: Int64 = 20
public func area() {
this.width * this.height
}
}
Access Modifiers of Class Members
For class members (including member variables, member properties, constructors, and member functions), there are four types of access modifiers: private, internal, protected, and public. Default indicates internal.
- The
privatemodifier indicates that members are visible within theclassdefinition. - The
internalmodifier indicates that only the current package and subpackages (including the subpackages of the subpackages) are visible. For details, see Package. - The
protectedmodifier indicates that the current module and the subclasses of the current class are visible. For details, see Package. - The
publicmodifier indicates that members are visible both inside and outside the module.
package a
public open class Rectangle {
public var width: Int64
protected var height: Int64
private var area: Int64
public init(width: Int64, height: Int64) {
this.width = width
this.height = height
this.area = this.width * this.height
}
init(width: Int64, height: Int64, multiple: Int64) {
this.width = width
this.height = height
this.area = width * height * multiple
}
}
func samePkgFunc() {
var r = Rectangle(10, 20) // Ok: constructor 'Rectangle' can be accessed here
r.width = 8 // Ok: public 'width' can be accessed here
r.height = 24 // Ok: protected 'height' can be accessed here
r.area = 30 // Error, private 'area' cannot be accessed here
}
package b
import a.*
public class Cuboid <: Rectangle {
private var length: Int64
public init(width: Int64, height: Int64, length: Int64) {
super(width, height)
this.length = length
}
public func volume() {
this.width * this.height * this.length // Ok: protected 'height' can be accessed here
}
}
main() {
var r = Rectangle(10, 20, 2) // Error, Rectangle has no `public` constructor with three parameters
var c = Cuboid(20, 20, 20)
c.width = 8 // Ok: public 'width' can be accessed here
c.height = 24 // Error, protected 'height' cannot be accessed here
c.area = 30 // Error, private 'area' cannot be accessed here
}
This Type
Inside a class, the This type placeholder is supported and refers to the type of the current class. The This type placeholder can only be used as the return type of an instance member function. When a subclass object is used to call a function whose return type is This type defined in the superclass, the calling type of the function is identified as a subclass instead of the superclass where the function is defined.
If an instance member function does not declare a return type and only an expression of This type exists, the return type of the current function is inferred as This. The following is an example:
open class C1 {
func f(): This { // its type is `() -> C1`
return this
}
func f2() { // its type is `() -> C1`
return this
}
public open func f3(): C1 {
return this
}
}
class C2 <: C1 {
// member function f is inherited from C1, and its type is `() -> C2` now
public override func f3(): This { // Ok
return this
}
}
var obj1: C2 = C2()
var obj2: C1 = C2()
var x = obj1.f() // During compilation, the type of x is C2
var y = obj2.f() // During compilation, the type of y is C1
Creating Objects
After the class type is defined, you can call its constructor to create an object (by calling the constructor through the class type name). In the following example, Rectangle(10, 20) is used to create an object of the Rectangle type and assign a value to the variable r.
let r = Rectangle(10, 20)
After an object is created, instance member variables and instance member functions (modified by public) can be accessed through the object. In the following example, r.width and r.height can be used to access the values of width and height in r, and r.area() can be used to call the member function area.
let r = Rectangle(10, 20) // r.width = 10, r.height = 20
let width = r.width // width = 10
let height = r.height // height = 20
let a = r.area() // a = 200
If you want to change the value of a member variable through an object (this method is not recommended, and you are advised to change the value through a member function), you need to define the member variable of the class type as a mutable member variable (by using var). The following is an example:
class Rectangle {
public var width: Int64
public var height: Int64
...
}
main() {
let r = Rectangle(10, 20) // r.width = 10, r.height = 20
r.width = 8 // r.width = 8
r.height = 24 // r.height = 24
let a = r.area() // a = 192
}
Different from the object of a struct, the object of a class is not copied when its values are assigned or its parameters are transferred. Multiple variables point to the same object. If the value of a member in an object is changed through a variable, the values of the corresponding member variables in other variables are also changed. The following uses value assignment as an example. After r1 is assigned to r2, if the values of width and height of r1 are changed, the values of width and height of r2 are also changed.
main() {
var r1 = Rectangle(10, 20) // r1.width = 10, r1.height = 20
var r2 = r1 // r2.width = 10, r2.height = 20
r1.width = 8 // r1.width = 8
r1.height = 24 // r1.height = 24
let a1 = r1.area() // a1 = 192
let a2 = r2.area() // a2 = 192
}
Inheriting Classes
Like most programming languages that support the class type, Cangjie supports class inheritance. If class B inherits class A, class A is the superclass and class B is the subclass. The subclass inherits all members of the superclass except private members and constructors.
Abstract classes can always be inherited. Therefore, the open modifier is optional when an abstract class is defined. You can also use sealed to modify an abstract class, indicating that the abstract class can be inherited only in the current package. A non-abstract class can be inherited only if it is modified by open during definition. When an instance member with the open modifier is inherited by a class, the open modifier is also inherited. When a class without the open modifier contains a member with the open modifier, the compiler generates an alarm.
You can use <: to specify the superclass that a subclass inherits, but the superclass must be inheritable. In the following example, class A is modified by open and can be inherited by class B. However, class B cannot be inherited. Therefore, an error is reported when class C inherits class B.
open class A {
let a: Int64 = 10
}
class B <: A { // Ok: 'B' Inheritance 'A'
let b: Int64 = 20
}
class C <: B { // Error, 'B' is not inheritable
let c: Int64 = 30
}
A class supports only single inheritance. Therefore, it is invalid for a class to inherit the code of two classes. (& is the syntax for a class to implement multiple interfaces. For details, see Interfaces.
open class A {
let a: Int64 = 10
}
open class B {
let b: Int64 = 20
}
class C <: A & B { // Error, 'C' can only inherit one class
let c: Int64 = 30
}
Because classes support single inheritance, each class can have at most one direct superclass. For a class whose superclass is specified during definition, its direct superclass is the specified class during definition. For a class whose superclass is not specified during definition, its direct superclass is of the Object type. Object is the superclass of all classes (note that Object has no direct superclass and contains no members).
Because a subclass is inherited from its superclass, the object of the subclass can be used as the object of its superclass. However, the object of the superclass cannot be used as the object of its subclass. In the following example, B is a subclass of A. Therefore, an object of type B can be assigned to a variable of type A, but an object of type A cannot be assigned to a variable of type B.
open class A {
let a: Int64 = 10
}
class B <: A {
let b: Int64 = 20
}
let a: A = B() // Ok: subclass objects can be assigned to superclass variables
open class A {
let a: Int64 = 10
}
class B <: A {
let b: Int64 = 20
}
let b: B = A() // Error, superclass objects cannot be assigned to subclass variables
The type defined by a class cannot inherit the type itself.
class A <: A {} // Error, 'A' inherits itself.
The sealed modifier can modify only abstract classes, indicating that the modified class definition can be inherited by other classes only in the package where the definition is located. The sealed modifier contains the semantics of public or open. Therefore, if the public or open modifier is provided when a sealed abstract class is defined, the compiler generates an alarm. A sealed subclass may be a non-sealed class. It can still be modified by open or sealed, or has no inheritance modifier. If a subclass of the sealed class is modified by open, the subclass can be inherited outside the package. A sealed subclass does not need to be modified by public.
package A
public sealed abstract class C1 {} // Warning, redundant modifier, 'sealed' implies 'public'
sealed open abstract class C2 {} // Warning, redundant modifier, 'sealed' implies 'open'
sealed abstract class C3 {} // OK, 'public' is optional when 'sealed' is used
class S1 <: C1 {} // OK
public open class S2 <: C1 {} // OK
public sealed abstract class S3 <: C1 {} // OK
open class S4 <: C1 {} // OK
package B
import A.*
class SS1 <: S2 {} // OK
class SS2 <: S3 {} // Error, S3 is sealed class, cannot be inherited here.
sealed class SS3 {} // Error, 'sealed' cannot be used on non-abstract class.
Calling Superclass Constructors
The init constructor of a subclass can call constructors of the superclass using super(args) or call other constructors of the class using this(args). However, only one of them can be called. If called, the constructor must be at the first expression in the constructor body with no preceding expressions or declarations.
open class A {
A(let a: Int64) {}
}
class B <: A {
let b: Int64
init(b: Int64) {
super(30)
this.b = b
}
init() {
this(20)
}
}
The main constructor of a subclass can use super(args) to call the constructor of the superclass, but cannot use this(args) to call other constructors of the class.
If the constructor of a subclass does not explicitly call the constructor of the superclass or other constructors, the compiler inserts the called parameterless constructor of the direct superclass at the beginning of the constructor body. If the superclass has no parameterless constructor, a compilation error is reported.
open class A {
let a: Int64
init() {
a = 100
}
}
open class B <: A {
let b: Int64
init(b: Int64) {
// OK, `super()` added by compiler
this.b = b
}
}
open class C <: B {
let c: Int64
init(c: Int64) { // Error, there is no non-parameter constructor in super class
this.c = c
}
}
Overriding and Redefining
A subclass can override a non-abstract instance member function with the same name in the superclass, that is, a subclass can define a new implementation for an instance member function in the superclass. During overriding, member functions in the superclass must be modified by open, and functions with the same name in the subclass must be modified by override. The override modifier is optional. In the following example, the function f in subclass B overrides the function f in superclass A.
open class A {
public open func f(): Unit {
println("I am superclass")
}
}
class B <: A {
public override func f(): Unit {
println("I am subclass")
}
}
main() {
let a: A = A()
let b: A = B()
a.f()
b.f()
}
For an overridden function, the version to be called is determined by the runtime type of the variable (determined by the object that is actually assigned to the variable). This is known as dynamic dispatch. In the preceding example, the runtime type of a is A. Therefore, a.f() calls the function f in superclass A. The runtime type of b is B (the compile-time type is A). Therefore, b.f() calls the function f in subclass B. Therefore, the program displays the following information:
I am superclass
I am subclass
For a static function, a subclass can redefine a non-abstract static function with the same name in the superclass, that is, a subclass can define a new implementation for a static function in the superclass. During redefinition, static functions with the same name in a subclass must be modified by redef. The redef modifier is optional. In the following example, the function foo in subclass D redefines the function foo in superclass C.
open class C {
public static func foo(): Unit {
println("I am class C")
}
}
class D <: C {
public redef static func foo(): Unit {
println("I am class D")
}
}
main() {
C.foo()
D.foo()
}
For a redefined function, the version to be called is determined by the type of class. For example, in the preceding example, C.foo() calls the foo function in superclass C, and D.foo() calls the foo function in subclass D.
I am class C
I am class D
If an abstract function or a function modified by open has named formal parameters, the implemented function or the function modified by override must have the same named formal parameters.
open class A {
public open func f(a!: Int32): Int32 {
a + 1
}
}
class B <: A {
public override func f(a!: Int32): Int32 { // Ok
a + 2
}
}
class C <: A {
public override func f(b!: Int32): Int32 { // Error
b + 3
}
}
main() {
B().f(a: 0)
C().f(b: 0)
}
It should be noted that when the implemented or redefined function is a generic function, the type variant constraint of the function in the subtype needs to be looser or the same as that of the corresponding function in the supertype.
open class A {}
open class B <: A {}
open class C <: B {}
open class Base {
static func f<T>(a: T): Unit where T <: B {}
static func g<T>(): Unit where T <: B {}
}
class D <: Base {
redef static func f<T>(a: T): Unit where T <: C {} // Error, stricter constraint
redef static func g<T>(): Unit where T <: C {} // Error, stricter constraint
}
class E <: Base {
redef static func f<T>(a: T): Unit where T <: A {} // OK: looser constraint
redef static func g<T>(): Unit where T <: A {} // OK: looser constraint
}
class F <: Base {
redef static func f<T>(a: T): Unit where T <: B {} // OK: same constraint
redef static func g<T>(): Unit where T <: B {} // OK: same constraint
}
Interfaces
An interface is used to define an abstract type. An interface contains no data but can define a behavior of a type. If a type declares that it implements an interface and implements all the members of the interface, the interface is implemented.
An interface can contain the following members:
- Member function
- Operator overloading function
- Member property
These members are abstract. Implementing types must have the corresponding implementation of the members.
Defining Interfaces
A simple interface is defined as follows:
interface I { // 'open' modifier is optional.
func f(): Unit
}
An interface is declared using the keyword interface, followed by the I identifier of the interface and the members of the interface. Interface members can be modified by the open modifier. The open modifier is optional.
After the I interface declares a member function f, to implement I for a type, you must implement a corresponding f function in the type.
Because an interface has the semantics of open by default, the open modifier is optional when an interface is defined.
As shown in the following code, class Foo is defined, and Foo is declared in the form of Foo <: I to implement the I interface.
Foo must contain the implementations of all members declared by I, that is, an f of the same type must be defined. Otherwise, a compilation error is reported because the interface is not implemented.
class Foo <: I {
public func f(): Unit {
println("Foo")
}
}
main() {
let a = Foo()
let b: I = a
b.f() // "Foo"
}
After a type implements an interface, the type becomes a subtype of the interface.
In the preceding example, Foo is a subtype of I. Therefore, any instance of the Foo type can be used as an instance of the I type.
In main, if you assign the variable a of the Foo type to the variable b of the I type and call the f function in b, the f version implemented by Foo is printed. The program output is as follows:
Foo
An interface can also use the sealed modifier to indicate that the interface can be inherited, implemented, or extended only within the package where the interface definition resides. The sealed modifier contains the semantics of public or open. Therefore, if the public or open modifier is provided when a sealed interface is defined, the compiler generates an alarm. Sub-interfaces that inherit a sealed interface or classes that implement a sealed interface can be modified by sealed or not be modified by sealed. If a sub-interface of a sealed interface is modified by public and is not modified by sealed, the sub-interface can be inherited, implemented, or extended outside the package. Types that inherit and implement sealed interfaces do not need to be modified by public.
package A
public interface I1 {}
sealed interface I2 {} // OK
public sealed interface I3 {} // Warning, redundant modifier, 'sealed' implies 'public'
sealed open interface I4 {} // Warning, redundant modifier, 'sealed' implies 'open'
class C1 <: I1 {}
public open class C2 <: I1 {}
sealed class C3 <: I2 {}
extend Int64 <: I2 {}
package B
import A.*
class S1 <: I1 {} // OK
class S2 <: I2 {} // Error, I2 is sealed interface, cannot be inherited here.
Through the constraint capability of the interface, common functions can be specified for a series of types to abstract the functions.
As shown in the following code, you can define a Flyable interface and have other classes with the properties of Flyable to implement it.
interface Flyable {
func fly(): Unit
}
class Bird <: Flyable {
public func fly(): Unit {
println("Bird flying")
}
}
class Bat <: Flyable {
public func fly(): Unit {
println("Bat flying")
}
}
class Airplane <: Flyable {
public func fly(): Unit {
println("Airplane flying")
}
}
func fly(item: Flyable): Unit {
item.fly()
}
main() {
let bird = Bird()
let bat = Bat()
let airplane = Airplane()
fly(bird)
fly(bat)
fly(airplane)
}
Compile and execute the preceding code. The following information is displayed:
Bird flying
Bat flying
Airplane flying
The members of an interface can be instance or static members. The preceding example shows the use of instance member functions. The following shows the use of static member functions.
Similar to instance member functions, static member functions require implementing types to provide implementation.
In the following example, the NamedType interface is defined. The interface contains a static member function typename to obtain the string name of each type.
Other types must implement the typename function when implementing the NamedType interface, and then the name of the type can be obtained safely on the subtype of the NamedType.
interface NamedType {
static func typename(): String
}
class A <: NamedType {
public static func typename(): String {
"A"
}
}
class B <: NamedType {
public static func typename(): String {
"B"
}
}
main() {
println("the type is ${ A.typename() }")
println("the type is ${ B.typename() }")
}
The program output is as follows:
the type is A
the type is B
Static member functions (or properties) in an interface may or may not have a default implementation.
When it has no default implementation, it cannot be accessed through the interface type name. As shown in the following code, a compilation error is reported when the typename function of the NamedType is directly accessed. This is because the NamedType does not have the implementation of the typename function.
main() {
NamedType.typename() // Error
}
A static member function (or property) in an interface can also have a default implementation. When another type inherits an interface that has a static function (or property) with a default implementation, the type does not need to implement the static member function (or property). The function (or property) can be accessed directly through the interface name and the type name. In the following example, the member function typename of NamedType has a default implementation, and it does not need to be re-implemented in A. In addition, it can be directly accessed through the interface name and the type name.
interface NamedType {
static func typename(): String {
"interface NamedType"
}
}
class A <: NamedType {}
main() {
println(NamedType.typename())
println(A.typename())
0
}
The program output is as follows:
interface NamedType
interface NamedType
Generally, we use such static members in generic functions through generic constraints.
The following uses printTypeName function as an example. When constraining the generic variant T to be a subtype of NamedType, ensure that all static member functions (or properties) in the instantiation type of T have implementations so that the implementation of the generic variant can be accessed in T.typename mode to abstract static members. For details, see Generics.
interface NamedType {
static func typename(): String
}
interface I <: NamedType {
static func typename(): String {
f()
}
static func f(): String
}
class A <: NamedType {
public static func typename(): String {
"A"
}
}
class B <: NamedType {
public static func typename(): String {
"B"
}
}
func printTypeName<T>() where T <: NamedType {
println("the type is ${ T.typename() }")
}
main() {
printTypeName<A>() // Ok
printTypeName<B>() // Ok
printTypeName<I>() // Error, 'I' must implement all static function. Otherwise, an unimplemented 'f' is called, causing problems.
}
It should be noted that the members of an interface are modified by public by default. Additional access control modifiers cannot be declared. In addition, the implementing type must use public for implementation.
interface I {
func f(): Unit
}
open class C <: I {
protected func f() {} // Compiler Error, f needs to be public semantics
}
Inheriting Interfaces
If you want to implement multiple interfaces for a type, you can use & to separate the interfaces. The interfaces can be implemented in any sequence.
In the following example, MyInt can implement the Addable and Subtractable interfaces at the same time.
interface Addable {
func add(other: Int64): Int64
}
interface Subtractable {
func sub(other: Int64): Int64
}
class MyInt <: Addable & Subtractable {
var value = 0
public func add(other: Int64): Int64 {
value + other
}
public func sub(other: Int64): Int64 {
value - other
}
}
An interface can inherit one or more interfaces, but cannot inherit classes. At the same time, new interface members can be added during interface inheritance.
In the following example, the Calculable interface inherits the Addable and Subtractable interfaces, and two overloaded operators multiplication and division are added.
interface Addable {
func add(other: Int64): Int64
}
interface Subtractable {
func sub(other: Int64): Int64
}
interface Calculable <: Addable & Subtractable {
func mul(other: Int64): Int64
func div(other: Int64): Int64
}
In this case, the addition, subtraction, multiplication, and division operators must be overloaded at the same time when the implementing type implements the Calculable interface. No member can be missing.
class MyInt <: Calculable {
var value = 0
public func add(other: Int64): Int64 {
value + other
}
public func sub(other: Int64): Int64 {
value - other
}
public func mul(other: Int64): Int64 {
value * other
}
public func div(other: Int64): Int64 {
value / other
}
}
MyInt implements both Calculable and all the interfaces inherited by Calculable. Therefore, MyInt also implements Addable and Subtractable, that is, Mylnt is the subtype of Addable and Subtractable.
main() {
let myInt = MyInt()
let add: Addable = myInt
let sub: Subtractable = myInt
let calc: Calculable = myInt
}
For interface inheritance, if a sub-interface inherits a function or property that is implemented by default in the super-interface, the declaration of the function or property cannot be written in the sub-interface (that is, there is no default implementation). Instead, a new default implementation must be provided, the override modifier (or redef modifier) before the function definition is optional. If a sub-interface inherits a function or property that has no default implementation in the super-interface, only the declaration of the function or property can be written in the sub-interface (the default implementation can also be defined). In addition, the override modifier (or redef modifier) before the function declaration or definition is optional.
interface I1 {
func f(a: Int64) {
a
}
static func g(a: Int64) {
a
}
func f1(a: Int64): Unit
static func g1(a: Int64): Unit
}
interface I2 <: I1 {
/*'override' is optional*/ func f(a: Int64) {
a + 1
}
override func f(a: Int32) {} // Error, override function 'f' does not have an overridden function from its supertypes
static /*'redef' is optional*/ func g(a: Int64) {
a + 1
}
/*'override' is optional*/ func f1(a: Int64): Unit {}
static /*'redef' is optional*/ func g1(a: Int64): Unit {}
}
Implementing Interfaces
All types can implement interfaces, including numeric types, Rune, String, struct, class, enum, Tuple, function, and other types.
A type can implement an interface in the following three ways:
- Declare the interface to be implemented when the type is defined. For details, see related examples in the preceding content.
- Implement the interface through extension. For details, see Extension.
- Implement the interface through language built-in interfaces. For details, see the Cangjie Programming Language Library API.
When an implementing type declares that an interface is implemented, all members required by the interface must be implemented. Therefore, the following rules must be met:
- The implementation of a member function or operator overloading function provided by the implementing type must be consistent with the interface in terms of the function name, parameter list and return type.
- Member properties must be consistent in whether being modified by
mutor not, and the property type must be the same.
In most cases, as shown in the above examples, an implementing type should have the same implementations of members as that of an interface.
There is an exception. If the return value of a member function or operator overloading function in an interface is the class type, the return type of the implemented function can be its subtype.
In the following example, the return type of f in I is Base of the class type. Therefore, the return type of f implemented in C can be a Base subtype Sub.
open class Base {}
class Sub <: Base {}
interface I {
func f(): Base
}
class C <: I {
public func f(): Sub {
Sub()
}
}
In addition, members of the interface can provide default implementations for the class type. For an interface member with a default implementation, if the implementing type is a class, the class can inherit the implementation of the interface without providing its own implementation.
Note:
The default implementation is valid only if the implementing type is a class.
As shown in the following code, say in SayHi has a default implementation. Therefore, A can inherit the implementation of say when implementing SayHi, and B can provide its own implementation of say.
interface SayHi {
func say() {
"hi"
}
}
class A <: SayHi {}
class B <: SayHi {
public func say() {
"hi, B"
}
}
Especially, if a type implements multiple interfaces which contain the default implementation of the same member, multiple inheritance conflicts occur, and the language cannot select the most suitable implementation. In this case, the default implementation in the interface becomes invalid, and the implementing type needs to provide its own implementation.
In the following example, both SayHi and SayHello contain the implementation of say. Foo must provide its own implementation when implementing the two interfaces. Otherwise, compilation errors may occur.
interface SayHi {
func say() {
"hi"
}
}
interface SayHello {
func say() {
"hello"
}
}
class Foo <: SayHi & SayHello {
public func say() {
"Foo"
}
}
When a struct, enum, or class implements an interface, the override modifier (or redef modifier) before the definition of a function or property is optional, regardless of whether the function or property in the interface has a default implementation.
interface I {
func foo(): Int64 {
return 0
}
}
enum E <: I{
elem
public override func foo(): Int64 {
return 1
}
}
struct S <: I {
public override func foo(): Int64 {
return 1
}
}
Any Type
The Any type is a built-in interface. Its definition is as follows:
interface Any {}
By default, all interfaces in Cangjie inherit the Any type, and all non-interface types implement the Any type by default. Therefore, all types can be used as subtypes of the Any type.
As shown in the following code, you can assign a series of variables of different types to the variables of the Any type.
main() {
var any: Any = 1
any = 2.0
any = "hello, world!"
}
Properties
Properties provide a getter and an optional setter to indirectly get and set values.
The use of properties is the same as that of common variables. You only need to perform operations on data and are unaware of internal implementation. In this way, mechanisms such as access control, data monitoring, tracing and debugging, and data binding can be implemented more conveniently.
Properties can be used as expressions or assigned values. The following uses classes and interfaces as examples, but properties are not limited to classes and interfaces.
For example, b is a typical property that encapsulates external access to a:
class Foo {
private var a = 0
public mut prop b: Int64 {
get() {
println("get")
a
}
set(value) {
println("set")
a = value
}
}
}
main() {
var x = Foo()
let y = x.b + 1 // get
x.b = y // set
}
Foo provides a property named b. Cangjie provides the get and set syntaxes to define the getter and setter functions. When variable x of the Foo type accesses b, the get operation of b is called to return a value of the Int64 type. Therefore, variable x can be added to 1. When x assigns a value to b, the set operation of b is called to transfer the value of y to the value of set, and finally value is assigned to a.
Through property b, the external system is unaware of the member variable a of Foo, but the same access and modification operations can be performed through property b, thereby implementing effective encapsulation. The program output is as follows:
get
set
Defining Properties
Properties can be defined in interface, class, struct, enum, and extend.
A typical property syntax structure is as follows:
class Foo {
public prop a: Int64 {
get() { 0 }
}
public mut prop b: Int64 {
get() { 0 }
set(v) {}
}
}
a and b declared using prop are properties, and the types of a and b are both Int64. a is a property without the mut modifier. This type of property has only the implementation of getter (corresponding to the value to be got). b is a property modified by mut. This type of property must define the implementations of getter (corresponding to the value to be got) and setter (corresponding to the value to be assigned).
The getter and setter of a property correspond to two different functions.
- The type of the getter function is
() -> T, where T is the type of the property. When the property is used as an expression, the getter function is executed. - The type of the setter function is
(T) -> Unit. T indicates the type of the property. The formal parameter name needs to be explicitly specified. When a value is assigned to the property, the setter function is executed.
Like the function body, the implementations of getter and setter can contain declarations and expressions. The rules of getter and setter are the same as those of the function body. For details, see [Function Body](../function/define_functions.md# Function Body).
The parameter in setter corresponds to the value transferred during value assignment.
class Foo {
private var j = 0
public mut prop i: Int64 {
get() {
j
}
set(v) {
j = v
}
}
}
It should be noted that accessing a property in the getter and setter of the property is a recursive call, which may cause an infinite loop like the case in calling a function.
Modifiers
You can declare the required modifiers before prop.
class Foo {
public prop a: Int64 {
get() {
0
}
}
private prop b: Int64 {
get() {
0
}
}
}
Like member functions, member properties can be modified by open, override, and redef. Therefore, you can override or redefine the implementations of supertype properties in subtypes.
When a subtype overrides a property of a supertype, if the property of the supertype has the mut modifier, the property of the subtype must also have the mut modifier and be of the same type as the supertype property.
As shown in the following code, properties x and y are defined in A, and override or redef can be performed on properties x and y in B.
open class A {
private var valueX = 0
private static var valueY = 0
public open prop x: Int64 {
get() { valueX }
}
public static mut prop y: Int64 {
get() { valueY }
set(v) {
valueY = v
}
}
}
class B <: A {
private var valueX2 = 0
private static var valueY2 = 0
public override prop x: Int64 {
get() { valueX2 }
}
public redef static mut prop y: Int64 {
get() { valueY2 }
set(v) {
valueY2 = v
}
}
}
Abstract Properties
Similar to abstract functions, abstract properties can be declared in an interface or abstract class and the abstract properties are not implemented.
interface I {
prop a: Int64
}
abstract class C {
public prop a: Int64
}
When an implementing type implements an interface or a non-abstract subclass inherits an abstract class, the abstract properties must be implemented.
The rule for implementing abstract properties is similar to that for overriding. When an implementing type or a subclass implements the abstract properties, if the supertype property has the mut modifier, the subtype property must also have the mut modifier and be of the same type as the supertype property.
interface I {
prop a: Int64
mut prop b: Int64
}
class C <: I {
private var value = 0
public prop a: Int64 {
get() { value }
}
public mut prop b: Int64 {
get() { value }
set(v) {
value = v
}
}
}
Through abstract properties, you can specify easy-to-use data operations for properties and abstract classes. Abstract properties are more intuitive than functions.
As shown in the following code, if you want to specify how to get and set of a size value, using a property (I1) requires less code than using a function (I2) and is more suitable for data operation.
interface I1 {
mut prop size: Int64
}
interface I2 {
func getSize(): Int64
func setSize(value: Int64): Unit
}
class C <: I1 & I2 {
private var mySize = 0
public mut prop size: Int64 {
get() {
mySize
}
set(value) {
mySize = value
}
}
public func getSize() {
mySize
}
public func setSize(value: Int64) {
mySize = value
}
}
main() {
let a: I1 = C()
a.size = 5
println(a.size)
let b: I2 = C()
b.setSize(5)
println(b.getSize())
}
5
5
Using Properties
Properties are classified into instance member properties and static member properties. The usage of member properties is the same as that of member variables. For details, see [Member Variables](./class.md#class-Member Variables).
class A {
public prop x: Int64 {
get() {
123
}
}
public static prop y: Int64 {
get() {
321
}
}
}
main() {
var a = A()
println(a.x) // 123
println(A.y) // 321
}
The result is:
123
321
A property without the mut modifier is similar to a variable declared by let and cannot be assigned a value.
class A {
private let value = 0
public prop i: Int64 {
get() {
value
}
}
}
main() {
var x = A()
println(x.i) // OK
x.i = 1 // Error
}
A property with the mut modifier is similar to a variable declared by var and you can get the value of the property or assign a value to it.
class A {
private var value: Int64 = 0
public mut prop i: Int64 {
get() {
value
}
set(v) {
value = v
}
}
}
main() {
var x = A()
println(x.i) // OK
x.i = 1 // OK
}
0
Subtype Relationships
Like other object-oriented languages, Cangjie provides subtype relationships and subtype polymorphisms. Some examples:
- If a formal parameter of a function has a certain type
T, the actual type of the input parameter when the function is called can be eitherTor a subtype ofT. (Strictly speaking, the subtypes ofTalways includeTitself. This also applies to the following content.) - If the type of the variable constituting the left part of an assignment expression
=isT, the actual type of the expression to the right of=can be eitherTor a subtype ofT. - If the return type marked by the user in the function definition is
T, the type of the function body, and the type of eachreturnexpression in the function body, can be eitherTor a subtype ofT.
So how to determine whether two types have a subtype relationship? The details are described below.
Note:
<:is a shorthand for "is a subtype of" in the textual paragraphs of this section.
Subtype Relationships From Class Inheritance
When a class is inherited, the subclass is a subtype of the superclass. In the following code, Sub is a subtype of Super.
open class Super { }
class Sub <: Super { }
Subtype Relationships From Interface Implementation
When an interface gets implemented (including implementation by an extension), the implementing type becomes a subtype of the interface. In the following code, I3 is a subtype of both I1 and I2, C is a subtype of I1, and Int64 is a subtype of I2:
interface I1 { }
interface I2 { }
interface I3 <: I1 & I2 { }
class C <: I1 { }
extend Int64 <: I2 { }
It should be noted that some type test and downcasting scenarios (is and as operators) are not supported after value assignment across extended types. As a result, the judgment may fail. Consider the following example:
// file1.cj
package p1
public class A{}
public func get(): Any {
return A()
}
// =====================
// file2.cj
import p1.*
interface I0 {}
extend A <: I0 {}
main() {
let v: Any = get()
println(v is I0) //The type cannot be correctly determined, and the printed content is uncertain.
}
Subtype Relationships of Tuple Types
Tuple types in Cangjie also have subtype relationships. Intuitively, if the type of each element in a tuple t1 is a subtype of the type of the corresponding element of another tuple t2, the type of the tuple t1 is also a subtype of the type of the tuple t2. As shown in the following code, C2 <: C1 and C4 <: C3, so (C2, C4) <: (C1, C3) and (C4, C2) <: (C3, C1).
open class C1 { }
class C2 <: C1 { }
open class C3 { }
class C4 <: C3 { }
let t1: (C1, C3) = (C2(), C4()) // OK
let t2: (C3, C1) = (C4(), C2()) // OK
Subtype Relationships of Function Types
In Cangjie, functions are first-class citizens, and function types have subtype relationships. Given two function types (U1) -> S2 and (U2) -> S1, if and only if U2 <: U1 and S2 <: S1 (note the sequence), (U1) -> S2 is a subtype of (U2) -> S1. For example, the following code defines two functions: f: (U1) -> S2 and g: (U2) -> S1, and the type of f is a subtype of the type of g. Therefore, f can be substituted anywhere in the code where g can.
open class U1 { }
class U2 <: U1 { }
open class S1 { }
class S2 <: S1 { }
func f(a: U1): S2 { S2() }
func g(a: U2): S1 { S1() }
func call1() {
g(U2()) // Ok.
f(U2()) // Ok.
}
func h(lam: (U2) -> S1): S1 {
lam(U2())
}
func call2() {
h(g) // Ok.
h(f) // Ok.
}
In the above rules, S2 <: S1 is easy to understand. The result produced by a called function will be used by the subsequently executed code. The g function returns values of the type S1, and the f function returns values of the type S2, which is a subtype of S1. Because a value of any given type can be used anywhere where a value of its supertype is required, a value of type T returned by a function can be used in the code that expects a value of a supertype of T. Therefore, S2 <: S1 is required, not the more strict S2 == S1.
It is the other way round with parameter types. U2 <: U1 can be understood as follows: Before a called function can produce a result, it must be possible to call that function in the first place. The actual parameter type of the called function is known. If the formal parameter type is the same or looser, the function can still be called; if the formal parameter type is stricter, it may not be called. For example, the expression f(U2()) in the above code compiles because the actual parameter type, U2, is a subtype of the formal parameter type, U1.
Permanent Subtype Relationships
In Cangjie, some preset subtype relationships are permanent.
- A type
Tis always a subtype of itself, that is,T <: T. - The
Nothingtype is always a subtype of any other typeT, that is,Nothing <: T. - Any type
Tis a subtype of theAnytype, that is,T <: Any. - The type defined by any class is a subtype of
Object, that is, if classCexists,C <: Object.
Subtype Relationship From Transitivity
The subtype relationship is transitive. For example, the following code only explicitly defines that I2 <: I1, C <: I2, and Bool <: I2, but the subtype relationships C <: I1 and Bool <: I1 exist implicitly based on the transitivity of the subtype relationship.
interface I1 { }
interface I2 <: I1 { }
class C <: I2 { }
extend Bool <: I2 { }
Subtype Relationships of Generic Types
Generic types also have subtype relationships. For details, see Subtype Relationship of a Generic Type.
Type Conversions
Cangjie does not support implicit conversions between different types. (A value of any given type is naturally also a value of each of its supertypes. Therefore, a conversion to a supertype is not an implicit type conversion.) Type conversions must be performed explicitly. This section describes the conversions between the numeric types, conversion from Rune to UInt32 and conversion from integers to Rune, as well as the is and as operators.
Conversions Between Numeric Types
For numeric types, namely Int8, Int16, Int32, Int64, IntNative, UInt8, UInt16, UInt32, UInt64, UIntNative, Float16, Float32, and Float64, Cangjie provides the function call-like T(e) notation for obtaining a value of the type T that is mathematically equal to the value of the expression e, or is as close as possible to the latter when T is incapable of representing the value of e without a loss of precision. The type of the expression e and the type T may be any pair of the numeric types listed above.
The following example shows the type conversion between numeric types:
main() {
let a: Int8 = 10
let b: Int16 = 20
let r1 = Int16(a)
println("The type of r1 is 'Int16', and r1 = ${r1}")
let r2 = Int8(b)
println("The type of r2 is 'Int8', and r2 = ${r2}")
let c: Float32 = 1.0
let d: Float64 = 1.123456789
let r3 = Float64(c)
println("The type of r3 is 'Float64', and r3 = ${r3}")
let r4 = Float32(d)
println("The type of r4 is 'Float32', and r4 = ${r4}")
let e: Int64 = 1024
let f: Float64 = 1024.1024
let r5 = Float64(e)
println("The type of r5 is 'Float64', and r5 = ${r5}")
let r6 = Int64(f)
println("The type of r6 is 'Int64', and r6 = ${r6}")
}
The execution result of the preceding code is as follows:
The type of r1 is 'Int16', and r1 = 10
The type of r2 is 'Int8', and r2 = 20
The type of r3 is 'Float64', and r3 = 1.000000
The type of r4 is 'Float32', and r4 = 1.123457
The type of r5 is 'Float64', and r5 = 1024.000000
The type of r6 is 'Int64', and r6 = 1024
If T is an integer type, and the value of e, possibly after rounding, is not within the range of valid values of T, an arithmetic overflow occurs. By default, the implementation then throws an OverflowException, but may also be configured to wrap the result around or saturate it using the respective compiler options.
The rules for the conversion of a numeric value to a floating-point type follow the IEEE 754 standard.
Conversions from Rune to UInt32 And from Integers to Rune
The value of an expression r of the type Rune may be converted to the type UInt32 using the UInt32(r) notation. The result is equal to the Unicode scalar value of r.
The value of an expression i of any integer type may be converted to the type Rune using the Rune(i) notation. If the value of i is a valid Unicode scalar value, that is, it lies either within the range [0x0000, 0xD7FF] or [0xE000, 0x10FFFF], the conversion succeeds, yielding a character represented by that Unicode scalar value. Otherwise, a compile-time error is reported if the value of i could be determined during compilation, or an exception is thrown at run time.
The following example demonstrates type conversion between Rune and UInt32:
main() {
let x: Rune = 'a'
let y: UInt32 = 65
let r1 = UInt32(x)
let r2 = Rune(y)
println("The type of r1 is 'UInt32', and r1 = ${r1}")
println("The type of r2 is 'Rune', and r2 = ${r2}")
}
The execution result of the above code is as follows:
The type of r1 is 'UInt32', and r1 = 97
The type of r2 is 'Rune', and r2 = A
is and as Operators
A Cangjie program can employ the is operator to determine whether the type of an expression is a subtype of a particular type (which can be that type itself). Specifically, the value of an expression of the form e is T, where e may be any expression and T may be any type, is true if the run-time type of e is a subtype of T, and false otherwise.
The following example shows how to use the is operator:
open class Base {
var name: String = "Alice"
}
class Derived <: Base {
var age: UInt8 = 18
}
main() {
let a = 1 is Int64
println("Is the type of 1 'Int64'? ${a}")
let b = 1 is String
println("Is the type of 1 'String'? ${b}")
let b1: Base = Base()
let b2: Base = Derived()
var x = b1 is Base
println("Is the type of b1 'Base'? ${x}")
x = b1 is Derived
println("Is the type of b1 'Derived'? ${x}")
x = b2 is Base
println("Is the type of b2 'Base'? ${x}")
x = b2 is Derived
println("Is the type of b2 'Derived'? ${x}")
}
The execution result of the above code is as follows:
Is the type of 1 'Int64'? true
Is the type of 1 'String'? false
Is the type of b1 'Base'? true
Is the type of b1 'Derived'? false
Is the type of b2 'Base'? true
Is the type of b2 'Derived'? true
The as operator can be used to attempt a conversion of the value of an expression to a specific type. As the attempt may fail, the value produced by the as operator has an Option type. Specifically, the value of an expression of the form e as T, where e may be any expression and T may be any type, is Option<T>.Some(e) iff the run-time type of e is a subtype of T. Otherwise, the value of e as T is Option<T>.None.
The following example shows how to use the as operator (the result of the as operator is indicated in the comments):
open class Base {
var name: String = "Alice"
}
class Derived <: Base {
var age: UInt8 = 18
}
let a = 1 as Int64 // a = Option<Int64>.Some(1)
let b = 1 as String // b = Option<String>.None
let b1: Base = Base()
let b2: Base = Derived()
let d: Derived = Derived()
let r1 = b1 as Base // r1 = Option<Base>.Some(b1)
let r2 = b1 as Derived // r2 = Option<Derived>.None
let r3 = b2 as Base // r3 = Option<Base>.Some(b2)
let r4 = b2 as Derived // r4 = Option<Derived>.Some(b2)
let r5 = d as Base // r5 = Option<Base>.Some(d)
let r6 = d as Derived // r6 = Option<Derived>.Some(d)
Generic Overview
In the Cangjie programming language, "generics" is a common term for parameterized types and functions, in the definitions of which certain types are left unspecified. Those types are specified each time such a generic type or function is used. Essentially, each generic type or function defines a set of regular types or functions, with one entry for each valid combination of those unspecified types.
The most common examples of generic types are container types such as Array<T> or Set<T>. Take the array type as an example. Arrays must be capable of storing elements of different types. At the same time, the set of operations on all arrays is the same and does not depend on their element types. It would be tedious to define a separate array type with all its members for each element type. Fortunately, Cangjie enables us to add a type parameter <T> to the Array type declaration and substitute particular element types instead of T at points of use, thus avoiding code duplication.
In Cangjie, class, interface, struct, and enum types, as well as functions, can be declared with type parameters. In other words, entities of all those kinds can be generic.
For the convenience of subsequent discussion, let's define the following common terms:
- Type parameter: An identifier denoting a type that needs to be specified during usage of the parameterized type or function. Type parameters are usually enclosed in angle brackets
< >and placed immediately after the name of the generic type or function being declared. - Type variable: An identifier referencing a type parameter of a generic user type or function within its declaration.
- Type argument: A particular type specified when a generic type of function is used.
- Type constructor: A type that requires zero, one, or multiple types as arguments.
For example, a generic list type can be declared and used like this:
class List<T> {
var elem: Option<T> = None
var tail: Option<List<T>> = None
}
func sumInt(a: List<Int64>) { }
In the above code, T in List<T> is a type parameter. T in elem: Option<T> and tail: Option<List<T>> is a type variable. In the parameters of the sumInt function, Int64 in List<Int64> is the type argument of List. List is a type constructor. List<Int64> uses the Int64 type argument to construct a concrete List type for the Int64 type.
Generic Functions
If a function declares one or more type parameters, it is called a generic function. Syntactically, type parameters follow the function name and are enclosed in angle brackets < >. Multiple type parameters are separated by commas ,.
Global Generic Functions
You may declare a global function as generic by using the angle brackets < > enclosing one or more type parameters after the function name. Then you may reference the type parameters in the formal parameters of the function, return type, and function body. For example, the identity function can be defined for any type T as follows:
func id<T>(a: T): T {
return a
}
In the above definition, <T> is the type parameter of the function, (a: T) is the formal parameter list of the function declaration, in which T is a type variable that corresponds to the type parameter of the id function declaration. The T type variable is then also used as the return type of the id function. Now for any type T there exists a global function id of type (T) -> T that simply returns is parameter.
The next example is more complex. In it, a generic function composition function is defined. That function has three type parameters T1, T2, T3, and is used to compose two functions of types (T1) -> T2 and (T2) -> T3 into one function of the type (T1) -> T3:
func composition<T1, T2, T3>(f: (T1) -> T2, g: (T2) -> T3): (T1) -> T3 {
return {x: T1 => g(f(x))}
}
Because composition<T1, T2, T3> is a generic function, it may compose two functions of any types, as long as each of them has a single formal parameter and the return value type of the first function is also the type of the sole formal parameter of the other. For instance, (Int32) -> Bool, (Bool) -> Int64 or (Int64) -> Rune, (Rune) -> Int8.
func times2(a: Int64): Int64 {
return a * 2
}
func plus10(a: Int64): Int64 {
return a + 10
}
func times2plus10(a: Int64) {
return composition<Int64, Int64, Int64>(times2, plus10)(a)
}
main() {
println(times2plus10(9))
return 0
}
Here, two (Int64) -> Int64 functions are composed. We multiply 9 by 2 and then add 10 to obtain the result 28.
28
Local Generic Functions
A local function can also be generic. For example, the id generic function can be nested and defined in other functions.
func foo(a: Int64) {
func id<T>(a: T): T { a }
func double(a: Int64): Int64 { a + a }
return (id<Int64> ~> double)(a) == (double ~> id<Int64>)(a)
}
main() {
println(foo(1))
return 0
}
Due to the unit element property of id, the id<Int64> ~> double and double ~> id<Int64> functions are equivalent, and the result is true.
true
Generic Member Functions
Generic Instance Member Functions
The instance member functions of classes, structs, and enums can be generic. For example:
class C {
func foo<T>(a: T): Unit where T <: ToString {
println("${a}")
}
}
struct S {
func bar<T>(a: T): Unit where T <: ToString {
println("${a}")
}
}
enum E {
| X | Y
func baz<T>(a: T): Unit where T <: ToString {
println("${a}")
}
}
main() {
var c = C()
var s = S()
var e = E.X
c.foo(10) // foo<Int64> is inferred
s.bar("abc") // bar<String> is inferred
e.baz(false) // baz<Bool> is inferred
return 0
}
Notes:
- The
whereclauses between the return value types and bodies of the generic member functions are called type constraints. They narrow down the choice of valid type arguments by specifying a superclass and/or one or more interfaces that the respective type argument(s) must respectively inherit or implement. In the above example,where T <: ToStringmeans that the type argument forTmust be a type that implements theToStringinterface. For details about generic constraints, see Generic Constraints.- The Cangjie compiler may infer the type arguments of generic function calls from actual parameter types in most cases, relieving the developer from the need to them explicitly, as in
c.foo<Int64>(10).
The above program outputs the following:
10
abc
false
It is worth noting that the generic instance member functions declared in a class cannot be modified with open, and the following instance member functions cannot be generic at all:
- Interface member functions, regardless of whether they have a default implementastion,
- Abstract member functions of abstract classes, and
- Operator overloading functions:
abstract class A {
public func foo<T>(a: T): Unit where T <: ToString // Error: abstract generic function not allowed in abstract class
}
open class C <: A {
public open func bar<T>(a: T): Unit where T <: ToString { // Error: generic function cannot have 'open' modifier
println("${a}")
}
}
interface I {
func baz<T>(a: T): Unit where T <: ToString { // Error: non-static generic function not allowed in interface
println("${a}")
}
func qux<T>(a: T): Unit where T <: ToString // Error: non-static generic function not allowed in interface
}
However, it is also important to distinguish between generic member functions and member functions of generic types that do not have their own type parameters:
abstract class A<T> where T <: ToString {
public func foo(a: T): Unit // OK
}
open class C<T> <: A<T> where T <: ToString {
public open func foo(a: T): Unit { // OK
println("${a}")
}
}
interface I<T> where T <: ToString {
func bar(a: T): Unit { // OK
println("${a}")
}
func baz(a: T): Unit // OK
}
class D<T> <: C<T> & I<T> where T <: ToString {
public func baz(a: T): Unit { // OK
println("${a}")
}
}
main() {
D().foo(0)
D().bar("bar")
D().baz(true)
}
The above program compiles and prints
0
bar
true
When a type is extended using an extend declaration, the functions in the extension can also be generic. For example, we can add a generic member function to the Int64 type.
extend Int64 {
func printIntAndArg<T>(a: T) where T <: ToString {
println(this)
println("${a}")
}
}
main() {
var a: Int64 = 12
a.printIntAndArg<String>("twelve")
}
The program outputs the following.
12
twelve
Generic Static Member Functions
Generic static member functions can be defined in interfaces, classes, structs, enums, and extends. For example, in the following ToPair class, a tuple is returned from ArrayList:
import std.collection.*
class ToPair {
public static func fromArray<T>(l: ArrayList<T>): (T, T) {
return (l[0], l[1])
}
}
main() {
var res: ArrayList<Int64> = ArrayList([1,2,3,4])
var a: (Int64, Int64) = ToPair.fromArray<Int64>(res)
return 0
}
Generic Interfaces
Interfaces can be declared as generic. Take the Iterable<E> interface defined in the standard library as an example. Its member function iterator needs to return a value of the type Iterator<E>, a traversal object for a container or sequence. Iterator<E> is also a generic interface, which includes the next member function that returns the next element from the underlying. The return value type of the next member function needs to be specified only at points of use. The type parameter E of Iterator<E> serves that need:
public interface Iterable<E> {
func iterator(): Iterator<E>
}
public interface Iterator<E> <: Iterable<E> {
func next(): Option<E>
}
public interface Collection<T> <: Iterable<T> {
prop size: Int64
func isEmpty(): Bool
}
Generic Classes
In Generic Interfaces, we have learned the definition and usage of generic interfaces. In this section, we will delve into the definition and usage of generic classes.
As shown in the following example, the type of the Node key-value pair in the Map type can be defined using a generic class:
public open class Node<K, V> where K <: Hashable & Equatable<K> {
public var key: Option<K> = Option<K>.None
public var value: Option<V> = Option<V>.None
public init() {}
public init(key: K, value: V) {
this.key = Option<K>.Some(key)
this.value = Option<V>.Some(value)
}
}
Because the key and value types may be different, Node requires two type parameters: K and V. For a map to work, it must be possible to test a pair of key values for equality, and for it to work fast it must also be possible to obtain a hash sum of a key value. Enforcing those requirements is the where K <: Hashable & Equatable<K> constraint placed on the key type, which indicates that a valid type argument for K must implement the Hashable and Equatable<K> interfaces. For details about generic constraints, see Generic Constraints.
Generic Structs
Generic structs are quite close to generic classes. The following code uses a struct to define a type similar to a 2-tuple.
struct Pair<T, U> {
let x: T
let y: U
public init(a: T, b: U) {
x = a
y = b
}
public func first(): T {
return x
}
public func second(): U {
return y
}
}
main() {
var a: Pair<String, Int64> = Pair<String, Int64>("hello", 0)
println(a.first())
println(a.second())
}
The program outputs the following.
hello
0
In Pair<T, U>, the first and second functions are provided to obtain the first and second elements of the "(T, U) tuple type-alike", so their return value types are respectively T and U type variables.
Generic Enums
In the Cangjie programming language, one of the most commonly used examples of generic enum types is the Option type (see Option Types). The Option type is used to represent a value of some other type that may be present or absent. The absence of a value can be used, for instance, to signify a calculation failure for a numeric type when the specific kind of failure does not matter. Because it is desirable to support the possible value absence for any underlying type, Option is best implemented as a generic type, Option<T>:
package core // `Option` is defined in core.
public enum Option<T> {
Some(T)
| None
public func getOrThrow(): T {
match (this) {
case Some(v) => v
case None => throw NoneValueException()
}
}
...
}
It is apparent that Option<T> has two constructors: one is Some(T), which indicates that a value is present (a normal result in the calculation example above). The other is None, which would indicate the absence of a result due to a failure. The getOrThrow instance function may be used to obtain the internal value v of a Some(v), or have a NoneValueException thrown if there is no value, i.e. the instance is None.
Assume we want to define a safe division function, because a division calculation may fail. If the divisor is 0, safeDiv returns None, otherwise it returns the result of division wrapped in Some:
func safeDiv(a: Int64, b: Int64): Option<Int64> {
var res: Option<Int64> = match (b) {
case 0 => None
case _ => Some(a/b)
}
return res
}
In this way, when the divisor is 0, the function won't throw an arithmetic operation exception during execution.
Subtype Relationship of a Generic Type
Instantiated generic types, that is, generic types supplied with type arguments that have no type variables, also have subtype relationships. The following code is used as an example.
interface I<X, Y> { }
class C<Z> <: I<Z, Z> { }
We can obtain C<Bool> <: I<Bool, Bool>, C<D> <: I<D, D> for certain type D, etc., based on line 3. Line 3 denotes that C<Z> <: I<Z, Z> is true for any type Z without type variables.
However, for the following code:
open class C { }
class D <: C { }
interface I<X> { }
I<D> <: I<C> is not true, even though D <: C is true. This is because in Cangjie, user-defined type constructors are invariant with respect to their type parameters (see the below subsection).
Type Variance
Type variance is defined as follows: If A and B are (instantiated) types, and T is a type constructor with a type parameter X (for example, interface T<X>), then
- When
T(A) <: T(B)if and only ifA = B,Tis invariant with respect toX. - When
T(A) <: T(B)if and only ifA <: B,Tis covariant with respect toX. - When
T(A) <: T(B)if and only ifB <: A,Tis contravariant with respect toX.
In the current version of Cangjie, all user-defined generic types are invariant over all their type parameters. Therefore, for a given interface I<X> and types A and B, we can obtain I<A> <: I<B> if and only if A = B. Conversely, if we know that I<A> <: I<B>, we can also deduce that A = B.
Note:
The built-in types are excluded from the above: built-in tuple types are covariant over each of their element types, and built-in function types are contravariant over their parameter types and covariant over their return types.
Invariance limits the expressiveness of a programming language, but at the same time prevents some safety issues, such as the problem of covariant arrays throwing runtime exceptions that occurs in Java.
Type Alias
A type notation can be inconveniently long and cumbersome, whether simply because the type name is long, the type itself is complex, or a mixture of the two. Complex types are generic type instantiations, tuple types and function types. Here is a type that includes all three:
(HashMap<Particle, (Position, Speed)>, Int64) -> Option<Collision>
In such cases, we can use a type alias to give the type a (more suitable) name:
type I64 = Int64
The definition of a type alias starts with the keyword type, followed by an identifier that is the type alias (I64 in the preceding example), the equals sign =, and the type to be aliased (Int64 in the preceding example).
A type alias can be defined only at the top level of a source file, and the original type must be visible at the location of the alias definition. For example, in the following example, an error is reported when the alias of Int64 is defined in main. Defining an alias for the LongNameClassB type when the original type is invisible also causes an error.
main() {
type I64 = Int64 // Error, type aliases can only be defined at the top level of a source file
}
class LongNameClassA { }
type B = LongNameClassB // Error, type 'LongNameClassB' is not defined
Direct or indirect circular references are not allowed in type alias definitions.
type A = (Int64, A) // Error, 'A' refers to itself
type B = (Int64, C) // Error, 'B' and 'C' are circularly referred
type C = (B, Int64)
A type alias does not define a new type, but simply functions as an alternative name for the original type. It can be used in the following scenarios:
-
When the type alias is used as a type, for example:
type A = B class B {} var a: A = B() // Use typealias A as type B -
When the type alias refers to a class or struct, it can be used as the constructor name.
type A = B class B {} func foo() { A() } // Use type alias A as constructor of B -
When the type alias refers to a class, interface, or struct, it can be used as the name to access static members or functions.
type A = B class B { static var b : Int32 = 0; static func foo() {} } func foo() { A.foo() // Use A to access static method in class B A.b } -
When the type alias refers to an enum, it can be used as the type name for accessing a constructor of the enum.
enum TimeUnit { Day | Month | Year } type Time = TimeUnit var a = Time.Day var b = Time.Month // Use type alias Time to access constructors in TimeUnit
A notable exception is that a user-defined type alias cannot be used as the type name in a type conversion expression. The following is an example:
type MyInt = Int32
MyInt(0) // Error, no matching function for operator '()' function call
Generic Alias
Type aliases can also declare type parameters, but cannot use where to declare constraints on parameters. For details about generic constraints, see Generic Constraints.
When the name of a generic type is too long, we can declare a shorter type alias for it. For example, if a type is named RecordData, it can be abbreviated as RD.
struct RecordData<T> {
var a: T
public init(x: T){
a = x
}
}
type RD<T> = RecordData<T>
main(): Int64 {
var struct1: RD<Int32> = RecordData<Int32>(2)
return 1
}
Then, we can use RD<Int32> to refer to the RecordData<Int32> type.
Generic Constraints
Generic constraints enable us to specify the operations and capabilities of type parameters in a generic function, class, interface, enum, or struct declaration. The member functions of type variables can be called only if the appropriate constraints are declared. Generic parameters need to be constrained in many scenarios. The following uses the id function as an example:
func id<T>(a: T) {
return a
}
Only the function parameter a can be returned, rather than a + 1 or println("${a}"), because the type argument may be any type. For example, id<Bool> would have type (Bool) -> Bool, so its parameter could not be added to an integer. Likewise, the println function cannot print values of arbitrary types. But if constraints are put on the type parameter, more operations on the values of that type are allowed within the body of the generic entity.
Constraints can be roughly categorized into interface constraints and subtype constraints. The syntax is to insert the keyword where followed by one or more comma-separated constraints before the body of a function or type declaration. A constraint in turn has the same syntax as the one used to denote inheritance and interface implementation, with a type variable to the left of <:. For example, if we have declared generic parameters T1 and T2, we can use where T1 <: Interface, T2 <: Type to declare generic constraints on them. Multiple constraints can be put on a type variable using ampersands &, as in where T1 <: Interface1 & Interface2.
Here is an example. Suppose the println function of Cangjie is not overloaded and only accepts values of the type String as its argument. We would naturally want to write a generic wrapper function that would convert its argument to a string and send it to the standard output via println. That wrapper, however, would only work for types that support conversion to a String. We could achieve what we want by constraining the respective type parameter with the ToString interface defined in core:
package core // `ToString` is defined in core.
public interface ToString {
func toString(): String
}
We can use that constraint when defining a function named genericPrint.
func genericPrint<T>(a: T) where T <: ToString {
println(a)
}
main() {
genericPrint<Int64>(10)
return 0
}
The output is:
10
If the type argument of the genericPrint function does not implement the ToString interface, the compiler reports an error. This example attempts passing a function as a parameter.
func genericPrint<T>(a: T) where T <: ToString {
println(a)
}
main() {
genericPrint<(Int64) -> Int64>({ i => 0 })
return 0
}
If we compile the above program, the compiler would issue an error message about a generic type argument that does not satisfy the constraints. This is because the generic type argument of the genericPrint function does not satisfy the (Int64) -> Int64 <: ToString constraint.
In addition to representing constraints through interfaces, we can also use subtypes to constrain a generic type parameter. In the below example, we want to declare a zoo type Zoo<T>, where T is an Animal and must be constrained accordingly. That is, T must be a subclass of the abstract animal class Animal that declares a member function run. We then define concrete subclasses Dog and Fox implementing the run member function. In this way, in the Zoo<T> type, we can call the run member function for the animal instances stored in the animals array list.
import std.collection.*
abstract class Animal {
public func run(): String
}
class Dog <: Animal {
public func run(): String {
return "dog runs"
}
}
class Fox <: Animal {
public func run(): String {
return "fox runs"
}
}
class Zoo<T> where T <: Animal {
var animals: ArrayList<Animal> = ArrayList<Animal>()
public func addAnimal(a: T) {
animals.append(a)
}
public func allAnimalsRun() {
for(a in animals) {
println(a.run())
}
}
}
main() {
var zoo: Zoo<Animal> = Zoo<Animal>()
zoo.addAnimal(Dog())
zoo.addAnimal(Fox())
zoo.allAnimalsRun()
return 0
}
The program outputs the following.
dog runs
fox runs
Extension Overview
Extensions add new functions (but not data!) to existing types that are visible in the current package, without breaking their encapsulation. Any Cangjie type aside from function types, tuple types, and interfaces can be extended.
An extension can add any or all of the following to the type that it extends:
- Member functions
- Operator overloads
- Member properties
- Interface implementations
At the same time, the requirement to preserve the encapsulation of the original type imposes the following restrictions on extensions:
- An extension cannot add member variables to a type.
- An extension cannot add abstract member functions or properties to a type.
- Members added by extensions cannot hide, override or redefine the existing members of a type, nor can they be overridden/redefined in its subtypes.
- Extensions cannot access members modified by
privatein the extended type.
Extensions can be classified into direct extensions and interface extensions based on whether they make the extended type implement new interfaces. A direct extension does not include extra interfaces. An interface extension includes interfaces and can be used to add new functions while also implementing those interfaces, thus enhancing abstraction and flexibility.
Direct Extensions
The following example illustrates the syntactic structure of a simple extension:
extend String {
public func printSize() {
println("the size is ${this.size}")
}
}
In the above example, an extension is declared using the extend keyword, followed by the type being extended (String) and a member function printSize in the body enclosed in braces { }.
String gets extended with the printSize member function in the current package only. The function can be accessed for any instance of String in the current package as if it was a member function of String:
main() {
let a = "123"
a.printSize() // the size is 3
}
The result is as follows:
the size is 3
When the type being extended is a generic type, there are two syntaxes available for extending its function:
One is to extend a specific instantiated generic type. The keyword extend can be followed by a generic type that is completely instantiated. The added functions can be used only when the types fully match. In addition, the type arguments of all generic types involved must comply with the constraints defined for those generic types, if any.
In the below example, only the types implementing the ToString interface are valid type arguments for Foo<T>:
class Foo<T> where T <: ToString {}
extend Foo<Int64> {} // OK: Int64 implements ToString
class Bar {}
extend Foo<Bar> {} // Error: Bar does not implement ToString
The other syntax introduces a generic extension. It has type parameters enclosed in angle brackets < > after extend. Generic extensions can be used to extend generic types that are not instantiated or partially instantiated. The generic parameter declared after extend must be directly or indirectly used in the extended generic type. The functions added for these types can be used only when the types and constraints fully match.
For example, for MyList<T>:
class MyList<T> {
public let data: Array<T> = Array<T>()
}
extend<T> MyList<T> {} // OK
extend<R> MyList<R> {} // OK
extend<T, R> MyList<(T, R)> {} // OK
extend MyList {} // Error
extend<T, R> MyList<T> {} // Error
extend<T, R> MyList<T, R> {} // Error
For the extensions of generic types, you can declare additional generic constraints for the additional functionality to be available only for certain (combinations of) type arguments.
For example, we can define a pair type, which can store two elements of any types (similar to a tuple).
To ensure that the pair type indeed can contain elements of any type, its two type parameters should not have any constraints.
However, when each of the two element types supports equality testing with the equals member function, we would naturally like that instantiation of the pair type to do so as well. We can use an extension to implement an equals function for pairs with such element types.
As shown in the following code, the extension syntax is used to constrain that a pair can implement the equals function only when the types of both its elements support equals:
class Pair<T1, T2> {
var first: T1
var second: T2
public init(a: T1, b: T2) {
first = a
second = b
}
}
interface Eq<T> {
func equals(other: T): Bool
}
extend<T1, T2> Pair<T1, T2> where T1 <: Eq<T1>, T2 <: Eq<T2> {
public func equals(other: Pair<T1, T2>) {
first.equals(other.first) && second.equals(other.second)
}
}
class Foo <: Eq<Foo> {
public func equals(other: Foo): Bool {
true
}
}
main() {
let a = Pair(Foo(), Foo())
let b = Pair(Foo(), Foo())
println(a.equals(b)) // true
}
The result is as follows:
true
Interface Extensions
In the following example, the Array type does not implement the PrintSizeable interface. However, we can extend Array to add a member function printSize and implement PrintSizeable.
interface PrintSizeable {
func printSize(): Unit
}
extend<T> Array<T> <: PrintSizeable {
public func printSize() {
println("The size is ${this.size}")
}
}
Once an extension has been used to implement PrintSizeable for Array, within the current package it looks as if the interface was implemented at the time of the Array type definition.
Therefore, we can now use Array as an implementation type of PrintSizeable, as shown in the following code:
main() {
let a: PrintSizeable = Array<Int64>()
a.printSize() // 0
}
The result is as follows:
The size is 0
We can implement multiple interfaces within the same extension, separating them with &. The order of the interfaces does not matter.
As shown in the following code, we can implement I1, I2, and I3 for Foo in one extension:
interface I1 {
func f1(): Unit
}
interface I2 {
func f2(): Unit
}
interface I3 {
func f3(): Unit
}
class Foo {}
extend Foo <: I1 & I2 & I3 {
public func f1(): Unit {}
public func f2(): Unit {}
public func f3(): Unit {}
}
We can also declare additional generic constraints in the interface extension to satisfy specific interface requirements.
For example, we can make the Pair type implement the Eq interface, allowing Pair itself to conform to the Eq constraint, as shown in the following code:
class Pair<T1, T2> {
var first: T1
var second: T2
public init(a: T1, b: T2) {
first = a
second = b
}
}
interface Eq<T> {
func equals(other: T): Bool
}
extend<T1, T2> Pair<T1, T2> <: Eq<Pair<T1, T2>> where T1 <: Eq<T1>, T2 <: Eq<T2> {
public func equals(other: Pair<T1, T2>) {
first.equals(other.first) && second.equals(other.second)
}
}
class Foo <: Eq<Foo> {
public func equals(other: Foo): Bool {
true
}
}
main() {
let a = Pair(Foo(), Foo())
let b = Pair(Foo(), Foo())
println(a.equals(b)) // true
}
The result is as follows:
true
If the type being extended already contains some or all of the functions or properties required for it to implement the given interface, we do not need to re-implement those functions or properties in the extension. (More precisely, we cannot do that, because extensions can never hide, override or redefine the existing members.)
In the following example, we define a new interface Sizeable, implementing which enables obtaining the size of the implementing type instance via its member function size. Since we know that the type Array already contains such function, we can extend Array to implement Sizeable without actually adding a size function to the extension:
interface Sizeable {
prop size: Int64
}
extend<T> Array<T> <: Sizeable {}
main() {
let a: Sizeable = Array<Int64>()
println(a.size)
}
The result is as follows:
0
Access Rules
Modifiers in Extensions
Extensions themselves cannot have any modifiers.
In the following example, public appears in front of a direct extension of A. As a result, an error is reported during compilation.
public class A {}
public extend A {} // Error, expected no modifier before extend
Extension members can use the following modifiers: static, public, protected, internal, private, and mut.
- Members modified by
privatecan be used only within the extension and are not visible externally. - Members modified by
internalcan be used in the current package, its subpackages, and subpackages of subpackages. This is the default behavior. - Members modified by
protectedcan be accessed within the module (constrained by export rules). If the extended type is class, these members can also be accessed in the subclass definition of the class. - Members modified by
staticcan be accessed only via the type name, not via an instance object. - Extensions of a
structtype can definemutmember functions.
package p1
public open class A {}
extend A {
public func f1() {}
protected func f2() {}
private func f3() {}
static func f4() {}
}
main() {
A.f4()
var a = A()
a.f1()
a.f2()
}
An extension member definition cannot be modified with open, override, or redef. In other words, extension member functions and properties can only be added to a type, not override or redefine the inherited ones, and cannot themselves be overridden or redefined.
class Foo {
public open func f() {}
static func h() {}
}
extend Foo {
public override func f() {} // Error
public open func g() {} // Error
redef static func h() {} // Error
}
No Orphan Extensions Rule
Implementing, by extension, an interface defined in some other package for a type defined in yet another package can lead to confusion.
To prevent a type from inadvertently implementing an inappropriate interface, Cangjie does not allow defining orphan extensions. An orphan extension is one that is neither defined in the same package as the interface (including all interfaces in its inheritance chain) nor defined in the same package as the type being extended.
As shown in the following code, we cannot implement Bar from package b for Foo in package a while in package c:
We can only implement Bar for Foo in package a or package b.
// package a
public class Foo {}
// package b
public interface Bar {}
// package c
import a.Foo
import b.Bar
extend Foo <: Bar {} // Error
Access and Hiding in Extensions
Instance members of an extension can use this, the semantics of which remains consistent with the type definition. You can also omit this when accessing members. However, instance members of an extension cannot use super.
class A {
var v = 0
}
extend A {
func f() {
print(this.v) // Ok
print(v) // Ok
}
}
extend Int64 {
func times(x: Int64): Int64 {
this * x // OK: The type of 'this' is Int64
}
}
main() {
println(2.times(3)) // OK
}
If you compile and run the above program, the following will be printed to the standard output:
6
Extensions cannot access members modified by private in the extended type.
class A {
private var v1 = 0
protected var v2 = 0
}
extend A {
func f() {
print(v1) // Error
print(v2) // Ok
}
}
Extensions cannot hide any members of the type being extended:
class A {
func f() {}
}
extend A {
func f() {} // Error
}
In one package, a type can be extended for multiple times, and functions not modified by private in other extensions of the extended type can be directly called in the extension.
class Foo {}
extend Foo { // OK
private func f() {}
func g() {}
}
extend Foo { // OK
func h() {
g() // OK
f() // Error
}
}
However, extensions cannot hide any members added by other extensions:
class A {}
extend A {
func f() {}
}
extend A {
func f() {} // Error
}
When extending generic types, you can use additional generic constraints so as to make the extension available only for particular combinations of type arguments of the type. The visibility rules between any two extensions of a generic type are as follows:
- If two extensions have the same constraints, they are mutually visible, meaning their non-
privatefunctions and properties can be directly used in each other's contexts. - If the constraints are different but have an inclusion relationship, the extension with the looser constraints is visible to the one with the stricter constraints, but not vice versa.
- If the constraints are different enough for there to be no inclusion relationship, the two extensions are invisible to each other.
Example: Suppose there are two extensions of the same type E<X>, where the constraints on X in extension 1 are stricter than those in extension 2. In this case, functions and properties in extension 1 are not visible to extension 2, but those in extension 2 are visible to extension 1.
open class A {}
class B <: A {}
class E<X> {}
interface I1 {
func f1(): Unit
}
interface I2 {
func f2(): Unit
}
extend<X> E<X> <: I1 where X <: B { // extension 1
public func f1(): Unit {
f2() // OK
}
}
extend<X> E<X> <: I2 where X <: A { // extension 2
public func f2(): Unit {
f1() // Error
}
}
Importing and Exporting Extensions
Extensions may be imported and exported only along with the types they extend. Described in this section are the additional restrictions that preserve encapsulation.
A direct extension is exported only if the extension itself and the type it extends are defined in the same package, and the extended type, as well as types used as generic constraints anywhere in the extension, if any, are modified with either public or protected.
Other direct extensions cannot be exported and can only be used within the package in which they are defined.
As shown in the following code, Foo is a type modified by public, and f and Foo are in the same package. Therefore, f is exported together with Foo. However, g and Foo are not in the same package. Therefore, g is not exported.
// package a
public class Foo {}
extend Foo {
public func f() {}
}
// package b
import a.*
extend Foo {
public func g() {}
}
// package c
import a.*
import b.*
main() {
let a = Foo()
a.f() // OK
a.g() // Error
}
For interface extensions, there are two cases:
- If the interface extension and the type being extended are in the same package, the extension will be exported together with the type regardless of the access modifiers of the interface(s) implemented by the extension, and its members will be accessible without importing the interface(s).
- If the interface extension is in a different package from the type being extended, the extension will be exported only if the interface type(s) and the types used as generic constraints, if any, are visible outisde the package.
As shown in the following code, both Foo and I are modified by public. Therefore, the extension of Foo can be exported.
// package a
public class Foo {}
public interface I {
func g(): Unit
}
extend Foo <: I {
public func g(): Unit {}
}
// package b
import a.*
main() {
let a: I = Foo()
a.g()
}
Similar to exporting extensions, importing them does not require an explicit use of import. You only need to import the types being extended and, possibly, interfaces to import all accessible extensions automatically.
As shown in the following code, in package b you only need to import Foo itself to use the function f defined in an extension of Foo.
For interface extensions, you need to import both the types being extended and the interfaces of extensions at the same time. Therefore, in package c, you must import both Foo and I to use the function g in the respective extension.
// package a
public class Foo {}
extend Foo {
public func f() {}
}
// package b
import a.Foo
public interface I {
func g(): Unit
}
extend Foo <: I {
public func g() {
this.f() // OK
}
}
// package c
import a.Foo
import b.I
func test() {
let a = Foo()
a.f() // OK
a.g() // OK
}
Basic Collection Type Overview
In the most general sense, a collection is an abstract data type representing a grouping of elements of the same type. Each particular collection type provides a specific set of operations and possesses unique performance and memory footprint characteristics.
We have already discussed one widely used collection type, Array, which is a fixed-size linearly indexed sequence of elements (see Array for details). In this chapter, we'll take a closer look at a few more basic collection types commonly used in Cangjie programs: ArrayList, HashSet, and HashMap.
Among those four types, you would normally select the most suitable for the problem at hand:
Array, if you do not need to add or delete elements, but possibly need to modify elementsArrayList, if you need to frequently add, delete, query, and modify elementsHashSet, if you want each element to be uniqueHashMap, if you want to store a series of key-value mappings
The following table compares the basic features of these types.
| Type name | Mutable elements | Adding/Deleting Elements | Element uniqueness | Ordered sequence |
|---|---|---|---|---|
Array<T> | Y | N | N | Y |
ArrayList<T> | Y | Y | N | Y |
HashSet<T> | N | Y | Y | N |
HashMap<K, V> | K: N, V: Y | Y | K: Y, V: N | N |
ArrayList
To use the ArrayList type, you need to import the collection package:
import std.collection.*
ArrayList is a generic type, so Cangjie uses ArrayList<T> to denote it, where T is the element type. T can be any type or a type variable.
ArrayList has excellent capacity expansion capability and is applicable to scenarios where elements must be stored sequentially and be directly accessible by their position in the sequence, as in an Array, but in addition need to be frequently added to, and removed from, the sequence. Compared with Array, ArrayList can add and remove elements in place, without copying the elements left intact to a newly created instance.
ArrayList is a reference type: all references to the same ArrayList instance share the same elements and are modified in a unified manner. See Modifying an ArrayList for details.
var a: ArrayList<Int64> = ... // ArrayList whose element type is Int64
var b: ArrayList<String> = ... // ArrayList whose element type is String
As generic types in Cangjie are invariant, two instantiations of ArrayList with different element types are themselves different, incompatible types, even if their element types are in a subtype relationship. Therefore, values of those two types cannot be "cross-assigned" to variables.
Therefore, the following continuation of the last example is invalid:
b = a // Error: Type mismatch
In Cangjie, you use a constructor to create an ArrayList with a particular element type. The different constructors enable you to pre-allocate storage and/or initialize the elements.
// Create an empty ArrayList of strings:
let a = ArrayList<String>()
// Create an ArrayList of strings, pre-allocating space for 100 elements:
let b = ArrayList<String>(100)
// Create an ArrayList of three Int64 integers, containing elements 0, 1, and 2:
let c = ArrayList<Int64>([0, 1, 2])
// Populate a freshly created ArrayList with elements of another collection "c":
let d = ArrayList<Int64>(c)
// Create an ArrayList of two strings, initialized by the specified rule function:
let e = ArrayList<String>(2, {x: Int64 => x.toString()})
Accessing ArrayList Members
When you need to access each element of an ArrayList, you can use a for-in loop expression to traverse it.
import std.collection.*
main() {
let list = ArrayList<Int64>([0, 1, 2])
for (i in list) {
println("The element is ${i}")
}
}
Compiling and executing the above code outputs the following information:
The element is 0
The element is 1
The element is 2
When you need to know the number of elements in an ArrayList, you can use the size property to obtain that information.
import std.collection.*
main() {
let list = ArrayList<Int64>([0, 1, 2])
if (list.size == 0) {
println("This is an empty arraylist")
} else {
println("The size of arraylist is ${list.size}")
}
}
Compiling and executing the above code outputs the following information:
The size of arraylist is 3
When you want to access a single element at a specific position, you can use the index operator [ ]. The type of the index expression must be Int64. The index of the first element of a non-empty ArrayList is zero. You can access any element of an ArrayList from 0 to the position of the last element, which is one less than the value of the size property of the ArrayList. Using a negative number or a number greater than or equal to size as an index triggers a run-time exception.
let a = list[0] // a == 0
let b = list[1] // b == 1
let c = list[-1] // Runtime exception
ArrayList also supports the syntax of Range in indices. For details, see section Array.
Modifying an ArrayList
You can use the index operator [ ] to modify an ArrayList element at a certain position:
let list = ArrayList<Int64>([0, 1, 2])
list[0] = 3
ArrayList is a reference type. When an ArrayList is used as an expression, no copy is created. All references to the same ArrayListinstance share the same data. Therefore, modifications of an ArrayList instance element affect all references to that instance:
let list1 = ArrayList<Int64>([0, 1, 2])
let list2 = list1
list2[0] = 3
// list1 contains elements 3, 1, 2
// list2 contains elements 3, 1, 2
To add a single element to the end of an ArrayList, use the append member function. If you want to add multiple elements to the end at the same time, you can use the appendAll member function. That function can accept a value of another collection type (for example, Array), provided its element type is the same.
import std.collection.*
main() {
let list = ArrayList<Int64>()
list.append(0) // list contains element 0
list.append(1) // list contains elements 0, 1
let li = [2, 3]
list.appendAll(li) // list contains elements 0, 1, 2, 3
}
You can use the insert and insertAll member functions in a similar manner to insert a specified element, or all elements of a collection with the same element type, at a specific position. The size of the ArrayList first increases accordingly and the elements at and to the right of the specified index are moved towards the end of the resized ArrayList to make space for the element(s) being inserted.
let list = ArrayList<Int64>([0, 1, 2]) // list contains elements 0, 1, 2
list.insert(1, 4) // list contains elements 0, 4, 1, 2
To delete an element from an ArrayList, you use its remove member function, specifying the index of the element to be deleted. The subsequent elements, if any, are then moved to fill the space, and the size property is decremented.
let list = ArrayList<String>(["a", "b", "c", "d"]) // list contains the elements "a", "b", "c", "d"
list.remove(1) // Delete the element at index 1, now the list contains elements "a", "c", "d"
Increasing the Size of an ArrayList
Each ArrayList reserves a certain amount of memory to hold its contents. When we add elements to an ArrayList so that its reserved capacity would be exceeded, the ArrayList allocates a larger memory area and copies all its elements to that new memory. This growth strategy means that operations adding elements have higher performance costs when they trigger such reallocation, but as the reserved memory of the ArrayList increases, such operations occur less frequently.
If you know how many elements will be added to an ArrayList, you can have it pre-allocate a sufficient amount of memory before adding elements to avoid intermediate reallocation, which improves performance.
import std.collection.*
main() {
let list = ArrayList<Int64>(100) // Allocate space at once
for (i in 0..100) {
list.append(i) // Does not trigger reallocation of space
}
list.reserve(100) // Prepare more space
for (i in 0..100) {
list.append(i) // Does not trigger reallocation of space
}
}
HashSet
To use the HashSet type, you need to import the collection package.
import std.collection.*
You can use the HashSet type to construct a collection that contains only unique elements.
HashSet is a generic type, hence Cangjie uses HashSet<T> to denote it, where T is the element type of the HashSet. T must be a type that implements the Hashable and Equatable<T> interfaces, e.g. a numeric type or String, or a type variable with the respective constraints.
var a: HashSet<Int64> = ... // HashSet whose element type is Int64
var b: HashSet<String> = ... // HashSet whose element type is String
Two HashSet instantiations with different element types are different types and their values cannot be "cross-assigned". Continuing the last example, the following code is invalid.
b = a // Type mismatch
In Cangjie, you use a constructor to create a HashSet with a particular element type. The different constructors enable you to pre-allocate storage and/or initialize the elements.
// Create an empty HashSet of strings:
let a = HashSet<String>()
// Create an empty HashSet with the initial capacity of 100:
let b = HashSet<String>(100)
// Create a HashSet of Int64 integers, containing elements 0 and 1 (no duplicates):
let c = HashSet<Int64>([0, 1, 0])
// Use another collection to initialize a HashSet:
let d = HashSet<Int64>(c)
// Create a HashSet of Int64 integers and add 10 elements to it using a rule function:
let e = HashSet<Int64>(10, {x: Int64 => (x * x)})
Accessing HashSet Members
When you need to access each element of a HashSet, you can use the for-in loop expression for traversal.
import std.collection.*
main() {
let mySet = HashSet<Int64>([0, 1, 2])
for (i in mySet) {
println("The element is ${i}")
}
}
It should be noted that HashSet does not guarantee that its elements are arranged in the order in which they were inserted, or in any other particular order. Therefore, the order of traversal may be different from that of insertion.
With that in mind, compiling and executing the above code will output the following lines:
The element is 0
The element is 1
The element is 2
but not necessarily in the same order as above.
When you need to know the number of elements in a HashSet, you can use its size property to obtain that information:
import std.collection.*
main() {
let mySet = HashSet<Int64>([0, 1, 2, 1])
if (mySet.size == 0) {
println("This is an empty hashset")
} else {
println("The size of hashset is ${mySet.size}")
}
}
Compiling and executing the above code outputs the following information:
The size of hashset is 3
because, again, a HashSet contains no duplicates.
When you want to determine whether a particular value v is present among the elements of a HashSet, you can use its contains member function. If such an element exists, contains(v) returns true, otherwise, it returns false.
let mySet = HashSet<Int64>([0, 1, 2])
let a = mySet.contains(0) // a == true
let b = mySet.contains(-1) // b == false
Modifying a HashSet
HashSet is a mutable reference type. It provides functions for adding and removing elements.
To add a single element to a HashSet, use its put member function. If you want to add multiple elements at the same time, you can use the putAll member function, which accepts another collection type (for example, Array) with the same element type. If the element is not already present in the HashSet, the put function adds it. Otherwise, the put function has no effect.
let mySet = HashSet<Int64>() // mySet is empty
mySet.put(0) // mySet contains element 0
mySet.put(0) // mySet still contains only element 0
mySet.put(1) // mySet contains elements 0, 1
let li = [2, 3]
mySet.putAll(li) // mySet contains elements 0, 1, 2, 3
HashSet is a reference type. When a HashSet instance is used as an expression, no copying occurs. All references to the same HashSet instance share the same data.
Therefore, modifications of a HashSet affect all references to that instance.
let set1 = HashSet<Int64>([0, 1, 2])
let set2 = set1
set2.put(3)
// set1 contains elements 0, 1, 2, 3
// set2 contains elements 0, 1, 2, 3
To delete an element from a HashSet, you can use the remove member function to specify the element to be deleted. If there is no such element, remove has no effect.
let mySet = HashSet<Int64>([0, 1, 2, 3])
mySet.remove(1) // mySet contains elements 0, 2, 3
HashMap
To use the HashMap type, you need to import the collection package.
import std.collection.*
You can use the HashMap type to construct a collection of key-value pairs, where each key is unique.
A HashMap is a hash table that provides quick access to elements contained in it. Each element in the table is identified by its key, and the key can be used to access the corresponding value.
HashMap is a generic type, so Cangjie uses HashMap<K, V> to denote it. K is the key type of the HashMap. It must be a type that implements the Hashable and Equatable<K> interfaces, for example, a numeric type or String, or a type variable with the respective constraints. V is the value type of the HashMap, which can be any type.
var a: HashMap<Int64, Int64> = ... // HashMap whose key type is Int64 and value type is Int64
var b: HashMap<String, Int64> = ... // HashMap whose key type is String and value type is Int64
Two HashMap instantiations with different key and/or value types are different, incompatible types, so their values cannot be "cross-assigned". Continuing the last example, the following code is invalid:
b = a // Type mismatch
In Cangjie, you use a constructor to create a HashMap with particular key and value types. The different constructors enable you to pre-allocate storage and/or initialize the elements:
// Create an empty HashMap that maps strings to Int64 integers:
let a = HashMap<String, Int64>()
// Create a HashMap that maps strings to Int64 integers,
// and populate it with key-value pairs ("a", 0), ("b", 1), and ("c", 2):
let b = HashMap<String, Int64>([("a", 0), ("b", 1), ("c", 2)])
// Use a collection of 2-tuples of type (String, Int64) to populate a HashMap:
let c = HashMap<String, Int64>(b)
// Create an empty HashMap that maps strings to Int64 integers
// with the initial capacity of 10:
let d = HashMap<String, Int64>(10)
// Create a HashMap with Int64 being both the key and value type
// and add ten key-value pairs to it using a rule function:
let e = HashMap<Int64, Int64>(10, {x: Int64 => (x, x * x)})
Accessing HashMap Members
When you need to access each key-value pair of a HashMap, you can use the for-in loop expression to traverse it.
import std.collection.*
main() {
let map = HashMap<String, Int64>([("a", 0), ("b", 1), ("c", 2)])
for ((k, v) in map) {
println("The key is ${k}, the value is ${v}")
}
}
It should be noted that a HashMap does not guarantee that its elements are arranged in the order in which they were inserted, or in any other particular order. Therefore, the traversal order may be different from the insertion order.
Compiling and executing the preceding code will output the following lines:
The key is a, the value is 0
The key is b, the value is 1
The key is c, the value is 2
but not necessarily in the same order.
When you need to know the number of elements in a HashMap, you can use its size property to obtain that information.
import std.collection.*
main() {
let map = HashMap<String, Int64>([("a", 0), ("b", 1), ("c", 2)])
if (map.size == 0) {
println("This is an empty hashmap")
} else {
println("The size of hashmap is ${map.size}")
}
}
Compiling and executing the preceding code outputs the following:
The size of hashmap is 3
When you want to determine whether there is a key-value pair with the given key in a HashMap, you can use its contains member function. If a pair with the key k is present in the HashMap, contains(k) returns true, otherwise, it returns false.
let map = HashMap<String, Int64>([("a", 0), ("b", 1), ("c", 2)])
let a = map.contains("a") // a == true
let b = map.contains("d") // b == false
When you want to access the value corresponding to the given key, you can use the index operator [ ] (the index expression must be of the key type). Using a key that is not present in the HashMap as an index triggers a run-time exception.
let map = HashMap<String, Int64>([("a", 0), ("b", 1), ("c", 2)])
let a = map["a"] // a == 0
let b = map["b"] // b == 1
let c = map["d"] // Runtime exception
Modifying a HashMap
HashMap is a mutable type. It provides functions for modifying, adding, and deleting elements.
You can use the index operator [ ] to modify the value of a key:
let map = HashMap<String, Int64>([("a", 0), ("b", 1), ("c", 2)])
map["a"] = 3
To add a single key-value pair to a HashMap, use its put member function. To add multiple key-value pairs at the same time, use the putAll member function. If a pair with the given key is not already present in the HashMap, the put function adds it. Otherwise, the put function overwrites the old value associated with that key with the new value.
let map = HashMap<String, Int64>()
map.put("a", 0) // map contains the element ("a", 0)
map.put("b", 1) // map contains the elements ("a", 0), ("b", 1)
let map2 = HashMap<String, Int64>([("c", 2), ("d", 3)])
map.putAll(map2) // map contains the elements ("a", 0), ("b", 1), ("c", 2), ("d", 3)
In addition to using the put function, you can also directly add a new key-value pair to a HashMap, or update the value already associated with the given key, by using the index operator [ ] in an assignment expression:
let map = HashMap<String, Int64>([("a", 0), ("b", 1), ("c", 2)])
map["d"] = 3 // map contains the elements ("a", 0), ("b", 1), ("c", 2), ("d", 3)
HashMap is a reference type. When a HashMap is used as an expression, no copy is created. All references to the same HashMap instance share the same data.
Therefore, modifications of a HashMap instance affect all references to that instance:
let map1 = HashMap<String, Int64>([("a", 0), ("b", 1), ("c", 2)])
let map2 = map1
map2["a"] = 3
// map1 contains the elements ("a", 3), ("b", 1), ("c", 2)
// map2 contains the elements ("a", 3), ("b", 1), ("c", 2)
To delete an element from a HashMap, you can use its remove member function to specify the key to be deleted from the HashMap along with the associated value. If there is no such key, nothing happens.
let map = HashMap<String, Int64>([("a", 0), ("b", 1), ("c", 2), ("d", 3)])
map.remove("d") // map contains the elements ("a", 0), ("b", 1), ("c", 2)
Iterable and Collections
We have learned that instances of Array, ArrayList and other collection types, as well as Range, can be traversed using a for-in loop expression. Can a user-defined type be traversed in a similar way? Yes.
Range, Array, ArrayList, etc., all use the Iterable interface to support the for-in syntax.
Iterable<T> is a built-in interface of the following form (non-essential code is omitted):
interface Iterable<T> {
func iterator(): Iterator<T>
...
}
The iterator member function, in turn, returns a value of the Iterator<T> type, another built-in interface type of the following form (again, only the relevant code is shown):
interface Iterator<T> <: Iterable<T> {
mut func next(): Option<T>
...
}
You can use the for-in syntax to traverse an instance of any type that implements the Iterable<T> interface for a certain type T (which can also be a type variable).
Assume that there is such a for-in expression:
let list = [1, 2, 3]
for (i in list) {
println(i)
}
It is actually equivalent to the following while loop expression:
let list = [1, 2, 3]
var it = list.iterator()
while (true) {
match (it.next()) {
case Some(i) => println(i)
case None => break
}
}
Another common method for traversing an instance of an Iterable type is to use while-let. For example, another equivalent writing method of the while code above is as follows:
let list = [1, 2, 3]
var it = list.iterator()
while (let Some(i) <- it.next()) {
println(i)
}
The Array, ArrayList, HashSet, and HashMap types all implement Iterable. Therefore, their instances can be used in a for-in or while-let expression. You can have the types that you define implement Iterable to enable such traversal.
Package Overview
As the size of a project grows, managing source code within a single large file becomes increasingly difficult. In this case, you can group the source code by functionality, separating code into distinct groups that are managed independently. Each group of code generates its own output file. You can import specific output files for the desired functionalities or combine various functions for more complex features for more efficient project management.
In Cangjie, a package is the minimum unit of compilation. Each package can independently produce output such as AST files, static library files, and dynamic library files. Each package has its own namespace, and top-level definitions or declarations (except for overloaded functions) cannot share the same name within a package. A package can contain multiple source files.
A module is a collection of packages and is the minimum unit of distribution for third-party developers. The program entry of a module must be in its root directory. A module can have at most one main as the program entry at the top level. The main either has no parameters or has parameters of the Array<String> type. The return type can be integer or Unit.
Package Declaration
In Cangjie, a package declaration starts with the keyword package, followed by package names from the root package to the current subpackage separated by dots .. Package and subpackage names must be valid common identifiers (that is, they cannot contain raw identifiers). For example:
package pkg1 // root package pkg1
package pkg1.sub1 // Subpackage sub1 of the root package pkg1
The package declaration must be in the first non-empty, non-commented line of the source file, and the package declarations of different source files in the same package must be consistent.
// file 1
// Comments are accepted
package test
// declarations...
// file 2
let a = 1 // Error, package declaration must appear first in a file
package test
// declarations...
The Cangjie package name should match the path of the current source file relative to the source code root directory src of the project, with dots . replacing the path separators. For example, if the source code of a package is in the src/directory_0/directory_1 directory and the root package name is pkg, the package declaration in the source code should be package pkg.directory_0.directory_1.
Note:
- The name of the directory where the package source files are located must be the same as the package name.
- The default name of the source code root directory is
src. - Source files located in the source root directory are permitted to have no package declaration. In such cases, the compiler will automatically assign the name
defaultto the package.
Assume that the source code directory structure is as follows:
// The directory structure is as follows:
src
`-- directory_0
|-- directory_1
| |-- a.cj
| `-- b.cj
`-- c.cj
`-- main.cj
The package declarations in the a.cj, b.cj, c.cj, and main.cj files can be the following:
// a.cj
// in file a.cj, the declared package name must correspond to relative path directory_0/directory_1.
package default.directory_0.directory_1
// b.cj
// in file b.cj, the declared package name must correspond to relative path directory_0/directory_1.
package default.directory_0.directory_1
// c.cj
// in file c.cj, the declared package name must correspond to relative path directory_0.
package default.directory_0
// main.cj
// file main.cj is in the module root directory and may omit package declaration.
main() {
return 0
}
In addition, a package declaration must avoid name conflicts. That is, a subpackage cannot have the same name as a top-level declaration in the current package.
The following are some incorrect examples:
// a.cj
package a
public class B { // Error, 'B' is conflicted with subpackage 'a.B'
public static func f() {}
}
// b.cj
package a.B
public func f {}
// main.cj
import a.B // ambiguous use of 'a.B'
main() {
a.B.f()
return 0
}
Visibility of Top-Level Declarations
In Cangjie, access modifiers can be used to control the visibility of top-level declarations such as types, global variables and global functions, known collectively as package members. There are four access modifiers in Cangjie: private, internal, protected, and public. The semantics of different access modifiers for top-level entities is as follows:
privatemembers are visible only in the current file and cannot be accessed from other files.internalmembers are visible only in the current package and its subpackages (including nested subpackages). These members can be accessed from the same package without being imported or from subpackages of the current package through imports.protectedmembers are visible only in the current module. Files in the same package can access these members without imports. Packages in the same module can access them through imports, but packages in different modules cannot access them.publicmembers are visible both inside and outside the module. Files in the same package can access these members without imports, and other packages can access them through imports.
| Modifier | File | Package and Subpackage | Module | All Packages |
|---|---|---|---|---|
private | Y | N | N | N |
internal | Y | Y | N | N |
protected | Y | Y | Y | N |
public | Y | Y | Y | Y |
The package declaration and import declarations may also have access modifiers discussed later in this chapter. The rules for access modifiers and default modifiers supported by different top-level declarations are as follows (The default modifiers can be explicitly specified, and are used when no access modifiers are specified):
package: supportsinternal,protected, andpublic, withpublicbeing the default modifier.import: supports all access modifiers, withprivatebeing the default modifier.- Other top-level declarations support all access modifiers, with
internalbeing the default modifier.
package a
private func f1() { 1 } // f1 is visible only in the current file.
func f2() { 2 } // f2 is visible only in the current package and its subpackages.
protected func f3() { 3 } // f3 is visible only in the current module.
public func f4() { 4 } // f4 is visible both inside and outside the current module.
The hierarchy of access levels in Cangjie is as follows: public > protected > internal > private. The level of the access modifier of a declaration cannot be higher than that of an entity used in the declaration. The following are some examples:
-
Parameters and return values in a function declaration:
// a.cj package a class C {} public func f1(a1: C) // Error, public declaration f1 cannot use internal type C. { return 0 } public func f2(a1: Int8): C // Error, public declaration f2 cannot use internal type C. { return C() } public func f3 (a1: Int8) // Error, public declaration f3 cannot use internal type C. { return C() } -
Variable declaration:
// a.cj package a class C {} public let v1: C = C() // Error, public declaration v1 cannot use internal type C. public let v2 = C() // Error, public declaration v2 cannot use internal type C. -
Inherited type in a class declaration:
// a.cj package a open class C1 {} public class C2 <: C1 {} // Error, public declaration C2 cannot use internal type C1. -
Interface for implementing a class:
// a.cj package a interface I {} public enum E <: I { A } // Error, public declaration uses internal types. -
Type argument of a generic type:
// a.cj package a public class C1<T> {} class C2 {} public let v1 = C1<C2>() // Error, public declaration v1 cannot use internal type C2. -
Upper bound of a class in the
whereconstraint:// a.cj package a interface I {} public class B<T> where T <: I {} // Error, public declaration B cannot use internal type I.
At the same time, however:
-
public-modified declarations can use any classes visible in the package in their initialization expressions or function bodies, includingpublic-modified classes and non-public-modified classes:// a.cj package a class C1 {} func f1(a1: C1) { return 0 } public func f2(a1: Int8) // Ok. { var v1 = C1() return 0 } public let v1 = f1(C1()) // Ok. public class C2 // Ok. { var v2 = C1() } -
public-modified top-level declarations can use anonymous functions or any top-level functions, includingpublic-modified classes and non-public-modified top-level functions.public var t1: () -> Unit = { => } // Ok. func f1(): Unit {} public let t2 = f1 // Ok. public func f2() // Ok. { return f1 } -
Built-in types such as
RuneandInt64are also modified bypublicby default.var num = 5 public var t3 = num // Ok.
Package Import
Using the import Statement to Import Declarations or Definitions from Other Packages
In Cangjie, you can use the import fullPackageName.itemName syntax to import a top-level declaration or definition from another package into a source file. That imported package member may then be used by its name throughout the file, except for scopes where its name is shadowed by another declaration or definition, if any. fullPackageName is the full path package name, and itemName is the name of the imported package member. Import declarations must be placed after the package declaration and before other declarations or definitions in the source file. For example:
package a
import std.math.*
import package1.foo
import {package1.foo, package2.bar}
If multiple itemName to be imported belong to the same fullPackageName, you can use the import fullPackageName.{itemName[, itemName]*} syntax. For example:
import package1.{foo, bar, fuzz}
This is equivalent to:
import package1.foo
import package1.bar
import package1.fuzz
In addition to importing a specific top-level declaration or definition using the import fullPackagename.itemName syntax, you can also use the import packageName.* syntax to import all visible top-level declarations and definitions of the packageName package. For example:
import package1.*
import {package1.*, package2.*}
Note:
importcan be modified by an access modifierprivate,internal,protected, orpublic(see Re-exporting an Imported Name below). Animportwithout an access modifier is equivalent to aprivate import.- The scope level of imported members is lower than that of members declared in the current package.
- If the module name or package name of an exported package is tampered with, causing it to differ from the name specified at the time of export, an error will occur during the import.
- Only top-level declarations and definitions visible to the current file can be imported. Importing invisible declarations or definitions will result in an error at the import location.
- As there is no need to import the declarations and definitions from the package to which the current source file belongs, the compiler treats such import as an error.
importis not allowed for packages with cyclic dependency. If a cyclic dependency exists between packages, the compiler reports an error.
The following is an example:
// pkga/a.cj
package pkga // Error, packages pkga pkgb are in circular dependencies.
import pkgb.*
class C {}
public struct R {}
// pkgb/b.cj
package pkgb
import pkga.*
// pkgc/c1.cj
package pkgc
import pkga.C // Error, 'C' is not accessible in package 'pkga'.
import pkga.R // OK, R is an external top-level declaration of package pkga.
import pkgc.f1 // Error, package 'pkgc' should not import itself.
public func f1() {}
// pkgc/c2.cj
package pkgc
func f2() {
/* OK, the imported declaration is visible to all source files of the same package
* and accessing import declaration by its name is supported.
*/
R()
// OK, accessing imported declaration by fully qualified name is supported.
pkga.R()
// OK, the declaration of current package can be accessed directly.
f1()
// OK, accessing declaration of current package by fully qualified name is supported.
pkgc.f1()
}
In Cangjie, an imported declaration or definition that has the same name as a top-level declaration or definition in the current package will be shadowed unless it constitutes an overloaded function. If it does constitute an overloaded function, function resolution during a function call follows the normal rules for overloaded functions.
// pkga/a.cj
package pkga
public struct R {} // R1
public func f(a: Int32) {} // f1
public func f(a: Bool) {} // f2
// pkgb/b.cj
package pkgb
import pkga.*
func f(a: Int32) {} // f3
struct R {} // R2
func bar() {
R() // OK, R2 shadows R1.
f(1) // OK, invoke f3 in current package.
f(true) // OK, invoke f2 in the imported package
}
Importing the core Package in Implicit Mode
Types such as String and Range can be used directly not because they are built into the language, but because the compiler automatically imports all public declarations from the core package into all source files in implicit mode.
Using "import as" to Rename the Imported File
Namespaces of different packages are separate, so it is possible to have top-level declarations with the same name in different packages. When importing multiple top-level declarations with the same name from different packages, you can use import packageName.name as newName to rename all but one of them to avoid conflicts. (Of course, you can also use import as for renaming even if there is no name conflict.) The rules for import as are as follows:
-
After you use
import asto rename an imported entity, the current package can use only the new name. -
If the new names conflict with names of members of the current package, and declarations corresponding to these names are functions, they are involved in function overloading; otherwise, a redefinition error occurs.
-
Packages can be renamed in
import pkg as newPkgNameformat to solve the name conflicts of packages with the same name in different modules.// a.cj package p1 public func f1() {} // d.cj package p2 public func f3() {} // b.cj package p1 public func f2() {} // c.cj package pkgc public func f1() {} // main.cj import p1 as A import p1 as B import p2.f3 as f // OK import pkgc.f1 as a import pkgc.f1 as b // OK func f(a: Int32) {} main() { A.f1() // OK, package name conflict is resolved by renaming package name. B.f2() // OK, package name conflict is resolved by renaming package name. p1.f1() // Error, the original package name cannot be used. a() // Ok. b() // Ok. pkgc.f1() // Error, the original name cannot be used. } -
If conflicting imported packages are not renamed, no error will occur in the
importstatement. However, an error will be reported during usage because the imported names are not unique. In this case, you can useimport asto define an alias or useimport fullPackageNameto import a package as the namespace.// a.cj package p1 public class C {} // b.cj package p2 public class C {} // main1.cj package pkga import p1.C import p2.C main() { let _ = C() // Error } // main2.cj package pkgb import p1.C as C1 import p2.C as C2 main() { let _ = C1() // Ok let _ = C2() // Ok } // main3.cj package pkgc import p1 import p2 main() { let _ = p1.C() // Ok let _ = p2.C() // Ok }
Re-exporting an Imported Name
During the development of a large-scale project with various functionalities, the following scenario is common: Package p2 uses a large number of declarations imported from package p1. For a package p3 to import package p2 and use its functions, the declarations from package p1 must also be visible to package p3. If p3 is required to import the declarations of p1 that are used in p2, the process becomes cumbersome. Therefore, it is desirable to simultaneously import package p2 and the declarations of p1 that are used in p2.
In Cangjie, import can be modified by the access modifiers private, internal, protected, and public. An import modified by public, protected, or internal can re-export the imported members (unless the imported members are unavailable in the package due to name conflicts or being shadowed). Other packages can directly import and use the entities re-exported by the current package according to visibility, without the need to import it from the original package.
private import: The imported content can be accessed only in the current file.privateis the default modifier ofimport. Animportwithout an access modifier is equivalent to aprivate import.internal import: The imported content can be accessed in the current package and its subpackages (including nested subpackages). Explicitimportis required for non-current packet access.protected import: The imported content can be accessed in the current module. Explicitimportis required for non-current packet access.public import: The imported content can be accessed externally. Explicitimportis required for non-current packet access.
In the following example, b is a subpackage of a, and a re-exports the f function that is defined in b through public import:
package a
public let x = 0
public import a.b.f
internal package a.b
public func f() { 0 }
import a.f // Ok
let _ = f() // Ok
It is worth noting that entire packages cannot be re-exported. If a package is imported by an import, the import cannot be modified by public, protected, or internal.
public import a.b // Error, cannot re-export package
Program Entry
The entry point of a Cangjie program is a special global function called main. Only one main is allowed at the top level of a package in the source files root directory.
If a module is compiled with the goal of generating an executable file, the compiler searches for main only at the top level of the source files root directory. If no main is found, the compiler reports an error. Otherwise, the compiler checks its parameters and return value types. Note that main cannot be modified by access modifiers. When a package is imported, the main defined in the package is not imported.
A main function that serves as the program entry point is declared without the func keyword and may either have no parameters or have one parameter of the Array<String> type. Its return value type can be either Unit or integer.
main without parameters:
// main.cj
main(): Int64 { // Ok.
return 0
}
main with parameters of the Array<String> type:
// main.cj
main(args: Array<String>): Unit { // Ok.
for (arg in args) {
println(arg)
}
}
After compiling the above example using cjc main.cj, run the ./main Hello, World command. The following information will be displayed:
Hello,
World
The following are some incorrect examples:
// main.cj
main(): String { // Error, return type of 'main' is not 'Integer' or 'Unit'.
return ""
}
// main.cj
main(args: Array<Int8>): Int64 { // Error, 'main' cannot be defined with parameter whose type is not Array<String>.
return 0
}
// main.cj
// Error, multiple 'main's are found in source files.
main(args: Array<String>): Int32 {
return 0
}
main(): Int8 {
return 0
}
Defining Exceptions
An exception is a special kind of error that can be captured and handled by the program. It is a general term for a series of abnormal behaviors that occur during program execution, for example, out-of-bounds array access, division by zero, arithmetic overflow, invalid input, and so on. To ensure correct operation and robustness, many software systems contain a large amount of code for error detection and error handling.
Exceptions break the normal execution flow of a program. Once an exception occurs, the program must handle it immediately, that is, transfer control from its normal function to the part that handles the exception. Cangjie provides an exception handling mechanism to handle various exceptions that may occur during program running.
In Cangjie, exception types are class types, and there are two base exception classes: Error and Exception.
Errorand its subclasses describe internal system errors and resource exhaustion errors. If an internal error occurs, you are notified to terminate the program safely.Exceptionand its subclasses describe exceptions caused by logic errors or I/O errors during program running, such as out-of-bounds array access or an attempt to open a file that does not exist. Such exceptions need to be captured and processed by the program.
You cannot customize exceptions by inheriting the Error class or any of its subclasses; they are reserved for the representation of built-in Cangjie errors. To create your own exception class, you can inherit the built-in Exception class or one of its subclasses. For example:
open class FatherException <: Exception {
public init() {
super("This is FatherException.")
}
public init(message: String) {
super(message)
}
public open override func getClassName(): String {
"FatherException"
}
}
class ChildException <: FatherException {
public init() {
super("This is ChildException.")
}
public open override func getClassName(): String {
"ChildException"
}
}
The following table lists the main functions of Exception and their descriptions.
| Function Type | Function and Description |
|---|---|
| Constructor | init() is the default constructor. |
| Constructor | init(message: String) can be used to specify a custom exception message. |
| Member attribute | open prop message: String returns the details about the exception. This message is initialized in the constructor of the exception class and is an empty string by default. |
| Member function | open func toString(): String returns the type name and details of the exception. The exception details call messages by default. |
| Member function | func getClassName(): String returns the user-defined class name. Rewrite this method for subclasses to return the subclass name. |
| Member function | func printStackTrace(): Unit prints stack trace information to the standard error stream. |
The following table lists the main functions of Error and their descriptions.
| Function Type | Function and Description |
|---|---|
| Member attribute | open prop message: String returns the details about the error. This message is initialized internally when an error occurs and is an empty string by default. |
| Member function | open func toString(): String returns the type name and details of the error. The error details call messages by default. |
| Member function | func printStackTrace(): Unit prints stack trace information to the standard error stream. |
Throwing and Handling Exceptions
The previous section described how to customize exceptions. This section shows how to throw and handle exceptions.
- An exception type is a class type. Therefore, you create an exception instance object just like you would do that with any other class. For example, the expression
FatherException()creates an exception of theFatherExceptiontype. - Cangjie provides the
throwexpression for throwing exceptions. It begins with thethrowkeyword, and the type of the expression that follows must be a subtype ofException(you cannot manually throw anErroreven though it is also an exception). For example, an arithmetic operation exception gets thrown whenthrow ArithmeticException("I am an Exception!")is executed. - Exceptions thrown by
throwexpressions need to be captured and handled. If an exception is not handled by the program, the system passes control to the default exception handler.
Exception handling is implemented by try expressions, which can be classified into the following types:
- Common
tryexpressions that do not involve automatic resource management try-with-resources expressions used for automatic resource management
Common try Expressions
A common try expression includes three parts: a try block, zero or more catch blocks, and an optional finally block.
-
A
tryblock starts with the keywordtryfollowed by a regular code block. The block, enclosed in a pair of curly braces{ }, defines a new local scope and can contain any expressions or declarations. Any exceptions thrown in thetryblock are captured and then an attempt is made to handle them by one of thecatchblocks that follow, if any. If there are nocatchblocks, or those that are present do not catch exceptions of the given type, the exception is re-thrown after thefinallyblock gets executed. -
A common
tryexpression can contain zero or more catch blocks. There must be afinallyblock when there is nocatchblock. Eachcatchblock starts with the keywordcatch, followed by acatchPatternand a block. ThecatchPatternmatches the exceptions to be captured through pattern matching. Once the exception matches, it gets handled by the block following the matching pattern, and othercatchblocks, if any, are ignored. When all the exception types that acatchblock can catch can be caught by acatchblock defined before it, a warning indicating that acatchblock is unreachable is reported. -
A
finallyblock starts with the keywordfinallythat is followed by a block. In principle, afinallyblock is mainly used to perform cleanup tasks, such as releasing resources. Ensure that no exception is thrown in thefinallyblock. The content of afinallyblock is executed regardless of whether an exception occurs (that is, whether an exception was thrown in thetryblock or not). If the exception was not caught and handled, it gets re-thrown after thefinallyblock is executed. If atryexpression contains at least onecatchblock, thefinallyblock is optional. Otherwise, it must contain afinallyblock.
The scopes of the try block and each of the catch blocks are independent of each other.
The following is a simple example of an expression with only try and catch blocks:
main() {
try {
throw NegativeArraySizeException("I am an Exception!")
} catch (e: NegativeArraySizeException) {
println(e)
println("NegativeArraySizeException is caught!")
}
println("This will also be printed!")
}
The execution result is as follows:
NegativeArraySizeException: I am an Exception!
NegativeArraySizeException is caught!
This will also be printed!
The scope level of the variable introduced by the catchPattern is the same as that of the variable in the block following that catch. If the same name is introduced in the catch block, a redefinition error is triggered. The following is an example:
main() {
try {
throw NegativeArraySizeException("I am an Exception!")
} catch (e: NegativeArraySizeException) {
println(e)
let e = 0 // Error, redefinition
println(e)
println("NegativeArraySizeException is caught!")
}
println("This will also be printed!")
}
The following is a simple example of a try expression with a finally block:
main() {
try {
throw NegativeArraySizeException("NegativeArraySizeException")
} catch (e: NegativeArraySizeException) {
println("Exception info: ${e}.")
} finally {
println("The finally block is executed.")
}
}
The execution result is as follows:
Exception info: NegativeArraySizeException: NegativeArraySizeException.
The finally block is executed.
The try expression can be used wherever an expression is allowed. The method of determining the type of the try expression is similar to that of determining the type of other multi-branch expressions such as if and match expressions. If the result of the try expression is used, its type is the minimum common parent type of the types of all branches except the finally branch. If there is no such common paretn type, a compilation error is reported.
For example, in the following code, the type of the try expression and variable x is the minimum common parent type D of E and D. C() in the finally branch is not involved in the calculation of the common parent type. If it were involved, the minimum common parent type would have changed to C.
open class C { }
open class D <: C { }
class E <: D { }
main () {
let x = try {
E()
} catch (e: Exception) {
D()
} finally {
C()
}
0
}
When the value of the try expression is not used, its type is Unit, and the types of its branches are not required to have a minimum common parent type.
try-with-resources Expressions
try-with-resources expressions are used to automatically release non-memory resources. Different from common try expressions, the catch and finally blocks in a try-with-resources expression are both optional. One or more ResourceSpecification can be inserted before the block following the try keyword to apply to a series of resources. ResourceSpecification does not affect the type of the entire try expression. Resources refer to objects at the language level. Therefore, ResourceSpecification is used to instantiate a series of objects. Separate multiple instances with commas ,.
The following is an example of a try-with-resources expression:
class R <: Resource {
public func isClosed(): Bool {
true
}
public func close(): Unit {
print("R is closed")
}
}
main() {
try (r = R()) {
println("Get the resource")
}
}
The output is as follows:
Get the resource
The variables introduced between the try keyword and the following block have the same scope as the variables defined in that block. If an entity with the same name is defined again in the block, a redefinition error is triggered.
class R <: Resource {
public func isClosed(): Bool {
true
}
public func close(): Unit {
print("R is closed")
}
}
main() {
try (r = R()) {
println("Get the resource")
let r = 0 // Error, redefinition
println(r)
}
}
The type of a variable introduced by a ResourceSpecification in a try-with-resources expression must implement the Resource interface and ensure that the isClosed function does not throw exceptions.
interface Resource {
func isClosed(): Bool
func close(): Unit
}
It should be noted that try-with-resources expressions do not need to contain any catch block or finally block, and you are advised not to manually release resources. No matter whether an exception occurs during the execution of a try block, all applicable resources are automatically released, and all exceptions generated during the execution are thrown. However, if you need to explicitly capture and handle exceptions that may be thrown in the try block or during resource application and release, you can still include catch and finally blocks in a try-with-resources expression.
class R <: Resource {
public func isClosed(): Bool {
true
}
public func close(): Unit {
print("R is closed")
}
}
main() {
try (r = R()) {
println("Get the resource")
} catch (e: Exception) {
println("Exception happened when executing the try-with-resources expression")
} finally {
println("End of the try-with-resources expression")
}
}
The output is as follows:
Get the resource
End of the try-with-resources expression
try-with-resources expressions are of the Unit type.
Advanced Operations of CatchPattern
In most cases, if you only want to capture exceptions of a certain type and its subtypes, you can use the type pattern of CatchPattern. However, if you need to process all exceptions in a unified manner (for example, errors are reported when exceptions occur), you can use the wildcard pattern of CatchPattern.
The type pattern has two syntax formats:
Identifier: ExceptionClass. This format can be used to capture exceptions of theExceptionClasstype and its subclasses, convert the captured exception instance toExceptionClass, and bind it to the variable defined byIdentifier. Then, the captured exception instance can be accessed through the variables defined byIdentifierin thecatchblock.Identifier: ExceptionClass_1 | ExceptionClass_2 | ... | ExceptionClass_n. This format can be used to combine multiple exception classes through the connector|. The connector|indicates an "or" relationship. This way, you can capture exceptions of theExceptionClass_1type and its subclasses, exceptions of theExceptionClass_2type and its subclasses, and so on, or exceptions of theExceptionClass_ntype and its subclasses (assuming thatnis greater than 1) in a singlecatchblock. When the type of the exception to be captured belongs to any type or its subtype in the "or" relationship, the exception is captured. However, the type of the captured exception cannot be statically determined in this case. Therefore, the captured exception is converted to the minimum common parent class of all types connected by|, and the exception instance is bound to the variable defined byIdentifier. Therefore, in this mode, the variable defined byIdentifiercan only be used in the catch block to access the member variables and member functions in the minimum common parent class ofExceptionClass_i (1 <= i <= n).
You can also use wildcards to replace Identifier in the type pattern. The only difference is that wildcards do not perform binding operations.
The following is an example:
main(): Int64 {
try {
throw IllegalArgumentException("This is an Exception!")
} catch (e: OverflowException) {
println(e.message)
println("OverflowException is caught!")
} catch (e: IllegalArgumentException | NegativeArraySizeException) {
println(e.message)
println("IllegalArgumentException or NegativeArraySizeException is caught!")
} finally {
println("finally is executed!")
}
return 0
}
Execution result:
This is an Exception!
IllegalArgumentException or NegativeArraySizeException is caught!
finally is executed!
The following is an example of "the type of the caught exception is the smallest common parent class of all types connected by |":
open class Father <: Exception {
var father: Int32 = 0
}
class ChildOne <: Father {
var childOne: Int32 = 1
}
class ChildTwo <: Father {
var childTwo: Int32 = 2
}
main() {
try {
throw ChildOne()
} catch (e: ChildTwo | ChildOne) {
println("ChildTwo or ChildOne?")
}
}
Execution result:
ChildTwo or ChildOne?
The syntax of wildcard pattern is _, which can capture any type of exception thrown in the try block of the same level. It is equivalent to e: Exception in the type pattern, that is, capture the exception defined by an Exception subclass, but it does not bind the exception to any variable. The following is an example:
// Catch with wildcardPattern.
try {
throw OverflowException()
} catch (_) {
println("catch an exception!")
}
Common Runtime Exceptions
Here are the most common exception classes built into Cangjie, which can be directly used by developers.
| Exception | Description |
|---|---|
ConcurrentModificationException | Exception caused by concurrent modification. |
IllegalArgumentException | Exception thrown when an invalid or incorrect parameter is passed. |
NegativeArraySizeException | Exception thrown when an array whose size is negative is created |
NoneValueException | Exception thrown when a value does not exist (for example, a key that is sought for does not exist in a map). |
OverflowException | Exception caused by an arithmetic operation overflow. |
Using Options
Option Types describes the definition of the Option type. The Option type can be used for error handling instead of exceptions, or in conjunction with them.
For example, if the value of the argument of the getOrThrow function is Some(v) in the following code, the value of v is returned. If the value of the argument is None, an exception is thrown.
func getOrThrow(a: ?Int64) {
match (a) {
case Some(v) => v
case None => throw NoneValueException()
}
}
Because Option is a very common type, Cangjie provides multiple deconstruction methods to facilitate its use, including pattern matching, getOrThrow functions, coalescing operators (??), and question mark operators (?). The following describes these methods one by one.
-
Pattern matching: Because the
Optiontype is an enum type, enum pattern matching can be used to deconstruct anOptionvalue, as the sample code above has already shown. In the following example, thegetStringfunction receives a parameter of the?Int64type, which is a shorthand forOption<Int64>. When the value of the argument isSome(x), the function returns the string representation of the value ofx. When the value of the parameter isNone, the function returns the string"none".func getString(p: ?Int64): String{ match (p) { case Some(x) => "${x}" case None => "none" } } main() { let a = Some(1) let b: ?Int64 = None let r1 = getString(a) let r2 = getString(b) println(r1) println(r2) }The execution result of the above code is as follows:
1 none -
The coalescing operator
??: For an expressione1of the type?T, if you want to substitute the valuee2of the typeTwhen the value ofe1isNone, you can use the??operator. If the value ofe1is equal to that ofSome(v), the expressione1 ?? e2evaluates tov, ande2is not evaluated at all. Otherwise,e2is evaluated and the result is used as the value of the entire coalescing expression. The following is an example:main() { let a = Some(1) let b: ?Int64 = None let r1: Int64 = a ?? 0 let r2: Int64 = b ?? 0 println(r1) println(r2) }The execution result of the preceding code is as follows:
1 0 -
Question mark operators (
?):?must be used with.,(),[], or{}(in the scenario where the trailing lambda is called) to enable theOptiontype to support.,(),[], and{}. Take.as an example (the same applies to(),[], and{}). For an expressioneof the?T1type, when the value ofeisSome(v), the value ofe?.bisOption<T2>.Some(v.b). Otherwise, the value ofe?.bisOption<T2>.None. In both cases,T2is the type ofv.b. The following is an example:struct R { public var a: Int64 public init(a: Int64) { this.a = a } } let r = R(100) let x = Some(r) let y = Option<R>.None let r1 = x?.a // r1 = Option<Int64>.Some(100) let r2 = y?.a // r2 = Option<Int64>.NoneQuestion mark operators (
?) support multi-layer access. The following usesa?.b.c?.das an example (the same applies to(),[], and{}). The type of the expressionamust beOption<T1>, andT1contains the instance memberb. The type ofbcontains the instance member variablec, and the type ofcisOption<T2>.T2contains the instance memberd. The type of the expressiona?.b.c?.disOption<T3>, whereT3is the type of the instance memberdofT2. Whenais equal toSome(va)andva.b.cis equal toSome(vc),a?.b.c?.dis equal toOption<T3>.Some(vc.d). Whenais equal toSome(va)andva.b.cis equal toNone,a?.b.c?.dis equal toOption<T3>.None(dis not evaluated). When the value ofais equal toNone, the value ofa?.b.c?.dis equal toOption<T3>.None(b,c, anddare not evaluated).struct A { let b: B = B() } struct B { let c: Option<C> = C() let c1: Option<C> = Option<C>.None } struct C { let d: Int64 = 100 } let a = Some(A()) let a1 = a?.b.c?.d // a1 = Option<Int64>.Some(100) let a2 = a?.b.c1?.d // a2 = Option<Int64>.None -
getOrThrowfunctions: The expressioneof the?Ttype can be deconstructed by calling thegetOrThrowfunction. If the value ofeis equal toSome(v),e.getOrThrow()returns the value ofv. Otherwise, it throws an exception. The following is an example:main() { let a = Some(1) let b: ?Int64 = None let r1 = a.getOrThrow() println(r1) try { let r2 = b.getOrThrow() } catch (e: NoneValueException) { println("b is None") } }The execution result of the preceding code is as follows:
1 b is None
Concurrency Overview
Concurrent programming is an essential feature in modern programming languages. The Cangjie programming language provides a preemptive thread model as its concurrent programming mechanism. When it comes to programming languages and threads, threads can be classified into two types: language threads and native threads.
- The former refers to a basic execution unit of a concurrency model in a programming language. The purpose of language threads is to shield underlying implementation details. Cangjie aims to provide a friendly, efficient, and unified concurrent programming interface for developers. As a result, the concept of Cangjie threads is introduced, enabling developers to write concurrent code without the care about differences between OS threads and user-mode threads.
- The latter refers to threads (usually OS threads) used in language implementation, which serve as specific implementation carriers of language threads. Different programming languages implement language threads in different ways. For example, some languages directly create threads via OS calls, meaning each language thread corresponds to a native thread. This implementation solution is generally referred to as a
1:1thread model. Other languages may provide special thread implementation, which allows multiple language threads to be scheduled on multiple native threads. This is also referred to as aM:Nthread model, that is, M language threads are scheduled and executed on N native threads, where M and N are not necessarily equal. Currently, the Cangjie language also uses theM:Nthread model. Therefore, Cangjie threads are essentially user-mode lightweight threads that support preemption and are lighter than OS threads.
Each Cangjie thread is scheduled and executed by an underlying native thread, and multiple Cangjie threads can be executed by a single native thread. Each native thread continuously selects a ready Cangjie thread for execution. If Cangjie thread is blocked during execution (for example, waiting for a mutex to be released), the native thread suspends the current Cangjie thread, and selects next ready Cangjie thread. The blocked Cangjie thread will be scheduled and executed by the native thread after being ready again.
In most cases, developers only need to perform concurrent programming for Cangjie threads without considering these details. However, during cross-language programming, developers need to exercise caution when calling foreign functions that may be blocked, for example, I/O-related OS calls. In the following sample code the new thread calls the foreign function socket_read. During program running, a native thread schedules and executes a Cangjie thread. After entering the foreign function, the system directly blocks the current native thread until the function execution is complete. When the native thread is blocked, other Cangjie threads cannot be scheduled for execution, which reduces the program throughput.
foreign socket_read(sock: Int64): CPointer<Int8>
let fut = spawn {
let sock: Int64 = ...
let ptr = socket_read(sock)
}
Note:
Unless otherwise specified, Thread is used to simply refer to Cangjie Thread in this document.
Creating a Thread
If you want to execute a segment of code concurrently, you only need to create a Cangjie thread. To create a Cangjie thread, you can use the keyword spawn next to a lambda expression with no parameters. The lambda expression contains the code to be executed in the new thread.
In the following sample code, both the main thread and the new thread attempt to print some text:
import std.sync.*
import std.time.*
main(): Int64 {
spawn { =>
println("New thread before sleeping")
sleep(100 * Duration.millisecond) // sleep for 100ms.
println("New thread after sleeping")
}
println("Main thread")
return 0
}
Here, the new thread stops when the main thread ends, regardless of whether the new thread has completed its execution. The output of the example may vary slightly each time it runs, potentially resembling the following:
New thread before sleeping
Main thread
The sleep() function enforces the current thread to suspend for an at least specified duration (determined by the Duration type) and then resume the execution. For details, see Thread Sleep Duration.
Accessing a Thread
Using Future<T> to Wait for Thread Completion and Obtain Return Value
In the preceding example, the newly created thread ends in advance because the main thread ends. If the sequence is not ensured, the newly created thread may even exit before it is executed. You can use the return value of the spawn expression to wait until the thread execution is complete.
The return type of the spawn expression is Future<T>, where T is a type variable and its type is the same as that of the lambda expression. When you call the get() member function of Future<T>, it waits for its thread to complete execution.
The prototype declaration of Future<T> is as follows:
public class Future<T> {
// Blocking the current thread, waiting for the result of the thread corresponding to the current Future object.
// If an exception occurs in the corresponding thread, the method will throw the exception.
public func get(): T
// Blocking the current thread, waiting for the result of the thread corresponding to the current Future object.
// If the corresponding thread has not completed execution within ns nanoseconds, the method will return an Option<T>.None.
// If `ns` <= 0, its behavior is the same as `get()`.
public func get(ns: Int64): Option<T>
// Non-blocking method that immediately returns Option<T>.None if thread has not finished execution.
// Returns the computed result otherwise.
// If an exception occurs in the corresponding thread, the method will throw the exception.
public func tryGet(): Option<T>
}
The following example code demonstrates how to use Future<T> to wait for the execution of a newly created thread in main:
import std.sync.*
import std.time.*
main(): Int64 {
let fut: Future<Unit> = spawn { =>
println("New thread before sleeping")
sleep(100 * Duration.millisecond) // sleep for 100 ms.
println("New thread after sleeping")
}
println("Main thread")
fut.get() // wait for the thread to finish.
return 0
}
When the get() of the Future<T> instance is called, the current thread is blocked until the thread represented by the Future<T> instance ends. Therefore, information similar to the following may be displayed in the preceding example:
New thread before sleeping
Main thread
New thread after sleeping
After the print operation is complete, the main thread will wait for the newly created thread to finish executing because it calls get(). However, the printing sequence of the main thread and new thread is uncertain.
But what happens if we move fut.get() before the main thread prints? The following is an example:
import std.sync.*
import std.time.*
main(): Int64 {
let fut: Future<Unit> = spawn { =>
println("New thread before sleeping")
sleep(100 * Duration.millisecond) // sleep for 100 ms.
println("New thread after sleeping")
}
fut.get() // wait for the thread to finish.
println("Main thread")
return 0
}
The main thread will wait for the newly created thread to finish executing before it performs the print operation. Therefore, the output of the program is determined as follows:
New thread before sleeping
New thread after sleeping
Main thread
A call location of the get() affects whether the threads can run concurrently.
In addition to waiting for the thread to finish, Future<T> can also be used to obtain the thread execution result. Now, let's look at the specific member functions provided by it.
-
get(): T: waits for the thread to finish executing and returns the execution result. If the thread has finished, the execution result is returned immediately.The sample code is as follows:
import std.sync.* import std.time.* main(): Int64 { let fut: Future<Int64> = spawn { sleep(Duration.second) // sleep for 1s. return 1 } try { // wait for the thread to finish, and get the result. let res: Int64 = fut.get() println("result = ${res}") } catch (_) { println("oops") } return 0 }The output is as follows.
result = 1 -
get(ns: Int64): Option<T>: waits for the thread represented byFuture<T>to finish executing and returns the execution result. If the timeout ofnsis reached and the thread has not finished executing,Option<T>.Noneis returned. Ifns <= 0, the behavior is the same as that ofget().The sample code is as follows:
import std.sync.* import std.time.* main(): Int64 { let fut = spawn { sleep(Duration.second) // sleep for 1s. return 1 } // wait for the thread to finish, but only for 1 ms. let res: Option<Int64> = fut.get(1000 * 1000) match (res) { case Some(val) => println("result = ${val}") case None => println("oops") } return 0 }The output is as follows.
oops
Accessing Thread Attributes
Each Future<T> object has a corresponding Cangjie thread, which is represented by a Thread object. The Thread class is mainly used to access thread attributes, for example, a thread ID. Note that Thread cannot be directly instantiated to construct an object. You can only obtain the corresponding Thread object from the thread member attribute of Future<T> or obtain the Thread object corresponding to the thread that is being executed through the static member attribute currentThread of Thread.
Some methods of the Thread class are defined as follows. For details about the methods, see Cangjie Programming Language Library API.
class Thread {
... ...
// Get the currently running thread
static prop currentThread: Thread
// Get the unique identifier (represented as an integer) of the thread object
prop id: Int64
// Check whether the thread has any cancellation request
prop hasPendingCancellation: Bool
}
The following example code demonstrates how to obtain a thread ID in two ways after creating a thread. Since the main thread and the new thread obtain the same Thread object, they can print the same thread ID.
main(): Unit {
let fut = spawn {
println("Current thread id: ${Thread.currentThread.id}")
}
println("New thread id: ${fut.thread.id}")
fut.get()
}
The output is as follows.
New thread id: 1
Current thread id: 1
Terminating a Thread
You can use the cancel() method of Future<T> to send a termination request to the corresponding thread. This method does not stop the thread's execution immediately. You need to use the hasPendingCancellation attribute of Thread to check whether a thread has a termination request.
Generally, if there is a termination request, you can implement appropriate logic to terminate the thread. It is up to you to decide how to terminate the thread. If the termination request is ignored, the thread will continue executing until it finishes normally.
The sample code is as follows:
import std.sync.SyncCounter
main(): Unit {
let syncCounter = SyncCounter(1)
let fut = spawn {
syncCounter.waitUntilZero()
// Check cancellation request
if (Thread.currentThread.hasPendingCancellation) {
println("cancelled")
return
}
println("hello")
}
fut.cancel() // Send cancellation request
syncCounter.dec()
fut.get() // Join thread
}
The output is as follows.
cancelled
Synchronization Mechanism
In concurrent programming, if there is no synchronization mechanism to protect variables shared by multiple threads, data race may occur.
The Cangjie programming language provides three common synchronization mechanisms to ensure data thread security: atomic operations, mutexes, and condition variables.
Atomic Operations
Cangjie provides atomic operations of the integer, Bool, and reference types.
The integer types include Int8, Int16, Int32, Int64, UInt8, UInt16, UInt32, and UInt64.
Atomic operations of the integer type support basic read, write, swap, and arithmetic operations.
| Operation | Function |
|---|---|
load | Read. |
store | Write. |
swap | Swap. The value before swap is returned. |
compareAndSwap | Compare and swap. If the swap is successful, true is returned. Otherwise, false is returned. |
fetchAdd | Addition. The value before the addition operation is returned. |
fetchSub | Subtraction. The value before the subtraction operation is returned. |
fetchAnd | AND. The value before the AND operation is returned. |
fetchOr | OR. The value before the OR operation is returned. |
fetchXor | XOR. The value before the XOR operation is returned. |
Note that:
- The return values of the swap and arithmetic operations are values before the operations.
- compareAndSwap checks whether the value of the current atomic variable is equal to the old value. If they are equal, it replaces the old value with the new value. Otherwise, it does not perform the replacement.
Take the Int8 type as an example. The corresponding atomic operation type is declared as follows:
class AtomicInt8 {
public func load(): Int8
public func store(val: Int8): Unit
public func swap(val: Int8): Int8
public func compareAndSwap(old: Int8, new: Int8): Bool
public func fetchAdd(val: Int8): Int8
public func fetchSub(val: Int8): Int8
public func fetchAnd(val: Int8): Int8
public func fetchOr(val: Int8): Int8
public func fetchXor(val: Int8): Int8
}
The methods for each atomic type listed above have corresponding versions that can accept memory ordering parameters, currently supporting only sequential consistency.
Similarly, other integer types correspond to the following atomic operation types:
class AtomicInt16 {...}
class AtomicInt32 {...}
class AtomicInt64 {...}
class AtomicUInt8 {...}
class AtomicUInt16 {...}
class AtomicUInt32 {...}
class AtomicUInt64 {...}
The following example shows how to use atomic operations to count in a multithreaded program:
import std.sync.*
import std.time.*
import std.collection.*
let count = AtomicInt64(0)
main(): Int64 {
let list = ArrayList<Future<Int64>>()
// create 1000 threads.
for (_ in 0..1000) {
let fut = spawn {
sleep(Duration.millisecond) // sleep for 1 ms.
count.fetchAdd(1)
}
list.append(fut)
}
// Wait for all threads finished.
for (f in list) {
f.get()
}
let val = count.load()
println("count = ${val}")
return 0
}
The output is as follows:
count = 1000
The following are some examples of using atomic operations of the integer type:
var obj: AtomicInt32 = AtomicInt32(1)
var x = obj.load() // x: 1, the type is Int32
x = obj.swap(2) // x: 1
x = obj.load() // x: 2
var y = obj.compareAndSwap(2, 3) // y: true, the type is Bool.
y = obj.compareAndSwap(2, 3) // y: false, the value in obj is no longer 2 but 3. Therefore, the CAS operation fails.
x = obj.fetchAdd(1) // x: 3
x = obj.load() // x: 4
Atomic operations of the Bool and reference types support only read, write, and swap operations.
| Operation | Function |
|---|---|
load | Read |
store | Write |
swap | Swap. The value before swap is returned. |
compareAndSwap | Compare and swap. If the swap is successful, true is returned. Otherwise, false is returned. |
Note:
The atomic operation of the reference type is valid only for the reference type.
The atomic reference type is AtomicReference. The following are some examples of using atomic operations of the Bool and reference types:
import std.sync.*
class A {}
main() {
var obj = AtomicBool(true)
var x1 = obj.load() // x1: true, the type is Bool
println(x1)
var t1 = A()
var obj2 = AtomicReference(t1)
var x2 = obj2.load() // x2 and t1 are the same object
var y1 = obj2.compareAndSwap(x2, t1) // x2 and t1 are the same object, y1: true
println(y1)
var t2 = A()
var y2 = obj2.compareAndSwap(t2, A()) // x and t1 are not the same object, CAS fails, y2: false
println(y2)
y2 = obj2.compareAndSwap(t1, A()) // CAS successes, y2: true
println(y2)
}
The result is as follows:
true
true
false
true
ReentrantMutex
The function of the ReentrantMutex is to protect the critical section so that only one thread can execute the code in the critical section at any time. When a thread attempts to acquire a lock that has been held by another thread, the thread is blocked and is not woken up until the lock is released. Reentrancy means that a thread can acquire the same lock multiple times.
Note:
ReentrantMutex is a built-in mutex. You need to ensure that it is not inherited.
When using a ReentrantMutex, you must keep two rules in mind:
- You must attempt to acquire the lock before accessing shared data.
- After the shared data is processed, the shared data must be unlocked so that other threads can acquire the lock.
ReentrantMutex provides the following member functions:
public open class ReentrantMutex {
// Create a ReentrantMutex.
public init()
// Locks the mutex, blocks if the mutex is not available.
public func lock(): Unit
// Unlocks the mutex. If there are other threads blocking on this
// lock, then wake up one of them.
public func unlock(): Unit
// Tries to lock the mutex, returns false if the mutex is not
// available, otherwise returns true.
public func tryLock(): Bool
}
The following example shows how to use ReentrantMutex to protect access to the global shared variable count, where operations on count are considered a critical section:
import std.sync.*
import std.time.*
import std.collection.*
var count: Int64 = 0
let mtx = ReentrantMutex()
main(): Int64 {
let list = ArrayList<Future<Unit>>()
// create 1000 threads.
for (i in 0..1000) {
let fut = spawn {
sleep(Duration.millisecond) // sleep for 1 ms.
mtx.lock()
count++
mtx.unlock()
}
list.append(fut)
}
// Wait for all threads finished.
for (f in list) {
f.get()
}
println("count = ${count}")
return 0
}
The output is as follows:
count = 1000
The following example shows how to use tryLock:
import std.sync.*
import std.time.*
main(): Int64 {
let mtx: ReentrantMutex = ReentrantMutex()
var future: Future<Unit> = spawn {
mtx.lock()
println("get the lock, do something")
sleep(Duration.millisecond * 10)
mtx.unlock()
}
let res: Option<Unit> = future.get(10 * 1000 * 1000)
match (res) {
case Some(v) =>
println("after wait 10 ms, end")
case None =>
println("after wait 10 ms, try to get the lock")
if (mtx.tryLock()) {
println("tryLock sucess, do something")
mtx.unlock()
return 1
}
println("tryLock failed, do nothing")
return 0
}
return 2
}
One possible output is as follows:
get the lock, do something
after wait 10 ms, try to get the lock
tryLock failed, do nothing
The following are some error examples involving mutexes:
Error example 1: A thread operates on the critical section without unlocking, causing other threads to be blocked and unable to acquire the lock.
import std.sync.*
var sum: Int64 = 0
let mutex = ReentrantMutex()
main() {
let foo = spawn { =>
mutex.lock()
sum = sum + 1
}
let bar = spawn { =>
mutex.lock()
sum = sum + 1
}
foo.get()
println("${sum}")
bar.get() // Because the thread is not unlocked, other threads waiting to obtain the current mutex will be blocked.
}
Error example 2: If the current thread does not hold a lock, an exception is thrown when unlock is called.
import std.sync.*
var sum: Int64 = 0
let mutex = ReentrantMutex()
main() {
let foo = spawn { =>
sum = sum + 1
mutex.unlock() // Error, Unlock without obtaining the lock and throw an exception: IllegalSynchronizationStateException.
}
foo.get()
0
}
Error example 3: tryLock() does not guarantee that the lock will be acquired, which can lead to operations on the critical section without the lock's protection and exceptions being thrown when calling unlock without holding the lock.
import std.sync.*
var sum: Int64 = 0
let mutex = ReentrantMutex()
main() {
for (i in 0..100) {
spawn { =>
mutex.tryLock() // Error, `tryLock()` just trying to acquire a lock, there is no guarantee that the lock will be acquired, and this can lead to abnormal behavior.
sum = sum + 1
mutex.unlock()
}
}
}
In addition, ReentrantMutex is designed to be a reentrant lock, meaning that if a thread already holds ReentrantMutex, it can immediately acquire the same ReentrantMutex again.
Note:
Although
ReentrantMutexis a reentrant lock, the number of calls tounlock()must be the same as the number of calls tolock()so that the lock can be successfully released.
The following example code demonstrates the reentrant feature of ReentrantMutex:
import std.sync.*
import std.time.*
var count: Int64 = 0
let mtx = ReentrantMutex()
func foo() {
mtx.lock()
count += 10
bar()
mtx.unlock()
}
func bar() {
mtx.lock()
count += 100
mtx.unlock()
}
main(): Int64 {
let fut = spawn {
sleep(Duration.millisecond) // sleep for 1 ms.
foo()
}
foo()
fut.get()
println("count = ${count}")
return 0
}
The output is as follows:
count = 220
In the example above, whether in the main thread or in the newly created thread, if the lock has already been acquired in foo(), calling bar() will allow the thread to immediately acquire the same ReentrantMutex again without causing a deadlock, since it is locking the same ReentrantMutex.
Monitor
Monitor is a built-in data structure that binds a mutex to a single related condition variable (wait queue). Monitor can block a thread and wait for a signal from another thread to resume execution. This mechanism uses shared variables to synchronize threads. The following methods are provided:
public class Monitor <: ReentrantMutex {
// Create a monitor.
public init()
// Wait for a signal, blocking the current thread.
public func wait(timeout!: Duration = Duration.Max): Bool
// Wake up one thread of those waiting on the monitor, if any.
public func notify(): Unit
// Wake up all threads waiting on the monitor, if any.
public func notifyAll(): Unit
}
Before calling the wait, notify, or notifyAll method of the Monitor object, ensure that the current thread has held the corresponding Monitor lock. The wait method contains the following actions:
- Add the current thread to the waiting queue corresponding to the
Monitor. - Block the current thread, release the
Monitorlock, and record the number of lock re-entry times. - Wait for another thread to use the
notifyornotifyAllmethod of the sameMonitorinstance to send a signal to the thread. - After the current thread is woken up, it automatically attempts to re-acquire the
Monitorlock. The re-entry status of the lock is the same as the number of re-entry times recorded in step 2. However, if the attempt to acquire theMonitorlock fails, the current thread is blocked on theMonitorlock.
The wait method accepts an optional parameter timeout. It should be noted that many common OSs in the industry do not ensure real-time scheduling. Therefore, it cannot be ensured that a thread is blocked for "exact N nanoseconds." There may be system-related inaccuracies. In addition, the current language specification explicitly allows implementations to produce false wake-ups. In this case, the return value of wait is implementation-determined, possibly true or false. Therefore, developers are encouraged to always wrap wait in a loop.
synchronized (obj) {
while (<condition is not true>) {
obj.wait()
}
}
The following is an example of using Monitor:
import std.sync.*
import std.time.*
var mon = Monitor()
var flag: Bool = true
main(): Int64 {
let fut = spawn {
mon.lock()
while (flag) {
println("New thread: before wait")
mon.wait()
println("New thread: after wait")
}
mon.unlock()
}
// Sleep for 10 ms, to make sure the new thread can be executed.
sleep(10 * Duration.millisecond)
mon.lock()
println("Main thread: set flag")
flag = false
mon.unlock()
mon.lock()
println("Main thread: notify")
mon.notifyAll()
mon.unlock()
// wait for the new thread finished.
fut.get()
return 0
}
The output is as follows:
New thread: before wait
Main thread: set flag
Main thread: notify
New thread: after wait
When a Monitor object executes wait, it must be protected by a lock. Otherwise, an exception is thrown when the lock is released in wait.
The following are some error examples of using condition variables:
import std.sync.*
var m1 = Monitor()
var m2 = ReentrantMutex()
var flag: Bool = true
var count: Int64 = 0
func foo1() {
spawn {
m2.lock()
while (flag) {
m1.wait() // Error: The lock used together with the condition variable must be the same lock and in the locked state. Otherwise, the unlock operation in `wait` throws an exception.
}
count = count + 1
m2.unlock()
}
m1.lock()
flag = false
m1.notifyAll()
m1.unlock()
}
func foo2() {
spawn {
while (flag) {
m1.wait() // Error: The `wait` of a conditional variable must be called with a lock held.
}
count = count + 1
}
m1.lock()
flag = false
m1.notifyAll()
m1.unlock()
}
main() {
foo1()
foo2()
m1.wait()
return 0
}
MultiConditionMonitor
MultiConditionMonitor is a built-in data structure that binds a mutex to a group of dynamically created condition variables. This class is used only when the Monitor class is insufficient for complex inter-thread synchronization. It primarily provides the following methods:
public class MultiConditionMonitor <: ReentrantMutex {
// Constructor.
init()
// Returns a new ConditionID associated with this monitor. May be used to implement
// "single mutex -- multiple wait queues" concurrent primitives.
// Throws IllegalSynchronizationStateException("Mutex is not locked by the current thread") if the current thread does not hold this mutex.
func newCondition(): ConditionID
// Blocks until either a paired `notify` is invoked or `timeout` nanoseconds pass.
// Returns `true` if the specified condition was signalled by another thread or `false` on timeout.
// Spurious wakeups are allowed.
// Throws IllegalSynchronizationStateException("Mutex is not locked by the current thread") if the current thread does not hold this mutex.
// Throws IllegalSynchronizationStateException("Invalid condition") if `id` was not returned by `newCondition` of this MultiConditionMonitor instance.
func wait(id: ConditionID, timeout!: Duration = Duration.Max): Bool
// Wakes up a single thread waiting on the specified condition, if any (no particular admission policy implied).
// Throws IllegalSynchronizationStateException("Mutex is not locked by the current thread") if the current thread does not hold this mutex.
// Throws IllegalSynchronizationStateException("Invalid condition") if `id` was not returned by `newCondition` of this MultiConditionMonitor instance.
func notify(id: ConditionID): Unit
// Wakes up all threads waiting on the specified condition, if any (no particular admission policy implied).
// Throws IllegalSynchronizationStateException("Mutex is not locked by the current thread") if the current thread does not hold this mutex.
// Throws IllegalSynchronizationStateException("Invalid condition") if `id` was not returned by `newCondition` of this MultiConditionMonitor instance.
func notifyAll(id: ConditionID): Unit
}
newCondition(): ConditionID: creates a condition variable, associates it with the current object, and returns a specificConditionID.wait(id: ConditionID, timeout!: Duration = Duration.Max): Bool: waits for a signal and blocks the current thread.notify(id: ConditionID): Unit: wakes up a thread waiting on theMonitor(if any).notifyAll(id: ConditionID): Unit: wakes up all threads waiting on theMonitor(if any).
During initialization, the MultiConditionMonitor does not have a related ConditionID instance. Each time newCondition is called, a new condition variable is created and associated with the current object, returning a unique identifier of the following type:
public struct ConditionID {
private init() { ... } // constructor is intentionally private to prevent
// creation of such structs outside of MultiConditionMonitor
}
Note that users cannot pass a ConditionID returned by a MultiConditionMonitor instance to other instances or manually create a ConditionID (for example, using unsafe). Because the data contained in the ConditionID (such as the index of the internal array, the direct address of the internal queue, or any other type of data) is related to the MultiConditionMonitor that created it, passing an "external" conditionID to the MultiConditionMonitor will result in IllegalSynchronizationStateException.
The following describes how to use MultiConditionMonitor to implement a bounded FIFO queue with a fixed length. When the queue is empty, get() is blocked. When the queue is full, put() is blocked.
import std.sync.*
class BoundedQueue {
// Create a MultiConditionMonitor, two Conditions.
let m: MultiConditionMonitor = MultiConditionMonitor()
var notFull: ConditionID
var notEmpty: ConditionID
var count: Int64 // Object count in buffer.
var head: Int64 // Write index.
var tail: Int64 // Read index.
// Queue's length is 100.
let items: Array<Object> = Array<Object>(100, {i => Object()})
init() {
count = 0
head = 0
tail = 0
synchronized(m) {
notFull = m.newCondition()
notEmpty = m.newCondition()
}
}
// Insert an object, if the queue is full, block the current thread.
public func put(x: Object) {
// Acquire the mutex.
synchronized(m) {
while (count == 100) {
// If the queue is full, wait for the "queue notFull" event.
m.wait(notFull)
}
items[head] = x
head++
if (head == 100) {
head = 0
}
count++
// An object has been inserted and the current queue is no longer
// empty, so wake up the thread previously blocked on get()
// because the queue was empty.
m.notify(notEmpty)
} // Release the mutex.
}
// Pop an object, if the queue is empty, block the current thread.
public func get(): Object {
// Acquire the mutex.
synchronized(m) {
while (count == 0) {
// If the queue is empty, wait for the "queue notEmpty" event.
m.wait(notEmpty)
}
let x: Object = items[tail]
tail++
if (tail == 100) {
tail = 0
}
count--
// An object has been popped and the current queue is no longer
// full, so wake up the thread previously blocked on put()
// because the queue was full.
m.notify(notFull)
return x
} // Release the mutex.
}
}
synchronized
The ReentrantMutex provides a convenient and flexible locking method. However, due to its flexibility, it can lead to issues such as forgetting to unlock or throwing exceptions while holding the mutex, which prevents automatic release of the held lock. To address these problems, the Cangjie programming language offers a synchronized keyword that can be used in conjunction with ReentrantMutex. It automatically handles locking and unlocking within the scope that follows it.
The following example code demonstrates how to use the synchronized keyword to protect shared data:
import std.sync.*
import std.time.*
import std.collection.*
var count: Int64 = 0
let mtx = ReentrantMutex()
main(): Int64 {
let list = ArrayList<Future<Unit>>()
// create 1000 threads.
for (i in 0..1000) {
let fut = spawn {
sleep(Duration.millisecond) // sleep for 1 ms.
// Use synchronized(mtx), instead of mtx.lock() and mtx.unlock().
synchronized(mtx) {
count++
}
}
list.append(fut)
}
// Wait for all threads finished.
for (f in list) {
f.get()
}
println("count = ${count}")
return 0
}
The output is as follows:
count = 1000
A ReentrantMutex instance is added after synchronized to protect the modified code block. In this way, only one thread can execute the protected code at any time.
- Before entering the code block modified by
synchronized, a thread automatically acquires the lock corresponding to theReentrantMutexinstance. If the lock cannot be acquired, the current thread is blocked. - Before exiting the code block modified by
synchronized, a thread automatically releases the lock of theReentrantMutexinstance.
For control transfer expressions (such as break, continue, return, and throw), when they cause the execution of the program to exit the synchronized code block, it also conforms to the previous description. That is, the lock corresponding to the synchronized expression is automatically released.
The following example demonstrates a case where a break statement appears in a synchronized code block:
import std.sync.*
import std.collection.*
var count: Int64 = 0
var mtx: ReentrantMutex = ReentrantMutex()
main(): Int64 {
let list = ArrayList<Future<Unit>>()
for (i in 0..10) {
let fut = spawn {
while (true) {
synchronized(mtx) {
count = count + 1
break
println("in thread")
}
}
}
list.append(fut)
}
// Wait for all threads finished.
for (f in list) {
f.get()
}
synchronized(mtx) {
println("in main, count = ${count}")
}
return 0
}
The output is as follows:
in main, count = 10
Actually, the in thread line is not printed because the break statement actually causes the program to exit the while loop (it exits the synchronized code block before exiting the while loop).
ThreadLocal
You can use ThreadLocal in the core package to create and use thread local variables. Each thread has an independent storage space to store these thread local variables. Therefore, each thread can safely access its own thread local variables without being affected by other threads.
public class ThreadLocal<T> {
/*
* Constructs a Cangjie thread local variable with a null value.
*/
public init()
/*
* Obtains the value of a Cangjie thread local variable. If the value does not exist, Option<T>.None is returned.
* Option<T>: return value of the Cangjie thread local variable
*/
public func get(): Option<T>
/*
* Sets the value of the Cangjie thread local variable.
* If Option<T>.None is passed, the value of the local variable will be deleted and cannot be acquired in subsequent operations of the thread.
* value: value of the local variable to be set
*/
public func set(value: Option<T>): Unit
}
The following example code demonstrates how to use the ThreadLocal class to create and use local variables of each thread:
main(): Int64 {
let tl = ThreadLocal<Int64>()
let fut1 = spawn {
tl.set(123)
println("tl in spawn1 = ${tl.get().getOrThrow()}")
}
let fut2 = spawn {
tl.set(456)
println("tl in spawn2 = ${tl.get().getOrThrow()}")
}
fut1.get()
fut2.get()
0
}
The possible output is as follows:
tl in spawn1 = 123
tl in spawn2 = 456
Or:
tl in spawn2 = 456
tl in spawn1 = 123
Thread Sleep Duration
The sleep function blocks the currently running thread, causing it to suspend for an at least specified duration before resuming execution. The parameter type is Duration. Its prototype is as follows:
func sleep(dur: Duration): Unit // Sleep for at least `dur`.
Note:
If the value of
duris less than or equal to that ofDuration.Zero, the current thread yields execution resources but does not enter the sleep state.
The following is an example of using sleep:
import std.sync.*
import std.time.*
main(): Int64 {
println("Hello")
sleep(Duration.second) // sleep for 1s.
println("World")
return 0
}
The output is as follows.
Hello
World
I/O Stream Overview
I/O Node Streams
I/O Processing Streams
Network Programming Overview
Network communication is a process of exchanging the data of two devices through a computer network. Network programming is an act of writing software to realize network communication.
Cangjie provides developers with basic network programming functions. Its standard library allows users to utilize the socket package in the std module to implement network communication at the transport layer.
Transport layer protocols are classified into unreliable transport protocols and reliable transport protocols, which are abstracted as DatagramSocket and StreamSocket in Cangjie. A common unreliable transport protocol is UDP and a common reliable transport protocol is TCP. They are respectively abstracted as UDPSocket and TcpSocket in Cangjie. In addition, Cangjie supports the Unix Domain protocol at the transport layer, enabling its communication in both reliable and unreliable transport modes.
A common application layer protocol is the HTTP protocol, which is widely used in developing web apps. Among the multiple HTTP protocol versions, Cangjie supports versions such as HTTP/1.1 and HTTP/2.0.
Besides, Cangjie abstracts WebSocket, an application layer protocol that contributes to a higher communication efficiency between the web server and the client, as a WebSocket object and supports the upgrade from HTTP to WebSocket.
It is worth noting that Cangjie's network programming adopts a blocking mode. The blocked Cangjie threads release the system thread. Therefore, the system thread is not blocked.
Socket Programming
Cangjie's socket programming enables the transfer of data packets over the network using transport layer protocols.
In a reliable transfer scenario, Cangjie separately starts a client socket and a server socket. The client socket must specify the remote address to be connected and selectively binds to the local address. Packets can be sent and received after the connection is successful. The server socket must be bound to the local address, after which packets can be sent and received.
In an unreliable transfer scenario, there is no need to distinguish between client and server sockets. Cangjie separately starts the two sockets for data transfer. Both sockets must be bound to the local address, after which packets can be sent and received. In addition, the socket may selectively specify a remote management address. After the address is specified, only packets of the specified address are accepted. When sending packets, there is no need to specify the remote address again; the packets will be automatically sent to the connected address.
TCP Programming
TCP is a common reliable transport protocol. Here we use a TCP socket as an example and provide a Cangjie programming model in a reliable transport scenario for reference.
- Create a server socket and specify the local address to be bound.
- Perform the binding.
- Perform the accept operation. The server is blocked and waits until a client socket is connected.
- Create a client socket and specify the remote address to be connected.
- Set up a connection.
- After the connection is successful, the server returns a new socket through the accept interface and performs read and write operations (sending and receiving packets) using the socket. By contrast, the client can directly perform read and write operations.
The following is an example of the TCP server and client programs:
import std.socket.*
import std.time.*
import std.sync.*
var SERVER_PORT: UInt16 = 0
func runTcpServer() {
try (serverSocket = TcpServerSocket(bindAt: SERVER_PORT)) {
serverSocket.bind()
SERVER_PORT = serverSocket.localAddress.port
try (client = serverSocket.accept()) {
let buf = Array<Byte>(10, item: 0)
let count = client.read(buf)
// 服务端读取到的数据为: [1, 2, 3, 0, 0, 0, 0, 0, 0, 0]
println("Server read ${count} bytes: ${buf}")
}
}
}
main(): Int64 {
let future = spawn {
runTcpServer()
}
sleep(Duration.millisecond * 500)
try (socket = TcpSocket("127.0.0.1", SERVER_PORT)) {
socket.connect()
socket.write(Array<Byte>([1, 2, 3]))
}
future.get()
return 0
}
Compiling and executing the preceding code will display the following information:
Server read 3 bytes: [1, 2, 3, 0, 0, 0, 0, 0, 0, 0]
UDP Programming
UDP is a common unreliable transport protocol. Here we use a UDP socket as an example and provide a Cangjie programming model in an unreliable transport scenario for reference.
- Create a socket and specify the local address to be bound.
- Perform the binding.
- Specify a remote address for sending packets.
- If no remote address is connected, packets from different remote addresses can be received and the remote address information can be returned.
Here is a program example that describes how a UDP receives and sends packets:
import std.socket.*
import std.time.*
import std.sync.*
let SERVER_PORT: UInt16 = 8080
func runUpdServer() {
try (serverSocket = UdpSocket(bindAt: SERVER_PORT)) {
serverSocket.bind()
let buf = Array<Byte>(3, item: 0)
let (clientAddr, count) = serverSocket.receiveFrom(buf)
let sender = clientAddr.hostAddress
// Packet received by the socket and the remote address: [1, 2, 3], 127.0.0.1
println("Server receive ${count} bytes: ${buf} from ${sender}")
}
}
main(): Int64 {
let future = spawn {
runUpdServer()
}
sleep(Duration.second)
try (udpSocket = UdpSocket(bindAt: 0)) {
udpSocket.sendTimeout = Duration.second * 2
udpSocket.bind()
udpSocket.sendTo(
SocketAddress("127.0.0.1", SERVER_PORT),
Array<Byte>([1, 2, 3])
)
}
future.get()
return 0
}
HTTP Programming
HTTP is a general application layer protocol which realizes data transfer through a request-response mechanism. The client sends a request and the server returns a response. Both the request and response contains a packet header and a packet body.
GET and POST are two common request types. The former request contains only a packet header and is used to request application-layer data from a server. The latter request has a packet body, which is separated from the header by a blank line. It provides application-layer data for the server.
The packet headers of requests and responses contain many fields, which are not described here. Cangjie supports HTTP 1.0, 1.1, and 2.0 and other versions. You can construct requests and response packets based on the RFC 9110, 9112, 9113, 9218, and 7541 protocols, as well as HttpRequestBuilder and HttpResponseBuilder provided by Cangjie.
The following example shows how to use Cangjie for client and server programing. The client sends a request whose header is "GET /hello" and the server returns a response whose body is "Hello Cangjie!" The code is as follows:
import net.http.*
import std.time.*
import std.sync.*
import std.log.LogLevel
// 1. Construct a server instance.
let server = ServerBuilder()
.addr("127.0.0.1")
.port(8080)
.build()
func startServer(): Unit {
// 2. Register with the request processing logic.
server.distributor.register("/hello", {httpContext =>
httpContext.responseBuilder.body("Hello Cangjie!")
})
server.logger.level = OFF
// 3. Start the service.
server.serve()
}
func startClient(): Unit {
// 1. Construct a client instance.
let client = ClientBuilder().build()
// 2. Send a request.
let response = client.get("http://127.0.0.1:${server.port}/hello")
// 3. Read the response.body
let buffer = Array<Byte>(32, item: 0)
let length = response.body.read(buffer)
println(String.fromUtf8(buffer[..length]))
// 4. Close the connection.
client.close()
}
main () {
spawn {
startServer()
}
sleep(Duration.second)
startClient()
}
Compiling and executing the preceding code will display the following information:
Hello Cangjie!
WebSocket Programming
WebSocket is also a common application layer protocol in network programming. Like HTTP, it is also TCP-based and achieves wide adoption in web server app development.
The difference lies in that WebSocket requires only a handshake between the client and server to establish a persistent connection for bidirectional data transfer. In other words, the server implemented based on WebSocket can actively transmit data to the client, achieving real-time communication.
WebSocket is an independent protocol whose handshake is interpreted as an upgrade request by the HTTP server. Therefore, Cangjie incorporates WebSocket into the HTTP packet.
Cangjie abstracts the WebSocket protocol communication mechanism as a WebSocket class. It provides a method to upgrade an HTTP/1.1 or HTTP/2.0 server handle to a WebSocket protocol instance, and realizes communication (for example, data packet reading and writing) through the returned WebSocket instance.
In Cangjie, a basic unit of data transferred by WebSocket is referred to as a frame. Frames are classified into two types. The first type is for transferring control information, such as a Close frame for closing a connection, the Ping frame for implementing keepalive, and the Pong frame, which is a response to the Ping frame. The second type is for transferring app data, which supports segmented transfer.
A Cangjie frame consists of three attributes, in which fin and frameType collectively indicate whether the frame is segmented and the frame type, and payload indicates the frame payload. Other attributes can be ignored during a packet transfer.
The following example shows a WebSocket handshake and the message sending and receiving process: An HTTP client and server are created to initiate a WebSocket upgrade (or handshake) separately, and frames are read and written after the handshake is successful.
import net.http.*
import encoding.url.*
import std.time.*
import std.sync.*
import std.collection.*
import std.log.*
let server = ServerBuilder()
.addr("127.0.0.1")
.port(0)
.build()
// client:
main() {
// 1. Start the server.
spawn { startServer() }
sleep(Duration.millisecond * 200)
let client = ClientBuilder().build()
let u = URL.parse("ws://127.0.0.1:${server.port}/webSocket")
let subProtocol = ArrayList<String>(["foo1", "bar1"])
let headers = HttpHeaders()
headers.add("test", "echo")
// 2. Complete the WebSocket handshake and obtain the WebSocket instance.
let websocket: WebSocket
let respHeaders: HttpHeaders
(websocket, respHeaders) = WebSocket.upgradeFromClient(client, u, subProtocols: subProtocol, headers: headers)
client.close()
println("subProtocol: ${websocket.subProtocol}") // fool1
println(respHeaders.getFirst("rsp") ?? "") // echo
// 3. Send and receive a message.
// Send "hello."
websocket.write(TextWebFrame, "hello".toArray())
// Receive a message.
let data = ArrayList<UInt8>()
var frame = websocket.read()
while(true) {
match(frame.frameType) {
case ContinuationWebFrame =>
data.appendAll(frame.payload)
if (frame.fin) {
break
}
case TextWebFrame | BinaryWebFrame =>
if (!data.isEmpty()) {
throw Exception("invalid frame")
}
data.appendAll(frame.payload)
if (frame.fin) {
break
}
case CloseWebFrame =>
websocket.write(CloseWebFrame, frame.payload)
break
case PingWebFrame =>
websocket.writePongFrame(frame.payload)
case _ => ()
}
frame = websocket.read()
}
println("data size: ${data.size}") // 4097
println("last item: ${String.fromUtf8(Array(data)[4096])}") // a
// 4. Close the WebSocket.
// Receive and send CloseFrame.
websocket.writeCloseFrame(status: 1000)
let websocketFrame = websocket.read()
println("close frame type: ${websocketFrame.frameType}") // CloseWebFrame
println("close frame payload: ${websocketFrame.payload}") // 3, 232
// Close the low-level connection.
websocket.closeConn()
server.close()
}
func startServer() {
// 1. Register the handler.
server.distributor.register("/webSocket", handler1)
server.logger.level = OFF
server.serve()
}
// server:
func handler1(ctx: HttpContext): Unit {
// 2. Complete the WebSocket handshake and obtain the WebSocket instance.
let websocketServer = WebSocket.upgradeFromServer(ctx, subProtocols: ArrayList<String>(["foo", "bar", "foo1"]),
userFunc: {request: HttpRequest =>
let value = request.headers.getFirst("test") ?? ""
let headers = HttpHeaders()
headers.add("rsp", value)
headers
})
// 3. Send and receive a message.
// Receive "hello."
let data = ArrayList<UInt8>()
var frame = websocketServer.read()
while(true) {
match(frame.frameType) {
case ContinuationWebFrame =>
data.appendAll(frame.payload)
if (frame.fin) {
break
}
case TextWebFrame | BinaryWebFrame =>
if (!data.isEmpty()) {
throw Exception("invalid frame")
}
data.appendAll(frame.payload)
if (frame.fin) {
break
}
case CloseWebFrame =>
websocketServer.write(CloseWebFrame, frame.payload)
break
case PingWebFrame =>
websocketServer.writePongFrame(frame.payload)
case _ => ()
}
frame = websocketServer.read()
}
println("data: ${String.fromUtf8(Array(data))}") // hello
// Send letter a for 4097 times.
websocketServer.write(TextWebFrame, Array<UInt8>(4097, item: 97))
// 4. Close the WebSocket.
// Receive and send CloseFrame.
let websocketFrame = websocketServer.read()
println("close frame type: ${websocketFrame.frameType}") // CloseWebFrame
println("close frame payload: ${websocketFrame.payload}") // 3, 232
websocketServer.write(CloseWebFrame, websocketFrame.payload)
// Close the low-level connection.
websocketServer.closeConn()
}
The execution result of the example code is as follows:
subProtocol: foo1
echo
data: hello
data size: 4097
last item: a
close frame type: CloseWebFrame
close frame payload: [3, 232]
close frame type: CloseWebFrame
close frame payload: [3, 232]
Macro Overview
A macro can be regarded as a special function. A regular function takes an input value and computes an output, whereas a macro takes a program fragment as its input and produces a program as an output. Resulting program is used for subsequent compilation and execution. To distinguish a macro call from a function call, we prefix macro name with @ when calling a macro.
The following sample code prints the value of an expression and the expression itself during debugging.
let x = 3
let y = 2
@dprint(x) // Print "x = 3"
@dprint(x + y) // Print "x + y = 5"
Obviously, dprint cannot be written as a regular function because a regular function can obtain only the input value rather than the input program fragment. However, we can implement dprint as a macro. A basic implementation code is as follows:
macro package define
import std.ast.*
public macro dprint(input: Tokens): Tokens {
let inputStr = input.toString()
let result = quote(
print($(inputStr) + " = ")
println($(input)))
return result
}
Before discussing each line of code, we can test that the macro behaves as intended. First, we need to create a macros folder in the current directory and a dprint.cj file in the macros folder. Then, we need to copy the preceding content to the dprint.cj file. In addition, we need to create a main.cj file that contains the following test code in the current directory.
import define.*
main() {
let x = 3
let y = 2
@dprint(x)
@dprint(x + y)
}
The directory structure is as follows:
// Directory layout.
src
|-- macros
| `-- dprint.cj
`-- main.cj
Run the following compilation command in the src directory.
cjc macros/*.cj --compile-macro
cjc main.cj -o main
Run ./main. The following information is output:
x = 3
x + y = 5
Let's discuss each part of the code:
-
Line 1:
macro package defineMacros must be declared in a special separate package (different from package that uses these macros). Packages containing macros are declared using
macro package. Here we declare a macro package nameddefine. -
Line 2:
import std.ast.*The data types required for implementing macros, such as
Tokensand the syntax node types (which will be mentioned later), are provided by theastpackage of the standard library of Cangjie. Therefore, theastpackage must be imported before any macro declaration. -
Line 3:
public macro dprint(input: Tokens): TokensHere we declare a macro named
dprint. Since the macro is a non-attribute macro (which will be explained later), it accepts a parameter of theTokenstype. The input represents the program fragment passed to the macro. The return value of the macro is also a program fragment of theTokenstype. -
Line 4:
let inputStr = input.toString()In the implementation of the macro, the input program fragment is first converted into a string. In the preceding test case,
inputStrbecomes"x"or"x + y". -
Lines 5 to 7:
let result = quote(...)The
quoteexpression is used to constructTokens. It converts the program fragment in parentheses toTokens. In the input ofquote, you can interpolate$(...)to convert the expression in parentheses toTokensand then insert it into theTokensconstructed byquote. In the above code,$(inputStr)inserts the value of theinputStrstring (including the quotation marks on both ends of the string), and$(input)insertsinput, that is, the input program fragment. Therefore, if the input expression isx + y, theTokensis as follows:print("x + y" + " = ") println(x + y) -
Line 8:
return resultFinally, the constructed code is returned. The two code lines will be compiled and
x + y = 5will be output during execution.
Looking back at the definition of the dprint macro, we can notice that dprint uses Tokens as the input parameter, and uses quote and interpolation to construct another Tokens as the return value. To use the Cangjie macro, you need to investigate the concepts of Tokens, quote, and interpolation. Let's discuss each one separately.
Token Types and quote Expressions
Token Type
Tokens are basic elements of macro operations, which represent a program fragment. A Tokens is a composition of several individual Tokens, each of which can be understood as a lexical unit that can be operated by a user. A Token can be an identifier (such as a variable name), a literal (such as an integer, floating-point number, or string), a keyword, or an operator. Each Token has its type, content, and location.
The type of a Token is an element in the TokenKind enum. The available values of TokenKind can be found in Cangjie Libraries. Any Token can be constructed directly based on a string of TokenKind and Token (for identifiers and literals). The constructor is as follows:
Token(k: TokenKind)
Token(k: TokenKind, v: String)
Here are some examples of how to construct a Token.
import std.ast.*
let tk1 = Token(TokenKind.ADD) // '+' operator
let tk2 = Token(TokenKind.FUNC) // func keyword
let tk3 = Token(TokenKind.IDENTIFIER, "x") // x identifier
let tk4 = Token(TokenKind.INTEGER_LITERAL, "3") // Integer literal
let tk5 = Token(TokenKind.STRING_LITERAL, "xyz") // String literal
Tokens Type
A Tokens is a sequence consisting of multiple Tokens. We can use a Token array to directly construct a Tokens. Here are three basic methods for constructing a Tokens instance.
Tokens() // Construct an empty list
Tokens(tks: Array<Token>)
Tokens(tks: ArrayList<Token>)
In addition, the following functions are supported by Tokens types:
size: returns the number ofTokencontained inTokens.get(index: Int64): obtains theTokenelement with a specified index.[]: obtains theTokenelement with a specified index.+: concatenates twoTokensor directly concatenateTokensandToken.dump(): prints allTokenfor debugging.toString(): prints the program segment corresponding toTokens.
In the following example, we use constructors to construct Token and Tokens, and print the debugging details.
import std.ast.*
let tks = Tokens(Array<Token>([
Token(TokenKind.INTEGER_LITERAL, "1"),
Token(TokenKind.ADD),
Token(TokenKind.INTEGER_LITERAL, "2")
]))
main() {
println(tks)
tks.dump()
}
The expected output is as follows (the exact location may vary).
1 + 2
description: integer_literal, token_id: 140, token_literal_value: 1, fileID: 1, line: 4, column: 5
description: add, token_id: 12, token_literal_value: +, fileID: 1, line: 5, column: 5
description: integer_literal, token_id: 140, token_literal_value: 2, fileID: 1, line: 6, column: 5
The dump information includes the kind (description) and value (token_literal_value) of each Token. Finally, the location information of each Token is printed.
quote Expression and Interpolation
In most cases, it is cumbersome to directly construct and concatenate Tokens. Therefore, the Cangjie language provides the quote expression to construct Tokens based on a code template. It is referred to as a code template because quote allows you to use $(...) to insert expressions. The types of the inserted expressions must support the conversion to Tokens (that is, implement the ToTokens interface). In the standard library, the following types implement the ToTokens interface:
- All node types (For details, see Syntax Nodes)
TokenandTokenstypes- All fundamental data types: integer, floating-point number,
Bool,Rune, andString Array<T>andArrayList<T>. Here, theTtype is constrained, and the output separators vary depending on theTtype. For details, see Cangjie Libraries.
The following presents an example of interpolating Array and a fundamental data type.
import std.ast.*
let intList = Array<Int64>([1, 2, 3, 4, 5])
let float: Float64 = 1.0
let str: String = "Hello"
let tokens = quote(
arr = $(intList)
x = $(float)
s = $(str)
)
main() {
println(tokens)
}
The output is as follows.
arr =[1, 2, 3, 4, 5]
x = 1.000000
s = "Hello"
For more details about the interpolation usage, see Using the quote Interpolation Syntax Node.
In particular, if a quote expression contains certain special Tokens, escaping is required.
- Unmatched parentheses are not allowed in
quoteexpressions unless escaped with\. - When
$is intended as a regularTokennot for code interpolation, use\to escape it. - Any other appearance of
\in aquoteexpression will result in a compilation error.
Here are some examples of quote expressions containing these special Tokens:
import std.ast.*
let tks1 = quote((x)) // ok
let tks2 = quote(\() // ok
let tks3 = quote( ( \) ) ) // ok
let tks4 = quote()) // error: unmatched delimiter: ')'
let tks5 = quote( ( \) ) // error: unclosed delimiter: '('
let tks6 = quote(\$(1)) // ok
let tks7 = quote(\x) // error: unknown start of token: \
Syntax Nodes
During the compilation of the Cangjie language, the code is converted into Tokens through lexical analysis, and then the syntax of Tokens is parsed to obtain a syntax tree. A node of each syntax tree could be an expression, declaration, type, pattern, among others. The ast library of Cangjie provides a class for each node, with an appropriate inheritance relationship among the classes. The main abstract classes are as follows:
Node: parent class of all syntax nodes.TypeNode: parent class of all type nodes.Expr: parent class of all expression nodes.Decl: parent class of all declaration nodes.Pattern: parent class of all pattern nodes.
For more details about the various node types, see Cangjie Programming Language Library API. In the examples below, the following two nodes are used:
BinaryExpr: binary operation expression.FuncDecl: function declaration.
Node Parsing
The ast library enables basically each type of node to be parsed from Tokens. There are two ways to parse a node.
Using Functions for Expression and Declaration Parsing
The following functions can be used to parse any expression or declaration from Tokens:
parseExpr(input: Tokens): Expr: Parses the inputTokensinto an expression.parseExprFragment(input: Tokens, startFrom!: Int64 = 0): (Expr, Int64): Parses a segment of the inputTokensinto an expression. The segment starts from thestartFromindex. The parsing may consume only a part of the segment starting from thestartFromindex and return the index of the first unconsumedToken. If the entire segment is consumed,input.sizeis returned.parseDecl(input: Tokens, astKind!: String = ""): Parses the inputTokensinto a declaration.astKindis an additional setting. For details, see Cangjie Programming Language Library API.parseDeclFragment(input: Tokens, startFrom!: Int64 = 0): (Decl, Int64): Parses a segment of the inputTokensinto a declaration. The meanings of thestartFromparameter and return index are the same as those ofparseExpr.
The following code cases illustrate how to use these functions.
let tks1 = quote(a + b)
let tks2 = quote(u + v, x + y)
let tks3 = quote(
func f1(x: Int64) { return x + 1 }
)
let tks4 = quote(
func f2(x: Int64) { return x + 2 }
func f3(x: Int64) { return x + 3 }
)
let binExpr1 = parseExpr(tks1)
let (binExpr2, mid) = parseExprFragment(tks2)
let (binExpr3, _) = parseExprFragment(tks2, startFrom: mid + 1) // Skip the comma.
println("binExpr1 = ${binExpr1.toTokens()}")
println("binExpr2 = ${binExpr2.toTokens()}, binExpr3 = ${binExpr3.toTokens()}")
let funcDecl1 = parseDecl(tks3)
let (funcDecl2, mid2) = parseDeclFragment(tks4)
let (funcDecl3, _) = parseDeclFragment(tks4, startFrom: mid2)
println("${funcDecl1.toTokens()}")
println("${funcDecl2.toTokens()}")
println("${funcDecl3.toTokens()}")
The output is as follows:
binExpr1 = a + b
binExpr2 = u + v, binExpr3 = x + y
func f1(x: Int64) {
return x + 1
}
func f2(x: Int64) {
return x + 2
}
func f3(x: Int64) {
return x + 3
}
Using Constructors for Parsing
Most node types support the init(input: Tokens) constructor, which can parse the input Tokens to the node of the corresponding type. For example:
import std.ast.*
let binExpr = BinaryExpr(quote(a + b))
let funcDecl = FuncDecl(quote(func f1(x: Int64) { return x + 1 }))
If the parsing fails, an exception is thrown. This parsing method applies to code snippets whose types are known, so manual type casting are not needed.
Node Composition
After a node is parsed based on Tokens, you can view the components of the node. The components of BinaryExpr and FuncDecl are listed as examples. For details about the components of other nodes, see Cangjie Programming Language Library API.
BinaryExprnode:leftExpr: Expr: expression on the left of the operatorop: Token: operatorrightExpr: Expr: expression on the right of the operator
FuncDeclnode (partial):identifier: Token: function namefuncParams: ArrayList<FuncParam>: parameter listdeclType: TypeNode: return value typeblock: Block: function body
FuncParamnode (partial):identifier: Token: parameter nameparamType: TypeNode: parameter type
Blocknode (partial):nodes: ArrayList<Node>: expressions and declarations in a block
Each component is a public mut prop and can be viewed and updated. Here are some examples of update results.
Case of BinaryExpr
let binExpr = BinaryExpr(quote(x * y))
binExpr.leftExpr = BinaryExpr(quote(a + b))
println(binExpr.toTokens())
binExpr.op = Token(TokenKind.ADD)
println(binExpr.toTokens())
The output is as follows:
(a + b) * y
a + b + y
To begin with, it is identified through parsing that binExpr represents the node x * y, as depicted in the following figure.
*
/ \
x y
After that, we replace the left node (that is, x) with a + b, which obtains the following syntax tree:
*
/ \
+ y
/ \
a b
When the syntax tree is tokenized (with toTokens), parentheses must be added around a + b to obtain (a + b) * y. (If a + b * y is a result, multiplication is performed before addition, which contradicts the connotation of the syntax tree.) The ast library can automatically add parentheses when the syntax tree is tokenized.
Finally, we replace the operator at the root of the syntax tree from * to + to obtain the following syntax tree:
+
/ \
+ y
/ \
a b
The syntax tree can be tokenized as a + b + y because addition is inherently left-associative and requires no parentheses on the left.
Case of FuncDecl
let funcDecl = FuncDecl(quote(func f1(x: Int64) { x + 1 }))
funcDecl.identifier = Token(TokenKind.IDENTIFIER, "foo")
println("Number of parameters: ${funcDecl.funcParams.size}")
funcDecl.funcParams[0].identifier = Token(TokenKind.IDENTIFIER, "a")
println("Number of nodes in body: ${funcDecl.block.nodes.size}")
let binExpr = (funcDecl.block.nodes[0] as BinaryExpr).getOrThrow()
binExpr.leftExpr = parseExpr(quote(a))
println(funcDecl.toTokens())
In this case, a FuncDecl node is constructed through parsing, and the function name, parameter name, and part of the expression in the function body are modified. The output is as follows:
Number of parameters: 1
Number of nodes in body: 1
func foo(a: Int64) {
a + 1
}
Using the quote Interpolation Syntax Node
Any node of an abstract syntax tree (AST) can be interpolated in the quote statement, and the ArrayList lists of some AST nodes can also be interpolated (corresponding to scenarios where such node lists appear in practice). Interpolation can be directly expressed by $(node), where node is an instance of any node type.
Next, we will demonstrate how to interpolate nodes through some cases.
var binExpr = BinaryExpr(quote(1 + 2))
let a = quote($(binExpr))
let b = quote($binExpr)
let c = quote($(binExpr.leftExpr))
let d = quote($binExpr.leftExpr)
println("a: ${a.toTokens()}")
println("b: ${b.toTokens()}")
println("c: ${c.toTokens()}")
println("d: ${d.toTokens()}")
The output is as follows:
a: 1 + 2
b: 1 + 2
c: 1
d: 1 + 2.leftExpr
Generally, the expression after an interpolation operator uses parentheses to limit the scope, for example, $(binExpr). If there is only one identifier, the expression can be written as $binExpr, with the parentheses omitted. In this case, both a and b insert the binExpr node into the quote statement, and the result is 1 + 2. However, if the expression after the interpolation operator is more complex, a scope error may occur if parentheses are not added. For example, the expression binExpr.leftExpr is evaluated as the left part of expression 1 + 2, that is, 1. Therefore, 1 is correctly assigned to c. However, the interpolation in d is interpreted as ($binExpr).leftExpr, so the result is 1 + 2.leftExpr. To specify the scope of interpolation, you are advised to use parentheses in interpolation operations.
The following example shows the interpolation of a node list (ArrayList).
var incrs = ArrayList<Node>()
for (i in 1..=5) {
incrs.append(parseExpr(quote(x += $(i))))
}
var foo = quote(
func foo(n: Int64) {
let x = n
$(incrs)
x
})
println(foo)
The output is as follows:
func foo(n: Int64) {
let x = n
x += 1
x += 2
x += 3
x += 4
x += 5
x
}
In this case, we create a node list incrs that contains expressions x += 1, ..., x += 5. The interpolation of incrs lists the nodes in sequence and wraps the line for each node. This applies to the scenario where expressions and declarations that need to be executed sequentially are inserted.
The following example shows that in some cases, parentheses need to be added around the interpolation for correctness.
var binExpr1 = BinaryExpr(quote(x + y))
var binExpr2 = BinaryExpr(quote($(binExpr1) * z)) // Error: x + y x z is obtained.
println("binExpr2: ${binExpr2.toTokens()}")
println("binExpr2.leftExpr: ${binExpr2.leftExpr.toTokens()}")
println("binExpr2.rightExpr: ${binExpr2.rightExpr.toTokens()}")
var binExpr3 = BinaryExpr(quote(($(binExpr1)) * z)) / Correct: (x + y) x z is obtained.
println("binExpr3: ${binExpr3.toTokens()}")
The output is as follows:
binExpr2: x + y * z
binExpr2.leftExpr: x
binExpr2.rightExpr: y * z
binExpr3: (x + y) * z
First, we construct the expression x + y, and then insert the expression into the $(binExpr1) * z template. The intent is to obtain an expression that first computes x + y and then multiplies the result by z. However, the result of interpolation is x + y * z, in which y * z is performed before x is added. This is because interpolation cannot automatically add parentheses to ensure the atomicity of the inserted expression, which differs from the replacement of leftExpr introduced in the previous section. Therefore, parentheses need to be added around $(binExpr1) to ensure result correctness.
Macro Implementation
This section describes the definition and usage of the Cangjie macros, which can be classified into Non-attribute Macros and Attribute Macros. In addition, the behaviors when macros are nested are illustrated.
Non-attribute Macros
Non-attribute macros receive only code and reject other parameters (attributes). They are defined in the following format:
import std.ast.*
public macro MacroName(args: Tokens): Tokens {
... // Macro body
}
A macro can be called in the following format:
@MacroName(...)
A macro is called with (). The value in the parentheses can be any valid tokens or blank.
When a macro is used for declaration, parentheses can be omitted under normal circumstances. The following presents some examples.
@MacroName func name() {} // Before a FuncDecl
@MacroName struct name {} // Before a StructDecl
@MacroName class name {} // Before a ClassDecl
@MacroName var a = 1 // Before a VarDecl
@MacroName enum e {} // Before an Enum
@MacroName interface i {} // Before a InterfaceDecl
@MacroName extend e <: i {} // Before an ExtendDecl
@MacroName mut prop i: Int64 {} // Before a PropDecl
@MacroName @AnotherMacro(input) // Before a macro call
Valid Tokens in the parentheses must meet the following requirements:
-
The input must be a sequence composed of valid
Tokens. Symbols like "#", "`", and "\" cannot be used individually as input, as they are not valid CangjieTokens. -
If the input contains unmatched parentheses, use the escape character ("\") to escape them.
-
If the at sign "@" needs to be included as the input
Token, use the escape character ("\") to escape it.
The following example illustrates these special requirements.
// Illegal input Tokens
@MacroName(#) // Not a whole Token
@MacroName(`) // Not a whole Token
@MacroName(() // ( and ) not match
@MacroName(\[) // Escape for unsupported symbol
// Legal input Tokens
@MacroName(#"abc"#)
@MacroName(`class`)
@MacroName([)
@MacroName([])
@MacroName(\()
@MacroName(\@)
The macro expansion process works on the Cangjie syntax tree. After the macro is expanded, the compiler continues the subsequent compilation. Therefore, you need to ensure that the code after the expansion is still valid Cangjie code. Otherwise, compilation problems may occur. When a macro is used for declaration, if the parentheses are omitted, the macro input must be a declaration with valid syntax. IDE enables syntax check and highlighting.
Here are some typical examples of macro application.
-
Example 1
Macro definition file
macro_definition.cjmacro package macro_definition import std.ast.* public macro testDef(input: Tokens): Tokens { println("I'm in macro body") return input }Macro call file
macro_call.cjpackage macro_calling import macro_definition.* main(): Int64 { println("I'm in function body") let a: Int64 = @testDef(1 + 2) println("a = ${a}") return 0 }For details about how to compile the preceding code, see Compiling and Using Macros.
I'm in macro bodyfrom the macro definition will be printed duringmacro_call.cjcompilation, when the macro definition is evaluated. In addition, the macro call point will be expanded. The following is an example of code compilation:let a: Int64 = @testDef(1 + 2)The compiler inserts the
Tokensreturned by the macro to the syntax tree where the call point is located to obtain following code:let a: Int64 = 1 + 2That is, the actual code in the executable program turns into the following:
main(): Int64 { println("I'm in function body") let a: Int64 = 1 + 2 println("a = ${a}") return 0 }The value of
ais calculated to be 3. Therefore, the value ofais printed as 3. Thus, the execution result of the preceding program is:I'm in function body a = 3
A more significant example in processing functions with macros is presented as follows: where the ModifyFunc macro adds the Composer parameter to MyFunc and inserts a code segment before and after counter++.
-
Example 2
Macro definition file
macro_definition.cj// file macro_definition.cj macro package macro_definition import std.ast.* public macro ModifyFunc(input: Tokens): Tokens { println("I'm in macro body") let funcDecl = FuncDecl(input) return quote( func $(funcDecl.identifier)(id: Int64) { println("start ${id}") $(funcDecl.block.nodes) println("end") }) }Macro call file
macro_call.cjpackage macro_calling import macro_definition.* var counter = 0 @ModifyFunc func MyFunc() { counter++ } func exModifyFunc() { println("I'm in function body") MyFunc(123) println("MyFunc called: ${counter} times") return 0 } main(): Int64 { exModifyFunc() }Likewise, the preceding two code segments are located in different files. The macro definition file
macro_definition.cjis compiled before the macro call filemacro_call.cjto generate an executable file.In this example, a function declaration is input for the ModifyFunc macro. Therefore, the parentheses can be omitted.
@ModifyFunc func MyFunc() { counter++ }The following code is obtained after macro expansion:
func MyFunc(id: Int64) { println("start ${id}") counter++ println("end") }Since MyFunc is called in main and the argument it receives is also defined in main, a valid Cangjie program is formed. The following information is printed during program execution:
I'm in function body start 123 end MyFunc called: 1 times
Attribute Macros
Compared with a non-attribute macro, an attribute macro adds to its definition an input parameter of the Tokens type, which allows developers to privide additional information. For example, if a developer wants to use different macro expansion strategies in different call scenarios, they can utilize the attribute to tag a setting. In addition, the attribute input parameter can accept any tokens, which can be combined with the code modified by the macro. The following is a simple example.
// Macro definition with attribute
public macro Foo(attrTokens: Tokens, inputTokens: Tokens): Tokens {
return attrTokens + inputTokens // Concatenate attrTokens and inputTokens.
}
As shown in the preceding macro definition, the number of input parameters of the attribute macro is 2 and the input parameter type is Tokens. A series of transformation operations such as combination and concatenation can be performed on attrTokens and inputTokens. Finally, a new Tokens is returned.
The method for calling macros with or without attributes is similar. When a macro with attributes is called, the new input parameter attrTokens is passed through []. The way of calling is as follows:
// attribute macro with parentheses
var a: Int64 = @Foo[1+](2+3)
// attribute macro without parentheses
@Foo[public]
struct Data {
var count: Int64 = 100
}
-
The preceding shows an example of calling the Foo macro, in which the parameter
2+3is concatenated with the attribute1+in[]to obtainvar a: Int64 = 1+2+3after macro expansion. -
When the parameter is changed to struct Data and is concatenated with the attribute
publicin[], the following is obtained after macro expansion:public struct Data { var count: Int64 = 100 }
Be mindful of the following points about attribute macros:
-
Attribute macros share the same AST that can be modified with non-attribute macros, with some enhancements in input parameters.
-
The validity requirements for the parameters in the parentheses in attribute macros are the same as those in non-attribute macros.
-
Valid parameters (attributes) in the square brackets in attribute macros must meet the following requirements:
-
The input must be a sequence composed of valid
Tokens. Symbols like "#", "`", and "\" cannot be used individually as input, as they are not valid CangjieTokens. -
If the input contains unmatched square brackets, use the escape character ("\") to escape them.
-
If the at sign "@" needs to be included as the input
Token, use the escape character ("\") to escape it.
// Illegal attribute Tokens @MacroName[#]() // Not a whole Token @MacroName[`]() // Not a whole Token @MacroName[@]() // Not escape for @ @MacroName[[]() // [ and ] not match @MacroName[\(]() // Escape for unsupported symbol // Legal attribute Tokens @MacroName[#"abc"#]() @MacroName[`class`]() @MacroName[(]() @MacroName[()]() @MacroName[\[]() @MacroName[\@]() -
-
The macro definition must be consistent with the call type. If a macro definition contains two input parameters, it is an attribute macro definition, indicating
[]must be added on the call site and the content can be left blank. If the macro definition contains one input parameter, it is a non-attribute macro definition, in which case[]cannot be used during the call.
Nested Macros
The Cangjie language does not support nesting macro definitions, but allows nesting macro calls in macro definitions and macro calls in some circumstances.
Nesting Macro Calls in a Macro Definition
The following is an example of a macro definition containing other macro calls.
The macro package pkg1 defines the getIdent macro.
macro package pkg1
import std.ast.*
public macro getIdent(attr:Tokens, input:Tokens):Tokens {
return quote(
let decl = (parseDecl(input) as VarDecl).getOrThrow()
let name = decl.identifier.value
let size = name.size - 1
let $(attr) = Token(TokenKind.IDENTIFIER, name[0..size])
)
}
The macro package pkg2 defines the Prop macro, in which the getIdent macro is called.
macro package pkg2
import std.ast.*
import pkg1.*
public macro Prop(input:Tokens):Tokens {
let v = parseDecl(input)
@getIdent[ident](input)
return quote(
$(input)
public prop $(ident): $(decl.declType) {
get() {
this.$(v.identifier)
}
}
)
}
The macro package pkg3 package calls the Prop macro.
package pkg3
import pkg2.*
class A {
@Prop
private let a_: Int64 = 1
}
main() {
let b = A()
println("${b.a}")
}
Note that the preceding three files must be compiled in the sequence of pkg1, pkg2, pkg3 based on the constraint that a macro definition must be compiled before a macro call point. The definition of the Prop macro in pkg2 is as follows:
public macro Prop(input:Tokens):Tokens {
let v = parseDecl(input)
@getIdent[ident](input)
return quote(
$(input)
public prop $(ident): $(decl.declType) {
get() {
this.$(v.identifier)
}
}
)
}
The following code is expanded before compilation:
public macro Prop(input: Tokens): Tokens {
let v = parseDecl(input)
let decl = (parseDecl(input) as VarDecl).getOrThrow()
let name = decl.identifier.value
let size = name.size - 1
let ident = Token(TokenKind.IDENTIFIER, name[0 .. size])
return quote(
$(input)
public prop $(ident): $(decl.declType) {
get() {
this.$(v.identifier)
}
}
)
}
Nesting Macro Calls in a Macro Call
A common scenario of macro nesting is that macros are called in the code blocks modified by a macro. Here is an example:
The pkg1 package defines the Foo and Bar macros.
macro package pkg1
import std.ast.*
public macro Foo(input: Tokens): Tokens {
return input
}
public macro Bar(input: Tokens): Tokens {
return input
}
The pkg2 package defines the addToMul macro.
macro package pkg2
import std.ast.*
public macro addToMul(inputTokens: Tokens): Tokens {
var expr: BinaryExpr = match (parseExpr(inputTokens) as BinaryExpr) {
case Some(v) => v
case None => throw Exception()
}
var op0: Expr = expr.leftExpr
var op1: Expr = expr.rightExpr
return quote(($(op0)) * ($(op1)))
}
The pkg3 package uses the three macros defined above:
package pkg3
import pkg1.*
import pkg2.*
@Foo
struct Data {
let a = 2
let b = @addToMul(2+3)
@Bar
public func getA() {
return a
}
public func getB() {
return b
}
}
main(): Int64 {
let data = Data()
var a = data.getA() // a = 2
var b = data.getB() // b = 6
println("a: ${a}, b: ${b}")
return 0
}
As shown in the preceding code, the macro Foo modifies struct Data, in which the addToMul and Bar macros are called. In such a nesting scenario, the rule for code transformation is to expand the inner macros (addToMul and Bar) within the nested structure before expanding the outer macro (Foo). The same rule applies to the scenario where multi-layer macros are nested.
Macros can be nested in macro calls with or without parentheses. The two types of macro calls can be combined only if there is no ambiguity and the macro expansion sequence is clear.
var a = @foo(@foo1(2 * 3)+@foo2(1 + 3)) // foo1, foo2 have to be defined.
@Foo1 // Foo2 expands first, then Foo1 expands.
@Foo2[attr: struct] // Attribute macro can be used in nested macro.
struct Data{
@Foo3 @Foo4[123] var a = @bar1(@bar2(2 + 3) + 3) // bar2, bar1, Foo4, Foo3 expands in order.
public func getA() {
return @foo(a + 2)
}
}
Message Transfer Between Nested Macros
Here we focus on the message transfer between macros nested in macro calls.
An inner macro can call the assertParentContext library function to ensure it is nested in a specific outer macro call. If the inner macro calls the function but fails to be nested in the given outer macro call, the function throws an error. The InsideParentContext library function also checks whether an inner macro call is nested in a specific outer macro call and returns a Boolean value. The following is a simple example.
The macro is defined as follows:
public macro Outer(input: Tokens): Tokens {
return input
}
public macro Inner(input: Tokens): Tokens {
assertParentContext("Outer")
return input
}
The macro is called as follows:
@Outer var a = 0
@Inner var b = 0 // Error, The macro call 'Inner' should with the surround code contains a call 'Outer'.
As shown in the preceding code, the Inner macro uses the assertParentContext function to check whether it is within the Outer macro during the call. The macro call example in the code indicates such a nesting relationship does not exist between the two macros during the call. Therefore, the compiler reports an error.
The inner macros can communicate with the outer macro by sending key/value pairs. When an inner macro is executed, the standard library function setItem is called to send a message to the outer macro. When an outer macro is executed, the standard library function getChildMessages is called to receive the message (a key/value pair mapping) sent by each inner macro. The following is a simple example.
The macro is defined as follows:
macro package define
import std.ast.*
public macro Outer(input: Tokens): Tokens {
let messages = getChildMessages("Inner")
let getTotalFunc = quote(public func getCnt() {
)
for (m in messages) {
let identName = m.getString("identifierName")
// let value = m.getString("key") // Receive multiple groups of messages
getTotalFunc.append(Token(TokenKind.IDENTIFIER, identName))
getTotalFunc.append(quote(+))
}
getTotalFunc.append(quote(0))
getTotalFunc.append(quote(}))
let funcDecl = parseDecl(getTotalFunc)
let decl = (parseDecl(input) as ClassDecl).getOrThrow()
decl.body.decls.append(funcDecl)
return decl.toTokens()
}
public macro Inner(input: Tokens): Tokens {
assertParentContext("Outer")
let decl = parseDecl(input)
setItem("identifierName", decl.identifier.value)
// setItem ("key," "value") // Transfer multiple groups of messages through different key values
return input
}
The macro is called as follows:
import define.*
@Outer
class Demo {
@Inner var state = 1
@Inner var cnt = 42
}
main(): Int64 {
let d = Demo()
println("${d.getCnt()}")
return 0
}
In the preceding code, Outer receives the variable names sent by two Inner macros and automatically adds the following content to the class:
public func getCnt() {
state + cnt + 0
}
The process is detailed as follows: The inner macros Inner send messages to the outer macro through setItem. The Outer macro receives a group of message objects sent by Inner macros through the getChildMessages function (Inner can be called for multiple times in Outer) and obtains the corresponding value of the message objects through the getString function.
Compiling, Error Reporting, and Debugging
Compiling and Using Macros
The current compiler restricts that the definition and invocation of a macro cannot be in the same package. The macro package must be compiled before the package calling the macro. The macro definition is not allowed in the package calling the macro. Since macros need to be exported from a package for use by another package, the compiler mandates that macro definitions must be declared with the public modifier.
The following is a simple example.
The structure of the source code directory is as follows.
// Directory layout.
src
`-- macros
|-- m.cj
`-- demo.cj
The macro definition is stored in the macros subdirectory.
// macros/m.cj
// In this file, we define the macro Inner, Outer.
macro package define
import std.ast.*
public macro Inner(input: Tokens) {
return input
}
public macro Outer(input: Tokens) {
return input
}
The macro calling code is as follows.
// demo.cj
import define.*
@Outer
class Demo {
@Inner var state = 1
@Inner var cnt = 42
}
main() {
println("test macro")
0
}
The following are the compilation commands for the Linux platform. (The specific compilation options will evolve with the cjc update. Use the latest cjc compilation options.)
# Current directory: src
# Compile the macro definition file to generate the default dynamic library file in the current directory. (You can specify the path for the dynamic library, but not the name of the library.)
cjc macros/m.cj --compile-macro
# Compile the file that uses the macro. After the macro is replaced, an executable file is generated.
cjc demo.cj -o demo
# Run the executable file.
./demo
On the Linux platform, the macro_define.cjo and dynamic library files are generated for package management.
The following are the compilation commands for the Windows platform.
# Current directory: src
# Compile the macro definition file to generate the default dynamic library file in the current directory. (You can specify the path for the dynamic library, but not the name of the library.)
cjc macros/m.cj --compile-macro
# Compile the file that uses the macro. After the macro is replaced, an executable file is generated.
cjc demo.cj -o demo.exe
Note:
Macro invocation depends on Cangjie Runtime. During the invocation, the default Cangjie Runtime configuration is used. The configuration parameters can be queried through Cangjie Runtime O&M logs. Only cjHeapSize and cjStackSize can be modified by users. For details about Cangjie Runtime configuration initialization, see Runtime Initialization Configuration Options.
Parallel Macro Expansion
You can add the --parallel-macro-expansion option when compiling a file with macro calls to enable the parallel macro expansion capability. The compiler automatically analyzes the dependency between macro calls. Macro calls that do not depend on each other can be executed in parallel. For example, two @Inner calls can be executed in parallel to shorten the overall compilation time.
Note:
If a macro function depends on some global variables, it is risky to use parallel macro expansion.
macro package define
import std.ast.*
import std.collection.*
var Counts = HashMap<String, Int64>()
public macro Inner(input: Tokens) {
for (t in input) {
if (t.value.size == 0) {
continue
}
// Count the number of occurrences of all valid token values.
if (!Counts.contains(t.value)) {
Counts[t.value] = 0
}
Counts[t.value] = Counts[t.value] + 1
}
return input
}
public macro B(input: Tokens) {
return input
}
According to the preceding code, if the @Inner macro is called in multiple places and the parallel macro expansion option is enabled, a conflict may occur when the global variable Counts is accessed. As a result, the obtained result is incorrect.
You are advised not to use global variables in macro functions. If you cannot avoid using them, either disable parallel macro expansion or protect global variables using Cangjie thread locks.
diagReport Error Reporting Mechanism
The Cangjie ast package provides the custom error reporting API diagReport. Users who define macros can customize the error messages for incorrect Tokens content when passed tokens are parsed.
The user-defined error reporting API provides the same output format as the native compiler error reporting API and allows users to report warning and error messages.
The prototype of the diagReport function is as follows.
public func diagReport(level: DiagReportLevel, tokens: Tokens, message: String, hint: String): Unit
The parameters are described as follows.
- level: severity level of the error message.
- tokens: tokens from the source code that are referenced in the error message.
- message: main error message.
- hint: auxiliary information.
For details, see the following example.
Macro definition file:
// macro_definition.cj
macro package macro_definition
import std.ast.*
public macro testDef(input: Tokens): Tokens {
for (i in 0..input.size) {
if (input[i].kind == IDENTIFIER) {
diagReport(DiagReportLevel.ERROR, input[i..(i + 1)],
"This expression is not allowed to contain identifier",
"Here is the illegal identifier")
}
}
return input
}
Macro call file:
// macro_call.cj
package macro_calling
import std.ast.*
import macro_definition.*
main(): Int64 {
let a = @testDef(1)
let b = @testDef(a)
let c = @testDef(1 + a)
return 0
}
The following error information is displayed during the compilation of the macro call file:
error: This expression is not allowed to contain identifier
==> call.cj:9:22:
|
9 | let b = @testDef(a)
| ^ Here is the illegal identifier
|
error: This expression is not allowed to contain identifier
==> call.cj:10:26:
|
10 | let c = @testDef(1 + a)
| ^ Here is the illegal identifier
|
2 errors generated, 2 errors printed.
Using --debug-macro to Output the Macro Expansion Result
When macros are used to generate code during compilation, debugging errors can be particularly difficult. This is a common problem for developers, as the source code written by the developer is transformed into different code snippets after macro expansion. The error messages thrown by the compiler are based on the final generated code, but this code is not directly visible in the developer's source code.
To solve this problem, Cangjie macros offer a debug mode. In this mode, developers can view the complete expanded macro code in the debug file generated by the compiler. An example is provided below:
Macro definition file:
macro package define
import std.ast.*
public macro Outer(input: Tokens): Tokens {
let messages = getChildMessages("Inner")
let getTotalFunc = quote(public func getCnt() {
)
for (m in messages) {
let identName = m.getString("identifierName")
getTotalFunc.append(Token(TokenKind.IDENTIFIER, identName))
getTotalFunc.append(quote(+))
}
getTotalFunc.append(quote(0))
getTotalFunc.append(quote(}))
let funcDecl = parseDecl(getTotalFunc)
let decl = (parseDecl(input) as ClassDecl).getOrThrow()
decl.body.decls.append(funcDecl)
return decl.toTokens()
}
public macro Inner(input: Tokens): Tokens {
assertParentContext("Outer")
let decl = parseDecl(input)
setItem("identifierName", decl.identifier.value)
return input
}
Macro call file demo.cj:
import define.*
@Outer
class Demo {
@Inner var state = 1
@Inner var cnt = 42
}
main(): Int64 {
let d = Demo()
println("${d.getCnt()}")
return 0
}
When compiling the file that uses the macro, add --debug-macro to the option, that is, use the debug mode of the Cangjie macro.
cjc --debug-macro demo.cj
In debug mode, a temporary file demo.cj.macrocall is generated. The corresponding macro expansion is as follows.
// demo.cj.macrocall
/* ===== Emitted by MacroCall @Outer in demo.cj:3:1 ===== */
/* 3.1 */class Demo {
/* 3.2 */ var state = 1
/* 3.3 */ var cnt = 42
/* 3.4 */ public func getCnt() {
/* 3.5 */ state + cnt + 0
/* 3.6 */ }
/* 3.7 */}
/* 3.8 */
/* ===== End of the Emit ===== */
If there is a semantic error in the expanded code, the compiler's error messages will trace back to the specific line and column of the expanded macro code. Pay attention to the following points when using the debug mode of the Cangjie macro:
-
In debug mode, the source code's line and column numbers are rearranged, which may not be suitable for certain special scenarios, such as handling line breaks. For example:
// before expansion @M{} - 2 // macro M return 2 // after expansion // ===== Emmitted my Macro M at line 1 === 2 // ===== End of the Emit ===== - 2The debug mode should not be used in cases where semantics is changed due to newline characters.
-
Macro calls cannot be debugged in the macro definition. Otherwise, a compilation error is reported.
public macro M(input: Tokens) { let a = @M2(1+2) // M2 is in macro M, not suitable for debug mode. return input + quote($a) } -
The debugging of macros with parentheses is not supported.
// main.cj main() { // For macro with parenthesis, newline introduced by debug will change the semantics // of the expression, so it is not suitable for debug mode. let t = @M(1+2) 0 }
Defining and Importing Macro Packages
The definition of a Cangjie macro must be placed in the package declared as a macro package. The package constrained by the macro package allows only the macro definition to be visible to external systems.
Note:
Re-exported declarations are also visible to external systems. For details about package management and re-export, see Package Import.
// file define.cj
macro package define // Compile define.cjo with the macro attributes.
import std.ast.*
public func A() {} // Error, macro package does not allow external visible non-macro definitions. An error is reported.
public macro M(input: Tokens): Tokens { // macro M is visible to external systems.
return input
}
It should be specifically noted that in a macro package, symbols from both macro packages and non-macro packages can be re-exported. In a non-macro package, only symbols from non-macro packages can be re-exported.
See the following example.
-
Define the
M1macro in a macro package Amacro package A import std.ast.* public macro M1(input: Tokens): Tokens { return input }The compilation command is as follows.
cjc A.cj --compile-macro -
Define a public function
f1in a non-macro package B. Note that themacro packagesymbols cannot be re-exported in a non-macro package.package B // public import A.* // Error, it is not allowed to re-export a macro package in a package. public func f1(input: Int64): Int64 { return input }The following is the compilation command. Here we use the
--output-typeoption to compile the B package into the dynamic library. For details about the cjc compilation options, see cjc Compilation Options.cjc B.cj --output-type=dylib -o libB.so -
Define the
M2macro in macro package C, which relies on the content of packages A and B. It can be observed thatmacro packageand non-macro packagesymbols can be re-exported in themacro package.macro package C public import A.* // correct: macro package is allowed to re-export in a macro package. public import B.* // correct: non-macro package is also allowed to re-export in a macro package. import std.ast.* public macro M2(input: Tokens): Tokens { return @M1(input) + Token(TokenKind.NL) + quote(f1(1)) }The following shows the compilation command. Note that the dynamic library of the B package needs to be explicitly linked.
cjc C.cj --compile-macro -L. -lB -
Use the
M2macro inmain.cjimport C.* main() { @M2(let a = 1) }The compilation command is as follows.
cjc main.cj -o main -L. -lBThe result obtained by expanding the
M2macro inmain.cjis:import C.* main() { let a = 1 f1(1) }
It is obvious that the symbol f1 from package B appears in main.cj. The macro compiler can re-export the symbols in the B package in the C package, enabling users to correctly compile the code after macro expansion by importing only the macro package. If only import C.M2 is used to import macro symbols in main.cj, the error message undeclared identifier 'f1' is reported.
Built-in Compilation Flags
The Cangjie language provides predefined compilation tags that can be used to control the behavior of the Cangjie compiler during compilation.
Source Code Location
Cangjie offers several built-in compilation tags to obtain the location of the source code during compilation.
- After
@sourcePackage()is expanded, it becomes a literal of theStringtype, representing the package name of the source code where the current macro is located. - After
@sourceFile()is expanded, it becomes a literal of theStringtype, representing the file name of the source code where the current macro is located. - After
@sourceLine()is expanded, it becomes a literal of theInt64type, representing the code line of the source code where the current macro is located.
These compilation tags can be used in any expressions, as long as they meet the type check rules. An example is provided below:
func test1() {
let s: String = @sourceFile() // The value of `s` is the current source file name
}
func test2(n!: Int64 = @sourceLine()) { /* at line 5 */
// The default value of `n` is the source file line number of the definition of `test2`
println(n) // print 5
}
Conditional Compilation
Conditional compilation uses the @When tag. It is a technology that selectively compiles different code segments in program code based on specific conditions. The main uses of conditional compilation include:
- Platform adaptation: Enables selective code compilation based on the current compilation environment, facilitating cross-platform compatibility.
- Function selection: Allows selective enabling or disabling of certain features based on different requirements, providing flexible feature configuration. For example, selectively compiling code to include or exclude certain functionalities.
- Debugging support: Supports compiling code in debug mode to improve program performance and security. For example, compiling debug information or logging code in debug mode, while excluding them in release versions.
- Performance optimization: Enables selective compilation based on predefined conditions to improve program performance.
For details about conditional compilation, see Conditional Compilation.
@FastNative
To enhance performance when interoperating with the C language, Cangjie provides the @FastNative tag to optimize C function calls. Note that @FastNative can be used only for functions declared by foreign.
An example usage is provided below:
@FastNative
foreign func strlen(str: CPointer<UInt8>): UIntNative
When using @FastNative to modify the foreign function, ensure that the corresponding C function meets the following requirements:
- The overall execution time of the function should not be too long. For example, the function should not contain large loops or produce blocking, such as calling functions like
sleepandwait. - The Cangjie method cannot be called in the function.
Practical Cases
Fast Power Calculation
Here is a simple example about how to perform evaluation with macros during compilation and generate optimized code. In calculating the power n ^ e, if e is a (large) integer, you can accelerate the calculation by repeated squaring instead of iterative multiplying. This calculation method can be implemented by using the while loop. For example:
func power(n: Int64, e: Int64) {
var result = 1
var vn = n
var ve = e
while (ve > 0) {
if (ve % 2 == 1) {
result *= vn
}
ve /= 2
if (ve > 0) {
vn *= vn
}
}
result
}
However, the implementation needs to analyze the value of e each time, and judge and update the ve for multiple times in the loop and condition judgment. In addition, the implementation supports only n of the Int64 type. To support n of other types, the problem of how to express result = 1 needs to be solved. If the value of e is known in advance, the code can be written in a simpler way. For example, if the value of e is 10, the entire loop can be expanded as follows:
func power_10(n: Int64) {
var vn = n
vn *= vn // vn = n ^ 2
var result = vn // result = n ^ 2
vn *= vn // vn = n ^ 4
vn *= vn // vn = n ^ 8
result *= vn // result = n ^ 10
result
}
Certainly, it is cumbersome to compile the code manually. Therefore, it is hoped that the code can be automatically generated after the value of e is given. This is where macro comes in. Let's look at a use case.
public func power_10(n: Int64) {
@power[10](n)
}
According to the .macrocall file, the code expanded by the macro is as follows:
public func power_10(n: Int64) {
/* ===== Emitted by MacroCall @power in main.cj:20:5 ===== */
/* 20.1 */var _power_vn = n
/* 20.2 */_power_vn *= _power_vn
/* 20.3 */var _power_result = _power_vn
/* 20.4 */_power_vn *= _power_vn
/* 20.5 */_power_vn *= _power_vn
/* 20.6 */_power_result *= _power_vn
/* 20.7 */_power_result
/* ===== End of the Emit ===== */
}
Next, we will take a look at the implementation of the @power macro.
macro package define
import std.ast.*
import std.convert.*
public macro power(attrib: Tokens, input: Tokens) {
let attribExpr = parseExpr(attrib)
if (let Some(litExpr) <- attribExpr as LitConstExpr) {
let lit = litExpr.literal
if (lit.kind != TokenKind.INTEGER_LITERAL) {
diagReport(DiagReportLevel.ERROR, attrib,
"Attribute must be integer literal",
"Expected integer literal")
}
var n = Int64.parse(lit.value)
var result = quote(var _power_vn = $(input)
)
var flag = false
while (n > 0) {
if (n % 2 == 1) {
if (!flag) {
result += quote(var _power_result = _power_vn
)
flag = true
} else {
result += quote(_power_result *= _power_vn
)
}
}
n /= 2
if (n > 0) {
result += quote(_power_vn *= _power_vn
)
}
}
result += quote(_power_result)
return result
} else {
diagReport(DiagReportLevel.ERROR, attrib,
"Attribute must be integer literal",
"Expected integer literal")
}
return input
}
Here is the interpretation of the code:
- First, the attribute
attribis checked to be an integer literal, otherwise an error is reported withdiagReport. The literal is then parsed to an integern. resultis assumed as the resulting code accumulator and thevar _power_vndeclaration is added. To avoid variable name conflicts,_power_vnis used as the name.- Then, the while loop starts. The Boolean variable
flagindicates whethervar _power_resulthas been initialized. The structure of the remaining code is similar to that of thepowerfunction. The difference lies in that the while loop and the if judgment are used to determine the generated code during compilation instead of operations. The final code is generated by properly combining_power_result *= _power_vnwith_power_vn *= _power_vn. - Finally, the code for returning
_power_resultis added.
Save the code to the macros/power.cj file and add the following test code to the main.cj file:
public func power_10(n: Int64) {
@power[10](n)
}
main() {
let a = 3
println(power_10(a))
}
The output is as follows:
59049
Memoize Macro
Memoize is a commonly used method in dynamic programming algorithms. It stores the result of a sub-problem that has been calculated. When the same sub-problem appears again, the result can be directly obtained by querying the table, avoiding repeated calculation and boosts the algorithm efficiency.
Generally, developers need to the storage and extraction functions of Memoize are implemented manually. Macros allow the process to be automatic. The macro effect is as follows:
@Memoize[true]
func fib(n: Int64): Int64 {
if (n == 0 || n == 1) {
return n
}
return fib(n - 1) + fib(n - 2)
}
main() {
let start = DateTime.now()
let f35 = fib(35)
let end = DateTime.now()
println("fib(35): ${f35}")
println("execution time: ${(end - start).toMicroseconds()} us")
}
In the preceding code, the fib function is implemented in a simple recursive mode. If @Memoize[true] is removed, the runtime of this function will grow exponentially with n. For example, if you remove @Memoize[true] from the preceding code or change true to false, the execution result of the main function will become:
fib(35): 9227465
execution time: 199500 us
If the @Memoize[true] is restored. The result will be:
fib(35): 9227465
execution time: 78 us
The same result and drastically reduced computation time indicate that the memorized effect achieved by the use of @Memoize.
To help you understand the principle of @Memoize, the results of the macro expansion of the preceding fib function are displayed, which are obtained from the .macrocall file but formatted for better readability.
import std.collection.*
var memoizeFibMap = HashMap<Int64, Int64>()
func fib(n: Int64): Int64 {
if (memoizeFibMap.contains(n)) {
return memoizeFibMap.get(n).getOrThrow()
}
let memoizeEvalResult = { =>
if (n == 0 || n == 1) {
return n
}
return fib(n - 1) + fib(n - 2)
}()
memoizeFibMap.put(n, memoizeEvalResult)
return memoizeEvalResult
}
The execution process of the preceding code is described as follows:
- First,
memoizeFibMapis defined as a hash table fromInt64toInt64. The firstInt64corresponds to the type of the unique parameter offib, and the second corresponds to the type of the return value offib. - Second, the input parameter in the function body is checked. If the parameter is in the
memoizeFibMap, the value stored in the hash table is returned immediately. Otherwise, the originalfibfunction body is used to obtain the calculation result. Here, an anonymous function (without parameters) is used to avoid changing thefibfunction body and allow any way to return from thefibfunction (in this case, the return in the middle and return of the last expression). - Finally, the calculation result is stored in
memoizeFibMapand returned.
Such a "template" makes it easy to understand the implementation of the following macros. The complete code is provided as follows:
public macro Memoize(attrib: Tokens, input: Tokens) {
if (attrib.size != 1 || attrib[0].kind != TokenKind.BOOL_LITERAL) {
diagReport(DiagReportLevel.ERROR, attrib,
"Attribute must be a boolean literal (true or false)",
"Expected boolean literal (true or false) here")
}
let memoized = (attrib[0].value == "true")
if (!memoized) {
return input
}
let fd = FuncDecl(input)
if (fd.funcParams.size != 1) {
diagReport(DiagReportLevel.ERROR, fd.lParen + fd.funcParams.toTokens() + fd.rParen,
"Input function to memoize should take exactly one argument",
"Expect only one argument here")
}
let memoMap = Token(TokenKind.IDENTIFIER, "_memoize_" + fd.identifier.value + "_map")
let arg1 = fd.funcParams[0]
return quote(
var $(memoMap) = HashMap<$(arg1.paramType), $(fd.declType)>()
func $(fd.identifier)($(arg1)): $(fd.declType) {
if ($(memoMap).contains($(arg1.identifier))) {
return $(memoMap).get($(arg1.identifier)).getOrThrow()
}
let _memoize_eval_result = { => $(fd.block.nodes) }()
$(memoMap).put($(arg1.identifier), _memoize_eval_result)
return _memoize_eval_result
}
)
}
First, the validity of the attribute and input is checked. The attribute must be a Boolean literal. If the result is false, the input is directly returned. In other cases, the input must be able to be parsed as a function declaration (FuncDecl) and must contain exactly one parameter. After that, the variable of the hash table is generated, with a variable name that avoids conflicts. Finally, the quote template is used to generate the return code, in which the variable name of the hash table, the name and type of the unique parameter, and the return type of the input function are incorporated.
Extension of a Dprint Macro
At the beginning of this section, a macro for printing expressions is used as an example. However, the macro accepts only one expression at a time. Hence, we want to extend the macro to accept multiple expressions separated by commas. The following displays how to realize this function through parseExprFragment.
The macro is implemented as follows:
public macro dprint2(input: Tokens) {
let exprs = ArrayList<Expr>()
var index: Int64 = 0
while (true) {
let (expr, nextIndex) = parseExprFragment(input, startFrom: index)
exprs.append(expr)
if (nextIndex == input.size) {
break
}
if (input[nextIndex].kind != TokenKind.COMMA) {
diagReport(DiagReportLevel.ERROR, input[nextIndex..nextIndex+1],
"Input must be a comma-separated list of expressions",
"Expected comma")
}
index = nextIndex + 1 // Skip commas
}
let result = quote()
for (expr in exprs) {
result.append(quote(
print($(expr.toTokens().toString()) + " = ")
println($(expr))
))
}
return result
}
Use case:
let x = 3
let y = 2
@dprint2(x, y, x + y)
The output is as follows:
x = 3
y = 2
x + y = 5
In implementing the macro, the while loop is used to parse each expression successively from index 0. The index variable stores the current parsing location. Each parseExprFragment call starts from current parsing position, and the latest position after parsing, together with the expression obtained, is returned. If the position after parsing reaches the end of the input, the loop exits. In other cases, the loop checks whether the reached position is a comma. If it is not a comma, the loop reports an error and exits. Otherwise, the loop skips the comma and starts the next round of parsing. After the list of expressions is obtained, each expression is output in sequence.
A Simple DSL
This case will demonstrate how to use macros to implement a simple domain specific language (DSL). Language integrated query (LINQ) is a component of the Microsoft .NET framework. It offers a unified data query syntax and allows developers to use SQL-like query statements to operate data sources. Here, we only demonstrate how to support a simplest LINQ syntax.
The syntax to be supported is as follows:
from <variable> in <list> where <condition> select <expression>
Where, variable is an identifier, and list, condition, and expression are all expressions. Therefore, the strategy for implementing a macro is to extract the identifier and expressions and check whether the keywords in the middle are correct. Finally, a query result composed of the extracted parts is generated.
The macro is implemented as follows:
public macro linq(input: Tokens) {
let syntaxMsg = "Syntax is \"from <attrib> in <table> where <cond> select <expr>\""
if (input.size == 0 || input[0].value != "from") {
diagReport(DiagReportLevel.ERROR, input[0..1], syntaxMsg,
"Expected keyword \"from\" here.")
}
if (input.size <= 1 || input[1].kind != TokenKind.IDENTIFIER) {
diagReport(DiagReportLevel.ERROR, input[1..2], syntaxMsg,
"Expected identifier here.")
}
let attribute = input[1]
if (input.size <= 2 || input[2].value != "in") {
diagReport(DiagReportLevel.ERROR, input[2..3], syntaxMsg,
"Expected keyword \"in\" here.")
}
var index: Int64 = 3
let (table, nextIndex) = parseExprFragment(input, startFrom: index)
if (nextIndex == input.size || input[nextIndex].value != "where") {
diagReport(DiagReportLevel.ERROR, input[nextIndex..nextIndex+1], syntaxMsg,
"Expected keyword \"where\" here.")
}
index = nextIndex + 1 // Skip where
let (cond, nextIndex2) = parseExprFragment(input, startFrom: index)
if (nextIndex2 == input.size || input[nextIndex2].value != "select") {
diagReport(DiagReportLevel.ERROR, input[nextIndex2..nextIndex2+1], syntaxMsg,
"Expected keyword \"select\" here.")
}
index = nextIndex2 + 1 // Skip select
let (expr, nextIndex3) = parseExprFragment(input, startFrom: index)
return quote(
for ($(attribute) in $(table)) {
if ($(cond)) {
println($(expr))
}
}
)
}
Use case:
@linq(from x in 1..=10 where x % 2 == 1 select x * x)
In this example, odd numbers are filtered out from a list of integers from 1 to 10, and the squares of all odd numbers are returned. The output is as follows:
1
9
25
49
81
As can be seen, the macro implementation is largely associated with parsing and validating the input tokens, which is crucial for the availability of macros. The syntax of the LINQ language (and most DSLs) in reality is more complex. Therefore, a complete set of parsing mechanisms is required to determine the content to be parsed by identifying different keywords or connectors.
Dynamic Features
This section introduces the dynamic features of Cangjie, which enable developers to implement functions more elegantly. The dynamic features of Cangjie consist of reflection and dynamic loading.
Introduction to Cangjie Reflection
Reflection is a mechanism by which a program can access, detect, and modify its own state or behavior.
The dynamic feature of reflection provides the following benefits:
-
It brings higher program flexibility and scalability.
-
A program can use reflection to obtain the types of objects and perform operations such as enumerations and calls on object members during execution.
-
It allows new types to be created at runtime without hard coding in advance.
However, a reflection call typically underperforms a direct call. Therefore, the reflection mechanism is applied primarily to a system framework that demands high flexibility and scalability.
How to Obtain TypeInfo
The TypeInfo class is a must-know when it comes to the reflection feature of Cangjie. This core class holds the information of any type and defines methods for obtaining type information and setting values. To facilitate user operations, we provide a series of information types such as ClassTypeInfo, PrimitiveTypeInfo, and ParameterInfo.
Three static of methods can be used to generate a TypeInfo class.
public class TypeInfo {
public static func of(a: Any): TypeInfo
public static func of(a: Object): ClassTypeInfo
public static func of<T>(): TypeInfo
}
If the of function with input parameters Any and Object types is used, the runtime type information of the instance is output. If the of function with generic parameters is used, the static type information of the input parameters is returned. The two methods generate the same information, but the object may vary.
For example, we can use reflection to obtain the information of a custom type.
import std.reflect.*
class Foo {}
main() {
let a: Foo = Foo()
let info: TypeInfo = TypeInfo.of(a)
let info2: TypeInfo = TypeInfo.of<Foo>()
println(info)
println(info2)
}
Compiling and executing the preceding code outputs the following information:
default.Foo
default.Foo
Furthermore, TypeInfo provides the static function get for use in conjunction with the dynamic loading feature. This interface can obtain TypeInfo based on the name of an input type.
public class TypeInfo {
public static func get(qualifiedName: String): TypeInfo
}
Note that the input parameters must comply with the rules of module/package.type in fully qualified mode. For the types pre-imported by the compiler, including those in the core package and those built in the compiler, such as primitive type, Option, and Iterable, their names must be directly used as the character strings to be searched for, excluding the package names and module name prefixes. If the instance of a type cannot be queried during execution, InfoNotFoundException is thrown.
let t1: TypeInfo = TypeInfo.get("Int64")
let t1: TypeInfo = TypeInfo.get("default.Foo")
let t2: TypeInfo = TypeInfo.get("std/socket.TcpSocket")
let t3: TypeInfo = TypeInfo.get("net/http.ServerBuilder")
In this case, an uninstantiated generic type cannot be obtained.
import std.collection.*
import std.reflect.*
class A<T> {
A(public let t: T) {}
}
class B<T> {
B(public let t: T) {}
}
main() {
let aInfo: TypeInfo = TypeInfo.get("default.A<Int64>")// Error,`default.A<Int64>` is not instantiated, will throw InfoNotFoundException
let b: B<Int64> = B<Int64>(1)
let bInfo: TypeInfo = TypeInfo.get("default.B<Int64>")// Ok `default.B<Int64>` has been instantiated.
}
How to Use Reflection to Access Members
After obtaining the TypeInfo class, you can access the instance members and static members of classes through interfaces. In addition, the subclass ClassTypeInfo of TypeInfo provides interfaces for accessing the public constructors of types and their member variables, attributes, and functions. Cangjie reflection is designed to access only the public members of a type, which indicates that private, protected, and default members are invisible in the reflection.
The following example describes how to obtain and modify the member variables of a type instance at runtime.
import std.reflect.*
public class Foo {
public static var param1 = 20
public var param2 = 10
}
main(): Unit{
let obj = Foo()
let info = TypeInfo.of(obj)
let staticVarInfo = info.getStaticVariable("param1")
let instanceVarInfo = info.getInstanceVariable("param2")
println ("Initial values of member variables")
print ("Static member variable ${staticVarInfo} of Foo = ")
println((staticVarInfo.getValue() as Int64).getOrThrow())
print ("Instance member variable ${instanceVarInfo} of obj = ")
println((instanceVarInfo.getValue(obj) as Int64).getOrThrow())
println ("Modify member variables")
staticVarInfo.setValue(8)
instanceVarInfo.setValue(obj, 25)
print ("Static member variable ${staticVarInfo} of Foo = ")
println((staticVarInfo.getValue() as Int64).getOrThrow())
print ("Instance member variable ${instanceVarInfo} of obj = ")
println((instanceVarInfo.getValue(obj) as Int64).getOrThrow())
return
}
Compiling and executing the preceding code outputs the following information:
Initial values of member variables
Static member variable static param1: Int64 of Foo = 20
Instance member variable of obj param2: Int64 = 10
Modify member variables
Static member variable static param1: Int64 of Foo = 8
Instance member variable of obj param2: Int64 = 25
We can also check and modify attributes through reflection.
import std.reflect.*
public class Foo {
public let _p1: Int64 = 1
public prop p1: Int64 {
get() { _p1 }
}
public var _p2: Int64 = 2
public mut prop p2: Int64 {
get() { _p2 }
set(v) { _p2 = v }
}
}
main(): Unit{
let obj = Foo()
let info = TypeInfo.of(obj)
let instanceProps = info.instanceProperties.toArray()
println ("The instance member attributes of obj include ${instanceProps}.")
let PropInfo1 = info.getInstanceProperty("p1")
let PropInfo2 = info.getInstanceProperty("p2")
println((PropInfo1.getValue(obj) as Int64).getOrThrow())
println((PropInfo2.getValue(obj) as Int64).getOrThrow())
if (PropInfo1.isMutable()) {
PropInfo1.setValue(obj, 10)
}
if (PropInfo2.isMutable()) {
PropInfo2.setValue(obj, 20)
}
println((PropInfo1.getValue(obj) as Int64).getOrThrow())
println((PropInfo2.getValue(obj) as Int64).getOrThrow())
return
}
Compiling and executing the preceding code outputs the following information:
The instance member attributes of obj include [prop p1: Int64, mut prop p2: Int64].
1
2
1
20
The reflection mechanism also supports function calls.
import std.reflect.*
public class Foo {
public static func f1(v0: Int64, v1: Int64): Int64 {
return v0 + v1
}
}
main(): Unit {
var num = 0
let intInfo = TypeInfo.of<Int64>()
let funcInfo = TypeInfo.of<default.Foo>().getStaticFunction("f1", intInfo, intInfo)
num = (funcInfo.apply([1, 1]) as Int64).getOrThrow()
println(num)
}
Compiling and executing the preceding code outputs the following information:
2
Dynamic Loading
As compared to compile-time loading, also known as static loading, dynamic loading allows a running Cangjie program to access a Cangjie dynamic module through specific functions to read and write global variables, call global functions, and obtain the type information. The dynamic loading capability of Cangjie depends on the ModuleInfo and PackageInfo classes.
For example, package0 in module0 contains a public class Foo, and the Cangjie dynamic module path is "./module_package.so." After the program is dynamically loaded, the type information of the Foo can be obtained at runtime.
let m = ModuleInfo.load("./module_package")
let p = m.getPackageInfo("package0").getOrThrow()
let at = TypeInfo.get("module0/package0.Foo")
Annotations
Cangjie provides some attribute macros for special case handling.
Annotations for Ensuring the Correct Use of Integer Operation Overflow Policy
Cangjie provides three types of attribute macros to specify the handling policy of integer overflow: @OverflowThrowing, @OverflowWrapping, and @OverflowSaturating. These attribute macros can only be labeled on function declarations and are used for integer operations and integer conversion in functions. They correspond to the following three overflow handling policies:
(1) Throwing: An exception is thrown when the integer operation overflows.
@OverflowThrowing
main() {
let res: Int8 = Int8(100) + Int8(29)
/* 100 + 29 equals to 129 in mathematics.
* An overflow occurs within the representation range of Int8.
* The program throws an exception.
*/
let con: UInt8 = UInt8(-132)
/* -132 causes an underflow within the representation range of UInt8.
* The program throws an exception.
*/
0
}
(2) Wrapping: When the result of an integer operation falls outside the data range that can be represented by the memory space used to receive the result, the part that exceeds the memory space is truncated.
@OverflowWrapping
main() {
let res: Int8 = Int8(105) * Int8(4)
/* 105 * 4 equals to 420 in mathematics.
* The value is 1 1010 0100 in binary.
* The 8-bit memory space used to receive the result is exceeded.
* The truncated result is represented as 1010 0100 in binary.
* The value equals to the signed integer -92.
*/
let temp: Int16 = Int16(-132)
let con: UInt8 = UInt8(temp)
/* -132 equals to 1111 1111 0111 1100 in binary.
* The 8-bit memory space used to receive the result is exceeded.
* The truncated result is represented as 0111 1100 in binary.
* The value equals to the signed integer 124.
*/
0
}
(3) Saturating: When an integer operation overflows, the result is set to the maximum or minimum value in the corresponding fixed precision.
@OverflowSaturating
main() {
let res: Int8 = Int8(-100) - Int8(45)
/* -100 - 45 equals to -145 in mathematics.
* An underflow occurs within the representation range of Int8.
* Set the result to the minimum Int8 value -128.
*/
let con: Int8 = Int8(1024)
/* 1024 causes an overflows within the representation range of Int8.
* Set the result to the maximum Int8 value 127.
*/
0
}
By default (that is, when the attribute macro is not labeled), the handling policy of the @OverflowThrowing exception is used.
In practice, you need to select a proper overflow policy based on service scenario requirements. For example, to implement a secure operation on Int32 so that the calculation result is mathematically equal to the calculation process, you can use the exception throwing policy.
[Negative Example]
// The high-order bits of the calculation result are truncated.
@OverflowWrapping
func operation(a: Int32, b: Int32): Int32 {
a + b // No exception will be thrown when overflow occurs
}
The negative example uses the high-order-bit truncation policy. For example, when two large input parameters a and b cause a result overflow, it leads to a high-order-bit truncation. Consequently, the result returned by the function does not mathematically equal to the calculation expression a + b.
[Positive Example]
// Secure
@OverflowThrowing
func operation(a: Int32, b: Int32): Int32 {
a + b
}
main() {
try {
operation(a, b)
} catch (e: ArithmeticException) {
//Handle error
}
0
}
The positive example correctly uses the Throwing overflow policy. When two large input parameters a and b cause an integer overflow, the operation function throws an exception.
The following summarizes mathematical operators that may cause an integer overflow.
| Operator | Overflow | Operator | Overflow | Operator | Overflow | Operator | Overflow |
|---|---|---|---|---|---|---|---|
+ | Y | -= | Y | << | N | < | N |
- | Y | *= | Y | >> | N | > | N |
* | Y | /= | Y | & | N | >= | N |
/ | Y | %= | N | | | N | <= | N |
% | N | <<= | N | ^ | N | == | N |
++ | Y | >>= | N | **= | Y | ||
-- | Y | &= | N | ! | N | ||
= | N | |= | N | != | N | ||
+= | Y | ^= | N | ** | Y |
Performance Optimization Annotations
To facilitate the interoperability with the C language, Cangjie provides the @FastNative attribute macro to specify the calling of the C function through backend cjnative optimization. It is worth noting that the @FastNative attribute macro can only be used for functions declared by foreign.
Constraints on @FastNative
When using @FastNative to modify the foreign function, ensure that the corresponding C function meets the following requirements:
- First, it is recommended that the overall execution time of the function be short. For example:
- A large loop is not allowed in the function.
- Function blocking is not allowed when a function such as
sleeporwaitis called.
- Second, Cangjie methods cannot be called in a function.
Custom Annotations
The custom annotation mechanism enables reflection (see the Reflection section) to obtain the annotation content. This mechanism is tailor-made for providing more useful information apart from the type metadata to support more complex logic.
You can customize annotations through @Annotation. @Annotation can only modify a class that is not modified by abstract, open, or sealed. When a class declares that it is labeled with @Annotation, it must provide at least one const init function. Otherwise, the compiler reports an error.
The following example defines a custom annotation @Version and uses it to modify A, B and C. In main, the @Version annotations on the classes are obtained through reflections and printed.
package pkg
import std.reflect.TypeInfo
@Annotation
public class Version {
let code: String
const init(code: String) {
this.code = code
}
}
@Version["1.0"]
class A {}
@Version["1.1"]
class B {}
main() {
let objects = [A(), B()]
for (obj in objects) {
let annOpt = TypeInfo.of(obj).findAnnotation<Version>()
if (let Some(ann) <- annOpt) {
if (let Some(version) <- ann as Version) {
println(version.code)
}
}
}
}
The preceding code is compiled and executed, and outputs the following:
1.0
1.1
Annotations need to be generated during compilation and bound to classes. const init must be used in annotation customization to construct valid instances. The declaration syntax of an annotation is the same as that of a macro. Parameters in [] must be passed by sequence or naming rule and must be const expressions. For details, see the constant evaluation section. Annotation classes with non-parameterized constructors can omit brackets in declaration.
The following example defines a custom annotation @Deprecated with a non-parameterized constructor const init. Therefore, both @Deprecated or @Deprecated[] are acceptable.
package pkg
import std.reflect.TypeInfo
@Annotation
public class Deprecated {
const init() {}
}
@Deprecated
class A {}
@Deprecated[]
class B {}
main() {
if (TypeInfo.of(A()).findAnnotation<Deprecated>().isSome()) {
println("A is deprecated")
}
if (TypeInfo.of(B()).findAnnotation<Deprecated>().isSome()) {
println("B is deprecated")
}
}
The preceding code is compiled and executed, and outputs the following:
A is deprecated
B is deprecated
An annotation class cannot be declared for multiple times for an annotation target. That is, the annotation class must be unique.
@Deprecated
@Deprecated // Error
class A {}
Annotation is not inherited. Therefore, the annotation metadata of a class comes only from the declared annotations when it is defined. If the annotation metadata of the parent class is required, you need to query the metadata through the reflection interface.
In the following example, A is modified by the @Deprecated annotation. B inherits A but does not obtain the annotation of A.
package pkg
import std.reflect.TypeInfo
@Annotation
public class Deprecated {
const init() {}
}
@Deprecated
open class A {}
class B <: A {}
main() {
if (TypeInfo.of(A()).findAnnotation<Deprecated>().isSome()) {
println("A is deprecated")
}
if (TypeInfo.of(B()).findAnnotation<Deprecated>().isSome()) {
println("B is deprecated")
}
}
The preceding code is compiled and executed, and outputs the following:
A is deprecated
Custom annotations can be used in type declarations (class, struct, enum, and interface), parameters in member functions or constructors, constructor declarations, member function declarations, member variable declarations, and member attribute declarations. They can also restrict their application scopes to reduce misuse. To this aim, you need to add the target parameter of the Array<AnnotationKind> type when declaring @Annotation. Where, AnnotationKind is an enum defined in the standard library. If no target is specified, the custom annotations can be used in all the preceding scopes. When the target is specified, it can be used only in the declared list.
public enum AnnotaitionKind {
| Type
| Parameter
| Init
| MemberProperty
| MemberFunction
| MemberVariable
}
The following example limits the use of custom annotations to member functions through target. Otherwise, a compilation error is reported.
@Annotation[target: [MemberFunction]]
public class Deprecated {
const init() {}
}
class A {
@Deprecated // Ok, member funciton
func deprecated() {}
}
@Deprecated // Error, type
class B {}
main() {}
Cangjie-C Interoperability
To ensure compatibility with existing ecosystems, Cangjie supports calling C language functions and allows C language functions to call Cangjie functions.
Cangjie Calling C Function
To call a C function in Cangjie, you need to declare the function using the @C and foreign modifiers in Cangjie, but@C can be omitted if foreign is present.
For example, if you want to call the rand and printf functions of C, their function signatures are as follows:
// stdlib.h
int rand();
// stdio.h
int printf (const char *fmt, ...);
In this case, a manner of calling the two functions in Cangjie is as follows:
// declare the function by `foreign` keyword, and omit `@C`
foreign func rand(): Int32
foreign func printf(fmt: CString, ...): Int32
main() {
// call this function by `unsafe` block
let r = unsafe { rand() }
println("random number ${r}")
unsafe {
var fmt = LibC.mallocCString("Hello, No.%d\n")
printf(fmt, 1)
LibC.free(fmt)
}
}
Note that:
foreign: used to modify a function declaration, indicating that the function is an external function. A function modified byforeigncan have only a function declaration but not a function implementation.foreign: functions declared withforeignmust have parameters and return types that comply with the mapping between C and Cangjie data types. For details, see [Type Mapping] (./cangjie-c.md#type-mapping).- Functions on the C side may cause unsafe operations. Therefore, when calling the function modified by
foreign, it must be wrapped by theunsafeblock. Otherwise, a compilation error occurs. - The
foreignkeyword modified by@Ccan only be used to modify function declarations and cannot be used to modify other declarations. Otherwise, a compilation error occurs. @Csupports only theforeignfunction, non-generic functions in thetop-levelscope, andstructtypes.- The
foreignfunction does not support named parameters or default parameter values. Theforeignfunction allows variable-length parameters, which are expressed by...and can be used only at the end of the parameter list. Variable-length parameters must meet theCTypeconstraint, but they do not need to be of the same type. - Although Cangjie (CJNative backend) provides the stack capacity expansion capability, it cannot detect the actual stack size used by the C-side function. Therefore, after the FFI calls the C-side function, stack overflow may still occur. You need to modify the
cjStackSizeconfiguration based on actual situation.
Sample codes for invalid foreign declarations are as follows:
foreign func rand(): Int32 { // compiler error
return 0
}
@C
foreign var a: Int32 = 0 // compiler error
@C
foreign class A{} // compiler error
@C
foreign interface B{} // compiler error
CFunc
In Cangjie, CFunc refers to the function that can be called by C language code. There are three forms:
foreignfunction modified by@C.- Cangjie function modified by
@C. - The lambda expression of the
CFunctype is different from the common lambda expression. TheCFunclambda expression cannot capture variables.
// Case 1
foreign func free(ptr: CPointer<Int8>): Unit
// Case 2
@C
func callableInC(ptr: CPointer<Int8>) {
print("This function is defined in Cangjie.")
}
// Case 3
let f1: CFunc<(CPointer<Int8>) -> Unit> = { ptr =>
print("This function is defined with CFunc lambda.")
}
The type of functions declared or defined in the preceding three forms is CFunc<(CPointer<Int8>) -> Unit>. CFunc corresponds to the function pointer type of the C language. This type is a generic type. Its generic parameter indicates the type of the CFunc input parameter and return value. The usage is as follows:
foreign func atexit(cb: CFunc<() -> Unit>): Int32
Similar to the foreign function, the parameters and return types of other CFunc functions must meet the CType constraint and do not support named parameters and default parameter values.
When CFunc is called in Cangjie code, it must be in the unsafe context.
The Cangjie language can convert a variable of the CPointer<T> type to a specific CFunc. The generic parameter T of CPointer can be any type that meets the CType constraint. The method is as follows:
main() {
var ptr = CPointer<Int8>()
var f = CFunc<() -> Unit>(ptr)
unsafe { f() } // core dumped when running, because the pointer is nullptr.
}
Note:
It is dangerous to forcibly convert a pointer to
CFuncand call a function. You need to ensure that the pointer points to an available function address. Otherwise, a runtime error occurs.
inout Parameter
When CFunc is called in Cangjie, the parameter can be modified by the inout keyword to form a reference value transfer expression. In this case, the parameter is transferred by reference. The type of the referenced value transfer expression is CPointer<T>, where T is the type of the expression modified by inout.
The value transfer expression by reference has the following restrictions:
- It can only be used to call
CFunc. - The type of the modifier object must meet the
CTypeconstraint, but cannot beCString. - The modifier object cannot be defined by
letor temporary variables such as literals, input parameters, and values of other expressions. - The pointer transferred to the C side by using the value transfer expression on the Cangjie side is valid only during function calling. That is, in this scenario, the C side should not save the pointer for future use.
Variables modified by inout can be variables defined in top-level scope, local variables, and member variables in struct types, but cannot be directly or indirectly derived from instance member variables of class types.
The following is an example:
foreign func foo1(ptr: CPointer<Int32>): Unit
@C
func foo2(ptr: CPointer<Int32>): Unit {
let n = unsafe { ptr.read() }
println("*ptr = ${n}")
}
let foo3: CFunc<(CPointer<Int32>) -> Unit> = { ptr =>
let n = unsafe { ptr.read() }
println("*ptr = ${n}")
}
struct Data {
var n: Int32 = 0
}
class A {
var data = Data()
}
main() {
var n: Int32 = 0
unsafe {
foo1(inout n) // OK
foo2(inout n) // OK
foo3(inout n) // OK
}
var data = Data()
var a = A()
unsafe {
foo1(inout data.n) // OK
foo1(inout a.data.n) // Error, n is derived indirectly from instance member variables of class A
}
}
Note:
When the macro extension feature is used, the
inoutparameter feature cannot be used in the macro definition.
unsafe
Many unsafe factors of C are also introduced during the introduction of interoperability with C language. Therefore, the unsafe keyword is used in Cangjie to identify unsafe behaviors of cross-C calling.
The unsafe keyword is described as follows:
unsafecan be used to modify functions, expressions, or a scope.- Functions modified by
@Cmust be called in theunsafecontext. - When
CFuncis called, it must be used in theunsafecontext. - When a
foreignfunction is called in Cangjie, the call must be in theunsafecontext. - When the called function is modified by
unsafe, the call must be in theunsafecontext.
The method is as follows:
foreign func rand(): Int32
@C
func foo(): Unit {
println("foo")
}
var foo1: CFunc<() -> Unit> = { =>
println("foo1")
}
main(): Int64 {
unsafe {
rand() // Call foreign func.
foo() // Call @C func.
foo1() // Call CFunc var.
}
0
}
Note that the common lambda expression cannot transfer the unsafe attribute. When an unsafe lambda expression escapes, it can be directly called without any compilation error in the unsafe context. To call an unsafe function in a lambda expression, you are advised to call the function in an unsafe block. For details, see the following case:
unsafe func A(){}
unsafe func B(){
var f = { =>
unsafe { A() } // Avoid calling A() directly without unsafe in a normal lambda.
}
return f
}
main() {
var f = unsafe{ B() }
f()
println("Hello World")
}
Calling Conventions
Function calling conventions describe how the caller and callee call functions (for example, how parameters are transferred and who clears the stack). The caller and callee must use the same calling conventions to run properly. The Cangjie programming language uses @CallingConv to indicate various calling conventions. The supported calling conventions are as follows:
- CDECL: The default calling conventions used by the C compiler of Clang on different platforms.
- STDCALL: The calling conventions used by the Win32 API.
If a C function is called using the C language interoperability mechanism, the default CDECL calling conventions is used when no calling convention is specified. The following is an example of calling the rand function in the C standard library:
@CallingConv[CDECL] // Can be omitted in default.
foreign func rand(): Int32
main() {
println(unsafe { rand() })
}
@CallingConv can only be used to modify the foreign block, a single foreign function, and a CFunc function in the top-level scope. When @CallingConv modifies the foreign block, the same @CallingConv modification is added to each function in the foreign block.
Type Mapping
Base Types
The Cangjie and C languages support the mapping of basic data types. The general principles are as follows:
- The Cangjie type does not contain references pointing to the managed memory.
- The Cangjie type and the C type have the same memory layout.
For example, some basic type mapping relationships are as follows:
| Cangjie Type | C Type | Size (byte) |
|---|---|---|
Unit | void | 0 |
Bool | bool | 1 |
UInt8 | char | 1 |
Int8 | int8_t | 1 |
UInt8 | uint8_t | 1 |
Int16 | int16_t | 2 |
UInt16 | uint16_t | 2 |
Int32 | int32_t | 4 |
UInt32 | uint32_t | 4 |
Int64 | int64_t | 8 |
UInt64 | uint64_t | 8 |
IntNative | ssize_t | platform dependent |
UIntNative | size_t | platform dependent |
Float32 | float | 4 |
Float64 | double | 8 |
Note:
Due to the uncertainty of the
intandlongtypes on different platforms, programmers need to specify the corresponding Cangjie programming language type. In C interoperability scenarios, similar to the C language, theUnittype can only be used as the return type inCFuncand the generic parameter ofCPointer.
Cangjie also supports the mapping with the structures and pointer types of the C language.
Structure
For the structure type, Cangjie uses struct modified by @C. For example, the C language has the following structure:
typedef struct {
long long x;
long long y;
long long z;
} Point3D;
The corresponding Cangjie type can be defined as follows:
@C
struct Point3D {
var x: Int64 = 0
var y: Int64 = 0
var z: Int64 = 0
}
If the C language contains such a function:
Point3D addPoint(Point3D p1, Point3D p2);
Accordingly, the function can be declared in Cangjie as follows:
foreign func addPoint(p1: Point3D, p2: Point3D): Point3D
The struct modified by @C must meet the following requirements:
- The type of a member variable must meet the
CTypeconstraint. interfacetypes cannot be implemented or extended.- To be used as an associated value type of
enumis not allowed. - Closure capture is not allowed.
- Generic parameters are not allowed.
The struct modified by @C automatically meets the CType constraint.
Pointer
For the pointer type, Cangjie provides the CPointer<T> type to correspond to the pointer type on the C side. The generic parameter T must meet the CType constraint. For example, the signature of the malloc function in C is as follows:
void* malloc(size_t size);
In Cangjie, it can be declared as follows:
foreign func malloc(size: UIntNative): CPointer<Unit>
The CPointer can be used for read and write, offset calculation, null check, and pointer conversion. For details about the API, see "Cangjie Programming Language Library API". Read, write, and offset calculation are unsafe behaviors. When invalid pointers call these functions, undefined behaviors may occur. These unsafe functions need to be called in unsafe blocks.
The following is an example of using CPointer:
foreign func malloc(size: UIntNative): CPointer<Unit>
foreign func free(ptr: CPointer<Unit>): Unit
@C
struct Point3D {
var x: Int64
var y: Int64
var z: Int64
init(x: Int64, y: Int64, z: Int64) {
this.x = x
this.y = y
this.z = z
}
}
main() {
let p1 = CPointer<Point3D>() // create a CPointer with null value
if (p1.isNull()) { // check if the pointer is null
print("p1 is a null pointer")
}
let sizeofPoint3D: UIntNative = 24
var p2 = unsafe { malloc(sizeofPoint3D) } // malloc a Point3D in heap
var p3 = unsafe { CPointer<Point3D>(p2) } // pointer type cast
unsafe { p3.write(Point3D(1, 2, 3)) } // write data through pointer
let p4: Point3D = unsafe { p3.read() } // read data through pointer
let p5: CPointer<Point3D> = unsafe { p3 + 1 } // offset of pointer
unsafe { free(p2) }
}
Cangjie supports forcible type conversion between CPointer. The generic parameter T of CPointer before and after the conversion must meet the constraints of CType. The method is as follows:
main() {
var pInt8 = CPointer<Int8>()
var pUInt8 = CPointer<UInt8>(pInt8) // CPointer<Int8> convert to CPointer<UInt8>
0
}
Cangjie can convert a variable of the CFunc type to a specific CPointer. The generic parameter T of CPointer can be any type that meets the CType constraint. The method is as follows:
foreign func rand(): Int32
main() {
var ptr = CPointer<Int8>(rand)
0
}
Note:
It is safe to forcibly convert a
CFuncto a pointer. However, noreadorwriteoperation should be performed on the converted pointer, which may cause runtime errors.
Array
Cangjie uses the VArray type to map to the array type of C. The VArray type can be used as a function parameter or @C struct member. When the element type T in VArray<T, $N> meets the CType constraint, the VArray<T, $N> type also meets the CType constraint.
As a function parameter type:
When VArray is used as a parameter of CFunc, the function signature of CFunc can only be of the CPointer<T> or the VArray<T, $N> type. If the parameter type in the function signature is VArray<T, $N>, the parameter is transferred in the CPointer<T> format.
The following is an example of using VArray as a parameter:
foreign func cfoo1(a: CPointer<Int32>): Unit
foreign func cfoo2(a: VArray<Int32, $3>): Unit
The corresponding C-side function definition may be as follows:
void cfoo1(int *a) { ... }
void cfoo2(int a[3]) { ... }
When calling CFunc, you need to use inout to modify the variable of the VArray type.
var a: VArray<Int32, $3> = [1, 2, 3]
unsafe {
cfoo1(inout a)
cfoo2(inout a)
}
VArray cannot be used as the return value type of CFunc.
As a member of @C struct:
When VArray is a member of @C struct, its memory layout is the same as the structure layout on the C side. Ensure that the declaration length and type on the Cangjie side are the same as those on the C side.
struct S {
int a[2];
int b[0];
}
In Cangjie, the following structure can be declared to correspond to the C code:
@C
struct S {
var a = VArray<Int32, $2>(item: 0)
var b = VArray<Int32, $0>(item: 0)
}
Note:
In the C language, the last field of a structure can be an array whose length is not specified. The array is called a flexible array. Cangjie does not support the mapping of structures that contain flexible arrays.
Character String
Particularly, for a string type in the C language, a CString type is designed in Cangjie. To simplify operations on C language strings, CString provides the following member functions:
init(p: CPointer<UInt8>): constructs a CString through CPointer.func getChars(): obtaining the address of a character string. The type isCPointer<UInt8>.func size(): Int64: calculates the length of the character string.func isEmpty(): Bool: checks that the length of the string is 0. If the pointer of the string is null,trueis returned.func isNotEmpty(): Bool: checks that the length of the string is not 0. If the pointer of the string is null,falseis returned.func isNull(): Bool: checks whether the pointer of the character string is null.func startsWith(str: CString): Bool: checks whether the character string starts with str.func endsWith(str: CString): Bool: checks whether the character string ends with str.func equals(rhs: CString): Bool: checks whether the character string is equal to rhs.func equalsLower(rhs: CString): Bool: checks whether the character string is equal to rhs. The value is case-insensitive.func subCString(start: UInt64): CString: truncates a substring from start and stores the returned substring in the newly allocated space.func subCString(start: UInt64, len: UInt64): CString: truncates a substring whose length is len from start and stores the returned substring in the newly allocated space.func compare(str: CString): Int32: returns a result which is the same asstrcmp(this, str)in the C language compared with str.func toString(): String: constructs a new String object using this string.func asResource(): CStringResource: obtains the resource type of CString.
In addition, the mallocCString function in LibC can be called to convert String to CString. After the conversion is complete, CString needs to be released.
The following is an example of using CString:
foreign func strlen(s: CString): UIntNative
main() {
var s1 = unsafe { LibC.mallocCString("hello") }
var s2 = unsafe { LibC.mallocCString("world") }
let t1: Int64 = s1.size()
let t2: Bool = s2.isEmpty()
let t3: Bool = s1.equals(s2)
let t4: Bool = s1.startsWith(s2)
let t5: Int32 = s1.compare(s2)
let length = unsafe { strlen(s1) }
unsafe {
LibC.free(s1)
LibC.free(s2)
}
}
sizeOf/alignOf
Cangjie also provides the sizeOf and alignOf functions to obtain the memory usage and memory alignment values (in bytes) of the preceding C interoperability types. The function declaration is as follows:
public func sizeOf<T>(): UIntNative where T <: CType
public func alignOf<T>(): UIntNative where T <: CType
Example:
@C
struct Data {
var a: Int64 = 0
var b: Float32 = 0.0
}
main() {
println(sizeOf<Data>())
println(alignOf<Data>())
}
If you run the command on a 64-bit computer, the following information is displayed:
16
8
CType
In addition to the types that are mapped to C-side types provided in "Type Mapping", Cangjie provides a CType interface. The interface does not contain any method and can be used as the parent type of all types supported by C interoperability for easy use in generic constraints.
Note that:
- The
CTypeinterface itself does not meet theCTypeconstraint. - The
CTypeinterface cannot be inherited or extended. - The
CTypeinterface does not break the usage restrictions of subtypes.
The following is an example of using CType:
func foo<T>(x: T): Unit where T <: CType {
match (x) {
case i32: Int32 => println(i32)
case ptr: CPointer<Int8> => println(ptr.isNull())
case f: CFunc<() -> Unit> => unsafe { f() }
case _ => println("match failed")
}
}
main() {
var i32: Int32 = 1
var ptr = CPointer<Int8>()
var f: CFunc<() -> Unit> = { => println("Hello") }
var f64 = 1.0
foo(i32)
foo(ptr)
foo(f)
foo(f64)
}
The result is as follows:
1
true
Hello
match failed
C Calling Cangjie Functions
Cangjie provides the CFunc type to correspond to the function pointer type on the C side. The function pointer on the C side can be transferred to Cangjie, and Cangjie can also construct and transfer a variable corresponding to the function pointer on the C side.
Assume that a C library API is as follows:
typedef void (*callback)(int);
void set_callback(callback cb);
Correspondingly, the function in Cangjie can be declared as follows:
foreign func set_callback(cb: CFunc<(Int32) -> Unit>): Unit
Variables of the CFunc type can be transferred from the C side or constructed on the Cangjie side. There are two methods to construct the CFunc type on the Cangjie side. One is to use the function modified by @C, and the other is to use the closure marked as CFunc.
The function modified by @C indicates that its function signature meets the calling rules of C and the definition is still written in Cangjie. The function modified by foreign is defined on the C side.
Note:
For functions modified by
foreignand@C, which are namedCFunc, you are advised not to useCJ_(case-insensitive) as the prefix. Otherwise, the names may conflict with internal compiler symbols such as the standard library and runtime, resulting in undefined behavior.
Example:
@C
func myCallback(s: Int32): Unit {
println("handle ${s} in callback")
}
main() {
// the argument is a function qualified by `@C`
unsafe { set_callback(myCallback) }
// the argument is a lambda with `CFunc` type
let f: CFunc<(Int32) -> Unit> = { i => println("handle ${i} in callback") }
unsafe { set_callback(f) }
}
Assume that the library compiled by the C function is "libmyfunc.so". You need to run the cjc -L. -lmyfunc test.cj -o test.out compilation command to enable the Cangjie compiler to link to the library. Finally, the desired executable program can be generated.
In addition, when compiling the C code, enable the -fstack-protector-all/-fstack-protector-strong stack protection option. By default, the Cangjie code has the overflow check and stack protection functions. After the C code is introduced, the security of overflows in unsafe blocks needs to be ensured.
Compiler Options
To use C interoperability, you need to manually link the C library. The Cangjie compiler provides corresponding options.
-
--library-path <value>,-L <value>,-L<value>: specifies the directory of the library file to be linked.--library-path <value>: adds the specified path to the library file search paths of the linker. The path specified by the environment variableLIBRARY_PATHwill also be added to the library file search paths of the linker. The path specified by--library-pathhas a higher priority than the path specified byLIBRARY_PATH. -
--library <value>,-l <value>,-l<value>: specifies the library file to be linked.The specified library file is directly transferred to the linker. The library file name must be in the
lib[arg].[extension]format.
For details about all compilation options supported by the CJC compiler, see [CJC Compilation Options] (../Appendix/compile_options_OHOS.md).
Example
Assume that there is a C library libpaint.so whose header file is as follows:
include <stdint.h>
typedef struct {
int64_t x;
int64_t y;
} Point;
typedef struct {
int64_t x;
int64_t y;
int64_t r;
} Circle;
int32_t DrawPoint(const Point* point);
int32_t DrawCircle(const Circle* circle);
The sample code for using the C library in the Cangjie code is as follows:
// main.cj
foreign {
func DrawPoint(point: CPointer<Point>): Int32
func DrawCircle(circle: CPointer<Circle>): Int32
func malloc(size: UIntNative): CPointer<Int8>
func free(ptr: CPointer<Int8>): Unit
}
@C
struct Point {
var x: Int64 = 0
var y: Int64 = 0
}
@C
struct Circle {
var x: Int64 = 0
var y: Int64 = 0
var r: Int64 = 0
}
main() {
let SIZE_OF_POINT: UIntNative = 16
let SIZE_OF_CIRCLE: UIntNative = 24
let ptr1 = unsafe { malloc(SIZE_OF_POINT) }
let ptr2 = unsafe { malloc(SIZE_OF_CIRCLE) }
let pPoint = CPointer<Point>(ptr1)
let pCircle = CPointer<Circle>(ptr2)
var point = Point()
point.x = 10
point.y = 20
unsafe { pPoint.write(point) }
var circle = Circle()
circle.r = 1
unsafe { pCircle.write(circle) }
unsafe {
DrawPoint(pPoint)
DrawCircle(pCircle)
free(ptr1)
free(ptr2)
}
}
Run the following command to compile the Cangjie code (using the CJNative backend as an example):
cjc -L . -l paint ./main.cj
In the compilation command, -L . indicates that the library is queried from the current directory (assume that libpaint.so exists in the current directory). -l paint indicates the name of the linked library. After the compilation is successful, the binary file main is generated by default. The command for running the binary file is as follows:
LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./main
Cangjie-Python Interoperability
To be compatible with powerful computing and AI ecosystems, Cangjie supports interoperability with Python. The Python interoperability provides capabilities for users through the ffi.python library in the std module.
Currently, Python interoperability can be used only on the Linux platform and supports only the CJNative backend of the Cangjie compiler.
Global Resources and Usage of Python
Providing Built-in Function Classes and Global Resources
Code prototype:
public class PythonBuiltins {
...
}
public let Python = PythonBuiltins()
The interfaces provided by the Python library cannot ensure concurrency security. When Python is called asynchronously (the IDs of system threads are inconsistent), the PythonException exception is thrown.
During Python initialization, the GIL global interpreter lock is locked based on the current OS thread. If the Cangjie thread (including the main thread) where the executed code is located is locked,
The Cangjie thread is scheduled on the OS thread (the ID of the OS thread changes). When Python attempts to check the GIL again, the thread status is verified and the GIL is found.
The ID of the OS thread saved in the status is inconsistent with that of the current OS thread. As a result, an internal error is triggered and the program breaks down.
Python interoperability uses a large amount of native code of the Python library. Stack protection cannot be performed on the code on the Cangjie side. The default size of the Cangjie stack protection is 64 KB. When the Python C API is called, the native code may exceed the default stack size. As a result, overflow occurs and unexpected results are triggered. Before executing Python interoperability code, you are advised to
set the default stack size of Cangjie to at least 1 MB: export cjStackSize=1MB.
Example:
import std.ffi.python.*
main(): Int64 {
Python.load()
Python.unload()
return 0
}
Providing the Python Library Log Class PythonLogger
Code prototype:
public class PythonLogger <: Logger {
mut prop level: LogLevel {...}
public func setOutput(output: io.File): Unit {} // do nothing
public func trace(msg: String): Unit {...}
public func debug(msg: String): Unit {...}
public func info(msg: String): Unit {...}
public func warn(msg: String): Unit {...}
public func error(msg: String): Unit {...}
public func log(level: LogLevel, msg: String): Unit {...}
}
public let PYLOG = PythonLogger()
The Logger class is declared as follows:
- The
PythonLoggerimplements theLoggerinterface only for printing output and printing level control. Logs are not dumped to log files. - If
setOutputis empty, log dump files are not supported. - The output of interfaces such as
info/warn/errorstarts with the corresponding prefix. - The default print level of
PythonLoggerisLogLevel.WARN. - The
PYLOG.error(msg)andlog(LogLevel.ERROR, msg)interfaces throw thePythonExceptionexception.
Example:
import std.ffi.python.*
import std.log.*
main(): Int64 {
PYLOG.level = LogLevel.WARN // Only logs of the warn level and above are printed.
PYLOG.info("log info")
PYLOG.warn("log warn")
try {
PYLOG.error("log error")
} catch(e: PythonException) {}
PYLOG.log(LogLevel.INFO, "loglevel info")
PYLOG.log(LogLevel.WARN, "loglevel warn")
try {
PYLOG.log(LogLevel.ERROR, "loglevel error")
} catch(e: PythonException) {}
return 0
}
Execution result:
WARN: log warn
ERROR: log error
WARN: loglevel warn
ERROR: loglevel error
Providing the Python Library Exception Class PythonException
Code prototype:
public class PythonException <: Exception {
public init() {...}
public init(message: String) {...}
}
The PythonException is described as follows:
- The usage of
PythonExceptionis the same as that of the inheritedExceptionexcept the exception prefix. - When an internal exception occurs in Python, the external system can capture the exception through
try-catch. If the exception is not captured, the exception stack is printed and the program exits. The return value is 1.
Example:
import std.ffi.python.*
import std.log.*
main(): Int64 {
try {
Python.load("/usr/lib/", loglevel: LogLevel.INFO)
} catch(e: PythonException) {
print("${e}") // PythonException: "/usr/lib/" does not exist or the file path is invalid.
}
return 0
}
Providing the Python Library Version Information Class Version
Code prototype:
public struct Version <: ToString {
public init(major: Int64, minor: Int64, micro: Int64)
public func getMajor(): Int64
public func getMinor(): Int64
public func getMicro(): Int64
public func getVersion(): (Int64, Int64, Int64)
public func toString(): String
}
The declaration of the Version class is as follows:
- The
Versionversion information consists of three parts:major version,minor version, andmicro version. - The
Versionversion is initialized only by using the constructor. Once defined, it cannot be modified. - The
toStringinterface is provided for direct printing. - The
getVersioninterface is provided to obtain the tuple format of the version.
Example:
import std.ffi.python.*
main(): Int64 {
Python.load()
var version = Python.getVersion()
print("${version}")
var tuple_version = version.getVersion()
Python.unload()
return 0
}
PythonBuiltins Built-in Function Class
Importing and Loading the Python Library
Code prototype:
public class PythonBuiltins {
public func load(loglevel!: LogLevel = LogLevel.WARN): Unit
public func load(path: String, loglevel!: LogLevel = LogLevel.WARN): Unit
public func isLoad(): Bool
public func unload(): Unit
}
public let Python = PythonBuiltins()
The following statements about loading and unloading are as follows:
- The
loadfunction is implemented in overloading mode. It can be loaded without participation or loaded from a specified dynamic library path. An optional parameter is provided to configure thePythonLoggerprint level. If the parameter is not configured, thePYLOGprint level is reset to thewarnprint level. - The
load()function is used for Python-related preparations and must be called before Python interoperability. For details about how to query the dynamic library, see the dynamic library loading policy. - For the
load(path: String)function, you need to configure the dynamic library pathpath.pathspecifies the dynamic library file (for example,/usr/lib/libpython3.9.so) and cannot be set to a directory or a non-dynamic library file. - When the
loadfunction fails, thePythonExceptionexception is thrown. If the program still needs to continue, pay attention totry-catch. - The
unloadfunction is called after Python interoperability is complete. Otherwise, related resources may be leaked. - The loading and unloading operations need to be called only once. If they are called for multiple times, only the first invoking takes effect.
- The
isload()function is used to determine whether the Python library is loaded.
Example:
load and unload:
import std.ffi.python.*
main(): Int64 {
Python.load()
Python.unload()
Python.load("/usr/lib/libpython3.9.so")
Python.unload()
return 0
}
isLoad Function:
import std.ffi.python.*
main(): Int64 {
print("${Python.isLoad()}\n") // false
Python.load()
print("${Python.isLoad()}\n") // true
Python.unload()
return 0
}
Loading Policy of Dynamic Library
The Python library depends on the official dynamic link library libpython3.x.so of Python. The recommended version is 3.9.2. Python3.0 and later versions are supported.
Obtaining the dynamic library from the Python source code:
# In the Python source code path:
./configure --enable-shared --with-system-ffi --prefix=/usr
make
make install
The dynamic library of Python is automatically searched as follows:
- Use the specified environment variable:
export PYTHON_DYNLIB=".../libpython3.9.so"
- If the environment variable is not specified, search for the dependency of the executable file.
- Ensure that the executable file
python3can be executed properly (the path has been added to the PATH environment variable). Query the dynamic library dependency of the Python3 executable file. - Python executable files that are not dependent on dynamic libraries cannot be used. (Python executable files that are not compiled using
--enable-sharedduring source code compilation do not depend on dynamic libraries.)
$ ldd $(which python3)
...
libpython3.9d.so.1.0 => /usr/local/lib/libpython3.9d.so.1.0 (0x00007f499102f000)
...
- If the executable file dependency cannot be found, search for the dependency from the default dynamic library query path.
["/lib", "/usr/lib", "/usr/local/lib"]
The name of the dynamic library queried in the path must comply with the naming format of libpythonX.Y.so. X Y indicates the major version number and minor version number. The following suffixes are supported: d.so, m.so, dm.so, and .so. The supported version is later than Python 3.0 and earlier than or equal to Python 3.10. Example:
libpython3.9.so
libpython3.9d.so
libpython3.9m.so
libpython3.9dm.so
Example:
import std.ffi.python.*
import std.log.*
main(): Int64 {
Python.load(loglevel: LogLevel.INFO)
print("${Python.getVersion()}\n")
Python.unload()
return 0
}
You can enable the INFO level printing of Python and view the search process of the Python library path.
# Specifying .so by Using Environment Variables
$ export PYTHON_DYNLIB=/root/code/python_source_code/Python-3.9.2/libpython3.9d.so
$ cjc ./main.cj -o ./main && ./main
INFO: Try to get libpython path.
INFO: Found PYTHON_DYNLIB value: /root/code/python_source_code/Python-3.9.2/libpython3.9d.so
...
# Find dynamic libraries by executable file dependency.
INFO: Try to get libpython path.
INFO: Can't get path from environment PYTHON_DYNLIB, try to find it from executable file path.
INFO: Exec cmd: "ldd $(which python3)":
INFO: ...
libpython3.9d.so.1.0 => /usr/local/lib/libpython3.9d.so.1.0 (0x00007fbbb5014000)
...
INFO: Found lib: /usr/local/lib/libpython3.9d.so.1.0.
INFO: Found exec dependency: /usr/local/lib/libpython3.9d.so.1.0
...
# Search for the dynamic library in the system path.
$ unset PYTHON_DYNLIB
$ cjc ./main.cj -o ./main && ./main
INFO: Can't get path from environment PYTHON_DYNLIB, try to find it from executable file path.
INFO: Can't get path from executable file path, try to find it from system lib path.
INFO: Find in /lib.
INFO: Found lib: /lib/libpython3.9.so.
...
# Failed to find the dynamic library.
$ cjc ./main.cj -o ./main && ./main
INFO: Can't get path from environment PYTHON_DYNLIB, try to find it from executable file path.
INFO: Can't get path from executable file path, try to find it from system lib path.
INFO: Find in /lib.
INFO: Can't find lib in /lib.
INFO: Find in /usr/lib.
INFO: Can't find lib in /usr/lib.
INFO: Find in /usr/local/lib.
INFO: Can't find lib in /usr/local/lib.
An exception has occurred:
PythonException: Can't get path from system lib path, load exit.
at std/ffi/python.std/ffi/python::(PythonException::)init(std/core::String)(stdlib/std/ffi/python/Python.cj:82)
at std/ffi/python.std/ffi/python::(PythonBuiltins::)load(std/log::LogLevel)(stdlib/std/ffi/python/Python.cj:127)
at default.default::main()(/root/code/debug/src/main.cj:5)
getVersion() Function
Function prototype:
public func getVersion(): Version
Interface description:
- The
getVersion()function is used to obtain the current Python version.
Return values of input parameters:
- The
getVersion()function has no parameter and returns aVersionobject.
Exceptions:
- Ensure that the
loadfunction has been called. Otherwise, the returned version number is0.0.0.
Example:
import std.ffi.python.*
main(): Int64 {
Python.load()
var version = Python.getVersion()
print("${version}")
var tuple_version = version.getVersion()
Python.unload()
return 0
}
Import() Function
Function prototype:
public func Import(module: String): PyModule
Return values of input parameters:
- The
Importfunction receives an input parameter of theStringtype, that is, a module name, and returns an object of thePyModuletype.
Exceptions:
- Ensure that the load function has been called for the
Importfunction. Otherwise, the returnedPyModuleobject is unavailable (isAvaliable()isfalse). - If the corresponding module cannot be found, an error is reported and the returned
PyModuleobject is unavailable (isAvaliable()isfalse).
Example:
import std.ffi.python.*
main(): Int64 {
Python.load()
var sys = Python.Import("sys")
if (sys.isAvailable()) {
print("Import sys success\n")
}
// Import the test.py file in the current folder.
var test = Python.Import("test")
if (test.isAvailable()) {
print("Import test success\n")
}
var xxxx = Python.Import("xxxx")
if (!xxxx.isAvailable()) {
print("Import test failed\n")
}
Python.unload()
return 0
}
Execution result:
Import sys success
Import test success
Import test failed
Eval() Function
Function prototype:
public func Eval(cmd: String, module!: String = "__main__"): PyObj
Interface description:
- The
Eval()function is used to create a Python data type.
Return values of input parameters:
Eval()receives acmdcommand of theStringtype and returns thePyObjformat of the command result.Eval()accepts a specified domain of theStringtype. The default domain is"__main__".
Exceptions:
- Ensure that the
loadfunction has been called. Otherwise, the returnedPyObjobject is unavailable (isAvaliable()isfalse). - If the command received by
Eval()fails to be executed, Python reports an error and the returnedPyObjobject is unavailable (isAvaliable()isfalse).
Example:
import std.ffi.python.*
main(): Int64 {
Python.load()
var a = Python.Eval("123")
if (a.isAvailable()) {
Python["print"]([a])
}
var b = Python.Eval("x = 123") // The expression in `Eval` needs have a return value.
if (!b.isAvailable()) {
print("b is unavailable.\n")
}
Python.unload()
return 0
}
Execution result:
123
b is unavailable.
index [] Operator Overloading
Interface description:
- The
[]function provides the capability of calling other built-in functions of Python.
Return values of input parameters:
- The input parameter of the
[]function accepts the name of a built-in function of theStringtype, and the return type isPyObj.
Exception Handling:
- Ensure that the
loadfunction has been called. Otherwise, the returnedPyObjobject is unavailable (isAvaliable()isfalse). - If the specified function name is not found, an error is reported and the returned
PyObjobject is unavailable (isAvaliable()isfalse).
Example:
import std.ffi.python.*
main(): Int64 {
Python.load()
if (Python["type"].isAvailable()) {
print("find type\n")
}
if (!Python["type1"].isAvailable()) {
print("cant find type1\n")
}
Python.unload()
return 0
}
Execution result:
find type
WARN: Dict key "type1" not found!
cant find type1
Type Mapping
The interoperability between Python and Cangjie is developed based on C APIs. The data type mapping between Python and C is implemented through the PyObject structure pointer, and a series of interfaces for different data types are provided. Compared with the C language, Cangjie has the advantage of object-oriented programming. Therefore, the PyObject structure pointer is encapsulated as a parent class and inherited by different data types.
Type Mapping Table
Mapping from the Cangjie type to the Python type:
| Cangjie Type | Python Type |
|---|---|
| Bool | PyBool |
| UInt8/Int8/Int16/UInt16/Int32/UInt32/Int64/UInt64 | PyLong |
| Float32/Float64 | PyFloat |
| Rune/String | PyString |
| Array< PyObj > | PyTuple |
| Array | PyList |
| HashMap | PyDict |
| HashSet | PySet |
Mapping from the Python type to the Cangjie type:
| Python Type | Cangjie Type |
|---|---|
| PyBool | Bool |
| PyLong | Int64/UInt64 |
| PyFloat | Float64 |
| PyString | String |
| PyTuple | - |
| PyList | Array |
| PyDict | HashMap |
| PySet | HashSet |
PyFFIType Interface of Python FFI Library Generic Constraint
public interface PyFFIType { }
- Some classes introduce generics. To restrict the use of generics, the abstract interface
PyFFITypeis introduced. - This interface has no abstract member function and is implemented or inherited only by
PyObjandCjObj. This interface cannot be implemented outside the package. If you customize a class and implement this interface, undefined behavior may occur.
PyObj Class
It corresponds to the PyObject structure in the Python library and provides common interfaces for subdivided data types, such as member variable access, function access, and character string conversion to Cangjie.
Class prototype:
public open class PyObj <: ToString & PyFFIType {
public func isAvailable(): Bool { ... }
public open operator func [](key: String): PyObj { ... }
public open operator func [](key: String, value!: PyObj): Unit { ... }
public operator func ()(): PyObj { ... }
public operator func ()(kargs: HashMap<String, PyObj>): PyObj { ... }
public operator func ()(args: Array<PyObj>): PyObj { ... }
public operator func ()(args: Array<PyObj>, kargs: HashMap<String, PyObj>): PyObj { ... }
public operator func ()(args: Array<CjObj>): PyObj { ... }
public operator func ()(args: Array<CjObj>, kargs: HashMap<String, PyObj>): PyObj { ... }
public operator func +(b: PyObj): PyObj { ... }
public operator func -(b: PyObj): PyObj { ... }
public operator func *(b: PyObj): PyObj { ... }
public operator func /(b: PyObj): PyObj { ... }
public operator func **(b: PyObj): PyObj { ... }
public operator func %(b: PyObj): PyObj { ... }
public open func toString(): String { ... }
public func hashCode(): Int64 { ... }
public operator func ==(right: PyObj): Bool { ... }
public operator func !=(right: PyObj): Bool { ... }
}
Description of the PyObj Class
-
The
PyObjclass does not provide constructors for external systems. This class cannot be inherited outside the package. If a user customizes a class and implements the interface, undefined behavior may occur. -
public func isAvailable(): Bool { ... }:- The
isAvailableinterface is used to determine whether thePyObjis available (that is, whether the encapsulated C pointer isNULL).
- The
-
public open operator func [](key: String): PyObj { ... }:[](key)is used to access members of a Python class or a module.- If
PyObjis unavailable (isAvaliable()isfalse), an exception is thrown. - If
keydoes not exist inPyObj, Python prints the corresponding error and returns an unavailablePyObjclass object (isAvaliable()isfalse).
-
public open operator func [](key: String, value!: PyObj): Unit { ... }:[](key, value): Set the member variables of the Python class and module tovalue.- If
PyObjis unavailable (isAvaliable()isfalse), an exception is thrown. - If the
PyObjdoes not contain the correspondingkey, the Python side prints the corresponding error. - If the value of
valueis an unavailable object (isAvaliable()isfalse), the correspondingkeyis deleted from the module or class.
-
The
()parenthesis operator is overloaded to call the function of the object.- If
PyObjis unavailable (isAvaliable()isfalse), an exception is thrown. - If
PyObjis an object that cannot be called, Python reports an error and returns an unavailablePyObjclass object (isAvaliable()isfalse). ()accepts function calls without parameters.- The
([...])parameter supports at least one parameter. The parameter type can beCjObjorPyObj. Note thatCjObjandPyObjcannot be used together when multiple parameters are transferred. - If the parameter contains an unavailable object (
isAvaliable()isfalse), an exception is thrown to prevent unpredictable program breakdown on the Python side. - The
()operator supportskargs, which corresponds to the variable naming parameter design of Python. It is transferred through aHashMap. ThekeytypeStringis configured as the variable name, and thevaluetype PyObj is configured as the parameter value.
- If
-
Binary operator overloading:
-
+(addition of two variables):- Basic data types:
PyStringandPyBool/PyLong/PyFloatcannot be added together. Other types can be added together. - Advanced data types:
PyDict/PySetcannot be added to any type.PyTuple/PyListcan only be added to itself.
- Basic data types:
-
-(subtraction of two variables):- Basic data types:
PyStringandPyBool/PyLong/PyFloat/PyStringdo not support subtraction. Other types support subtratcion. - Advanced data types:
PyDict/PySet/PyTuple/PyListdoes not support subtraction from any type.
- Basic data types:
-
*(multiplication of two variables):- Basic data types:
PyStringandPyFloat/PyStringdo not support multiplication. Other types support multiplication. - Advanced data types:
PyDict/PySetcannot be multiplied by any type.PyTuple/PyListcan be multiplied only byPyLong/PyBool.
- Basic data types:
-
/(division of two variables):- Basic data types:
PyStringandPyBool/PyLong/PyFloat/PyStringcannot be divided by each other. Other types can be divided by each other. If the divisor is 0 (Falseis interpreted as 0 on the Python side and cannot be used as a divisor), an error is printed on the Python side. - Advanced data types:
PyDict/PySet/PyTuple/PyListcannot be divided by any type.
- Basic data types:
-
**(exponent calculation):- Basic data types:
PyStringandPyBool/PyLong/PyFloat/PyStringdo not support exponential calculation. Other data types support exponential calculation. - Advanced data types:
PyDict/PySet/PyTuple/PyListdo not support exponentiation.
- Basic data types:
-
%(remainder operation):- Basic data types:
PyStringandPyBool/PyLong/PyFloat/PyStringdo not support the remainder operation. Other data types support the remainder operation. If the divisor is 0 (Falseis interpreted as 0 in Python and cannot be used as a divisor), an error message is displayed in Python. - Advanced data types:
PyDict/PySet/PyTuple/PyListand all types do not support the modulo operation.
- Basic data types:
-
All the preceding errors are recorded at the warn level, and the returned
PyObjis unavailable (isAvaliable()isfalse).
-
-
public open func toString(): String { ... }:- The
toStringfunction can return the Python data type as a string, and the basic data type is returned in Python style. - If
PyObjis unavailable (isAvaliable()isfalse), an exception is thrown.
- The
-
The
hashCodefunction is the encapsulated Pythonhashalgorithm and returns an Int64 hash value. -
The
==operator is used to determine whether twoPyObjobjects are the same. The!=operator is used to determine whether twoPyObjobjects are the same. If the interface comparison fails, the==returnsfalseand captures the Python error. If the two compared objects are unavailable, an exception is thrown.
Example:
test01.py file:
a = 10
def function():
print("a is", a)
def function02(b, c = 1):
print("function02 call.")
print("b is", b)
print("c is", c)
Cangjie file main.cj in the same directory:
import std.ffi.python.*
import std.collection.*
main(): Int64 {
Python.load()
// Create an unavailable value.
var a = Python.Eval("a = 10") // SyntaxError: invalid syntax
print("${a.isAvailable()}\n") // false
// Uncallable value `b` be invoked
var b = Python.Eval("10")
b() // TypeError: 'int' object is not callable
// Import .py file.
var test = Python.Import("test01")
// `get []` get value of `a`.
var p_a = test["a"]
print("${p_a}\n") // 10
// `set []` set the value of a to 20.
test["a"] = Python.Eval("20")
test["function"]() // a is 20
// Call function02 with a named argument.
test["function02"]([1], HashMap<String, PyObj>([("c", 2.toPyObj())]))
// Set `a` in test01 to an unavailable value, and `a` will be deleted.
test["a"] = a
test["function"]() // NameError: name 'a' is not defined
Python.unload()
0
}
CjObj Interface
Interface prototype and type extension:
public interface CjObj <: PyFFIType {
func toPyObj(): PyObj
}
extend Bool <: CjObj {
public func toPyObj(): PyBool { ... }
}
extend Rune <: CjObj {
public func toPyObj(): PyString { ... }
}
extend Int8 <: CjObj {
public func toPyObj(): PyLong { ... }
}
extend UInt8 <: CjObj {
public func toPyObj(): PyLong { ... }
}
extend Int16 <: CjObj {
public func toPyObj(): PyLong { ... }
}
extend UInt16 <: CjObj {
public func toPyObj(): PyLong { ... }
}
extend Int32 <: CjObj {
public func toPyObj(): PyLong { ... }
}
extend UInt32 <: CjObj {
public func toPyObj(): PyLong { ... }
}
extend Int64 <: CjObj {
public func toPyObj(): PyLong { ... }
}
extend UInt64 <: CjObj {
public func toPyObj(): PyLong { ... }
}
extend Float32 <: CjObj {
public func toPyObj(): PyFloat { ... }
}
extend Float64 <: CjObj {
public func toPyObj(): PyFloat { ... }
}
extend String <: CjObj {
public func toPyObj(): PyString { ... }
}
extend<T> Array<T> <: CjObj where T <: PyFFIType {
public func toPyObj(): PyList<T> { ... }
}
extend<K, V> HashMap<K, V> <: CjObj where K <: Hashable & Equatable<K> & PyFFIType {
public func toPyObj(): PyDict<K, V> { ... }
}
extend<T> HashSet<T> <: CjObj where T <: Hashable, T <: Equatable<T> & PyFFIType {
public func toPyObj(): PySet<T> { ... }
}
Description of the CjObj Class
The CjObj interface is implemented by all basic data types and toPyObj is extended. The CjObj interface can be converted to the corresponding Python data type.
Mapping between PyBool and Bool
Class prototype:
public class PyBool <: PyObj {
public init(bool: Bool) { ... }
public func toCjObj(): Bool { ... }
}
Description of the PyBool Class
- The
PyBoolclass is inherited from thePyObjclass. ThePyBoolclass has all the interfaces of the parent class. PyBoolcan be constructed only by using theBooltype of Cangjie.- The
toCjObjinterface convertsPyBoolto the Cangjie data typeBool.
Example:
import std.ffi.python.*
main(): Int64 {
Python.load()
// Creation of `PyBool`.
var a = PyBool(true) // The type of `a` is `PyBool`.
var b = Python.Eval("True") // The type of `b` is `PyObj` and needs to be matched to `PyBool`.
var c = true.toPyObj() // The type of `c` is `PyBool`, which is the same as `a`.
print("${a}\n")
if (a.toCjObj()) {
print("success\n")
}
if (b is PyBool) {
print("b is PyBool\n")
}
Python.unload()
0
}
Execution result:
True
success
b is PyBool
Mapping between PyLong and Integers
Class prototype:
public class PyLong <: PyObj {
public init(value: Int64) { ... }
public init(value: UInt64) { ... }
public init(value: Int32) { ... }
public init(value: UInt32) { ... }
public init(value: Int16) { ... }
public init(value: UInt16) { ... }
public init(value: Int8) { ... }
public init(value: UInt8) { ... }
public func toCjObj(): Int64 { ... }
public func toInt64(): Int64 { ... }
public func toUInt64(): UInt64 { ... }
}
Description of the PyLong Class
-
The
PyLongclass is inherited from thePyObjclass. ThePyLongclass has all the interfaces of the parent class. -
The
PyLongsupports the construction of input parameters of the integer type from all Cangjie. -
The
toCjObjandtoInt64interfaces convertPyLongto theInt64type. -
The
toUInt64interface convertsPyLongtoUInt64. -
The
PyLongtype is converted to the Cangjie type to the 8-byte type. ThePyLongtype cannot be converted to the lower-byte type. -
Overflow/Underflow problems:
- If the original value of
toInt64(UInt64is used to assign a value and no error is reported) exceeds theInt64range, an overflow occurs. - If the original value of
toUInt64(Int64is used to assign a value and no error is reported) exceeds theUInt64range, an overflow occurs.
- If the original value of
-
Currently,
PyLongdoes not support large number processing.
Example:
import std.ffi.python.*
main(): Int64 {
Python.load()
// Creation of `PyLong`.
var a = PyLong(10) // The type of `a` is `PyLong`.
var b = Python.Eval("10") // The type of `b` is `PyObj` and needs to be matched to `PyLong`.
var c = 10.toPyObj() // The type of `c` is `PyLong`, which is the same as `a`.
print("${a}\n")
if (a.toCjObj() == 10 && a.toUInt64() == 10) {
print("success\n")
}
if (b is PyLong) {
print("b is PyLong\n")
}
Python.unload()
0
}
Execution result:
10
success
b is PyLong
Mapping between PyFloat and Floating Points
Class prototype:
public class PyFloat <: PyObj {
public init(value: Float32) { ... }
public init(value: Float64) { ... }
public func toCjObj(): Float64 { ... }
}
Description of the PyFloat Class
- The
PyFloatclass is inherited from thePyObjclass. ThePyFloatclass has all the interfaces of the parent class. PyBoolcan be constructed using data of the CangjieFloat32/Float64type.- To ensure precision, the
toCjObjinterface convertsPyFloatto the Cangjie data typeFloat64.
Example:
import std.ffi.python.*
main(): Int64 {
Python.load()
// Creation of `PyLong`.
var a = PyFloat(3.14) // The type of `a` is `PyFloat`.
var b = Python.Eval("3.14") // The type of `b` is `PyObj` and needs to be matched to `PyFloat`.
var c = 3.14.toPyObj() // The type of `c` is `PyFloat`, which is the same as `a`.
print("${a}\n")
if (a.toCjObj() == 3.14) {
print("success\n")
}
if (b is PyFloat) {
print("b is PyFloat\n")
}
Python.unload()
0
}
Execution result:
3.14
success
b is PyFloat
Mapping between PyString and Characters and Character Strings
Class prototype:
public class PyString <: PyObj {
public init(value: String) { ... }
public init(value: Rune) { ... }
public func toCjObj(): String { ... }
public override func toString(): String { ... }
}
Description of the PyString Class
- The
PyStringclass is inherited from thePyObjclass. ThePyStringclass has all the interfaces of the parent class. PyStringcan be constructed using data of the CangjieRune/Stringtype.- The
toCjObj/toStringinterface is used to convertPyStringto theStringdata type.
Example
import std.ffi.python.*
main(): Int64 {
Python.load()
// Creation of `PyString`.
var a = PyString("hello python") // The type of `a` is `PyString`.
var b = Python.Eval("\"hello python\"") // The type of `b` is `PyObj` and needs to be matched to `PyString`.
var c = "hello python".toPyObj() // The type of `c` is `PyString`, which is the same as `a`.
print("${a}\n")
if (a.toCjObj() == "hello python") {
print("success\n")
}
if (b is PyString) {
print("b is PyString\n")
}
Python.unload()
0
}
Execution result:
hello python
success
b is PyString
PyTuple Type
Class prototype:
public class PyTuple <: PyObj {
public init(args: Array<PyObj>) { ... }
public operator func [](key: Int64): PyObj { ... }
public func size(): Int64 { ... }
public func slice(begin: Int64, end: Int64): PyTuple { ... }
}
Description of the PyTuple Class
- The
PyTupletype is the same as the tuple type in Python, that is, the(...)variable is used in Python code. - The
PyTupleclass is inherited from thePyObjclass. ThePyTupleclass has all the interfaces of the parent class. PyTuplecan be constructed using CangjieArray. The element type ofArraymust bePyObj(different data types of Python can be transferred usingPyObj, that is, different data types of different elements inTupleare compatible). If a member contains an unavailable object, an exception is thrown.- Overloading of the
[]operator:- The input parameter type of
[]in the parent classPyObjisString. When this class is called, the internal member variables or functions of thePythontuple type can be accessed or set. - The subclass
PyTuplecan use[]to access elements. If the badgekeyexceeds the range of [0, size ()), an error is reported and an unavailablePyObjobject is returned. - The
set []operator is not reloaded because the Python tuple is an immutable object.
- The input parameter type of
- The
sizefunction is used to obtain the length ofPyTuple. - The
slicefunction is used to tailor the sourcePyTupleand return a newPyTuple. If the input parametersbeginandendofsliceare not in the range of [0, size ()), the sourcePyTupleis still tailored.
Example:
import std.ffi.python.*
main(): Int64 {
Python.load()
// Creation of `PyTuple`.
var a = PyTuple(["Array".toPyObj(), 'a'.toPyObj(), 1.toPyObj(), 1.1.toPyObj()])
var b = match (Python.Eval("('Array', 'a', 1, 1.1)")) {
case val: PyTuple => val
case _ => throw PythonException()
}
// Usage of size
println(a.size()) // 4
// Usage of slice
println(a.slice(1, 2)) // ('a',). This print is same as Python code `a[1: 2]`.
println(a.slice(-1, 20)) // ('Array', 'a', 'set index 3 to String', 1.1)
Python.unload()
return 0
}
Execution result:
4
('a',)
('Array', 'a', 1, 1.1)
Mapping between PyList and Array
Class prototype:
public class PyList<T> <: PyObj where T <: PyFFIType {
public init(args: Array<T>) { ... }
public operator func [](key: Int64): PyObj { ... }
public operator func [](key: Int64, value!: T): Unit { ... }
public func toCjObj(): Array<PyObj> { ... }
public func size(): Int64 { ... }
public func insert(index: Int64, value: T): Unit { ... }
public func append(item: T): Unit { ... }
public func slice(begin: Int64, end: Int64): PyList<T> { ... }
}
Description of the PyList Class
-
The
PyListclass is the same as the list type in Python. That is, the Python code uses the[...]variable. -
The
PyListclass is inherited from thePyObjclass. ThePyListclass has all interfaces of the parent class. This class maps the array of the Cangjie class. Therefore, the genericTclass is introduced. TheTtype is restricted to the subclass of thePyFFITypeinterface. -
The
PyListclass can be constructed based on theArraytype of Cangjie. The member type ofArrayis also restricted to the subclass of thePyFFITypeinterface. -
Overloading of the
[]operator:- In the parent class
PyObj, the input parameter type of[]isString. When this class object is called, only the internal member variables or functions ofPythoncan be accessed or set. - The input parameter type of
[]in this class isInt64, that is, the corner mark value ofArray. The value range is [0, size ()). If the input parameter is not within the range, an error is reported and the returned object is unavailable. []also supportsgetandset. Whensetis used, thevaluetype isT. If thevaluecontains an unavailable Python object, an exception is thrown.
- In the parent class
-
The
toCjObjfunction can convertPyListtoArray<PyObj>of Cangjie. Note thatPyListis not converted toArray<T>. -
The
sizefunction returns the length ofPyList. -
The
insertfunction insertsvalueat the position ofindexand moves the elements followingvaluebackward. If the index is not in the range of [0, size ()),valuecan be inserted normally. Ifvalueis an unavailable object, an exception is thrown. -
The
appendfunction appendsitemtoPyList. Ifvalueis an unavailable object, an exception is thrown. -
The
slicefunction is used to truncate data in the range of [begin, end) and return a newPyList,beginandendthat are not in the range of [0, size ()).
Example:
import std.ffi.python.*
main(): Int64 {
Python.load()
// Creation of `PyList`.
var a = PyList<Int64>([1, 2, 3])
var b = match (Python.Eval("[1, 2, 3]")) {
case val: PyList<PyObj> => val
case _ => throw PythonException()
}
var c = [1, 2, 3].toPyObj()
// Usage of `[]`
println(a["__add__"]([b])) // [1, 2, 3, 1, 2, 3]
a[1]
b[1]
a[2] = 13
b[2] = 15.toPyObj()
// Usage of `toCjObj`
var cjArr = a.toCjObj()
for (v in cjArr) {
print("${v} ") // 1 2 13
}
print("\n")
// Usage of `size`
println(a.size()) // 3
// Usage of `insert`
a.insert(1, 4) // [1, 4, 2, 13]
a.insert(-100, 5) // [5, 1, 4, 2, 13]
a.insert(100, 6) // [5, 1, 4, 2, 13, 6]
b.insert(1, 4.toPyObj()) // [1, 4, 2, 15]
// Usage of `append`
a.append(7) // [5, 1, 4, 2, 13, 6, 7]
b.append(5.toPyObj()) // [1, 4, 2, 15, 5]
// Usage of `slice`
a.slice(1, 2) // [1]
a.slice(-100, 100) // [5, 1, 4, 2, 13, 6, 7]
b.slice(-100, 100) // [1, 4, 2, 15, 5]
return 0
}
Execution result:
[1, 2, 3, 1, 2, 3]
1 2 13
3
Mapping between PyDict and HashMap
Class prototype:
public class PyDict<K, V> <: PyObj where K <: Hashable & Equatable<K> & PyFFIType {
public init(args: HashMap<K, V>) { ... }
public func getItem(key: K): PyObj { ... }
public func setItem(key: K, value: V): Unit { ... }
public func toCjObj(): HashMap<PyObj, PyObj> { ... }
public func contains(key: K): Bool { ... }
public func copy(): PyDict<K, V> { ... }
public func del(key: K): Unit { ... }
public func size(): Int64 { ... }
public func empty(): Unit { ... }
public func items(): PyList<PyObj> { ... }
public func values(): PyList<PyObj> { ... }
public func keys(): PyList<PyObj> { ... }
}
Description of the PyDict Class
-
The
PyDictis the same as the Python dictionary type, that is, the{ a: b}variable is used in the Python code. -
The
PyDictclass is inherited from thePyObjclass. ThePyDictclass has all interfaces of the parent class. This class maps the HashMap of the Cangjie class. Therefore, the generic<K, V>class is introduced. TheKtype is a subclass of thePyFFITypeinterface, can be calculated by theHashclass, and the==and!=operators are reloaded. -
The
PyDictreceives data from theHashMapof the Cangjie type for construction.Kcan only be of theCjObjorPyObjtype or its subclasses.- The values of the same Python data are the same. For example,
Python.Eval("1")and1.toPyObj()are in the==relationship.
-
The
getItemfunction is used to obtain thevalueof the key value corresponding toPyDict. If the key value cannot be found, an error is reported and an unavailablePyObjis returned. If the configured valuekeyorvalueis of thePyObjtype and is unavailable, an exception is thrown. -
The
setItemfunction is used to configurevalueof the key value corresponding toPyDict. If the key value cannot be found, it is inserted. If the configured valuekeyorvalueis of thePyObjtype and is unavailable, an exception is thrown. -
The
toCjObjfunction is used to convertPyDicttoHashMap<PyObj, PyObj>. -
The
containsfunction is used to check whether the value ofkeyis contained in the current dictionary. The return value is of the Boolean type. If the interface fails to be invoked, an error is reported and false is returned. -
The
copyfunction is used to copy the current dictionary and return a newPyDict<T>type. If the copy fails, the returned PyDict is unavailable. -
The
delfunction is used to delete the value of the correspondingkey. If the key value is of the PyObj type and is unavailable, an exception is thrown. -
The
sizefunction is used to return the length of the current dictionary. -
The
emptyfunction is used to clear the current dictionary content. -
The
itemsfunction is used to obtain a list of key-value pairs of the Pythonlisttype, which can be iteratively accessed. -
The
valuesfunction is used to obtain a list of values of the Pythonlisttype, which can be iteratively accessed. -
The
keysfunction is used to obtain a list of Python keys of thelisttype, which can be iteratively accessed.
Example:
import std.ffi.python.*
import std.collection.*
main() {
Python.load()
// Creation of `PyDict`
var a = PyDict(HashMap<Int64, Int64>([(1, 1), (2, 2)])) // The key type is `CjObj`.
var b = PyDict(HashMap<PyObj, Int64>([(Python.Eval("1"), 1), (Python.Eval("2"), 2)])) // The key type is `PyObj`.
var c = match (Python.Eval("{'pydict': 1, 'hashmap': 2, 3: 3, 3.1: 4}")) {
case val: PyDict<PyObj, PyObj> => val // Python side return `PyDict<PyObj, PyObj>`
case _ => throw PythonException()
}
var d = HashMap<Int64, Int64>([(1, 1), (2, 2)]).toPyObj()
// Usage of `getItem`
println(a.getItem(1)) // 1
println(b.getItem(1.toPyObj())) // 1
// Usage of `setItem`
a.setItem(1, 10)
b.setItem(1.toPyObj(), 10)
println(a.getItem(1)) // 10
println(b.getItem(1.toPyObj())) // 10
// Usage of `toCjObj`
var hashA = a.toCjObj()
for ((k, v) in hashA) {
print("${k}: ${v}, ") // 1: 10, 2: 2,
}
print("\n")
var hashB = b.toCjObj()
for ((k, v) in hashB) {
print("${k}: ${v}, ") // 1: 10, 2: 2,
}
print("\n")
// Usage of `contains`
println(a.contains(1)) // true
println(a.contains(3)) // false
println(b.contains(1.toPyObj())) // true
// Usage of `copy`
println(a.copy()) // {1: 10, 2: 2}
// Usage of `del`
a.del(1) // Delete the key-value pair (1: 1).
// Usage of `size`
println(a.size()) // 1
// Usage of `empty`
a.empty() // Clear all elements in dict.
// Usage of `items`
for (i in b.items()) {
print("${i} ") // (1, 10) (2, 2)
}
print("\n")
// Usage of `values`
for (i in b.values()) {
print("${i} ") // 10 2
}
print("\n")
// Usage of `keys`
for (i in b.keys()) {
print("${i} ") // 1, 2
}
print("\n")
Python.unload()
}
Mapping between PySet and HashSet
Class prototype:
public class PySet<T> <: PyObj where T <: Hashable, T <: Equatable<T> & PyFFIType {
public init(args: HashSet<T>) { ... }
public func toCjObj(): HashSet<PyObj> { ... }
public func contains(key: T): Bool { ... }
public func add(key: T): Unit { ... }
public func pop(): PyObj { ... }
public func del(key: T): Unit { ... }
public func size(): Int64 { ... }
public func empty(): Unit { ... }
}
Description of the PySet Class
-
PySetcorresponds to the data type of the collection in Python. When an element is inserted, the hash algorithm in Python is used to sort the elements in the collection. (The elements may not be sorted in strict ascending order. Some methods may cause different running results.) -
The
PySetclass is inherited from thePyObjclass. ThePySetclass has all interfaces of the parent class. This class maps theHashSetof the Cangjie class. Therefore, the genericTis introduced. TheTtype is a subclass of thePyFFITypeinterface, can be calculated by theHashclass, and the==and!=operators are reloaded. -
The
PySetreceives data from theHashMapof the Cangjie type for construction.Kcan only be of theCjObjorPyObjtype or its subclasses.- The values of the same Python data are the same. For example,
Python.Eval("1")and1.toPyObj()are in the==relationship.
-
The
toCjObjfunction is used to convertPySet<T>toHashSet<PyObj>. Note that only the element typePyObjcan be converted. -
The
containsfunction is used to determine whetherkeyexists in the current dictionary. Thekeytype isT. -
The
addfunction can be used to insert a value. If a key value already exists inPySet, the insertion does not take effect. IfkeyisPyObjand is unavailable, an exception is thrown. -
The
popfunction is used to obtain the first element fromPySet. -
Delete the corresponding key value from
del. Ifkeyis not inPySet, an error is reported and the system exits normally. IfkeyisPyObjand is unavailable, an exception is thrown. -
sizeis used to return the length ofPySet. -
The
emptycommand is used to clear the currentPySet.
Note:
After
toCjObjis called, all elements are displayed bypop. In this case, the originalPySetis empty (sizeis 0, and the originalPySetis still available).
Example:
import std.ffi.python.*
import std.collection.*
main() {
Python.load()
// Creation of `PySet`
var a = PySet<Int64>(HashSet<Int64>([1, 2, 3]))
var b = match (Python.Eval("{'PySet', 'HashSet', 1, 1.1, True}")) {
case val: PySet<PyObj> => val
case _ => throw PythonException()
}
var c = HashSet<Int64>([1, 2, 3]).toPyObj()
// Usage of `toCjObj`
var cja = a.toCjObj()
println(a.size()) // 0
// Usage of `contains`
println(b.contains("PySet".toPyObj())) // true
// Usage of `add`
a.add(2)
println(a.size()) // 1
a.add(2) // Insert same value, do nothing.
println(a.size()) // 1
a.add(1) // Insert `1`.
// Usage of `pop`
println(a.pop()) // 1. Pop the first element.
println(a.size()) // 1
// Usage of `del`
c.del(2)
println(c.contains(2)) // false
// Usage of `empty`
println(c.size()) // 2
c.empty()
println(c.size()) // 0
Python.unload()
}
PySlice Type
The usage of the PySlice type is the same as that of the return value of the Python built-in function slice(). The PySlice type can be used to identify a range and step, and can be used as the index value of the type that can be sliced to tailor and obtain the substring. To facilitate construction on the Cangjie side, the PySlice class and the Range range type of Cangjie can be converted to each other. For details, see the following description.
Class prototype:
public class PySlice<T> <: PyObj where T <: Countable<T> & Comparable<T> & Equatable<T> & CjObj {
public init(args: Range<T>) { ... }
public func toCjObj(): Range<Int64> { ... }
}
Description of PySlice
- The
PySlicecan be constructed using theRangetype of Cangjie and supports the syntax sugar of theRangetype. The genericThas the originalRangeconstraint and the constraint is added to the implementation of theCjObjtype. ThePyObjtype is not supported. - The
toCjObjfunction can be used to convertPySliceto CangjieRange. Note that the generic type ofRangeis an integer of theInt64type. - If you want to transfer the
PySlicetype toPyString/PyList/PyTupleor otherPyObjtypes that can be transferred byslice, you can use the member function__getitem__to transfer thePySlicetype. For details, see the example.
Example:
import std.ffi.python.*
main() {
Python.load()
var range = 1..6:2
// Create a PySlice.
var slice1 = PySlice(range)
var slice2 = match (Python["slice"]([0, 6, 2])) {
case val: PySlice<Int64> => val
case _ => throw PythonException()
}
var slice3 = range.toPyObj()
// Use PySlice in PyString.
var str = PyString("1234567")
println(str["__getitem__"]([range])) // 246
println(str["__getitem__"]([slice1])) // 246
// Use PySlice in PyList.
var list = PyList(["a", "b", "c", "d", "e", "f", "g", "h"])
println(list["__getitem__"]([range])) // ['b', 'd', 'f']
println(list["__getitem__"]([slice1])) // ['b', 'd', 'f']
// Use PySlice in PyTuple.
var tup = PyTuple(list.toCjObj())
println(tup["__getitem__"]([range])) // ('b', 'd', 'f')
println(tup["__getitem__"]([slice1])) // ('b', 'd', 'f')
Python.unload()
0
}
Execution result:
246
246
['b', 'd', 'f']
['b', 'd', 'f']
('b', 'd', 'f')
('b', 'd', 'f')
PyObjIterator of PyObj
Code prototype:
Extension of PyObj:
extend PyObj <: Iterable<PyObj> {
public func iterator(): Iterator<PyObj> { ... }
}
PyObjIterator type:
public class PyObjIterator <: Iterator<PyObj> {
public init(obj: PyObj) { ... }
public func next(): Option<PyObj> { ... }
public func iterator(): Iterator<PyObj> { ... }
}
Description of PyObjIterator
-
You can obtain
PyObjIteratorby using the iterator method ofPyObj. -
The
PyObjIteratorcan be constructed externally. If the providedPyObjcannot be iterated or is unavailable, an exception is thrown.- The
PyString/PyTuple/PyList/PySet/PyDictobject can be iterated. - When
PyDictis iterated directly, the value ofkeyis iterated.
- The
-
The
nextfunction is used to iterate the iterator. -
The
iteratormethod is used to return itself.
Example
import std.ffi.python.*
import std.collection.*
main() {
Python.load()
// iter of PyString
var S = PyString("Str")
for (s in S) {
print("${s} ") // S t r
}
print("\n")
// iter of PyTuple
var T = PyTuple(["T".toPyObj(), "u".toPyObj(), "p".toPyObj()])
for (t in T) {
print("${t} ") // T u p
}
print("\n")
// iter of PyList
var L = PyList(["L", "i", "s", "t"])
for (l in L) {
print("${l} ") // L i s t
}
print("\n")
// iter of PyDict
var D = PyDict(HashMap<Int64, String>([(1, "D"), (2, "i"), (3, "c"), (4, "t")]))
for (d in D) {
print("${d} ") // 1 2 3 4, dict print keys.
}
print("\n")
// iter of PySet
var Se = PySet(HashSet<Int64>([1, 2, 3]))
for (s in Se) {
print("${s} ") // 1 2 3
}
print("\n")
0
}
Execution result:
S t r
T u p
L i s t
1 2 3 4
1 2 3
Registration and Callback between Cangjie and Python
The Python interoperability library supports simple function registration and Python's calling of Cangjie functions.
The Python callback code needs to be called using C as the medium, and the third-party libraries of Python, ctypes and _ctypes, are used.
Mapping between Cangjie, C, and Python Types
The following table lists the basic data.
| Cangjie Type | CType | Python Type |
|---|---|---|
Bool | PyCBool | PyBool |
Rune | PyCWchar | PyString |
Int8 | PyCByte | PyLong |
UInt8 | PyCUbyte/PyCChar | PyLong |
Int16 | PyCShort | PyLong |
UInt16 | PyCUshort | PyLong |
Int32 | PyCInt | PyLong |
UInt32 | PyCUint | PyLong |
Int64 | PyCLonglong | PyLong |
UInt64 | PyCUlonglong | PyLong |
Float32 | PyCFloat | PyFloat |
Float64 | PyCDouble | PyFloat |
[unsupport CPointer as param] CPointer<T> | PyCPointer | ctypes.pointer |
[unsupport CString as param] CString | PyCCpointer | ctypes.c_char_p |
[unsupport CString as param] CString | PyCWcpointer | ctypes.c_wchar_p |
Unit | PyCVoid | - |
Cangjie Typeis a variable type modified on the Cangjie side. Unless otherwise specified, parameters of this type can be transferred to Python code and can be transferred from Python to Cangjie.PyCTypeis thePyCFuncinterface configuration type on the Cangjie side. For details, see Prototype ofPyCFuncand Example.Python Typeis a type mapping on the Cangjie side. There is no pointer type mapping. Python functions with pointers cannot be called from the Cangjie side.- Both
PyCCpointerandPyCWcpointerare mapped toCString. The difference is thatPyCCpointeris a character string in C, andPyCWcpointeris only a character pointer. Even if multiple characters are transferred, only the first character is used. - Type mismatch will result in unpredictable results.
Prototype of PyCFunc Class
PyCFunc is a PyObj subtype based on the Python interoperability library and Python third-party library ctype/_ctype. This type can be directly transferred to Python
for use. PyCFunc provides the CFunc function for Python to register with Cangjie and allows Python to call back the CFunc function.
Code prototype:
public enum PyCType {
PyCBool |
PyCChar |
PyCWchar |
PyCByte |
PyCUbyte |
PyCShort |
PyCUshort |
PyCInt |
PyCUint |
PyCLonglong |
PyCUlonglong |
PyCFloat |
PyCDouble |
PyCPointer |
PyCCpointer |
PyCWcpointer |
PyCVoid
}
public class PyCFunc <: PyObj {
public init(f: CPointer<Unit>, argsTy!: Array<PyCType> = [], retTy!: PyCType = PyCType.PyCVoid) { ... }
public func setArgTypes(args: Array<PyCType>): PyCFunc { ... }
public func setRetTypes(ret: PyCType): PyCFunc { ... }
}
Description of Class
-
PyCFuncis inherited fromPyObj. Some interfaces of the parent class can be used. (If an interface is not supported, an error is reported.) -
The
initcan be constructed by external users. The function pointer must be provided as the first parameter (theCFunctype needs to be converted to theCPointer<Unit>type on the Cangjie side). The last two optional parameters are the array of the input parameter type and the return value type.If the input pointer is not a function pointer, the program will crash when the function is called (the library layer cannot intercept the function).
-
The
setArgTypes/setRetTypesfunction is used to configure parameters and return value types. For details about the supported parameters, see thePyCTypeenumeration. -
The
()operator in the parent class can call the registeredCFuncfunction on the Cangjie side. -
This class can be directly transferred to the Python side or directly called on the Cangjie side. (If a non-function pointer is used during class construction, the system will crash when this class is called.)
-
This class supports chain calling similar to Java Script.
Example
- Prepare the
CFuncfunction of Cangjie.
@C
func cfoo(a: Bool, b: Int32, c: Int64): CPointer<Unit> {
print("cfoo called.\n")
print("${a}, ${b}, ${c}\n")
return CPointer<Unit>()
}
- Construct a PyCFunc class object.
import std.ffi.python.*
// Define the @C function.
@C
func cfoo(a: Bool, b: Int32, c: Int64): CPointer<Unit> {
print("cfoo called.\n")
print("${a}, ${b}, ${c}\n")
return CPointer<Unit>()
}
main() {
Python.load()
/*
Construct PyCFunc class.
Set args type: Bool -> PyCBool
Int32 -> PyCInt
Int64 -> PyCLonglong
CPointer<Unit> -> PyCPointer
*/
var f1 = PyCFunc(unsafe {CPointer<Unit>(cfoo)},
argsTy: [PyCBool, PyCInt, PyCLonglong],
retTy: PyCPointer)
// You also can use it by chain-call.
var f2 = PyCFunc(unsafe {CPointer<Unit>(cfoo)})
.setArgTypes([PyCBool, PyCInt, PyCLonglong])
.setRetTypes(PyCPointer)([true, 1, 2])
// Call f1
f1([true, 1, 2])
f1([PyBool(true), PyLong(1), PyLong(2)])
Python.unload()
0
}
Compile and run the following file:
$ cjc ./main.cj -o ./main && ./main
cfoo called.
true, 1, 2
cfoo called.
true, 1, 2
cfoo called.
true, 1, 2
- Register the function with Python and enable Python to call the function.
The Python code is as follows:
# File test.py
# `foo` get a function pointer and call it.
def foo(func):
func(True, 10, 40)
Modify the preceding main.
import std.ffi.python.*
// Define the @C function.
@C
func cfoo(a: Bool, b: Int32, c: Int64): CPointer<Unit> {
print("cfoo called.\n")
print("${a}, ${b}, ${c}\n")
return CPointer<Unit>()
}
main() {
Python.load()
var f1 = PyCFunc(unsafe {CPointer<Unit>(cfoo)},
argsTy: [PyCBool, PyCInt, PyCLonglong],
retTy: PyCPointer)
// Import test.py
var cfunc01 = Python.Import("test")
// Call `foo` and transfer `f1`
cfunc01["foo"]([f1])
Python.unload()
0
}
- The Python side transfers the pointer to the Cangjie side.
Add a function to the Python file.
# File test.py
# If you want transfer pointer type to Cangjie CFunc, you need import ctypes.
import ctypes.*
# `foo` get a function pointer and call it.
def foo(func):
func(True, 10, 40)
# `fooptr` get a function pointer and call it with pointer type args.
def fooptr(func):
a = c_int(10)
# c_char_p will get whole symbols, but c_wchar_p only get first one symbol 'd'.
func(pointer(a), c_char_p(b'abc'), c_wchar_p('def'))
Modify the Cangjie code.
import std.ffi.python.*
var x = Python.load()
// Modify the `foo` param type to pointer.
@C
func foo(a: CPointer<Int64>, b: CString, c: CString): Unit {
print("${unsafe {a.read(0)}}, ${b.toString()}, ${c.toString()}\n")
}
main(): Int64 {
var f1 = PyCFunc(unsafe {CPointer<Unit>(foo)},
argsTy: [PyCPointer, PyCCpointer, PyCWcpointer],
retTy: PyCVoid)
// Import test.py
var test = Python.Import("test")
// Call `fooptr` and transfer `f1`
test["fooptr"]([f1])
return 0
}
The pointer type cannot be transferred to the Python library when the function is called on the Cangjie side. Therefore, the function can be called only on the Python side.
Compile and run the following command:
$ cjc ./main.cj -o ./main && ./main
10, abc, d
cjc Usage
cjc is a compilation command of the Cangjie programming language. It provides various functions and compilation options. This section describes how to use cjc.
The cjc-frontend (Cangjie frontend compiler) is provided together with the cjc through the Cangjie SDK. The cjc-frontend can compile the Cangjie source code to the Cangjie intermediate representation (LLVM IR). The cjc-frontend performs only frontend compilation of the Cangjie code. Although the cjc-frontend and cjc share some compilation options, the compilation process stops when the frontend compilation is complete. When cjc is used, the Cangjie compiler automatically performs frontend and backend compilation and linking. cjc-frontend is provided only as an entity of the frontend compiler. It is advised to use cjc for compiling Cangjie code, unless you are a compiler developer.
Note:
When
cjccompilation is performed on macOS M1, thecjccompilation performance may fluctuate due to variations in CPU usage. Restarting the computer or stopping the task for a period of time may alleviate the issue, though there is currently no complete solution.
Basic cjc Usage
This section describes how to use cjc. For details about the compilation options, see cjc Compilation Options.
The method of using cjc is as follows:
cjc [option] file...
Assume that there is a Cangjie file named hello.cj.
main() {
println("Hello, World!")
}
You can compile the file by running the following command:
$ cjc hello.cj
The executable file main is added to the working directory. By default, the cjc compiles the specified source code file into an executable file and names the executable file main.
The preceding is the default behavior of cjc when no compilation option is provided. You can use compilation options to control the behavior of cjc, for example, enable cjc to compile the entire package or specify the name of the output file.
Introduction to cjpm
Cangjie Package Manager (CJPM) is an official Cangjie package management tool. It is used to manage and maintain the module system of Cangjie projects, provide a simpler and unified compilation entry, and support customized compilation commands. The package manager automatically manages dependencies to analyze and combine third-party dependencies of multiple versions. Developers do not need to worry about dependency conflicts between multiple versions, greatly reducing their workload. It also provides a custom build mechanism based on the native Cangjie language, allowing developers to add pre-processing and post-processing steps in different build phases. In this way, the build process can be flexibly customized to meet build requirements in different service scenarios.
Basic cjpm Usage
You can run the cjpm -h command to view the main interface. The main interface consists of the following parts from top to bottom: current command description, usage example, available subcommands, available options, and more prompts.
Cangjie Package Manager
Usage:
cjpm [subcommand] [option]
Available subcommands:
init Init a new cangjie module
check Check the dependencies
update Update cjpm.lock
tree Display the package dependencies in the source code
build Compile the current module
run Compile and run an executable product
test Unittest a local package or module
clean Clean up the target directory
publish Push a module to the repository
load Load a module from the repository
list Get module list from the repository
install Install a cangjie binary
uninstall Uninstall a cangjie binary
Available options:
-h, --help help for cjpm
-v, --version version for cjpm
Use "cjpm [subcommand] --help" for more information about a command.
The cjpm init command is used to initialize a new Cangjie module or workspace. During module initialization, the cjpm.toml file is created in the current folder by default, and the src source code folder is created. The default main.cj file is generated in src. You can run the cjpm init -h command to view the customized parameter initialization function.
Example:
Input: cjpm init
Output: cjpm init success
The cjpm build command is used to build the current Cangjie project. Before running this command, the system checks the dependencies. After the check is passed, the cjc command is called to build the project. Full compilation, incremental compilation, cross compilation, and parallel compilation are supported. You can run the cjpm build -h command to view more compilation functions. The cjpm build -V command is used to print all compilation commands.
Example:
Input: cjpm build -V
Output:
compile package module1.package1: cjc --import-path target -p "src/package1" --output-type=staticlib -o target/release/module1/libmodule1.package1.a
compile package module1: cjc --import-path target -L target/release/module1 -lmodule1.package1 -p "src" --output-type=exe --output-dir target/release/bin -o main
cjpm build success
cjpm.toml Configuration File
The configuration file cjpm.toml is used to configure basic information, dependencies, compilation options, and other related content. The cjpm primarily relies on this file for parsing and execution.
The code in the configuration file is as follows:
[package] # Single-module configuration field, which cannot coexist with the workspace field.
cjc-version = "0.49.1" # Minimum required version of 'cjc', which is required.
name = "demo" # Module name and root package name, which are required.
description = "nothing here" # Description, which is optional.
version = "1.0.0" # Module version information, which is required.
compile-option = "" # Additional compilation command option, which is optional.
link-option = "" # Transparent transmission option of the linker, which is optional and can transparently transmit secure compilation commands.
output-type = "executable" # Type of the compilation output product, which is required.
src-dir = ""# Path for storing the source code, which is optional.
target-dir = ""# Path for storing the product, which is optional.
package-configuration = {} # Single-package configuration option, which is optional.
[workspace] # Workspace management field, which cannot coexist with the package field.
members = [] # Workspace member module list, which is required.
build-members = [] # List of compiled modules in the workspace, which is optional and must be a subset of the member module list.
test-members = [] # List of test modules in the workspace, which is optional and must be a subset of the compiled module list.
compile-option = "" # Additional compilation command option applied to all workspace member modules, which is optional.
link-option = "" # Transparent transmission option of the linker applied to all workspace member modules, which is optional.
target-dir = ""# Path for storing the product, which is optional.
[dependencies] # Configuration options of source code dependency.
aoo = { version = "1.0.0" } # Import the central repository dependency.
boo = "1.1.0" # Import the central repository dependency.
coo = { git = "xxx",branch = "dev" , version = "1.0.0"} # Import the `git` dependency.
doo = { path = "./pro1" ,version = "1.0.0"} # Import the source code dependency.
[test-dependencies] # Dependency configuration options in the test phase. The format is the same as that of dependencies.
[script-dependencies] # Dependency configuration options of the build script. The format is the same as that of dependencies.
[ffi.c] # Import the `c` library dependency.
clib1.path = "xxx"
[profile] # Configuration items of the command profile
build = {}
test = {}
customized-option = {}
[target.x86_64-unknown-linux-gnu] # Configuration items for isolating the backend from the platform
compile-option = "value1" # Additional compilation command option, which is applicable to the compilation process of a specific target and the compilation process of specifying the target as the cross compilation target platform. This is optional.
link-option = "value2" # Transparent transmission option of the linker, which is applicable to the compilation process of a specific target and the compilation process of specifying the target as the cross compilation target platform. This is optional.
[target.x86_64-w64-mingw32.dependencies] # Configuration item applicable to the source code dependency of the corresponding target. This is optional.
[target.x86_64-w64-mingw32.test-dependencies] # Configuration item applicable to the test phase of the corresponding target. This is optional.
[target.cjvm.bin-dependencies] # Cangjie binary library dependency, which is applicable to the compilation process of a specific target and the compilation process of specifying the target as the cross compilation target platform. This is optional.
path-option = ["./test/pro0", "./test/pro1"]
[target.cjvm.bin-dependencies.package-option]
"pro0.xoo" = "./test/pro0/pro0.xoo.cjo"
"pro0.yoo" = "./test/pro0/pro0.yoo.cjo"
"pro1.zoo" = "./test/pro1/pro1.zoo.cjo"
Conditional Compilation
Developers can complete conditional compilation based on predefined or user-defined conditions. Currently, Cangjie supports conditional compilation for imports and declarations.
Conditional Compilation for Imports and Declarations
Cangjie can use the built-in compilation tag @When to complete conditional compilation. One or more sets of conditions are enclosed in square brackets ([]). @When can be used for the import nodes and declaration nodes except the package nodes.
Usage
The following uses the built-in OS compilation conditions as an example:
@When[os == "Linux"]
class mc{}
main(): Int64 {
var a = mc()
return 0
}
In the preceding code, developers can correctly compile and execute the code in the Linux system. In a non-Linux system, a compilation error indicating that the mc class definition cannot be found occurs.
Note that:
-
Cangjie does not support compilation condition nesting. The following is not allowed:
@When[os == "Windows"] @When[os == "Linux"] // Error, illegal nested when conditional compilation import std.ast.* @When[os == "Windows"] @When[os == "Linux"] // Error, illegal nested when conditional compilation func A(){} -
@When[...]is a built-in compilation tag and is processed before import. If the code generated by expanding the macro contains@When[...], a compilation error is reported. For example:@M0 // macro which returns the input @When[os == "Linux"] // Error, unexpected when conditional compilation directive func A(){}
Built-in Compilation Condition Variables
Cangjie provides five built-in condition variables: os, backend, cjc_version, debug, and test.
os
os indicates the operating system of the target platform. os supports the == and != operators. The following operating systems are supported: Windows, Linux, and macOS.
The usage is as follows:
@When[os == "Linux"]
func foo() {
print("Linux, ")
}
@When[os == "Windows"]
func foo() {
print("Windows, ")
}
@When[os != "Windows"]
func fee() {
println("NOT Windows")
}
@When[os != "Linux"]
func fee() {
println("NOT Linux")
}
main() {
foo()
fee()
}
If the compilation is performed in the Windows environment, the information Windows, NOT Linux is displayed. If the compilation is performed in the Linux environment, the information Linux, NOT Windows is displayed.
backend
backend is a built-in condition of Cangjie. Cangjie is a multi-backend language that supports various backend conditional compilations. The backend condition supports the == and != operators.
The following backends are supported: cjnative, cjnative-x86_64, cjnative-aarch64.
When the condition is cjnative, the arch information is automatically supplemented based on the environment information when the compiler is executed.
The usage is as follows:
@When[backend == "cjnative-x86_64"]
func foo() {
print("cjnative-x86_64 backend, ")
}
@When[backend == "cjnative-aarch64"]
func foo() {
print("cjnative-aarch64 backend, ")
}
@When[backend != "cjnative-x86_64"]
func fee() {
println("NOT cjnative-x86_64 backend")
}
@When[backend != "cjnative-aarch64"]
func fee() {
println("NOT cjnative-aarch64 backend")
}
main() {
foo()
fee()
}
If the compilation is performed using a release package of the cjnative-x86_64 backend, you will obtain the cjnative-x86_64 backend, NOT cjnative-aarch64 backend information. If the compilation is performed using a release package of the cjnative-aarch64 backend, you will obtain the cjnative-aarch64 backend, NOT cjnative-x86_64 backend information.
cjc_version
cjc_version is a built-in condition of Cangjie. Developers can select the code to be compiled based on the current Cangjie compiler version. The cjc_version condition supports the ==, !=, >, <, >=, and <= operators. The format is xx.xx.xx, where each xx can be one or two digits. The comparison rule is based on zero-padding (padding to 2 digits), for example, 0.18.8 < 0.18.11, 0.18.8 == 0.18.08.
The usage is as follows:
@When[cjc_version == "0.18.6"]
func foo() {
println("cjc_version equals 0.18.6")
}
@When[cjc_version != "0.18.6"]
func foo() {
println("cjc_version is NOT equal to 0.18.6")
}
@When[cjc_version > "0.18.6"]
func fnn() {
println("cjc_version is greater than 0.18.6")
}
@When[cjc_version <= "0.18.6"]
func fnn() {
println("cjc_version is less than or equal to 0.18.6")
}
@When[cjc_version < "0.18.6"]
func fee() {
println("cjc_version is less than 0.18.6")
}
@When[cjc_version >= "0.18.6"]
func fee() {
println("cjc_version is greater than or equal to 0.18.6")
}
main() {
foo()
fnn()
fee()
}
The execution result of the preceding code varies according to the cjc version.
debug
debug specifies whether the debugging mode is enabled, that is, whether the -g compilation option is enabled. This option can be used to switch between the debugging and release versions during code compilation. The debug condition supports only the logical NOT operator (!).
The usage is as follows:
@When[debug]
func foo() {
println("debug")
}
@When[!debug]
func foo() {
println("NOT debug")
}
main() {
foo()
}
If -g is enabled, the cjc debug information is displayed. If -g is not enabled, the NOT debug information is displayed.
test
test specifies whether the unit test option --test is enabled. The test condition supports only the logical NOT operator (!). It can be used to distinguish test code from common code.
The usage is as follows:
@When[test]
@Test
class Tests {
@TestCase
public func case1(): Unit {
@Expect("run", foo())
}
}
func foo() {
"run"
}
@When[!test]
main () {
println(foo())
}
Using --test for compilation and execution will yield test results, while compiling and running without --test will complete normally and provide the run information.
User-defined Compilation Condition Variables
Cangjie allows developers to define compilation condition variables and values. A defined condition variable must be a valid identifier and cannot have the same name as built-in condition variables. Its value is a character string literal. User-defined conditions support the == and != operators. Different from built-in condition variables, user-defined conditions need to be defined by using the --cfg compilation option during compilation or in the cfg.toml configuration file.
Configuring User-defined Condition Variables
You can configure user-defined condition variables in either of the following ways: Configure key-value pairs in the compilation options or configure key-value pairs in the configuration file.
You can use --cfg <value> to pass user-defined compilation condition variables to the compiler in the form of key-value pairs or specify the search path of the cfg.toml configuration file.
-
The option value must be enclosed in double quotation marks (
""). -
If the option value contains an equal sign (
=), the value is configured in the form of key-value pairs. If the path contains an equal sign (=), use a backslash (\) to escape the equal sign. Multiple key-value pairs can be separated by commas (,). Example:$ cjc --cfg "feature = lion, platform = dsp" source.cj -
The
--cfgcompilation option can be used for multiple times, for example:$ cjc --cfg "feature = lion" --cfg "platform = dsp" source.cj -
The same condition variable cannot be defined for multiple times, for example:
$ cjc --cfg "feature = lion" --cfg "feature = meta" source.cj$ cjc --cfg "feature = lion, feature = meta" source.cjErrors are reported for the preceding two compilation commands.
-
If the option value does not contain the equal sign (
=) or contains the equal sign (=) that is escaped by the backslash (\), the option value is passed to the compiler as the search path of thecfg.tomlconfiguration file, for example:$ cjc --cfg "./cfg" source.cjIf the
cfg.tomlfile exists in the./cfgdirectory, the user-defined compilation conditions configured in the./cfg/cfg.tomlfile are passed to the compiler during compilation. In thecfg.tomlfile, you need to use key-value pairs to configure user-defined condition variables. Each key-value pair occupies a line. The key name is a valid identifier, and the key value is a character string enclosed in double quotation marks (""). Example:feature = "lion" platform = "dsp" -
When
--cfgis used to configure the search path of thecfg.tomlfile for multiple times, thecfg.tomlfile is searched in the input sequence. If thecfg.tomlfile is not found in any input search path, thecfg.tomlfile is searched in the default path. -
If the
--cfgcompilation option is used for multiple times and the configuration is performed in the form of key-value pairs, the configuration in thecfg.tomlconfiguration file is ignored. -
If the
--cfgcompilation option is not used, the compiler searches for thecfg.tomlconfiguration file in the default path (thepackagedirectory orcjcexecution directory specified by--packageor-p).
Multi-condition Compilation
Cangjie conditional compilation allows developers to combine multiple conditional compilation options. Logical operators can be used to combine multiple conditions, and parentheses can be used to specify priorities.
The usage is as follows:
//source.cj
@When[(test || feature == "lion") && !debug]
func fee() {
println("feature lion")
}
main() {
fee()
}
Run the following command to compile and run the preceding code:
$ cjc --cfg="feature=lion" source.cj -o runner.out
The output is as follows:
feature lion
cjc Compilation Options
This section describes some common cjc compilation options. If an option also applies to cjc-frontend, the option is marked with a superscript [frontend]. If the behavior of the option in cjc-frontend is different from that of the option in cjc, the description is added for the option.
-
An option starting with two hyphens (-) is a long option, for example,
--xxxx. If a long option is followed by a parameter, a space or an equal sign (=) can be used between the option and parameter. For example,--xxxx <value>is equivalent to--xxxx=<value>. -
An option starting with a hyphen (-) is a short option, for example,
-x. If a short option is followed by a parameter, the option and parameter can be separated by a space or not. For example,-x <value>is equivalent to-x<value>.
Basic Options
--output-type=[exe|staticlib|dylib] [frontend]
Specifies the type of the output file. In exe mode, an executable file will be generated. In staticlib mode, a static library file (.a file) will be generated. In dylib mode, a dynamic library file (.so file for Linux, .dll file for Windows, and .dylib file for macOS) will be generated.
By default, the exe mode is used for cjc.
In addition to compiling the .cj file into an executable file, you can also compile it into a static or dynamic link library.
For example, using
$ cjc tool.cj --output-type=dylib
tool.cj can be compiled into a dynamic link library. On the Linux platform, cjc will generate a dynamic link library file named libtool.so.
[frontend] In cjc-frontend, the compilation process is performed only to the LLVM IR. Therefore, the output is always the .bc file. However, different --output-type types still affect the front-end compilation policy.
--package, -p [frontend]
Compiles a package. If using this option, you need to specify a directory as the input. The source code files in the directory must belong to the same package.
Assume that there is the log/printer.cj file.
package log
public func printLog(message: String) {
println("[Log]: ${message}")
}
In addition, there is the main.cj file.
import log.*
main() {
printLog("Everything is great")
}
Using
$ cjc -p log --output-type=staticlib
To compile the log package. cjc will generate the liblog.a file in the current directory.
Then, you can use the liblog.a file to compile the main.cj file. The compilation command is as follows:
$ cjc main.cj liblog.a
cjc compiles main.cj and liblog.a into an executable file main.
--module-name <value> [frontend]
Specifies the name of the module to be compiled.
Assume that there is the my_module/src/log/printer.cj file.
package log
public func printLog(message: String) {
println("[Log]: ${message}")
}
In addition, there is the main.cj file.
import my_module.log.*
main() {
printLog("Everything is great")
}
Using
$ cjc -p my_module/src/log --module-name my_module --output-type=staticlib -o my_module/liblog.a
To compile the log package and specify the module name as my_module. The cjc generates a my_module/liblog.a file in the my_module directory.
Then, you can use the liblog.a file to compile the main.cj file where the log package is imported. The compilation command is as follows:
$ cjc main.cj my_module/liblog.a
cjc compiles main.cj and liblog.a into an executable file main.
--output <value>, -o <value>, -o<value> [frontend]
Specifies the path of the output file. The output of the compiler will be written to the specified file.
For example, the following command specifies the name of the executable file that is output as a.out:
cjc main.cj -o a.out
--library <value>, -l <value>, -l<value>
Specifies the library file to be linked.
The specified library file is directly transferred to the linker. Generally, this compilation option needs to be used together with --library-path <value>.
The file name must be in the lib[arg].[extension] format. To link the a library, you can use the -l a option. The linker will search for files such as liba.a and liba.so in the library file search paths (or search for liba.dll when linking to the Windows target program) and links them to the final output as required.
--library-path <value>, -L <value>, -L<value>
Specifies the directory of the library file to be linked.
Generally, when using the --library <value> option, you also need to use this option to specify the directory of the library file to be linked.
The path specified by --library-path <value> will be added to the library file search paths of the linker. The path specified by the environment variable LIBRARY_PATH will also be added to the library file search paths of the linker. The path specified by --library-path has a higher priority than the path specified by LIBRARY_PATH.
Assume that there is the dynamic library file libcProg.so that is generated by compiling the following C language source file using the C language compiler.
#include <stdio.h>
void printHello() {
printf("Hello World\n");
}
In addition, there is the Cangjie file main.cj.
foreign func printHello(): Unit
main(): Int64 {
unsafe {
printHello()
}
return 0
}
Using
cjc main.cj -L . -l cProg
To compile main.cj and specify the cProg library to be linked. cjc will output an executable file main.
When main is executed, the output is as follows:
$ LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./main
Hello World
Note that because the dynamic library file is used, you need to add the directory of the library file to $LD_LIBRARY_PATH to ensure that main can be dynamically linked during execution.
-g [frontend]
Generates an executable file or library file with debugging information.
Note:
-gcan be used only with-O0. If a higher optimization level is used, an exception may occur for the debugging function.
--trimpath <value> [frontend]
Removes the prefix of the source file path information from the debugging information.
When compiling the Cangjie code, the cjc saves the absolute path information of the source file (.cj file) to provide debugging and exception information at runtime.
This option can be used to remove the specified path prefix from the source file path information. In this way, the source file path information in the file output by cjc does not contain the specified content.
You can use --trimpath multiple times to specify multiple different path prefixes. For each source file path, the compiler removes the first matched prefix from the path.
--coverage [frontend]
Generates an executable program that supports code coverage statistics. The compiler generates a code information file with the suffix gcno for each compilation unit. After the program is executed, an execution statistics file with the suffix gcda is generated for each compilation unit. With these two files, you can use the cjcov tool to generate the code coverage report for the current execution.
Note:
--coveragecan be used only with-O0. If a higher optimization level is used, the compiler generates an alarm and forces-O0to be used.--coverageis used to compile and generate executable programs. If it is used to generate static or dynamic libraries, link errors may occur when the libraries are used.
--int-overflow=[throwing|wrapping|saturating] [frontend]
Specifies the overflow policy for fixed-precision integer operation. The default value is throwing.
- In the
throwingpolicy, when the overflow occurs for an integer operation, an exception is thrown. - In the
wrappingpolicy, the integer operation wraps to the other end of the corresponding fixed-precision integer when the overflow occurs. - In the
saturatingpolicy, when the overflow occurs for an integer operation, the extremum value in the corresponding fixed precision is specified as the result.
--diagnostic-format=[default|noColor|json] [frontend]
Note:
Windows does not support the output of error information rendered in colors.
Specifies the output format of error information. The default value is default.
default: Error information is output in default format (with color).noColor: Error information is output in the default format (without color).json: Error information is output injsonformat.
--verbose, -V [frontend]
cjc prints the compiler version, toolchain dependency, and commands executed during compilation.
--help, -h [frontend]
Prints available compilation options.
When this option is used, the compiler only prints information about compilation options and does not compile any input file.
--version, -v [frontend]
Prints the compiler version information.
When this option is used, the compiler only prints version information and does not compile any input file.
--save-temps <value>
Saves the intermediate files generated during compilation to the directory specified by <value>.
The compiler retains intermediate files such as .bc, .o generated during compilation.
--import-path <value> [frontend]
Specifies the search path of the AST file of the imported module.
Assume that the following directory structure exists: The libs/myModule directory contains the library file of the myModule module and the AST export file of the log package.
.
├── libs
| └── myModule
| ├── log.cjo
| └── libmyModule.a
└── main.cj
And there is the main.cj file containing the following code:
import myModule.log.printLog
main() {
printLog("Everything is great")
}
You can use --import-path ./libs to add ./libs to the AST file search paths of the imported module. cjc uses the ./libs/myModule/log.cjo file to perform semantic check and compilation on the main.cj file.
--import-path provides the same functionality as the CANGJIE_PATH environment variable, but the path set through --import-path has a higher priority.
--scan-dependency [frontend]
Uses the --scan-dependency command to obtain the information about the direct dependency of the source code of a specified package or the cjo file of a package on other packages and other information. The information is output in json format.
// this file is placed under directory pkgA
macro package pkgA
import pkgB.*
import std.io.*
import pkgB.subB.*
cjc --scan-dependency --package pkgA
Or
cjc --scan-dependency pkgA.cjo
{
"package": "pkgA",
"isMacro": true,
"dependencies": [
{
"package": "pkgB",
"isStd": false,
"imports": [
{
"file": "pkgA/pkgA.cj",
"begin": {
"line": 2,
"column": 1
},
"end": {
"line": 2,
"column": 14
}
}
]
},
{
"package": "pkgB.subB",
"isStd": false,
"imports": [
{
"file": "pkgA/pkgA.cj",
"begin": {
"line": 4,
"column": 1
},
"end": {
"line": 4,
"column": 19
}
}
]
},
{
"package": "std.io",
"isStd": true,
"imports": [
{
"file": "pkgA/pkgA.cj",
"begin": {
"line": 3,
"column": 1
},
"end": {
"line": 3,
"column": 16
}
}
]
}
]
}
--no-sub-pkg [frontend]
Indicates that the current compilation package does not have subpackages.
After this option is enabled, the compiler can further reduce the code size.
--warn-off, -Woff <value> [frontend]
Disables all or some of the warnings that occur during compilation.
<value> can be specified as all or a preset warning group. If the parameter is specified as all, the compiler does not print all warnings generated during compilation. If the parameter is specified as a preset warning group, the compiler does not print the warnings in this group generated during compilation.
When a warning is printed, a #note line is displayed, indicating the group to which the warning belongs and how to close the warning. You can use --help to print all available parameters of the compilation option to view the specific group names.
--warn-on, -Won <value> [frontend]
Enables all or some of the warnings that occur during compilation.
The value range of <value> of --warn-on is the same as that of <value> of --warn-off. --warn-on is usually used together with --warn-off. For example, you can set -Woff all -Won <value> to allow only the warnings in the group specified by <value> to be printed.
Note that the sequence of --warn-on and --warn-off is sensitive. For the same group, the later option overwrites the previous option. For example, if you change the positions of the two compilation options in the preceding example to -Won <value> -Woff all, all warnings will be disabled.
--error-count-limit <value> [frontend]
Limits the maximum number of errors printed by the compiler.
The parameter <value> can be specified as all or a non-negative integer. If the parameter is specified as all, the compiler prints all errors generated during compilation. If the parameter is specified as a non-negative integer N, the compiler prints a maximum of N errors. The default value is 8.
--output-dir <value> [frontend]
Controls the directory for storing intermediate files and final files generated by the compiler.
Controls the directory for storing intermediate files generated by the compiler, for example, the .cjo files. If both --output-dir <path1> and --output <path2> are specified, the intermediate files are saved to <path1>, and the final output files are saved to <path1>/<path2>.
Note:
If this option and the
--outputoption are specified at the same time, the parameter of the--outputoption must be specified as a relative path.
--static-std
Statically links the std module of the Cangjie library.
This option takes effect only when the dynamic link library or executable file is compiled. By default, cjc statically links to the std module of the Cangjie library.
--dy-std
Dynamically links the std module of the Cangjie library.
This option takes effect only when the dynamic link library or executable file is compiled.
Note:
- If the
--static-stdand--dy-stdoptions are used together, only the last option takes effect. - The
--dy-stdand--static-libsoptions cannot be used together. Otherwise, an error is reported.
--static-libs
Statically links to non-std modules of the Cangjie library.
This option takes effect only when the dynamic link library or executable file is compiled. By default, cjc statically links to non-std modules of the Cangjie library.
--dy-libs
Dynamically links to non-std modules of the Cangjie library.
This option takes effect only when the dynamic link library or executable file is compiled.
Note:
- If the
--static-libsand--dy-libsoptions are used together, only the last option takes effect. - The
--static-stdand--dy-libsoptions cannot be used together. Otherwise, an error is reported. - If
--dy-stdis used independently, the--dy-libsoption takes effect by default and an alarm is generated. - If
--dy-libsis used independently, the--dy-stdoption takes effect by default and an alarm is generated.
--stack-trace-format=[default|simple|all]
Specifies the print format of the abnormal call stack to control the display of the stack frame information when an exception is thrown. The default format is default.
The formats of the abnormal call stack are described as follows:
default: The format isFunction name with generic parameters omitted (File name:Line number).simple: The format isFile name:Line number.all: The format isComplete function name (File name:Line number).
--lto=[full|thin]
Enables and specifies the compilation mode of Link Time Optimization (LTO).
Note:
- Executable files and static libraries (
.bcfiles) inLTOmode can be compiled, but dynamic libraries cannot be compiled and generated. That is, if--output-type=dylibis specified inLTOmode, an error is reported during compilation. WindowsandmacOSdo not support this function.- When the
Link Time Optimization(LTO) compilation mode is enabled and specified, the following optimization compilation options cannot be used at the same time:-Osand-Oz.
LTO supports two compilation modes:
-
--lto=full:full LTOmerges all compilation modules into a single module for global optimization. This can maximize the optimization potential and requires longer compilation time. -
--lto=thin: Compared withfull LTO,thin LTOuses parallel optimization on multiple modules and supports incremental compilation during link by default. The compilation time is shorter than that offull LTO. Because more global information is lost, the optimization effect ofthin LTOis not as good as that offull LTO.- Generally, the optimization effects from high to low are as follows:
full LTO>thin LTO> common static link compilation. - Generally, the compilation time in descending order is as follows:
full LTO>thin LTO> common static link compilation.
- Generally, the optimization effects from high to low are as follows:
LTO is used in the following scenarios:
-
Run the following command to compile the executable file:
$ cjc test.cj --lto=full or $ cjc test.cj --lto=thin -
Run the following command to compile the static library (
.bcfile) required inLTOmode and use the library file to compile the executable file:# The generated static library is a .bc file. $ cjc pkg.cj --lto=full --output-type=staticlib -o libpkg.bc # Input the .bc file and source file to the Cangjie compiler to compile the executable file. $ cjc test.cj libpkg.bc --lto=fullNote:
The path of the static library (
.bcfile) inLTOmode needs to be input to the Cangjie compiler together with the file. -
In
LTOmode, when the standard library is statically linked (--static-std&-static-libs), the code of the standard library also participates inLTOoptimization and is statically linked to the executable file. When the standard library is dynamically linked (--dy-std&-dy-libs), the dynamic library in the standard library is still used for linking inLTOmode.# Static linking. The code of the standard library also participates in LTO optimization. $ cjc test.cj --lto=full --static-std # Dynamic linking. The dynamic library is still used for linking. The code of the standard library is not participated in LTO optimization. $ cjc test.cj --lto=full --dy-std
--pgo-instr-gen
Enables instrumentation compilation to generate an executable program that carries instrumentation information.
This function does not support the compilation of macOS targets.
Profile-guided optimization (PGO) is a common compilation optimization technique that uses runtime profiling information to further improve program performance. Instrumentation-based PGO is a PGO optimization method using instrumentation information. It usually consists of three steps:
- The compiler performs instrumentation compilation on the source code, and generates the instrumented program.
- Run the instrumented program to generate a configuration file.
- The compiler uses the configuration file to compile the source code again.
# Generate the executable program "test" that supports source code execution statistics (carrying instrumentation information).
$ cjc test.cj --pgo-instr-gen -o test
# Run the executable program "test" to generate the configuration file "test.profraw".
$ LLVM_PROFILE_FILE="test.profraw" ./test
Note:
When running the program, you can use the environment variable
LLVM_PROFILE_FILE="test%c.profraw"to enable the continuous mode. That is, a configuration file can still be generated when the program crashes or is killed by a signal. You can use thellvm-profdatatool to view and analyze the configuration file. However,PGOdoes not support subsequent optimization steps in continuous mode.
--pgo-instr-use=<.profdata>
Uses the specified profdata configuration file to instruct the compilation and generate an optimized executable program.
This function does not support the compilation of macOS targets.
Note:
The
--pgo-instr-usecompilation option supports only configuration files in theprofdataformat. You can use thellvm-profdatatool to convert theprofrawconfiguration file to theprofdataconfiguration file.
# Convert the 'profraw' file to the 'profdata' file.
$ LD_LIBRARY_PATH=$CANGJIE_HOME/third_party/llvm/lib:$LD_LIBRARY_PATH $CANGJIE_HOME/third_party/llvm/bin/llvm-profdata merge test.profraw -o test.profdata
# Uses the specified configuration file "test.profdata" to instruct the compilation and generate an optimized executable program "testOptimized".
$ cjc test.cj --pgo-instr-use=test.profdata -o testOptimized
--target <value> [frontend]
Specifies the triple of the target platform for compilation.
The <value> parameter is a character string in the <arch>(-<vendor>)-<os>(-<env>) format. Specifically:
<arch>indicates the system architecture of the target platform, for example,aarch64orx86_64.<vendor>indicates the vendor of the target platform, such aspcorapple. If the platform vendor is not specified or the vendor is not important, you can typeunknownor omit this item.<os>indicates the operating system of the target platform, for example,LinuxorWin32.<env>indicates the ABI or standard specifications of the target platform, which is used to distinguish different running environments of the same operating system in a finer granularity, for example,gnuormusl.<env>can be omitted when the operating system does not need to be identified in a finer granularity.
cjc supports the following local and target platforms for cross compilation.
| Local Platform (host) | Target Platform (target) |
|---|---|
| x86_64-linux-gnu | aarch64-hm-gnu |
Before using --target to specify the target platform for cross compilation, prepare the cross compilation tool chain of the target platform and the corresponding Cangjie SDK version that can run on the local platform and be compiled to the target platform.
--target-cpu <value>
Note:
This option is an experimental function. The binary files generated using this option may have potential runtime problems. Pay attention to the risks of using this option. This option must be used together with the
--experimentaloption.
Specifies the CPU type of the compilation target.
When the CPU type of the compilation target is specified, the compiler attempts to use the extended instruction set specific to the CPU type when generating the binary files and attempts to apply the optimization applicable to the CPU type. The binary files generated for a particular CPU type typically lose portability and may not be able to run on other CPUs (with the same architectural instruction set).
This option supports the following tested CPU types:
x86-64 architecture:
- generic
aarch64 architecture:
- generic
- tsv110
generic is a general-purpose CPU type. When generic is specified, the compiler generates a general instruction applicable to the architecture. In this way, the generated binary file can run on various CPU types based on the architecture on the premise that the dynamic dependency of the operating system is consistent with that of the binary file. The default value of the --target-cpu option is generic.
This option also supports the following CPU types. They are not tested and verified. Note that the binary files generated using the following CPU types may have runtime problems.
x86-64 architecture:
- alderlake
- amdfam10
- athlon
- athlon-4
- athlon-fx
- athlon-mp
- athlon-tbird
- athlon-xp
- athlon64
- athlon64-sse3
- atom
- barcelona
- bdver1
- bdver2
- bdver3
- bdver4
- bonnell
- broadwell
- btver1
- btver2
- c3
- c3-2
- cannonlake
- cascadelake
- cooperlake
- core-avx-i
- core-avx2
- core2
- corei7
- corei7-avx
- geode
- goldmont
- goldmont-plus
- haswell
- i386
- i486
- i586
- i686
- icelake-client
- icelake-server
- ivybridge
- k6
- k6-2
- k6-3
- k8
- k8-sse3
- knl
- knm
- lakemont
- nehalem
- nocona
- opteron
- opteron-sse3
- penryn
- pentium
- pentium-m
- pentium-mmx
- pentium2
- pentium3
- pentium3m
- pentium4
- pentium4m
- pentiumpro
- prescott
- rocketlake
- sandybridge
- sapphirerapids
- silvermont
- skx
- skylake
- skylake-avx512
- slm
- tigerlake
- tremont
- westmere
- winchip-c6
- winchip2
- x86-64
- x86-64-v2
- x86-64-v3
- x86-64-v4
- yonah
- znver1
- znver2
- znver3
aarch64 architecture:
- a64fx
- ampere1
- apple-a10
- apple-a11
- apple-a12
- apple-a13
- apple-a14
- apple-a7
- apple-a8
- apple-a9
- apple-latest
- apple-m1
- apple-s4
- apple-s5
- carmel
- cortex-a34
- cortex-a35
- cortex-a510
- cortex-a53
- cortex-a55
- cortex-a57
- cortex-a65
- cortex-a65ae
- cortex-a710
- cortex-a72
- cortex-a73
- cortex-a75
- cortex-a76
- cortex-a76ae
- cortex-a77
- cortex-a78
- cortex-a78c
- cortex-r82
- cortex-x1
- cortex-x1c
- cortex-x2
- cyclone
- exynos-m3
- exynos-m4
- exynos-m5
- falkor
- kryo
- neoverse-512tvb
- neoverse-e1
- neoverse-n1
- neoverse-n2
- neoverse-v1
- saphira
- thunderx
- thunderx2t99
- thunderx3t110
- thunderxt81
- thunderxt83
- thunderxt88
In addition to the preceding optional CPU types, this option can use native as the current CPU type. The compiler attempts to identify the CPU type of the current machine and uses the CPU type as the target type to generate binary files.
--toolchain <value>, -B <value>, -B<value>
Specifies the path for storing binary files in the compilation toolchain.
Binary files include C runtime target files (such as crt0.o and crti.o) provided by compilers, linkers, and toolchains.
After the compilation toolchain is prepared, you can save it in a customized path and transfer the path to the compiler using --toolchain <value>. Then, the compiler can invoke the binary files in the path for cross compilation.
--sysroot <value>
Specifies the root directory of the compilation toolchain.
For a cross compilation toolchain with a fixed directory structure, if you do not need to specify other paths to binary files, dynamic libraries, and static libraries, you can use --sysroot <value> to transfer the root directory of the toolchain to the compiler. The compiler will automatically search for required binary files, dynamic libraries, and static libraries by analyzing the directory structures based on the target platform type. If this option is used, you do not need to specify the --toolchain and --library-path parameters.
Assume that cross compilation is performed on the platform whose triple is arch-os-env, and the cross compilation toolchain has the following directory structure:
/usr/sdk/arch-os-env
├── bin
| ├── arch-os-env-gcc (Cross compiler)
| ├── arch-os-env-ld (Linker)
| └── ...
├── lib
| ├── crt1.o (Target file at C runtime)
| ├── crti.o
| ├── crtn.o
| ├── libc.so (Dynamic library)
| ├── libm.so
| └── ...
└── ...
In addition, there is the Cangjie source file hello.cj. You can run the following command to cross-compile hello.cj to the arch-os-env platform:
cjc --target=arch-os-env --toolchain /usr/sdk/arch-os-env/bin --toolchain /usr/sdk/arch-os-env/lib --library-path /usr/sdk/arch-os-env/lib hello.cj -o hello
You can also use abbreviated parameters:
cjc --target=arch-os-env -B/usr/sdk/arch-os-env/bin -B/usr/sdk/arch-os-env/lib -L/usr/sdk/arch-os-env/lib hello.cj -o hello
If the directory of the toolchain complies with the common directory structure, you can run the following command without using the --toolchain and --library-path parameters:
cjc --target=arch-os-env --sysroot /usr/sdk/arch-os-env hello.cj -o hello
--strip-all, -s
Deletes the symbol table in the output file during the compilation of an executable file or dynamic library.
--discard-eh-frame
Deletes some information in the eh_frame and eh_frame_hdr segments (the CRT information is not processed) during the compilation of an executable file or dynamic library. This can reduce the size of the executable file or dynamic library. However, the debugging information is affected.
This function does not support the compilation of macOS targets.
--link-options <value>1
Specifies a linker option.
cjc transparently transmits the parameter of this option to the linker. The available parameters vary depending on the linker (system or specified). --link-options can be repeatedly used to specify multiple linker options.
The 1 superscript indicates that the linker transparent transmission option may vary according to the linker. For details about the supported options, see the linker document.
--disable-reflection
Disables the reflection option. That is, no reflection information is generated during compilation.
Note:
When cross compilation is performed to the aarch64-linux-ohos target, the reflection information is not generated default. This option does not take effect.
Unit Test Options
--test [frontend]
Indicates the entry provided by the unittest framework, which is automatically generated by the macro. When the cjc --test option is used for compilation, the program entry is test_entry instead of main. For details about how to use the unittest framework, see Cangjie Programming Language Library API.
For the a.cj file in the pkgc directory:
import std.unittest.*
import std.unittest.testmacro.*
@Test
public class TestA {
@TestCase
public func case1(): Unit {
print("case1\n")
}
}
You can run the following command in the pkgc directory:
cjc a.cj --test
Compile a.cj. The following information is displayed if you run main:
Note:
The execution duration of a test case may be inconsistent each time.
case1
--------------------------------------------------------------------------------------------------
TP: default, time elapsed: 29710 ns, Result:
TCS: TestA, time elapsed: 26881 ns, RESULT:
[ PASSED ] CASE: case1 (16747 ns)
Summary: TOTAL: 1
PASSED: 1, SKIPPED: 0, ERROR: 0
FAILED: 0
--------------------------------------------------------------------------------------------------
For the following directory structure:
application
├── src
├── pkgc
| ├── a1.cj
| └── a2.cj
└── a3.cj
You can use the -p compilation option in the application directory to compile the entire package.
cjc pkgc --test -p
Compile the test cases a1.cj and a2.cj in the pkgc package.
/*a1.cj*/
package a
import std.unittest.*
import std.unittest.testmacro.*
@Test
public class TestA {
@TestCase
public func caseA(): Unit {
print("case1\n")
}
}
/*a2.cj*/
package a
import std.unittest.*
import std.unittest.testmacro.*
@Test
public class TestB {
@TestCase
public func caseB(): Unit {
throw IndexOutOfBoundsException()
}
}
When you run main, the output is as follows (for reference only):
case1
--------------------------------------------------------------------------------------------------
TP: a, time elapsed: 367800 ns, Result:
TCS: TestA, time elapsed: 16802 ns, RESULT:
[ PASSED ] CASE: caseA (14490 ns)
TCS: TestB, time elapsed: 347754 ns, RESULT:
[ ERROR ] CASE: caseB (345453 ns)
REASON: An exception has occurred:IndexOutOfBoundsException
at std/core.Exception::init()(std/core/exception.cj:23)
at std/core.IndexOutOfBoundsException::init()(std/core/index_out_of_bounds_exception.cj:9)
at a.TestB::caseB()(/home/houle/cjtest/application/pkgc/a2.cj:7)
at a.lambda.1()(/home/houle/cjtest/application/pkgc/a2.cj:7)
at std/unittest.TestCases::execute()(std/unittest/test_case.cj:92)
at std/unittest.UT::run(std/unittest::UTestRunner)(std/unittest/test_runner.cj:194)
at std/unittest.UTestRunner::doRun()(std/unittest/test_runner.cj:78)
at std/unittest.UT::run(std/unittest::UTestRunner)(std/unittest/test_runner.cj:200)
at std/unittest.UTestRunner::doRun()(std/unittest/test_runner.cj:78)
at std/unittest.UT::run(std/unittest::UTestRunner)(std/unittest/test_runner.cj:200)
at std/unittest.UTestRunner::doRun()(std/unittest/test_runner.cj:75)
at std/unittest.entryMain(std/unittest::TestPackage)(std/unittest/entry_main.cj:11)
Summary: TOTAL: 2
PASSED: 1, SKIPPED: 0, ERROR: 1
FAILED: 0
--------------------------------------------------------------------------------------------------
--mock <on|off|runtime-error> [frontend]
If on is specified, the mock compilation is enabled for the package. This option allows classes in the package to be mocked in test cases. off is a method for explicitly disabling mock.
Note:
The mock is automatically enabled for this package in test mode (when
--testis enabled), and the--mockoption does not need to be explicitly passed.
runtime-error is available only in test mode (when --test is enabled). It allows compilation of packages with mock code, but any mock-related processing is not executed in the compiler (the processing may cause some overhead and affect the runtime performance of the test). This may be useful for the benchmark test of cases with mock code. When using this compilation option, avoid compiling cases with mock code and running tests. Otherwise, a runtime exception will be thrown.
Macro Options
cjc supports the following macro options. For more information about the macro, see Macro.
--compile-macro [frontend]
Compiles the macro definition file to generate the default macro definition dynamic library file.
--debug-macro [frontend]
Generates the Cangjie code file after macro expansion. This option can be used to debug the macro expansion function.
--parallel-macro-expansion [frontend]
Enables parallel macro expansion. This option can be used to shorten the macro expansion compilation time.
Conditional Compilation Options
cjc supports the following conditional compilation options. For more information about conditional compilation, see Conditional Compilation.
--cfg <value> [frontend]
Specifies a customized compilation condition.
Parallel Compilation Options
cjc supports the following parallel compilation options for higher compilation efficiency.
--jobs <value>, -j <value> [frontend]
Sets the maximum number of jobs for parallel compilation. value must be a proper positive integer. When value is greater than the maximum parallel processing capability supported by hardware, the compiler performs parallel compilation based on the default setting calculated based on the parallel processing capability supported by the hardware.
If this compilation option is not set, the compiler performs parallel compilation based on the default setting calculated based on the parallel processing capability supported by the hardware.
Note:
--jobs 1indicates that the compilation is performed in serial mode.
--aggressive-parallel-compile, --apc [frontend]
After this option is enabled, the compiler uses a more aggressive policy (which may affect optimization) to perform parallel compilation to achieve higher compilation efficiency.
Note:
In some scenarios, the
--aggressive-parallel-compileoption is forcibly enabled or disabled by the compiler.
The --aggressive-parallel-compile option is forcibly enabled by the compiler in the following scenarios:
-O0-g
The --aggressive-parallel-compile option is forcibly disabled by the compiler in the following scenarios:
--fobf-string--fobf-const--fobf-layout--fobf-cf-flatten--fobf-cf-bogus--lto--coverage- Compiling Windows targets
Optimization Options
--fchir-constant-propagation [frontend]
Enables the chir constant propagation optimization.
--fno-chir-constant-propagation [frontend]
Disables the chir constant propagation optimization.
--fchir-function-inlining [frontend]
Enables the chir function inlining optimization.
--fno-chir-function-inlining [frontend]
Disables the chir function inlining optimization.
--fchir-devirtualization [frontend]
Enables the chir call devirtualization optimization.
--fno-chir-devirtualization [frontend]
Disables the chir call devirtualization optimization.
--fast-math [frontend]
After this option is enabled, the compiler makes fast assumption about floating-point numbers that may cause precision loss to optimize floating-point number operations.
-O<N> [frontend]
Specifies the code optimization level with parameters.
A higher optimization level indicates that the compiler performs more code optimization to generate more efficient programs and may require longer compilation time.
By default, cjc performs the code optimization at level O0. Currently, cjc supports the following optimization levels: O0, O1, O2, Os, and Oz.
When the optimization level is 2, cjc also enables the following options in addition to the corresponding optimization:
--fchir-constant-propagation--fchir-function-inlining--fchir-devirtualization
When the optimization level is s, cjc also optimizes the code size in addition to O2-level optimization.
When the optimization level is z, cjc further reduces the code size in addition to Os-level optimization.
Note:
When the optimization level is s or z, the link-time optimization compilation option
--lto=[full|thin]cannot be used.
-O [frontend]
Uses O1-level code optimization, which is equivalent to -O1.
Code Obfuscation Options
cjc supports code obfuscation, which is disabled by default, to provide extra code protection.
cjc supports the following code obfuscation options:
--fobf-string
Enables string obfuscation.
Obfuscate strings in code so that attackers cannot statically and directly read string data in binary programs.
--fno-obf-string
Disables string obfuscation.
--fobf-const
Enables constant obfuscation.
Obfuscate constants in code by replacing numeric operation instructions with the equivalent numeric operation instruction sequence that is more complex.
--fno-obf-const
Disables constant obfuscation.
--fobf-layout
Enables layout obfuscation.
The layout obfuscation function obfuscates symbols (including function names and global variable names), path names, code line numbers, and function layout in code. After this compilation option is used, cjc generates the symbol mapping output file *.obf.map in the current directory. If the --obf-sym-output-mapping option is configured, the parameter value in --obf-sym-output-mapping is used as the name of the symbol mapping output file generated by cjc. The symbol mapping output file contains the mapping between symbols before and after obfuscation, and can be used to de-obfuscate the obfuscated symbols.
Note:
Layout obfuscation and parallel compilation conflict with each other. Do not enable them at the same time. Otherwise, parallel compilation becomes invalid.
--fno-obf-layout
Disables layout obfuscation.
--obf-sym-prefix <string>
Specifies the prefix string added by the layout obfuscation function for symbol obfuscation.
After this option is configured, the prefix is added to all obfuscated symbols. Symbol conflicts may occur when multiple Cangjie packages are obfuscated during compilation. You can use this option to specify different prefixes for different packages to avoid symbol conflicts.
--obf-sym-output-mapping <file>
Specifies the symbol mapping output file for layout obfuscation.
The symbol mapping output file records the original symbol names, symbol names after obfuscation, and paths of the files containing symbols. The symbol mapping output file can be used to de-obfuscate the obfuscated symbols.
--obf-sym-input-mapping <file,...>
Specifies symbol mapping input files for layout obfuscation.
The layout obfuscation function uses the mapping relationships in these files to obfuscate symbols. To compile Cangjie packages with call relationships, use the symbol mapping output file of the called package as the parameter of the --obf-sym-input-mapping option for obfuscating the calling package, ensuring that the obfuscation results of the same symbol are the same.
--obf-apply-mapping-file <file>
Provides a customized symbol mapping file for layout obfuscation. The layout obfuscation function obfuscates symbols based on the mapping in the file.
The file format is as follows:
<original_symbol_name> <new_symbol_name>
original_symbol_name indicates the names before obfuscation, and new_symbol_name indicates the names after obfuscation. original_symbol_name consists of multiple fields. field indicates a field name, which can be a module name, package name, class name, structure name, enumeration name, function name, or variable name. fields are separated by '.'. If field indicates a function name, the parameter type of the function needs to be modified with parentheses '()' and appended to the function name. For a function without parameters, the content in the parentheses is empty. If field has a generic parameter, use angle brackets '<>' to add the generic parameter to the end of field.
The layout obfuscation function replaces original_symbol_name in Cangjie apps with new_symbol_name. The symbols that are not in the file are replaced with random names. If the mapping specified in the file conflicts with that in --obf-sym-input-mapping, the compiler throws an exception and stops compilation.
--fobf-export-symbols
Enables the layout obfuscation function to obfuscate export symbols. This option is enabled by default when the layout obfuscation function is enabled.
After this option is enabled, the layout obfuscation function will obfuscate the export symbols.
--fno-obf-export-symbols
Disables the layout obfuscation function from obfuscating export symbols.
--fobf-source-path
Enables the layout obfuscation function to obfuscate the path information of symbols. This option is enabled by default when the layout obfuscation function is enabled.
After this option is enabled, the layout obfuscation function obfuscates the path in the exception stack information and replaces the path name with the character string "SOURCE".
--fno-obf-source-path
Disables the layout obfuscation function from obfuscating the path in the stack information.
--fobf-line-number
Enables the layout obfuscation function to obfuscate the line number in the stack information. This option is enabled by default when the layout obfuscation function is enabled.
After this option is enabled, the layout obfuscation function obfuscates the line number in the exception stack information and replaces the line number with 0.
--fno-obf-line-number
Disables the layout obfuscation function from obfuscating the line number in the stack information.
--fobf-cf-flatten
Enables control flow flattening obfuscation.
Obfuscate the control flow in the code to complicate the transfer logic.
--fno-obf-cf-flatten
Disables control flow flattening obfuscation.
--fobf-cf-bogus
Enables false control flow obfuscation.
A false control flow is inserted into the code, complicating the code logic.
--fno-obf-cf-bogus
Disables false control flow obfuscation.
--fobf-all
Enables all obfuscation functions.
Specifying this option is equivalent to specifying the following options:
--fobf-string--fobf-const--fobf-layout--fobf-cf-flatten--fobf-cf-bogus
--obf-config <file>
Specifies the path of the code obfuscation configuration file.
In the configuration file, you can disable the obfuscation tool from obfuscating some functions or symbols. The format of the configuration file is as follows:
obf_func1 name1
obf_func2 name2
...
The first parameter obf_func indicates the specific obfuscation function as follows:
obf-cf-bogus: False control flow obfuscationobf-cf-flatten: Control flow flattening obfuscationobf-const: constant obfuscationobf-layout: layout obfuscation
The second parameter name indicates the object to be reserved. It consists of multiple fields. field indicates a field name, which can be a package name, class name, structure name, enumeration name, function name, or variable name.
fields are separated by '.'. If field indicates a function name, the parameter type of the function needs to be modified with parentheses '()' and appended to the function name. For a function without parameters, the content in the parentheses is empty.
For example, assume that the packA package contains the following code:
package packA
class MyClassA {
func funcA(a: String, b: Int64): String {
return a
}
}
To disable the control flow flattening function from obfuscating funcA, you can write the following rule:
obf-cf-flatten packA.MyClassA.funcA(std.core.String, Int64)
You can also use wildcards to write a more flexible rule so that one rule can retain multiple objects. Currently, the following types of wildcards are supported:
Wildcards of obfuscation functions
| Wildcard of Obfuscation Functions | Description |
|---|---|
? | Matches a single character in names. |
* | Matches any number of characters in names. |
Wildcards of field names
| Wildcard of Field Names | Description |
|---|---|
? | Matches a single non-delimiter '.' character in field names. |
* | Matches any number of characters in field names, excluding separators '.' and parameters. |
** | Matches any number of characters in field names, including the separator '.' between fields and parameters. '**' takes effect only when it is used as an independent field. Otherwise, it is processed as '*'. |
Wildcards of parameter types of functions
| Wildcard of Parameter Types | Description |
|---|---|
... | Matches any number of parameters. |
*** | Matches a parameter of any type. |
Note:
Parameter types also consist of field names. Therefore, wildcards of field names also can be used to match a single parameter type.
Here are some examples of using wildcards:
Example 1:
obf-cf-flatten pro?.myfunc()
This rule indicates that the obf-cf-flatten function is not allowed to obfuscate the pro?.myfunc() function. pro?.myfunc() can match pro0.myfunc() but cannot match pro00.myfunc().
Example 2:
* pro0.**
This rule indicates that any obfuscation function is not allowed to obfuscate any function or variable in the pro0 package.
Example 3:
* pro*.myfunc(...)
This rule indicates that any obfuscation function is not allowed to obfuscate the pro*.myfunc(...) function. pro*.myfunc(...) can match the myfunc function with any parameters in any single-layer package starting with pro.
For a multi-layer package name, for example, pro0.mypack.myfunc(), use pro*.**.myfunc(...) for matching. Note that '**' takes effect only when it is used as a field name. Therefore, pro**.myfunc(...) is equivalent to pro*.myfunc(...) and cannot be used for multi-layer package names. To match all myfunc functions in all packages starting with pro (including functions named myfunc in classes), use pro*.**.myfunc(...).
Example 4:
obf-cf-* pro0.MyClassA.myfunc(**.MyClassB, ***, ...)
This rule indicates that the obf-cf-* function is not allowed to obfuscate the pro0.MyClassA.myfunc(**.MyClassB, ***, ...) function. obf-cf-* matches the obf-cf-bogus and obf-cf-flatten obfuscation functions. pro0.MyClassA.myfunc(**.MyClassB, ***, ...) matches the pro0.MyClassA.myfunc function, where the first parameter can be of the MyClassB type in any package, and the second parameter can be of any type and be followed by zero or more parameters.
--obf-level <value>
Specifies the obfuscation strength level.
You can specify the strength level from 1 to 9. The default strength level is 5. The larger the level number, the higher the strength. This option affects the size of the output file and the execution overhead.
--obf-seed <value>
Specifies the random seed of the obfuscation algorithm.
By specifying the random seed of the obfuscation algorithm, the same Cangjie code can have different obfuscation results in different builds. By default, the same Cangjie code has the same obfuscation result after each obfuscation.
Compiler Security Options
Note:
Windows and macOS versions do not support compiler security options.
By default, cjc generates address-independent code and address-independent executable files when compiling executable files.
cjc supports the following security-related linker options using --link-options:
--link-options "-z noexecstack"1
Sets a thread stack to be a non-executable one.
--link-options "-z relro"1
Sets a global offset table (GOT) relocation to read-only.
--link-options "-z now"1
Sets immediate binding.
Code Coverage Instrumentation Options
Note:
Windows and macOS versions do not support the code coverage instrumentation options.
Cangjie supports code coverage instrumentation (SanitizerCoverage, short for SanCov) and provides the same interfaces as those of LLVM SanitizerCoverage. The compiler inserts the coverage feedback function at the function or BasicBlock level. You only need to implement the specified callback function to obtain the program running status during running.
Cangjie provides the SanCov function by package. That is, a package can only be instrumented or not instrumented.
--sanitizer-coverage-level=0/1/2
Indicates the instrumentation level. The value 0 indicates that no instrumentation is performed. The value 1 indicates that function-level instrumentation is performed, that is, callback functions are inserted only at the entry of every function. The value 2 indicates that BasicBlock-level instrumentation is performed, that is, callback functions are inserted at every basic block.
If no value is specified, the value 2 is used by default.
This compilation option affects only the instrumentation levels of --sanitizer-coverage-trace-pc-guard, --sanitizer-coverage-inline-8bit-counters, and --sanitizer-coverage-inline-bool-flag.
--sanitizer-coverage-trace-pc-guard
After this option is enabled, the function call __sanitizer_cov_trace_pc_guard(uint32_t *guard_variable) is inserted on every edge. The option is affected by sanitizer-coverage-level.
Note that the implementation of this function is different from that of gcc/llvm: void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) is not inserted to a constructor; instead the function call uint32_t *__cj_sancov_pc_guard_ctor(uint64_t edgeCount) is inserted during package initialization.
The callback function __cj_sancov_pc_guard_ctor needs to be implemented by developers. The package with SanCov enabled calls the callback function as early as possible. The input parameter is the number of edges of the package, and the return value is the memory area created by the calloc function.
To call __sanitizer_cov_trace_pc_guard_init, you are advised to call it in __cj_sancov_pc_guard_ctor and use the dynamically created buffer to calculate the input parameter and return value of the function.
A standard __cj_sancov_pc_guard_ctor reference implementation is as follows:
uint32_t *__cj_sancov_pc_guard_ctor(uint64_t edgeCount) {
uint32_t *p = (uint32_t *) calloc(edgeCount, sizeof(uint32_t));
__sanitizer_cov_trace_pc_guard_init(p, p + edgeCount);
return p;
}
--sanitizer-coverage-inline-8bit-counters
After this option is enabled, an accumulator is inserted on every edge and the accumulator is incremented by 1 for the experienced edge. The option is affected by sanitizer-coverage-level.
Note that the implementation of this function is different from that of gcc/llvm: void __sanitizer_cov_8bit_counters_init(char *start, char *stop) is not inserted to a constructor; instead the function call uint8_t *__cj_sancov_8bit_counters_ctor(uint64_t edgeCount) is inserted during package initialization.
The callback function __cj_sancov_pc_guard_ctor needs to be implemented by developers. The package with SanCov enabled calls the callback function as early as possible. The input parameter is the number of edges of the package, and the return value is the memory area created by the calloc function.
To call __sanitizer_cov_8bit_counters_init, you are advised to call it in __cj_sancov_8bit_counters_ctor and use the dynamically created buffer to calculate the input parameter and return value of the function.
A standard __cj_sancov_8bit_counters_ctor reference implementation is as follows:
uint8_t *__cj_sancov_8bit_counters_ctor(uint64_t edgeCount) {
uint8_t *p = (uint8_t *) calloc(edgeCount, sizeof(uint8_t));
__sanitizer_cov_8bit_counters_init(p, p + edgeCount);
return p;
}
--sanitizer-coverage-inline-bool-flag
After this option is enabled, a boolean value is inserted on every edge and the boolean value is set to True for the experienced edge. The option is affected by sanitizer-coverage-level.
Note that the implementation of this function is different from that of gcc/llvm: void __sanitizer_cov_bool_flag_init(bool *start, bool *stop) is not inserted to a constructor; instead the function call bool *__cj_sancov_bool_flag_ctor(uint64_t edgeCount) is inserted during package initialization.
The callback function __cj_sancov_bool_flag_ctor needs to be implemented by developers. The package with SanCov enabled calls the callback function as early as possible. The input parameter is the number of edges of the package, and the return value is the memory area created by the calloc function.
To call __sanitizer_cov_bool_flag_init, you are advised to call it in __cj_sancov_bool_flag_ctor and use the dynamically created buffer to calculate the input parameter and return value of the function.
A standard __cj_sancov_bool_flag_ctor reference implementation is as follows:
bool *__cj_sancov_bool_flag_ctor(uint64_t edgeCount) {
bool *p = (bool *) calloc(edgeCount, sizeof(bool));
__sanitizer_cov_bool_flag_init(p, p + edgeCount);
return p;
}
--sanitizer-coverage-pc-table
This compilation option provides the mapping between instrumentation points and source code. Currently, only the function-level mapping is provided. This option must work with --sanitizer-coverage-trace-pc-guard, --sanitizer-coverage-inline-8bit-counters, and --sanitizer-coverage-inline-bool-flag options, and requires one or more of the options to be enabled at the same time.
Note that the implementation of this function is different from that of gcc/llvm: void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg, const uintptr_t *pcs_end); is not inserted to a constructor; instead the function call void __cj_sancov_pcs_init(int8_t *packageName, uint64_t n, int8_t **funcNameTable, int8_t **fileNameTable, uint64_t *lineNumberTable) is inserted during package initialization. The input parameters are described as follows:
int8_t *packageName: package name, which is a character string. (The instrumentation uses the C-style int8 array as the input parameter to express the character string, same as below.)uint64_t n: indicates that n functions are instrumented.int8_t **funcNameTable: string array whose length is n. The function name corresponding to the ith instrumentation point is funcNameTable[i].int8_t **fileNameTable: string array whose length is n. The file name corresponding to the ith instrumentation point is fileNameTable[i].uint64_t *lineNumberTable: uint64 array whose length is n. The line number corresponding to the ith instrumentation point is lineNumberTable[i].
To call __sanitizer_cov_pcs_init, you need to convert Cangjie pc-table to C pc-table.
--sanitizer-coverage-stack-depth
After this compilation option is enabled, the SP pointer can be obtained only that the call __updateSancovStackDepth is inserted at every function entry and implemented in C, because Cangjie cannot obtain the SP pointer.
A standard updateSancovStackDepth implementation is as follows:
thread_local void* __sancov_lowest_stack;
void __updateSancovStackDepth()
{
register void* sp = __builtin_frame_address(0);
if (sp < __sancov_lowest_stack) {
__sancov_lowest_stack = sp;
}
}
--sanitizer-coverage-trace-compares
After this option is enabled, the function callback functions are inserted before all compare and match instructions are called. The following are the function lists, which are the same as the API functions of LLVM. For details, see Tracing data flow.
void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2);
void __sanitizer_cov_trace_const_cmp1(uint8_t Arg1, uint8_t Arg2);
void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2);
void __sanitizer_cov_trace_const_cmp2(uint16_t Arg1, uint16_t Arg2);
void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2);
void __sanitizer_cov_trace_const_cmp4(uint32_t Arg1, uint32_t Arg2);
void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2);
void __sanitizer_cov_trace_const_cmp8(uint64_t Arg1, uint64_t Arg2);
void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases);
--sanitizer-coverage-trace-memcmp
Feeds back prefix comparison information in String and Array comparisons. If this option is enabled, a callback function is inserted before the comparison functions of String and Array. Specifically, the corresponding stub functions will be inserted for the following APIs of String and Array:
- String==: __sanitizer_weak_hook_memcmp
- String.startsWith: __sanitizer_weak_hook_memcmp
- String.endsWith: __sanitizer_weak_hook_memcmp
- String.indexOf: __sanitizer_weak_hook_strstr
- String.replace: __sanitizer_weak_hook_strstr
- String.contains: __sanitizer_weak_hook_strstr
- CString==: __sanitizer_weak_hook_strcmp
- CString.startswith: __sanitizer_weak_hook_memcmp
- CString.endswith: __sanitizer_weak_hook_strncmp
- CString.compare: __sanitizer_weak_hook_strcmp
- CString.equalsLower: __sanitizer_weak_hook_strcasecmp
- Array==: __sanitizer_weak_hook_memcmp
- ArrayList==: __sanitizer_weak_hook_memcmp
Experimental Function Options
--experimental [frontend]
Enables the experimental function to allow other experimental function options to be used on the command line.
Note:
Binary files generated using the experimental function may have potential runtime problems. Pay attention to the risks of using this option.
Other Functions
Coloring the error information of the compiler
For the Cangjie compiler for Windows, the error information is colored only when the compiler runs Windows 10 version 1511(Build 10586) or later.
Setting build-id
--link-options "--build-id=<arg>"1 can be used to transparently transmit the linker options to set build-id.
This function is unavailable to compile Windows targets.
Setting rpath
--link-options "-rpath=<arg>"1 can be used to transparently transmit the linker options to set rpath.
This function is unavailable to compile Windows targets.
Incremental compilation
--incremental-compile[frontend] can be used to enable incremental compilation. After this function is enabled, cjc accelerates the compilation based on the cache file of the previous compilation.
Environment Variables Used by cjc
Here describe the environment variables that may be used by the Cangjie compiler during code compilation.
TMPDIR or TMP
The Cangjie compiler saves the temporary files generated during compilation to a temporary directory. By default, the files are saved in the /tmp directory for the Linux and macOS operating systems, and in the C:\Windows\Temp directory for the Windows operating system. The Cangjie compiler also allows you to set the directory of temporary files. On the Linux and macOS operating systems, you can set the environment variable TMPDIR to change the directory of temporary files. On the Windows operating system, you can set the environment variable TMP to change the directory of temporary files.
For example: In Linux shell
export TMPDIR=/home/xxxx
In Windows cmd
set TMP=D:\\xxxx
Installation and Support of Toolchain on Linux
The Cangjie toolchain has been fully tested on the following Linux distributions:
- SUSE Linux Enterprise Server 12 SP5
- Ubuntu 18.04
- Ubuntu 20.04
Commands for Installing Cangjie Toolchain Dependencies on Various Linux Distributions
Note:
Some tools on which the Cangjie toolchain depends may not be directly installed through the default software source on certain Linux distributions. You can manually install them by referring to Compiling and Installing Dependency Tools.
SUSE Linux Enterprise Server 12 SP5
$ zypper install \
binutils \
glibc-devel \
gcc-c++
In addition, you need to install OpenSSL 3. For details about the installation method, see Compiling and Installing Dependency Tools.
Ubuntu 18.04
$ apt-get install \
binutils \
libc-dev \
libc++-dev \
libgcc-7-dev
In addition, you need to install OpenSSL 3. For details about the installation method, see Compiling and Installing Dependency Tools.
Ubuntu 20.04
$ apt-get install \
binutils \
libc-dev \
libc++-dev \
libgcc-9-dev
In addition, you need to install OpenSSL 3. For details about the installation method, see Compiling and Installing Dependency Tools.
Other Linux Distributions
Depending on the Linux distribution you use, you may need to refer to the preceding dependency installation commands and use your system package management tool to install the corresponding dependencies. If your system does not provide related software packages, you may need to install the link tool, C language development tool, C++ development tool, GCC compiler, and OpenSSL 3 to use the Cangjie toolchain.
Compiling and Installing Dependency Tools
Currently, some standard libraries (and some tools) in the Cangjie toolchain use OpenSSL 3. If the system package management tool does not provide OpenSSL 3, you may need to compile and install OpenSSL 3 using the source code. This section describes how to compile OpenSSL 3 using the source code.
OpenSSL 3
You can download the OpenSSL 3 source code from the following link:
- https://www.openssl.org/source/
- https://www.openssl.org/source/old/
OpenSSL 3.0.7 or later is recommended.
Note:
Before running the following compilation and installation commands, read the notes carefully and adjust the commands based on the actual situation. Incorrect configuration and installation may cause other software to be unavailable. If you encounter issues during the compilation and installation or you want to perform additional installation and configuration, see the
INSTALLfile in the OpenSSL source code or the OpenSSL FAQ.
Using OpenSSL 3.0.7 as an example, after downloading, run the following command to decompress the package:
$ tar xf openssl-3.0.7.tar.gz
Go to the directory after decompressing the package.
$ cd openssl-3.0.7
Compile OpenSSL.
Note:
If OpenSSL has been installed on your system, you are advised to use the
--prefix=<path>option to specify a custom installation path, for example,--prefix=/usr/local/openssl-3.0.7or your personal directory. If OpenSSL already exists in the system directory, running the following command to compile and install OpenSSL may overwrite OpenSSL and cause applications that depend on OpenSSL to be unavailable.
$ ./Configure --libdir=lib
$ make
Test OpenSSL.
$ make test
To install OpenSSL to the system directory (or the directory you specified in --prefix), you may need to provide root permissions to successfully run the following command:
$ make install
Or
$ sudo make install
If the installation path is not set using --prefix during OpenSSL compilation, the OpenSSL installation is complete. If you specified a custom installation path using --prefix, you need to set the following variables so that the Cangjie toolchain can find OpenSSL 3.
Note:
If another version of OpenSSL exists in your system, the default OpenSSL version used by other compilation and development tools may also be affected in addition to the Cangjie toolchain after the following configuration. If OpenSSL incompatibility occurs when other compilation and development tools are used, configure the following variables only for the Cangjie development environment.
Replace <prefix> with the custom installation path.
$ export LIBRARY_PATH=<prefix>/lib:$LIBRARY_PATH
$ export LD_LIBRARY_PATH=<prefix>/lib:$LD_LIBRARY_PATH
The environment variables configured using the preceding method are valid only in the current shell session window. If you want the shell to configure them automatically every time it starts, you can add the preceding commands to $HOME/.bashrc, $HOME/.zshrc, or other shell configuration files (depending on the shell type).
If you want the configuration to take effect for all users by default, run the following commands.
Replace <prefix> with the custom installation path.
$ echo "export LIBRARY_PATH=<prefix>/lib:$LIBRARY_PATH" >> /etc/profile
$ echo "<prefix>/lib" >> /etc/ld.so.conf
$ ldconfig
After the execution is complete, open the shell session window again for the modification to take effect.
OpenSSL 3 has been successfully installed. You can go back to the original section to continue reading or try to run the Cangjie compiler.
Runtime Environment Variable User Guide
This section describes the environment variables provided by runtime.
In the Linux shell and macOS shell, you can use the following mode to set the environment variables provided at Cangjie runtime:
$ export VARIABLE=value
In the Windows cmd, you can use the following mode to set the environment variables provided at Cangjie runtime:
> set VARAIBLE=value
The examples in this section use the setting method for Linux shell. You can choose an appropriate method for setting environment variables based on your operating platform.
Optional Configuration for Runtime Initialization
Note:
- All integer parameters are of the Int64 type, and floating-point parameters are of the Float64 type.
- If the maximum value is not explicitly specified by any parameter, the implicit maximum value is the maximum value of such type by default.
- If any parameter exceeds the specified range, the default value is used automatically.
cjHeapSize
Specifies the maximum size of the Cangjie heap. The unit can be KB, MB, or GB. The value range is [4 MB, System physical memory]. If the specified value is out of the range, the default value is used. If the physical memory is less than 1 GB, the default size is 64 MB. Otherwise, the default size is 256 MB.
Example:
export cjHeapSize=32GB
cjRegionSize
Specifies the size of the thread local buffer of the region allocator. The unit can be KB, MB, or GB. The value range is [4 KB, 2048 KB]. If the value is out of the range, the default value is used. The default size is 64 KB.
Example:
export cjRegionSize=1024kb
cjExemptionThreshold
Specifies the threshold of live regions. The value range is (0,1]. If the number of live objects in a region is greater than this value multiplied by the region size, the region will not be collected (dead objects continue to occupy the memory). A larger value indicates a higher probability that regions are collected and less fragmentation in the heap. However, frequent region collection affects performance. If the value is out of the range, the default value is used. The default size is 1024 KB. The default value is 0.8, that is, 80%.
Example:
export cjExemptionThreshold=0.8
cjHeapUtilization
Specifies the Cangjie heap utilization. This parameter is used as a reference for updating the heap threshold after GC. The value range is (0, 1]. When the total size of objects in the heap reaches the threshold, GC is performed. A smaller value indicates a higher updated heap threshold and a lower probability of triggering GC. If the value is out of the range, the default value is used. The default value is 0.8, that is, 80%.
Example:
export cjHeapUtilization=0.8
cjHeapGrowth
Specifies the growth rate of the Cangjie heap. This parameter is used as a reference for updating the heap threshold after GC. The value must be greater than 0. The growth rate is calculated as 1 + cjHeapGrowth. A larger value indicates a higher updated heap threshold and a lower probability of triggering GC. The default value is 0.15, indicating that the growth rate is 1.15.
Example:
export cjHeapGrowth=0.15
cjAlloctionRate
Specifies the rate at which the Cangjie runtime allocates objects. The value must be greater than 0, measured in MB/s, indicating the number of objects that can be allocated per second. The default value is 10240, indicating that 10240 MB objects can be allocated per second.
Example:
export cjAlloctionRate=10240
cjAlloctionWaitTime
Specifies the wait time for the Cangjie runtime when objects are being allocated. The value must be greater than 0. The unit can be s, ms, μs, or ns (recommended). If the time interval since the last object allocation is less than this value, the system waits. The default interval is 1000 ns.
Example:
export cjAlloctionWaitTime=1000ns
cjGCThreshold
Specifies the reference threshold of the Cangjie heap. The unit can be KB, MB, or GB. The value must be an integer greater than 0. When the size of the Cangjie heap exceeds this value, GC is triggered. The default value is the heap size.
Example:
export cjGCThreshold=20480KB
cjGarbageThreshold
When GC occurs, if the ratio of dead objects in a region exceeds this environment variable, the region is placed in the candidate set and may be collected later (if affected by other policies, the region may not be collected). The default value is 0.5, unitless. The value range is [0.0, 1.0].
Example:
export cjGarbageThreshold=0.5
cjGCInterval
Specifies the interval time between two GCs. The value must be greater than 0. The unit can be s, ms (recommended), μs, or ns. If the interval since the last GC is less than this value, the current GC will be ignored. This parameter controls the GC frequency. The default interval is 150 ms.
Example:
export cjGCInterval=150ms
cjBackupGCInterval
Specifies the backup GC interval. The value must be greater than 0. The unit can be s (recommended), ms, μs, or ns. If GC is not triggered within this time, a backup GC is triggered. The default interval is 240 seconds, that is, 4 minutes.
Example:
export cjBackupGCInterval=240s
cjGCThreads
Specifies a factor that affects the number of GC threads. The value must be greater than 0. The number of GC threads is calculated as follows: (Number of concurrent threads supported by the system/cjGCThreads) – 1. The default value is 8.
Example:
export cjGCThreads=8
cjProcessorNum
Specifies the maximum number of concurrent Cangjie threads. The value range is (0, Number of CPU cores x 2]. If the value is out of the range, the default value is used. The system API is called to obtain the number of CPU cores. If the operation is successful, the default value is the number of CPU cores. Otherwise, the default value is 8.
Example:
export cjProcessorNum=2
cjStackSize
Specifies the stack size of the Cangjie thread. The unit can be KB, MB, or GB. The value range is [64 KB, 1 GB] on the Linux platform and [128 KB, 1 GB] on the Windows platform. If the value is out of the range, the default value is used. The default size is 64 KB on Linux and 128 KB on Windows.
Example:
export cjStackSize=100kb
Optional Configuration for O&M Logs
MRT_LOG_FILE_SIZE
Specifies the size of runtime O&M logs. The default size is 10 MB. The unit can be KB, MB, or GB. The value must be greater than 0.
When the log size exceeds this value, logs are printed from the beginning.
The size of the generated logs is slightly greater than the value of MRT_LOG_FILE_SIZE.
Example:
export MRT_LOG_FILE_SIZE=100kb
MRT_LOG_PATH
Specifies the output path of runtime O&M logs. If the environment variable is not set or the path fails to be set, O&M logs are printed to stdout (standard output) or stderr (standard error) by default.
Example:
export MRT_LOG_PATH=/home/cangjie/runtime/runtime_log.txt
MRT_LOG_LEVEL
Specifies the minimum output level of runtime O&M logs. Logs at or above this level will be printed. The default value is e. The value range is [v|d|i|w|e|f|s]: v (VERBOSE), d (DEBUGY), i (INFO), w (WARNING), e (ERROR), f (FATAL), s (FATAL_WITHOUT_ABORT).
Example:
export MRT_LOG_LEVEL=v
MRT_REPORT
Specifies the output path of runtime GC logs. If the environment variable is not set or the path fails to be set, the logs are not printed by default.
Example:
export MRT_REPORT=/home/cangjie/runtime/gc_log.txt
MRT_LOG_CJTHREAD
Specifies the output path of cjthread logs. If the environment variable is not set or the path fails to be set, the logs are not printed by default.
Example:
export MRT_LOG_CJTHREAD=/home/cangjie/runtime/cjthread_log.txt
cjHeapDumpOnOOM
Specifies whether to output a heap snapshot file after a heap overflow occurs. By default, this function is disabled. The value range is [on|off]. If the value is on, the function is enabled. If the value is off or other values, the function is disabled.
Example:
export cjHeapDumpOnOOM=on
cjHeapDumpLog
Specifies the path of an output heap snapshot file. The specified path must exist and the application executor must have the read and write permissions on the path. If it is not specified, the heap snapshot file is exported to the current execution directory.
Example:
export cjHeapDumpLog=/home/cangjie
Optional Configuration for Runtime Environment
MRT_STACK_CHECK
Enables the native stack overflow check. This function is disabled by default and supports the values 1, true, or TRUE to enable it.
Example:
export MRT_STACK_CHECK=true
CJ_SOF_SIZE
When StackOverflowError occurs, the exception stack is automatically folded to facilitate reading. The default number of stack frames after folding is 32. You can set this environment variable to control the length of the folded stack. The value can be an integer within the int range.
CJ_SOF_SIZE = 0: prints the entire call stack.
CJ_SOF_SIZE < 0: starts printing from the bottom of the stack for the number of frames set by the environment variable.
CJ_SOF_SIZE > 0: starts printing from the top of the stack for the number of frames set by the environment variable.
If CJ_SOF_SIZE is not configured, the default is to print 32 layers of the call stack starting from the top.
Example:
export CJ_SOF_SIZE=30
Keywords
Keywords are special character strings that cannot be used as identifiers. The following table lists the Cangjie keywords.
| Keyword | Keyword | Keyword |
|---|---|---|
| as | abstract | break |
| Bool | case | catch |
| class | const | continue |
| Rune | do | else |
| enum | extend | for |
| func | false | finally |
| foreign | Float16 | Float32 |
| Float64 | if | in |
| is | init | import |
| interface | Int8 | Int16 |
| Int32 | Int64 | IntNative |
| let | mut | main |
| macro | match | Nothing |
| open | operator | override |
| prop | public | package |
| private | protected | quote |
| redef | return | spawn |
| super | static | struct |
| synchronized | try | this |
| true | type | throw |
| This | unsafe | Unit |
| UInt8 | UInt16 | UInt32 |
| UInt64 | UIntNative | var |
| VArray | where | while |
Operators
The table below lists all the operators supported by Cangjie, along with their precedence and associativity. A smaller value in the Precedence column indicates a higher priority for the corresponding operator.
| Operator | Precedence | Description | Example | Associativity |
|---|---|---|---|---|
@ | 0 | Macro call | @id | Right |
. | 1 | Member access | expr.id | Left |
[] | 1 | Index | expr[expr] | Left |
() | 1 | Function call | expr(expr) | Left |
++ | 2 | Auto increment | var++ | None |
-- | 2 | Auto decrement | var-- | None |
? | 2 | Question mark | expr?.id, expr?[expr], expr?(expr), expr?{expr} | None |
! | 3 | Bitwise NOT, logical NOT | !expr | Right |
- | 3 | Unary minus sign | -expr | Right |
** | 4 | Exponentiation | expr ** expr | Right |
*, / | 5 | Multiplication, division | expr * expr, expr / expr | Left |
% | 5 | Modulo | expr % expr | Left |
+, - | 6 | Addition, subtraction | expr + expr, expr - expr | Left |
<< | 7 | Bitwise left shift | expr << expr | Left |
>> | 7 | Bitwise right shift | expr >> expr | Left |
.. | 8 | Range operator | expr..expr | None |
..= | 8 | Range operator with step | expr..=expr | None |
< | 9 | Less than | expr < expr | None |
<= | 9 | Less than or equal to | expr <= expr | None |
> | 9 | Greater than | expr > expr | None |
>= | 9 | Greater than or equal to | expr >= expr | None |
is | 9 | Type check | expr is Type | None |
as | 9 | Type conversion | expr as Type | None |
== | 10 | Equality | expr == expr | None |
!= | 10 | Inequality | expr != expr | None |
& | 11 | Bitwise AND | expr & expr | Left |
^ | 12 | Bitwise XOR | expr ^ expr | Left |
| | 13 | Bitwise OR | expr | expr | Left |
&& | 14 | Logical AND | expr && expr | Left |
|| | 15 | Logical OR | expr || expr | Left |
?? | 16 | Coalescing operator | expr ?? expr | Right |
|> | 17 | Pipeline operator | id |> expr | Left |
~> | 17 | Composition operator | expr ~> expr | Left |
= | 18 | Assignment | id = expr | None |
**= | 18 | Compound operator | id **= expr | None |
*= | 18 | Compound operator | id *= expr | None |
/= | 18 | Compound operator | id /= expr | None |
%= | 18 | Compound operator | id %= expr | None |
+= | 18 | Compound operator | id += expr | None |
-= | 18 | Compound operator | id -= expr | None |
<<= | 18 | Compound operator | id <<= expr | None |
>>= | 18 | Compound operator | id >>= expr | None |
&= | 18 | Compound operator | id &= expr | None |
^= | 18 | Compound operator | id ^= expr | None |
|= | 18 | Compound operator | id |= expr | None |
&&= | 18 | Compound operator | id &&= expr | None |
||= | 18 | Compound operator | id ||= expr | None |
Operator Functions
The following table lists all operator functions supported by Cangjie.
| Operator Function | Function Signature | Example |
|---|---|---|
[] (Index value) | operator func [](index1: T1, index2: T2, ...): R | this[index1, index2, ...] |
[] (Index assignment) | operator func [](index1: T1, index2: T2, ..., value!: TN): R | this[index1, index2, ...] = value |
() | operator func ()(param1: T1, param2: T2, ...): R | this(param1, param2, ...) |
! | operator func !(): R | !this |
** | operator func **(other: T): R | this ** other |
* | operator func *(other: T): R | this * other |
/ | operator func /(other: T): R | this / other |
% | operator func %(other: T): R | this % other |
+ | operator func +(other: T): R | this + other |
- | operator func -(other: T): R | this - other |
<< | operator func <<(other: T): R | this << other |
>> | operator func >>(other: T): R | this >> other |
< | operator func <(other: T): R | this < other |
<= | operator func <=(other: T): R | this <= other |
> | operator func >(other: T): R | this > other |
>= | operator func >=(other: T): R | this >= other |
== | operator func ==(other: T): R | this == other |
!= | operator func !=(other: T): R | this != other |
& | operator func &(other: T): R | this & other |
^ | operator func ^(other: T): R | this ^ other |
| | operator func |(other: T): R | this | other |
TokenKind Type
public enum TokenKind <: ToString {
DOT| /* "." */
COMMA| /* "," */
LPAREN| /* "(" */
RPAREN| /* ")" */
LSQUARE| /* "[" */
RSQUARE| /* "]" */
LCURL| /* "{" */
RCURL| /* "}" */
EXP| /* "**" */
MUL| /* "*" */
MOD| /* "%" */
DIV| /* "/" */
ADD| /* "+" */
SUB| /* "-" */
INCR| /* "++" */
DECR| /* "--" */
AND| /* "&&" */
OR| /* "||" */
COALESCING| /* "??" */
PIPELINE| /* "|>" */
COMPOSITION| /* "~>" */
NOT| /* "!" */
BITAND| /* "&" */
BITOR| /* "|" */
BITXOR| /* "^" */
BITNOT| /* "~" */
LSHIFT| /* "<<" */
RSHIFT| /* ">>" */
COLON| /* ":" */
SEMI| /* ";" */
ASSIGN| /* "=" */
ADD_ASSIGN| /* "+=" */
SUB_ASSIGN| /* "-=" */
MUL_ASSIGN| /* "*=" */
EXP_ASSIGN| /* "**=" */
DIV_ASSIGN| /* "/=" */
MOD_ASSIGN| /* "%=" */
AND_ASSIGN| /* "&&=" */
OR_ASSIGN| /* "||=" */
BITAND_ASSIGN| /* "&=" */
BITOR_ASSIGN| /* "|=" */
BITXOR_ASSIGN| /* "^=" */
LSHIFT_ASSIGN| /* "<<=" */
RSHIFT_ASSIGN| /* ">>=" */
ARROW| /* "->" */
BACKARROW| /* "<-" */
DOUBLE_ARROW| /* "=>" */
RANGEOP| /* ".." */
CLOSEDRANGEOP| /* "..=" */
ELLIPSIS| /* "..." */
HASH| /* "#" */
AT| /* "@" */
QUEST| /* "?" */
LT| /* "<" */
GT| /* ">" */
LE| /* "<=" */
GE| /* ">=" */
IS| /* "is" */
AS| /* "as" */
NOTEQ| /* "!=" */
EQUAL| /* "==" */
WILDCARD| /* "_" */
INT8| /* "Int8" */
INT16| /* "Int16" */
INT32| /* "Int32" */
INT64| /* "Int64" */
INTNATIVE| /* "IntNative" */
UINT8| /* "UInt8" */
UINT16| /* "UInt16" */
UINT32| /* "UInt32" */
UINT64| /* "UInt64" */
UINTNATIVE| /* "UIntNative" */
FLOAT16| /* "Float16" */
FLOAT32| /* "Float32" */
FLOAT64| /* "Float64" */
RUNE| /* "Rune" */
BOOLEAN| /* "Bool" */
NOTHING| /* "Nothing" */
UNIT| /* "Unit" */
STRUCT| /* "struct" */
ENUM| /* "enum" */
CFUNC| /* "CFunc" */
VARRAY| /* "VArray" */
THISTYPE| /* "This" */
PACKAGE| /* "package" */
IMPORT| /* "import" */
CLASS| /* "class" */
INTERFACE| /* "interface" */
FUNC| /* "func" */
MACRO| /* "macro" */
QUOTE| /* "quote" */
DOLLAR| /* "$" */
LET| /* "let" */
VAR| /* "var" */
CONST| /* "const" */
TYPE| /* "type" */
INIT| /* "init" */
THIS| /* "this" */
SUPER| /* "super" */
IF| /* "if" */
ELSE| /* "else" */
CASE| /* "case" */
TRY| /* "try" */
CATCH| /* "catch" */
FINALLY| /* "finally" */
FOR| /* "for" */
DO| /* "do" */
WHILE| /* "while" */
THROW| /* "throw" */
RETURN| /* "return" */
CONTINUE| /* "continue" */
BREAK| /* "break" */
IN| /* "in" */
NOT_IN| /* "!in" */
MATCH| /* "match" */
FROM| /* "from" */
WHERE| /* "where" */
EXTEND| /* "extend" */
WITH| /* "with" */
PROP| /* "prop" */
STATIC| /* "static" */
PUBLIC| /* "public" */
PRIVATE| /* "private" */
PROTECTED| /* "protected" */
OVERRIDE| /* "override" */
REDEF| /* "redef" */
ABSTRACT| /* "abstract" */
SEALED| /* "sealed" */
OPEN| /* "open" */
FOREIGN| /* "foreign" */
INOUT| /* "inout" */
MUT| /* "mut" */
UNSAFE| /* "unsafe" */
OPERATOR| /* "operator" */
SPAWN| /* "spawn" */
SYNCHRONIZED| /* "synchronized */
UPPERBOUND| /* "<:" */
MAIN| /* "main" */
IDENTIFIER| /* "x" */
PACKAGE_IDENTIFIER| /* "x-y" */
INTEGER_LITERAL| /* e.g. "1" */
RUNE_BYTE_LITERAL| /* e.g. "b'x'" */
FLOAT_LITERAL| /* e.g. "'1.0'" */
COMMENT| /* e.g. "//xx" */
NL| /* newline */
END| /* end of file */
SENTINEL| /* ";" */
RUNE_LITERAL| /* e.g. "r'x'" */
STRING_LITERAL| /* e.g. ""xx"" */
JSTRING_LITERAL| /* e.g. "J"xx"" */
MULTILINE_STRING| /* e.g. """"aaa"""" */
MULTILINE_RAW_STRING| /* e.g. "#"aaa"#" */
BOOL_LITERAL| /* "true" or "false" */
UNIT_LITERAL| /* "()" */
DOLLAR_IDENTIFIER| /* e.g. "$x" */
ANNOTATION| /* e.g. "@When" */
ILLEGAL
}
Cangjie Programming Language Library API
The Cangjie programming language library provides the std module (standard library module) and some common extension modules. Each module contains several packages that provide specific and rich functions related to the module.
The standard library provides developers with the most common APIs, including input and output functions, basic data structures and algorithms, and date and time representation. The extension library focuses on a specific field. For example, the compress module provides compression and decompression capabilities, the crypto module provides encryption and decryption capabilities, and the net module provides efficient network protocol parsing and network communication capabilities.
Both the standard library and the official extension library comply with the Cangjie programming specifications as well as official standards in terms of function, performance, and security.
Note:
- The standard library and official extension library are released with the Cangjie compiler and toolchain and do not need to be downloaded separately.
- According to the subsequent evolution plan, the extension library may be separated from the Cangjie compiler and tool chain release and placed in a dedicated repository for management.
Usage Description
In the Cangjie programming language, a package is the minimum unit for compilation. Each package can output products such as AST files, static library files, and dynamic library files. A package can define subpackages to form a tree structure. A package without a parent package is called a root package. The entire tree consisting of the root package and its subpackages (including the subpackages of the subpackages) is called a module. The name of a module is the same as that of the root package. A module is the minimum unit released by a third-party developer.
The rules for importing packages are as follows:
-
A top-level declaration or definition in a package can be imported. The syntax is as follows:
import fullPackageName.itemNamefullPackageName indicates the full path package name, and itemName indicates the declaration name. For example:
import std.collection.ArrayList -
If more than one itemName to be imported belong to the same fullPackageName, run the following command:
import fullPackageName.{itemName[, itemName]*}For example:
import std.collection.{ArrayList, HashMap} -
All public-qualified top-level declarations or definitions in the fullPackageName package can also be imported. The syntax is as follows:
import fullPackageName.*For example:
import std.collection.*
Module List
Currently, the Cangjie standard library provides the following modules:
| Name | Description |
|---|---|
| std | Refers to a standard library. A standard library refers to a group of functions, classes, and structs predefined in a programming language and aims to provide common functions and tools for developers to compile programs more quickly and efficiently. |
| compress | Provides the compression and decompression functions. |
| crypto | Provides the security encryption capability. |
| encoding | Provides the character encoding and decoding capabilities. |
| fuzz | Provides the fuzzing capability based on coverage feedback. |
| log | Provides log recording capabilities. |
| net | Provides capabilities related to network communication. |
| serialization | Provides the serialization and deserialization capabilities. |
std Module
Note:
The STD module cannot be directly imported through the import std command. Otherwise, an error indicating that the STD package cannot be found is reported during compilation. (error: can not find package 'std'). You are advised to import the std subpackage to use the std module.
Function Description
The std module refers to a standard library. In programming languages, a standard library is a group of predefined functions, classes, and structs. It is intended to provide commonly used functionality and tools so that developers can compile programs more quickly and efficiently.
Capabilities provided by the Cangjie standard library include but are not limited to the following:
- I/O: console I/O and file I/O;
- data structures: arrays, linked lists, and hash tables;
- algorithms: sorting, summation, exponentiation, and logarithm;
- date and time: obtaining time, formatting time, and setting scheduled tasks; and
- concurrent programming: locks, atomic operations, and the like.
The Cangjie standard library has three features:
- Ease of use: The standard library is released with the compiler and tool chain. You do not need to download them separately.
- Function universality: The standard library provides some commonly-used library capabilities so that you can solve most basic problems.
- Quality benchmark: The standard library aims to set examples and benchmarks for other Cangjie libraries in terms of performance and code style.
Packages of the std Module
The std module provides the following packages:
| Name | Description |
|---|---|
| core | Specifies the core package of the standard library and provides fundamental APIs for Cangjie programming. |
| argopt | Provides capabilities for parsing parameter names and values from command line parameter strings. |
| ast | Contains the syntax parser of Cangjie source code and Cangjie syntax tree nodes, and provides syntactic parsing functions. |
| binary | Provides interfaces for converting and reversing the endianness of basic data types and binary byte arrays. |
| collection | Provides efficient implementations of commonly used data structures, definitions of related abstract interfaces, and functions in the collection type. |
| collection.concurrent | Provides implementations of the concurrent collection type. |
| console | Provides methods for interaction with standard input, standard output, and standard errors. |
| convert | Provides a series of Convert functions for converting strings into specific types. |
| crypto.cipher | Provides common APIs for symmetric encryption and decryption. |
| crypto.digest | Provides common interfaces for digest algorithms, including MD5, SHA1, SHA224, SHA256, SHA384, SHA512, HMAC, and SM3. |
| database.sql | Provides interfaces for access to Cangjie databases. |
| ffi.python | Provides the interoperability between Cangjie and Python for compatibility with powerful computing and AI ecosystems. |
| format | Provides the formatting capability for converting Cangjie instances into formatted strings. |
| fs | Provides functions for operations with files, folders, paths, and file metadata. |
| io | Allows the program to exchange data with external devices. |
| log | Provides functionality of log management and printing. |
| math | Provides functionality including commonly used mathematical operations, constant definition, and floating-point number processing. |
| math.numeric | Extends the expressible range of basic types. |
| objectpool | Provides functionality of object caching and reuse. |
| os | Provides capabilities of obtaining information related to current process of the OR operation (such as process parameters, environment variables, and directory information), registering callback functions, and exiting the current process. |
| os.posix | Adapts to POSIX interfaces. |
| os.process | Provides Process operation interfaces, including process creation, standard flow obtaining, process waiting, and process information querying. |
| overflow | Provides overflow processing capabilities. |
| random | Provides the capability of generating pseudo-random numbers. |
| reflect | Provides the reflection function, enabling a running program to obtain the type information of instances and execute read, write, and call operations. |
| regex | Provides the capability of analyzing and processing text (ASCII character strings only) through regular expressions, and supports functions such as search, segmentation, replacement, and verification. |
| runtime | Interacts with the runtime environment of a program. It provides a series of functions and variables for controlling, managing, and monitoring the execution of the program. |
| socket | Provides functionality such as starting a Socket server, connecting to a Socket server, sending data, and receiving data, and is used for network communication. |
| sort | Provides sorting functions of the array type. |
| sync | Provides concurrent programming capabilities. |
| time | Provides time-related types, including date and time, time interval, monotonic time, and time zone, and provides functionality of calculation and comparison. |
| unicode | Provides the capability of processing characters according to the unicode encoding standard. |
| unittest | Compiles the unit test code of Cangjie projects and provides basic functionality such as code compilation, running, and debugging. |
| unittest.mock | Provides a mock framework for Cangjie unit tests and provides APIs for creating and configuring mock objects. These mock objects and the real objects have the same APIs. |
| unittest.testmacro | Provides macros for the unit test framework. |
| unittest.mock.mockmacro | Provides macros for the mock framework. |
| unittest.common | Provides the unit test framework with the types and common methods required by printing. |
| unittest.diff | Provides the unit test framework with APIs for printing difference comparison information. |
| unittest.prop_test | Provides the unit test framework with the types and common methods required by parameterized tests. |
std.core Package
Function Description
The core package provides some basic API capabilities applicable to Cangjie programming.
Built-in types (such as signed integer, unsigned integer, and floating-point number), common functions (such as print, println, and eprint), common interfaces (such as ToString, Hashable, Equatable, and Collection), common classes and structs (such as Array, String, and Range), and common exception classes (such as Error, Exception, and their subclasses) are provided.
Note:
The core package is imported by default.
API List
Function
| Name | Description |
|---|---|
| CJ_CORE_AddAtexitCallback(() -> Unit) | Registers an exit function executed when the current process exits. |
| CJ_CORE_ExecAtexitCallbacks() | Executes the registered exit function until the current process ends. |
| acquireArrayRawData(Array<T>) where T <: CType | Obtains an original pointer instance of data in Array |
| alignOf<T>() where T <: CType | Obtains the memory alignment value of T type. |
| eprint(String, Bool) | Prints error messages. |
| eprintln(String) | Prints error messages and adds a newline character to the end of a message. |
| ifNone(Option<T>, () -> Unit) | If data of the Option.None type is input, the action function is executed. |
| ifSome(Option<T>, (T) -> Unit) | If data of the Option.Some type is input, the action function is executed. |
| print(Bool, Bool) | Outputs the string representation of data of the Bool type to the console. |
| print(Float16, Bool) | Outputs the string representation of data of the Float16 type to the console. |
| print(Float32, Bool) | Outputs the string representation of data of the Float32 type to the console. |
| print(Float64, Bool) | Outputs the string representation of data of the Float64 type to the console. |
| print(Int16, Bool) | Outputs the string representation of data of the Int16 type to the console. |
| print(Int32, Bool) | Outputs the string representation of data of the Int32 type to the console. |
| print(Int64, Bool) | Outputs the string representation of data of the Int64 type to the console. |
| print(Int8, Bool) | Outputs the string representation of data of the Int8 type to the console. |
| print(Rune, Bool) | Outputs the string representation of data of the Rune type to the console. |
| print(String, Bool) | Outputs a specified string to the console. |
| print(UInt16, Bool) | Outputs the string representation of data of the UInt16 type to the console. |
| print(UInt32, Bool) | Outputs the string representation of data of the UInt32 type to the console. |
| print(UInt64, Bool) | Outputs the string representation of data of the UInt64 type to the console. |
| print(UInt8, Bool) | Outputs the string representation of data of the UInt8 type to the console. |
| print<T>(T, Bool) where T <: ToString | Outputs the string representation of an instance of the T type to the console. |
| println() | Outputs a newline character to the standard output (stdout). |
| println(Bool) | Outputs the string representation (with a newline character at the end) of data of the Bool type to the console. |
| println(Float16) | Outputs the string representation (with a newline character at the end) of data of the Float16 type to the console. |
| println(Float32) | Outputs the string representation (with a newline character at the end) of data of the Float32 type to the console. |
| println(Float64) | Outputs the string representation (with a newline character at the end) of data of the Float64 type to the console. |
| println(Int16) | Outputs the string representation (with a newline character at the end) of data of the Int16 type to the console. |
| println(Int32) | Outputs the string representation (with a newline character at the end) of data of the Int32 type to the console. |
| println(Int64) | Outputs the string representation (with a newline character at the end) of data of the Int64 type to the console. |
| println(Int8) | Outputs the string representation (with a newline character at the end) of data of the Int8 type to the console. |
| println(Rune) | Outputs the string representation (with a newline character at the end) of data of the Rune type to the console. |
| println(String) | Outputs a specified string (with a newline character at the end) to the console. |
| println(UInt16) | Outputs the string representation (with a newline character at the end) of data of the UInt16 type to the console. |
| println(UInt32) | Outputs the string representation (with a newline character at the end) of data of the UInt32 type to the console. |
| println(UInt64) | Outputs the string representation (with a newline character at the end) of data of the UInt64 type to the console. |
| println(UInt8) | Outputs the string representation (with a newline character at the end) of data of the UInt8 type to the console. |
| println<T>(T) where T <: ToString | Outputs the string representation (with a newline character at the end) of instance of the T type to the console. |
| refEq(Object, Object) | Checks whether the memory addresses of two Object instances are the same. |
| releaseArrayRawData(CPointerHandle<T>) where T <: CType | Releases an original pointer instance obtained using acquireArrayRawData. |
| sizeOf<T>() where T <: CType | Obtains the memory space occupied by the T type. |
| zeroValue<T>() | Obtains a T-type instance that has been subject to zero initialization. |
Type Alias
| Name | Description |
|---|---|
| Byte | The Byte type is the alias of the built-in UInt8 type. |
| Int | The Int type is the alias of the built-in Int64 type. |
| UInt | The UInt type is the alias of the built-in UInt64 type. |
Built-in Type
| Name | Description |
|---|---|
| Int8 | Represents an 8-bit signed integer ranging from –2^7 to 2^7 – 1. |
| Int16 | Represents a 16-bit signed integer ranging from –2^{15} to 2^{15} – 1. |
| Int32 | Represents a 32-bit signed integer ranging from –2^{31} to 2^{31} – 1. |
| Int64 | Represents a 64-bit signed integer ranging from –2^{63} to 2^{63} – 1. |
| IntNative | Represents a platform-related signed integer with the length same as the bit width of the current system. |
| UInt8 | Represents an 8-bit unsigned integer ranging from 0 to 2^8-1. |
| UInt16 | Represents a 16-bit unsigned integer ranging from 0 to 2^{16}-1. |
| UInt32 | Represents a 32-bit unsigned integer ranging from 0 to 2^{32}-1. |
| UInt64 | Represents a 64-bit unsigned integer ranging from 0 to 2^{64}-1. |
| UIntNative | Represents a platform-related unsigned integer with the length same as the bit width of the current system. |
| Float16 | Represents a 16-bit floating-point number complying with the half-precision format (binary16) specified in IEEE 754. |
| Float32 | Represents a 32-bit floating-point number complying with the single-precision format (binary32) specified in IEEE 754. |
| Float64 | Represents a 64-bit floating-point number complying with the double-precision format (binary64) specified in IEEE 754. |
| Bool | Represents the Boolean type. The value options are true and false. |
| Rune | Represents the characters in the Unicode character set. |
| Unit | Represents the type of an expression that concerns only side effects but not values in the Cangjie language. |
| CPointer<T> | Indicates the pointer to the instance of the T type. It corresponds to T* of the C language in the scenario where the C language is used. |
| CString | Represents the C-style string, which is used in the scenario where the C language is used. |
Interface
| Name | Description |
|---|---|
| Any | Specifies the parent type of all types. By default, all interface types inherit Any and all non-interface types implement Any. |
| RuneExtension | Implements extension methods for the Rune type. It does not contain any attributes or methods. |
| Hasher | Processes combined hash operations. |
| ThreadContext | Specifies a Cangjie thread context interface. |
| ByteExtension | Implements extension methods for the Byte type. It does not contain any attributes or methods. |
| Countable<T> | Indicates a countable type. |
| Collection<T> | Indicates a collection. Generally, a container type should implement this interface. |
| FloatToBits | Supports conversion of the Float type to integer values represented by bits. |
| Less<T> | Supports calculations with the result indicating whether one instance is less than the other instance or not. |
| Greater<T> | Supports calculations with the result indicating whether one instance is greater than the other instance or not. |
| LessOrEqual<T> | Supports calculations with the result indicating whether one instance is less than or equal to the other instance or not. |
| GreaterOrEqual<T> | Supports calculations with the result indicating whether one instance is greater than or equal to the other instance or not. |
| Comparable<T> | Indicates comparison operation. This interface is a collection of interfaces indicating equal to, less than, greater than, less than or equal to, and greater than or equal to. |
| Equal<T> | Supports equality check. |
| NotEqual<T> | Supports inequality check. |
| Equatable<T> | Specifies a collection of the equality check and inequality check interfaces. |
| Hashable | Calculates hash values. |
| Iterable<E> | Supports iteration. A type (usually the container type) that implements this interface can be iterated in the for-in statement. Alternatively, such type can be iterated by calling the next function based on the corresponding iterator type instance. |
| Resource | Manages resources, such as closing and releasing memory and handles. |
| ToString | Provides the string representation of a specific type. |
| CType | Indicates the interface that supports interoperability with the C language. |
Class
| Name | Description |
|---|---|
| ArrayIterator<T> | Specifies an array iterator. For details about its functions, see the description of Iterable and Iterator. |
| Box<T> | Provides the capability of adding a layer of class encapsulation to other types. |
| Future<T> | Represents a Cangjie thread task. It can be used to obtain the calculation result of a Cangjie thread and send a cancellation signal to the Cangjie thread. |
| Iterator<T> | Indicates an iterator and provides the next method to support iterative traversal of members in a container. |
| Object | Constructs an object instance. |
| RangeIterator<T> <: Iterator<T> where T <: Countable<T> & Comparable<T> & Equatable<T> | Specifies an iterator of the Range type. For details about its functions, see the description of Iterable and Iterator. |
| StackTraceElement | Indicates the detailed information about an exception stack, including the class name, function name, file name, and line number involved in the exception. |
| StringBuilder | Constructs strings. |
| Thread | Represents a Cangjie class, which can be used to obtain thread IDs and names, check whether a thread receives any cancellation request, and register processing functions for exceptions not handled by threads. |
| ThreadLocal<T> | Indicates a Cangjie thread local variable. |
Enumeration
| Name | Description |
|---|---|
| AnnotationKind | Indicates the location that the custom annotation is expected to support. |
| Endian | Indicates the endianness of the running platform, which can be big endian or little endian. |
| Ordering | Indicates a comparison result and includes three situations: less than, greater than, and equal to. |
| Option<T> | Encapsulates the T type, indicating that the type may or may not have a value. |
Struct
| Name | Description |
|---|---|
| Array<T> | Specifies a Cangjie array type used to represent an ordered sequence consisting of elements of a single type. |
| CPointerHandle<T> where T <: CType | Indicates the original pointer of Array. Generic parameters in this type must meet the CType constraint. |
| CPointerResource<T> where T <: CType | Indicates the resource management type corresponding to CPointer. Instances of this type can be obtained by using the member function asResource of CPointer. |
| CStringResource | Indicates the resource management type corresponding to CString. Instances of this type can be obtained by using the member function asResource of CString. |
| DefaultHasher | Provides the default hash algorithm implementation. |
| LibC | Provides C APIs that are frequently used in Cangjie, such as APIs for applying for and releasing CType instances on the heap. |
| Range<T> where T <: Countable<T> & Comparable<T> & Equatable<T> | Indicates an interval type used to indicate a sequence of T with a fixed range and step. T must be countable and ordered. |
| String | Indicates a Cangjie string with a series of string operations provided, such as construction, search, and concatenation. |
Exception Class
| Name | Description |
|---|---|
| Error | Specifies the parent class of all error classes. This class cannot be inherited or initialized, but can be captured. |
| InternalError | Indicates the internal error class. This class cannot be initialized but can be captured. |
| OutOfMemoryError | Indicates the out-of-memory error class. This class cannot be inherited or initialized, but can be captured. |
| StackOverflowError | Indicates the stack overflow error class. This class cannot be inherited or initialized, but can be captured. |
| Exception | Specifies the parent class of all exception classes. |
| SpawnException | Indicates the thread exception class, indicating that an exception occurs during thread processing. |
| IllegalArgumentException | Indicates the exception class that is thrown when a parameter is invalid. |
| IllegalFormatException | Indicates the exception class that is thrown when the format of a variable is invalid or not standard. |
| IllegalStateException | Indicates the exception class that is thrown when a status is invalid. |
| IndexOutOfBoundsException | Indicates the exception class that is thrown when an index is out of range. |
| NegativeArraySizeException | Indicates an exception class that is thrown when the array size is negative. |
| NoneValueException | Indicates the exception class that is thrown (usually in the getOrThrow function) when the value of the Option<T> instance is None. |
| UnsupportedException | Indicates the exception class that is thrown when a function is not supported. |
| OverflowException | Indicates the exception class this is thrown when overflow occurs in an arithmetic operation. |
| IllegalMemoryException | Indicates the exception class which is thrown when a memory operation error occurs. |
| ArithmeticException | Indicates the arithmetic exception class which is thrown when an arithmetic exception occurs. |
Function
func CJ_CORE_AddAtexitCallback(() -> Unit)
public func CJ_CORE_AddAtexitCallback(callback: () -> Unit): Unit
Description: Registers an exit function executed when the current process exits.
Note:
It is advised to use the Process.atexit function in the OS library only when a process management framework needs to be created.
Parameters:
- callback: () ->Unit: exit function to be registered
func CJ_CORE_ExecAtexitCallbacks()
public func CJ_CORE_ExecAtexitCallbacks(): Unit
Description: Executes the registered exit function until the current process ends.
Note:
It is advised to use the Process.exit function in the OS library only when a process management framework needs to be created.
func acquireArrayRawData<T>(Array<T>) where T <: CType
public unsafe func acquireArrayRawData<T>(arr: Array<T>): CPointerHandle<T> where T <: CType
Description: Obtains an original pointer instance of data in Array<T>, where T must meet the CType constraint.
Note:
After the pointer is used, use the releaseArrayRawData function to release the pointer in time. Only simple logic such as foreign C function call is supported between pointer obtaining and release. Do not construct Cangjie objects such as CString. Otherwise, unexpected problems may occur.
Parameters:
- arr: Array<T>: array in which an original pointer is to be obtained
Returns:
- CPointerHandle<T>: original pointer instance of the array
func alignOf<T>() where T <: CType
public func alignOf<T>(): UIntNative where T <: CType
Description: Obtains the memory alignment value of the T type.
Returns:
- UIntNative: number of bytes for memory alignment of the T type
func eprint(String, Bool)
public func eprint(str: String, flush!: Bool = true): Unit
Description: Prints error messages.
If an exception is thrown, the messages are printed to the standard error text stream (stderr) instead of standard output (stdout).
Parameters:
- str: String: string to be output
- flush!: Bool: whether to clear the cache; true: yes, false (default): no
func eprintln(String)
public func eprintln(str: String): Unit
Description: Prints error messages and adds a newline character to the end of a message.
If an exception is thrown, the messages are printed to the standard error text stream (stderr) instead of standard output (stdout).
Parameters:
- str: String: string to be output
func ifNone<T>(Option<T>, () -> Unit)
public func ifNone<T>(o: Option<T>, action: () -> Unit): Unit
Description: If data of the Option.None type is input, the action function is executed.
Parameters:
- o: Option<T>: instance of the Option<T> type to be checked for whether it is Option.None
- action: () ->Unit: function to be executed
func ifSome<T>(Option<T>, (T) -> Unit)
public func ifSome<T>(o: Option<T>, action: (T) -> Unit): Unit
Description: If data of the Option.Some type is input, the action function is executed.
Parameters:
- o: Option<T>: instance of the Option<T> type to be checked whether it is of the Option.Some type. The encapsulated instance of the
Ttype is used as the input of the action function. - action: (T) ->Unit: function to be executed
func print(Bool, Bool)
public func print(b: Bool, flush!: Bool = false): Unit
Description: Outputs the string representation of data of the Bool type to the console.
Parameters:
- b: Bool: data of the Bool type to be output
- flush!: Bool: whether to clear the cache; true: yes, false (default): no
func print(Float16, Bool)
public func print(f: Float16, flush!: Bool = false): Unit
Description: Outputs the string representation of data of the Float16 type to the console.
Parameters:
- f: Float16: data of the Float16 type to be output
- flush!: Bool: whether to clear the cache; true: yes, false (default): no
func print(Float32, Bool)
public func print(f: Float32, flush!: Bool = false): Unit
Description: Outputs the string representation of data of the Float32 type to the console.
Parameters:
- f: Float32: data of the Float32 type to be output
- flush!: Bool: whether to clear the cache; true: yes, false (default): no
func print(Float64, Bool)
public func print(f: Float64, flush!: Bool = false): Unit
Description: Outputs the string representation of data of the Float64 type to the console.
Parameters:
- f: Float64: data of the Float64 type to be output
- flush!: Bool: whether to clear the cache; true: yes, false (default): no
func print(Int16, Bool)
public func print(i: Int16, flush!: Bool = false): Unit
Description: Outputs the string representation of data of the Int16 type to the console.
Parameters:
- i: Int16: data of the Int16 type to be output
- flush!: Bool: whether to clear the cache; true: yes, false (default): no
func print(Int32, Bool)
public func print(i: Int32, flush!: Bool = false): Unit
Description: Outputs the string representation of data of the Int32 type to the console.
Parameters:
- i: Int32: data of the Int32 type to be output
- flush!: Bool: whether to clear the cache; true: yes, false (default): no
func print(Int64, Bool)
public func print(i: Int64, flush!: Bool = false): Unit
Description: Outputs the string representation of data of the Int64 type to the console.
Parameters:
- i: Int64: data of the Int64 type to be output
- flush!: Bool: whether to clear the cache; true: yes, false (default): no
func print(Int8, Bool)
public func print(i: Int8, flush!: Bool = false): Unit
Description: Outputs the string representation of data of the Int8 type to the console.
Parameters:
- i: Int8: data of the Int8 type to be output
- flush!: Bool: whether to clear the cache; true: yes, false (default): no
func print(Rune, Bool)
public func print(c: Rune, flush!: Bool = false): Unit
Description: Outputs the string representation of data of the Rune type to the console.
Parameters:
- c: Rune: data of the Rune type to be output
- flush!: Bool: whether to clear the cache; true: yes, false (default): no
func print(String, Bool)
public func print(str: String, flush!: Bool = false): Unit
Description: Outputs a specified string to the console.
Parameters:
- str: String: string to be output
- flush!: Bool: whether to clear the cache; true: yes, false (default): no
func print(UInt16, Bool)
public func print(i: UInt16, flush!: Bool = false): Unit
Description: Outputs the string representation of data of the UInt16 type to the console.
Parameters:
- i: UInt16: data of the UInt16 type to be output
- flush!: Bool: whether to clear the cache; true: yes, false (default): no
func print(UInt32, Bool)
public func print(i: UInt32, flush!: Bool = false): Unit
Description: Outputs the string representation of data of the UInt32 type to the console.
Parameters:
- i: UInt32: data of the UInt32 type to be output
- flush!: Bool: whether to clear the cache; true: yes, false (default): no
func print(UInt64, Bool)
public func print(i: UInt64, flush!: Bool = false): Unit
Description: Outputs the string representation of data of the UInt64 type to the console.
Parameters:
- i: UInt64: data of the UInt64 type to be output
- flush!: Bool: whether to clear the cache; true: yes, false (default): no
func print(UInt8, Bool)
public func print(i: UInt8, flush!: Bool = false): Unit
Description: Outputs the string representation of data of the UInt8 type to the console.
Parameters:
- i: UInt8: data of the UInt8 type to be output.
- flush!: Bool: whether to clear the cache; true: yes, false (default): no
func print<T>(T, Bool) where T <: ToString
public func print<T>(arg: T, flush!: Bool = false): Unit where T <: ToString
Description: Outputs the string representation of an instance of the T type to the console.
Parameters:
- arg: T: data to be output. Types that implement the ToString interface are supported.
- flush!: Bool: whether to clear the cache; true: yes, false (default): no
func println()
public func println(): Unit
Description: Outputs a newline character to the standard output (stdout).
func println(Bool)
public func println(b: Bool): Unit
Description: Outputs the string representation (with a newline character at the end) of data of the Bool type to the console.
Parameters:
func println(Float16)
public func println(f: Float16): Unit
Description: Outputs the string representation (with a newline character at the end) of data of the Float16 type to the console.
Parameters:
func println(Float32)
public func println(f: Float32): Unit
Description: Outputs the string representation (with a newline character at the end) of data of the Float32 type to the console.
Parameters:
func println(Float64)
public func println(f: Float64): Unit
Description: Outputs the string representation (with a newline character at the end) of data of the Float64 type to the console.
Parameters:
func println(Int16)
public func println(i: Int16): Unit
Description: Outputs the string representation (with a newline character at the end) of data of the Int16 type to the console.
Parameters:
func println(Int32)
public func println(i: Int32): Unit
Description: Outputs the string representation (with a newline character at the end) of data of the Int32 type to the console.
Parameters:
func println(Int64)
public func println(i: Int64): Unit
Description: Outputs the string representation (with a newline character at the end) of data of the Int64 type to the console.
Parameters:
func println(Int8)
public func println(i: Int8): Unit
Description: Outputs the string representation (with a newline character at the end) of data of the Int8 type to the console.
Parameters:
func println(Rune)
public func println(c: Rune): Unit
Description: Outputs the string representation (with a newline character at the end) of data of the Rune type to the console.
Parameters:
func println(String)
public func println(str: String): Unit
Description: Outputs a specified string (with a newline character at the end) to the console.
Parameters:
- str: String: string to be output
func println(UInt16)
public func println(i: UInt16): Unit
Description: Outputs the string representation (with a newline character at the end) of data of the UInt16 type to the console.
Parameters:
func println(UInt32)
public func println(i: UInt32): Unit
Description: Outputs the string representation (with a newline character at the end) of data of the UInt32 type to the console.
Parameters:
func println(UInt64)
public func println(i: UInt64): Unit
Description: Outputs the string representation (with a newline character at the end) of data of the UInt64 type to the console.
Parameters:
func println(UInt8)
public func println(i: UInt8): Unit
Description: Outputs the string representation (with a newline character at the end) of data of the UInt8 type to the console.
Parameters:
func println<T>(T) where T <: ToString
public func println<T>(arg: T): Unit where T <: ToString
Description: Outputs the string representation (with a newline character at the end) of instance of the T type to the console.
Parameters:
- arg: T: data to be output. Types that implement the ToString interface are supported.
func refEq(Object, Object)
public func refEq(a: Object, b: Object): Bool
Description: Checks whether the memory addresses of two Object instances are the same.
Parameters:
Returns:
- Bool: If the two memory addresses are the same, true is returned. Otherwise, false is returned.
func releaseArrayRawData<T>(CPointerHandle<T>) where T <: CType
public unsafe func releaseArrayRawData<T>(handle: CPointerHandle<T>): Unit where T <: CType
Description: Releases an original pointer instance obtained using acquireArrayRawData.
Parameters:
- handle: CPointerHandle<T>: pointer instance to be released
func sizeOf<T>() where T <: CType
public func sizeOf<T>(): UIntNative where T <: CType
Description: Obtains the memory space occupied by the T type.
Returns:
- UIntNative: number of bytes in the memory space occupied by the T type
func zeroValue<T>()
public unsafe func zeroValue<T>(): T
Description: Obtains a T-type instance that has been subject to zero initialization.
Note:
The instance must be assigned a normal initialized value before being used. Otherwise, the program crashes.
Returns:
- T: T-type instance that has been subject to zero initialization
Type Alias
type Byte
public type Byte = UInt8
Description: Specifies the alias of the built-in UInt8 type.
type Int
public type Int = Int64
Description: Specifies the alias of the built-in Int64 type.
type UInt
public type UInt = UInt64
Description: Specifies the alias of the built-in UInt64 type.
Built-in Type
Bool
Description: Represents the Boolean type. The value options are true and false.
extend Bool <: Equatable<Bool>
extend Bool <: Equatable<Bool>
Description: Extends the Equatable<Bool> interface for the Bool type to support the equality check operation.
Parent Type:
extend Bool <: Hashable
extend Bool <: Hashable
Description: Extends the Hashable interface for the Bool type to support hash value calculation.
Parent Type:
func hashCode()
public func hashCode(): Int64
Description: Obtains a hash value.
Returns:
- Int64: hash value
extend Bool <: ToString
extend Bool <: ToString
Description: Extends the ToString interface for the Bool type to convert it to the String type.
Parent Type:
func toString()
public func toString(): String
Description: Converts the value of Bool to a string that can be output.
Returns:
- String: string after conversion
CPointer<T>
Description: Indicates the pointer to the instance of the T type. It corresponds to T* of the C language in the scenario where the C language is used.
T must comply with the CType constraint.
The CPointer type must meet the following requirements:
- Its size and alignment depend on the platform.
- The addition and subtraction operations and memory read and write operations need to be performed in an unsafe context.
- The CPointer<T1> can be forcibly converted to the CPointer<T2> type in an unsafe context.
extend<T> CPointer<T>
extend<T> CPointer<T>
Description: Extends some necessary pointer-related interfaces (including null check and data read and write interfaces) for CPointer<T>.
The generic T indicates the pointer type and meets the CType constraint. Operations on CPointer must be performed in an unsafe context.
func asResource()
public func asResource(): CPointerResource<T>
Description: Obtains the CPointerResource instance of the pointer. The instance can automatically release resources in the try-with-resource syntax context.
Returns:
- CPointerResource<T>: CPointerResource instance corresponding to the current pointer
func isNotNull()
public func isNotNull(): Bool
Description: Checks whether a pointer is not null.
Returns:
- Bool: If the pointer is not null, true is returned. Otherwise, false is returned.
func isNull()
public func isNull(): Bool
Description: Checks whether a pointer is null.
Returns:
- Bool: If the pointer is null, true is returned. Otherwise, false is returned.
func read()
public unsafe func read(): T
Description: Reads the first piece of data. The pointer must be valid to prevent undefined behaviors.
Returns:
- T: first piece of data of the object type
func read(Int64)
public unsafe func read(idx: Int64): T
Description: Reads data according to the index. The pointer must be valid to prevent undefined behaviors.
Parameters:
- idx: Int64: index of the data to be obtained
Returns:
- T: data corresponding to the index
func toUIntNative()
public func toUIntNative(): UIntNative
Description: Obtains the integer type of the pointer.
Returns:
- UIntNative: integer type of the pointer
func write(Int64, T)
public unsafe func write(idx: Int64, value: T): Unit
Description: Writes a piece of data to a specified index location. The pointer must be valid to prevent undefined behaviors.
Parameters:
- idx: Int64: specified index location
- value: T: data to be written
func write(T)
public unsafe func write(value: T): Unit
Description: Writes a piece of data which is always at the first location. The pointer must be valid to prevent undefined behaviors.
Parameters:
- value: T: data to be written
operator func +(Int64)
public unsafe operator func +(offset: Int64): CPointer<T>
Description: Moves the pointer of a CPointer object backward. This function is the same as pointer addition operation in the C language.
Parameters:
- offset: Int64: offset
Returns:
- CPointer<T>: pointer after offset
operator func -(Int64)
public unsafe operator func -(offset: Int64): CPointer<T>
Description: Moves the pointer of a CPointer object forward. This function is the same as pointer subtraction operation in the C language.
Parameters:
- offset: Int64: offset
Returns:
- CPointer<T>: pointer after offset
CString
Description: Represents the C-style string, which is used in the scenario where the C language is used.
A C-style string can be created by using the constructor of CString or mallocCString of LibC. To release the string in Cangjie, call the free method of LibC.
extend CString <: ToString
extend CString <: ToString
Description: Extends some common methods for string pointers of the CString type, including null check, length obtaining, equality check, and substring obtaining.
Parent Type:
func asResource()
public func asResource(): CStringResource
Description: Obtains the instance of the CStringResource C-type string resource type corresponding to the current CString instance.
CStringResource implements the Resource interface and can automatically release resources in the try-with-resource syntax context.
Returns:
- CStringResource: instance of the CStringResource C-type string resource type
func compare(CString)
public func compare(str: CString): Int32
Description: Compares the current string with the other string specified by str in lexicographic order. This function is the same as strcmp in the C language.
Parameters:
- str: CString: the other string to be compared with
Returns:
- Int32: If the two strings are equal, 0 is returned. If the current string is smaller than str, –1 is returned. Otherwise, 1 is returned.
Throws:
- Exception: If the two strings of the CString type to be compared contain null pointers, this exception is thrown.
func endsWith(CString)
public func endsWith(suffix: CString): Bool
Description: Checks whether a string contains a specified suffix.
Parameters:
- suffix: CString: matched string with target suffix
Returns:
- Bool: If the string contains the suffix, true is returned. If not, false is returned. Particularly, if the pointer of the original string or suffix string is null, false is returned.
func equals(CString)
public func equals(rhs: CString): Bool
Description: Checks whether two strings are equal.
Parameters:
- rhs: CString: the string to be compared with
Returns:
- Bool: If the two strings are equal, true is returned. Otherwise, false is returned.
func equalsLower(CString)
public func equalsLower(rhs: CString): Bool
Description: Checks whether two strings are equal in case-insensitive mode.
Parameters:
- rhs: CString: the string to be compared with
Returns:
- Bool: If the two strings are equal in case-insensitive mode, true is returned. Otherwise, false is returned.
func getChars()
public func getChars(): CPointer<UInt8>
Description: Obtains the pointer of the string.
Returns:
func isEmpty()
public func isEmpty(): Bool
Description: Checks whether a string is empty.
Returns:
- Bool: If the string is empty or the string pointer is null, true is returned. Otherwise, false is returned.
func isNotEmpty()
public func isNotEmpty(): Bool
Description: Checks whether a string is not empty.
Returns:
- Bool: If the string is not empty, true is returned. If the string pointer is null, false is returned.
func isNull()
public func isNull(): Bool
Description: Checks whether a string pointer is null.
Returns:
- Bool: If the string pointer is null, true is returned. Otherwise, false is returned.
func size()
public func size(): Int64
Description: Returns the length of the string. This function is the same as strlen in the C language.
Returns:
- Int64: length of the string
func startsWith(CString)
public func startsWith(prefix: CString): Bool
Description: Checks whether a string contains a specified prefix.
Parameters:
- prefix: CString: matched string with target prefix
Returns:
- Bool: If the string contains the prefix, true is returned. If not, false is returned. Particularly, if the pointer of the original string or prefix string is null, false is returned.
func subCString(UIntNative)
public func subCString(beginIndex: UIntNative): CString
Description: Truncates a substring from a specified location to the end of a string.
Note:
- This interface returns a copy of a string. After the returned substring is used, you need to manually release it.
- If the value of beginIndex is equal to the length of the string, a null pointer is returned.
Parameters:
- beginIndex: UIntNative: truncation start location. The value ranges from 0 to this.size().
Returns:
- CString: substring obtained
Throws:
- IndexOutOfBoundsException: If the value of beginIndex is greater than the length of the string, this exception is thrown.
- IllegalMemoryException: If memory allocation or copy fails, this exception is thrown.
func subCString(UIntNative, UIntNative)
public func subCString(beginIndex: UIntNative, subLen: UIntNative): CString
Description: Truncates a substring of a string with the length and start location specified.
If the end location does not fall into the length of the string, the truncation ends at the end of the string.
Note:
- This interface returns a copy of a string. After the returned substring is used, you need to manually release it.
- If the value of beginIndex is equal to the length of the string or the value of subLen is 0, a null pointer is returned.
Parameters:
- beginIndex: UIntNative: truncation start location. The value ranges from 0 to this.size().
- subLen: UIntNative: truncation length. The value ranges from 0 to UIntNative.Max.
Returns:
- CString: substring obtained
Throws:
- IndexOutOfBoundsException: If the value of beginIndex is greater than the length of the string, this exception is thrown.
- IllegalMemoryException: If memory allocation or copy fails, this exception is thrown.
func toString()
public func toString(): String
Description: Converts the CString type to the String type of Cangjie.
Returns:
- String: string after conversion
Float16
Description: Represents a 16-bit floating point number complying with the half-precision format (binary16) specified in IEEE 754.
extend Float16 <: Comparable<Float16>
extend Float16 <: Comparable<Float16>
Description: Extends the Comparable<Float16> interface for the Float16 type to support the comparison operation.
Parent Type:
func compare(Float16)
public func compare(rhs: Float16): Ordering
Description: Compares the current value of Float16 with a specified value of Float16.
Parameters:
Returns:
- Ordering: If the current value is greater than rhs, Ordering.GT is returned. If it is equal to rhs, Ordering.EQ is returned. If it is less than rhs, Ordering.LT is returned.
extend Float16 <: FloatToBits
extend Float16 <: FloatToBits
Description: Implements the FloatToBits interface for Float16 to support conversion between Float16 and UInt16.
Parent Type:
static func fromBits(UInt16)
public static func fromBits(bits: UInt16): Float16
Description: Converts a specified UInt16 number to a Float16 number.
Parameters:
- bits: UInt16: number to be converted
Returns:
- Float16: conversion result. The value is the same as that of bits.
Example:
import std.unittest.*
import std.unittest.testmacro.*
main() {
let v = Float16.fromBits(0x4A40)
@Assert(v, 12.5)
}
func toBits()
public func toBits(): UInt16
Description: Converts a specified Float16 number to a UInt16 number represented by bits.
Returns:
Example:
import std.unittest.*
import std.unittest.testmacro.*
main() {
@Assert(12.5f16.toBits(), 0x4A40)
}
extend Float16 <: Hashable
extend Float16 <: Hashable
Description: Extends the Hashable interface for the Float16 type to support hash value calculation.
Parent Type:
func hashCode()
public func hashCode(): Int64
Description: Obtains a hash value.
Returns:
- Int64: hash value
extend Float16 <: ToString
extend Float16 <: ToString
Description: Extends the ToString interface for the Float16 type to convert it to the String type.
By default, six decimal places are reserved. For other precisions, refer to extension using Formatter.
Parent Type:
func toString()
public func toString(): String
Description: Converts the value of Float16 to a string that can be output.
Returns:
- String: string after conversion
Float32
Description: Represents a 32-bit floating point number complying with the single-precision format (binary32) specified in IEEE 754.
extend Float32 <: Comparable<Float32>
extend Float32 <: Comparable<Float32>
Description: Extends the Comparable<Float32> interface for the Float32 type to support the comparison operation.
Parent Type:
func compare(Float32)
public func compare(rhs: Float32): Ordering
Description: Compares the current value of Float32 with a specified value of Float32.
Parameters:
Returns:
- Ordering: If the current value is greater than rhs, Ordering.GT is returned. If it is equal to rhs, Ordering.EQ is returned. If it is less than rhs, Ordering.LT is returned.
extend Float32 <: FloatToBits
extend Float32 <: FloatToBits
Description: Implements the FloatToBits interface for Float32 to support conversion between Float32 and UInt32.
Parent Type:
static func fromBits(UInt32)
public static func fromBits(bits: UInt32): Float32
Description: Converts a specified UInt32 number to a Float32 number.
Parameters:
- bits: UInt32: number to be converted
Returns:
- Float32: conversion result. The value is the same as that of bits.
Example:
import std.unittest.*
import std.unittest.testmacro.*
main() {
let v = Float32.fromBits(0x41480000)
@Assert(v, 12.5)
}
func toBits()
public func toBits(): UInt32
Description: Converts a specified Float32 number to a UInt32 number represented by bits.
Returns:
Example:
import std.unittest.*
import std.unittest.testmacro.*
main() {
@Assert(12.5f32.toBits(), 0x41480000)
}
extend Float32 <: Hashable
extend Float32 <: Hashable
Description: Extends the Hashable interface for the Float32 type to support hash value calculation.
Parent Type:
func hashCode()
public func hashCode(): Int64
Description: Obtains a hash value.
Returns:
- Int64: hash value
extend Float32 <: ToString
extend Float32 <: ToString
Description: Extends the ToString interface for the Float32 type to convert it to the String type.
By default, six decimal places are reserved. For other precisions, refer to extension using Formatter.
Parent Type:
func toString()
public func toString(): String
Description: Converts the value of Float32 to a string that can be output.
Returns:
- String: string after conversion
Float64
Description: Represents a 64-bit floating point number complying with the double-precision format (binary64) specified in IEEE 754.
extend Float64 <: Comparable<Float64>
extend Float64 <: Comparable<Float64>
Description: Extends the Comparable<Float64> interface for the Float64 type to support the comparison operation.
Parent Type:
func compare(Float64)
public func compare(rhs: Float64): Ordering
Description: Compares the current value of Float64 with a specified value of Float64.
Parameters:
Returns:
- Ordering: If the current value is greater than rhs, Ordering.GT is returned. If it is equal to rhs, Ordering.EQ is returned. If it is less than rhs, Ordering.LT is returned.
extend Float64 <: FloatToBits
extend Float64 <: FloatToBits
Description: Implements the FloatToBits interface for Float64 to support conversion between Float64 and UInt64.
Parent Type:
static func fromBits(UInt64)
public static func fromBits(bits: UInt64): Float64
Description: Converts a specified UInt64 number to a Float64 number.
Parameters:
- bits: UInt64: number to be converted
Returns:
- Float64: conversion result. The value is the same as that of bits.
Example:
import std.unittest.*
import std.unittest.testmacro.*
main() {
let v = Float64.fromBits(0x4029000000000000)
@Assert(v, 12.5)
}
func toBits()
public func toBits(): UInt64
Description: Converts a specified Float64 number to a UInt64 number represented by bits.
Returns:
Example:
import std.unittest.*
import std.unittest.testmacro.*
main() {
@Assert(12.5f64.toBits(), 0x4029000000000000)
}
extend Float64 <: Hashable
extend Float64 <: Hashable
Description: Extends the Hashable interface for the Float64 type to support hash value calculation.
Parent Type:
func hashCode()
public func hashCode(): Int64
Description: Obtains a hash value.
Returns:
- Int64: hash value
extend Float64 <: ToString
extend Float64 <: ToString
Description: Extends the ToString interface for the Float64 type to convert it to the String type.
By default, six decimal places are reserved. For other precisions, refer to extension using Formatter.
Parent Type:
func toString()
public func toString(): String
Description: Converts the value of Float64 to a string that can be output.
Returns:
- String: string after conversion
Int16
Description: Represents a 16-bit signed integer ranging from –2^{15} to 2^{15} – 1.
extend Int16 <: Comparable<Int16>
extend Int16 <: Comparable<Int16>
Description: Extends the Comparable<Int16> interface for the Int16 type to support the comparison operation.
Parent Type:
func compare(Int16)
public func compare(rhs: Int16): Ordering
Description: Compares the current value of Int16 with a specified value of Int16.
Parameters:
Returns:
- Ordering: If the current value is greater than rhs, Ordering.GT is returned. If it is equal to rhs, Ordering.EQ is returned. If it is less than rhs, Ordering.LT is returned.
extend Int16 <: Countable<Int16>
extend Int16 <: Countable<Int16>
Description: Extends the Countable<Int16> interface for the Int16 type to support the counting operation.
Parent Type:
func next(Int64)
public func next(right: Int64): Int16
Description: Obtains the value of Int16 at the rightth location on the right of the current value.
Parameters:
- right: Int64: numbers counted to the right
Returns:
func position()
public func position(): Int64
Description: Obtains the location of the current value of Int16, that is, converts the value of Int16 to the value of Int64.
Returns:
extend Int16 <: Hashable
extend Int16 <: Hashable
Description: Extends the Hashable interface for the Int16 type to support hash value calculation.
Parent Type:
func hashCode()
public func hashCode(): Int64
Description: Obtains a hash value.
Returns:
- Int64: hash value
extend Int16 <: ToString
extend Int16 <: ToString
Description: Extends the ToString interface for the Int16 type to convert it to the String type.
Parent Type:
func toString()
public func toString(): String
Description: Converts the value of Int16 to a string that can be output.
Returns:
- String: string after conversion
Int32
Description: Represents a 32-bit signed integer ranging from –2^{31} to 2^{31} – 1.
extend Int32 <: Comparable<Int32>
extend Int32 <: Comparable<Int32>
Description: Extends the Comparable<Int32> interface for the Int32 type to support the comparison operation.
Parent Type:
func compare(Int32)
public func compare(rhs: Int32): Ordering
Description: Compares the current value of Int32 with a specified value of Int32.
Parameters:
Returns:
- Ordering: If the current value is greater than rhs, Ordering.GT is returned. If it is equal to rhs, Ordering.EQ is returned. If it is less than rhs, Ordering.LT is returned.
extend Int32 <: Countable<Int32>
extend Int32 <: Countable<Int32>
Description: Extends the Countable<Int32> interface for the Int32 type to support the counting operation.
Parent Type:
func next(Int64)
public func next(right: Int64): Int32
Description: Obtains the value of Int32 at the rightth location on the right of the current value.
Parameters:
- right: Int64: numbers counted to the right
Returns:
func position()
public func position(): Int64
Description: Obtains the location of the current value of Int32, that is, converts the value of Int32 to the value of Int64.
Returns:
extend Int32 <: Hashable
extend Int32 <: Hashable
Description: Extends the Hashable interface for the Int32 type to support hash value calculation.
Parent Type:
func hashCode()
public func hashCode(): Int64
Description: Obtains a hash value.
Returns:
- Int64: hash value
extend Int32 <: ToString
extend Int32 <: ToString
Description: Extends the ToString interface for the Int32 type to convert it to the String type.
Parent Type:
func toString()
public func toString(): String
Description: Converts the value of Int32 to a string that can be output.
Returns:
- String: string after conversion
Int64
Description: Represents a 64-bit signed integer ranging from –2^{63} to 2^{63} – 1.
extend Int64 <: Comparable<Int64>
extend Int64 <: Comparable<Int64>
Description: Extends the Comparable<Int64> interface for the Int64 type to support the comparison operation.
Parent Type:
func compare(Int64)
public func compare(rhs: Int64): Ordering
Description: Compares the current value of Int64 with a specified value of Int64.
Parameters:
Returns:
- Ordering: If the current value is greater than rhs, Ordering.GT is returned. If it is equal to rhs, Ordering.EQ is returned. If it is less than rhs, Ordering.LT is returned.
extend Int64 <: Countable<Int64>
extend Int64 <: Countable<Int64>
Description: Extends the Countable<Int64> interface for the Int64 type to support the counting operation.
Parent Type:
func next(Int64)
public func next(right: Int64): Int64
Description: Obtains the value of Int64 at the rightth location on the right of the current value.
Parameters:
- right: Int64: numbers counted to the right
Returns:
func position()
public func position(): Int64
Description: Obtains the location of the current value of Int64, that is, returns this value.
Returns:
extend Int64 <: Hashable
extend Int64 <: Hashable
Description: Extends the Hashable interface for the Int64 type to support hash value calculation.
Parent Type:
func hashCode()
public func hashCode(): Int64
Description: Obtains a hash value.
Returns:
- Int64: hash value
extend Int64 <: ToString
extend Int64 <: ToString
Description: Extends the ToString interface for the Int64 type to convert it to the String type.
Parent Type:
func toString()
public func toString(): String
Description: Converts the value of Int64 to a string that can be output.
Returns:
- String: string after conversion
Int8
Description: Represents an 8-bit signed integer ranging from –2^7 to 2^7 – 1.
extend Int8 <: Comparable<Int8>
extend Int8 <: Comparable<Int8>
Description: Extends the Comparable<Int8> interface for the Int8 type to support the comparison operation.
Parent Type:
func compare(Int8)
public func compare(rhs: Int8): Ordering
Description: Compares the current value of Int8 with a specified value of Int8.
Parameters:
Returns:
- Ordering: If the current value is greater than rhs, Ordering.GT is returned. If it is equal to rhs, Ordering.EQ is returned. If it is less than rhs, Ordering.LT is returned.
extend Int8 <: Countable<Int8>
extend Int8 <: Countable<Int8>
Description: Extends the Countable<Int8> interface for the Int8 type to support the counting operation.
Parent Type:
func next(Int64)
public func next(right: Int64): Int8
Description: Obtains the value of Int8 at the rightth location on the right of the current value.
Parameters:
- right: Int64: numbers counted to the right
Returns:
func position()
public func position(): Int64
Description: Obtains the location of the current value of Int8, that is, converts the value of Int8 to the value of Int64.
Returns:
extend Int8 <: Hashable
extend Int8 <: Hashable
Description: Extends the Hashable interface for the Int8 type to support hash value calculation.
Parent Type:
func hashCode()
public func hashCode(): Int64
Description: Obtains a hash value.
Returns:
- Int64: hash value
extend Int8 <: ToString
extend Int8 <: ToString
Description: Extends the ToString interface for the Int8 type to convert it to the String type.
Parent Type:
func toString()
public func toString(): String
Description: Converts the value of Int8 to a string that can be output.
Returns:
- String: string after conversion
IntNative
Description: Represents a platform-related signed integer with the length same as the bit width of the current system.
extend IntNative <: Comparable<IntNative>
extend IntNative <: Comparable<IntNative>
Description: Extends the Comparable<IntNative> interface for the IntNative type to support the comparison operation.
Parent Type:
func compare(IntNative)
public func compare(rhs: IntNative): Ordering
Description: Compares the current value of IntNative with a specified value of IntNative.
Parameters:
Returns:
- Ordering: If the current value is greater than rhs, Ordering.GT is returned. If it is equal to rhs, Ordering.EQ is returned. If it is less than rhs, Ordering.LT is returned.
extend IntNative <: Countable<IntNative>
extend IntNative <: Countable<IntNative>
Description: Extends the Countable<IntNative> interface for the IntNative type to support the counting operation.
Parent Type:
func next(Int64)
public func next(right: Int64): IntNative
Description: Obtains the value of IntNative at the rightth location on the right of the current value.
Parameters:
- right: Int64: numbers counted to the right
Returns:
func position()
public func position(): Int64
Description: Obtains the location of the current value of IntNative, that is, converts the value of IntNative to the value of Int64.
Returns:
extend IntNative <: Hashable
extend IntNative <: Hashable
Description: Extends the Hashable interface for the IntNative type to support hash value calculation.
Parent Type:
func hashCode()
public func hashCode(): Int64
Description: Obtains a hash value.
Returns:
- Int64: hash value
extend IntNative <: ToString
extend IntNative <: ToString
Description: Extends the ToString interface for the IntNative type to convert it to the String type.
Parent Type:
func toString()
public func toString(): String
Description: Converts the value of IntNative to a string that can be output.
Returns:
- String: string after conversion
Rune
Description: Represents the characters in the Unicode character set.
The value range is Unicode scalar value, that is, characters from \u{0000} to \u{D7FF} and from \u{E000} to \u{10FFF}.
extend Rune <: RuneExtension
extend Rune <: RuneExtension
Description: Extends a series of extension methods for the Rune type, including character determination and conversion in the ASCII character set.
Parent Type:
static func fromUtf8(Array<UInt8>, Int64)
public static func fromUtf8(arr: Array<UInt8>, index: Int64): (Rune, Int64)
Description: Converts a specified element in a byte array to a character according to the UTF-8 encoding rule and notifies the byte length occupied by the character.
Parameters:
- arr: Array<UInt8>: byte array where the byte to be converted is located
- index: Int64: index of the byte to be converted in the array
Returns:
static func getPreviousFromUtf8(Array<UInt8>, Int64)
public static func getPreviousFromUtf8(arr: Array<UInt8>, index: Int64): (Rune, Int64)
Description: Obtains the UTF-8 encoded character where the byte corresponding to a specified index in the byte array is located and returns the index of the first bytecode of the character in the array.
The function finds the location of a specified index in an array and checks whether the bytecode is the first bytecode of the character based on the UTF-8 rule. If the bytecode is not the first bytecode of the character, the traversal continues until the first bytecode is found. Then, the corresponding character is found based on the bytecode sequence.
Parameters:
- arr: Array<UInt8>: byte array from which the character is to be obtained
- index: Int64: index of the character to be searched for in the array
Returns:
Throws:
- IllegalArgumentException: If the corresponding first bytecode cannot be found, that is, the byte at the specified byte location does not comply with the UTF-8 encoding rule, this exception is thrown.
static func intoUtf8Array(Rune, Array<UInt8>, Int64)
public static func intoUtf8Array(c: Rune, arr: Array<UInt8>, index: Int64): Int64
Description: Converts a character to a bytecode sequence and overwrites the bytecode at a specified location in the Array array.
Parameters:
- c: Rune: character to be converted
- arr: Array<UInt8>: Array array to be overwritten
- index: Int64: start index at the specified location
Returns:
- Int64: bytecode length of the character, such as three bytes for a Chinese character
static func utf8Size(Array<UInt8>, Int64)
public static func utf8Size(arr: Array<UInt8>, index: Int64): Int64
Description: Returns the number of bytes occupied by the character starting from a specified index location in a byte array.
In UTF-8 encoding, the first bit of the first byte of an ASCII code cannot be 1. The number of 1s at the beginning of the first byte of a character of other lengths indicates the length of the bytecode corresponding to the character. This function scans the first byte of a character to determine the length of the bytecode. If the index does not correspond to the first bytecode, an exception is thrown.
Parameters:
- arr: Array<UInt8>: byte array of the character to be obtained
- index: Int64: index of the specified character
Returns:
- Int64: bytecode length of the character, such as three bytes for a Chinese character
Throws:
- IllegalArgumentException: If the bytecode at the index location does not comply with the first bytecode rule, this exception is thrown.
static func utf8Size(Rune)
public static func utf8Size(c: Rune): Int64
Description: Returns the UTF-8 encoded bytecode length corresponding to a character, such as three bytes for a Chinese character.
Parameters:
- c: Rune: character whose UTF-8 encoded bytecode length is to be calculated
Returns:
- Int64: UTF-8 encoded bytecode length of the character
func isAscii()
public func isAscii(): Bool
Description: Checks whether a character is in ASCII.
Returns:
- Bool: If the character is in ASCII, true is returned. Otherwise, false is returned.
func isAsciiControl()
public func isAsciiControl(): Bool
Description: Checks whether a character is a control character in ASCII. The value range is the union set of [00, 1F] and {7F}.
Returns:
- Bool: If the character is a control character in ASCII, true is returned. Otherwise, false is returned.
func isAsciiGraphic()
public func isAsciiGraphic(): Bool
Description: Checks whether a character is a graphic character in ASCII. The value range is [21, 7E].
Returns:
- Bool: If the character is a graphic character in ASCII, true is returned. Otherwise, false is returned.
func isAsciiHex()
public func isAsciiHex(): Bool
Description: Checks whether a character is a hexadecimal character in ASCII.
Returns:
- Bool: If the character is a hexadecimal character in ASCII, true is returned. Otherwise, false is returned.
func isAsciiLetter()
public func isAsciiLetter(): Bool
Description: Checks whether a character is a letter character in ASCII.
Returns:
- Bool: If the character is a letter character in ASCII, true is returned. Otherwise, false is returned.
func isAsciiLowerCase()
public func isAsciiLowerCase(): Bool
Description: Checks whether a character is a lowercase character in ASCII.
Returns:
- Bool: If the character is a lowercase character in ASCII, true is returned. Otherwise, false is returned.
func isAsciiNumber()
public func isAsciiNumber(): Bool
Description: Checks whether a character is a numeric character in ASCII.
Returns:
- Bool: If the character is a numeric character in ASCII, true is returned. Otherwise, false is returned.
func isAsciiNumberOrLetter()
public func isAsciiNumberOrLetter(): Bool
Description: Checks whether a character is a numeric or Latin letter character in ASCII.
Returns:
- Bool: If the character is a numeric or Latin letter character in ASCII, true is returned. Otherwise, false is returned.
func isAsciiOct()
public func isAsciiOct(): Bool
Description: Checks whether a character is an octal character in ASCII.
Returns:
- Bool: If the character is an octal character in ASCII, true is returned. Otherwise, false is returned.
func isAsciiPunctuation()
public func isAsciiPunctuation(): Bool
Description: Checks whether a character is a punctuation character in ASCII. The value range is the union set of [21, 2F], [3A, 40], [5B, 60], and [7B, 7E].
Returns:
- Bool: If the character is a punctuation character in ASCII, true is returned. Otherwise, false is returned.
func isAsciiUpperCase()
public func isAsciiUpperCase(): Bool
Description: Checks whether a character is an uppercase character in ASCII.
Returns:
- Bool: If the character is an uppercase character in ASCII, true is returned. Otherwise, false is returned.
func isAsciiWhiteSpace()
public func isAsciiWhiteSpace(): Bool
Description: Checks whether a character is a whitespace character in ASCII. The value range is the union set of [09, 0D] and {20}.
Returns:
- Bool: If the character is a whitespace character in ASCII, true is returned. Otherwise, false is returned.
func toAsciiLowerCase()
public func toAsciiLowerCase(): Rune
Description: Converts a character to a lowercase character in ASCII or retains the original character if the conversion fails.
Returns:
func toAsciiUpperCase()
public func toAsciiUpperCase(): Rune
Description: Converts a character to an uppercase character in ASCII or retains the original character if the conversion fails.
Returns:
extend Rune <: Comparable<Rune>
extend Rune <: Comparable<Rune>
Description: Extends the Comparable<Rune> interface for the Rune type to support the comparison operation.
Parent Type:
func compare(Rune)
public func compare(rhs: Rune): Ordering
Description: Compares the current Rune instance with a specified Rune instance.
The corresponding Unicode code points are compared.
Parameters:
Returns:
- Ordering: When the current instance is greater than, equal to, and less than that specified by rhs, Ordering.GT, Ordering.EQ , and Ordering.LT are returned respectively.
extend Rune <: Countable<Rune>
extend Rune <: Countable<Rune>
Description: Extends the Countable<Rune> interface for the Rune type to support the counting operation.
Parent Type:
func next(Int64)
public func next(right: Int64): Rune
Description: Obtains the value of Rune at the rightth location on the right of the current value.
Parameters:
- right: Int64: numbers counted to the right
Returns:
Throws:
- OverflowException: If the returned value is an invalid Unicode value after being added to the value of Int64, this exception is thrown.
func position()
public func position(): Int64
Description: Obtains the location of the current value of Rune, that is, converts the value of Rune to the value of Int64.
Returns:
extend Rune <: Hashable
extend Rune <: Hashable
Description: Extends the Hashable interface for the Rune type to support hash value calculation.
Parent Type:
func hashCode()
public func hashCode(): Int64
Description: Obtains a hash value.
Returns:
- Int64: hash value
extend Rune <: ToString
extend Rune <: ToString
Description: Extends the ToString interface for the Rune type to convert it to the String type.
Parent Type:
func toString()
public func toString(): String
Description: Converts the value of Rune to a string that can be output.
Returns:
- String: string after conversion
UInt16
Description: Represents a 16-bit unsigned integer, within the range of [0,2^16 - 1].
extend UInt16 <: Comparable<UInt16>
extend UInt16 <: Comparable<UInt16>
Description: Extends the Comparable<UInt16> interface for the UInt16 type to support the comparison operation.
Parent Type:
func compare(UInt16)
public func compare(rhs: UInt16): Ordering
Description: Compares the current value of UInt16 with a specified value of UInt16.
Parameters:
Returns:
- Ordering: If the current value is greater than rhs, Ordering.GT is returned. If it is equal to rhs, Ordering.EQ is returned. If it is less than rhs, Ordering.LT is returned.
extend UInt16 <: Countable<UInt16>
extend UInt16 <: Countable<UInt16>
Description: Extends the Countable<UInt16> interface for the UInt16 type to support the counting operation.
Parent Type:
func next(Int64)
public func next(right: Int64): UInt16
Description: Obtains the value of UInt16 at the rightth location on the right of the current value.
Parameters:
- right: Int64: numbers counted to the right
Returns:
func position()
public func position(): Int64
Description: Obtains the location of the current value of UInt16, that is, converts the value of UInt16 to the value of Int64.
Returns:
extend UInt16 <: Hashable
extend UInt16 <: Hashable
Description: Extends the Hashable interface for the UInt16 type to support hash value calculation.
Parent Type:
func hashCode()
public func hashCode(): Int64
Description: Obtains a hash value.
Returns:
- Int64: hash value
extend UInt16 <: ToString
extend UInt16 <: ToString
Description: Extends the ToString interface for the UInt16 type to convert it to the String type.
Parent Type:
func toString()
public func toString(): String
Description: Converts the value of UInt16 to a string that can be output.
Returns:
- String: string after conversion
UInt32
Description: Represents a 32-bit unsigned integer, within the range of [0,2^{32} - 1].
extend UInt32 <: Comparable<UInt32>
extend UInt32 <: Comparable<UInt32>
Description: Extends the Comparable<UInt32> interface for the UInt32 type to support the comparison operation.
Parent Type:
func compare(UInt32)
public func compare(rhs: UInt32): Ordering
Description: Compares the current value of UInt32 with a specified value of UInt32.
Parameters:
Returns:
- Ordering: If the current value is greater than rhs, Ordering.GT is returned. If it is equal to rhs, Ordering.EQ is returned. If it is less than rhs, Ordering.LT is returned.
extend UInt32 <: Countable<UInt32>
extend UInt32 <: Countable<UInt32>
Description: Extends the Countable<UInt32> interface for the UInt32 type to support the counting operation.
Parent Type:
func next(Int64)
public func next(right: Int64): UInt32
Description: Obtains the value of UInt32 at the rightth location on the right of the current value.
Parameters:
- right: Int64: numbers counted to the right
Returns:
func position()
public func position(): Int64
Description: Obtains the location of the current value of UInt32, that is, converts the value of UInt32 to the value of UInt64.
Returns:
extend UInt32 <: Hashable
extend UInt32 <: Hashable
Description: Extends the Hashable interface for the UInt32 type to support hash value calculation.
Parent Type:
func hashCode()
public func hashCode(): Int64
Description: Obtains a hash value.
Returns:
- Int64: hash value
extend UInt32 <: ToString
extend UInt32 <: ToString
Description: Extends the ToString interface for the UInt32 type to convert it to the String type.
Parent Type:
func toString()
public func toString(): String
Description: Converts the value of UInt32 to a string that can be output.
Returns:
- String: string after conversion
UInt64
Description: Represents a 64-bit unsigned integer, within the range of [0,2^{64} - 1].
extend UInt64 <: Comparable<UInt64>
extend UInt64 <: Comparable<UInt64>
Description: Extends the Comparable<UInt64> interface for the UInt64 type to support the comparison operation.
Parent Type:
func compare(UInt64)
public func compare(rhs: UInt64): Ordering
Description: Compares the current value of UInt64 with a specified value of UInt64.
Parameters:
Returns:
- Ordering: If the current value is greater than rhs, Ordering.GT is returned. If it is equal to rhs, Ordering.EQ is returned. If it is less than rhs, Ordering.LT is returned.
extend UInt64 <: Countable<UInt64>
extend UInt64 <: Countable<UInt64>
Description: Extends the Countable<UInt64> interface for the UInt64 type to support the counting operation.
Parent Type:
func next(Int64)
public func next(right: Int64): UInt64
Description: Obtains the value of UInt64 at the rightth location on the right of the current value.
Parameters:
- right: Int64: numbers counted to the right
Returns:
func position()
public func position(): Int64
Description: Obtains the location of the current value of UInt64, that is, converts the value of UInt64 to the value of Int64.
Returns:
extend UInt64 <: Hashable
extend UInt64 <: Hashable
Description: Extends the Hashable interface for the UInt64 type to support hash value calculation.
Parent Type:
func hashCode()
public func hashCode(): Int64
Description: Obtains a hash value.
Returns:
- Int64: hash value
extend UInt64 <: ToString
extend UInt64 <: ToString
Description: Extends the ToString interface for the UInt64 type to convert it to the String type.
Parent Type:
func toString()
public func toString(): String
Description: Converts the value of UInt64 to a string that can be output.
Returns:
- String: string after conversion
UInt8
Description: Represents an 8-bit unsigned integer, within the range of [0,2^8 - 1].
extend UInt8 <: Comparable<UInt8>
extend UInt8 <: Comparable<UInt8>
Description: Extends the Comparable<UInt8> interface for the UInt8 type to support the comparison operation.
Parent Type:
func compare(UInt8)
public func compare(rhs: UInt8): Ordering
Description: Compares the current value of UInt8 with a specified value of UInt8.
Parameters:
Returns:
- Ordering: If the current value is greater than rhs, Ordering.GT is returned. If it is equal to rhs, Ordering.EQ is returned. If it is less than rhs, Ordering.LT is returned.
extend UInt8 <: Countable<UInt8>
extend UInt8 <: Countable<UInt8>
Description: Extends the Countable<UInt8> interface for the UInt8 type to support the counting operation.
Parent Type:
func next(Int64)
public func next(right: Int64): UInt8
Description: Obtains the value of UInt8 at the rightth location on the right of the current value.
Parameters:
- right: Int64: numbers counted to the right
Returns:
func position()
public func position(): Int64
Description: Obtains the location of the current value of UInt8, that is, converts the value of UInt8 to the value of Int64.
Returns:
extend UInt8 <: Hashable
extend UInt8 <: Hashable
Description: Extends the Hashable interface for the UInt8 type to support hash value calculation.
Parent Type:
func hashCode()
public func hashCode(): Int64
Description: Obtains a hash value.
Returns:
- Int64: hash value
extend UInt8 <: ToString
extend UInt8 <: ToString
Description: Extends the ToString interface for the UInt8 type to convert it to the String type.
Parent Type:
func toString()
public func toString(): String
Description: Converts the value of UInt8 to a string that can be output.
Returns:
- String: string after conversion
UIntNative
Description: Represents a platform-related unsigned integer with the length same as the bit width of the current system.
extend UIntNative <: Comparable<UIntNative>
extend UIntNative <: Comparable<UIntNative>
Description: Extends the Comparable<UIntNative> interface for the UIntNative type to support the comparison operation.
Parent Type:
func compare(UIntNative)
public func compare(rhs: UIntNative): Ordering
Description: Compares the current value of UIntNative with a specified value of UIntNative.
Parameters:
- rhs: UIntNative: the other value of UIntNative to be compared with
Returns:
- Ordering: If the current value is greater than rhs, Ordering.GT is returned. If it is equal to rhs, Ordering.EQ is returned. If it is less than rhs, Ordering.LT is returned.
extend UIntNative <: Countable
extend UIntNative <: Countable<UIntNative>
Description: Extends the Countable<UIntNative> interface for the UIntNative type to support the counting operation.
Parent Type:
func next(Int64)
public func next(right: Int64): UIntNative
Description: Obtains the value of UIntNative at the rightth location on the right of the current value.
Parameters:
- right: Int64: numbers counted to the right
Returns:
- UIntNative: value of UIntNative at the
rightth location on the right of the current value
func position()
public func position(): Int64
Description: Obtains the location of the current value of UIntNative, that is, converts the value of UIntNative to the value of Int64.
Returns:
- Int64: location of the current value of UIntNative
extend UIntNative <: Hashable
extend UIntNative <: Hashable
Description: Extends the Hashable interface for the UIntNative type to support hash value calculation.
Parent Type:
func hashCode()
public func hashCode(): Int64
Description: Obtains a hash value.
Returns:
- Int64: hash value
extend UIntNative <: ToString
extend UIntNative <: ToString
Description: Extends the ToString interface for the UIntNative type to convert it to the String type.
Parent Type:
func toString()
public func toString(): String
Description: Converts the value of UIntNative to a string that can be output.
Returns:
- String: string after conversion
Unit
Description: Represents the type of an expression that concerns only side effects but not values in Cangjie language.
For example, the type of the print function, assignment expression, compound assignment expression, increment and decrement expression, and loop expression is Unit.
The value of the Unit type must be (), which is also its literal. The Unit type does not support other operations except value assignment, equality check, and inequality check.
extend Unit <: Equatable<Unit>
extend Unit <: Equatable<Unit>
Description: Extends the Equatable<Unit> interface for the Unit type.
Parent Type:
extend Unit <: Hashable
extend Unit <: Hashable
Description: Extends the Hashable interface for the Unit type to support hash value calculation.
Parent Type:
func hashCode()
public func hashCode(): Int64
Description: Obtains a hash value. The hash value of Unit is 0.
Returns:
- Int64: hash value
extend Unit <: ToString
extend Unit <: ToString
Description: Extends the ToString interface for the Unit type to convert it to the String type.
The string representation of Unit is "()."
Parent Type:
func toString()
public func toString(): String
Description: Converts the value of Unit to a string that can be output.
Returns:
- String: string after conversion
Interface
interface Any
public interface Any
Description: Specifies the parent type of all types. By default, all interface types inherit it and all non-interface types implement it.
interface ByteExtension
public interface ByteExtension
Description: Implements extension methods for the Byte type. It does not contain any attributes or methods.
extend Byte <: ByteExtension
extend Byte <: ByteExtension
Description: Extends a series of extension methods for the Byte type, including character determination and conversion in the ASCII character set.
Parent Type:
func isAscii()
public func isAscii(): Bool
Description: Checks whether the Byte type value is within the ASCII range.
Returns:
- Bool: If the Byte type value is within the ASCII range, true is returned. Otherwise, false is returned.
func isAsciiControl()
public func isAsciiControl(): Bool
Description: Checks whether the Byte type value is within the control character range in ASCII. The value range is the union set of [00, 1F] and {7F}.
Returns:
- Bool: If the Byte type value is within the control character range in ASCII, true is returned. Otherwise, false is returned.
func isAsciiGraphic()
public func isAsciiGraphic(): Bool
Description: Checks whether the Byte type value is within the graphical character range in ASCII. The value range is [21, 7E].
Returns:
- Bool: If the Byte type value is within the graphical character range in ASCII, true is returned. Otherwise, false is returned.
func isAsciiHex()
public func isAsciiHex(): Bool
Description: Checks whether the Byte type value is within the hexadecimal number range in ASCII.
Returns:
- Bool: If the Byte type value is within the hexadecimal number range in ASCII, true is returned. Otherwise, false is returned.
func isAsciiLetter()
public func isAsciiLetter(): Bool
Description: Checks whether the Byte type value is within the Latin letter range in ASCII.
Returns:
- Bool: If the Byte type value is within the Latin letter range in ASCII, true is returned. Otherwise, false is returned.
func isAsciiLowerCase()
public func isAsciiLowerCase(): Bool
Description: Checks whether the Byte type value is within the lowercase Latin letter range in ASCII.
Returns:
- Bool: If the Byte type value is within the lowercase Latin letter range in ASCII, true is returned. Otherwise, false is returned.
func isAsciiNumber()
public func isAsciiNumber(): Bool
Description: Checks whether the Byte type value is within the decimal number range in ASCII.
Returns:
- Bool: If the Byte type value is within the decimal number range in ASCII, true is returned. Otherwise, false is returned.
func isAsciiNumberOrLetter()
public func isAsciiNumberOrLetter(): Bool
Description: Checks whether the Byte type value is within the decimal number and Latin letter ranges in ASCII.
Returns:
- Bool: If the Byte type value is within the decimal number and Latin letter ranges in ASCII, true is returned. Otherwise, false is returned.
func isAsciiOct()
public func isAsciiOct(): Bool
Description: Checks whether the Byte type value is within the octal number range in ASCII.
Returns:
- Bool: If the Byte type value is within the octal number range in ASCII, true is returned. Otherwise, false is returned.
func isAsciiPunctuation()
public func isAsciiPunctuation(): Bool
Description: Checks whether the Byte type value is within the punctuation range in ASCII. The value range is the union set of [21, 2F], [3A, 40], [5B, 60], and [7B, 7E].
Returns:
- Bool: If the Byte type value is within the punctuation range in ASCII, true is returned. Otherwise, false is returned.
func isAsciiUpperCase()
public func isAsciiUpperCase(): Bool
Description: Checks whether the Byte type value is within the uppercase Latin letter range in ASCII.
Returns:
- Bool: If the Byte type value is within the uppercase Latin letter range in ASCII, true is returned. Otherwise, false is returned.
func isAsciiWhiteSpace()
public func isAsciiWhiteSpace(): Bool
Description: Checks whether the Byte type value is within the whitespace character range in ASCII. The value range is the union set of [09, 0D] and {20}.
Returns:
- Bool: If the Byte type value is within the whitespace character range in ASCII, true is returned. Otherwise, false is returned.
func toAsciiLowerCase()
public func toAsciiLowerCase(): Byte
Description: Converts Byte to the corresponding lowercase character Byte in ASCII or retains the original Byte if the conversion fails.
Returns:
func toAsciiUpperCase()
public func toAsciiUpperCase(): Byte
Description: Converts Byte to the corresponding uppercase character Byte in ASCII or retains the original Byte if the conversion fails.
Returns:
interface CType
sealed interface CType
Description: Indicates the interface that supports interoperability with the C language.
The CType interface is a built-in empty interface of the language. It is the specific implementation of the CType constraint. All types supporting interoperability with the C language implicitly implement this interface. Therefore, all types supporting interoperability with the C language can be used as subtypes of the CType type.
Note:
Example:
@C
struct Data {}
@C
func foo() {}
main() {
var c: CType = Data() // ok
c = 0 // ok
c = true // ok
c = CString(CPointer<UInt8>()) // ok
c = CPointer<Int8>() // ok
c = foo // ok
}
interface Collection<T>
public interface Collection<T> <: Iterable<T> {
prop size: Int64
func isEmpty(): Bool
func toArray(): Array<T>
}
Description: Indicates a collection. Generally, a container type should implement this interface.
Parent Type:
- Iterable<T>
prop size
prop size: Int64
Description: Obtains the size of the current collection, that is, the capacity of the container.
Type: Int64
func isEmpty()
func isEmpty(): Bool
Description: Checks whether the current collection is empty.
Returns:
- Bool: If the collection is empty, true is returned. Otherwise, false is returned.
func toArray()
func toArray(): Array<T>
Description: Converts the current collection to the array type.
Returns:
- Array<T>: array obtained by conversion
interface Comparable<T>
public interface Comparable<T> <: Equatable<T> & Less<T> & Greater<T> & LessOrEqual<T> & GreaterOrEqual<T> {
func compare(that: T): Ordering
}
Description: Indicates the comparison operation. This interface is a collection of interfaces indicating equal to, less than, greater than, less than or equal to, and greater than or equal to.
Parent Type:
- Equatable<T>
- Less<T>
- Greater<T>
- LessOrEqual<T>
- GreaterOrEqual<T>
func compare(T)
func compare(that: T): Ordering
Description: Compares the current instance of the T type and the instance of the T type specified by that.
Parameters:
- that: T: the other instance to be compared with the current instance
Returns:
- Ordering: If the current instance is greater than that, Ordering.GT is returned. If it is equal to that, Ordering.EQ is returned. If it is less than that, Ordering.LT is returned.
interface Countable<T>
public interface Countable<T> {
func next(right: Int64): T
func position(): Int64
}
Description: Indicates a countable type.
Each instance of a countable type corresponds to a location (Int64 value). Other instances of this type can be obtained by counting to subsequent numbers.
func next(Int64)
func next(right: Int64): T
Description: Obtains the instance of the T type at the location right numbers counted to the right from the current instance.
Parameters:
- right: Int64: numbers counted to the right
Returns:
- T: instance of the
Ttype at the locationrightnumbers counted to the right from the current instance
func position()
func position(): Int64
Description: Obtains the location information of the current countable instance, that is, converts the current instance to the Int64 type.
Returns:
interface Equal<T>
public interface Equal<T> {
operator func ==(rhs: T): Bool
}
Description: Supports equality check.
operator func ==(T)
operator func ==(rhs: T): Bool
Description: Checks whether two instances are equal.
Parameters:
- rhs: T: the other instance to be compared with
Returns:
- Bool: If the two instances are equal, true is returned. Otherwise, false is returned.
interface Equatable<T>
public interface Equatable<T> <: Equal<T> & NotEqual<T>
Description: Specifies a collection of the equality check and inequality check interfaces.
This interface has been implemented for some Cangjie types, including Unit, Bool, Rune, Int64, Int32, Int16, Int8, UIntNative, UInt64, UInt32, UInt16, UInt8, Float64, Float32, Float16, String, Array, Box, ArrayList, and HashSet.
Parent Type:
interface FloatToBits
public interface FloatToBits
Description: Supports conversion of the Float type to integer values represented by bits.
interface GreaterOrEqual<T>
public interface GreaterOrEqual<T> {
operator func >=(rhs: T): Bool
}
Description: Supports calculations with the result indicating whether one instance is greater than or equal to the other instance or not.
operator func >=(T)
operator func >=(rhs: T): Bool
Description: Checks whether the current instance of the T type is greater than or equal to the instance of the T type specified by rhs.
Parameters:
- rhs: T: the other instance to be compared with the current instance
Returns:
- Bool: If the current instance is greater than or equal to rhs, true is returned. Otherwise, false is returned.
interface Greater<T>
public interface Greater<T> {
operator func >(rhs: T): Bool
}
Description: Supports calculations with the result indicating whether one instance is greater than the other instance or not.
operator func >(T)
operator func >(rhs: T): Bool
Description: Checks whether the current instance of the T type is greater than the instance of the T type specified by rhs.
Parameters:
- rhs: T: the other instance to be compared with the current instance
Returns:
- Bool: If the current instance is greater than rhs, true is returned. Otherwise, false is returned.
interface Hashable
public interface Hashable {
func hashCode(): Int64
}
Description: Calculates hash values.
This interface has been implemented for some Cangjie types, including Bool, Rune, IntNative, Int64, Int32, Int16, Int8, UIntNative, UInt64, UInt32, UInt16, UInt8, Float64, Float32, Float16, String, and Box.
func hashCode()
func hashCode(): Int64
Description: Obtains the hash value of an instance type.
Returns:
- Int64: hash value of the instance type
interface Hasher
public interface Hasher {
func finish(): Int64
mut func reset(): Unit
mut func write(value: Bool): Unit
mut func write(value: Rune): Unit
mut func write(value: Int8): Unit
mut func write(value: Int16): Unit
mut func write(value: Int32): Unit
mut func write(value: Int64): Unit
mut func write(value: UInt8): Unit
mut func write(value: UInt16): Unit
mut func write(value: UInt32): Unit
mut func write(value: UInt64): Unit
mut func write(value: Float16): Unit
mut func write(value: Float32): Unit
mut func write(value: Float64): Unit
mut func write(value: String): Unit
}
Description: Processes combined hash operation.
A series of write functions can be used to pass instances of different data types for combined hash value calculation.
func finish()
func finish(): Int64
Description: Obtains the result of hash operation.
Returns:
- Int64: hash value obtained
func reset()
mut func reset(): Unit
Description: Resets a hash value to 0.
func write(Bool)
mut func write(value: Bool): Unit
Description: Passes a Bool value to be hashed and performs combined hash operation.
Parameters:
- value: Bool: value to be hashed
func write(Float16)
mut func write(value: Float16): Unit
Description: Passes a Float16 value to be hashed and performs combined hash operation.
Parameters:
- value: Float16: value to be hashed
func write(Float32)
mut func write(value: Float32): Unit
Description: Passes a Float32 value to be hashed and performs combined hash operation.
Parameters:
- value: Float32: value to be hashed
func write(Float64)
mut func write(value: Float64): Unit
Description: Passes a Float64 value to be hashed and performs combined hash operation.
Parameters:
- value: Float64: value to be hashed
func write(Int16)
mut func write(value: Int16): Unit
Description: Passes an Int16 value to be hashed and performs combined hash operation.
Parameters:
- value: Int16: value to be hashed
func write(Int32)
mut func write(value: Int32): Unit
Description: Passes an Int32 value to be hashed and performs combined hash operation.
Parameters:
- value: Int32: value to be hashed
func write(Int64)
mut func write(value: Int64): Unit
Description: Passes an Int64 value to be hashed and performs combined hash operation.
Parameters:
- value: Int64: value to be hashed
func write(Int8)
mut func write(value: Int8): Unit
Description: Passes an Int8 value to be hashed and performs combined hash operation.
Parameters:
- value: Int8: value to be hashed
func write(Rune)
mut func write(value: Rune): Unit
Description: Passes a Rune value to be hashed and performs combined hash operation.
Parameters:
- value: Rune: value to be hashed
func write(String)
mut func write(value: String): Unit
Description: Passes a String value to be hashed and performs combined hash operation.
Parameters:
- value: String: value to be hashed
func write(UInt16)
mut func write(value: UInt16): Unit
Description: Passes a UInt16 value to be hashed and performs combined hash operation.
Parameters:
- value: UInt16: value to be hashed
func write(UInt32)
mut func write(value: UInt32): Unit
Description: Passes a UInt32 value to be hashed and performs combined hash operation.
Parameters:
- value: UInt32: value to be hashed
func write(UInt64)
mut func write(value: UInt64): Unit
Description: Passes a UInt64 value to be hashed and performs combined hash operation.
Parameters:
- value: UInt64: value to be hashed
func write(UInt8)
mut func write(value: UInt8): Unit
Description: Passes a UInt8 value to be hashed and performs combined hash operation.
Parameters:
- value: UInt8: value to be hashed
interface Iterable<E>
public interface Iterable<E> {
func iterator(): Iterator<E>
}
Description: Supports iteration. A type (usually the container type) that implements this interface can be iterated in the for-in statement. Alternatively, such type can be iterated by calling the next function based on the corresponding iterator type instance.
This interface has been implemented for basic container types such as Array, ArrayList, and HashMap, and can be implemented for other types to support iterative traversal.
func iterator()
func iterator(): Iterator<E>
Description: Obtains an iterator.
Returns:
- Iterator<T>: iterator
interface LessOrEqual<T>
public interface LessOrEqual<T> {
operator func <=(rhs: T): Bool
}
Description: Supports calculations with the result indicating whether one instance is less than or equal to the other instance or not.
operator func <=(T)
operator func <=(rhs: T): Bool
Description: Checks whether the current instance of the T type is less than or equal to the instance of the T type specified by rhs.
Parameters:
- rhs: T: the other instance to be compared with the current instance
Returns:
- Bool: If the current instance is less than or equal to rhs, true is returned. Otherwise, false is returned.
interface Less<T>
public interface Less<T> {
operator func <(rhs: T): Bool
}
Description: Supports calculations with the result indicating whether one instance is less than the other instance or not.
operator func <(T)
operator func <(rhs: T): Bool
Description: Checks whether the current instance of the T type is less than the instance of the T type specified by rhs.
Parameters:
- rhs: T: the other instance to be compared with the current instance
Returns:
- Bool: If the current instance is less than rhs, true is returned. Otherwise, false is returned.
interface NotEqual<T>
public interface NotEqual<T> {
operator func !=(rhs: T): Bool
}
Description: Supports inequality check.
operator func !=(T)
operator func !=(rhs: T): Bool
Description: Checks whether two instances are not equal.
Parameters:
- rhs: T: the other instance to be compared with
Returns:
- Bool: If the two instances are not equal, true is returned. Otherwise, false is returned.
interface Resource
public interface Resource {
func close(): Unit
func isClosed(): Bool
}
Description: Manages resources, such as closing and releasing memory and handles.
The type that implements this interface can automatically release resources in the try-with-resource syntax context.
func isClosed()
func isClosed(): Bool
Description: Checks whether a resource is closed.
Returns:
- Bool: If the resource has been closed, true is returned. Otherwise, false is returned.
func close()
func close(): Unit
Description: Closes a resource.
interface RuneExtension
public interface RuneExtension
Description: Implements extension methods for the Rune type, but it does not contain any attributes or methods.
interface ThreadContext
public interface ThreadContext {
func end(): Unit
func hasEnded(): Bool
}
Description: Specifies a Cangjie thread context interface.
When a thread is created, besides the default spawn expression input parameter, instances of different ThreadContext types can be passed to select different thread contexts, thereby controlling concurrency to some extent.
Currently, the ThreadContext interface cannot be implemented by users. Cangjie provides MainThreadContext based on the application scenarios. For details about the definition, use the terminal framework library.
Note:
At the CJVM back end, parameters of the ThreadContext type input using
spawndo not take effect.
func end()
func end(): Unit
Description: Specifies an end method used to send an end request to the current context.
func hasEnded()
func hasEnded(): Bool
Description: Specifies a check method used to check whether the current context has ended.
Returns:
- Bool: If the current context has ended, true is returned. Otherwise, false is returned.
interface ToString
public interface ToString {
func toString(): String
}
Description: Provides the string representation of a specific type.
func toString()
func toString(): String
Description: Obtains the string representation of an instance type.
Returns:
- String: string representation of an instance type
Class
class ArrayIterator<T>
public class ArrayIterator<T> <: Iterator<T> {
public init(data: Array<T>)
}
Description: Specifies an array iterator. For details about its functions, see the description of Iterable and Iterator.
Parent Type:
- Iterator<T>
init(Array<T>)
public init(data: Array<T>)
Description: Creates an iterator for a given Array instance to iteratively traverse all objects in the array instance.
Parameters:
- data: Array<T>: array instance
func iterator()
public func iterator(): Iterator<T>
Description: Obtains the current iterator instance.
Returns:
- Iterator<T>: current iterator instance
func next()
public func next(): Option<T>
Description: Returns the next value in an array iterator.
Returns:
- Option<T>: next member of the array iterator, encapsulated by Option. When the iteration reaches the end,
Noneis returned.
class Box<T>
public class Box<T> {
public var value: T
public init(v: T)
}
Description: The Box type provides the capability of adding a layer of class encapsulation to other types.
If a T type does not have the reference capability, for example, the struct type, the Box<T> type can be referenced after encapsulation.
var value
public var value: T
Description: Obtains or modifies a wrapped value.
Type: T
init(T)
public init(v: T)
Description: Constructs a Box<T> instance for a given T instance.
Parameters:
- v: T: instance of any type
extend<T> Box<T> <: Comparable<Box<T>> where T <: Comparable<T>
extend<T> Box<T> <: Comparable<Box<T>> where T <: Comparable<T>
Description: Extends the Comparable<Box<T>> interface for the Box<T> class to support comparison.
The size of the Box<T> instance is the same as that of the encapsulated T instance.
Parent Type:
- Comparable<Box<T>>
func compare(Box<T>)
public func compare(that: Box<T>): Ordering
Description: Compares the current Box instance with the other Box instance.
Parameters:
Returns:
- Ordering: If the current Box instance is greater than that, Ordering.GT is returned. If it is equal to that, Ordering.EQ is returned. If it is less than that, Ordering.LT is returned.
operator func !=(Box<T>)
public operator func !=(that: Box<T>): Bool
Description: Checks whether two Box objects are not equal.
Parameters:
Returns:
- Bool: If the current Box object is not equal to that, true is returned. Otherwise, false is returned.
operator func <(Box<T>)
public operator func <(that: Box<T>): Bool
Description: Compares two Box objects.
Parameters:
Returns:
operator func <=(Box<T>)
public operator func <=(that: Box<T>): Bool
Description: Compares two Box objects.
Parameters:
Returns:
- Bool: If the current Box object is less than or equal to that, true is returned. Otherwise, false is returned.
operator func ==(Box<T>)
public operator func ==(that: Box<T>): Bool
Description: Checks whether two Box objects are equal.
Parameters:
Returns:
operator func >(Box<T>)
public operator func >(that: Box<T>): Bool
Description: Compares two Box objects.
Parameters:
Returns:
- Bool: If the current Box object is greater than that, true is returned. Otherwise, false is returned.
operator func >=(Box<T>)
public operator func >=(that: Box<T>): Bool
Description: Compares two Box objects.
Parameters:
Returns:
- Bool: If the current Box object is greater than or equal to that, true is returned. Otherwise, false is returned.
extend<T> Box<T> <: Hashable where T <: Hashable
extend<T> Box<T> <: Hashable where T <: Hashable
Parent Type:
func hashCode()
public func hashCode(): Int64
Description: Obtains the hash value of a Box object.
Such value is the hash value of an instance of the T type encapsulated in Box.
Returns:
extend<T> Box<T> <: ToString where T <: ToString
extend<T> Box<T> <: ToString where T <: ToString
Description: Extends the ToString interface for the Box<T> type to support conversion to strings.
Parent Type:
func toString()
public func toString(): String
Description: Obtains the string representation of a Box object, that is, the string representation of an instance of the T type encapsulated by the current instance.
Returns:
- String: new string after conversion
class Future<T>
public class Future<T>
Description: A Future<T> instance represents a Cangjie thread task, and it can be used to obtain the calculation result of a Cangjie thread and send a cancellation signal to the Cangjie thread.
The return type of the spawn expression is Future<T>. The type of T depends on the return value type of the closure in the spawn expression.
prop thread
public prop thread: Thread
Description: Obtains the Thread instance of the corresponding Cangjie thread.
Type: Thread
func cancel()
public func cancel(): Unit
Description: Sends a cancellation request to the Cangjie thread corresponding to the current Future instance. This method sends a request but does not stop thread execution immediately. The hasPendingCancellation function of the Thread class can be used to check whether a thread receives any cancellation request. A user can determine whether to terminate the thread in advance and how to terminate the thread according to the check result.
func get()
public func get(): T
Description: Blocks the current thread, and waits for and obtains the result of the thread corresponding to the current Future<T> object.
Returns:
- T: value returned after the thread represented by the current Future<T> instance ends
func get(Int64)
public func get(ns: Int64): Option<T>
Description: Blocks the current thread, waits for a specified period of time, and obtains the return value of the thread corresponding to the current Future<T> object.
The waiting timeout should be specified. If the corresponding thread execution does not end within the specified time, None is returned. If ns ≤ 0 (this function equals get()), the waiting timeout is not limited. If an exception is thrown in the thread and the thread ends, the exception is still thrown when get is called.
Parameters:
- ns: Int64: waiting time, in nanoseconds
Returns:
- Option<T>: execution result of the Cangjie thread after the specified period of time
func tryGet()
public func tryGet(): Option<T>
Description: Attempts to obtain the execution result without blocking the current thread. If the corresponding thread execution does not end, None is returned.
Returns:
- Option<T>: If the current Cangjie thread execution does not end,
Noneis returned. Otherwise, the execution result is returned.
class Iterator<T>
public abstract class Iterator<T> <: Iterable<T>
Description: Indicates an iterator and provides the next method to support iterative traversal of members in a container.
Parent Type:
- Iterable<T>
func iterator()
public func iterator() : Iterator<T>
Description: Returns an iterator.
Returns:
- Iterator<T>: iterator
func next()
public func next(): Option<T>
Description: Obtains the next element during iteration.
Returns:
- Option<T>: next element during iteration
extend<T> Iterator<T>
extend<T> Iterator<T>
Description: Extends the Iterator<T> type.
func all((T) -> Bool)
public func all(predicate: (T)-> Bool): Bool
Description: Checks whether all elements of the iterator meet a given condition.
Parameters:
- predicate: (T) -> Bool: given condition
Returns:
- Bool: result of whether all elements meet the given condition
func any((T) -> Bool)
public func any(predicate: (T)-> Bool): Bool
Description: Checks whether an element that meets a given condition exists in the iterator.
Parameters:
- predicate: (T) -> Bool: given condition
Returns:
- Bool: result of whether an element that meets the given condition exists
func at(Int64)
public func at(n: Int64): Option<T>
Description: Obtains the nth element of the current iterator.
Parameters:
- n: Int64: number specified
Returns:
- Option<T>: element at the specified location. If n is greater than the number of remaining elements, None is returned.
func concat(Iterator<T>)
public func concat(other: Iterator<T>): Iterator<T>
Description: Concatenates two iterators with the current iterator before the iterator represented by the parameter.
Parameters:
- other: Iterator<T>: iterator concatenated after the current iterator
Returns:
- Iterator<T>: new iterator after concatenation
func count()
public func count(): Int64
Description: Counts the number of elements contained in the current iterator.
Returns:
- Int64: number of elements contained in the current iterator
func enumerate()
public func enumerate(): Iterator<(Int64, T)>
Description: Obtains an iterator with indexes.
Returns:
func filter((T) -> Bool)
public func filter(predicate: (T)-> Bool): Iterator<T>
Description: Filters out elements that meet a given condition.
Parameters:
- predicate: (T) -> Bool: given condition. The elements whose condition value is
trueare contained in the returned iterator in sequence.
Returns:
- Iterator<T>: new iterator
func filterMap<R>((T) -> Option<R>)
public func filterMap<R>(transform: (T)-> Option<R>): Iterator<R>
Description: Creates an iterator that both filters and maps.
Parameters:
- transform: (T) -> Option<T>: given mapping function If the return value of the function is Some, predicate of filter is true. If the return value is None, predicate of filter is false.
Returns:
- Iterator<R>: new iterator
func first()
public func first(): Option<T>
Description: Obtains the first element of the current iterator.
Returns:
- Option<T>: first element. If it does not exist, None is returned.
func flatMap<R>((T) -> Iterator<R>)
public func flatMap<R>(transform: (T)-> Iterator<R>): Iterator<R>
Description: Creates a mapping with the flatten function.
Parameters:
- transform: (T) -> Iterable<R>: given mapping function
Returns:
func fold<R>(R, (R, T) -> R)
public func fold<R>(initial: R, operation: (R, T)->R): R
Description: Uses a specified initial value to calculate from left to right.
Parameters:
- initial: R: specified initial value of the R type
- operation: (R, T) -> R: specified calculation function
Returns:
- R: calculation result
func forEach((T) -> Unit)
public func forEach(action: (T)-> Unit): Unit
Description: Traverses all elements of the current iterator and performs the specified operation on each element.
Parameters:
- action: (T) -> Unit: specified operation function
func inspect((T) -> Unit)
public func inspect(action: (T) -> Unit): Iterator<T>
Description: Performs an extra operation on the current element each time the iterator calls next() (without consuming elements in the iterator).
Parameters:
- action: (T) -> Unit: specified operation function
Returns:
- Iterator<T>: new iterator
func isEmpty()
public func isEmpty(): Bool
Description: Checks whether the current iterator is empty.
Returns:
- The Bool: result of whether the current iterator is empty
func last()
public func last(): Option<T>
Description: Obtains the last element of the current iterator.
Returns:
- Option<T>: last element. If it does not exist, None is returned.
func map<R>((T) -> R)
public func map<R>(transform: (T)-> R): Iterator<R>
Description: Creates a mapping.
Parameters:
- transform: (T) - > R: specified mapping function
Returns:
- Iterator<R>: a mapping
func none((T) -> Bool)
public func none(predicate: (T)-> Bool): Bool
Description: Checks whether all elements of the current iterator do not meet a given condition.
Parameters:
- predicate: (T) -> Bool: given condition
Returns:
- Bool: result of whether all elements of the current iterator do not meet the given condition
func reduce((T, T) -> T)
public func reduce(operation: (T, T) -> T): Option<T>
Description: Uses the first element as the initial value to calculate from left to right.
Parameters:
- operation: (T, T) -> T: specified calculation function
Returns:
- The Option<T>: calculation result
func skip(Int64)
public func skip(count: Int64): Iterator<T>
Description: Skips a specified number of elements in the current iterator.
If the value of count is less than 0, an exception is thrown. If the value of count is 0, no element is skipped and the original iterator is returned. If the value of count is greater than 0 and less than the size of the iterator, count elements are skipped and a new iterator containing the remaining elements is returned. If the value of count is greater than or equal to the size of the iterator, all elements are skipped and an empty iterator is returned.
Parameters:
- count: Int64: number of elements to be skipped
Returns:
- Iterator<T>: an iterator in which a specified number of elements are skipped
Throws:
- IllegalArgumentException: If the value of count is less than 0, this exception is thrown.
func step(Int64)
public func step(count: Int64): Iterator<T>
Description: Skips a specified number of elements each time the iterator calls next().
If the value of count is less than or equal to 0, an exception is thrown. If the value of count is greater than 0, next() is called to skip count elements until the iterator is empty.
Parameters:
- count: Int64: number of elements to be skipped each time next() is called
Returns:
- Iterator<T>: a new iterator in which a specified number of elements are skipped each time next() is called
Throws:
- IllegalArgumentException: If the value of count is less than or equal to 0, this exception is thrown.
func take(Int64)
public func take(count: Int64): Iterator<T>
Description: Takes a specified number of elements from the current iterator.
Takes a specified number of elements from the current iterator from the end to the beginning. If the value of count is less than 0, an exception is thrown. If the value of count is 0, no element is taken and an empty iterator is returned. If the value of count is greater than 0 and less than the size of the iterator, the first count elements are taken and a new iterator is returned. If the value of count is greater than or equal to the size of the iterator, all elements are taken and the original iterator is returned.
Parameters:
- count: Int64: number of elements to be taken
Returns:
- Iterator<T>: an iterator in which a specified number of elements are taken
Throws:
- IllegalArgumentException: If the value of count is less than 0, this exception is thrown.
func zip<R>(Iterator<R>)
public func zip<R>(it: Iterator<R>): Iterator<(T, R)>
Description: Combines two iterators into one (the length depends on the shorter iterator).
Parameters:
- it: Iterable<R>: one of the iterators to be combined
Returns:
- Iterator <(T, R)>: new iterator
extend<T> Iterator<T> where T <: Comparable<T>
extend<T> Iterator<T> where T <: Comparable<T>
Description: Extends the Comparable<T> interface for the Iterator<T> type to support comparison.
func max()
public func max(): Option<T>
Description: Filters out the element of the maximum value.
Returns:
- Option<T>: element of the maximum value. If it does not exist, None is returned.
func min()
public func min(): Option<T>
Description: Filters out the element of the minimum value.
Returns:
- Option<T>: element of the minimum value. If it does not exist, None is returned.
extend<T> Iterator<T> where T <: Equatable<T>
extend<T> Iterator<T> where T <: Equatable<T>
Description: Extends the Equatable<T> interface for the Iterator<T> type to support equality check.
func contains(T)
public func contains(element: T): Bool
Description: Traverses all elements and checks whether a specified element is included.
Parameters:
- element: T: element to be searched for
Returns:
- Bool: result of whether the specified element is included
class Object
public open class Object <: Any {
public const init()
}
Object is the parent class of all class types. All class types inherit it by default. Object does not contain any member. That is, Object is empty.
Parent Type:
init()
public const init()
Description: Constructs an object instance.
class RangeIterator<T> <: Iterator<T> where T <: Countable<T> & Comparable<T> & Equatable<T>
public class RangeIterator<T> <: Iterator<T> where T <: Countable<T> & Comparable<T> & Equatable<T>
Description: Specifies an iterator of the Range type. For details about its functions, see the description of Iterable and Iterator interfaces.
Parent Type:
- Iterator<T>
func iterator()
public func iterator(): Iterator<T>
Description: Obtains the current iterator instance.
Returns:
- Iterator<T>: current iterator instance
func next()
public func next(): Option<T>
Description: Obtains the next value in the Range iterator.
Returns: next member in the Range iterator, encapsulated using Option. When the iteration reaches the end, None is returned.
class StackTraceElement
public open class StackTraceElement {
public let declaringClass: String
public let methodName: String
public let fileName: String
public let lineNumber: Int64
public init(declaringClass: String, methodName: String, fileName: String, lineNumber: Int64)
}
Description: Indicates the detailed information about an exception stack, including the class name, function name, file name, and line number involved in the exception.
let declaringClass
public let declaringClass: String
Description: Obtains the class name involved in an exception.
Type: String
let fileName
public let fileName: String
Description: Obtains the file name involved in an exception.
Type: String
let lineNumber
public let lineNumber: Int64
Description: Obtains the line number involved in an exception.
Type: Int64
let methodName
public let methodName: String
Description: Obtains the function name involved in an exception.
Type: String
init(String, String, String, Int64)
public init(declaringClass: String, methodName: String, fileName: String, lineNumber: Int64)
Description: Constructs an exception stack instance and specifies the class name, function name, file name, and line number.
Parameters:
- declaringClass: String: class name
- methodName: String: function name
- fileName: String: file name
- lineNumber: Int64: line number
class StringBuilder
public class StringBuilder <: ToString {
public init()
public init(str: String)
public init(r: Rune, n: Int64)
public init(value: Array<Rune>)
public init(capacity: Int64)
}
Description: Constructs strings.
StringBuilder is more efficient than String in string construction.
- Values of different types can be transferred. This class automatically converts a value of other type to the String type and adds it to the constructed string.
- The dynamic capacity expansion algorithm is used to reduce the memory allocation frequency, accelerate string construction, and occupy less memory resources.
Note:
StringBuilder supports only UTF-8-encoded character data.
Parent Type:
prop capacity
public prop capacity: Int64
Description: Obtains the length of the string that can be contained in the StringBuilder instance. The length increases with the capacity expansion.
Type: Int64
prop size
public prop size: Int64
Description: Obtains the length of the string in the StringBuilder instance.
Type: Int64
init()
public init()
Description: Constructs an empty StringBuilder instance with an initial capacity of 32.
init(Array<Rune>)
public init(value: Array<Rune>)
Description: Initializes a StringBuilder instance using the character array specified by value. The initial capacity of the instance is the size of value, and the initial content is the character content contained in value.
Parameters:
- value: Array<Rune>: character array used to initialize the StringBuilder instance
init(Int64)
public init(capacity: Int64)
Description: Initializes an empty StringBuilder instance using the capacity specified by capacity. The initial capacity of the instance is the size of value, and the initial content is several \0 characters.
Parameters:
- capacity: Int64: byte capacity used to initialize StringBuilder. The value ranges from 0 to Int64.Max.
Throws:
- IllegalArgumentException: If
capacityis less than or equal to 0, this exception is thrown.
init(Rune, Int64)
public init(r: Rune, n: Int64)
Description: Initializes a StringBuilder instance using n characters r. The initial capacity of the instance is n, and the initial content is n characters r.
Parameters:
- r: Rune: characters used to initialize the StringBuilder instance
- n: Int64: number of characters
r. The value ranges from 0 to Int64.Max.
Throws:
- IllegalArgumentException: If
nis less than 0, this exception is thrown.
init(String)
public init(str: String)
Description: Constructs a StringBuilder instance using the specified initial string. The initial capacity of the instance is the size of the specified string, and the initial content is the specified string.
Parameters:
- str: String: string used to initialize the StringBuilder instance
func append(Array<Rune>)
public func append(runeArr: Array<Rune>): Unit
Description: Inserts all characters in a Rune array to the end of StringBuilder.
Parameters:
- runeArr: Array<Rune>:
Runearray to be inserted
func append<T>(Array<T>) where T <: ToString
public func append<T>(val: Array<T>): Unit where T <: ToString
Description: Inserts the string that represents the Array<T> type specified by val to the end of StringBuilder. The ToString interface needs to be implemented for the T type.
Parameters:
func append(Bool)
public func append(b: Bool): Unit
Description: Inserts the string representation of b to the end of StringBuilder.
Parameters:
func append(CString)
public func append(cstr: CString): Unit
Description: Inserts the content in CString specified by cstr to the end of StringBuilder.
Parameters:
func append(Float16)
public func append(n: Float16): Unit
Description: Inserts the string representation of n to the end of StringBuilder.
Parameters:
func append(Float32)
public func append(n: Float32): Unit
Description: Inserts the string representation of n to the end of StringBuilder.
Parameters:
func append(Float64)
public func append(n: Float64): Unit
Description: Inserts the string representation of n to the end of StringBuilder.
Parameters:
func append(Int16)
public func append(n: Int16): Unit
Description: Inserts the string representation of n to the end of StringBuilder.
Parameters:
func append(Int32)
public func append(n: Int32): Unit
Description: Inserts the string representation of n to the end of StringBuilder.
Parameters:
func append(Int64)
public func append(n: Int64): Unit
Description: Inserts the string representation of n to the end of StringBuilder.
Parameters:
func append(Int8)
public func append(n: Int8): Unit
Description: Inserts the string representation of n to the end of StringBuilder.
Parameters:
func append(Rune)
public func append(r: Rune): Unit
Description: Inserts a character specified by r to the end of StringBuilder.
Parameters:
- r: Rune: character to be inserted
func append(String)
public func append(str: String): Unit
Description: Inserts a string specified by str to the end of StringBuilder.
Parameters:
- str: String: string to be inserted
func append(StringBuilder)
public func append(sb: StringBuilder): Unit
Description: Inserts the content in StringBuilder specified by sb to the end of StringBuilder.
Parameters:
- sb: StringBuilder: StringBuilder instance to be inserted
func append<T>(T) where T <: ToString
public func append<T>(v: T): Unit where T <: ToString
Description: Inserts the string that represents the T type specified by v to the end of StringBuilder. The ToString interface needs to be implemented for the T type.
Parameters:
- v: T: instance of the
Ttype to be inserted
func append(UInt16)
public func append(n: UInt16): Unit
Description: Inserts the string representation of n to the end of StringBuilder.
Parameters:
func append(UInt32)
public func append(n: UInt32): Unit
Description: Inserts the string representation of n to the end of StringBuilder.
Parameters:
func append(UInt64)
public func append(n: UInt64): Unit
Description: Inserts the string representation of n to the end of StringBuilder.
Parameters:
func append(UInt8)
public func append(n: UInt8): Unit
Description: Inserts the string representation of n to the end of StringBuilder.
Parameters:
func appendFromUtf8(Array<Byte>)
public func appendFromUtf8(arr: Array<Byte>): Unit
Description: Inserts a byte array specified by arr to the end of StringBuilder.
This function requires that arr complies with the UTF-8 encoding rule. If not, an exception is thrown.
Parameters:
Throws:
- IllegalArgumentException: If the byte array does not comply with the UTF-8 encoding rule, this exception is thrown.
func appendFromUtf8Unchecked(Array<Byte>)
public unsafe func appendFromUtf8Unchecked(arr: Array<Byte>): Unit
Description: Inserts a byte array specified by arr to the end of StringBuilder.
Compared with the appendFromUtf8 function, this function does not check byte arrays according to related UTF-8 rules. Therefore, strings constructed using this function may be invalid, and even unexpected exceptions may occur. In scenarios where the speed is not prioritized, preferentially use the appendFromUtf8 function which is secure.
Parameters:
func reserve(Int64)
public func reserve(additional: Int64): Unit
Description: Expands capacity of StringBuilder by additional.
If additional is less than or equal to 0 or the remaining capacity is greater than or equal to additional, capacity expansion is not performed. If the remaining capacity is less than additional, capacity is expanded to the larger one between 1.5 times the current capacity (rounded down) and the sum of size and additional.
Parameters:
- additional: Int64: specified capacity by which StringBuilder is to be expanded
func reset(?Int64)
public func reset(capacity!: Option<Int64> = None): Unit
Description: Clears the current StringBuilder instance and resets the capacity to the value specified by capacity.
Parameters:
- capacity!: Option<Int64>: capacity of the StringBuilder instance after resetting. The value is
Noneor ranges fromSome(0)toSome(Int64.Max). The default valueNoneindicates that the default capacity (32) is used.
Throws:
- IllegalArgumentException: If
capacityis less than or equal to 0, this exception is thrown.
func toString()
public func toString(): String
Description: Obtains the string in the StringBuilder instance.
Note:
This function does not copy string data.
Returns:
- String: string in the StringBuilder instance
class Thread
public class Thread
Description: Specifies a Thread class, which represents a Cangjie class, and can be used to obtain thread IDs and names, check whether a thread receives any cancellation request, and register processing functions for exceptions not handled by threads.
Instances of this type cannot be obtained through constructors, and can be obtained only through the thread property of Future objects or the currentThread static property of the Thread class.
static prop currentThread
public static prop currentThread: Thread
Description: Obtains the Thread object of the current thread.
Type: Thread
prop hasPendingCancellation
public prop hasPendingCancellation: Bool
Description: Checks whether a thread receives any cancellation request, that is, whether any cancellation request has been sent through future.cancel(). Common usage: Thread.currentThread.hasPendingCancellation.
Type: Bool
prop id
public prop id: Int64
Description: Obtains the ID of the current thread of the Int64 type. All alive threads have different IDs, but the ID of a thread may not be reused after the thread is executed.
Type: Int64
prop name
public mut prop name: String
Description: Obtains or sets a thread name. Obtaining and setting are atomic operations.
Type: String
static func handleUncaughtExceptionBy((Thread, Exception) -> Unit)
public static func handleUncaughtExceptionBy(exHandler: (Thread, Exception) -> Unit): Unit
Description: Registers a processing function for an exception not handled by a thread.
If a thread is terminated in advance due to an exception but the global unprocessed exception function has been registered, this function is called and the thread ends. When an exception is thrown inside this function, a prompt message is displayed on the terminal and the thread ends, but the abnormal call stack information is not printed. If the global exception handling function is not registered, the abnormal call stack information is displayed on the terminal by default.
When a processing function is registered for multiple times, the subsequent registered function overwrites the previous processing function.
When multiple threads are terminated due to exceptions at the same time, the processing function is executed concurrently. Therefore, developers need to ensure correct concurrency in the processing function.
The first parameter of the processing function is of the Thread type, which is the thread where the exception occurs. The second parameter of the processing function is of the Exception type, which is the exception not processed by the thread.
Parameters:
class ThreadLocal<T>
public class ThreadLocal<T>
Description: Indicates a Cangjie thread local variable.
Compared with common variables, thread local variables have different access semantics. When multiple threads share the same thread local variable, each thread has its own copy of the value. When a thread accesses a variable, the thread reads and writes the local value of the variable without affecting the values of variables in other threads.
func get()
public func get(): ?T
Description: Obtains the value of a Cangjie thread local variable.
Returns:
- ?T: If the current thread local variable is not null, this value is returned. If it is null,
Noneis returned.
func set(?T)
public func set(value: ?T): Unit
Description: Sets the value of a Cangjie thread local variable by using the value parameter. If None is passed, the value of the local variable is deleted and cannot be obtained in subsequent operations of the thread.
Parameters:
- value: ?T: value of the local variable to be set
Enumeration
enum AnnotationKind
public enum AnnotationKind {
| Init
| MemberFunction
| MemberProperty
| MemberVariable
| Parameter
| Type
}
Description: Indicates the location that the custom annotation is expected to support.
Init
Init
Description: Declares a constructor.
MemberFunction
MemberFunction
Description: Declares a member function.
MemberProperty
MemberProperty
Description: Declares a member property.
MemberVariable
MemberVariable
Description: Declares a member variable.
Parameter
Parameter
Description: Specifies a parameter in a member function or constructor.
Type
Type
Description: Declares a type (class, struct, enum, or interface).
enum Endian
public enum Endian {
| Big
| Little
}
Description: Indicates the endianness of the running platform, which can be big endian or little endian.
Big
Big
Description: Specifies the big endian.
Little
Little
Description: Specifies the little endian.
static prop Platform
public static prop Platform: Endian
Description: Obtains the endianness of the running platform.
Type: Endian
Throws:
- UnsupportedException: If the endianness returned by the running platform cannot be identified, this exception is thrown.
Example:
main() {
let e = Endian.Platform
match (e) {
case Big => println("BigEndian")
case Little => println("LittleEndian")
}
}
enum Option<T>
public enum Option<T> {
| Some(T)
| None
}
Description: Encapsulates the T type, indicating that the type may or may not have a value.
It includes Some and None constructors. Some carries a parameter, indicating that there is a value. None carries no parameter, indicating that there is no value. The Option type can be used to indicates that a type may or may not have a value.
Another format of the Option type is to add a question mark (?) before a type name. That is, for any Type, ?Type is equivalent to Option<Type>.
None
None
Description: Constructs an Option<T> instance without parameters, indicating that there is no value.
Some(T)
Some(T)
Description: Constructs an Option<T> instance with parameters, indicating that there is value.
func getOrDefault(() -> T)
public func getOrDefault(other: ()->T): T
Description: Obtains a value or returns the default value. If the value of Option is Some, an instance of the T type is returned. If the value is None, the input parameter is called and the value of the T type is returned.
Parameters:
- other: () - > T: default function. If the value of the current instance is
None, this function is called to obtain an instance of theTtype and return the instance.
Returns:
- T: If the value of the current instance is
Some<T>, an instance of theTtype in the current instance is returned. If the value of Option isNone, the function specified by the input parameter is called to obtain the instance of theTtype and return the instance.
func getOrThrow(() -> Exception)
public func getOrThrow(exception: ()->Exception): T
Description: Obtains a value or throws a specified exception.
Parameters:
- exception: () ->Exception: exception function. If the current instance value is
None, this function is executed and the return value is thrown as an exception.
Returns:
- T - If the current instance value is
Some<T>, an instance of theTtype is returned.
Throws:
- Exception: If the current instance value is
None, the return value of the exception function is thrown as an exception.
func getOrThrow()
public func getOrThrow(): T
Description: Obtains a value or throws an exception.
Returns:
- T - If the current instance value is
Some<T>, an instance of theTtype is returned.
Throws:
- NoneValueException: If the current instance value is
None, this exception is thrown.
func isNone()
public func isNone(): Bool
Description: Checks whether the current instance value is None.
Returns:
- Bool: If the current instance value is
None, true is returned. Otherwise, false is returned.
func isSome()
public func isSome(): Bool
Description: Checks whether the current instance value is Some.
Returns:
- Bool: If the current instance value is
Some, true is returned. Otherwise, false is returned.
extend<T> Option<T> <: Equatable<Option<T>> where T <: Equatable<T>
extend<T> Option<T> <: Equatable<Option<T>> where T <: Equatable<T>
Description: Extends the Equatable<Option<T>> interface for the Option<T> enumeration type to support equality check.
Parent Type:
operator func !=(?T)
public operator func !=(that: Option<T>): Bool
Description: Checks whether the current instance is not equal to the Option<T> instance specified by that.
Parameters:
Returns:
- Bool: If the two instances are not equal, true is returned. Otherwise, false is returned.
operator func ==(?T)
public operator func ==(that: Option<T>): Bool
Description: Checks whether the current instance is equal to the Option<T> instance specified by that.
If the values of the two instances are None, they are equal. If the values of the two instances are Some (v1) and Some (v2), respectively, and v1 and v2 are equal, the instances are equal.
Parameters:
Returns:
- Bool: If the two instances are equal, true is returned. Otherwise, false is returned.
extend<T> Option<T> <: Hashable where T <: Hashable
extend<T> Option<T> <: Hashable where T <: Hashable
Description: Extends the Hashable interface for the Option type.
The hash value of Some(T) is equal to that corresponding to the value of T, and the hash value of None is equal to Int64(0).
Parent Type:
func hashCode()
public func hashCode(): Int64
Description: Obtains a hash value.
Returns:
- Int64: hash value
extend<T> Option<T> <: ToString where T <: ToString
extend<T> Option<T> <: ToString where T <: ToString
Description: Implements the ToString interface for the Option<T> enumeration type to support conversion to strings.
Parent Type:
func toString()
public func toString(): String
Description: Converts Option to a string that can be output. The string content is "Some(${T.toString()})" or "None".
Returns:
- String: string after conversion
enum Ordering
public enum Ordering {
| LT
| GT
| EQ
}
Description: Indicates a comparison result and includes three situations: less than, greater than, and equal to.
EQ
EQ
Description: Constructs an Ordering instance that indicates the situation equal to.
GT
GT
Description: Constructs an Ordering instance that indicates the situation greater than.
LT
LT
Description: Constructs an Ordering instance that indicates the situation less than.
extend Ordering <: Comparable
extend Ordering <: Comparable<Ordering>
Description: Extends the Comparable<Ordering> interface for the Ordering type to support the compare operation.
Parent Type:
func compare(Ordering)
public func compare(that: Ordering): Ordering
Description: Compares the current Ordering instance with the Ordering instance specified by that.
The Ordering enumeration values are in the following sequence: GT > EQ > LT.
Parameters:
Returns:
- Ordering: If the current instance is greater than that, GT is returned. If it is equal to that, EQ is returned. If it is less than that, LT is returned.
operator func !=(Ordering)
public operator func !=(that: Ordering): Bool
Description: Checks whether two Ordering instances are not equal.
Parameters:
Returns:
- Bool: If the two instances are not equal, true is returned. Otherwise, false is returned.
operator func <(Ordering)
public operator func <(that: Ordering): Bool
Description: Checks whether the current Ordering instance is less than the Ordering instance specified by that.
Parameters:
Returns:
- Bool: If the current Ordering instance is less than the Ordering instance specified by that, true is returned. Otherwise, false is returned.
operator func <=(Ordering)
public operator func <=(that: Ordering): Bool
Description: Checks whether the current Ordering instance is less than or equal to the Ordering instance specified by that.
Parameters:
Returns:
- Bool: If the current Ordering instance is less than or equal to the Ordering instance specified by that, true is returned. Otherwise, false is returned.
operator func ==(Ordering)
public operator func ==(that: Ordering): Bool
Description: Checks whether two Ordering instances are equal.
Parameters:
Returns:
- Bool: If the two instances are equal, true is returned. Otherwise, false is returned.
operator func >(Ordering)
public operator func >(that: Ordering): Bool
Description: Checks whether the current Ordering instance is greater than the Ordering instance specified by that.
Parameters:
Returns:
- Bool: If the current Ordering instance is greater than the Ordering instance specified by that, true is returned. Otherwise, false is returned.
operator func >=(Ordering)
public operator func >=(that: Ordering): Bool
Description: Checks whether the current Ordering instance is greater than or equal to the Ordering instance specified by that.
Parameters:
Returns:
- Bool: If the current Ordering instance is greater than or equal to the Ordering instance specified by that, true is returned. Otherwise, false is returned.
extend Ordering <: Hashable
extend Ordering <: Hashable
Description: Extends the Hashable interface for the Ordering type.
Parent Type:
func hashCode
public func hashCode(): Int64
Description: Obtains a hash value. The hash value of GT is 3, that of EQ is 2, and that of LT is 1.
Returns:
- Int64: hash value
extend Ordering <: ToString
extend Ordering <: ToString
Description: Extends the ToString interface for the Ordering type to support conversion to strings.
Parent Type:
func toString()
public func toString(): String
Description: Converts the value of Ordering to a string that can be output.
The conversion result is as follows:
Returns:
- String: string after conversion
Struct
struct Array<T>
public struct Array<T> {
public const init()
public init(elements: Collection<T>)
public init(size: Int64, item!: T)
public init(size: Int64, initElement: (Int64) -> T)
}
Description: Specifies a Cangjie array type used to represent an ordered sequence consisting of elements of a single type.
T indicates the element type of an array. T can be any type.
init()
public const init()
Description: Constructs an empty array.
init(Collection<T>)
public init(elements: Collection<T>)
Description: Creates an array based on a Collection instance and saves all elements in the Collection instance to the array.
Parameters:
- elements: Collection<T>: Collection instance based on which the array is created
init(Int64, (Int64) -> T)
public init(size: Int64, initElement: (Int64) -> T)
Description: Creates an array of a specified length whose elements are obtained through initialization function calculation.
That is, values in the range [0, size) are passed to the initialization function initElement for execution to obtain elements of the corresponding indexes in the array.
Parameters:
Throws:
- NegativeArraySizeException: If size is less than 0, this exception is thrown.
init(Int64, T)
public init(size: Int64, item!: T)
Description: Constructs an array of a specified length whose elements are initialized with a specified initial value.
Note:
The constructor does not copy item. If item is of a reference type, each element of the array after construction points to the same reference.
Parameters:
- size: Int64: array size; value range: [0, Int64.Max]
- item!: T: initial value for elements in the array
Throws:
- NegativeArraySizeException: If size is less than 0, this exception is thrown.
func clone()
public func clone(): Array<T>
Description: Clones an array, that is, performs deep copy on the data in an array.
Returns:
- Array<T>: new array obtained by cloning
func clone(Range<Int64>)
public func clone(range: Range<Int64>) : Array<T>
Description: Clones a specified range of an array.
Note:
- If the parameter range is a Range instance constructed using the Range constructor:
- The value of start is the value passed to the constructor and is not affected by the value of hasStart passed in during construction.
- When hasEnd is false, the value of end does not take effect and is not affected by the value of isClosed passed in during construction, and the last element of the original array is included.
- The step of range must be 1.
Parameters:
Returns:
- Array<T>: new array obtained by cloning
Throws:
- IndexOutOfBoundsException: If range exceeds the array range, this exception is thrown.
Example:
main() {
let arr = [0, 1, 2, 3, 4, 5]
let new = arr.clone(1..4)
println(new)
}
Running result:
[1, 2, 3]
func concat(Array<T>)
public func concat(other: Array<T>): Array<T>
Description: Creates an array whose content is an array concatenated with the array other.
Parameters:
- other: Array<T>: array to be concatenated to the end of the current array
Returns:
- Array<T>: new array obtained by concatenating
Example:
main() {
let arr = [0, 1, 2, 3, 4, 5]
let new = arr.concat([6, 7, 8, 9, 10])
println(new)
}
Running result:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
func copyTo(Array<T>, Int64, Int64, Int64)
public func copyTo(dst: Array<T>, srcStart: Int64, dstStart: Int64, copyLen: Int64): Unit
Description: Copies a segment of data in an array to the target array.
Parameters:
- dst: Array<T>: target array
- srcStart: Int64: index in this array from which the clone starts; value range: [0, this.size)
- dstStart: Int64: index in the target array from which the writing starts; value range: [0, dst.size)
- copyLen: Int64: length of the copied array; requirements: copyLen + srcStart < this.size, copyLen + dstStart < dst.size
Throws:
- IllegalArgumentException: If copyLen is less than 0, this exception is thrown.
- IndexOutOfBoundsException: If a parameter value is not within the required range, this exception is thrown.
Example:
main() {
let arr = [0, 1, 2, 3, 4, 5]
let new = [0, 0, 0, 0, 0, 0]
arr.copyTo(new, 2, 2, 4)
println(new)
}
Running result:
[0, 0, 2, 3, 4, 5]
func get(Int64)
public func get(index: Int64): Option<T>
Description: Obtains the element corresponding to index in an array.
The result of this function is encapsulated with Option. If index is out of range, None is returned.
The element corresponding to a specified index in an array can be obtained by using the operator []. This function throws an exception when index is out of range.
Parameters:
- index: Int64: index of the value to be obtained
Returns:
- Option<T>: value corresponding to index in the array
func reverse()
public func reverse(): Unit
Description: Reverses the sequence of elements in an array.
Example:
main() {
let arr = [0, 1, 2, 3, 4, 5]
arr.reverse()
println(arr)
}
Running result:
[5, 4, 3, 2, 1, 0]
func set(Int64, T)
public func set(index: Int64, element: T): Unit
Description: Modifies the value corresponding to index in an array.
The element corresponding to a specified index can also be modified using the operator []. The two functions have the same behavior.
Parameters:
- index: Int64: index of the value to be modified; value range: [0, this.size – 1]
- element: T: target value of the modification
Throws:
- IndexOutOfBoundsException: If index is less than 0 or greater than or equal to the Array length, this exception is thrown.
func slice(Int64, Int64)
public func slice(start: Int64, len: Int64): Array<T>
Description: Obtains an array slice.
Note:
Slicing does not copy the data in an array. It is a reference to a specific range of the original data.
Parameters:
- start: Int64: start position of the slice. The value must be greater than 0, and the sum of start and len must be less than or equal to the length of the current Array instance.
- len: Int64: length of the slice. The value must be greater than 0.
Returns:
- Array<T>: array after slicing
Throws:
- IndexOutOfBoundsException: If a parameter value is not within the required range, this exception is thrown.
operator func [](Int64)
public operator func [](index: Int64): T
Description: Obtains the value corresponding to index in an array.
An exception is thrown if index in this function is out of range.
The element corresponding to a specified index in an array can also be obtained by using the function get. The function get returns None when index is out of range.
Parameters:
Returns:
- T: value corresponding to index in the array
Throws:
- IndexOutOfBoundsException: If index is less than 0 or greater than or equal to the length of the array, this exception is thrown.
operator func [](Int64, T)
public operator func [](index: Int64, value!: T): Unit
Description: Modifies the value corresponding to index in an array.
Parameters:
- index: Int64: index of the value to be modified; value range: [0, Int64.Max]
- value!: T: target value of the modification
Throws:
- IndexOutOfBoundsException: If index is less than 0 or greater than or equal to the length of the array, this exception is thrown.
operator func [](Range<Int64>)
public operator func [](range: Range<Int64>): Array<T>
Description: Obtains an array slice according to a specified range.
Note:
- If the parameter range is a Range instance constructed using the Range constructor:
- The value of start is the value passed to the constructor and is not affected by the value of hasStart passed in during construction.
- When hasEnd is false, the value of end does not take effect and is not affected by the value of isClosed passed in during construction, and the last element of the original array is included.
- The step of range must be 1.
Parameters:
Returns:
- Array<T>: array slice
Throws:
- IllegalArgumentException: If the step of range is not 1, this exception is thrown.
- IndexOutOfBoundsException: If the array range specified by the parameter range is invalid, this exception is thrown.
Example:
main() {
let arr = [0, 1, 2, 3, 4, 5]
let slice = arr[1..4]
arr[3] = 10
println(slice)
}
Running result:
[1, 2, 10]
operator func [](Range<Int64>, Array<T>)
public operator func [](range: Range<Int64>, value!: Array<T>): Unit
Description: Assigns values to elements in a consecutive range in an array using a specified array.
The length of the range specified by the parameter range must be equal to value of the target array.
Note:
- If the parameter range is a Range instance constructed using the Range constructor:
- The value of start is the value passed to the constructor and is not affected by the value of hasStart passed in during construction.
- When hasEnd is false, the value of end does not take effect and is not affected by the value of isClosed passed in during construction, and the last element of the original array is included.
- The step of range must be 1.
Parameters:
- range: Range<Int64>: array range to be modified, which cannot exceed the array range
- value!: Array<T>: target value of the modification
Throws:
- IllegalArgumentException: If the step of range is not 1 or the length of range is not equal to that of value, this exception is thrown.
- IndexOutOfBoundsException: If the array range specified by the parameter range is invalid, this exception is thrown.
Example:
main() {
let arr = [0, 1, 2, 3, 4, 5]
arr[1..3] = [10, 11]
println(arr)
}
Running result:
[0, 10, 11, 3, 4, 5]
operator func [](Range<Int64>, T)
public operator func [](range: Range<Int64>, value!: T): Unit
Description: Assigns values to elements in a consecutive range in an array using a specified value.
Note:
- If the parameter range is a Range instance constructed using the Range constructor:
- The value of start is the value passed to the constructor and is not affected by the value of hasStart passed in during construction.
- When hasEnd is false, the value of end does not take effect and is not affected by the value of isClosed passed in during construction, and the last element of the original array is included.
- The step of range must be 1.
- Slicing does not copy the data in an array. It is a reference to a specific range of the original data.
Parameters:
- range: Range<Int64>: array range to be modified, which cannot exceed the array range
- value!: T: target value of the modification
Throws:
- IllegalArgumentException: If the step of range is not 1, this exception is thrown.
- IndexOutOfBoundsException: If the array range specified by the parameter range is invalid, this exception is thrown.
Example:
main() {
let arr = [0, 1, 2, 3, 4, 5]
arr[1..3] = 10
println(arr)
}
Running result:
[0, 10, 10, 3, 4, 5]
extend<T> Array<T> <: Collection<T>
extend<T> Array<T> <: Collection<T>
Parent Type:
- Collection<T>
prop size
public prop size: Int64
Description: Obtains the number of elements.
Type: Int64
func isEmpty()
public func isEmpty(): Bool
Description: Checks whether an array is empty.
Returns:
- Bool: If it is empty, true is returned. Otherwise, false is returned.
func iterator()
public func iterator(): Iterator<T>
Description: Obtains the iterator of an array used to traverse the array.
Returns:
- Iterator<T>: iterator of the array
func toArray()
public func toArray(): Array<T>
Description: Copies a new Array instance based on the current Array instance.
Returns:
extend<T> Array<T> <: Equatable<Array<T>> where T <: Equatable<T>
extend<T> Array<T> <: Equatable<Array<T>> where T <: Equatable<T>
Description: Extends the Equatable<Array<T>> interface implementation for the Array<T> type to support equality judgment.
Parent Type:
func contains(T)
public func contains(element: T): Bool
Description: Checks whether an array contains a specified element.
Parameters:
- element: T: target element to be searched for
Returns:
- Bool: If it exists, true is returned. Otherwise, false is returned.
func indexOf(Array<T>)
public func indexOf(elements: Array<T>): Option<Int64>
Description: Returns the first position of the subarray elements in an array. If the array does not contain the subarray, None is returned.
Note:
When the type of T is Int64, the syntactic sugar version of the variable-length parameter of this function may be ambiguous with
public func indexOf(element: T, fromIndex: Int64): Option<Int64>. According to the priority, when the number of parameters is 2,public func indexOf(element: T, fromIndex: Int64): Option<Int64>is called preferentially.
Parameters:
- elements: Array<T>: target array to be located
Returns:
- Option<Int64>: first position of the subarray
elementsin the array. If the array does not contain the subarray, None is returned.
func indexOf(Array<T>, Int64)
public func indexOf(elements: Array<T>, fromIndex: Int64): Option<Int64>
Description: Returns the first position of the subarray elements after fromIndex in an array. If the subarray is not found, None is returned.
The function searches from fromIndex. If fromIndex is less than 0, the search starts from index 0. If fromIndex is greater than or equal to the size of the array, None is returned.
Parameters:
Returns:
- Option<Int64>: position of the subarray
elementsafterfromIndexin the array. If the subarray is not found, None is returned.
func indexOf(T)
public func indexOf(element: T): Option<Int64>
Description: Obtains the first position of element in an array. If the array does not contain the element, None is returned.
Parameters:
- element: T: element to be located
Returns:
- Option<Int64>: first position of
elementin the array. If the array does not contain the element, None is returned.
func indexOf(T, Int64)
public func indexOf(element: T, fromIndex: Int64): Option<Int64>
Description: Returns the first position of element after fromIndex in an array. If the element is not found, None is returned.
The function searches from fromIndex. If fromIndex is less than 0, the search starts from index 0. If fromIndex is greater than or equal to the size of the array, None is returned.
Parameters:
- element: T: element to be located
- fromIndex: Int64: start position of the search
Returns:
- Option<Int64>: position of
elementafterfromIndexin the array. If the element is not found, None is returned.
func lastIndexOf(Array<T>)
public func lastIndexOf(elements: Array<T>): Option<Int64>
Description: Returns the last position of elements in an array. If the array does not contain the subarray, None is returned.
Parameters:
- elements: Array<T>: target array to be located
Returns:
- Option<Int64>: last position of
elementsin the array. If the array does not contain the subarray, None is returned.
func lastIndexOf(Array<T>, Int64)
public func lastIndexOf(elements: Array<T>, fromIndex: Int64): Option<Int64>
Description: Searches backwards from fromIndex and returns the last position of the subarray elements in an array. If the array does not contain the subarray, None is returned.
The function searches from fromIndex. If fromIndex is less than 0, the search starts from index 0. If fromIndex is greater than or equal to the size of the array, None is returned.
Parameters:
Returns:
- Option<Int64>: last position of the subarray
elementsobtained through searching backwards fromfromIndexin the array. If the array does not contain the subarray, None is returned.
func lastIndexOf(T)
public func lastIndexOf(element: T): Option<Int64>
Description: Returns the last position of element in an array. If the array does not contain the element, None is returned.
Parameters:
- element: T: target element to be located
Returns:
- Option<Int64>: last position of
elementin the array. If the array does not contain the element, None is returned.
func lastIndexOf(T, Int64)
public func lastIndexOf(element: T, fromIndex: Int64): Option<Int64>
Description: Searches backwards from fromIndex and returns the last position of element in an array. If the array does not contain the element, None is returned.
The function searches from fromIndex. If fromIndex is less than 0, the search starts from index 0. If fromIndex is greater than or equal to the size of the array, None is returned.
Parameters:
- element: T: target element to be located
- fromIndex: Int64: start position of the search
Returns:
- Option<Int64>: last position of
elementobtained through searching backwards fromfromIndexin the array. If the array does not contain the element, None is returned.
func trimLeft(Array<T>)
public func trimLeft(prefix: Array<T>): Array<T>
Description: Trims an array, that is, removes the part prefixed with prefix and returns the slice of the array.
Parameters:
- prefix: Array<T>: subarray to be trimmed
Returns:
- Array<T>: array slice after trimming
func trimRight(Array<T>)
public func trimRight(suffix: Array<T>): Array<T>
Description: Trims an array, that is, removes the part suffixed with suffix and returns the slice of the array.
Parameters:
- suffix: Array<T>: subarray to be trimmed
Returns:
- Array<T>: array slice after trimming
operator func !=(Array<T>)
public operator const func !=(that: Array<T>): Bool
Description: Checks whether an instance is not equal to a specified Array<T> instance.
Parameters:
Returns:
- Bool: If they are not equal, true is returned. Otherwise, false is returned.
operator func ==(Array<T>)
public operator const func ==(that: Array<T>): Bool
Description: Checks whether an instance is equal to a specified Array<T> instance.
Each element of equal Array<T> instances is equal.
Parameters:
Returns:
- Bool: If they are equal, true is returned. Otherwise, false is returned.
extend<T> Array<T> where T <: ToString
extend<T> Array<T> <: ToString where T <: ToString
Description: Extends the ToString interface for the Array<T> type to support conversion to strings.
Parent Type:
func toString()
public func toString(): String
Description: Converts an array to a string that can be output.
Example: "[1, 2, 3, 4, 5]"
Returns:
- String: string after conversion
struct CPointerHandle<T> where T <: CType
public struct CPointerHandle<T> where T <: CType {
public let array: Array<T>
public let pointer: CPointer<T>
public init()
public init(ptr: CPointer<T>, arr: Array<T>)
}
Description: Specifies the original pointer of an Array. The generic parameters of arr must meet the CType constraint.
let array
public let array: Array<T>
Description: Obtains the Array instance corresponding to the original pointer.
Type: Array<T>
let pointer
public let pointer: CPointer<T>
Description: Obtains the original pointer corresponding to a specified Array.
Type: CPointer<T>
init()
public init()
Description: Constructs a default CPointerHandle instance, in which the original pointer is a null pointer and the Cangjie array is an empty array.
init(CPointer<T>, Array<T>)
public init(ptr: CPointer<T>, arr: Array<T>)
Description: Initializes a CPointerHandle instance based on the CPointer and Array passed.
Parameters:
- ptr: CPointer<T>: original pointer of the array
- arr: Array<T>: Cangjie array corresponding to the pointer
struct CPointerResource<T> where T <: CType
public struct CPointerResource<T> <: Resource where T <: CType {
public let value: CPointer<T>
}
Description: Specifies the resource management type corresponding to CPointer. Instances of this type can be obtained by using the function asResource of CPointer.
Parent Type:
let value
public let value: CPointer<T>
Description: Specifies the CPointer<T> instance managed by the current instance.
Type: CPointer<T>
func close()
public func close(): Unit
Description: Releases the content pointed to by the CPointer<T> instance managed by the current instance.
func isClosed()
public func isClosed(): Bool
Description: Checks whether pointer content has been released.
Returns:
- Bool: If it has been released, true is returned.
struct CStringResource
public struct CStringResource <: Resource {
public let value: CString
}
Description: Specifies the resource management type corresponding to CString](core_package_intrinsics.md#cstring). Instances of this type can be obtained by using the function asResource of CString.
Parent Type:
let value
public let value: CString
Description: Specifies the CString resource managed by the current instance.
Type: CString
func close()
public func close(): Unit
Description: Releases the content pointed to by the CString instance managed by the current instance.
func isClosed()
public func isClosed(): Bool
Description: Checks whether a string has been released.
Returns:
- Bool: If it has been released, true is returned.
struct DefaultHasher
public struct DefaultHasher <: Hasher {
public init(res!: Int64 = 0)
}
Description: Provides the default hash algorithm implementation.
A series of write functions can be used to pass instances of different data types for combined hash value calculation.
Parent Type:
init(Int64)
public init(res!: Int64 = 0)
Description: Creates a DefaultHasher instance.
Parameters:
- res!: Int64: initial hash value; default value: 0
func finish()
public func finish(): Int64
Description: Obtains the result of hash operation.
Returns:
- Int64: result of hash operation
func reset()
public mut func reset(): Unit
Description: Resets a hash value to 0.
func write(Bool)
public mut func write(value: Bool): Unit
Description: Passes a Bool value to be hashed and performs combined hash operation.
Parameters:
- value: Bool: value to be hashed
func write(Float16)
public mut func write(value: Float16): Unit
Description: Passes a Float16 value to be hashed and performs combined hash operation.
Parameters:
- value: Float16: value to be hashed
func write(Float32)
public mut func write(value: Float32): Unit
Description: Passes a Float32 value to be hashed and performs combined hash operation.
Parameters:
- value: Float32: value to be hashed
func write(Float64)
public mut func write(value: Float64): Unit
Description: Passes a Float64 value to be hashed and performs combined hash operation.
Parameters:
- value: Float64: value to be hashed
func write(Int16)
public mut func write(value: Int16): Unit
Description: Passes an Int16 value to be hashed and performs combined hash operation.
Parameters:
- value: Int16: value to be hashed
func write(Int32)
public mut func write(value: Int32): Unit
Description: Passes an Int32 value to be hashed and performs combined hash operation.
Parameters:
- value: Int32: value to be hashed
func write(Int64)
public mut func write(value: Int64): Unit
Description: Passes an Int64 value to be hashed and performs combined hash operation.
Parameters:
- value: Int64: value to be hashed
func write(Int8)
public mut func write(value: Int8): Unit
Description: Passes an Int8 value to be hashed and performs combined hash operation.
Parameters:
- value: Int8: value to be hashed
func write(Rune)
public mut func write(value: Rune): Unit
Description: Passes a Rune value to be hashed and performs combined hash operation.
Parameters:
- value: Rune: value to be hashed
func write(String)
public mut func write(value: String): Unit
Description: Passes a String value to be hashed and performs combined hash operation.
Parameters:
- value: String: value to be hashed
func write(UInt16)
public mut func write(value: UInt16): Unit
Description: Passes a UInt16 value to be hashed and performs combined hash operation.
Parameters:
- value: UInt16: value to be hashed
func write(UInt32)
public mut func write(value: UInt32): Unit
Description: Passes a UInt32 value to be hashed and performs combined hash operation.
Parameters:
- value: UInt32: value to be hashed
func write(UInt64)
public mut func write(value: UInt64): Unit
Description: Passes a UInt64 value to be hashed and performs combined hash operation.
Parameters:
- value: UInt64: value to be hashed
func write(UInt8)
public mut func write(value: UInt8): Unit
Description: Passes a UInt8 value to be hashed and performs combined hash operation.
Parameters:
- value: UInt8: value to be hashed
struct LibC
public struct LibC
Description: Provides C APIs that are frequently used in Cangjie, such as APIs for applying for and releasing CType instances on the heap.
static func free<T>(CPointer<T>) where T <: CType
public static unsafe func free<T>(p: CPointer<T>): Unit where T <: CType
Description: Releases the heap memory to which the pointer p points.
Parameters:
- p: CPointer<T>: address of the memory to be released
static func free(CString)
public static unsafe func free(cstr: CString): Unit
Description: Releases a C-style string.
Parameters:
- cstr: CString: C-style string to be released
static func mallocCString(String)
public static unsafe func mallocCString(str: String): CString
Description: Applies for a C-style string with the same character content as String.
The constructed C-style string ends with '\0'.
Parameters:
- str: String: Cangjie string used to construct the C string
Returns:
- CString: newly constructed C-style string
Throws:
- IllegalMemoryException: If memory is insufficient, this exception is thrown.
static func malloc<T>(Int64) where T <: CType
public static func malloc<T>(count!: Int64 = 1): CPointer<T> where T <: CType
Description: Applies for a specified number of T instances in the heap and returns their start pointers.
The memory length applied for is sizeOf<T>() * count.
Parameters:
- count!: Int64: default value: 1. This parameter is optional and indicates the number of T-type instances to be applied for.
Returns:
- CPointer<T>: T-type pointer applied for
Throws:
- IllegalArgumentException: If the value of the input parameter is negative, this exception is thrown.
struct Range<T> where T <: Countable<T> & Comparable<T> & Equatable<T>
public struct Range<T> <: Iterable<T> where T <: Countable<T> & Comparable<T> & Equatable<T> {
public let end: T
public let hasEnd: Bool
public let hasStart: Bool
public let isClosed: Bool
public let start: T
public let step: Int64
public const init(start: T, end: T, step: Int64, hasStart: Bool, hasEnd: Bool, isClosed: Bool)
}
Description: Specifies the interval type used to indicate a sequence of T with a fixed range and step. T must be countable and ordered.
The interval type has the following literal representation formats:
- Left-closed and right-open interval:
start..end : step, which indicates an interval from start to end (exclusive) with the step. - Left-closed and right-closed interval:
start..=end : step, which indicates an interval from start to end (inclusive) with the step.
Note:
- If step is greater than 0 and start is greater than or equal to end, or if step is less than 0 and start is less than or equal to end, the Range instance is an empty interval.
- If step is greater than 0 and start is greater than end, or if step is less than 0 and start is less than end, the Range instance is an empty interval.
Parent Type:
- Iterable<T>
let end
public let end: T
Description: Obtains the end value.
Type: T
let hasEnd
public let hasEnd: Bool
Description: Specifies whether the end value is included.
Type: Bool
let hasStart
public let hasStart: Bool
Description: Specifies whether the start value is included.
Type: Bool
let isClosed
public let isClosed: Bool
Description: Indicates whether the opening and closing status of an interval. true indicates that the interval is left-closed and right-closed, and false indicates that the interval is left-closed and right-open.
Type: Bool
let start
public let start: T
Description: Obtains the start value.
Type: T
let step
public let step: Int64
Description: Obtains the step.
Type: Int64
init(T, T, Int64, Bool, Bool, Bool)
public const init(start: T, end: T, step: Int64, hasStart: Bool, hasEnd: Bool, isClosed: Bool)
Description: Creates a Range sequence.
Parameters:
- start: T: start value
- end: T: end value
- step: Int64: step, which cannot be 0
- hasStart: Bool: whether the created sequence has a start value
- hasEnd: Bool: whether the created sequence has an end value
- isClosed: Bool: true: left-closed and right-closed; false: left-closed and right-open
Throws:
- IllegalArgumentException: If step is equal to 0, this exception is thrown.
func isEmpty()
public const func isEmpty(): Bool
Description: Checks whether an interval is empty.
Returns:
- Bool: If it is empty, true is returned. Otherwise, false is returned.
func iterator()
public func iterator(): Iterator<T>
Description: Obtains the iterator of the current interval.
Returns:
- Iterator<T>: iterator of the interval
extend<T> Range<T> <: Equatable<Range<T>> where T <: Countable<T> & Comparable<T> & Equatable<T>
extend<T> Range<T> <: Equatable<Range<T>> where T <: Countable<T> & Comparable<T> & Equatable<T>
Description: Extends the Equatable<Range<T>> interface for the Range<T> type.
Parent Type:
operator func !=(Range<T>)
public operator func !=(that: Range<T>): Bool
Description: Checks whether two Range instances are not equal.
Parameters:
Returns:
- Bool: true indicates that the two instances are not equal, and false indicates that the two instances are equal.
operator func ==(Range<T>)
public operator func ==(that: Range<T>): Bool
Description: Checks whether two Range instances are equal.
Equal Range instances indicate the same interval, that is, they have the same values of start, end, step, and isClosed.
Parameters:
Returns:
- Bool: true indicates that the two instances are equal, and false indicates that the two instances are not equal.
extend<T> Range<T> <: Hashable where T <: Hashable & Countable<T> & Comparable<T> & Equatable<T>
extend<T> Range<T> <: Hashable where T <: Hashable & Countable<T> & Comparable<T> & Equatable<T>
Description: Extends the Hashable interface for the Range type to support hash value calculation.
Parent Type:
func hashCode()
public func hashCode(): Int64
Description: Obtains the combined hash operation result of start, end, step, and isClosed.
Returns:
- Int64: hash value
struct String
public struct String <: Collection<Byte> & Equatable<String> & Comparable<String> & Hashable & ToString {
public static const empty: String
public const init()
public init(value: Array<Rune>)
public init(value: Collection<Rune>)
}
Description: Specifies a Cangjie string with a series of string operations provided, such as construction, search, and concatenation.
Note:
The String type supports only UTF-8 encoding.
Parent Type:
static const empty
public static const empty: String = String()
Description: Creates an empty string and returns it.
Type: String
prop size
public prop size: Int64
Description: Obtains the byte length of a string encoded in the UTF-8 format.
Type: Int64
init()
public const init()
Description: Constructs an empty string.
init(Array<Rune>)
public init(value: Array<Rune>)
Description: Constructs a string based on a character array. The string contains all characters in the array.
Parameters:
- value: Array<Rune>: character array used to construct the string
init(Collection<Rune>)
public init(value: Collection<Rune>)
Description: Constructs a string based on a character set. The string contains all characters in the set.
Parameters:
- value: Collection<Rune>: character set used to construct the string
static func fromUtf8(Array<UInt8>)
public static func fromUtf8(utf8Data: Array<UInt8>): String
Description: Constructs a string based on a byte array encoded in the UTF-8 format.
Parameters:
Returns:
- String: constructed string
Throws:
- IllegalArgumentException: If an input parameter does not comply with the UTF-8 sequence rule, this exception is thrown.
static func fromUtf8Unchecked(Array<UInt8>)
public static unsafe func fromUtf8Unchecked(utf8Data: Array<UInt8>): String
Description: Constructs a string based on a byte array.
Compared with the fromUtf8 function, this function does not check the byte array according to UTF-8 rules. Therefore, the string constructed by this function may be invalid or even unexpected exceptions may occur. If performance is not considered preferentially in some scenarios, preferentially use the secure function fromUtf8.
Parameters:
Returns:
- String: constructed string
static func join(Array<String>, String)
public static func join(strArray: Array<String>, delimiter!: String = String.empty): String
Description: Concatenates all strings in a string list and separates them with a specified separator.
Parameters:
- strArray: Array<String>: string array to be concatenated. If the array is empty, an empty string is returned.
- delimiter!: String: intermediate string used for concatenation; default value: String.empty
Returns:
- String: new string after concatenation
func clone()
public func clone(): String
Description: Returns the copy of the original string.
Returns:
- String: new string obtained by copying
func compare(String)
public func compare(str: String): Ordering
Description: Compares lexicographic orders of a string and a string specified by the parameter str.
Parameters:
- str: String: string to be compared
Returns:
- Ordering: value of the enumeration type Ordering. Ordering.GT indicates that the lexicographical order of the string is greater than that of the string specified by str. Ordering.LT indicates that the lexicographical order of the string is less than that of the string specified by str. Ordering.EQ indicates that the lexicographical orders of the two strings are equal.
Throws:
- IllegalArgumentException: If the original data of the two strings contains an invalid UTF-8 code, this exception is thrown.
func contains(String)
public func contains(str: String): Bool
Description: Checks whether the original string contains the string specified by str.
Parameters:
- str: String: string to be searched for
Returns:
- Bool: If the string specified by str is in the original string, true is returned. Otherwise, false is returned. Specially, if the length of the string specified by str is 0, true is returned.
func count(String)
public func count(str: String): Int64
Description: Returns the count of the substring specified by str in the original string.
Parameters:
- str: String: substring to be searched for
Returns:
- Int64: count. If str is an empty string, the Rune count in the original string plus 1 is returned.
func endsWith(String)
public func endsWith(suffix: String): Bool
Description: Checks whether the original string ends with the string specified by suffix.
Parameters:
- suffix: String: suffix string to be checked
Returns:
- Bool: If the string specified by str is the suffix of the original string, true is returned. Otherwise, false is returned. Specially, if the length of the string specified by str is 0, true is returned.
func getRaw()
public unsafe func getRaw(): CPointerHandle<UInt8>
Description: Obtains the original pointer of the current String for interacting with the C language. After the pointer is used, the function releaseRaw needs to be called to release the pointer.
Note:
Only simple logic such as foreign C function call is supported between getRaw and releaseRaw. Do not construct any Cangjie object such as CString. Otherwise, unpredictable errors may occur.
Returns:
- CPointerHandle<UInt8>: original pointer instance of the string
func hashCode()
public func hashCode(): Int64
Description: Obtains the hash value of a string.
Returns:
- Int64: hash value of the string
func indexOf(Byte)
public func indexOf(b: Byte): Option<Int64>
Description: Obtains the index of the first byte specified by b appearing in the original string.
Parameters:
- b: Byte: byte to be searched for
Returns:
- Option<Int64>: If the original string contains the specified byte, the index of the first one appearing is returned. If the original string does not contain the specified byte,
Noneis returned.
func indexOf(Byte, Int64)
public func indexOf(b: Byte, fromIndex: Int64): Option<Int64>
Description: Searches from the specified index in the original string to obtain the index of the first one of a specified byte appearing in the original string.
Parameters:
Returns:
- Option<Int64>: If the specified byte is found, the index of the first one appearing is returned. Otherwise,
Noneis returned. Specially, fromIndex being less than or equal to 0 makes the same sense. If fromIndex is greater than or equal to the length of the original string,Noneis returned.
func indexOf(String)
public func indexOf(str: String): Option<Int64>
Description: Returns the start index of the first string specified by str appearing in the original string.
Parameters:
- str: String: string to be searched for
Returns:
- Option<Int64>: If the original string contains the string specified by str, the index of the first one appearing is returned. If the original string does not contain the string specified by str, None is returned.
func indexOf(String, Int64)
public func indexOf(str: String, fromIndex: Int64): Option<Int64>
Description: Searches from the index fromIndex in the original string and obtains the start index of the first string specified by str appearing in the original string.
Parameters:
- str: String: string to be searched for
- fromIndex: Int64: specified index from which the search starts
Returns:
- Option<Int64>: If the specified string is found, the index of the first one appearing is returned. Otherwise, None is returned. Specially, if str is an empty string and fromIndex is greater than 0, None is returned. Otherwise, Some(0) is returned. fromIndex being less than or equal to 0 makes the same sense. If fromIndex is greater than or equal to the length of the original string, None is returned.
func isAscii()
public func isAscii(): Bool
Description: Checks whether a string is an ASCII string. If the string is empty or does not contain non-ASCII characters, true is returned.
Returns:
- Bool: If the string is empty or does not contain non-ASCII characters, true is returned. Otherwise, false is returned.
func isAsciiBlank()
public func isAsciiBlank(): Bool
Description: Checks whether a string is empty or whether all Rune values in the string are blank characters (including 0x09, 0x10, 0x11, 0x12, 0x13, and 0x20) in ASCII.
Returns:
- Bool: If the string is empty or all Rune values in the string are blank characters (including 0x09, 0x10, 0x11, 0x12, 0x13, and 0x20) in ASCII, true is returned. Otherwise, false is returned.
func isEmpty()
public func isEmpty(): Bool
Description: Checks whether the original string is empty.
Returns:
- Bool: If it is empty, true is returned. Otherwise, false is returned.
func iterator()
public func iterator(): Iterator<Byte>
Description: Obtains the UTF-8 encoded byte iterator of a string which can be used to support the for-in loop.
Returns:
func lastIndexOf(Byte)
public func lastIndexOf(b: Byte): Option<Int64>
Description: Returns the index of the last byte specified by b appearing in the original string.
Parameters:
- b: Byte: byte to be searched for
Returns:
- Option<Int64>: If the original string contains the byte, the index of the last one appearing is returned. Otherwise,
Noneis returned.
func lastIndexOf(Byte, Int64)
public func lastIndexOf(b: Byte, fromIndex: Int64): Option<Int64>
Description: Searches from the index fromIndex in the original string and returns the index of the last UTF-8 encoded byte specified by b appearing in the original string.
Parameters:
Returns:
- Option<Int64>: If the specified byte is found, the index of the last one appearing is returned. Otherwise,
Noneis returned. Specially, fromIndex being less than or equal to 0 makes the same sense. If fromIndex is greater than or equal to the length of the original string,Noneis returned.
func lastIndexOf(String)
public func lastIndexOf(str: String): Option<Int64>
Description: Returns the start index of the last string specified by str appearing in the original string.
Parameters:
- str: String: string to be searched for
Returns:
- Option<Int64>: If the original string contains the string specified by str, the index of the last one appearing is returned. Otherwise,
Noneis returned.
func lastIndexOf(String, Int64)
public func lastIndexOf(str: String, fromIndex: Int64): Option<Int64>
Description: Searches from the index fromIndex in the original string and obtains the start index of the last string specified by str appearing in the original string.
Parameters:
- str: String: string to be searched for
- fromIndex: Int64: specified index from which the search starts
Returns:
- Option<Int64>: If the string does not appear at and after fromIndex,
Noneis returned. Specially, if str is an empty string and fromIndex is greater than 0,Noneis returned. Otherwise,Some(0)is returned. fromIndex being less than or equal to 0 makes the same sense. If fromIndex is greater than or equal to the length of the original string,Noneis returned.
func lazySplit(String, Bool)
public func lazySplit(str: String, removeEmpty!: Bool = false): Iterator<String>
Description: Splits the original string based on the string separator specified by str. This function does not split a string immediately. Instead, the function returns an iterator used to actually split the string during traversal.
If the string separator specified by str does not appear in the original string, a string iterator of size 1 containing only the original string is returned.
Parameters:
- str: String: string separator
- removeEmpty!: Bool: whether to remove empty strings from the splitting result; default value: false
Returns:
func lazySplit(String, Int64, Bool)
public func lazySplit(str: String, maxSplits: Int64, removeEmpty!: Bool = false): Iterator<String>
Description: Splits the original string based on the string separator specified by str. This function does not split a string immediately. Instead, the function returns an iterator used to actually split the string during traversal.
- If maxSplit is 0, an empty string iterator is returned.
- If maxSplit is 1, a string iterator of size 1 containing only the original string is returned.
- If maxSplit is a negative number, a string iterator after splitting is directly returned.
- If maxSplit is greater than the number of complete substrings after splitting, a completely split string iterator is returned.
- If the string separator specified by str does not appear in the original string, a string iterator of size 1 containing only the original string is returned.
- If str is empty, each character is split. If the original string and separator are empty, an empty string iterator is returned.
Parameters:
- str: String: string separator
- maxSplits: Int64: maximum number of substrings after splitting
- removeEmpty!: Bool: whether to remove empty strings from the splitting result; default value: false
Returns:
func lines()
public func lines(): Iterator<String>
Description: Obtains the line iterator of a string. Each line is separated by a newline character \n, \r, or \r\n. Each line in the result does not contain any newline character.
Returns:
func padLeft(Int64, String)
public func padLeft(totalWidth: Int64, padding!: String = " "): String
Description: Aligns the original string right according to the specified length. If the length of the original string is less than the specified length, a specified string is added to the left.
If the specified length is less than the length of the string, the string is returned without being truncated. If the specified length is greater than the length of the string, a string is added to the left for padding. If the length of the string for padding is greater than 1, the length of the returned string may be greater than the specified length.
Parameters:
- totalWidth: Int64: specified length of the string after alignment, which must be greater than or equal to 0
- padding!: String: specified string for padding on the left when the length is insufficient
Returns:
- String: string after padding
Throws:
- IllegalArgumentException: If totalWidth is less than 0, this exception is thrown.
func padRight(Int64, String)
public func padRight(totalWidth: Int64, padding!: String = " "): String
Description: Aligns the original string left according to the specified length. If the length of the original string is less than the specified length, a specified string is added to the right.
If the specified length is less than the length of the string, the string is returned without being truncated. If the specified length is greater than the length of the string, a string is added to the right for padding. If the length of the string for padding is greater than 1, the length of the returned string may be greater than the specified length.
Parameters:
- totalWidth: Int64: specified length of the string after alignment, which must be greater than or equal to 0
- padding!: String: specified string for padding on the right when the length is insufficient
Returns:
- String: string after padding
Throws:
- IllegalArgumentException: If totalWidth is less than 0, this exception is thrown.
func rawData()
public unsafe func rawData(): Array<Byte>
Description: Obtains the original byte string of a UTF-8 encoded string.
Note:
Modifying the obtained array damages invariability of the string.
Returns:
func releaseRaw(CPointerHandle<UInt8>)
public unsafe func releaseRaw(cp: CPointerHandle<UInt8>): Unit
Description: Releases a pointer obtained by the function getRaw.
Note:
Only the pointer obtained by the same String can be released. If a pointer obtained by another String is released, an unpredictable error occurs.
Parameters:
- cp: CPointerHandle<UInt8>: pointer instance to be released
func replace(String, String)
public func replace(old: String, new: String): String
Description: Replaces an old string in the original string with a new string.
Parameters:
Returns:
- String: new string after replacement
Throws:
- OutOfMemoryError: If an error occurs when this function allocates memory, this exception is thrown.
func runes()
public func runes(): Iterator<Rune>
Description: Obtains the Rune iterator of a string.
Returns:
- Iterator<Rune>: Rune iterator of the string
Throws:
- IllegalArgumentException: If an invalid character is read when the
for-inornext()method is used to traverse the iterator, this exception is thrown.
func split(String, Bool)
public func split(str: String, removeEmpty!: Bool = false): Array<String>
Description: Splits the original string by the string separator specified by str and with specifying whether to delete empty strings.
If the string separator specified by str does not appear in the original string, a string array of length 1 containing only the original string is returned.
Parameters:
- str: String: string separator
- removeEmpty!: Bool: whether to remove empty strings from the splitting result; default value: false
Returns:
func split(String, Int64, Bool)
public func split(str: String, maxSplits: Int64, removeEmpty!: Bool = false): Array<String>
Description: Splits the original string by the string separator specified by str with specifying the maximum number of substrings after splitting and whether to delete empty strings.
- If maxSplit is 0, an empty string array is returned.
- If maxSplit is 1, a string array of length 1 containing only the original string is returned.
- If maxSplit is a negative number, the string array after complete splitting is returned.
- If maxSplit is greater than the number of complete substrings after splitting, string arrays after complete splitting is returned.
- If the string separator specified by str does not appear in the original string, a string array of length 1 containing only the original string is returned.
- If str is empty, each character is split. If the original string and separator are empty, an empty string array is returned.
Parameters:
- str: String: string separator
- maxSplits: Int64: maximum number of substrings after splitting
- removeEmpty!: Bool: whether to remove empty strings from the splitting result; default value: false
Returns:
func startsWith(String)
public func startsWith(prefix: String): Bool
Description: Checks whether the original string starts with the string specified by prefix.
Parameters:
- prefix: String: prefix string to be checked
Returns:
- Bool: If the string specified by str is the prefix of the original string, true is returned. Otherwise, false is returned. Specially, if the length of the string specified by str is 0, true is returned.
func toArray()
public func toArray(): Array<Byte>
Description: Obtains the UTF-8 encoded byte array of a string.
Returns:
func toAsciiLower()
public func toAsciiLower(): String
Description: Converts all ASCII uppercase letters in a string to ASCII lowercase letters.
Returns:
- String: new string after conversion
func toAsciiTitle()
public func toAsciiTitle(): String
Description: Capitalizes English characters in a string.
This function converts only ASCII English characters. If an English character is the first character of the string or the character before the English character is not an English character, the English character is capitalized with other English characters being lowercase.
Returns:
- String: new string after conversion
func toAsciiUpper()
public func toAsciiUpper(): String
Description: Converts all ASCII lowercase letters in a string to ASCII uppercase letters.
Returns:
- String: new string after conversion
func toRuneArray()
public func toRuneArray(): Array<Rune>
Description: Obtains the Rune array of a string. If the original string is empty, an empty array is returned.
Returns:
- Array<Rune>: Rune array of the string
func toString()
public func toString(): String
Description: Obtains the current string.
Returns:
- String: The current string is returned.
func trimAscii()
public func trimAscii(): String
Description: Removes substrings that start and end with whitespace characters in the original string.
The Unicode code point range of whitespace is [0009, 000D] and [0020].
Returns:
- String: new string after conversion
func trimAsciiLeft()
public func trimAsciiLeft(): String
Description: Removes substrings that start with whitespace characters in the original string.
Returns:
- String: new string after conversion
func trimAsciiRight()
public func trimAsciiRight(): String
Description: Removes substrings that end with whitespace characters in the original string.
Returns:
- String: new string after conversion
func trimLeft(String)
public func trimLeft(prefix: String): String
Description: Removes the prefix specified by prefix of a string.
Parameters:
- prefix: String: prefix to be removed
Returns:
- String: new string after conversion
func trimRight(String)
public func trimRight(suffix: String): String
Description: Removes the suffix specified by suffix of a string.
Parameters:
- suffix: String: suffix to be removed
Returns:
- String: new string after conversion
func tryGet(Int64)
public func tryGet(index: Int64): Option<Byte>
Description: Returns the UTF-8 encoded byte value corresponding to the index in a string.
Parameters:
- index: Int64: index of the byte value to be obtained
Returns:
- Option<Byte>: UTF-8 encoded byte value corresponding to the index. If index is less than 0 or greater than or equal to the string length, Option<Byte>.None is returned.
operator func !=(String)
public const operator func !=(right: String): Bool
Description: Checks whether two strings are not equal.
Parameters:
Returns:
- Bool: If they are not equal, true is returned. Otherwise, false is returned.
operator func *(Int64)
public const operator func *(count: Int64): String
Description: Repeats the original string for count times
Parameters:
- count: Int64: number of times the original string is to be repeated
Returns:
operator func +(String)
public const operator func +(right: String): String
Description: Concatenates two strings, that is, concatenates the string specified by right to the end of the original string.
Parameters:
- right: String: string to be concatenated
Returns:
- String: string after concatenation
operator func <(String)
public const operator func <(right: String): Bool
Description: Compares lexicographical orders of two strings.
Parameters:
- right: String: string to be compared
Returns:
- Bool: If the lexicographical order of the original string is less than that of the string specified by right, true is returned. Otherwise, false is returned.
operator func <=(String)
public const operator func <=(right: String): Bool
Description: Compares lexicographical orders of two strings.
Parameters:
- right: String: string to be compared
Returns:
- Bool: If the lexicographical order of the original string is less than or equal to that of the string specified by right, true is returned. Otherwise, false is returned.
operator func ==(String)
public const operator func ==(right: String): Bool
Description: Checks whether two strings are equal.
Parameters:
- right: String: string to be compared
Returns:
- Bool: If they are equal, true is returned. Otherwise, false is returned.
operator func >(String)
public const operator func >(right: String): Bool
Description: Compares lexicographical orders of two strings.
Parameters:
- right: String: string to be compared
Returns:
- Bool: If the lexicographical order of the original string is greater than that of the string specified by right, true is returned. Otherwise, false is returned.
operator func >=(String)
public const operator func >=(right: String): Bool
Description: Compares lexicographical orders of two strings.
Parameters:
- right: String: string to be compared
Returns:
- Bool: If the lexicographical order of the original string is greater than or equal to that of the string specified by right, true is returned. Otherwise, false is returned.
operator func [](Int64)
public const operator func [](index: Int64): Byte
Description: Returns the UTF-8 encoded byte at index.
Parameters:
- index: Int64: index of the UTF-8 encoded byte to be obtained
Returns:
- Byte: obtained UTF-8 encoded byte corresponding to the index
Throws:
- IndexOutOfBoundsException: If index is less than 0 or greater than or equal to the length of the string, this exception is thrown.
operator func [](Range<Int64>)
public const operator func [](range: Range<Int64>): String
Description: Obtains the slice of a string according to a specified range.
Note:
- If the parameter range is a Range instance constructed using the Range constructor:
- The value of start is the value passed to the constructor and is not affected by the value of hasStart passed in during construction.
- When hasEnd is false, the value of end does not take effect and is not affected by the value of isClosed passed in during construction, and the last element of the original string is included.
- The step of range must be 1.
Parameters:
Returns:
- String: string slice
Throws:
- IndexOutOfBoundsException: If the slice range exceeds the original string, this exception is thrown.
- IllegalArgumentException: If range.step is not 1 or the start and end values of the range are not character bounds, this exception is thrown.
Exception Class
class ArithmeticException
public open class ArithmeticException <: Exception {
public init()
public init(message: String)
}
Description: Indicates the arithmetic exception class which is thrown when an arithmetic exception occurs.
Parent Type:
init()
public init()
Description: Constructs a default ArithmeticException instance. The default exception information is empty.
init(String)
public init(message: String)
Description: Constructs an ArithmeticException instance according to the exception information.
Parameters:
- message: String: exception information
func getClassName()
protected open override func getClassName(): String
Description: Obtains a class name.
Returns:
- String: class name string
class Error
public open class Error <: ToString
Description: Specifies the base class of all error classes. This class cannot be inherited or initialized, but can be captured.
Parent Type:
prop message
public open prop message: String
Description: Obtains error information.
Type: String
func getStackTrace()
public func getStackTrace(): Array<StackTraceElement>
Description: Obtains stack information, of which each piece is represented by a StackTraceElement instance, and returns a StackTraceElement array.
Returns:
- Array<StackTraceElement>: stack information array
func printStackTrace()
public open func printStackTrace(): Unit
Description: Prints stack information to the console.
func toString()
public open func toString(): String
Description: Obtains the string value of the current Error instance, including the class name and error information.
Returns:
- String: error information string
class Exception
public open class Exception <: ToString {
public init()
public init(message: String)
}
Description: Specifies the parent class of all exception classes.
It supports to construct an exception class, set and obtain exception information, convert exception information to strings, obtain and print stacks, and set the exception name (used for string representation).
Parent Type:
prop message
public open prop message: String
Description: Obtains exception information.
Type: String
init()
public init()
Description: Constructs a default Exception instance. The default exception information is empty.
init(String)
public init(message: String)
Description: Constructs an Exception instance according to the exception information.
Parameters:
- message: String: exception information
func getClassName()
protected open func getClassName(): String
Description: Obtains a class name represented by a string.
The class name is displayed in the exception string (return value of the toString function). Overwriting this function changes the class name in the exception information string.
Returns:
- String: class name
func getStackTrace()
public func getStackTrace(): Array<StackTraceElement>
Description: Obtains stack information, of which each piece is represented by a StackTraceElement instance, and returns a StackTraceElement array.
Returns:
- Array<StackTraceElement>: stack information array
func printStackTrace()
public func printStackTrace(): Unit
Description: Prints stack information to the console.
func toString()
public open func toString(): String
Description: Obtains the string value of the current Exception instance, including the class name and exception information.
Returns:
- String: exception string
class IllegalArgumentException
public open class IllegalArgumentException <: Exception {
public init()
public init(message: String)
}
Description: Indicates the exception class that is thrown when a parameter is invalid.
Parent Type:
init()
public init()
Description: Constructs a default IllegalArgumentException instance. The default exception information is empty.
init(String)
public init(message: String)
Description: Constructs an IllegalArgumentException instance according to the exception information.
Parameters:
- message: String: exception information
func getClassName()
protected override open func getClassName(): String
Description: Obtains a class name represented by a string.
The class name is displayed in the exception string (return value of the toString function). Overwriting this function changes the class name in the exception information string. The class name is "IllegalArgumentException" in the default implementation.
Returns:
- String: class name
class IllegalFormatException
public open class IllegalFormatException <: IllegalArgumentException {
public init()
public init(message: String)
}
Description: Indicates the exception class that is thrown when the format of a variable is invalid or not standard.
Parent Type:
init()
public init()
Description: Constructs a default IllegalFormatException instance. The default exception information is empty.
init(String)
public init(message: String)
Description: Constructs an IllegalFormatException instance according to the exception information.
Parameters:
- message: String: exception information
class IllegalMemoryException
public class IllegalMemoryException <: Exception {
public init()
public init(message: String)
}
Description: Indicates the exception class which is thrown when a memory operation error occurs.
Parent Type:
init()
public init()
Description: Constructs a default IllegalMemoryException instance. The default exception information is empty.
init(String)
public init(message: String)
Description: Constructs an IllegalMemoryException instance according to the specified exception information.
Parameters:
- message: String: exception information
class IllegalStateException
public class IllegalStateException <: Exception {
public init()
public init(message: String)
}
Description: Indicates the exception class that is thrown when a status is invalid.
Parent Type:
init()
public init()
Description: Constructs a default IllegalStateException instance. The default exception information is empty.
init(String)
public init(message: String)
Description: Constructs an IllegalStateException instance according to the exception information.
Parameters:
- message: String: exception information
class IndexOutOfBoundsException
public class IndexOutOfBoundsException <: Exception {
public init()
public init(message: String)
}
Description: Indicates the exception class that is thrown when an index is out of range.
Parent Type:
init()
public init()
Description: Constructs a default IndexOutOfBoundsException instance. The default exception information is empty.
init(String)
public init(message: String)
Description: Constructs an IndexOutOfBoundsException instance according to the exception information.
Parameters:
- message: String: exception information
class InternalError
public class InternalError <: Error
Description: Indicates the internal error class. This class cannot be initialized but can be captured.
Parent Type:
class NegativeArraySizeException
public class NegativeArraySizeException <: Exception {
public init()
public init(message: String)
}
Description: Specifies the exception class in which the array size is negative.
Parent Type:
init()
public init()
Description: Constructs a default NegativeArraySizeException instance. The default exception information is empty.
init(String)
public init(message: String)
Description: Constructs a NegativeArraySizeException instance according to the exception information.
Parameters:
- message: String: exception information
class NoneValueException
public class NoneValueException <: Exception {
public init()
public init(message: String)
}
Description: Indicates the exception class that is thrown (usually in the getOrThrow function) when the value of an Option<T> instance is None.
Parent Type:
init()
public init()
Description: Constructs a default NoneValueException instance. The default exception information is empty.
init(String)
public init(message: String)
Description: Constructs a NoneValueException instance according to the exception information.
Parameters:
- message: String: exception information
class OutOfMemoryError
public class OutOfMemoryError <: Error
Description: Indicates the out-of-memory error class. This class cannot be inherited or initialized, but can be captured.
Parent Type:
class OverflowException
public class OverflowException <: ArithmeticException {
public init()
public init(message: String)
}
Description: Indicates the exception class this is thrown when overflow occurs in an arithmetic operation.
Parent Type:
init()
public init()
Description: Constructs a default OverflowException instance. The default exception information is empty.
init(String)
public init(message: String)
Description: Constructs an OverflowException instance according to the specified exception information.
Parameters:
- message: String: exception information
class SpawnException
public class SpawnException <: Exception {
public init()
public init(message: String)
}
Description: Indicates the thread exception class, indicating that an exception occurs during thread processing.
Parent Type:
init()
public init()
Description: Constructs a default SpawnException instance. The default exception information is empty.
init(String)
public init(message: String)
Description: Constructs a SpawnException instance according to the exception information.
Parameters:
- message: String: exception information
class StackOverflowError
public class StackOverflowError <: Error
Description: Indicates the stack overflow error class. This class cannot be inherited or initialized, but can be captured.
Parent Type:
func printStackTrace()
public override func printStackTrace(): Unit
Description: Prints stack information to the console.
class UnsupportedException
public class UnsupportedException <: Exception {
public init()
public init(message: String)
}
Description: Indicates the exception class that is thrown when a function is not supported.
Parent Type:
init()
public init()
Description: Constructs a default UnsupportedException instance. The default exception information is empty.
init(String)
public init(message: String)
Description: Constructs an UnsupportedException instance according to the specified exception information.
Parameters:
- message: String: exception information
Cangjie Concurrent Programming Example
Using spawn
The main thread and new thread attempt to print some text at the same time.
Code:
import std.sync.sleep
import std.time.{Duration, DurationExtension}
main(): Int64 {
spawn { =>
for (i in 0..10) {
println("New thread, number = ${i}")
sleep(100 * Duration.millisecond) /* Sleep for 100 ms. */
}
}
for (i in 0..5) {
println("Main thread, number = ${i}")
sleep(100 * Duration.millisecond) /* Sleep for 100 ms. */
}
return 0
}
Running result:
Main thread, number = 0
New thread, number = 0
Main thread, number = 1
New thread, number = 1
Main thread, number = 2
New thread, number = 2
Main thread, number = 3
New thread, number = 3
Main thread, number = 4
New thread, number = 4
New thread, number = 5
Notes:
The preceding information is for reference only. The actual running result is affected by the runtime sequence.
Since the main thread does not wait for the execution of the new thread to end, the new thread does not end when the program exits.
Using get in Future
The main thread waits for execution until thread creation is complete.
Code:
import std.sync.sleep
import std.time.{Duration, DurationExtension}
main(): Int64 {
let fut: Future<Unit> = spawn { =>
for (i in 0..10) {
println("New thread, number = ${i}")
sleep(100 * Duration.millisecond) /* Sleep for 100 ms. */
}
}
fut.get() /* Wait for the thread to complete. */
for (i in 0..5) {
println("Main thread, number = ${i}")
sleep(100 * Duration.millisecond) /* Sleep for 100 ms. */
}
return 0
}
Running result:
New thread, number = 0
New thread, number = 1
New thread, number = 2
New thread, number = 3
New thread, number = 4
New thread, number = 5
New thread, number = 6
New thread, number = 7
New thread, number = 8
New thread, number = 9
Main thread, number = 0
Main thread, number = 1
Main thread, number = 2
Main thread, number = 3
Main thread, number = 4
Canceling a Cangjie Thread
The child thread receives a cancellation request sent by the main thread.
main(): Unit {
let future = spawn { // Create a new thread
while (true) {
if (Thread.currentThread.hasPendingCancellation) {
return 0
}
}
return 1
}
//...
future.cancel() // Send a termination request
let res = future.get() // Wait for thread termination
println(res) // 0
}
Running result:
0
Example of Interaction Between CString and C Language Code
Two functions, getCString and printCString, are provided in C language code. The getCString function is used to return a string pointer on the C language side, and the printCString function is used to print the CString on the Cangjie side.
#include <stdio.h>
char *str = "CString in C code.";
char *getCString() { return str; }
void printCString(char *s) { printf("%s\n", s); }
In Cangjie code, a CString object is created and transferred to the C language side for printing. The string on the C language side is obtained and the following is printed on the Cangjie side:
foreign func getCString(): CString
foreign func printCString(s: CString): Unit
main() {
// Constructs a **CString** instance in Cangjie and transfers it to the C language side.
unsafe {
let s: CString = LibC.mallocCString("CString in Cangjie code.")
printCString(s)
LibC.free(s)
}
unsafe {
// Applies for a string pointer on the C language side, transfers the pointer to Cangjie to convert it to a **CString** instance, and then converts the instance to the Cangjie **String** type.
let cs = getCString()
println(cs.toString())
}
// Uses **CStringResource** in the **try-with-resource** syntax context to automatically manage the **CString** memory.
let cs = unsafe { LibC.mallocCString("CString in Cangjie code.") }
try (csr = cs.asResource()) {
unsafe { printCString(csr.value) }
}
0
}
Output example:
CString in Cangjie code.
CString in C code.
CString in Cangjie code.
Note:
Compilation method: Compile the C language code into a static or dynamic library, compile the Cangjie code, and link the C language library. The compilation process when the C language file name is test.c and the Cangjie file name is test.cj is as follows:
- Run the gcc command
gcc -fPIC -shared test.c -o libtest.soto compilelibtest.soin the C language library.- Run the cjc command
cjc -L. -l test test.cjto compile the executable filemain.
std.argopt Package
Function Description
The argopt package provides the capability of parsing parameter names and values from command line parameter strings.
Command line parameters are passed to a program in the command line and are used to specify the configuration or behavior of the program. For example, a command-line program may have a parameter to specify the name of the file to be processed, or a parameter to specify the database to be used. These parameters are usually parsed and passed to the code of the program so that the program can correctly execute its functions based on these parameters.
Command line parameters are classified into short and long command line parameters, which differ in their length and readability. A short command line parameter usually consists of a single letter and is easy to remember. A long command line parameter usually consists of one or more words and is easy to understand.
API List
Class
| Name | Description |
|---|---|
| ArgOpt | Argopt is used to parse command line parameters and obtain parsing results. |
Class
class Argopt
public class ArgOpt {
public init(shortArgFormat: String)
public init(longArgList: Array<String>)
public init(shortArgFormat: String, longArgList: Array<String>)
public init(args: Array<String>, shortArgFormat: String, longArgList: Array<String>)
}
Description: Argopt is used to parse command line parameters and obtain parsing results.
A command line parameter consists of a prefix symbol, a parameter name, and a parameter value.
"-" indicates the prefix of a short parameter (short command line parameter), and "--" indicates the prefix of a long parameter (long command line parameter). The name of a short parameter that can be parsed can only be a letter. The name of a long parameter that can be parsed must start with a letter and cannot contain "=".
For example, in command parameters "-a123" and "--target=abc.txt", "a" is the short parameter name of -a123, and "target" is the long parameter name of --target=abc.txt. "-123" and "--tar=get=abc.txt" are incorrect command line parameters.
This class allows users to specify parameter names and parameter strings, and provides methods for parsing strings based on parameter names.
The formats of short and long parameter names are as follows:
- Format of a short parameter name string parameter: a letter + ":"; correct example: "a:"; special example: "ab:". In the special example, only "b" is used as the short parameter name through parsing.
- Format of the parameter of a long parameter name string array: "--" (optional) + long parameter name + "="; example: "--testA=" or "testA=".
When a command line parameter is parsed based on the parameter name, if the format of the command line parameter is correct and the corresponding parameter name exists, the command line parameter can be correctly parsed and the result can be obtained by users. Otherwise, the command line parameter cannot be parsed.
For example, if the parameter name is "a:b:" and command line parameters are "-a123 -cofo", the command line parameter whose parameter name is "a" and parameter value is "123" is parsed, and "-cofo" is not parsed.
init(Array<String>)
public init(longArgList: Array<String>)
Description: Constructs an ArgOpt instance and parses the long parameter name from the string of the list.
Parameters:
Throws:
- IllegalArgumentException: If the long parameter name string in the string array does not comply with the specifications, the string does not comply with the UTF-8 encoding, or a character does not have the corresponding Unicode character, this exception is thrown.
init(Array<String>, String, Array<String>)
public init(args: Array<String>, shortArgFormat: String, longArgList: Array<String>)
Description: Constructs an ArgOpt instance, parses the short parameter name from the short parameter name string, and parses the long parameter name from the string of the list. If the parsing is successful, parses the value of the parameter name from the command line parameter specified by the args parameter based on the parameter name obtained through parsing.
Parameters:
- args: Array<String>: command line parameter string array to be parsed
- shortArgFormat: String: string containing the short parameter name
- longArgList: Array<String>: string array containing the long parameter name
Throws:
- IllegalArgumentException: If the short parameter name string does not comply with the specifications, the long parameter name string in the string array does not comply with the specifications, the string does not comply with the UTF-8 encoding, or a character does not have the corresponding Unicode character, this exception is thrown.
init(String)
public init(shortArgFormat: String)
Description: Constructs an ArgOpt instance and parses the short parameter name from the short parameter name string.
Parameters:
- shortArgFormat: String: string containing the short parameter name
Throws:
- IllegalArgumentException: If the short parameter name string does not comply with the specifications, the string does not comply with the UTF-8 encoding, or a character does not have the corresponding Unicode character, this exception is thrown.
init(String, Array<String>)
public init(shortArgFormat: String, longArgList: Array<String>)
Description: Constructs an ArgOpt instance, parses the short parameter name from the short parameter name string, and parses the long parameter name from the string of the list.
Parameters:
- shortArgFormat: String: string containing the short parameter name
- longArgList: Array<String>: string array containing the long parameter name
Throws:
- IllegalArgumentException: If the short parameter name string does not comply with the specifications, the long parameter name string in the string array does not comply with the specifications, the string does not comply with the UTF-8 encoding, or a character does not have the corresponding Unicode character, this exception is thrown.
func getArg(String)
public func getArg(arg: String): Option<String>
Description: Returns the parsed value of the parameter specified by arg.
Parameters:
- arg: String: string consisting of the prefix and parameter name (the prefix can be omitted)
Returns:
func getArgumentsMap()
public func getArgumentsMap(): HashMap<String, String>
Description: Obtains all parsed parameter names and values and returns them in a hash table.
Returns:
- HashMap < String, String >: hash table in which parsed parameter names are keys and parameter values are values
func getUnparseArgs()
public func getUnparseArgs(): Array<String>
Description: Returns command line parameters that are not parsed.
Returns:
Parsing Long Command Line Parameters
import std.argopt.*
main() {
let shortArgs: Array<String> = Array<String>(["--test1=abc", "--test2=123", "--test3 xyz"])
let shortArgName: String = ""
let longArgName: Array<String> = Array<String>(["--test1=", "test2=", "--test3="])
let ao: ArgOpt = ArgOpt(shortArgs, shortArgName, longArgName)
println(ao.getArg("--test1") ?? "None")
println(ao.getArg("--test2") ?? "None")
println(ao.getArg("--test3") ?? "None")
}
Running result:
abc
123
None
Parsing Short Command Line Parameters
import std.argopt.*
main() {
let shortArgs: Array<String> = Array<String>(["-a123", "-bofo", "-cccc"])
let shortArgName: String = "a:b:c"
let longArgName: Array<String> = Array<String>()
let ao: ArgOpt = ArgOpt(shortArgs, shortArgName, longArgName)
println(ao.getArg("-a") ?? "None")
println(ao.getArg("-b") ?? "None")
println(ao.getArg("-c") ?? "None")
}
Running result:
123
ofo
None
std.ast Package
Function Description
The ast package contains the syntax parser of Cangjie source code and Cangjie syntax tree nodes, and provides syntactic parsing functions. It can parse lexical units (Tokens) of Cangjie source code to node objects of the abstract syntax tree.
The Cangjie ast package provides functions related to Macro With Context used to obtain the context information during macro expansion. In the nested macro scenario, an inner macro can call the library function assertParentContext(String) to ensure that the inner macro call is nested in a specific outer macro call. If the call of this function by the inner macro is not nested within the given outer macro call, the function throws an error. In addition, the insideParentContext(String) function is also used to check whether an inner macro call is nested in a specific outer macro call and return a Boolean value. Functions related to Macro With Context can only be directly called as functions, do not support variable assignment, and cannot be used as actual parameters or return values.
The functions related to Macro With Context are as follows:
- assertParentContext(String)
- getChildMessages(String)
- insideParentContext(String)
- setItem(String, Bool)
- setItem(String, Int64)
- setItem(String, String)
API List
Function
| Name | Description |
|---|---|
| assertParentContext(String) | Checks whether the current macro call is within a specific macro call. If the check result does not meet the expectation, the compiler displays an error message. |
| cangjieLex(String) | Converts a string to a value of the Tokens type. |
| cangjieLex(String, Bool) | Converts a string to a value of the Tokens type. |
| compareTokens(Tokens, Tokens) | Checks whether two Tokens are the same. |
| diagReport(DiagReportLevel, Tokens, String, String) | Specifies an error reporting API used to output error messages during macro expansion in the compilation process. WARNING and ERROR messages are supported. |
| getChildMessages(String) | Obtains information sent by a specific inner macro. |
| getTokenKind(UInt16) | Converts a sequence number of the lexical unit type to TokenKind. |
| insideParentContext(String) | Checks whether the current macro call is within a specific macro call and returns a Boolean value. |
| parseDecl(Tokens, String) | Parses a group of lexical units to obtain a node of the Decl type. |
| parseDeclFragment(Tokens, Int64) | Parses a group of lexical units to obtain a node of the Decl type and an index for continuing node parsing. |
| parseExpr(Tokens) | Parses a group of lexical units to obtain a node of the Expr type. |
| parseExprFragment(Tokens, Int64) | Parses a group of lexical units to obtain a node of the Expr type and an index for continuing node parsing. |
| parseProgram(Tokens) | Parses the source code of a single Cangjie file to obtain a node of the Program type. |
| setItem(String, Bool) | Sends information of the Bool type from an inner macro to an outer macro. |
| setItem(String, Int64) | Sends information of the Int64 type from an inner macro to an outer macro. |
| setItem(String, String) | Sends information of the String type from an inner macro to an outer macro. |
Interface
| Name | Description |
|---|---|
| ToBytes | Provides the serialization function of the corresponding type. |
| ToTokens | Converts an instance type to the Tokens type. To support the quote interpolation operation, this interface must be implemented. |
Class
| Name | Description |
|---|---|
| Annotation | Specifies a built-in annotation node of the compiler. |
| Argument | Specifies an argument node in function call. |
| ArrayLiteral | Specifies an Array literal node. |
| AsExpr | Specifies a type check expression. |
| AssignExpr | Specifies an assignment expression node. |
| BinaryExpr | Specifies a binary operation expression node. |
| Block | Specifies a block node. |
| Body | Specifies a structure of the Class, Struct, or Interface type with an extension containing {} and a group of declaration nodes enclosed therein. |
| CallExpr | Specifies a function call node. |
| ClassDecl | Specifies a class definition node. |
| ConstPattern | Specifies a constant pattern node. |
| Constructor | Specifies a Constructor node of the enum type. |
| Decl | Specifies the parent class of all declaration nodes, which is inherited from the Node and provides the common API for all declaration nodes. |
| DoWhileExpr | Specifies a do-while expression. |
| EnumDecl | Specifies an Enum definition node. |
| EnumPattern | Specifies an enum pattern node. |
| ExceptTypePattern | Specifies a node used in exception pattern. |
| Expr | Specifies the parent class of all expression nodes, which is inherited from the Node. |
| ExtendDecl | Specifies an extension definition node. |
| ForInExpr | Specifies a for-in expression. |
| FuncDecl | Specifies a function definition node. |
| FuncParam | Specifies a function parameter node, including unnamed parameters and named parameters. |
| FuncType | Specifies a function type node. |
| GenericConstraint | Specifies a generic constraint node. |
| GenericParam | Specifies a type formal parameter node. |
| IfExpr | Specifies a condition expression. |
| ImportContent | Specifies an import item in the package import node. |
| ImportList | Specifies a package import node. |
| IncOrDecExpr | Specifies an expression that contains an auto-increment operator (++) or auto-decrement operator (--). |
| InterfaceDecl | Specifies an API definition node. |
| IsExpr | Specifies a type check expression. |
| JumpExpr | Specifies break and continue in the loop body of a loop expression. |
| LambdaExpr | Specifies a Lambda expression, which is an anonymous function. |
| LetPatternExpr | Specifies a deconstruction match node declared by let. |
| LitConstExpr | Specifies a constant expression node. |
| MacroDecl | Specifies a macro definition node. |
| MacroExpandDecl | Specifies a macro call node. |
| MacroExpandExpr | Specifies a macro call node. |
| MacroExpandParam | Specifies a macro call node. |
| MacroMessage | Records information sent by an inner macro. |
| MainDecl | Specifies a main function definition node. |
| MatchCase | Specifies a case node in a match expression. |
| MatchExpr | Specifies that a pattern matching expression implements pattern matching. |
| MemberAccess | Specifies a member access expression. |
| Modifier | Specifies that a definition has certain features. It is usually placed at the beginning of a definition. |
| Node | Specifies the parent class of all Cangjie syntax tree nodes. |
| OptionalExpr | Specifies an expression node with a question mark (?). |
| PackageHeader | Specifies a package declaration node. |
| ParenExpr | Specifies a parenthesis expression node, which is an expression enclosed in parentheses. |
| ParenType | Specifies a parenthesis type node. |
| Pattern | Specifies the parent class of all pattern matching nodes, which is inherited from the Node. |
| PrefixType | Specifies a prefix type node with a question mark (?). |
| PrimaryCtorDecl | Specifies a primary constructor node. |
| PrimitiveType | Specifies a primitive type node. |
| PrimitiveTypeExpr | Specifies a primitive type expression node. |
| Program | Specifies a Cangjie source code file node. |
| PropDecl | Specifies a property definition node. |
| QualifiedType | Specifies a user-defined member type. |
| QuoteExpr | Specifies a quote expression node. |
| QuoteToken | Specifies any valid token in a quoteexpression node. |
| RangeExpr | Specifies an expression that contains range operators. |
| RefExpr | Specifies an expression node related to a node of a user-defined type. |
| RefType | Specifies a user-defined type node. |
| ReturnExpr | Specifies a return expression node. |
| SpawnExpr | Specifies a Spawn expression. |
| StructDecl | Specifies a Struct node. |
| SubscriptExpr | Specifies an index access expression. |
| SynchronizedExpr | Specifies a synchronized expression. |
| ThisType | Specifies a This type node. |
| ThrowExpr | Specifies a throw expression node. |
| Tokens | Specifies a type for encapsulating Token sequences. |
| TokensIterator | Implements the iterator function of Tokens. |
| TrailingClosureExpr | Specifies a trailing Lambda node. |
| TryExpr | Specifies a try expression node. |
| TupleLiteral | Specifies a tuple literal node. |
| TuplePattern | Specifies a Tuple pattern node. |
| TupleType | Specifies a tuple type node. |
| TypeAliasDecl | Specifies a type alias node. |
| TypeConvExpr | Specifies a type conversion expression. |
| TypeNode | Specifies the parent class of all type nodes, which is inherited from Node. |
| TypePattern | Specifies a type pattern node. |
| UnaryExpr | Specifies a unary operation expression node. |
| VArrayExpr | Specifies a VArray instance node. |
| VArrayType | Specifies a VArray type node. |
| VarDecl | Specifies a variable definition node. |
| VarOrEnumPattern | Specifies a node when the pattern identifier is an Enum constructor. |
| VarPattern | Specifies a binding pattern node. |
| Visitor | Specifies an abstract class that defines default visit functions for accessing different types of AST nodes. |
| WhileExpr | Specifies a while expression. |
| WildcardExpr | Specifies a wildcard expression node. |
| WildcardPattern | Specifies a wildcard pattern node. |
Enumeration
| Name | Description |
|---|---|
| DiagReportLevel | Specifies information levels supported by an error reporting API. ERROR and WARNING are supported. |
| ImportKind | Specifies the type of an import statement, including single import, alias import, full import, and multi-import. |
| TokenKind | Specifies all lexical structures in Cangjie compilation, including symbols, keywords, identifiers, and line breaks. |
Struct
| Name | Description |
|---|---|
| Position | Specifies the data structure of location information, including the file ID, row number, and column number. |
| Token | Specifies the lexical unit type. |
Exception Class
| Name | Description |
|---|---|
| ASTException | Specifies an exception class for the ast library, which is used when an exception occurs during ast library invocation. |
| MacroContextException | Specifies a context macro exception class for the ast library, which is used when an exception occurs in context macro-related APIs. |
| ParseASTException | Specifies a parsing exception class for the ast library, which is used when an exception occurs during node parsing. |
Function
func assertParentContext(String)
public func assertParentContext(parentMacroName: String): Unit
Description: Checks whether the current macro call is within a specific macro call. If the check result does not meet the expectation, the compiler displays an error message.
Note:
This function can only be directly called as a function and cannot be assigned to a variable or used as an actual parameter or a return value.
Parameters:
- parentMacroName: String: name of the outer macro call to be checked
func cangjieLex(String)
public func cangjieLex(code: String): Tokens
Description: Converts a string to a Tokens object.
Parameters:
- code: String: string pending lexical parsing
Returns:
Throws:
- IllegalMemoryException: When the memory fails to be allocated, this exception is thrown.
- IllegalArgumentException: When the input code cannot be correctly parsed as a Tokens object, this exception is thrown.
func cangjieLex(String, Bool)
public func cangjieLex(code: String, truncated: Bool): Tokens
Description: Converts a string to a Tokens object.
Parameters:
- code: String: string pending lexical parsing
- truncated: Bool: whether to delete Token(END) in the parsed Tokens
Returns:
Throws:
- IllegalMemoryException: When the memory fails to be allocated, this exception is thrown.
- IllegalArgumentException: When the input code cannot be correctly parsed as a Tokens object, this exception is thrown.
func compareTokens(Tokens, Tokens)
public func compareTokens(tokens1: Tokens, tokens2: Tokens): Bool
Description: Checks whether two Tokens instances are the same.
Parameters:
- tokens1: Tokens: one Tokens instance for comparison
- tokens2: Tokens: the other Tokens instance for comparison
Returns:
- Bool: If the contents (except the newline character, end character, and location information) of the two Tokens instances are the same,
trueis returned.
func diagReport(DiagReportLevel, Tokens, String, String)
public func diagReport(level: DiagReportLevel, tokens: Tokens, message: String, hint: String): Unit
Description: Specifies the error reporting API used to output error messages during macro expansion in the compilation process, which supports outputting errors of the WARNING and ERROR levels.
Note:
- For this API, the compilation process is terminated when the error level is
ERROR, but the macro expansion process is not terminated. You are advised to directly perform the return operation or throw an exception to terminate the macro expansion process after this API is called.- This API lists the code in the line where the input tokens are located based on the cjc standard error reporting API and marks content of tokens with wavy lines. The message information is displayed in the first line, and the hint information is displayed following the wavy lines.
- The source code content referenced in the error information is determined only based on the start location of the first Token instance and the end location of the last Token instance. Consistency of the location information of intermediate Token instances is not verified.
- Calling this API is valid only during macro expansion. For details, see [Sample Code](../ast_samples/report.md#Call Example Not in Macro Expansion).
Parameters:
- level: DiagReportLevel: error information level
- tokens: Tokens: Tokens corresponding to the source code content referenced in the error information
- message: String: main information of the error information
- hint: String: auxiliary prompt information
Throws:
-
ASTException: This exception is thrown when the input Tokens instance has any of the following errors:
- The input Tokens instance is empty.
- Token instances in the input Tokens instance are from different source files.
- In the input Tokens instance, the first Token instance is placed before the last Token instance.
- The location range of the Token instance in the input Tokens instance is beyond the location range of the macro call.
func getChildMessages(String)
public func getChildMessages(children:String): ArrayList<MacroMessage>
Description: Obtains information sent by a specific inner macro.
Note:
This function can only be directly called as a function and cannot be assigned to a variable or used as an actual parameter or a return value.
Parameters:
- children: String: name of the inner macro to which information is to be sent
Returns:
- ArrayList<MacroMessage>: group of MacroMessage objects
func getTokenKind(UInt16)
public func getTokenKind(no: UInt16): TokenKind
Description: Converts a lexical unit type sequence number to TokenKind.
Parameters:
- no: UInt16: sequence number to be converted
Returns:
func insideParentContext(String)
public func insideParentContext(parentMacroName: String): Bool
Description: Checks whether the current macro call is within a specific macro call and returns a Boolean value.
Note:
- In a nested macro scenario, an inner macro can also communicate with an outer macro by sending a key-value pair. When inner macros are executed, the standard library function setItem is called to send information to outer macros. Then, when the outer macros are executed, the standard library function getChildMessages is called to receive information (a group of key-value pair mappings) sent by each inner macro.
- This function can only be directly called as a function and cannot be assigned to a variable or used as an actual parameter or a return value.
Parameters:
- parentMacroName: String: name of the outer macro call to be checked
Returns:
- Bool: true is returned if the current macro is nested within a specific macro call.
func parseDecl(Tokens, String)
public func parseDecl(input: Tokens, astKind!: String = ""): Decl
Description: Parses a group of lexical units to obtain a node of the Decl type.
Parameters:
- input: Tokens: lexical unit pending source code parsing
- astKind!: String: Specifies the type of the node to be parsed. The valid values are
PrimaryCtorDeclandPropMemberDecl.PrimaryCtorDecl: Parses the primary constructor.PropMemberDecl: Parses the getter and setter functions declared with prop.
Returns:
Throws:
- ParseASTException: If the input Tokens instance cannot be constructed as a Decl node, this exception is thrown.
Example:
-
The following code shows the case where
astKindis set toPropMemberDecl. In this case,parseDeclcan be used to parse the getter and setter functions declared withprop. The parsing results are of theFuncDecltype. IfastKindis not set, the parsing fails because there is nofunckeyword.import std.ast.* main() { let getter = quote( get() { _val } ) let setter = quote( set(v) { _val = v }) let getterDecl = parseDecl(getter, astKind: "PropMemberDecl") let setterDecl = parseDecl(setter, astKind: "PropMemberDecl") println((getterDecl as FuncDecl).getOrThrow().block.toTokens()) println((setterDecl as FuncDecl).getOrThrow().block.toTokens()) }Running result:
{ _val } { _val = v } -
The following code shows the case where
astKindis set toPrimaryCtorDecl. In this case,parseDeclcan be used to parse the primary constructor node. The parsing result is of thePrimaryCtorDecltype. IfastKindis not set, the parsing fails because there is nofunckeyword.import std.ast.* main() { let ctor = quote( Point(var x: Int32, var y: Int32) {} ) let ctorDecl = parseDecl(ctor, astKind: "PrimaryCtorDecl") println(ctorDecl is PrimaryCtorDecl) println(ctorDecl.toTokens()) }Running result:
true Point(var x: Int32, var y: Int32) { }
func parseDeclFragment(Tokens, Int64)
public func parseDeclFragment(input: Tokens, startFrom !: Int64 = 0): (Decl, Int64)
Description: Parses a group of lexical units to obtain a node of the Decl type and an index used to continue parsing.
Parameters:
Returns:
Throws:
- ParseASTException: If the input Tokens instance cannot be constructed as a Decl node, this exception is thrown.
func parseExpr(Tokens)
public func parseExpr(input: Tokens): Expr
Description: Parses a group of lexical units to obtain a node of the Expr type.
Parameters:
- input: Tokens: lexical unit pending source code parsing
Returns:
Throws:
- ParseASTException: If the input Tokens instance cannot be constructed as an Expr node, this exception is thrown.
func parseExprFragment(Tokens, Int64)
public func parseExprFragment(input: Tokens, startFrom !: Int64 = 0): (Expr, Int64)
Description: Parses a group of lexical units to obtain a node of the Expr type and an index used to continue parsing.
Parameters:
Returns:
Throws:
- ParseASTException: If the input Tokens instance cannot be constructed as an Expr node, this exception is thrown.
func parseProgram(Tokens)
public func parseProgram(input: Tokens): Program
Description: Parses the source codes of a single Cangjie file to obtain a node of the Program type.
Parameters:
- input: Tokens: lexical unit pending source code parsing
Returns:
Throws:
- ParseASTException: If the input Tokens instance cannot be constructed as a Program node, this exception is thrown.
func setItem(String, Bool)
public func setItem(key: String, value: Bool): Unit
Description: Sends information of the Bool type from an inner macro to an outer macro.
Note:
This function can only be directly called as a function and cannot be assigned to a variable or used as an actual parameter or a return value.
Parameters:
- key: String: keyword to be sent, used for information search
- value: Bool: information of the Bool type to be sent
func setItem(String, Int64)
public func setItem(key: String, value: Int64): Unit
Description: Sends information of the Int64 type from an inner macro to an outer macro.
Note:
This function can only be directly called as a function and cannot be assigned to a variable or used as an actual parameter or a return value.
Parameters:
- key: String: keyword to be sent, used for information search
- value: Int64: information of the Int64 type to be sent
func setItem(String, String)
public func setItem(key: String, value: String): Unit
Description: Sends information of the String type from an inner macro to an outer macro.
Note:
This function can only be directly called as a function and cannot be assigned to a variable or used as an actual parameter or a return value.
Parameters:
- key: String: keyword to be sent, used for information search
- value: String: information of the String type to be sent
Interface
interface ToBytes
public interface ToBytes {
func toBytes(): Array<UInt8>
}
Description: Provides the serialization function of the corresponding type.
func toBytes()
func toBytes(): Array<UInt8>
Description: Provides the serialization function of the corresponding type.
Returns:
extend Position <: ToBytes
extend Position <: ToBytes
Description: Provides the serialization function of the Position type.
Parent Type:
func toBytes()
public func toBytes(): Array<UInt8>
Description: Provides the serialization function of the Position type.
Returns:
extend Token <: ToBytes
extend Token <: ToBytes
Description: Provides the serialization function of the Token type.
Parent Type:
func toBytes()
public func toBytes(): Array<UInt8>
Description: Provides the serialization function of the Token type.
Returns:
extend Tokens <: ToBytes
extend Tokens <: ToBytes
Description: Provides the serialization function of the Tokens type.
Parent Type:
func toBytes()
public func toBytes(): Array<UInt8>
Description: Provides the serialization function of the Tokens type.
Returns:
interface ToTokens
public interface ToTokens {
func toTokens(): Tokens
}
Description: Converts an instance of the corresponding type to an instance of the Tokens type. To support the quote interpolation operation, this API must be implemented.
func toTokens()
func toTokens(): Tokens
Description: Converts an instance of the corresponding type to an instance of the Tokens type.
Returns:
extend Array <: ToTokens
extend<T> Array<T> <: ToTokens
Description: Converts an instance of the Array type to an instance of the Tokens type.
Parent Type:
func toTokens()
public func toTokens(): Tokens
Description: Converts an instance of the Array type to an instance of the Tokens type. Only the numeric, Rune, Bool, and String types are supported.
Returns:
extend ArrayList <: ToTokens
extend<T> ArrayList<T> <: ToTokens
Description: Converts an instance of the ArrayList type to an instance of the Tokens type.
Parent Type:
func toTokens()
public func toTokens(): Tokens
Description: Converts an instance of the ArrayList type to an instance of the Tokens type. Currently, the Decl, Node, Constructor, Argument, FuncParam, MatchCase, Modifier, Annotation, ImportList, Pattern, and TypeNode types are supported.
Returns:
extend Bool <: ToTokens
extend Bool <: ToTokens
Description: Converts an instance of the Bool type to an instance of the Tokens type.
Parent Type:
func toTokens()
public func toTokens(): Tokens
Description: Converts an instance of the Bool type to an instance of the Tokens type.
Returns:
extend Float16 <: ToTokens
extend Float16 <: ToTokens
Description: Converts an instance of the Float16 type to an instance of the Tokens type.
Parent Type:
func toTokens()
public func toTokens(): Tokens
Description: Converts an instance of the Float16 type to an instance of the Tokens type.
Returns:
extend Float32 <: ToTokens
extend Float32 <: ToTokens
Description: Converts an instance of the Float32 type to an instance of the Tokens type.
Parent Type:
func toTokens()
public func toTokens(): Tokens
Description: Converts an instance of the Float32 type to an instance of the Tokens type.
Returns:
extend Float64 <: ToTokens
extend Float64 <: ToTokens
Description: Converts an instance of the Float64 type to an instance of the Tokens type.
Parent Type:
func toTokens()
public func toTokens(): Tokens
Description: Converts an instance of the Float64 type to an instance of the Tokens type.
Returns:
extend Int16 <: ToTokens
extend Int16 <: ToTokens
Description: Converts an instance of the Int16 type to an instance of the Tokens type.
Parent Type:
func toTokens()
public func toTokens(): Tokens
Description: Converts an instance of the Int16 type to an instance of the Tokens type.
Returns:
extend Int32 <: ToTokens
extend Int32 <: ToTokens
Description: Converts an instance of the Int32 type to an instance of the Tokens type.
Parent Type:
func toTokens()
public func toTokens(): Tokens
Description: Converts an instance of the Int32 type to an instance of the Tokens type.
Returns:
extend Int64 <: ToTokens
extend Int64 <: ToTokens
Description: Converts an instance of the Int64 type to an instance of the Tokens type.
Parent Type:
func toTokens()
public func toTokens(): Tokens
Description: Converts an instance of the Int64 type to an instance of the Tokens type.
Returns:
extend Int8 <: ToTokens
extend Int8 <: ToTokens
Description: Converts an instance of the Int8 type to an instance of the Tokens type.
Parent Type:
func toTokens()
public func toTokens(): Tokens
Description: Converts an instance of the Int8 type to an instance of the Tokens type.
Returns:
extend Rune <: ToTokens
extend Rune <: ToTokens
Description: Converts an instance of the Rune type to an instance of the Tokens type.
Parent Type:
func toTokens()
public func toTokens(): Tokens
Description: Converts an instance of the Rune type to an instance of the Tokens type.
Returns:
extend String <: ToTokens
extend String <: ToTokens
Description: Converts an instance of the String type to an instance of the Tokens type.
Parent Type:
func toTokens()
public func toTokens(): Tokens
Description: Converts an instance of the String type to an instance of the Tokens type.
Returns:
extend Token <: ToTokens
extend Token <: ToTokens
Description: Converts an instance of the Token type to an instance of the Tokens type.
Parent Type:
func toTokens()
public func toTokens(): Tokens
Description: Converts an instance of the Token type to an instance of the Tokens type.
Returns:
extend Tokens <: ToTokens
extend Tokens <: ToTokens
Description: Converts an instance of the Tokens type to an instance of the Tokens type.
Parent Type:
func toTokens()
public func toTokens(): Tokens
Description: Converts an instance of the Tokens type to an instance of the Tokens type.
Returns:
extend UInt16 <: ToTokens
extend UInt16 <: ToTokens
Description: Converts an instance of the UInt16 type to an instance of the Tokens type.
Parent Type:
func toTokens()
public func toTokens(): Tokens
Description: Converts an instance of the UInt16 type to an instance of the Tokens type.
Returns:
extend UInt32 <: ToTokens
extend UInt32 <: ToTokens
Description: Converts an instance of the UInt32 type to an instance of the Tokens type.
Parent Type:
func toTokens()
public func toTokens(): Tokens
Description: Converts an instance of the UInt32 type to an instance of the Tokens type.
Returns:
extend UInt64 <: ToTokens
extend UInt64 <: ToTokens
Description: Converts an instance of the UInt64 type to an instance of the Tokens type.
Parent Type:
func toTokens()
public func toTokens(): Tokens
Description: Converts an instance of the UInt64 type to an instance of the Tokens type.
Returns:
extend UInt8 <: ToTokens
extend UInt8 <: ToTokens
Description: Converts an instance of the UInt8 type to an instance of the Tokens type.
Parent Type:
func toTokens()
public func toTokens(): Tokens
Description: Converts an instance of the UInt8 type to an instance of the Tokens type.
Returns:
Class
class Annotation
public class Annotation <: Node {
public init()
public init(inputs: Tokens)
}
Description: Specifies a built-in annotation node of the compiler.
Examples of an Annotation node: @CallingConv[xxx], @Attribute[xxx], and @When[condition]
Parent Type:
prop arguments
public mut prop arguments: ArrayList<Argument>
Description: Obtains or sets the parameter sequence in Annotation, for example, xxx in @CallingConv[xxx].
prop at
public mut prop at: Token
Description: Obtains or sets the operator @ in an Annotation node.
Type: Token
Throws:
- ASTException: If Token is not the operator
@, this exception is thrown.
prop attributes
public mut prop attributes: Tokens
Description: Obtains or sets an attribute value in Attribute in @Attribute format, for example, xxx in @Attribute[xxx].
Type: Tokens
prop condition
public mut prop condition: Expr
Description: Obtains or sets a condition expression in conditional compilation in @When format, for example, xxx in @When[xxx].
Type: Expr
Throws:
- ASTException: If the Annotation node contains no condition expression, this exception is thrown.
prop identifier
public mut prop identifier: Token
Description: Obtains or sets the identifier of an Annotation node, for example, CallingConv in @CallingConv[xxx].
Type: Token
init()
public init()
Description: Constructs a default Annotation object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs an Annotation object based on input lexical units.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the Annotation type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the Annotation node, this exception is thrown.
class Argument
public class Argument <: Node {
public init()
}
Description: Specifies an argument node in function call.
Example: arg:value in foo(arg:value)
Parent Type:
prop colon
public mut prop colon: Token
Description: Obtains or sets the operator ":" in an Argument node, which may be an ILLEGAL lexical unit.
Type: Token
Throws:
- ASTException: If Token is not the operator colon (:), this exception is thrown.
prop expr
public mut prop expr: Expr
Description: Obtains or sets the expression in an Argument node, for example, value in arg:value.
Type: Expr
prop identifier
public mut prop identifier: Token
Description: Obtains or sets the identifier in an Argument node, for example, arg in arg:value, which may be an ILLEGAL lexical unit.
Type: Token
prop keyword
public mut prop keyword: Token
Description: Obtains or sets the keyword inout in an Argument node, which may be an ILLEGAL lexical unit.
Type: Token
init()
public init()
Description: Constructs a default Argument object.
class ArrayLiteral
public class ArrayLiteral <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies an Array literal node.
An ArrayLiteral node is specified in the format of [element1, element2, ... , elementN], where each element is an expression.
Parent Type:
prop elements
public mut prop elements: ArrayList<Expr>
Description: Obtains or sets the expression list in ArrayLiteral.
prop lSquare
public mut prop lSquare: Token
Description: Obtains or sets the left square bracket ([) in ArrayLiteral.
Type: Token
Throws:
- ASTException: If Token is not a left square bracket ([), this exception is thrown.
prop rSquare
public mut prop rSquare: Token
Description: Obtains or sets the right square bracket (]) in ArrayLiteral.
Type: Token
Throws:
- ASTException: If Token is not a right square bracket (]), this exception is thrown.
init()
public init()
Description: Constructs a default ArrayLiteral object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs an ArrayLiteral object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the ArrayLiteral type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the ArrayLiteral node, this exception is thrown.
class AsExpr
public class AsExpr <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies a type check expression.
An AsExpr expression is in the e as T format and of the Option<T> type. e can be any type of expression, and T can be any type.
Parent Type:
prop expr
public mut prop expr: Expr
Description: Obtains or sets the expression node in an AsExpr node.
Type: Expr
prop keyword
public mut prop keyword: Token
Description: Obtains or sets the operator as in an AsExpr node.
Type: Token
Throws:
- ASTException: If Token is not the operator
as, this exception is thrown.
prop shiftType
public mut prop shiftType: TypeNode
Description: Obtains or sets the target type in an AsExpr node.
Type: TypeNode
init()
public init()
Description: Constructs a default AsExpr object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs an AsExpr object.
Parameters:
Throws:
- ASTException: If the input Tokens type cannot be used to construct the AsExpr node, this exception is thrown.
class AssignExpr
public class AssignExpr <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies an assignment expression node.
Such node changes the value of the left operand to the value of the right operand. Example of an AssignExpr node: a = b
Parent Type:
prop assign
public mut prop assign: Token
Description: Obtains or sets the assignment operator (such as =) in an AssignExpr node.
Type: Token
Throws:
- ASTException: If Token is not an assignment operator, this exception is thrown.
prop leftExpr
public mut prop leftExpr: Expr
Description: Obtains or sets the left operand in an AssignExpr node.
Type: Expr
prop rightExpr
public mut prop rightExpr: Expr
Description: Obtains or sets the right operand in an AssignExpr node.
Type: Expr
init()
public init()
Description: Constructs a default AssignExpr object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs an AssignExpr object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the AssignExpr type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the AssignExpr node, this exception is thrown.
class BinaryExpr
public class BinaryExpr <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies a binary operation expression node.
Examples of a BinaryExpr node: a + b and a - b
Parent Type:
prop leftExpr
public mut prop leftExpr: Expr
Description: Obtains or sets the expression node on the left of the operator in a BinaryExpr node.
Type: Expr
prop op
public mut prop op: Token
Description: Obtains or sets the binary operator in a BinaryExpr node.
Type: Token
prop rightExpr
public mut prop rightExpr: Expr
Description: Obtains or sets the expression node on the right of the operator in a BinaryExpr node.
Type: Expr
init()
public init()
Description: Constructs a default BinaryExpr object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a BinaryExpr object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the BinaryExpr type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the BinaryExpr node, this exception is thrown.
class Block
public class Block <: Expr {
public init()
}
Description: Specifies a block node.
Block is a structure consisting of a pair of matching braces and an optional expression/declaration sequence in them.
Parent Type:
prop lBrace
public mut prop lBrace: Token
Description: Obtains or sets the left curly bracket ({) in a Block.
Type: Token
Throws:
- ASTException: If Token is not a left curly bracket ({), this exception is thrown.
prop nodes
public mut prop nodes: ArrayList<Node>
Description: Obtains or sets the expression or declaration sequence in Block.
prop rBrace
public mut prop rBrace: Token
Description: Obtains or sets the right curly bracket (}) in a Block.
Type: Token
Throws:
- ASTException: If Token is not a right curly bracket (}), this exception is thrown.
init()
public init()
Description: Constructs a default Block object.
Note:
A Block node cannot exist independently of the expression or declaration node. Therefore, no other constructor is provided.
class Body
public class Body <: Node {
public init()
public init(decls: ArrayList<Decl>)
}
Description: Specifies a structure of Class, Struct, or Interface type, or consisting of {} and a group of declaration nodes in the extension.
Parent Type:
prop decls
public mut prop decls: ArrayList<Decl>
Description: Obtains or sets the set of declaration nodes in Body.
prop lBrace
public mut prop lBrace: Token
Description: Obtains or sets the lexical unit {.
Type: Token
Throws:
- ASTException: If Token is not the lexical unit
{, this exception is thrown.
prop rBrace
public mut prop rBrace: Token
Description: Obtains or sets the lexical unit }.
Type: Token
Throws:
- ASTException: If Token is not the lexical unit
}, this exception is thrown.
init()
public init()
Description: Constructs a default Body object.
init(ArrayList<Decl>)
public init(decls: ArrayList<Decl>)
Description: Constructs a Body object.
Parameters:
class CallExpr
public class CallExpr <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies a function call node.
A CallExpr node contains an expression followed by a parameter list, for example, foo(100).
Parent Type:
prop arguments
public mut prop arguments: ArrayList<Argument>
Description: Obtains or sets the function parameters in a CallExpr node.
prop callFunc
public mut prop callFunc: Expr
Description: Obtains or sets the function call node in a CallExpr node.
Type: Expr
prop lParen
public mut prop lParen: Token
Description: Obtains or sets the left parenthesis "(" in a CallExpr node.
Type: Token
Throws:
- ASTException: If Token is not a left parenthesis "(", this exception is thrown.
prop rParen
public mut prop rParen: Token
Description: Obtains or sets the right parenthesis ")" in a CallExpr node.
Type: Token
Throws:
- ASTException: If Token is not a right parenthesis ")", this exception is thrown.
init()
public init()
Description: Constructs a default CallExpr object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a CallExpr object.
Parameters:
Throws:
- ASTException: If the input Tokens type cannot be used to construct the CallExpr node, this exception is thrown.
class ClassDecl
public class ClassDecl <: Decl {
public init()
public init(inputs: Tokens)
}
Description: Specifies a class definition node.
A class is defined using the keyword class in the following sequence: modifier (default or not), class keyword, class name, optional type parameter, whether to specify a parent class or interface, optional generic constraint, and class body.
Parent Type:
prop body
public mut prop body: Body
Description: Obtains or sets the class body of a ClassDecl node.
Type: Body
prop superTypeBitAnds
public mut prop superTypeBitAnds: Tokens
Description: Obtains or sets the lexical unit sequence of the operator & in the parent class or parent interface declaration of a ClassDecl node. The lexical unit sequence may be empty.
Type: Tokens
Throws:
- ASTException: If Tokens is not the lexical unit sequence
&, this exception is thrown.
prop superTypes
public mut prop superTypes: ArrayList<TypeNode>
Description: Obtains or sets the parent class or parent interface of a ClassDecl node.
prop upperBound
public mut prop upperBound: Token
Description: Obtains or sets the operator <:.
Type: Token
Throws:
- ASTException: If Token is not the operator
<:, this exception is thrown.
init()
public init()
Description: Constructs a default ClassDecl object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a ClassDecl object.
Parameters:
- inputs: [Tokens](ast_package_classes.md#class-tokens: collection of lexical units (Tokens) used to construct the ClassDecl type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the ClassDecl node, this exception is thrown.
class ConstPattern
public class ConstPattern <: Pattern {
public init()
public init(inputs: Tokens)
}
Description: Specifies a constant pattern node.
The constant pattern can be an integer literal, a character byte literal, a floating-point number literal, a character literal, a Boolean literal, a character string literal, or the like, for example, 1 in case 1 => 0.
Parent Type:
prop litConstExpr
public mut prop litConstExpr: LitConstExpr
Description: Obtains or sets the literal expression in a ConstPattern node.
Type: LitConstExpr
init()
public init()
Description: Constructs a default ConstPattern object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a ConstPattern object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the ConstPattern type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the ConstPattern node, this exception is thrown.
class Constructor
public class Constructor <: Node {
public init()
}
Description: Specifies a Constructor node in the enum type.
Example of a Constructor node: Year and Month(Float32, Float32) in enum TimeUnit { Year | Month(Float32, Float32)}
Note:
Constructor may have no parameter or a group of parameters of different types.
Parent Type:
prop identifier
public mut prop identifier: Token
Description: Obtains or sets the lexical unit identifier of Constructor.
Type: Token
prop lParen
public mut prop lParen: Token
Description: Obtains or sets the lexical unit left parenthesis "(" in a Constructor node.
Type: Token
Throws:
- ASTException: If Token is not a left parenthesis "(", this exception is thrown.
prop rParen
public mut prop rParen: Token
Description: Obtains or sets the lexical unit right parenthesis ")" in a Constructor node.
Type: Token
Throws:
- ASTException: If Token is not a right parenthesis ")", this exception is thrown.
prop typeArguments
public mut prop typeArguments: ArrayList<TypeNode>
Description: Obtains or sets the collection of optional parameter type nodes for a Constructor node.
init()
public init()
Description: Constructs a default Constructor object.
class Decl
public open class Decl <: Node
Description: Specifies the parent class of all declaration nodes, which is inherited from a Node node and provides universal APIs for all declaration nodes.
Note:
Class definition, interface definition, function definition, variable definition, enumeration definition, struct definition, extension definition, type alias definition, and macro definition all belong to a Decl node.
Parent Type:
prop annotations
public mut prop annotations: ArrayList<Annotation>
Description: Obtains or sets the annotation list applying to a Decl node.
Type: ArrayList<Annotation>
prop constraintCommas
public mut prop constraintCommas: Tokens
Description: Obtains or sets the lexical unit sequence comma (,) in a Decl node. The lexical unit sequence may be empty.
Type: Tokens
Throws:
- ASTException: If Tokens is not the lexical unit sequence comma (,), this exception is thrown.
prop genericConstraint
public mut prop genericConstraint: ArrayList<GenericConstraint>
Description: Obtains or sets the generic constraint for defining a node, which may be empty, for example, where T <: Comparable<T> in func foo<T>() where T <: Comparable<T> {}.
Type: ArrayList<GenericConstraint>
prop genericParam
public mut prop genericParam: GenericParam
Description: Obtains or sets a formal parameter list. A type formal parameter list is enclosed by <>. Multiple type formal parameters are separated by commas (,).
Type: GenericParam
Throws:
- ASTException: If the type formal parameter list is not defined for the node, this exception is thrown.
prop identifier
public mut open prop identifier: Token
Description: Obtains or sets the identifier for defining a node, for example, foo in class foo {}.
Type: Token
prop isGenericDecl()
public mut prop isGenericDecl: Bool
Description: Checks whether a node is a generic node.
Type: Bool: If the node is a generic node, true is returned. Otherwise, false is returned.
prop keyword
public mut prop keyword: Token
Description: Obtains or sets the keyword for defining a node.
Type: Token
prop modifiers
public mut prop modifiers: ArrayList<Modifier>
Description: Obtains or sets the list of modifiers for modifying a node.
func getAttrs()
public func getAttrs(): Tokens
Description: Obtains attributes of the current node. (Generally, a built-in Attribute is used to set a declared attribute value.)
Returns:
- Tokens: attributes of the current node
func hasAttr(String)
public func hasAttr(attr: String): Bool
Description: Checks whether the current node has a certain attribute. (Generally, a built-in Attribute is used to set a declared attribute value.)
Parameters:
- attr: String: attribute to be checked for whether it belongs to the node
Returns:
- Bool: If the current node has the attribute, true is returned. Otherwise, false is returned.
class DoWhileExpr
public class DoWhileExpr <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies a do-while expression.
Parent Type:
prop block
public mut prop block: Block
Description: Obtains or sets the block expression in DoWhileExpr.
Type: Block
prop condition
public mut prop condition: Expr
Description: Obtains or sets the condition expression in the keyword DoWhileExpr.
Type: Expr
prop keywordD
public mut prop keywordD: Token
Description: Obtains or sets the keyword do in a DoWhileExpr node. D in keywordD is the uppercase first letter of the keyword do, indicating the keyword do.
Type: Token
Throws:
- ASTException: If Token is not the keyword
do, this exception is thrown.
prop keywordW
public mut prop keywordW: Token
Description: Obtains or sets the keyword while in a DoWhileExpr node. W in keywordW is the uppercase first letter of the keyword while, indicating the keyword while.
Type: Token
Throws:
- ASTException: If Token is not the keyword
while, this exception is thrown.
prop lParen
public mut prop lParen: Token
Description: Obtains or sets the left parenthesis "(" following the keyword while in DoWhileExpr.
Type: Token
Throws:
- ASTException: If Token is not a left parenthesis "(" this exception is thrown.
prop rParen
public mut prop rParen: Token
Description: Obtains or sets the right parenthesis ")" following the keyword while in DoWhileExpr.
Type: Token
Throws:
- ASTException: If Token is not a right parenthesis ")" this exception is thrown.
init()
public init()
Description: Constructs a default DoWhileExpr object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a DoWhileExpr object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the DoWhileExpr type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the DoWhileExpr node, this exception is thrown.
class EnumDecl
public class EnumDecl <: Decl {
public init()
public init(inputs: Tokens)
}
Description: Specifies an Enum definition node.
Enum is defined using the keyword enum in the following sequence: modifier (default or not), enum keyword, enum name, optional type parameter, whether to specify a parent interface, optional generic constraint, and enum body.
Parent Type:
prop constructors
public mut prop constructors: ArrayList<Constructor>
Description: Obtains or sets the constructors in an EnumDecl node.
Type: ArrayList<Constructor>
prop decls
public mut prop decls: ArrayList<Decl>
Description: Obtains or sets members other than constructors in an EnumDecl node.
prop lBrace
public mut prop lBrace: Token
Description: Obtains or sets the { lexical unit type of an EnumDecl node.
Type: Token
Throws:
- ASTException: If Token is not the lexical unit type
{, this exception is thrown.
prop rBrace
public mut prop rBrace: Token
Description: Obtains or sets the } lexical unit type of an EnumDecl node.
Type: Token
Throws:
- ASTException: If Token is not the lexical unit type
}, this exception is thrown.
prop superTypeBitAnds
public mut prop superTypeBitAnds: Tokens
Description: Obtains or sets the lexical unit sequence of the operator & in the parent interface declaration of an EnumDecl node. The lexical unit sequence may be empty.
Type: Tokens
Throws:
- ASTException: If Tokens is not the lexical unit sequence
&, this exception is thrown.
prop superTypes
public mut prop superTypes: ArrayList<TypeNode>
Description: Obtains or sets the parent interface of an EnumDecl node.
prop upperBound
public mut prop upperBound: Token
Description: Obtains or sets the operator <:.
Type: Token
Throws:
- ASTException: If Token is not the operator
<:, this exception is thrown.
init()
public init()
Description: Constructs a default EnumDecl object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs an EnumDecl object.
Parameters:
Throws:
- ASTException: If the input Tokens type cannot be used to construct the EnumDecl node, this exception is thrown.
class EnumPattern
public class EnumPattern <: Pattern {
public init()
public init(inputs: Tokens)
}
Description: Specifies an enum pattern node.
Such node is used to match the constructor of enum, for example, Year(n) in case Year(n) => 1.
Parent Type:
prop commas
public mut prop commas: Tokens
Description: Obtains or sets the lexical unit sequence comma (,) in an EnumPattern node. The lexical unit sequence may be empty.
Type: Tokens
Throws:
- ASTException: If Tokens is not the lexical unit sequence comma (,), this exception is thrown.
prop constructor
public mut prop constructor: Expr
Description: Obtains or sets the constructor expression node in an EnumPattern node.
Type: Expr
prop lParen
public mut prop lParen: Token
Description: Obtains or sets the lexical unit left parenthesis "(" in an EnumPattern node.
Type: Token
Throws:
- ASTException: If Token is not a left parenthesis "(", this exception is thrown.
prop patterns
public mut prop patterns: ArrayList<Pattern>
Description: Obtains or sets the list of pattern nodes in the parameterized constructor in an EnumPattern node.
prop rParen
public mut prop rParen: Token
Description: Obtains or sets the lexical unit right parenthesis ")" in an EnumPattern node.
Type: Token
Throws:
- ASTException: If Token is not a right parenthesis ")", this exception is thrown.
init()
public init()
Description: Constructs a default EnumPattern object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs an EnumPattern object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the EnumPattern type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the EnumPattern node, this exception is thrown.
class ExceptTypePattern
public class ExceptTypePattern <: Pattern {
public init()
public init(inputs: Tokens)
}
Description: Specifies a node used in exception pattern.
Example: e: Exception1 | Exception2
Parent Type:
prop colon
public mut prop colon: Token
Description: Obtains or sets the lexical unit of the operator colon (:) in an ExceptTypePattern node.
Type: Token
Throws:
- ASTException: If Token is not the operator colon (:), this exception is thrown.
prop pattern
public mut prop pattern: Pattern
Description: Obtains or sets the pattern node in an ExceptTypePattern node.
Type: Pattern
prop types
public mut prop types: ArrayList<TypeNode>
Description: Obtains or sets the type list in an ExceptTypePattern node.
init()
public init()
Description: Constructs a default ExceptTypePattern object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs an ExceptTypePattern object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the ExceptTypePattern type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the ExceptTypePattern node, this exception is thrown.
class Expr
public open class Expr <: Node
Description: Specifies the parent class of all expression nodes, which is inherited from a Node node.
The toTokens method of an expression node adds parentheses based on the operator priority. For example, if the left expression a of the BinaryExpr node a * b is modified to a + 1, the toTokens method adds parentheses to the left expression, and (a + 1) * b is outputted.
Parent Type:
class ExtendDecl
public class ExtendDecl <: Decl {
public init()
public init(inputs: Tokens)
}
Description: Specifies an extension definition node.
Extension is defined using the keyword extend in the following sequence: extend keyword, extension type, whether to specify a parent interface, optional generic constraint, and extension body.
Parent Type:
prop body
public mut prop body: Body
Description: Obtains or sets the class body of an ExtendDecl node.
Type: Body
prop extendType
public mut prop extendType: TypeNode
Description: Obtains or sets the extension type.
Type: TypeNode
prop identifier
public mut override prop identifier: Token
Description: The ExtendDecl node inherits a Decl node but does not support the identifier attribute, whose usage triggers an exception.
Type: Token
Throws:
- ASTException: If the
identifierattribute is used, this exception is thrown.
prop superTypeBitAnds
public mut prop superTypeBitAnds: Tokens
Description: Obtains or sets the lexical unit sequence of the operator & in the parent interface declaration of an ExtendDecl node. The lexical unit sequence may be empty.
Type: Tokens
Throws:
- ASTException: If Tokens is not the lexical unit sequence
&, this exception is thrown.
prop superTypes
public mut prop superTypes: ArrayList<TypeNode>
Description: Obtains or sets the parent interface of an ExtendDecl node.
prop upperBound
public mut prop upperBound: Token
Description: Obtains or sets the operator <:.
Type: Token
Throws:
- ASTException: If Token is not the operator
<:, this exception is thrown.
init()
public init()
Description: Constructs a default ExtendDecl object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs an ExtendDecl object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the [ExtendDecl](ast_package_classes.md#class-extenddecl type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the ExtendDecl node, this exception is thrown.
class ForInExpr
public class ForInExpr <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies a for-in expression.
In the ForInExpr type, the keyword for is followed by Pattern, the keyword in and expression node, and an execution loop body Block.
Parent Type:
prop block
public mut prop block: Block
Description: Obtains or sets the loop body in ForInExpr.
Type: Block
prop expr
public mut prop expr: Expr
Description: Obtains or sets an expression in ForInExpr.
Type: Expr
prop keywordF
public mut prop keywordF: Token
Description: Obtains or sets the keyword for in ForInExpr.
Type: Token
Throws:
- ASTException: If Token is not the keyword
for, this exception is thrown.
prop keywordI
public mut prop keywordI: Token
Description: Obtains or sets the keyword in in ForInExpr.
Type: Token
Throws:
- ASTException: If Token is not the keyword
in, this exception is thrown.
prop keywordW
public mut prop keywordW: Token
Description: Obtains or sets the keyword where in ForInExpr.
Type: Token
Throws:
- ASTException: If Token is not the keyword
where, this exception is thrown.
prop lParen
public mut prop lParen: Token
Description: Obtains or sets the left parenthesis "(" following the keyword for in ForInExpr.
Type: Token
Throws:
- ASTException: If Token is not a left parenthesis "(", this exception is thrown.
prop pattern
public mut prop pattern: Pattern
Description: Obtains or sets the Pattern node in ForInExpr.
Type: Pattern
prop patternGuard
public mut prop patternGuard: Expr
Description: Obtains or sets the patternGuard condition expression in ForInExpr.
Type: Expr
Throws:
- ASTException: If the ForInExpr node contains no
patternGuardcondition expression, this exception is thrown.
prop rParen
public mut prop rParen: Token
Description: Obtains or sets the right parenthesis ")" in ForInExpr.
Type: Token
Throws:
- ASTException: If Token is not a right parenthesis ")", this exception is thrown.
init()
public init()
Description: Constructs a default ForInExpr object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a ForInExpr object.
Parameters:
Throws:
- ASTException: If the input Tokens type cannot be used to construct the ForInExpr node, this exception is thrown.
class FuncDecl
public class FuncDecl <: Decl {
public init()
public init(inputs: Tokens)
}
Description: Specifies a function definition node.
A function is defined by an optional function modifier, the keyword func, a function name, an optional type formal parameter list, function parameters, and a function return type (default or not). A function body is a block and mandatory during definition.
Parent Type:
prop block
public mut prop block: Block
Description: Obtains or sets the function body of a FuncDecl node.
Type: Block
prop colon
public mut prop colon: Token
Description: Obtains or sets colons (:) of a FuncDecl node.
Type: Token
Throws:
- ASTException: If Token is not a colon (:), this exception is thrown.
prop declType
public mut prop declType: TypeNode
Description: Obtains or sets the function return type of a FuncDecl node.
Type: TypeNode
Throws:
- ASTException: When the FuncDecl node returns a default value, this exception is thrown.
prop funcParams
public mut prop funcParams: ArrayList<FuncParam>
Description: Obtains or sets the function parameters of a FuncDecl node.
prop lParen
public mut prop lParen: Token
Description: Obtains or sets the left parenthesis "(" in a FuncDecl node.
Type: Token
Throws:
- ASTException: If Token is not a left parenthesis "(", this exception is thrown.
prop overloadOp
public mut prop overloadOp: Tokens
Description: Obtains or sets the overload operator of a FuncDecl node.
Type: Tokens
prop rParen
public mut prop rParen: Token
Description: Obtains or sets the right parenthesis ")" in a FuncDecl node.
Type: Token
Throws:
- ASTException: If Token is not a right parenthesis ")", this exception is thrown.
init()
public init()
Description: Constructs a default FuncDecl object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a FuncDecl object.
Parameters:
Throws:
- ASTException: If the inputTokens type cannot be used to construct the FuncDecl node, this exception is thrown.
func isConst()
public func isConst(): Bool
Description: Checks whether a node is of the Const type.
Returns:
- Bool: If the node is of the
Consttype, true is returned. Otherwise, false is returned.
class FuncParam
public open class FuncParam <: Decl {
public init()
public init(inputs: Tokens)
}
Description: Specifies a function parameter node, including non-named parameters and named parameters.
Example of a FuncParam node: a: Int64 and b: Float64 in func foo(a: Int64, b: Float64) {...}
Parent Type:
prop assign
public mut prop assign: Token
Description: Obtains or sets = in a function parameter with a default value.
Type: Token
Throws:
- ASTException: If Token is not
=, this exception is thrown.
prop colon
public mut prop colon: Token
Description: Obtains or sets the colon (:) in a formal parameter.
Type: Token
Throws:
- ASTException: If Token is not a colon (:), this exception is thrown.
prop expr
public mut prop expr: Expr
Description: Obtains or sets the variable initialization node of a function parameter with a default value.
Type: Expr
Throws:
- ASTException: If the function parameters are not initialized, this exception is thrown.
prop not
public mut prop not: Token
Description: Obtains or sets ! in named formal parameters.
Type: Token
Throws:
- ASTException: If Token is not
!, this exception is thrown.
prop paramType
public mut prop paramType: TypeNode
Description: Obtains or sets the type of function parameters.
Type: TypeNode
init()
public init()
Description: Constructs a default FuncParam object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a FuncParam object.
Parameters:
Throws:
- ASTException: If the input Tokens type cannot be used to construct the FuncParam node, this exception is thrown.
func isMemberParam()
public func isMemberParam(): Bool
Description: Specifies whether the current function parameter is in a primary constructor.
Returns:
- Bool: Boolean type. If the parameter is in the primary constructor,
trueis returned.
class FuncType
public class FuncType <: TypeNode {
public init()
public init(inputs: Tokens)
}
Description: Specifies a function type node.
The node consists of the parameter type and return type of the function. The parameter type and return type are separated by ->, for example, (Int32) -> Unit.
Parent Type:
prop arrow
public mut prop arrow: Token
Description: Obtains or sets the lexical unit -> between the parameter type and return type of a FuncType node.
Type: Token
Throws:
- ASTException: If Token is not the lexical unit
->, this exception is thrown.
prop commas
public mut prop commas: Tokens
Description: Obtains or sets the lexical unit sequence comma (,) in a FuncType node. The lexical unit sequence may be empty.
Type: Tokens
Throws:
- ASTException: If Tokens is not the lexical unit sequence comma (,), this exception is thrown.
prop keyword
public mut prop keyword: Token
Description: Obtains or sets the lexical unit keyword CFunc in a FuncType node. If the type is not CFunc, an ILLEGAL lexical unit is obtained.
Type: Token
prop lParen
public mut prop lParen: Token
Description: Obtains or sets the lexical unit left parenthesis "(" in a FuncType node.
Type: Token
Throws:
- ASTException: If Token is not a left parenthesis "(", this exception is thrown.
prop rParen
public mut prop rParen: Token
Description: Obtains or sets the lexical unit right parenthesis ")" in a FuncType node.
Type: Token
Throws:
- ASTException: If Token is not a right parenthesis ")", this exception is thrown.
prop returnType
public mut prop returnType: TypeNode
Description: Obtains or sets the FuncType return type node.
Type: TypeNode
prop types
public mut prop types: ArrayList<TypeNode>
Description: Obtains or sets the parameter type list of the function in a FuncType node.
init()
public init()
Description: Constructs a default FuncType object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a FuncType object.
Parameters:
Throws:
- ASTException: If the input Tokens type cannot be used to construct the FuncType node, this exception is thrown.
class GenericConstraint
public class GenericConstraint <: Node {
public init()
}
Description: Specifies a generic constraint node.
Example of a GenericConstraint node: where where U <: Bounded in interface Enumerable<U> where U <: Bounded {}
Note:
The node is declared by the operator
<:afterwhereand consists of a lower bound and an upper bound. The part on the left of<:is referred to as the lower constraint bound, which can only be a type variable. The part on the right of<:is referred to as the upper constraint bound, which can be a type.
Parent Type:
prop bitAnds
public mut prop bitAnds: Tokens
Description: Obtains or sets the lexical unit sequence of the operator & in a GenericConstraint node. The lexical unit sequence may be empty.
Type: Tokens
Throws:
- ASTException: If Tokens is not the lexical unit sequence
&, this exception is thrown.
prop keyword
public mut prop keyword: Token
Description: Obtains or sets the lexical unit keyword where in a GenericConstraint node, which may be an ILLEGAL lexical unit.
Type: Token
Throws:
- ASTException: If Token is not the keyword
where, this exception is thrown.
prop typeArgument
public mut prop typeArgument: TypeNode
Description: Obtains or sets the lower constraint bound in a GenericConstraint node.
Type: TypeNode
prop upperBound
public mut prop upperBound: Token
Description: Obtains or sets the operator <: in a GenericConstraint node.
Type: Token
Throws:
- ASTException: If Token is not the operator
<:, this exception is thrown.
prop upperBounds
public mut prop upperBounds: ArrayList<TypeNode>
Description: Obtains or sets a collection of TypeNode type nodes on the upper constraint bound of a GenericConstraint node.
init()
public init()
Description: Constructs a default GenericConstraint object.
class GenericParam
public class GenericParam <: Node {
public init()
public init(parameters: Tokens)
}
Description: Specifies a type formal parameter node.
Example of a GenericParam node: <T1, T2, T3>
Note:
Type formal parameters are enclosed in
<>, and multiple type formal parameter names are separated by,.
Parent Type:
prop lAngle
public mut prop lAngle: Token
Description: Obtains or sets the lexical unit left angle bracket in a GenericParam node.
Type: Token
Throws:
- ASTException: If Token is not a left angle bracket, this exception is thrown.
prop parameters
public mut prop parameters: Tokens
Description: Obtains or sets the Tokens type of the type formal parameters in a GenericParam node. The type may be empty, for example, T1, T2, and T3 in <T1, T2, T3>.
Type: Tokens
prop rAngle
public mut prop rAngle: Token
Description: Obtains or sets the lexical unit right angle bracket in a GenericParam node.
Type: Token
Throws:
- ASTException: If Token is not a right angle bracket, this exception is thrown.
init()
public init()
Description: Constructs a default GenericParam object.
init(Tokens)
public init(parameters: Tokens)
Description: Constructs a GenericParam object.
Parameters:
- parameters: Tokens: collection of lexical units (Tokens) used to construct the type formal parameters of GenericParam
class IfExpr
public class IfExpr <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies a condition expression.
Which code branch to be executed can be determined based on whether a condition is met. An IfExpr node has the keyword if, followed by a pair of parentheses in which an expression, or a deconstruction match declared by let is enclosed, a Block, and an optional else branch. The else branch starts with the keyword else, followed by a new if expression or a Block.
Parent Type:
prop condition
public mut prop condition: Expr
Description: Obtains or sets the condition expression after if in an IfExpr node.
Type: Expr
prop elseExpr
public mut prop elseExpr: Expr
Description: Obtains or sets the else branch node in an IfExpr node.
Type: Expr
Throws:
- ASTException: The current IfExpr node has no else branch node.
prop ifBlock
public mut prop ifBlock: Block
Description: Obtains or sets the block node after if in an IfExpr node.
Type: Block
prop keywordE
public mut prop keywordE: Token
Description: Obtains or sets the keyword else in an IfExpr node.
Type: Token
Throws:
- ASTException: If Token is not the keyword
else, this exception is thrown.
prop keywordI
public mut prop keywordI: Token
Description: Obtains or sets the keyword if in an IfExpr node.
Type: Token
Throws:
- ASTException: If Token is not the keyword
if, this exception is thrown.
prop lParen
public mut prop lParen: Token
Description: Obtains or sets the left parenthesis "(" following if in an IfExpr node.
Type: Token
Throws:
- ASTException: If Token is not a left parenthesis "(", this exception is thrown.
prop rParen
public mut prop rParen: Token
Description: Obtains or sets the right parenthesis ")" following if in an IfExpr node.
Type: Token
Throws:
- ASTException: If Token is not a right parenthesis ")", this exception is thrown.
init()
public init()
Description: Constructs a default IfExpr object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs an IfExpr object.
Parameters:
Throws:
- ASTException: If the input Tokens type cannot be used to construct the IfExpr node, this exception is thrown.
class ImportContent
public class ImportContent <: Node {
public init()
}
Parent Type:
prop importKind
public mut prop importKind: ImportKind
Description: Obtains or sets the import type in an ImportContent node.
Type: ImportKind
prop prefixPaths
public mut prop prefixPaths: Tokens
Description: Obtains or sets the lexical unit sequence of the prefix of a full package name in an ImportContent node. The lexical unit sequence may be empty. Example: a and b in import a.b.c.
Type: Tokens
prop prefixDots
public mut prop prefixDots: Tokens
Description: Obtains or sets the lexical unit sequence used to separate the subpackage layers in a full package name in an ImportContent node. The lexical unit sequence may be empty. Example: two periods (.) in import a.b.c.
Type: Tokens
Throws:
- ASTException: If Tokens is not the lexical unit sequence period (.), this exception is thrown.
prop identifier
public mut prop identifier: Token
Description: Obtains or sets the item imported in an ImportContent node. It may be a top-level definition or declaration in a package, or may be the name of a subpackage.
Type: Token
prop importAlias
public mut prop importAlias: Tokens
Description: Obtains or sets the alias lexical unit sequence of the definition or declaration imported in an ImportContent node. It is not empty only when importKind is ImportKind.Alias, for example, as yyy in import packageName.xxx as yyy.
Type: Tokens
prop lBrace
public mut prop lBrace: Token
Description: Obtains or sets the operator lexical unit { in an ImportContent node. It is not empty only when importKind is ImportKind.Multi.
Type: Token
Throws:
- ASTException: If Token is not the operator
{, this exception is thrown.
prop items
public mut prop items: ArrayList<ImportContent>
Description: Obtains or sets all items imported in an ImportContent node. It is not empty only when importKind is ImportKind.Multi.
Type: ArrayList<ImportContent>
prop commas
public mut prop commas: Tokens
Description: Obtains or sets the operator lexical unit comma (,) in an ImportContent node. It is not empty only when importKind is ImportKind.Multi.
Type: Tokens
Throws:
- ASTException: If Tokens is not the lexical unit sequence comma (,), this exception is thrown.
prop rBrace
public mut prop rBrace: Token
Description: Obtains or sets the operator lexical unit } in an ImportContent node. It is not empty only when importKind is ImportKind.Multi.
Type: Token
Throws:
- ASTException: If Token is not the operator
}, this exception is thrown.
init()
public init()
Description: Constructs a default ImportContent object.
func isImportAlias()
public func isImportAlias(): Bool
Description: Checks whether an ImportContent node has an alias for the imported item.
Returns:
- Bool: whether the ImportContent node has an alias for the imported item
func isImportAll()
public func isImportAll(): Bool
Description: Checks whether full import is configured for an ImportContent node.
Returns:
- Bool: whether full import is configured for the ImportContent node
func isImportMulti()
public func isImportMulti(): Bool
Description: Checks whether multiple top-level definitions or declarations are imported in an ImportContent node.
Returns:
- Bool: whether multiple top-level definitions or declarations are imported in the ImportContent node
func isImportSingle()
public func isImportSingle(): Bool
Description: Checks whether single import is configured for an ImportContent node.
Returns:
- Bool: whether single import is configured for the ImportContent node
class ImportList
public class ImportList <: Node {
public init()
public init(inputs: Tokens)
}
Description: Specifies a package import node.
One ImportList node: import moduleName.packageName.foo as bar.
Note:
The import node starts with an optional access modifier (
public/protected/internal/private) and the keywordimport. Takeimport pkga.pkgb.itemas an example.pkga.pkgbis the name of the package where an imported top-level definition or declaration resides, anditemis the imported top-level definition or declaration.
Parent Type:
prop modifier
public mut prop modifier: Token
Description: Obtains or sets the modifier in an ImportList node, which may be an ILLEGAL lexical unit.
Type: Token
prop keywordI
public mut prop keywordI: Token
Description: Obtains or sets the lexical unit keyword import in an ImportList node. I is the first letter of the keyword.
Type: Token
prop content
public mut prop content: ImportContent
Description: Obtains or sets an imported item in an ImportList node, for example, a.b.c in import a.b.c.
Type: ImportContent
init()
public init()
Description: Constructs a default ImportList object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs an ImportList object.
Parameters:
- inputs: Tokens: the sequence of collection of lexical units (Tokens) used to construct the ImportList type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the ImportList node, this exception is thrown.
func isImportMulti()
public func isImportMulti(): Bool
Description: Checks whether multiple top-level definitions or declarations are imported to an ImportList node.
Returns:
- Bool: If multiple top-level definitions or declarations are imported to the ImportList node, true is returned. Otherwise, false is returned.
class IncOrDecExpr
public class IncOrDecExpr <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies an expression that contains an auto-increment operator (++) or auto-decrement operator (--).
Parent Type:
prop expr
public mut prop expr: Expr
Description: Obtains or sets an expression in IncOrDecExpr.
Type: Expr
prop op
public mut prop op: Token
Description: Obtains or sets an operator in IncOrDecExpr.
Type: Token
init()
public init()
Description: Constructs a default IncOrDecExpr object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs an IncOrDecExpr object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the IncOrDecExpr type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the IncOrDecExpr node, this exception is thrown.
class InterfaceDecl
public class InterfaceDecl <: Decl {
public init()
public init(inputs: Tokens)
}
Description: Specifies an interface definition node.
An interface is defined using the keyword interface in the following sequence: modifier (default or not), interface keyword, interface name, optional type parameter, whether to specify a parent interface, optional generic constraint, and interface body.
Parent Type:
prop body
public mut prop body: Body
Description: Obtains or sets the class body of an InterfaceDecl node.
Type: Body
prop superTypeBitAnds
public mut prop superTypeBitAnds: Tokens
Description: Obtains or sets the lexical unit sequence of the operator & in the parent interface declaration of an InterfaceDecl node. The lexical unit sequence may be empty.
Type: Tokens
Throws:
- ASTException: If Tokens is not the lexical unit sequence
&, this exception is thrown.
prop superTypes
public mut prop superTypes: ArrayList<TypeNode>
Description: Obtains or sets the parent interface of an InterfaceDecl node.
prop upperBound
public mut prop upperBound: Token
Description: Obtains or sets the operator <:.
Type: Token
Throws:
- ASTException: If Token is not the operator
<:, this exception is thrown.
init()
public init()
Description: Constructs a default InterfaceDecl object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs an InterfaceDecl object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the InterfaceDecl type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the InterfaceDecl node, this exception is thrown.
class IsExpr
public class IsExpr <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies a type check expression.
An IsExpr expression is in the e is T format and of the Bool type. e can be any type of expression, and T can be any type.
Parent Type:
prop exprs
public mut prop expr: Expr
Description: Obtains or sets the expression node in an IsExpr node.
Type: Expr
prop keyword
public mut prop keyword: Token
Description: Obtains or sets the operator is in an IsExpr node.
Type: Token
Throws:
- ASTException: If Token is not the operator
is, this exception is thrown.
prop shiftType
public mut prop shiftType: TypeNode
Description: Obtains or sets the target type in an IsExpr node.
Type: TypeNode
init()
public init()
Description: Constructs a default IsExpr object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs an IsExpr object.
Parameters:
Throws:
- ASTException: If the input Tokens type cannot be used to construct the IsExpr node, this exception is thrown.
class JumpExpr
public class JumpExpr <: Expr {
public init()
public init(kind: Tokens)
}
Description: Specifies break and continue in the body of a loop expression.
Parent Type:
prop keyword
public mut prop keyword: Token
Description: Obtains or sets a keyword.
Type: Token
init()
public init()
Description: Constructs a default JumpExpr object.
init(Tokens)
public init(kind: Tokens)
Description: Constructs a JumpExpr object.
Parameters:
Throws:
- ASTException: If the input Tokens type cannot be used to construct the JumpExpr node, this exception is thrown.
class LambdaExpr
public class LambdaExpr <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies a Lambda expression, which is an anonymous function.
A LambdaExpr node may have formal parameters, for example, {a: Int64 => e1; e2 }, or have no formal parameter, for example, { => e1; e2 }.
Parent Type:
prop doubleArrow
public mut prop doubleArrow: Token
Description: Obtains or sets => in LambdaExpr.
Type: Token
Throws:
- ASTException: If Token is not the operator
=>, this exception is thrown.
prop funcParams
public mut prop funcParams: ArrayList<FuncParam>
Description: Obtains or sets the parameter list in LambdaExpr.
prop lBrace
public mut prop lBrace: Token
Description: Obtains or sets the left curly bracket ({) in LambdaExpr.
Type: Token
Throws:
- ASTException: If Token is not a left curly bracket ({), this exception is thrown.
prop nodes
public mut prop nodes: ArrayList<Node>
Description: Obtains or sets the expression or declaration node in LambdaExpr.
prop rBrace
public mut prop rBrace: Token
Description: Obtains or sets the right curly bracket (}) in LambdaExpr.
Type: Token
Throws:
- ASTException: If Token is not a right curly bracket (}), this exception is thrown.
init()
public init()
Description: Constructs a default LambdaExpr object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a LambdaExpr object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the LambdaExpr type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the LambdaExpr node, this exception is thrown.
class LetPatternExpr
public class LetPatternExpr <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies a deconstruction match node declared by let.
Example of a LetPatternExpr node: let Some(v) <- x in if (let Some(v) <- x)
Parent Type:
prop backArrow
public mut prop backArrow: Token
Description: Obtains or sets the operator <- in a LetPatternExpr node.
Type: Token
Throws:
- ASTException: If Token is not the operator
<-, this exception is thrown.
prop expr
public mut prop expr: Expr
Description: Obtains or sets the expression after the operator <- in a LetPatternExpr node.
Type: Expr
prop keyword
public mut prop keyword: Token
Description: Obtains or sets the keyword let in a LetPatternExpr node.
Type: Token
Throws:
- ASTException: If Token is not the keyword
let, this exception is thrown.
prop pattern
public mut prop pattern: Pattern
Description: Obtains or sets the pattern after let in a LetPatternExpr node.
Type: Pattern
init()
public init()
Description: Constructs a default LetPatternExpr object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a LetPatternExpr object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the LetPatternExpr type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the LetPatternExpr node, this exception is thrown.
class LitConstExpr
public class LitConstExpr <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies a constant expression node.
Examples of a LitConstExpr expression: "abc" and 123
Parent Type:
prop literal
public mut prop literal: Token
Description: Obtains or sets the literal in a LitConstExpr node.
Type: Token
init()
public init()
Description: Constructs a default LitConstExpr object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a LitConstExpr object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the LitConstExpr type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the ParenExpr node, this exception is thrown.
class MacroDecl
public class MacroDecl <: Decl {
public init()
public init(inputs: Tokens)
}
Description: Specifies a macro definition node.
Example of a MacroDecl node: public macro M(input: Tokens): Tokens {...}
Parent Type:
prop block
public mut prop block: Block
Description: Obtains or sets the function body of a MacroDecl node.
Type: Block
prop colon
public mut prop colon: Token
Description: Obtains or sets colons (:) of a MacroDecl node.
Type: Token
Throws:
- ASTException: If Token is not a colon (:), this exception is thrown.
prop declType
public mut prop declType: TypeNode
Description: Obtains or sets the function return type of a MacroDecl node.
Type: TypeNode
Throws:
- ASTException: When the MacroDecl node returns a default value, this exception is thrown.
prop funcParams
public mut prop funcParams: ArrayList<FuncParam>
Description: Obtains or sets the parameters of a MacroDecl node.
prop lParen
public mut prop lParen: Token
Description: Obtains or sets the right parenthesis ")" in a MacroDecl node.
Type: Token
Throws:
- ASTException: If Token is not a left parenthesis "(", this exception is thrown.
prop rParen
public mut prop rParen: Token
Description: Obtains or sets the right parenthesis ")" in a MacroDecl node.
Type: Token
Throws:
- ASTException: If Token is not a right parenthesis ")", this exception is thrown.
init()
public init()
Description: Constructs a default MacroDecl object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a MacroDecl object.
Parameters:
Throws:
- ASTException: If the input Tokens type cannot be used to construct the MacroDecl node, this exception is thrown.
class MacroExpandDecl
public class MacroExpandDecl <: Decl {
public init()
public init(inputs: Tokens)
}
Description: Specifies a macro call node.
Example of a MacroExpandDecl node: @M class A {}
Parent Type:
prop fullIdentifier
public mut prop fullIdentifier: Token
Description: Obtains or sets the full identifier of a macro call node.
Type: Token
prop lParen
public mut prop lParen: Token
Description: Obtains or sets the left parenthesis "(" invoked by the MacroExpandDecl macro.
Type: Token
Throws:
- ASTException: If Token is not a left parenthesis "(", this exception is thrown.
prop lSquare
public mut prop lSquare: Token
Description: Obtains or sets the left square bracket ([) invoked by the MacroExpandDecl attribute macro.
Type: Token
Throws:
- ASTException: If Token is not a left square bracket ([), this exception is thrown.
prop macroAttrs
public mut prop macroAttrs: Tokens
Description: Obtains or sets the input of a MacroExpandDecl attribute macro call.
Type: Tokens
prop macroInputDecl
public mut prop macroInputDecl: Decl
Description: Obtains or sets the declaration node in MacroExpandDecl.
Type: Decl
Throws:
- ASTException: If the MacroExpandDecl node does not have the declaration node, this exception is thrown.
prop macroInputs
public mut prop macroInputs: Tokens
Description: Obtains or sets the input of a MacroExpandDecl macro call.
Type: Tokens
prop rParen
public mut prop rParen: Token
Description: Obtains or sets the right parenthesis ")" invoked by the MacroExpandDecl macro.
Type: Token
Throws:
- ASTException: If Token is not a right parenthesis ")", this exception is thrown.
prop rSquare
public mut prop rSquare: Token
Description: Obtains or sets the right square bracket (]) invoked by the MacroExpandDecl attribute macro.
Type: Token
Throws:
- ASTException: If Token is not a right square bracket (]), this exception is thrown.
init()
public init()
Description: Constructs a default MacroExpandDecl object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a MacroExpandDecl object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the MacroExpandDecl type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the MacroExpandDecl node, this exception is thrown.
class MacroExpandExpr
public class MacroExpandExpr <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies a macro call node.
Example of a MacroExpandExpr node: @M (a is Int64)
Parent Type:
prop at
public mut prop at: Token
Description: Obtains or sets the operator @ in a MacroExpandExpr node.
Type: Token
Throws:
- ASTException: If Token is not the operator
@, this exception is thrown.
prop identifier
public mut prop identifier: Token
Description: Obtains or sets the identifier of a macro call node.
Type: Token
prop lParen
public mut prop lParen: Token
Description: Obtains or sets the left parenthesis "(" invoked by the [MacroExpandExpr](ast_package_classes.md#class-macroexpandexpr) macro.
Type: Token
Throws:
- ASTException: If Token is not a left parenthesis "(", this exception is thrown.
prop lSquare
public mut prop lSquare: Token
Description: Obtains or sets the left square bracket ([) invoked by the [MacroExpandExpr](ast_package_classes.md#class-macroexpandexpr) attribute macro.
Type: Token
Throws:
- ASTException: If Token is not a left square bracket ([), this exception is thrown.
prop macroAttrs
public mut prop macroAttrs: Tokens
Description: Obtains or sets the input of a MacroExpandExpr attribute macro call.
Type: Tokens
prop macroInputs
public mut prop macroInputs: Tokens
Description: Obtains or sets the input of a MacroExpandExpr macro call.
Type: Tokens
prop rParen
public mut prop rParen: Token
Description: Obtains or sets the right parenthesis ")" invoked by the [MacroExpandExpr](ast_package_classes.md#class-macroexpandexpr) macro.
Type: Token
Throws:
- ASTException: If Token is not a right parenthesis ")", this exception is thrown.
prop rSquare
public mut prop rSquare: Token
Description: Obtains or sets the right square bracket (]) invoked by the [MacroExpandExpr](ast_package_classes.md#class-macroexpandexpr) attribute macro.
Type: Token
Throws:
- ASTException: If Token is not a right square bracket (]), this exception is thrown.
init()
public init()
Description: Constructs a default MacroExpandExpr object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a MacroExpandExpr object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the MacroExpandExpr type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the MacroExpandExpr node, this exception is thrown.
class MacroExpandParam
public class MacroExpandParam <: FuncParam {
public init()
}
Description: Specifies a macro call node.
Example of a MacroExpandDecl node: @M a: Int64 in func foo (@M a: Int64)
Parent Type:
prop fullIdentifier
public mut prop fullIdentifier: Token
Description: Obtains or sets the full identifier of a macro call node.
Type: Token
prop lParen
public mut prop lParen: Token
Description: Obtains or sets the left parenthesis "(" invoked by the MacroExpandParam macro.
Type: Token
Throws:
- ASTException: If Token is not a left parenthesis "(", this exception is thrown.
prop lSquare
public mut prop lSquare: Token
Description: Obtains or sets the lfet square bracket ([) invoked by the MacroExpandParam attribute macro.
Type: Token
Throws:
- ASTException: If Token is not a left square bracket ([), this exception is thrown.
prop macroAttrs
public mut prop macroAttrs: Tokens
Description: Obtains or sets the input of a MacroExpandParam attribute macro call.
Type: Tokens
prop macroInputDecl
public mut prop macroInputDecl: Decl
Description: Obtains or sets the declaration node in MacroExpandParam.
Type: Decl
Throws:
- ASTException - If the MacroExpandParam node contains no declaration node, this exception is thrown.
prop macroInputs
public mut prop macroInputs: Tokens
Description: Obtains or sets the input of a MacroExpandParam macro call.
Type: Tokens
prop rParen
public mut prop rParen: Token
Description: Obtains or sets the right parenthesis of a MacroExpandParam macro call.
Type: Token
Throws:
- ASTException: If Token is not a right parenthesis ")", this exception is thrown.
prop rSquare
public mut prop rSquare: Token
Description: Obtains or sets the right square bracket (]) invoked by the MacroExpandParam attribute macro.
Type: Token
Throws:
- ASTException: If Token is not a right square bracket (]), this exception is thrown.
init()
public init()
Description: Constructs a default MacroExpandParam object.
class MacroMessage
public class MacroMessage
Description: Records information sent by an inner macro.
func getBool(String)
public func getBool(key: String): Bool
Description: Obtains the Bool type information corresponding to a key value.
Parameters:
- key: String: key of the keyword to be searched for
Returns:
Throws:
- Exception: If the Bool type information corresponding to the key value does not exist, this exception is thrown.
func getInt64(String)
public func getInt64(key: String): Int64
Description: Obtains the Int64 type information corresponding to a key value.
Parameters:
- key: String: key of the keyword to be searched for
Returns:
Throws:
- Exception: If the Int64 type information corresponding to the key value does not exist, this exception is thrown.
func getString(String)
public func getString(key: String): String
Description: Obtains the String type information corresponding to a key value.
Parameters:
- key: String: key of the keyword to be searched for
Returns:
Throws:
- Exception: If the String type information corresponding to the key value does not exist, this exception is thrown.
func hasItem(String)
public func hasItem(key: String): Bool
Description: Checks whether the information corresponding to a key value exists.
Parameters:
- key: String: key of the keyword to be searched for
Returns:
- Bool: If the information corresponding to the key value exists, true is returned. Otherwise, false is returned.
class MainDecl
public class MainDecl <: Decl {
public init()
public init(inputs: Tokens)
}
Description: Specifies a main function definition node.
Example of a MainDecl node: main() {}
Parent Type:
prop block
public mut prop block: Block
Description: Obtains or sets the function body of a MainDecl node.
Type: Block
prop colon
public mut prop colon: Token
Description: Obtains or sets colons (:) of a MainDecl node.
Type: Token
Throws:
- ASTException: If Token is not a colon (:), this exception is thrown.
prop declType
public mut prop declType: TypeNode
Description: Obtains or sets the function return type of a MainDecl node.
Type: TypeNode
Throws:
- ASTException: When the MainDecl node returns a default value, this exception is thrown.
prop funcParams
public mut prop funcParams: ArrayList<FuncParam>
Description: Obtains or sets the function parameters of a MainDecl node.
prop lParen
public mut prop lParen: Token
Description: Obtains or sets the left parenthesis "(" in a MainDecl node.
Type: Token
Throws:
- ASTException: If Token is not a left parenthesis "(", this exception is thrown.
prop rParen
public mut prop rParen: Token
Description: Obtains or sets the right parenthesis ")" in a MainDecl node.
Type: Token
Throws:
- ASTException: If Token is not a right parenthesis ")", this exception is thrown.
init()
public init()
Description: Constructs a default MainDecl object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a MainDecl object.
Parameters:
Throws:
- ASTException: If the input Tokens type cannot be used to construct the MainDecl node, this exception is thrown.
class MatchCase
public class MatchCase <: Node {
public init()
}
Description: Specifies a MatchCase type.
Example of a MatchCase node: case failScore where score > 0 => 0
Note:
Parent Type:
prop arrow
public mut prop arrow: Token
Description: Obtains or sets the lexical unit operator => in MatchCase.
Type: Token
Throws:
- ASTException: If Token is not the operator
=>, this exception is thrown.
prop bitOrs
public mut prop bitOrs: Tokens
Description: Obtains or sets the lexical unit sequence of the operator | in MatchCase, which may be empty.
Type: Tokens
Throws:
- ASTException: If Tokens is not the lexical unit sequence
|, this exception is thrown.
prop block
public mut prop block: Block
Description: Obtains or sets a series of declaration or expression nodes in MatchCase.
Type: Block
prop expr
public mut prop expr: Expr
Description: Obtains or sets the expression node after case in MatchCase.
Type: Expr
Throws:
- ASTException: If the MatchCase node contains no expression node, this exception is thrown.
prop keywordC
public mut prop keywordC: Token
Description: Obtains or sets the lexical unit keyword case in MatchCase.
Type: Token
Throws:
- ASTException: If Token is not the keyword
case, this exception is thrown.
prop keywordW
public mut prop keywordW: Token
Description: Obtains or sets the lexical unit optional keyword where in MatchCase, which may be an ILLEGAL lexical unit.
Type: Token
Throws:
- ASTException: If Token is not the keyword
where, this exception is thrown.
prop patternGuard
public mut prop patternGuard: Expr
Description: Obtains or sets the optional pattern guard expression node in MatchCase.
Type: Expr
Throws:
- ASTException: If the MatchCase node contains no pattern guard expression, this exception is thrown.
prop patterns
public mut prop patterns: ArrayList<Pattern>
Description: Obtains or sets the pattern list after case in MatchCase.
init()
public init()
Description: Constructs a default MatchCase object.
class MatchExpr
public class MatchExpr <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies that a pattern matching expression implements pattern matching.
Pattern matching expressions are classified into match expressions with a selector and match expressions without any selector.
Parent Type:
prop keyword
public mut prop keyword: Token
Description: Obtains or sets the keyword match in a MatchExpr node.
Type: Token
Throws:
- ASTException: If Token is not the keyword
matcch, this exception is thrown.
prop lBrace
public mut prop lBrace: Token
Description: Obtains or sets the left curly bracket ({) following [MatchExpr](ast_package_classes.md#class-matchexpr).
Type: Token
Throws:
- ASTException: If Token is not a left curly bracket ({), this exception is thrown.
prop lParen
public mut prop lParen: Token
Description: Obtains or sets the left parenthesis "(" following [MatchExpr](ast_package_classes.md#class-matchexpr).
Type: Token
Throws:
- ASTException: If Token is not a left parenthesis "(", this exception is thrown.
prop matchCases
public mut prop matchCases: ArrayList<MatchCase>
Description: Obtains or sets matchCase in MatchExpr. matchCase starts with the keyword case, followed by one or more Pattern or Expr nodes. For details, see MatchCase.
prop rBrace
public mut prop rBrace: Token
Description: Obtains or sets the right curly bracket (}) following [MatchExpr](ast_package_classes.md#class-matchexpr).
Type: Token
Throws:
- ASTException: If Token is not a right curly bracket (}), this exception is thrown.
prop rParen
public mut prop rParen: Token
Description: Obtains or sets the right parenthesis ")" following [MatchExpr](ast_package_classes.md#class-matchexpr).
Type: Token
Throws:
- ASTException: If Token is not a right parenthesis ")", this exception is thrown.
prop selector
public mut prop selector: Expr
Description: Obtains or sets Expr after the keyword match.
Type: Expr
Throws:
- ASTException: If the expression is a
matchexpression without any selector, this exception is thrown.
init()
public init()
Description: Constructs a default MatchExpr object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a MatchExpr object.
Parameters:
Throws:
- ASTException: If the input Tokens type cannot be used to construct the MatchExpr node, this exception is thrown.
class MemberAccess
public class MemberAccess <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies a member access expression.
This can be used to access members of types such as class, interface, and struct. A MemberAccess node is in the form of T.a, where T is the body of the member access expression, and a is the name of the member.
Parent Type:
prop baseExpr
public mut prop baseExpr: Expr
Description: Obtains or sets the body of the member access expression of a MemberAccess node.
Type: Expr
prop commas
public mut prop commas: Tokens
Description: Obtains or sets the lexical unit sequence comma (,) in a MemberAccess node. The lexical unit sequence may be empty.
Type: Tokens
Throws:
- ASTException: If Tokens is not the lexical unit sequence comma (,), this exception is thrown.
prop dot
public mut prop dot: Token
Description: Obtains or sets the period (.) in a MemberAccess node.
Type: Token
Throws:
- ASTException: If Token is not the lexical unit sequence period (.), this exception is thrown.
prop field
public mut prop field: Token
Description: Obtains or sets the name of a MemberAccess node member.
Type: Token
prop lAngle
public mut prop lAngle: Token
Description: Obtains or sets the left angle bracket in a MemberAccess node.
Type: Token
Throws:
- ASTException: If Token is not a left angle bracket, this exception is thrown.
prop rAngle
public mut prop rAngle: Token
Description: Obtains or sets the right angle bracket in a MemberAccess node.
Type: Token
Throws:
- ASTException: If Token is not a right angle bracket, this exception is thrown.
prop typeArguments
public mut prop typeArguments: ArrayList<TypeNode>
Description: Obtains or sets the instantiation type in a MemberAccess node.
init()
public init()
Description: Constructs a default MemberAccess object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a MemberAccess object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the MemberAccess type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the MemberAccess node, this exception is thrown.
class Modifier
public class Modifier <: Node {
public init()
public init(keyword: Token)
}
Description: Specifies that a definition has certain features. This class is usually placed at the beginning of a definition.
Example of a Modifier node: public in public func foo()
Parent Type:
prop keyword(Token)
public mut prop keyword: Token
Description: Obtains or sets the modifier lexical unit in a Modifier node.
Type: Token
init()
public init()
Description: Constructs a default Modifier object.
init(Token)
public init(keyword: Token)
Description: Constructs a Modifier object.
Parameters:
class Node
abstract sealed class Node <: ToTokens
Description: Specifies the parent class of all Cangjie syntax tree nodes.
This class provides universal operation APIs for all data types.
Parent Type:
prop beginPos
public mut prop beginPos: Position
Description: Obtains or sets the start position of the current node.
Type: Position
prop endPos
public mut prop endPos: Position
Description: Obtains or sets the end position of the current node.
Type: Position
func dump()
public func dump(): Unit
Description: Converts the current syntax tree node into a tree structure and prints it.
In the tree structure output of the syntax tree node:
- The
-character string indicates the public attribute of the current node, for example,-keywordand-identifier. - The node type immediately follows the node attribute, for example,
-declType: PrimitiveTypeindicates that the node type is PrimitiveType. - Braces indicate the application range of each type.
For details about the output format of a syntax tree, see Syntax Tree Node Printing in the sample code.
func toTokens()
public func toTokens(): Tokens
Description: Converts a syntax tree node to the Tokens type.
Returns:
func traverse(Visitor)
public func traverse(v: Visitor): Unit
Description: Traverses the current syntax tree node and its subnodes. To terminate subnode traversal in advance, rewrite the visit function and call the breakTraverse function. For details, see Examples of Traversing AST Objects Using a User-defined Access Function in the sample code.
Parameters:
class OptionalExpr
public class OptionalExpr <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies an expression node with the operator question mark (?).
Example of an OptionalExpr node: a? in a?.b, a?(b), a?[b]
Parent Type:
prop baseExpr
public mut prop baseExpr: Expr
Description: Obtains or sets the expression node of OptionalExpr.
Type: Expr
prop quest
public mut prop quest: Token
Description: Obtains or sets the operator question mark (?) in OptionalExpr.
Type: Token
Throws:
- ASTException: If Token is not the operator question mark (?), this exception is thrown.
init()
public init()
Description: Constructs a default OptionalExpr object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs an OptionalExpr object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the OptionalExpr type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the OptionalExpr node, this exception is thrown.
class PackageHeader
public class PackageHeader <: Node {
public init()
public init(inputs: Tokens)
}
Description: Specifies a package declaration node.
Example of a PackageHeader node: package define or macro package define
Note:
A package declaration starts with the keyword
packageormacro package, followed by the package name, and must be in the first line of the source file.
Parent Type:
prop accessible
public mut prop accessible: Token
Description: Obtains or sets the lexical unit access modifier in a PackageHeader node, which may be an ILLEGAL lexical unit.
Type: Token
prop keywordM
public mut prop keywordM: Token
Description: Obtains or sets the lexical unit keyword macro in a PackageHeader node. (M is the first letter of the keyword, which applies to the following scenarios.) The lexical unit may be an ILLEGAL lexical unit.
Type: Token
Throws:
- ASTException: If Token is not the keyword
macro, this exception is thrown.
prop keywordP
public mut prop keywordP: Token
Description: Obtains or sets the lexical unit keyword package in a PackageHeader node.
Type: Token
Throws:
- ASTException: If Token is not the keyword
package, this exception is thrown.
prop prefixPaths
public mut prop prefixPaths: Tokens
Description: Obtains or sets the lexical unit sequence of the prefix of a full package name in a PackageHeader node. The lexical unit sequence may be empty. Example: a and b in package a.b.c.
Type: Tokens
prop prefixDots
public mut prop prefixDots: Tokens
Description: Obtains or sets the lexical unit sequence used to separate the subpackage layers in a full package name in a PackageHeader node. The lexical unit sequence may be empty. Example: two periods (.) in package a.b.c.
Type: Tokens
Throws:
- ASTException: If Tokens is not the lexical unit sequence period (.), this exception is thrown.
prop packageIdentifier
public mut prop packageIdentifier: Token
Description: Obtains or sets the name of the current package in a PackageHeader node. If the current package is a root package, a full package name is returned. If the current package is a subpackage, the part following the last period (.) is returned.
Type: Token
init()
public init()
Description: Constructs a default PackageHeader object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a PackageHeader object.
Parameters:
- inputs: Tokens: the sequence of collection of lexical units (Tokens) used to construct the PackageHeader type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the PackageHeader node, this exception is thrown.
class ParenExpr
public class ParenExpr <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies a parenthesis expression node, which is an expression enclosed in parentheses.
Example of a ParenExpr node: (1 + 2)
Parent Type:
prop lParen
public mut prop lParen: Token
Description: Obtains or sets the left parenthesis "(" in a ParenExpr node.
Type: Token
Throws:
- ASTException: If Token is not a left parenthesis "(", this exception is thrown.
prop parenthesizedExpr
public mut prop parenthesizedExpr: Expr
Description: Obtains or sets a subexpression enclosed in parentheses in a ParenExpr node.
Type: Expr
prop rParen
public mut prop rParen: Token
Description: Obtains or sets the right parenthesis ")" in a ParenExpr node.
Type: Token
Throws:
- ASTException: If Token is not a right parenthesis ")", this exception is thrown.
init()
public init()
Description: Constructs a default ParenExpr object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a ParenExpr object.
Parameters:
Throws:
- ASTException: If the input Tokens type cannot be used to construct the ParenExpr node, this exception is thrown.
class ParenType
public class ParenType <: TypeNode {
public init()
public init(inputs: Tokens)
}
Description: Specifies a parenthesis type node.
Example: (Int64) in var a: (Int64)
Parent Type:
prop lParen
public mut prop lParen: Token
Description: Obtains or sets the lexical unit left parenthesis "(" in a ParenType node.
Type: Token
Throws:
- ASTException: If Token is not a left parenthesis "(", this exception is thrown.
prop parenthesizedType
public mut prop parenthesizedType: TypeNode
Description: Obtains or sets the type enclosed in parentheses in a ParenType node, for example, Int64 in (Int64).
Type: TypeNode
prop rParen
public mut prop rParen: Token
Description: Obtains or sets the lexical unit right parenthesis ")" in a ParenType node.
Type: Token
Throws:
- ASTException: If Token is not a right parenthesis ")", this exception is thrown.
init()
public init()
Description: Constructs a default ParenType object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a ParenType object.
Parameters:
Throws:
- ASTException: If the input Tokens type cannot be used to construct the ParenType node, this exception is thrown.
class Pattern
public open class Pattern <: Node
Description: Specifies the parent class of all pattern matching nodes, which is inherited from a Node node.
Parent Type:
class PrefixType
public class PrefixType <: TypeNode {
public init()
public init(inputs: Tokens)
}
Description: Specifies a prefix type node with a question mark (?).
Example: ?A in var a: ?A
Parent Type:
prop baseType
public mut prop baseType: TypeNode
Description: Obtains or sets the type node in a PrefixType node, for example, A in var a: ?A.
Type: TypeNode
prop prefixOps
public mut prop prefixOps: Tokens
Description: Obtains or sets the collection of prefix operators in a PrefixType node.
Type: Tokens
init()
public init()
Description: Constructs a default PrefixType object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a PrefixType object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the PrefixType type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the PrefixType node, this exception is thrown.
class PrimaryCtorDecl
public class PrimaryCtorDecl <: Decl {
public init()
public init(inputs: Tokens)
}
Description: Specifies a primary constructor node.
A primary constructor node consists of a modifier, a primary constructor name, a formal parameter list, and a primary constructor body.
Parent Type:
prop block
public mut prop block: Block
Description: Obtains or sets the primary constructor body of a PrimaryCtorDecl node.
Type: Block
prop funcParams
public mut prop funcParams: ArrayList<FuncParam>
Description: Obtains or sets the parameters of a PrimaryCtorDecl node.
prop lParen
public mut prop lParen: Token
Description: Obtains or sets the left parenthesis "(" in a PrimaryCtorDecl node.
Type: Token
Throws:
- ASTException: If Token is not a left parenthesis "(", this exception is thrown.
prop rParen
public mut prop rParen: Token
Description: Obtains or sets the right parenthesis ")" in a PrimaryCtorDecl node.
Type: Token
Throws:
- ASTException: If Token is not a right parenthesis ")", this exception is thrown.
init()
public init()
Description: Constructs a default PrimaryCtorDecl object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a PrimaryCtorDecl object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the PrimaryCtorDecl type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the PrimaryCtorDecl node, this exception is thrown.
func isConst()
public func isConst(): Bool
Description: Checks whether a node is of the Const type.
Returns:
- Bool: If the current node is of the
Consttype, true is returned. Otherwise, false is returned.
class PrimitiveType
public class PrimitiveType <: TypeNode {
public init()
public init(inputs: Tokens)
}
Description: Specifies a primitive type node.
Examples: value, run, and Boolean types
Parent Type:
prop keyword
public mut prop keyword: Token
Description: Obtains or sets the keyword for constructing a PrimitiveType type, for example, Int8.
Type: Token
init()
public init()
Description: Constructs a default PrimitiveType object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a PrimitiveType object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the PrimitiveType type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the PrimitiveType node, this exception is thrown.
class PrimitiveTypeExpr
public class PrimitiveTypeExpr <: Expr {
public init()
public init(kind: Tokens)
}
Description: Specifies a primitive type expression node.
A PrimitiveTypeExpr node is a primitive type built in the compiler appearing in the node as an expression, for example, Int64 in Int64.toSting().
Parent Type:
prop keyword
public mut prop keyword: Token
Description: Obtains or sets the primitive type keywords in PrimitiveTypeExpr.
Type: Token
init()
public init()
Description: Constructs a default PrimitiveTypeExpr object.
init(Tokens)
public init(kind: Tokens)
Description: Constructs a PrimitiveTypeExpr object.
Parameters:
- kind: Tokens: collection of lexical units (Tokens) used to construct the PrimitiveTypeExpr type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the PrimitiveTypeExpr node, this exception is thrown.
class Program
public class Program <: Node {
public init()
public init(inputs: Tokens)
}
Description: Specifies a Cangjie source code file node.
A Cangjie source code file node includes a package definition node, a package import node, and all declaration nodes in the top-level scope.
Note:
Any Cangjie source code file can be parsed into a Program type.
Parent Type:
prop decls
public mut prop decls: ArrayList<Decl>
Description: Obtains or sets the declaration node list defined in the top-level scope in a Cangjie source code file.
prop importLists
public mut prop importLists: ArrayList<ImportList>
Description: Obtains or sets the package import node ImportList list in a Cangjie source code file.
Type: ArrayList<ImportList>
prop packageHeader
public mut prop packageHeader: PackageHeader
Description: Obtains or sets the package declaration node PackageHeader in a Cangjie source code file.
Type: PackageHeader
init()
public init()
Description: Constructs a default Program object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a Program object.
Parameters:
- inputs: Tokens: the sequence of collection of lexical units (Tokens) used to construct the Program type
Throws:
- ASTException: If the input Tokens type cannot be used to construct a file node, this exception is thrown.
class PropDecl
public class PropDecl <: Decl {
public init()
public init(inputs: Tokens)
}
Description: Specifies an attribute definition node.
Example of a PropDecl node: prop var X: Int64 { get() { 0 } }
Parent Type:
prop colon
public mut prop colon: Token
Description: Obtains or sets colons (:) of a PropDecl node.
Type: Token
Throws:
- ASTException: If Token is not a colon (:), this exception is thrown.
prop declType
public mut prop declType: TypeNode
Description: Obtains or sets the return type of a PropDecl node.
Type: TypeNode
prop getter
public mut prop getter: FuncDecl
Description: Obtains or sets the getter function of a PropDecl node.
Type: FuncDecl
Throws:
-ASTException: When the PropDecl node does not contain the getter function, this exception is thrown.
prop lBrace
public mut prop lBrace: Token
Description: Obtains or sets the left curly bracket ({) in a PropDecl node.
Type: Token
Throws:
- ASTException: If Token is not a left curly bracket ({), this exception is thrown.
prop rBrace
public mut prop rBrace: Token
Description: Obtains or sets the right curly bracket (}) in a PropDecl node.
Type: Token
Throws:
- ASTException: If Token is not a right curly bracket (}), this exception is thrown.
prop setter
public mut prop setter: FuncDecl
Description: Obtains or sets the setter function of a PropDecl node.
Type: FuncDecl
Throws:
-ASTException: When the PropDecl node does not contain the setter function, this exception is thrown.
init()
public init()
Description: Constructs a default PropDecl object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a PropDecl object.
Parameters:
Throws:
- ASTException: If the input Tokens type cannot be used to construct the PropDecl node, this exception is thrown.
class QualifiedType
public class QualifiedType <: TypeNode {
public init()
public init(inputs: Tokens)
}
Description: Specifies a user-defined member type.
Example: T.a in var a: T.a, where T is the package name, and a is the type imported from the T package.
Parent Type:
prop baseType
public mut prop baseType: TypeNode
Description: Obtains or sets the member access type body of a QualifiedType node, for example, T in var a : T.a.
Type: TypeNode
prop commas
public mut prop commas: Tokens
Description: Obtains or sets the lexical unit sequence comma (,) in a QualifiedType node. The lexical unit sequence may be empty.
Type: Tokens
Throws:
- ASTException: If Tokens is not the lexical unit sequence comma (,), this exception is thrown.
prop dot
public mut prop dot: Token
Description: Obtains or sets the period (.) in a QualifiedType node.
Type: Token
Throws:
- ASTException: If Tokens is not the lexical unit sequence period (.), this exception is thrown.
prop identifier
public mut prop identifier: Token
Description: Obtains or sets the identifier of a QualifiedType node member, for example, a in var a : T.a.
Type: Token
prop lAngle
public mut prop lAngle: Token
Description: Obtains or sets the lexical unit left angle bracket in a QualifiedType node, which may be an ILLEGAL lexical unit.
Type: Token
Throws:
- ASTException: If Token is not a left angle bracket, this exception is thrown.
prop rAngle
public mut prop rAngle: Token
Description: Obtains or sets the lexical unit right angle bracket in a QualifiedType node, which may be an ILLEGAL lexical unit.
Type: Token
Throws:
- ASTException: If Token is not a right angle bracket, this exception is thrown.
prop typeArguments
public mut prop typeArguments: ArrayList<TypeNode>
Description: Obtains or sets the list of instantiation types in a QualifiedType node, for example, Int32 in T.a<Int32>. The list may be empty.
init()
public init()
Description: Constructs a default QualifiedType object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a QualifiedType object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the QualifiedType type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the QualifiedType node, this exception is thrown.
class QuoteExpr
public class QuoteExpr <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies a quote expression node.
Example of a QuoteExpr node: quote(var ident = 0)
Parent Type:
prop exprs
public mut prop exprs: ArrayList<Expr>
Description: Obtains or sets the internal reference expression node enclosed in () in QuoteExpr.
prop keyword
public mut prop keyword: Token
Description: Obtains or sets the keyword quote in [QuoteExpr](ast_package_classes.md#class-quoteexpr).
Type: Token
Throws:
- ASTException: If Token is not the keyword
quote, this exception is thrown.
prop lParen
public mut prop lParen: Token
Description: Obtains or sets the left parenthesis "(" in QuoteExpr.
Type: Token
Throws:
- ASTException: If Token is not a left parenthesis "(", this exception is thrown.
prop rParen
public mut prop rParen: Token
Description: Obtains or sets the right parenthesis ")" in QuoteExpr.
Type: Token
Throws:
- ASTException: If Token is not a right parenthesis ")", this exception is thrown.
init()
public init()
Description: Constructs a default QuoteExpr object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a QuoteExpr object.
Parameters:
Throws:
- ASTException: If the input Tokens type cannot be used to construct the QuoteExpr node, this exception is thrown.
class QuoteToken
public class QuoteToken <: Expr
Description: Specifies any valid token in a quote expression node.
Parent Type:
prop tokens
public mut prop tokens: Tokens
Description: Obtains Tokens in QuoteToken.
Type: Tokens
class RangeExpr
public class RangeExpr <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies an expression that contains range operators.
A RangeExpr node supports two Range operators: .. and ..=, which are used in the forms of start..end:step and start..=end:step to create left-closed and right-open Range instances and left-closed and right-closed Range instances, respectively.
Parent Type:
prop colon
public mut prop colon: Token
Description: Obtains or sets the operator colon (:) in RangeExpr.
Type: Token
Throws:
- ASTException: If Token is not the operator colon (:), this exception is thrown.
prop end
public mut prop end: Expr
Description: Obtains or sets the end value in RangeExpr.
Type: Expr
Throws:
- ASTException: The end expression is omitted. Only when instances are of the Range<Int64> type, and the index operator
[]is empty, this exception is thrown.
prop op
public mut prop op: Token
Description: Obtains or sets the operator of Range in RangeExpr.
Type: Token
prop start
public mut prop start: Expr
Description: Obtains or sets the start value in RangeExpr.
Type: Expr
Throws:
- ASTException: The start expression is omitted. Only when instances are of the Range<Int64> type, and the index operator
[]is empty, this exception is thrown.
prop step
public mut prop step: Expr
Description: Obtains or sets the difference between two adjacent elements in a sequence in RangeExpr.
Type: Expr
Throws:
- ASTException: If the difference between the two adjacent elements in the sequence is not set in RangeExpr, this exception is thrown.
init()
public init()
Description: Constructs a default RangeExpr object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a RangeExpr object.
Parameters:
Throws:
- ASTException: If the input Tokens type cannot be used to construct the RangeExpr node, this exception is thrown.
class RefExpr
public class RefExpr <: Expr {
public init()
public init(inputs: Tokens)
}
Description: References a declared expression node.
RefExpr node: a in var b = a + 1 is one RefExpr node.
Parent Type:
prop commas
public mut prop commas: Tokens
Description: Obtains or sets the lexical unit sequence comma (,) in a RefExpr node. The lexical unit sequence may be empty.
Type: Tokens
Throws:
- ASTException: If Tokens is not the lexical unit sequence comma (,), this exception is thrown.
prop identifier
public mut prop identifier: Token
Description: Obtains or sets the identifier of a user-defined type in a RefExpr node.
Type: Token
prop lAngle
public mut prop lAngle: Token
Description: Obtains or sets the left angle bracket in a RefExpr node.
Type: Token
Throws:
- ASTException: If Token is not a left angle bracket, this exception is thrown.
prop rAngle
public mut prop rAngle: Token
Description: Obtains or sets the right angle bracket in a RefExpr node.
Type: Token
Throws:
- ASTException: If Token is not a right angle bracket, this exception is thrown.
prop typeArguments
public mut prop typeArguments: ArrayList<TypeNode>
Description: Obtains or sets the instantiation type in a RefExpr node.
init()
public init()
Description: Constructs a default RefExpr object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a RefExpr object.
Parameters:
Throws:
- ASTException: If the input Tokens type cannot be used to construct the RefExpr node, this exception is thrown.
class RefType
public class RefType <: TypeNode {
public init()
public init(inputs: Tokens)
}
Description: Specifies a non-primitive type node.
For example, RefType can be used to specify user-defined types such as class, struct, and enum, as well as built-in types such as Array and String, for example, A in var a : A.
Parent Type:
prop commas
public mut prop commas: Tokens
Description: Obtains or sets the lexical unit sequence comma (,) in a RefType node. The lexical unit sequence may be empty.
Type: Tokens
Throws:
- ASTException: If Tokens is not the lexical unit sequence comma (,), this exception is thrown.
prop identifier
public mut prop identifier: Token
Description: Obtains or sets the keyword for constructing a RefType type, for example, A in var a: A = A().
Type: Token
prop lAngle
public mut prop lAngle: Token
Description: Obtains or sets the lexical unit left angle bracket in a RefType node, which may be an ILLEGAL lexical unit.
Type: Token
Throws:
- ASTException: If Token is not a left angle bracket, this exception is thrown.
prop rAngle
public mut prop rAngle: Token
Description: Obtains or sets the lexical unit right angle bracket in a RefType node, which may be an ILLEGAL lexical unit.
Type: Token
Throws:
- ASTException: If Token is not a right angle bracket, this exception is thrown.
prop typeArguments
public mut prop typeArguments: ArrayList<TypeNode>
Description: Obtains or sets the list of instantiation types in a RefType node, which may be empty, for example, Int32 in var a: Array<Int32>.
init()
public init()
Description: Constructs a default RefType object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a RefType object.
Parameters:
Throws:
- ASTException: If the input Tokens type cannot be used to construct the RefType node, this exception is thrown.
class ReturnExpr
public class ReturnExpr <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies a return expression node.
Example of a ReturnExpr node: return 1
Parent Type:
prop expr
public mut prop expr: Expr
Description: Obtains or sets the expression node in a ReturnExpr node.
Type: Expr
Throws:
- ASTException: If the ReturnExpr node contains no expression, this exception is thrown.
prop keyword
public mut prop keyword: Token
Description: Obtains or sets the keyword in a ReturnExpr node.
Type: Token
Throws:
- ASTException: If Token is not the keyword
return, this exception is thrown.
init()
public init()
Description: Constructs a default ReturnExpr object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a ReturnExpr object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the ReturnExpr type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the ReturnExpr node, this exception is thrown.
class SpawnExpr
public class SpawnExpr <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies a Spawn expression.
A SpawnExpr node consists of the keyword spawn and a closure that contains no formal parameter, for example, spawn { add(1, 2) }.
Parent Type:
prop keyword
public mut prop keyword: Token
Description: Obtains or sets the keyword spawn in SpawnExpr.
Type: Token
Throws:
- ASTException: If Token is not the keyword
spawn, this exception is thrown.
prop lParen
public mut prop lParen: Token
Description: Obtains or sets the left parenthesis "(" in SpawnExpr.
Type: Token
Throws:
- ASTException: If Token is not a left parenthesis "(", this exception is thrown.
prop lambdaExpr
public mut prop lambdaExpr: LambdaExpr
Description: Obtains or sets the closure that contains no formal parameter in SpawnExpr.
Type: LambdaExpr
prop rParen
public mut prop rParen: Token
Description: Obtains or sets the right parenthesis ")" in SpawnExpr.
Type: Token
Throws:
- ASTException: If Token is not a right parenthesis ")", this exception is thrown.
prop threadContext
public mut prop threadContext: Expr
Description: Obtains or sets the thread context environment expression in SpawnExpr.
Type: Expr
Throws:
- ASTException: If SpawnExpr contains no context expression, this exception is thrown.
init()
public init()
Description: Constructs a default SpawnExpr object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a SpawnExpr object.
Parameters:
Throws:
- ASTException: If the input Tokens type cannot be used to construct the SpawnExpr node, this exception is thrown.
class StructDecl
public class StructDecl <: Decl {
public init()
public init(inputs: Tokens)
}
Description: Specifies a Struct node.
Struct is defined using the keyword struct in the following sequence: modifier (default or not), struct keyword, struct name, optional type parameter, whether to specify a parent interface, optional generic constraint, and struct body.
Parent Type:
prop body
public mut prop body: Body
Description: Obtains or sets the class body of a StructDecl node.
Type: Body
prop superTypeBitAnds
public mut prop superTypeBitAnds: Tokens
Description: Obtains or sets the lexical unit sequence of the operator & in the parent interface declaration of a StructDecl node. The lexical unit sequence may be empty.
Type: Tokens
Throws:
- ASTException: If Tokens is not the lexical unit sequence
&, this exception is thrown.
prop superTypes
public mut prop superTypes: ArrayList<TypeNode>
Description: Obtains or sets the parent interface of a StructDecl node.
prop upperBound
public mut prop upperBound: Token
Description: Obtains or sets the operator <:.
Type: Token
Throws:
- ASTException: If Token is not the operator
<:, this exception is thrown.
init()
public init()
Description: Constructs a default StructDecl object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a StructDecl object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the StructDecl type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the StructDecl node, this exception is thrown.
class SubscriptExpr
public class SubscriptExpr <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies an index access expression.
A SubscriptExpr node is used by types (including Array and Tuple types) that support index access to access elements at specific locations through indexes, for example, arr[0].
Parent Type:
prop baseExpr
public mut prop baseExpr: Expr
Description: Obtains or sets an expression in SubscriptExpr.
Type: Expr
prop indexList
public mut prop indexList: ArrayList<Expr>
Description: Obtains or sets the index expression sequence in SubscriptExpr.
prop lSquare
public mut prop lSquare: Token
Description: Obtains or sets the left square bracket ([) in SubscriptExpr.
Type: Token
Throws:
- ASTException: If Token is not a left square bracket ([), this exception is thrown.
prop rSquare
public mut prop rSquare: Token
Description: Obtains or sets the right square bracket (]) in SubscriptExpr.
Type: Token
Throws:
- ASTException: If Token is not a right square bracket (]), this exception is thrown.
init()
public init()
Description: Constructs a default SubscriptExpr object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a SubscriptExpr object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the SubscriptExpr type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the SubscriptExpr node, this exception is thrown.
class SynchronizedExpr
public class SynchronizedExpr <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies a synchronized expression.
A SynchronizedExpr node consists of the keyword synchronized, StructuredMutex pair, and code block, for example, synchronized(m) { foo() }.
Parent Type:
prop block
public mut prop block: Block
Description: Obtains or sets a code block modified by SynchronizedExpr.
Type: Block
prop keyword
public mut prop keyword: Token
Description: Obtains or sets the keyword synchronized in SynchronizedExpr.
Type: Token
Throws:
- ASTException: If Token is not the keyword
synchronized, this exception is thrown.
prop lParen
public mut prop lParen: Token
Description: Obtains or sets the left parenthesis "(" in SynchronizedExpr.
Type: Token
Throws:
- ASTException: If Token is not a left parenthesis "(", this exception is thrown.
prop rParen
public mut prop rParen: Token
Description: Obtains or sets the right parenthesis ")" in SynchronizedExpr.
Type: Token
Throws:
- ASTException: If Token is not a right parenthesis ")", this exception is thrown.
prop structuredMutex
public mut prop structuredMutex: Expr
Description: Obtains or sets the StructuredMutex object in SynchronizedExpr.
Type: Expr
init()
public init()
Description: Constructs a default SynchronizedExpr object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a SynchronizedExpr object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the SynchronizedExpr type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the SynchronizedExpr node, this exception is thrown.
class ThisType
public class ThisType <: TypeNode {
public init()
public init(inputs: Tokens)
}
Description: Specifies a This type node.
Parent Type:
prop keyword
public mut prop keyword: Token
Description: Obtains or sets the lexical unit keyword This of a ThisType node.
Type: Token
init()
public init()
Description: Constructs a default ThisType object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a ThisType object.
Parameters:
Throws:
- ASTException: If the input Tokens type cannot be used to construct the ThisType node, this exception is thrown.
class ThrowExpr
public class ThrowExpr <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies a throw expression node.
Example of a ThrowExpr node: throw Exception()
Parent Type:
prop expr
public mut prop expr: Expr
Description: Obtains or sets the expression node in a ThrowExpr node.
Type: Expr
prop keyword
public mut prop keyword: Token
Description: Obtains or sets a keyword in a ThrowExpr node.
Type: Token
Throws:
- ASTException: If Token is not the keyword
throw, this exception is thrown.
init()
public init()
Description: Constructs a default ThrowExpr object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a ThrowExpr object.
Parameters:
Throws:
- ASTException: If the input Tokens type cannot be used to construct the ThrowExpr node, this exception is thrown.
class Tokens
public open class Tokens <: ToString & Iterable<Token> {
public init()
public init(tokArray: Array<Token>)
public init(tokArrayList: ArrayList<Token>)
}
Description: Specifies a type for encapsulating a Token sequence.
Parent Type:
prop size
public open prop size: Int64
Description: Obtains the number of Token types in a Tokens object.
Type: Int64
init()
public init()
Description: Constructs a default Tokens object.
init(Array<Token>)
public init(tokArray: Array<Token>)
Description: Constructs a Tokens object.
Parameters:
init(ArrayList<Token>)
public init(tokArrayList: ArrayList<Token>)
Description: Constructs a Tokens object.
Parameters:
func append(Node)
public func append(node: Node): Tokens
Description: Concatenates the current Tokens with the Tokens converted from the input node.
Parameters:
Returns:
func append(Token)
public open func append(token: Token): Tokens
Description: Concatenates the current Tokens with the input Token.
Parameters:
Returns:
func append(Tokens)
public open func append(tokens: Tokens): Tokens
Description: Adds the input Tokens to the end of the current Tokens for concatenation. (This function has better performance than other concatenation functions.)
Parameters:
Returns:
func concat(Tokens)
public func concat(tokens: Tokens): Tokens
Description: Concatenates the current Tokens with the input Tokens.
Parameters:
Returns:
func dump()
public func dump(): Unit
Description: Prints all Token information in Tokens.
func get(Int64)
public open func get(index: Int64): Token
Description: Obtains the Token element based on an index value.
Parameters:
- index: Int64: value to be indexed
Returns:
func iterator()
public func iterator(): TokensIterator
Description: Obtains an iterator object in Tokens objects.
Returns:
- TokensIterator: iterator object in the Tokens objects
func remove(Int64)
public func remove(index: Int64): Tokens
Description: Deletes a Token object from a specified location.
Parameters:
Returns:
func toString()
public func toString(): String
Description: Converts Tokens to the String type.
operator func +(Token)
public operator func +(r: Token): Tokens
Description: Adds the current Tokens and another Token to obtain new Tokens.
Parameters:
Returns:
operator func +(Tokens)
public operator func +(r: Tokens): Tokens
Description: Adds the current Tokens and Tokens to obtain a new Tokens type.
Parameters:
Returns:
operator func [](Int64)
public operator func [](index: Int64): Token
Description: Overloads operators and obtains the corresponding Token based on an index value.
Parameters:
- index: Int64: value to be indexed
Returns:
operator func [](Range<Int64>)
public open operator func [](range: Range<Int64>): Tokens
Description: Overloads operators and obtains the corresponding Tokens slice through range.
Parameters:
Returns:
Throws:
- IllegalArgumentException: If the value of
range.stepis not 1, this exception is thrown. - IndexOutOfBoundsException: If the range is invalid, this exception is thrown.
class TokensIterator
public class TokensIterator <: Iterator<Token> {
public init(tokens: Tokens)
}
Description: Implements the iterator function of Tokens.
Parent Type:
init(Tokens)
public init(tokens: Tokens)
Description: Constructs a TokensIterator object.
Parameters:
func iterator()
public func iterator(): Iterator<Token>
Description: Obtains an instance of the current iterator.
Returns:
func next()
public func next(): Option<Token>
Description: Obtains the next value in an iterator.
Returns:
- Option<Token>: The Option<Token> type is returned, and None is returned after the traversal is complete.
func peek()
public func peek(): Option<Token>
Description: Obtains the current value in an iterator.
Returns:
- Option<Token>: The Option<Token> type is returned, and None is returned after the traversal is complete.
func seeing(TokenKind)
public func seeing(kind: TokenKind): Bool
Description: Checks whether the Token type of the current node is the input type.
Parameters:
Returns:
- Bool: If the TokenKind of the current node is the same as the input type, true is returned. Otherwise, false is returned.
class TrailingClosureExpr
public class TrailingClosureExpr <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies a trailing Lambda node.
A TrailingClosureExpr node has the lambda expression placed at the end of a function call and outside parentheses, for example, f(a){ i => i * i }.
Parent Type:
prop expr
public mut prop expr: Expr
Description: Obtains or sets an expression in TrailingClosureExpr.
Type: Expr
prop lambdaExpr
public mut prop lambdaExpr: LambdaExpr
Description: Obtains or sets the trailing lambda in TrailingClosureExpr.
Type: LambdaExpr
init()
public init()
Description: Constructs a default TrailingClosureExpr object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a TrailingClosureExpr object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the TrailingClosureExpr type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the TrailingClosureExpr node, this exception is thrown.
class TryExpr
public class TryExpr <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies a try expression node.
A try expression includes three parts: a try block, a catch block, and a finally block.
Parent Type:
prop catchBlocks
public mut prop catchBlocks: ArrayList<Block>
Description: Obtains or sets the Catch block in TryExpr.
prop catchPatterns
public mut prop catchPatterns: ArrayList<Pattern>
Description: Obtains or sets the exception sequence to be captured through pattern matching in TryExpr.
prop finallyBlock
public mut prop finallyBlock: Block
Description: Obtains or sets the keyword Finally block in TryExpr.
Type: Block
Throws:
- ASTException: If the TryExpr node contains no
Finallyblock node, this exception is thrown.
prop keywordF
public mut prop keywordF: Token
Description: Obtains or sets the keyword finally in TryExpr.
Type: Token
Throws:
- ASTException: If Token is not the keyword
finally, this exception is thrown.
prop keywordT
public mut prop keywordT: Token
Description: Obtains or sets the keyword try in TryExpr.
Type: Token
Throws:
- ASTException: If Token is not the keyword
try, this exception is thrown.
prop keywordsC
public mut prop keywordsC: Tokens
Description: Obtains or sets the keyword catch in TryExpr.
Type: Tokens
Throws:
- ASTException: If Token is not the keyword
catch, this exception is thrown.
prop resourceSpec
public mut prop resourceSpec: ArrayList<VarDecl>
Description: Obtains or sets the instantiated object sequence of the Try-with-resources expression in TryExpr.
prop tryBlock
public mut prop tryBlock: Block
Description: Obtains or sets the block consisting of expressions and declarations in TryExpr.
Type: Block
init()
public init()
Description: Constructs a default TryExpr object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a TryExpr object.
Parameters:
Throws:
- ASTException: If the input Tokens type cannot be used to construct the TryExpr node, this exception is thrown.
class TupleLiteral
public class TupleLiteral <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies a tuple literal node.
A TupleLiteral node is specified in the format of (expr1, expr2, ..., exprN), where each expr is an expression.
Parent Type:
prop elements
public mut prop elements: ArrayList<Expr>
Description: Obtains or sets the expression list in TupleLiteral.
prop lParen
public mut prop lParen: Token
Description: Obtains or sets the left parenthesis "(" in TupleLiteral.
Type: Token
Throws:
- ASTException: If Token is not a left parenthesis "(", this exception is thrown.
prop rParen
public mut prop rParen: Token
Description: Obtains or sets the right parenthesis ")" in TupleLiteral.
Type: Token
Throws:
- ASTException: If Token is not a right parenthesis ")", this exception is thrown.
init()
public init()
Description: Constructs a default TupleLiteral object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a TupleLiteral object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the TupleLiteral type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the TupleLiteral node, this exception is thrown.
class TuplePattern
public class TuplePattern <: Pattern {
public init()
public init(inputs: Tokens)
}
Description: Specifies a Tuple pattern node.
This class is used to match the tuple value, for example, ("Bob", age) in case ("Bob", age) => 1.
Parent Type:
prop commas
public mut prop commas: Tokens
Description: Obtains or sets the lexical unit sequence comma (,) in a TuplePattern node. The lexical unit sequence may be empty.
Type: Tokens
Throws:
- ASTException: If Tokens is not the lexical unit sequence comma (,), this exception is thrown.
prop lParen
public mut prop lParen: Token
Description: Obtains or sets the lexical unit left parenthesis "(" in a TuplePattern node.
Type: Token
Throws:
- ASTException: If Token is not a left parenthesis "(", this exception is thrown.
prop patterns
public mut prop patterns: ArrayList<Pattern>
Description: Obtains or sets a group of Pattern nodes in a TuplePattern node.
prop rParen
public mut prop rParen: Token
Description: Obtains or sets the lexical unit right parenthesis ")" in a TuplePattern node.
Type: Token
Throws:
- ASTException: If Token is not a right parenthesis ")", this exception is thrown.
init()
public init()
Description: Constructs a default TuplePattern object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a TuplePattern object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the TuplePattern type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the TuplePattern node, this exception is thrown.
class TupleType
public class TupleType <: TypeNode {
public init()
public init(inputs: Tokens)
}
Description: Specifies a tuple type node.
Example: (Int64, Int32) in var a: (Int64, Int32)
Parent Type:
prop lParen
public mut prop lParen: Token
Description: Obtains or sets the lexical unit left parenthesis "(" in a TupleType node.
Type: Token
Throws:
- ASTException: If Token is not a left parenthesis "(", this exception is thrown.
prop rParen
public mut prop rParen: Token
Description: Obtains or sets the lexical unit right parenthesis ")" in a TupleType node.
Type: Token
Throws:
- ASTException: If Token is not a right parenthesis ")", this exception is thrown.
prop types
public mut prop types: ArrayList<TypeNode>
Description: Obtains or sets the type node list in a TupleType node.
init()
public init()
Description: Constructs a default TupleType object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a TupleType object.
Parameters:
Throws:
- ASTException: If the input Tokens type cannot be used to construct the TupleType node, this exception is thrown.
class TypeAliasDecl
public class TypeAliasDecl <: Decl {
public init()
public init(inputs: Tokens)
}
Description: Specifies a type alias node.
Example of a TypeAliasDecl node: type Point2D = Float64
Note:
In this node,
typeis used as a keyword and is followed by any valid identifier. The type on the right of the=is any top-level visible type.
Parent Type:
prop aliasType
public mut prop aliasType: TypeNode
Description: Obtains or sets the type whose alias is to be created.
Type: TypeNode
prop assign
public mut prop assign: Token
Description: Obtains or sets = between an identifier and type.
Type: Token
Throws:
- ASTException: If Token is not
=, this exception is thrown.
init()
public init()
Description: Constructs a default TypeAliasDecl object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a TypeAliasDecl object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the TypeAliasDecl type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the TypeAliasDecl node, this exception is thrown.
class TypeConvExpr
public class TypeConvExpr <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies a type conversion expression.
This class is used to implement the conversion between several numeric types. Example of a TypeConvExpr node: Int8(32)
Parent Type:
prop expr
public mut prop expr: Expr
Description: Obtains or sets the original expression for type conversion in TypeConvExpr.
Type: Expr
prop lParen
public mut prop lParen: Token
Description: Obtains or sets the left parenthesis "(" in TypeConvExpr.
Type: Token
Throws:
- ASTException: If Token is not a left parenthesis "(", this exception is thrown.
prop rParen
public mut prop rParen: Token
Description: Obtains or sets the right parenthesis ")" in TypeConvExpr.
Type: Token
Throws:
- ASTException: If Token is not a right parenthesis ")", this exception is thrown.
prop targetType
public mut prop targetType: PrimitiveType
Description: Obtains or sets the target type for conversion in TypeConvExpr.
Type: PrimitiveType
init()
public init()
Description: Constructs a default TypeConvExpr object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a TypeConvExpr object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the TypeConvExpr type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the TypeConvExpr node, this exception is thrown.
class TypeNode
public open class TypeNode <: Node
Description: Specifies the parent class of all type nodes, which is inherited from Node.
Parent Type:
prop typeParameterName
public mut prop typeParameterName: Token
Description: Obtains or sets the parameters of a type node, for example, p1 and p2 in (p1:Int64, p2:Int64), which may be ILLEGAL lexical units.
Type: Token
prop colon
public mut prop colon: Token
Description: Obtains or sets the operator colon (:) in a TypeNode node, which may be an ILLEGAL lexical unit.
Type: Token
Throws:
- ASTException: If Token is not the operator colon (:), this exception is thrown.
class TypePattern
public class TypePattern <: Pattern {
public init()
public init(inputs: Tokens)
}
Description: Specifies a type pattern node.
This class is used to check whether the runtime type of a value is a subtype of a certain type, for example, b: Base in case b: Base => 0.
Parent Type:
prop colon
public mut prop colon: Token
Description: Obtains or sets the lexical unit of the operator colon (:) in a TypePattern node.
Type: Token
Throws:
- ASTException: If Token is not the operator colon (:), this exception is thrown.
prop pattern
public mut prop pattern: Pattern
Description: Obtains or sets the pattern node in a TypePattern node.
Type: Pattern
prop patternType
public mut prop patternType: TypeNode
Description: Obtains or sets the pattern type node to be matched in a TypePattern node.
Type: TypeNode
init()
public init()
Description: Constructs a default TypePattern object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a TypePattern object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the TypePattern type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the TypePattern node, this exception is thrown.
class UnaryExpr
public class UnaryExpr <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies a unary operation expression node.
Parent Type:
prop expr
public mut prop expr: Expr
Description: Obtains or sets the operand in a UnaryExpr node.
Type: Expr
prop op
public mut prop op: Token
Description: Obtains or sets the unary operator in a UnaryExpr node.
Type: Token
init()
public init()
Description: Constructs a default UnaryExpr object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a UnaryExpr object.
Parameters:
Throws:
- ASTException: If the input Tokens type cannot be used to construct the UnaryExpr node, this exception is thrown.
class VArrayExpr
public class VArrayExpr <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies a VArray instance node.
Example of a VArrayExpr node: VArray<Int64, $5> { i => i} in let arr: VArray<Int64, $5> = VArray<Int64, $5> { i => i}
Parent Type:
prop arguments
public mut prop arguments: ArrayList<Argument>
Description: Obtains or sets the sequence of initialization parameters in VArrayExpr.
prop lParen
public mut prop lParen: Token
Description: Obtains or sets the left parenthesis "(" in VArrayExpr.
Type: Token
Throws:
- ASTException: If Token is not a left parenthesis "(", this exception is thrown.
prop rParen
public mut prop rParen: Token
Description: Obtains or sets the right parenthesis ")" in VArrayExpr.
Type: Token
Throws:
- ASTException: If Token is not a right parenthesis ")", this exception is thrown.
prop vArrayType
public mut prop vArrayType: VArrayType
Description: Obtains or sets the VArray type node of VArrayExpr.
Type: VArrayType
init()
public init()
Description: Constructs a default VArrayExpr object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a VArrayExpr object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the VArrayExpr type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the VArrayExpr node, this exception is thrown.
class VArrayType
public class VArrayType <: TypeNode {
public init()
public init(inputs: Tokens)
}
Description: Specifies a VArray node.
The generic VArray<T, size: Int64> is used to indicate a VArray type.
Parent Type:
prop dollar
public mut prop dollar: Token
Description: Obtains or sets the lexical unit operator $ in a VArrayType node.
Type: Token
Throws:
- ASTException: If Token is not the lexical unit
$, this exception is thrown.
prop elementTy
public mut prop elementTy: TypeNode
Description: Obtains or sets the type variable node in a VArrayType node, for example, Int16 in VArray<Int16, $0>.
Type: TypeNode
prop keyword
public mut prop keyword: Token
Description: Obtains or sets the lexical unit keyword VArray of a VArrayType node.
Type: Token
prop lAngle
public mut prop lAngle: Token
Description: Obtains or sets the lexical unit left angle bracket of a VArrayType node.
Type: Token
Throws:
- ASTException: If Token is not a left angle bracket, this exception is thrown.
prop rAngle
public mut prop rAngle: Token
Description: Obtains or sets the lexical unit right angle bracket of a VArrayType node.
Type: Token
Throws:
- ASTException: If Token is not a right angle bracket, this exception is thrown.
prop size
public mut prop size: Token
Description: Obtains or sets the lexical unit type length in a VArrayType node.
Type: Token
init()
public init()
Description: Constructs a default VArrayType object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a VArrayType object.
Parameters:
- inputs: Tokens: collection of lexical units (Tokens) used to construct the VArrayType type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the VArrayType node, this exception is thrown.
class VarDecl
public class VarDecl <: Decl {
public init()
public init(inputs: Tokens)
}
Description: Specifies a variable definition node.
Example of a VarDecl node: var a: String or var b: Int64 = 1
Note:
The definition of a variable consists of the following: modifier, keyword, patternsMaybeIrrefutable, variable type, and initial value.
Parent Type:
prop assign
public mut prop assign: Token
Description: Obtains or sets the location information of the assignment operator in a VarDecl node.
Type: Token
Throws:
- ASTException: If Token is not an assignment operator, this exception is thrown.
prop colon
public mut prop colon: Token
Description: Obtains or sets the location information of colons (:) in a VarDecl node.
Type: Token
Throws:
- ASTException: If Token is not a colon (:), this exception is thrown.
prop declType
public mut prop declType: TypeNode
Description: Obtains or sets the variable type of a VarDecl node.
Type: TypeNode
Throws:
- ASTException: If the VarDecl node does not declare the variable type, this exception is thrown.
prop expr
public mut prop expr: Expr
Description: Obtains or sets the variable initialization node of a VarDecl node.
Type: Expr
Throws:
- ASTException: If the VarDecl node does not initialize variables, this exception is thrown.
prop pattern
public mut prop pattern: Pattern
Description: Obtains or sets the pattern node of a VarDecl node.
Type: Pattern
Throws:
- ASTException: If the VarDecl node does not declare the pattern node, this exception is thrown.
init()
public init()
Description: Constructs a default VarDecl object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a VarDecl object.
Parameters:
Throws:
- ASTException: If the input Tokens type cannot be used to construct the VarDecl node, this exception is thrown.
func isConst()
public func isConst(): Bool
Description: Checks whether a node is of the Const type.
Returns:
- Bool: If the node is of the
Consttype, true is returned. Otherwise, false is returned.
class VarOrEnumPattern
public class VarOrEnumPattern <: Pattern {
public init()
public init(identifier: Token)
}
Description: Specifies a node when the identifier of a pattern is the Enum constructor.
Example: RED in case RED is the Enum constructor.
Parent Type:
prop identifier
public mut prop identifier: Token
Description: Obtains or sets the lexical unit identifier in a VarOrEnumPattern node.
Type: Token
init()
public init()
Description: Constructs a default VarOrEnumPattern object.
init(Tokens)
public init(identifier: Token)
Description: Constructs a VarOrEnumPattern object.
Parameters:
- identifier: Token: lexical unit used to construct the VarOrEnumPattern type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the VarOrEnumPattern node, this exception is thrown.
class VarPattern
public class VarPattern <: Pattern {
public init()
public init(identifier: Token)
}
Description: Specifies a binding pattern node.
This class is represented by a valid identifier, for example, i in for (i in 1..10).
Parent Type:
prop identifier
public mut prop identifier: Token
Description: Obtains or sets the lexical unit identifier in a VarPattern node.
Type: Token
init()
public init()
Description: Constructs a default VarPattern object.
init(Tokens)
public init(identifier: Token)
Description: Constructs a VarPattern object.
Parameters:
- identifier: Token: lexical unit used to construct the VarPattern type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the VarPattern node, this exception is thrown.
class Visitor
public abstract class Visitor
Description: Specifies an abstract class that defines default visit functions for accessing different types of AST nodes.
Note:
- The
visitfunctions can be used together withtraverseto access and modify nodes. Allvisitfunctions have empty implementations by default. Specificvisitmethods can be implemented as required.- This class needs to be inherited and allows subclasses to redefine access functions.
func breakTraverse()
public func breakTraverse(): Unit
Description: Rewrites the visit function and calls this function to terminate subnodes traversal.
class WhileExpr
public class WhileExpr <: Expr {
public init()
public init(inputs: Tokens)
}
Description: Specifies a while expression.
while is the keyword, followed by a pair of parentheses, which may have an expression or a deconstruction match of the let declaration enclosed in them, and then followed by a Block node.
Parent Type:
prop block
public mut prop block: Block
Description: Obtains or sets the block node in WhileExpr.
Type: Block
prop condition
public mut prop condition: Expr
Description: Obtains or sets the condition expression in the keyword WhileExpr.
Type: Expr
prop keyword
public mut prop keyword: Token
Description: Obtains or sets the keyword while in a WhileExpr node.
Type: Token
Throws:
- ASTException: If Token is not the keyword
while, this exception is thrown.
prop lParen
public mut prop lParen: Token
Description: Obtains or sets the left parenthesis "(" following the keyword while in WhileExpr.
Type: Token
Throws:
- ASTException: If Token is not a left parenthesis "(", this exception is thrown.
prop rParen
public mut prop rParen: Token
Description: Obtains or sets the right parenthesis ")" following the keyword while in WhileExpr.
Type: Token
Throws:
- ASTException: If Token is not a right parenthesis ")", this exception is thrown.
init()
public init()
Description: Constructs a default WhileExpr object.
init(Tokens)
public init(inputs: Tokens)
Description: Constructs a WhileExpr object.
Parameters:
Throws:
- ASTException: If the input Tokens type cannot be used to construct the WhileExpr node, this exception is thrown.
class WildcardExpr
public class WildcardExpr <: Expr {
public init()
public init(keyword: Tokens)
}
Description: Specifies a wildcard expression node.
Parent Type:
prop keyword
public mut prop keyword: Token
Description: Obtains the keyword underscore (_) in WildcardExpr.
Type: Token
Throws:
- ASTException: If Token is not the keyword underscore (_), this exception is thrown.
init()
public init()
Description: Constructs a default WildcardExpr object.
init(Tokens)
public init(keyword: Tokens)
Description: Constructs a WildcardExpr object.
Parameters:
- keyword: Tokens: collection of lexical units (Tokens) used to construct the WildcardExpr type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the WildcardExpr node, this exception is thrown.
class WildcardPattern
public class WildcardPattern <: Pattern {
public init()
public init(keyword: Tokens)
}
Description: Specifies a wildcard pattern node.
This class is represented by an underscore (_) and can match any value.
Parent Type:
prop wildcard
public mut prop wildcard: Token
Description: Obtains or sets the lexical unit of the operator underscore (_) in a WildcardPattern node.
Type: Token
Throws:
- ASTException: If Token is not the operator underscore (_), this exception is thrown.
init()
public init()
Description: Constructs a default WildcardPattern object.
init(Tokens)
public init(keyword: Tokens)
Description: Constructs a WildcardPattern object.
Parameters:
- keyword: Tokens: collection of lexical units (Tokens) used to construct the WildcardPattern type
Throws:
- ASTException: If the input Tokens type cannot be used to construct the WildcardPattern node, this exception is thrown.
Enumeration
enum DiagReportLevel
public enum DiagReportLevel {
ERROR|
WARNING
}
Description: Specifies information levels supported by an error reporting interface. ERROR and WARNING are supported.
ERROR
ERROR
Description: Constructs an enumeration instance that indicates ERROR.
WARNING
WARNING
Description: Constructs an enumeration instance that indicates WARNING.
func level()
public func level(): Int32
Description: Returns the integer corresponding to an enumerated value.
Returns:
- Int32: integer corresponding to the enumerated value For
ERROR, 0 is returned. ForWARNING, 1 is returned.
enum ImportKind
public enum ImportKind <: ToString {
Single | Alias | All | Multi
}
Description: Specifies the type of an imported statement.
Parent Type:
Single
Single
Description: Specifies the single import, for example, import a.b.
Alias
Alias
Description: Specifies the alias import, for example, import a.b as c.
All
All
Description: Specifies the full import, for example, import a.b.*.
Multi
Multi
Description: Specifies the multiple imports, for example, import a.{b, c, d}.
func toString()
public func toString(): String
Description: Converts the ImportKind type to a string representation.
Returns:
- String: string value obtained through the ImportKind conversion
enum TokenKind
public enum TokenKind <: ToString {
DOT| /* "." */
COMMA| /* "," */
LPAREN| /* "(" */
RPAREN| /* ")" */
LSQUARE| /* "[" */
RSQUARE| /* "]" */
LCURL| /* "{" */
RCURL| /* "}" */
EXP| /* "**" */
MUL| /* "*" */
MOD| /* "%" */
DIV| /* "/" */
ADD| /* "+" */
SUB| /* "-" */
INCR| /* "++" */
DECR| /* "--" */
AND| /* "&&" */
OR| /* "||" */
COALESCING| /* "??" */
PIPELINE| /* "|>" */
COMPOSITION| /* "~>" */
NOT| /* "!" */
BITAND| /* "&" */
BITOR| /* "|" */
BITXOR| /* "^" */
BITNOT| /* "~" */
LSHIFT| /* "<<" */
RSHIFT| /* ">>" */
COLON| /* ":" */
SEMI| /* ";" */
ASSIGN| /* "=" */
ADD_ASSIGN| /* "+=" */
SUB_ASSIGN| /* "-=" */
MUL_ASSIGN| /* "*=" */
EXP_ASSIGN| /* "**=" */
DIV_ASSIGN| /* "/=" */
MOD_ASSIGN| /* "%=" */
AND_ASSIGN| /* "&&=" */
OR_ASSIGN| /* "||=" */
BITAND_ASSIGN| /* "&=" */
BITOR_ASSIGN| /* "|=" */
BITXOR_ASSIGN| /* "^=" */
LSHIFT_ASSIGN| /* "<<=" */
RSHIFT_ASSIGN| /* ">>=" */
ARROW| /* "->" */
BACKARROW| /* "<-" */
DOUBLE_ARROW| /* "=>" */
RANGEOP| /* ".." */
CLOSEDRANGEOP| /* "..=" */
ELLIPSIS| /* "..." */
HASH| /* "#" */
AT| /* "@" */
QUEST| /* "?" */
LT| /* "<" */
GT| /* ">" */
LE| /* "<=" */
GE| /* ">=" */
IS| /* "is" */
AS| /* "as" */
NOTEQ| /* "!=" */
EQUAL| /* "==" */
WILDCARD| /* "_" */
INT8| /* "Int8" */
INT16| /* "Int16" */
INT32| /* "Int32" */
INT64| /* "Int64" */
INTNATIVE| /* "IntNative" */
UINT8| /* "UInt8" */
UINT16| /* "UInt16" */
UINT32| /* "UInt32" */
UINT64| /* "UInt64" */
UINTNATIVE| /* "UIntNative" */
FLOAT16| /* "Float16" */
FLOAT32| /* "Float32" */
FLOAT64| /* "Float64" */
RUNE| /* "Rune" */
BOOLEAN| /* "Bool" */
NOTHING| /* "Nothing" */
UNIT| /* "Unit" */
STRUCT| /* "struct" */
ENUM| /* "enum" */
CFUNC| /* "CFunc" */
VARRAY| /* "VArray" */
THISTYPE| /* "This" */
PACKAGE| /* "package" */
IMPORT| /* "import" */
CLASS| /* "class" */
INTERFACE| /* "interface" */
FUNC| /* "func" */
MACRO| /* "macro" */
QUOTE| /* "quote" */
DOLLAR| /* "$" */
LET| /* "let" */
VAR| /* "var" */
CONST| /* "const" */
TYPE| /* "type" */
INIT| /* "init" */
THIS| /* "this" */
SUPER| /* "super" */
IF| /* "if" */
ELSE| /* "else" */
CASE| /* "case" */
TRY| /* "try" */
CATCH| /* "catch" */
FINALLY| /* "finally" */
FOR| /* "for" */
DO| /* "do" */
WHILE| /* "while" */
THROW| /* "throw" */
RETURN| /* "return" */
CONTINUE| /* "continue" */
BREAK| /* "break" */
IN| /* "in" */
NOT_IN| /* "!in" */
MATCH| /* "match" */
WHERE| /* "where" */
EXTEND| /* "extend" */
WITH| /* "with" */
PROP| /* "prop" */
STATIC| /* "static" */
PUBLIC| /* "public" */
PRIVATE| /* "private" */
INTERNAL| /* "internal" */
PROTECTED| /* "protected" */
OVERRIDE| /* "override" */
REDEF| /* "redef" */
ABSTRACT| /* "abstract" */
SEALED| /* "sealed" */
OPEN| /* "open" */
FOREIGN| /* "foreign" */
INOUT| /* "inout" */
MUT| /* "mut" */
UNSAFE| /* "unsafe" */
OPERATOR| /* "operator" */
SPAWN| /* "spawn" */
SYNCHRONIZED| /* "synchronized" */
UPPERBOUND| /* "<:" */
MAIN| /* "main" */
IDENTIFIER| /* "x" */
PACKAGE_IDENTIFIER| /* e.g. "x-y" */
INTEGER_LITERAL| /* e.g. "1" */
RUNE_BYTE_LITERAL| /* e.g. "b'x'" */
FLOAT_LITERAL| /* e.g. "'1.0'" */
COMMENT| /* e.g. "/*xx*/" */
NL| /* newline */
END| /* end of file */
SENTINEL| /* ";" */
RUNE_LITERAL| /* e.g. "r'x'" */
STRING_LITERAL| /* e.g. ""xx"" */
JSTRING_LITERAL| /* e.g. "J"xx"" */
MULTILINE_STRING| /* e.g. """"aaa"""" */
MULTILINE_RAW_STRING| /* e.g. "#"aaa"#" */
BOOL_LITERAL| /* "true" or "false" */
UNIT_LITERAL| /* "()" */
DOLLAR_IDENTIFIER| /* e.g. "$x" */
ANNOTATION| /* e.g. "@When" */
ILLEGAL
}
Description: Specifies all lexical structures in Cangjie compilation, including symbols, keywords, identifiers, and line breaks.
Parent Type:
ABSTRACT
ABSTRACT
Description: Constructs an abstract enumeration instance.
ADD
ADD
Description: Constructs an enumeration instance that indicates +.
ADD_ASSIGN
ADD_ASSIGN
Description: Constructs an enumeration instance that indicates +=.
AND
AND
Description: Constructs an enumeration instance that indicates &&.
AND_ASSIGN
AND_ASSIGN
Description: Constructs an enumeration instance that indicates &&=.
ANNOTATION
ANNOTATION
Description: Constructs an annotation enumeration instance.
ARROW
ARROW
Description: Constructs an enumeration instance that indicates ->.
AS
AS
Description: Constructs an as enumeration instance.
ASSIGN
ASSIGN
Description: Constructs an enumeration instance that indicates =.
AT
AT
Description: Constructs an enumeration instance that indicates @.
BACKARROW
BACKARROW
Description: Constructs an enumeration instance that indicates <-.
BITAND
BITAND
Description: Constructs an enumeration instance that indicates &.
BITAND_ASSIGN
BITAND_ASSIGN
Description: Constructs an enumeration instance that indicates &=.
BITNOT
BITNOT
Description: Constructs an enumeration instance that indicates ~.
BITOR
BITOR
Description: Constructs an enumeration instance that indicates |.
BITOR_ASSIGN
BITOR_ASSIGN
Description: Constructs an enumeration instance that indicates |=.
BITXOR
BITXOR
Description: Constructs an enumeration instance that indicates ^.
BITXOR_ASSIGN
BITXOR_ASSIGN
Description: Constructs an enumeration instance that indicates ^=.
BOOLEAN
BOOLEAN
Description: Constructs a bool enumeration instance.
BOOL_LITERAL
BOOL_LITERAL
Purpose: Constructs a Boolean literal enumeration instance.
BREAK
BREAK
Description: Constructs a break enumeration instance.
CASE
CASE
Description: Constructs a case enumeration instance.
CATCH
CATCH
Description: Constructs a catch enumeration instance.
CFUNC
CFUNC
Description: Constructs a cfunc enumeration instance.
CLASS
CLASS
Description: Constructs a class enumeration instance.
CLOSEDRANGEOP
CLOSEDRANGEOP
Description: Constructs an enumeration instance that indicates ..=.
COALESCING
COALESCING
Description: Constructs an enumeration instance that indicates ??.
COLON
COLON
Description: Constructs an enumeration instance that indicates :.
COMMA
COMMA
Description: Constructs an enumeration instance that indicates ,.
COMMENT
COMMENT
Description: Constructs a comment enumeration instance.
COMPOSITION
COMPOSITION
Description: Constructs an enumeration instance that indicates ~>.
CONST
CONST
Description: Constructs a const enumeration instance.
CONTINUE
CONTINUE
Description: Constructs a continue enumeration instance.
DECR
DECR
Description: Constructs an enumeration instance that indicates --.
DIV
DIV
Description: Constructs an enumeration instance that indicates /.
DIV_ASSIGN
DIV_ASSIGN
Description: Constructs an enumeration instance that indicates /=.
DO
DO
Description: Constructs a do enumeration instance.
DOLLAR
DOLLAR
Description: Constructs an enumeration instance that indicates $.
DOLLAR_IDENTIFIER
DOLLAR_IDENTIFIER
Description: Constructs an interpolated string enumeration instance.
DOT
DOT
Description: Constructs an enumeration instance that indicates ..
DOUBLE_ARROW
DOUBLE_ARROW
Description: Constructs an enumeration instance that indicates =>.
ELLIPSIS
ELLIPSIS
Description: Constructs an enumeration instance that indicates ....
ELSE
ELSE
Description: Constructs an else enumeration instance.
END
END
Description: Constructs an EOF enumeration instance.
ENUM
ENUM
Description: Constructs an enum enumeration instance.
EQUAL
EQUAL
Description: Constructs an enumeration instance that indicates ==.
EXP
EXP
Description: Constructs an enumeration instance that indicates ******.
EXP_ASSIGN
EXP_ASSIGN
Description: Constructs an enumeration instance that indicates ****=**.
EXTEND
EXTEND
Description: Constructs an extend enumeration instance.
FINALLY
FINALLY
Description: Constructs a finally enumeration instance.
FLOAT16
FLOAT16
Description: Constructs a float16 enumeration instance.
FLOAT32
FLOAT32
Description: Constructs a float32 enumeration instance.
FLOAT64
FLOAT64
Description: Constructs a float64 enumeration instance.
FLOAT_LITERAL
FLOAT_LITERAL
Purpose: Constructs a floating-point literal enumeration instance.
FOR
FOR
Description: Constructs a for enumeration instance.
FOREIGN
FOREIGN
Description: Constructs a foreign enumeration instance.
FUNC
FUNC
Description: Constructs a func enumeration instance.
GE
GE
Description: Constructs an enumeration instance that indicates >=.
GT
GT
Description: Constructs an enumeration instance that indicates >.
HASH
HASH
Description: Constructs an enumeration instance that indicates #.
IDENTIFIER
IDENTIFIER
Description: Constructs an identifier enumeration instance.
PACKAGE_IDENTIFIER
PACKAGE_IDENTIFIER
Description: Constructs a package identifier enumeration instance.
IF
IF
Description: Constructs a if enumeration instance.
ILLEGAL
ILLEGAL
Description: Constructs an illegal enumeration instance.
IMPORT
IMPORT
Description: Constructs an import enumeration instance.
IN
IN
Description: Constructs an in enumeration instance.
INCR
INCR
Description: Constructs an enumeration instance that indicates ++.
INIT
INIT
Description: Constructs an init enumeration instance.
INOUT
INOUT
Description: Constructs an inout enumeration instance.
INT16
INT16
Description: Constructs an int16 enumeration instance.
INT32
INT32
Description: Constructs an int32 enumeration instance.
INT64
INT64
Description: Constructs an int64 enumeration instance.
INT8
INT8
Description: Constructs an int8 enumeration instance.
INTEGER_LITERAL
INTEGER_LITERAL
Purpose: Constructs an integer literal enumeration instance.
INTERFACE
INTERFACE
Description: Constructs an interface enumeration instance.
INTERNAL
INTERNAL
Description: Constructs an internal enumeration instance.
INTNATIVE
INTNATIVE
Description: Constructs an intnative enumeration instance.
IS
IS
Description: Constructs an is enumeration instance.
JSTRING_LITERAL
JSTRING_LITERAL
Description: Constructs a JavaSTRING literal enumeration instance.
LCURL
LCURL
Description: Constructs an enumeration instance that indicates {.
LE
LE
Description: Constructs an enumeration instance that indicates <=.
LET
LET
Description: Constructs a let enumeration instance.
LPAREN
LPAREN
Description: Constructs an enumeration instance that indicates (.
LSHIFT
LSHIFT
Description: Constructs an enumeration instance that indicates <<.
LSHIFT_ASSIGN
LSHIFT_ASSIGN
Description: Constructs an enumeration instance that indicates <<=.
LSQUARE
LSQUARE
Description: Constructs an enumeration instance that indicates [.
LT
LT
Description: Constructs an enumeration instance that indicates <.
MACRO
MACRO
Description: Constructs a macro enumeration instance.
MAIN
MAIN
Description: Constructs a main enumeration instance.
MATCH
MATCH
Description: Constructs a match enumeration instance.
MOD
MOD
Description: Constructs an enumeration instance that indicates %.
MOD_ASSIGN
MOD_ASSIGN
Description: Constructs an enumeration instance that indicates %=.
MUL
MUL
Description: Constructs an enumeration instance that indicates *****.
MULTILINE_RAW_STRING
MULTILINE_RAW_STRING
Description: Constructs a multi-line original string literal enumeration instance.
MULTILINE_STRING
MULTILINE_STRING
Description: Constructs a multi-line string literal enumeration instance.
MUL_ASSIGN
MUL_ASSIGN
Description: Constructs an enumeration instance that indicates *=.
MUT
MUT
Description: Constructs a mut enumeration instance.
NL
NL
Description: Constructs a newline character enumeration instance.
NOT
NOT
Description: Constructs an enumeration instance that indicates !.
NOTEQ
NOTEQ
Description: Constructs an enumeration instance that indicates !=.
NOTHING
NOTHING
Description: Constructs a nothing enumeration instance.
NOT_IN
NOT_IN
Description: Constructs an enumeration instance that indicates !in.
OPEN
OPEN
Description: Constructs an open enumeration instance.
OPERATOR
OPERATOR
Description: Constructs an operator enumeration instance.
OR
OR
Description: Constructs an enumeration instance that indicates ||.
OR_ASSIGN
OR_ASSIGN
Description: Constructs an enumeration instance that indicates ||=.
OVERRIDE
OVERRIDE
Description: Constructs an override enumeration instance.
PACKAGE
PACKAGE
Description: Constructs a package enumeration instance.
PIPELINE
PIPELINE
Description: Constructs an enumeration instance that indicates |>.
PRIVATE
PRIVATE
Description: Constructs a private enumeration instance.
PROP
PROP
Description: Constructs a prop enumeration instance.
PROTECTED
PROTECTED
Description: Constructs a protected enumeration instance.
PUBLIC
PUBLIC
Description: Constructs a public enumeration instance.
QUEST
QUEST
Description: Constructs an enumeration instance that indicates ?.
QUOTE
QUOTE
Description: Constructs a quote enumeration instance.
RANGEOP
RANGEOP
Description: Constructs an enumeration instance that indicates ...
RCURL
RCURL
Description: Constructs an enumeration instance that indicates }.
REDEF
REDEF
Description: Constructs a redef enumeration instance.
RETURN
RETURN
Description: Constructs a return enumeration instance.
RPAREN
RPAREN
Description: Constructs an enumeration instance that indicates ).
RSHIFT
RSHIFT
Description: Constructs an enumeration instance that indicates >>.
RSHIFT_ASSIGN
RSHIFT_ASSIGN
Description: Constructs an enumeration instance that indicates >>=.
RSQUARE
RSQUARE
Description: Constructs an enumeration instance that indicates ].
RUNE
RUNE
Description: Constructs a Rune enumeration instance.
RUNE_BYTE_LITERAL
RUNE_BYTE_LITERAL
Description: Constructs a character byte literal enumeration instance.
RUNE_LITERAL
RUNE_LITERAL
Description: Constructs a character literal enumeration instance.
SEALED
SEALED
Description: Constructs a sealed enumeration instance.
SEMI
SEMI
Description: Constructs an enumeration instance that indicates ;.
SENTINEL
SENTINEL
Description: Constructs an enumeration instance that indicates ;.
SPAWN
SPAWN
Description: Constructs a spawn enumeration instance.
STATIC
STATIC
Description: Constructs a static enumeration instance.
STRING_LITERAL
STRING_LITERAL
Description: Constructs a string literal enumeration instance.
STRUCT
STRUCT
Description: Constructs a struct enumeration instance.
SUB
SUB
Description: Constructs an enumeration instance that indicates -.
SUB_ASSIGN
SUB_ASSIGN
Description: Constructs an enumeration instance that indicates -=.
SUPER
SUPER
Description: Constructs a super enumeration instance.
SYNCHRONIZED
SYNCHRONIZED
Description: Constructs a synchronized enumeration instance.
THIS
THIS
Description: Constructs a this enumeration instance.
THISTYPE
THISTYPE
Description: Constructs a This enumeration instance.
THROW
THROW
Description: Constructs a throw enumeration instance.
TRY
TRY
Description: Constructs a try enumeration instance.
TYPE
TYPE
Description: Constructs a type enumeration instance.
UINT16
UINT16
Description: Constructs a uint16 enumeration instance.
UINT32
UINT32
Description: Constructs a uint32 enumeration instance.
UINT64
UINT64
Description: Constructs a uint64 enumeration instance.
UINT8
UINT8
Description: Constructs a uint8 enumeration instance.
UINTNATIVE
UINTNATIVE
Description: Constructs a uintnative enumeration instance.
UNIT
UNIT
Description: Constructs a unit enumeration instance.
UNIT_LITERAL
UNIT_LITERAL
Description: Constructs a unit literal enumeration instance.
UNSAFE
UNSAFE
Description: Constructs an unsafe enumeration instance.
UPPERBOUND
UPPERBOUND
Description: Constructs an enumeration instance that indicates <:.
VAR
VAR
Description: Constructs a var enumeration instance.
VARRAY
VARRAY
Description: Constructs a varray enumeration instance.
WHERE
WHERE
Description: Constructs a where enumeration instance.
WHILE
WHILE
Description: Constructs a while enumeration instance.
WILDCARD
WILDCARD
Description: Constructs an enumeration instance that indicates _.
WITH
WITH
Description: Constructs a with enumeration instance.
func !=(TokenKind)
public operator func !=(right: TokenKind): Bool
Description: Overloads the inequality operator to check whether two TokenKind instances are equal.
Returns:
- Bool: Boolean value
func ==(TokenKind)
public operator func ==(right: TokenKind): Bool
Description: Overloads the equal operator to check whether two TokenKind instances are equal.
Returns:
- Bool: Boolean value
func toString()
public func toString(): String
Description: Converts a TokenKind instance to a string.
Returns:
Struct
struct Position
public struct Position {
public let column: Int32
public let fileID: UInt32
public let line: Int32
public init()
public init(fileID: UInt32, line: Int32, column: Int32)
}
Description: Specifies the data structure of location information, including the file ID, line number, and column number.
let column
public let column: Int32
Description: Obtains a column number.
Type: Int32
let fileID
public let fileID: UInt32
Description: Obtains a file ID.
Type: UInt32
let line
public let line: Int32
Description: Obtains a line number.
Type: Int32
init()
public init()
Description: Constructs a default Position instance, in which, the fileID, line, and column member variables are all 0.
init(UInt32, Int32, Int32)
public init(fileID: UInt32, line: Int32, column: Int32)
Description: Constructs a Position instance.
Parameters:
func dump()
public func dump(): Unit
Description: Print the information of a Position instance.
func isEmpty()
public func isEmpty(): Bool
Description: Checks whether both the line number and column number are 0.
Returns:
- Bool: true is returned if both the line number and column number are
0.
operator func !=(Position)
public operator func !=(r: Position): Bool
Description: Checks whether two Position instances are not equal.
Parameters:
- r: Position: the other location instance to be compared with the current location
Returns:
operator func ==(Position)
public operator func ==(r: Position): Bool
Description: Checks whether two Position instances are equal.
Parameters:
- r: Position: the other location instance to be compared with the current location
Returns:
struct Token
public struct Token {
public let kind: TokenKind
public let pos: Position
public let value: String
public var delimiterNum: UInt16 = 1
public init()
public init(kind: TokenKind)
public init(kind: TokenKind, value: String)
}
Description: Specifies lexical unit types.
A lexical unit is the minimum unit of Cangjie source code. A syntax tree node can be generated after syntax parsing performed on a group of valid lexical units.
let kind
public let kind: TokenKind
Description: Obtains the type of a lexical unit. Lexical unit types include keywords, identifiers, operators, and constant values. For details, see TokenKind.
Type: TokenKind
let pos
public let pos: Position
Description: Obtains the location of a lexical unit in source code.
Type: Position
let value
public let value: String
Description: Obtains the literal value of a lexical unit.
Type: String
var delimiterNum
public var delimiterNum: UInt16 = 1
Description: Obtains and sets the '#' quantity in a multi-line string.
Type: UInt16
init()
public init()
Description: Constructs a default Token object, in which, the TokenKind instance is ILLEGAL, the value is an empty string, and member variables of the Position instance are all 0.
init(TokenKind)
public init(kind: TokenKind)
Description: Constructs a default Token object based on a lexical unit type.
Parameters:
- kind: TokenKind: type of the lexical unit to be constructed
init(TokenKind, String)
public init(kind: TokenKind, value: String)
Description: Constructs a Token object based on the lexical unit type kind and lexical unit value value.
Parameters:
- kind: TokenKind: type of the lexical unit to be constructed
- value: String:
valuevalue of the lexical unit to be constructed
Throws:
- IllegalArgumentException: If the passed
kinddoes not matchvalue, this exception is thrown.
func addPosition(UInt32, Int32, Int32)
public func addPosition(fileID: UInt32, line: Int32, colum: Int32): Token
Description: Adds the location information of a lexical unit.
Parameters:
- fileID: UInt32: fileID of Token
- line: Int32: number of the line where Token is located
- colum: Int32: number of the column where Token is located
Returns:
func dump()
public func dump(): Unit
Description: Print the information of a Token instance.
operator func !=(Token)
public operator func !=(r: Token): Bool
Description: Checks whether two Token objects are not equal.
Parameters:
Returns:
- Bool: If the type
ID, value, and location of one lexical unit are different from those of another one, true is returned.
operator func +(Token)
public operator func +(r: Token): Tokens
Description: Obtains a new Tokens instance by adding the current Token instance with another Token instance.
Parameters:
Returns:
operator func +(Tokens)
public operator func +(r: Tokens): Tokens
Description: Obtains a new Tokens instance by adding the current Token instance with a Tokens instance.
Parameters:
Returns:
operator func ==(Token)
public operator func ==(r: Token): Bool
Description: Checks whether two Token objects are equal.
Parameters:
Returns:
- Bool: If the type
ID, value, and location of one lexical unit are the same as those of another one, true is returned.
Exception Class
class ASTException
public class ASTException <: Exception {
public init()
public init(message: String)
}
Description: Specifies the exception class of the ast library used when an exception occurs during ast library calling.
Parent Type:
init()
public init()
Description: Constructs a default ASTException object.
init(String)
public init(message: String)
Description: Constructs an ASTException object based on exception information.
Parameters:
- message: String: exception information
class MacroContextException
public class MacroContextException <: Exception {
public init()
public init(message: String)
}
Description: Specifies the context macro exception class of the ast library used when an exception occurs in context macro-related APIs.
Parent Type:
init()
public init()
Description: Constructs a default MacroContextException object.
init(String)
public init(message: String)
Description: Constructs a MacroContextException object based on exception information.
Parameters:
- message: String: exception information
class ParseASTException
public class ParseASTException <: Exception {
public init()
public init(message: String)
}
Description: Specifies the parsing exception class of the ast library used when an exception occurs during node parsing.
Parent Type:
init()
public init()
Description: Constructs a default ParseASTException object.
init(String)
public init(message: String)
Description: Constructs a ParseASTException object based on exception information.
Parameters:
- message: String: exception information
Macro With Context
Macro definition:
// macro_definition.cj
macro package macro_definition
import std.ast.*
public macro Outter(input: Tokens): Tokens {
return input
}
public macro Inner(input: Tokens): Tokens {
assertParentContext("Outter")
return input
}
Macro call:
// macro_call.cj
package macro_calling
import macro_definition.*
main() {
@Outter var a = 0
@Inner var b = 0 // error: The macro call 'Inner' should with the surround code contains a call 'Outter'.
}
Compilation commands:
# Compile the macro definition file.
cjc macro_definition.cj --compile-macro
# Compile the file of the macro to be used.
cjc macro_call.cj -o demo
As shown in the preceding code, the Inner macro uses the assertParentContext function to check whether it is within the Outter macro during a call. The macro call code example indicates such a nesting relationship does not exist between the two macros during the call. Therefore, the compiler reports an error.
Macro definition:
// macro_definition.cj
macro package macro_definition
import std.ast.*
public macro Outter(input: Tokens): Tokens {
let messages = getChildMessages("Inner")
for (m in messages) {
let value1 = m.getString("key1") // get value: "value1"
let value2 = m.getString("key2") // get value: "value2"
println("value1: ${value1} value2: ${value2}")
}
return input
}
public macro Inner(input: Tokens): Tokens {
assertParentContext("Outter")
setItem("key1", "value1")
setItem("key2", "value2")
return input
}
Macro call:
// macro_call.cj
import std.ast.*
import macro_definition.*
main() {
@Outter(
@Inner var cnt = 0
)
println(cnt)
}
Compilation commands:
# Compile the macro definition file.
cjc macro_definition.cj --compile-macro
# Compile the file of the macro to be used.
cjc macro_call.cj -o demo
Compilation output:
value1: value1 value2: value2
In the preceding code, the inner macro Inner sends messages to the outer macro through setItem. The Outter macro receives a group of message objects from Inner through the getChildMessages function (Inner can be called for multiple times in Outter) and obtains the corresponding value of the message objects through the getString function.
Syntax Tree Node Print
The Cangjie ast package provides various syntax tree nodes to represent Cangjie source code. Various types of nodes and different attributes of different nodes may cause confusion. Therefore, the dump function is implemented for each AST node to view the overall structure of syntax tree nodes in real time, avoiding repeated reading of this manual.
Example:
import std.ast.*
main() {
let input = quote(var demo: Int64 = 1) // Assume that the current code is in line 3.
let varDecl = parseDecl(input)
varDecl.dump()
}
Running result:
VarDecl {
-keyword: Token {
value: "var"
kind: VAR
pos: 3: 23
}
-identifier: Token {
value: "demo"
kind: IDENTIFIER
pos: 3: 27
}
-declType: PrimitiveType {
-keyword: Token {
value: "Int64"
kind: INT64
pos: 3: 33
}
}
-assign: Token {
value: "="
kind: ASSIGN
pos: 3: 39
}
-expr: LitConstExpr {
-literal: Token {
value: "1"
kind: INTEGER_LITERAL
pos: 3: 41
}
}
}
AST Object Operation Example
After a node of the ClassDecl type is obtained, the node can be added, deleted, modified, and queried. The code is as follows:
import std.ast.*
main() {
let input: Tokens = quote(
class Data {
var a: Int32
init(a_: Int32) {
a = a_
}
}
)
let decl = parseDecl(input) // Obtains a **Decl** declaration node.
var classDecl = match (decl as ClassDecl) { // Performs type conversion on **decl**, of which the specific type is **ClassDecl**.
case Some(v) => v
case None => throw Exception()
}
var identifier = classDecl.identifier
// Adds a function to the node for obtaining the value of **a**.
var funcdecl = FuncDecl(quote(func getValue() {a}))
classDecl.body.decls.append(funcdecl)
println("Identifier value is ${identifier.value}")
println("ClassDecl body size is ${classDecl.body.decls.size}")
0
}
Running result:
Identifier value is Data
ClassDecl body size is 3
Example of Parsing Cangjie Source Code into an AST Object
The following is a class named Data:
class Data {
var a: Int32
init(a_: Int32) {
a = a_
}
}
Use the parsing function to parse the preceding code into a Decl object as follows:
import std.ast.*
main() {
let input: Tokens = quote(
class Data {
var a: Int32
init(a_: Int32) {
a = a_
}
}
)
let decl = parseDecl(input) // Obtains a **Decl** declaration node.
var classDecl = match (decl as ClassDecl) { // Performs type conversion on **decl**, of which the specific type is **ClassDecl**.
case Some(v) => v
case None => throw Exception()
}
classDecl.dump()
}
Running result:
ClassDecl {
-keyword: Token {
value: "class"
kind: CLASS
pos: 5: 9
}
-identifier: Token {
value: "Data"
kind: IDENTIFIER
pos: 5: 15
}
-body: Body {
-decls: 0, VarDecl {
-keyword: Token {
value: "var"
kind: VAR
pos: 6: 13
}
-identifier: Token {
value: "a"
kind: IDENTIFIER
pos: 6: 17
}
-declType: PrimitiveType {
-keyword: Token {
value: "Int32"
kind: INT32
pos: 6: 20
}
}
}
-decls: 1, FuncDecl {
-keyword: Token {
value: "init"
kind: INIT
pos: 7: 13
}
-identifier: Token {
value: "init"
kind: IDENTIFIER
pos: 7: 13
}
-funcParams: 0, FuncParam {
-identifier: Token {
value: "a_"
kind: IDENTIFIER
pos: 7: 18
}
-colon: Token {
value: ":"
kind: COLON
pos: 7: 20
}
-paramType: PrimitiveType {
-keyword: Token {
value: "Int32"
kind: INT32
pos: 7: 22
}
}
}
-block: Block {
-nodes: 0, AssignExpr {
-leftExpr: RefExpr {
-identifier: Token {
value: "a"
kind: IDENTIFIER
pos: 8: 17
}
}
-assign: Token {
value: "="
kind: ASSIGN
pos: 8: 19
}
-rightExpr: RefExpr {
-identifier: Token {
value: "a_"
kind: IDENTIFIER
pos: 8: 21
}
}
}
}
}
}
}
User-defined Error Reporting API
The Cangjie ast package provides a user-defined error reporting API diagReport, so that users defining macros can perform user-defined error reporting on incorrect Tokens during parsing of input Tokens.
The user-defined error reporting API provides the same error output format as the native compiler and allows users to report WARNING and ERROR messages.
Usage Example
Macro definition:
// macro_definition.cj
macro package macro_definition
import std.ast.*
public macro testDef(input: Tokens): Tokens {
for (i in 0..input.size) {
if (input[i].kind == IDENTIFIER) {
diagReport(DiagReportLevel.ERROR, input[i..(i + 1)], "This expression is not allowed to contain identifier", "Here is the illegal identifier")
}
}
return input
}
Macro call:
// macro_call.cj
package macro_calling
import std.ast.*
import macro_definition.*
main(): Int64 {
let a = @testDef(1)
let b = @testDef(a)
let c = @testDef(1 + a)
return 0
}
Compilation commands:
# Compile the macro definition file.
cjc macro_definition.cj --compile-macro
# Compile the file of the macro to be used.
cjc macro_call.cj -o demo
Error message:
error: This expression is not allowed to contain identifier
==> call.cj:9:22:
|
9 | let b = @testDef(a)
| ^ Here is the illegal identifier
|
error: This expression is not allowed to contain identifier
==> call.cj:10:26:
|
10 | let c = @testDef(1 + a)
| ^ Here is the illegal identifier
|
2 errors generated, 2 errors printed.
Example of a Call Not in Macro Expansion
import std.ast.*
func A(input: Tokens) {
diagReport(DiagReportLevel.ERROR, input, "Message", "Hint") // The call is in common function **A**. **diagReport** does not perform any operation.
}
main() {
let tokens = quote(var a = 0)
A(tokens)
}
Example of Traversing AST Objects Using a User-defined Access Function
Defining the behavior of accessing the variable declaration node: Inherit Visitor, re-write the access function, find the undefined variable, and store lexical units of the variable.
import std.ast.*
class MyVisitor <: Visitor {
public var unitializedVars = Tokens() // Stores the lexical units of the variable.
override public func visit(varDecl: VarDecl) {
try {
varDecl.expr
} catch (e: ASTException) {
unitializedVars.append(varDecl.identifier)
}
breakTraverse() // The subnodes of **varDecl** are not traversed.
return
}
}
main(): Int64 {
let input = quote(
var a : Int64
)
let varDecl = parseDecl(input)
let visitor = MyVisitor() // The processing for the **varDecl** node is defined in **MyVisitor**.
varDecl.traverse(visitor) // Processes the **varDecl** node.
println("Unitialized VarDecl size is ${visitor.unitializedVars.size}")
0
}
Running result:
Unitialized VarDecl size is 1
std.binary Package
Function Description
The binary package provides the following interfaces:
- Interface for conversion between a Cangjie data type and a binary byte sequence, which is classified into big-endian conversion and little-endian conversion; and
- Interface for big-endian and little-endian conversion of a Cangjie data type.
Notes:
- Generally, multi-byte objects are stored as consecutive byte sequences. In a memory or a digital communication link, the arranged order bytes is referred to as endianness, which is also referred to as a byte order.
- Bytes can be arranged in little-endian and big-endian modes. In little-endian mode, the least significant bit of a multi-bit number is stored at the smallest memory address and the most significant bit at the largest memory address, while in big-endian mode, the most significant bit is stored at the smallest memory address and the least significant bit at the largest memory address.
API List
Interface
| Name | Description |
|---|---|
| BigEndianOrder<T> | Big-endian byte sequence conversion interface |
| LittleEndianOrder<T> | Little-endian byte sequence conversion interface |
| SwapEndianOrder<T> | Byte order reversion interface |
Interface
interface BigEndianOrder<T>
public interface BigEndianOrder<T> {
func writeBigEndian(buffer: Array<Byte>): Int64
static func readBigEndian(buffer: Array<Byte>): T
}
Description: Specifies the big-endian byte sequence conversion interface.
static func readBigEndian(Array<Byte>)
static func readBigEndian(buffer: Array<Byte>): T
Description: Reads a T value from a byte array in big-endian mode.
Parameters:
Returns:
- T: T value
Throws:
- IllegalArgumentException: If buffer is insufficient for reading the T value, this exception is thrown.
func writeBigEndian(Array<Byte>)
func writeBigEndian(buffer: Array<Byte>): Int64
Description: Writes the T value to a byte array in big-endian mode.
Parameters:
Returns:
- Int64: number of bytes of the written data
Throws:
- IllegalArgumentException: If buffer is insufficient for storing the T value, this exception is thrown.
extend Bool <: BigEndianOrder<Bool>
extend Bool <: BigEndianOrder<Bool>
Description: Extends the BigEndianOrder interface for Bool to implement the conversion between Bool values and big-endian byte sequences.
Parent Type:
static func readBigEndian(Array<Byte>)
public static func readBigEndian(buffer: Array<Byte>): Bool
Description: Reads a Bool value from a byte array in big-endian mode.
Parameters:
Returns:
Throws:
- IllegalArgumentException: If buffer is insufficient for reading the Bool value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer: Array<Byte> = [0x1]
let n = Bool.readBigEndian(buffer)
@Assert(n, true)
}
func writeBigEndian(Array<Byte>)
public func writeBigEndian(buffer: Array<Byte>): Int64
Description: Writes a Bool value to a byte array in big-endian mode.
Parameters:
Returns:
- Int64: number of bytes of the written data
Throws:
- IllegalArgumentException: If buffer is insufficient for storing the Bool value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer = Array<Byte>(8, item: 0)
let n = true.writeBigEndian(buffer)
@Assert(n, 1)
@Assert(buffer[..n], [0x01u8])
}
extend Float16 <: BigEndianOrder<Float16>
extend Float16 <: BigEndianOrder<Float16>
Description: Extends the BigEndianOrder interface for Float16 to implement the conversion between Float16 values and big-endian byte sequences.
Parent Type:
static func readBigEndian(Array<Byte>)
public static func readBigEndian(buffer: Array<Byte>): Float16
Description: Reads a Float16 value from a byte array in big-endian mode.
Parameters:
Returns:
Throws:
- IllegalArgumentException: If buffer is insufficient for reading the Float16 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer: Array<Byte> = [0x4A, 0x40]
let n = Float16.readBigEndian(buffer)
@Assert(n, 12.5)
}
func writeBigEndian(Array<Byte>)
public func writeBigEndian(buffer: Array<Byte>): Int64
Description: Writes a Float16 value to a byte array in big-endian mode.
Parameters:
Returns:
- Int64: number of bytes of the written data
Throws:
- IllegalArgumentException: If buffer is insufficient for storing the Float16 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer = Array<Byte>(8, item: 0)
let n = 12.5f16.writeBigEndian(buffer)
@Assert(n, 2)
@Assert(buffer[..n], [0x4A, 0x40])
}
extend Float32 <: BigEndianOrder<Float32>
extend Float32 <: BigEndianOrder<Float32>
Description: Extends the BigEndianOrder interface for Float32 to implement the conversion between Float32 values and big-endian byte sequences.
Parent Type:
static func readBigEndian(Array<Byte>)
public static func readBigEndian(buffer: Array<Byte>): Float32
Description: Reads a Float32 value from a byte array in big-endian mode.
Parameters:
Returns:
Throws:
- IllegalArgumentException: If buffer is insufficient for reading the Float32 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer: Array<Byte> = [0x41, 0x48, 0x00, 0x00]
let n = Float32.readBigEndian(buffer)
@Assert(n, 12.5)
}
func writeBigEndian(Array<Byte>)
public func writeBigEndian(buffer: Array<Byte>): Int64
Description: Writes a Float32 value to a byte array in big-endian mode.
Parameters:
Returns:
- Int64: number of bytes of the written data
Throws:
- IllegalArgumentException: If buffer is insufficient for storing the Float32 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer = Array<Byte>(8, item: 0)
let n = 12.5f32.writeBigEndian(buffer)
@Assert(n, 4)
@Assert(buffer[..n], [0x41, 0x48, 0x00, 0x00])
}
extend Float64 <: BigEndianOrder<Float64>
extend Float64 <: BigEndianOrder<Float64>
Description: Extends the BigEndianOrder interface for Float64 to implement the conversion between Float64 values and big-endian byte sequences.
Parent Type:
static func readBigEndian(Array<Byte>)
public static func readBigEndian(buffer: Array<Byte>): Float64
Description: Reads a Float64 value from a byte array in big-endian mode.
Parameters:
Returns:
Throws:
- IllegalArgumentException: If buffer is insufficient for reading the Float64 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer: Array<Byte> = [0x40, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
let n = Float64.readBigEndian(buffer)
@Assert(n, 12.5)
}
func writeBigEndian(Array<Byte>)
public func writeBigEndian(buffer: Array<Byte>): Int64
Description: Writes a Float64 value to a byte array in big-endian mode.
Parameters:
Returns:
- Int64: number of bytes of the written data
Throws:
- IllegalArgumentException: If buffer is insufficient for storing the Float64 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer = Array<Byte>(8, item: 0)
let n = 12.5f64.writeBigEndian(buffer)
@Assert(n, 8)
@Assert(buffer[..n], [0x40, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
}
extend Int16 <: BigEndianOrder<Int16>
extend Int16 <: BigEndianOrder<Int16>
Description: Extends the BigEndianOrder interface for Int16 to implement the conversion between Int16 values and big-endian byte sequences.
Parent Type:
static func readBigEndian(Array<Byte>)
public static func readBigEndian(buffer: Array<Byte>): Int16
Description: Reads an Int16 value from a byte array in big-endian mode.
Parameters:
Returns:
Throws:
- IllegalArgumentException: If buffer is insufficient for reading the Int16 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer: Array<Byte> = [0x12, 0x34]
let n = Int16.readBigEndian(buffer)
@Assert(n, 0x1234)
}
func writeBigEndian(Array<Byte>)
public func writeBigEndian(buffer: Array<Byte>): Int64
Description: Writes an Int16 value to a byte array in big-endian mode.
Parameters:
Returns:
- Int64: number of bytes of the written data
Throws:
- IllegalArgumentException: If buffer is insufficient for storing the Int16 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer = Array<Byte>(8, item: 0)
let n = 0x1234i16.writeBigEndian(buffer)
@Assert(n, 2)
@Assert(buffer[..n], [0x12, 0x34])
}
extend Int32 <: BigEndianOrder<Int32>
extend Int32 <: BigEndianOrder<Int32>
Description: Extends the BigEndianOrder interface for Int32 to implement the conversion between Int32 values and big-endian byte sequences.
Parent Type:
static func readBigEndian(Array<Byte>)
public static func readBigEndian(buffer: Array<Byte>): Int32
Description: Reads an Int32 value from a byte array in big-endian mode.
Parameters:
Returns:
Throws:
- IllegalArgumentException: If buffer is insufficient for reading the Int32 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer: Array<Byte> = [0x12, 0x34, 0x56, 0x78]
let n = Int32.readBigEndian(buffer)
@Assert(n, 0x12345678)
}
func writeBigEndian(Array<Byte>)
public func writeBigEndian(buffer: Array<Byte>): Int64
Description: Writes an Int32 value to a byte array in big-endian mode.
Parameters:
Returns:
- Int64: number of bytes of the written data
Throws:
- IllegalArgumentException: If buffer is insufficient for storing the Int32 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer = Array<Byte>(8, item: 0)
let n = 0x12345678i32.writeBigEndian(buffer)
@Assert(n, 4)
@Assert(buffer[..n], [0x12, 0x34, 0x56, 0x78])
}
extend Int64 <: BigEndianOrder<Int64>
extend Int64 <: BigEndianOrder<Int64>
Description: Extends the BigEndianOrder interface for Int64 to implement the conversion between Int64 values and big-endian byte sequences.
Parent Type:
static func readBigEndian(Array<Byte>)
public static func readBigEndian(buffer: Array<Byte>): Int64
Description: Reads an Int64 value from a byte array in big-endian mode.
Parameters:
Returns:
Throws:
- IllegalArgumentException: If buffer is insufficient for reading the Int64 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer: Array<Byte> = [0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]
let n = Int64.readBigEndian(buffer)
@Assert(n, 0x1234567890123456)
}
func writeBigEndian(Array<Byte>)
public func writeBigEndian(buffer: Array<Byte>): Int64
Description: Writes an Int64 value to a byte array in big-endian mode.
Parameters:
Returns:
- Int64: number of bytes of the written data
Throws:
- IllegalArgumentException: If buffer is insufficient for storing the Int64 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer = Array<Byte>(8, item: 0)
let n = 0x1234567890123456i64.writeBigEndian(buffer)
@Assert(n, 8)
@Assert(buffer[..n], [0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56])
}
extend Int8 <: BigEndianOrder<Int8>
extend Int8 <: BigEndianOrder<Int8>
Description: Extends the BigEndianOrder interface for Int8 to implement the conversion between Int8 values and big-endian byte sequences.
Parent Type:
static func readBigEndian(Array<Byte>)
public static func readBigEndian(buffer: Array<Byte>): Int8
Description: Reads an Int8 value from a byte array in big-endian mode.
Parameters:
Returns:
Throws:
- IllegalArgumentException: If buffer is insufficient for reading the Int8 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer: Array<Byte> = [0x12]
let n = Int8.readBigEndian(buffer)
@Assert(n, 0x12)
}
func writeBigEndian(Array<Byte>)
public func writeBigEndian(buffer: Array<Byte>): Int64
Description: Writes an Int8 value to a byte array in big-endian mode.
Parameters:
Returns:
- Int64: number of bytes of the written data
Throws:
- IllegalArgumentException: If buffer is insufficient for storing the Int8 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer = Array<Byte>(8, item: 0)
let n = 0x12i8.writeBigEndian(buffer)
@Assert(n, 1)
@Assert(buffer[..n], [0x12])
}
extend UInt16 <: BigEndianOrder<UInt16>
extend UInt16 <: BigEndianOrder<UInt16>
Description: Extends the BigEndianOrder interface for UInt16 to implement the conversion between UInt16 values and big-endian byte sequences.
Parent Type:
static func readBigEndian(Array<Byte>)
public static func readBigEndian(buffer: Array<Byte>): UInt16
Description: Reads a UInt16 value from a byte array in big-endian mode.
Parameters:
Returns:
Throws:
- IllegalArgumentException: If buffer is insufficient for reading the UInt16 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer: Array<Byte> = [0x12, 0x34]
let n = UInt16.readBigEndian(buffer)
@Assert(n, 0x1234)
}
func writeBigEndian(Array<Byte>)
public func writeBigEndian(buffer: Array<Byte>): Int64
Description: Writes a UInt16 value to a byte array in big-endian mode.
Parameters:
Returns:
- Int64: number of bytes of the written data
Throws:
- IllegalArgumentException: If buffer is insufficient for storing the UInt16 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer = Array<Byte>(8, item: 0)
let n = 0x1234u16.writeBigEndian(buffer)
@Assert(n, 2)
@Assert(buffer[..n], [0x12, 0x34])
}
extend UInt32 <: BigEndianOrder<UInt32>
extend UInt32 <: BigEndianOrder<UInt32>
Description: Extends the BigEndianOrder interface for UInt32 to implement the conversion between UInt32 values and big-endian byte sequences.
Parent Type:
static func readBigEndian(Array<Byte>)
public static func readBigEndian(buffer: Array<Byte>): UInt32
Description: Reads a UInt32 value from a byte array in big-endian mode.
Parameters:
Returns:
Throws:
- IllegalArgumentException: If buffer is insufficient for reading the UInt32 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer: Array<Byte> = [0x12, 0x34, 0x56, 0x78]
let n = UInt32.readBigEndian(buffer)
@Assert(n, 0x12345678)
}
func writeBigEndian(Array<Byte>)
public func writeBigEndian(buffer: Array<Byte>): Int64
Description: Writes a UInt32 value to a byte array in big-endian mode.
Parameters:
Returns:
- Int64: number of bytes of the written data
Throws:
- IllegalArgumentException: If buffer is insufficient for storing the UInt32 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer = Array<Byte>(8, item: 0)
let n = 0x12345678u32.writeBigEndian(buffer)
@Assert(n, 4)
@Assert(buffer[..n], [0x12, 0x34, 0x56, 0x78])
}
extend UInt64 <: BigEndianOrder<UInt64>
extend UInt64 <: BigEndianOrder<UInt64>
Description: Extends the BigEndianOrder interface for UInt64 to implement the conversion between UInt64 values and big-endian byte sequences.
Parent Type:
static func readBigEndian(Array<Byte>)
public static func readBigEndian(buffer: Array<Byte>): UInt64
Description: Reads a UInt64 value from a byte array in big-endian mode.
Parameters:
Returns:
Throws:
- IllegalArgumentException: If buffer is insufficient for reading the UInt64 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer: Array<Byte> = [0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]
let n = UInt64.readBigEndian(buffer)
@Assert(n, 0x1234567890123456)
}
func writeBigEndian(Array<Byte>)
public func writeBigEndian(buffer: Array<Byte>): Int64
Description: Writes a UInt64 value to a byte array in big-endian mode.
Parameters:
Returns:
- Int64: number of bytes of the written data
Throws:
- IllegalArgumentException: If buffer is insufficient for storing the UInt64 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer = Array<Byte>(8, item: 0)
let n = 0x1234567890123456u64.writeBigEndian(buffer)
@Assert(n, 8)
@Assert(buffer[..n], [0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56])
}
extend UInt8 <: BigEndianOrder<UInt8>
extend UInt8 <: BigEndianOrder<UInt8>
Description: Extends the BigEndianOrder interface for UInt8 to implement the conversion between UInt8 values and big-endian byte sequences.
Parent Type:
static func readBigEndian(Array<Byte>)
public static func readBigEndian(buffer: Array<Byte>): UInt8
Description: Reads a UInt8 value from a byte array in big-endian mode.
Parameters:
Returns:
Throws:
- IllegalArgumentException: If buffer is insufficient for reading the UInt8 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer: Array<Byte> = [0x12]
let n = UInt8.readBigEndian(buffer)
@Assert(n, 0x12)
}
func writeBigEndian(Array<Byte>)
public func writeBigEndian(buffer: Array<Byte>): Int64
Description: Writes a UInt8 value to a byte array in big-endian mode.
Parameters:
Returns:
- Int64: number of bytes of the written data
Throws:
- IllegalArgumentException: If buffer is insufficient for storing the UInt8 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer = Array<Byte>(8, item: 0)
let n = 0x12u8.writeBigEndian(buffer)
@Assert(n, 1)
@Assert(buffer[..n], [0x12])
}
interface LittleEndianOrder<T>
public interface LittleEndianOrder<T> {
func writeLittleEndian(buffer: Array<Byte>): Int64
static func readLittleEndian(buffer: Array<Byte>): T
}
Description: Specifies the little-endian byte sequence conversion interface.
static func readLittleEndian(Array<Byte>)
static func readLittleEndian(buffer: Array<Byte>): T
Description: Reads a T value from a byte array in little-endian mode.
Parameters:
Returns:
- T: T value
Throws:
- IllegalArgumentException: If buffer is insufficient for reading the T value, this exception is thrown.
func writeLittleEndian(Array<Byte>)
func writeLittleEndian(buffer: Array<Byte>): Int64
Description: Writes the T value to a byte array in little-endian mode.
Parameters:
Returns:
- Int64: number of bytes of the written data
Throws:
- IllegalArgumentException: If buffer is insufficient for storing the T value, this exception is thrown.
extend Bool <: LittleEndianOrder<Bool>
extend Bool <: LittleEndianOrder<Bool>
Description: Extends the LittleEndianOrder interface for Bool to implement the conversion between Bool values and little-endian byte sequences.
Parent Type:
static func readLittleEndian(Array<Byte>)
public static func readLittleEndian(buffer: Array<Byte>): Bool
Description: Reads a Bool value from a byte array in little-endian mode.
Parameters:
Returns:
Throws:
- IllegalArgumentException: If buffer is insufficient for reading the Bool value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer: Array<Byte> = [0x1]
let n = Bool.readLittleEndian(buffer)
@Assert(n, true)
}
func writeLittleEndian(Array<Byte>)
public func writeLittleEndian(buffer: Array<Byte>): Int64
Description: Writes a Bool value to a byte array in little-endian mode.
Parameters:
Returns:
- Int64: number of bytes of the written data
Throws:
- IllegalArgumentException: If buffer is insufficient for storing the Bool value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer = Array<Byte>(8, item: 0)
let n = true.writeLittleEndian(buffer)
@Assert(n, 1)
@Assert(buffer[..n], [0x01])
}
extend Float16 <: LittleEndianOrder<Float16>
extend Float16 <: LittleEndianOrder<Float16>
Description: Extends the LittleEndianOrder interface for Float16 to implement the conversion between Float16 values and little-endian byte sequences.
Parent Type:
static func readLittleEndian(Array<Byte>)
public static func readLittleEndian(buffer: Array<Byte>): Float16
Description: Reads a Float16 value from a byte array in little-endian mode.
Parameters:
Returns:
Throws:
- IllegalArgumentException: If buffer is insufficient for reading the Float16 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer: Array<Byte> = [0x40, 0x4A]
let n = Float16.readLittleEndian(buffer)
@Assert(n, 12.5)
}
func writeLittleEndian(Array<Byte>)
public func writeLittleEndian(buffer: Array<Byte>): Int64
Description: Writes a Float16 value to a byte array in little-endian mode.
Parameters:
Returns:
- Int64: number of bytes of the written data
Throws:
- IllegalArgumentException: If buffer is insufficient for storing the Float16 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer = Array<Byte>(8, item: 0)
let n = 12.5f16.writeLittleEndian(buffer)
@Assert(n, 2)
@Assert(buffer[..n], [0x40, 0x4A])
}
extend Float32 <: LittleEndianOrder<Float32>
extend Float32 <: LittleEndianOrder<Float32>
Description: Extends the LittleEndianOrder interface for Float32 to implement the conversion between Float32 values and little-endian byte sequences.
Parent Type:
static func readLittleEndian(Array<Byte>)
public static func readLittleEndian(buffer: Array<Byte>): Float32
Description: Reads a Float32 value from a byte array in little-endian mode.
Parameters:
Returns:
Throws:
- IllegalArgumentException: If buffer is insufficient for reading the Float32 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer: Array<Byte> = [0x00, 0x00, 0x48, 0x41]
let n = Float32.readLittleEndian(buffer)
@Assert(n, 12.5)
}
func writeLittleEndian(Array<Byte>)
public func writeLittleEndian(buffer: Array<Byte>): Int64
Description: Writes a Float32 value to a byte array in little-endian mode.
Parameters:
Returns:
- Int64: number of bytes of the written data
Throws:
- IllegalArgumentException: If buffer is insufficient for storing the Float32 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer = Array<Byte>(8, item: 0)
let n = 12.5f32.writeLittleEndian(buffer)
@Assert(n, 4)
@Assert(buffer[..n], [0x00, 0x00, 0x48, 0x41])
}
extend Float64 <: LittleEndianOrder<Float64>
extend Float64 <: LittleEndianOrder<Float64>
Description: Extends the LittleEndianOrder interface for Float64 to implement the conversion between Float64 values and little-endian byte sequences.
Parent Type:
static func readLittleEndian(Array<Byte>)
public static func readLittleEndian(buffer: Array<Byte>): Float64
Description: Reads a Float64 value from a byte array in little-endian mode.
Parameters:
Returns:
Throws:
- IllegalArgumentException: If buffer is insufficient for reading the Float64 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer: Array<Byte> = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x40]
let n = Float64.readLittleEndian(buffer)
@Assert(n, 12.5)
}
func writeLittleEndian(Array<Byte>)
public func writeLittleEndian(buffer: Array<Byte>): Int64
Description: Writes a Float64 value to a byte array in little-endian mode.
Parameters:
Returns:
- Int64: number of bytes of the written data
Throws:
- IllegalArgumentException: If buffer is insufficient for storing the Float64 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer = Array<Byte>(8, item: 0)
let n = 12.5f64.writeLittleEndian(buffer)
@Assert(n, 8)
@Assert(buffer[..n], [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x40])
}
extend Int16 <: LittleEndianOrder<Int16>
extend Int16 <: LittleEndianOrder<Int16>
Description: Extends the LittleEndianOrder interface for Int16 to implement the conversion between Int16 values and little-endian byte sequences.
Parent Type:
static func readLittleEndian(Array<Byte>)
public static func readLittleEndian(buffer: Array<Byte>): Int16
Description: Reads an Int16 value from a byte array in little-endian mode.
Parameters:
Returns:
Throws:
- IllegalArgumentException: If buffer is insufficient for reading the Int16 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer: Array<Byte> = [0x34, 0x12]
let n = Int16.readLittleEndian(buffer)
@Assert(n, 0x1234i16)
}
func writeLittleEndian(Array<Byte>)
public func writeLittleEndian(buffer: Array<Byte>): Int64
Description: Writes an Int16 value to a byte array in little-endian mode.
Parameters:
Returns:
- Int64: number of bytes of the written data
Throws:
- IllegalArgumentException: If buffer is insufficient for storing the Int16 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer = Array<Byte>(8, item: 0)
let n = 0x1234i16.writeLittleEndian(buffer)
@Assert(n, 2)
@Assert(buffer[..n], [0x34, 0x12])
}
extend Int32 <: LittleEndianOrder<Int32>
extend Int32 <: LittleEndianOrder<Int32>
Description: Extends the LittleEndianOrder interface for Int32 to implement the conversion between Int32 values and little-endian byte sequences.
Parent Type:
static func readLittleEndian(Array<Byte>)
public static func readLittleEndian(buffer: Array<Byte>): Int32
Description: Reads an Int32 value from a byte array in little-endian mode.
Parameters:
Returns:
Throws:
- IllegalArgumentException: If buffer is insufficient for reading the Int32 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer: Array<Byte> = [0x78, 0x56, 0x34, 0x12]
let n = Int32.readLittleEndian(buffer)
@Assert(n, 0x12345678i32)
}
func writeLittleEndian(Array<Byte>)
public func writeLittleEndian(buffer: Array<Byte>): Int64
Description: Writes an Int32 value to a byte array in little-endian mode.
Parameters:
Returns:
- Int64: number of bytes of the written data
Throws:
- IllegalArgumentException: If buffer is insufficient for storing the Int32 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer = Array<Byte>(8, item: 0)
let n = 0x12345678i32.writeLittleEndian(buffer)
@Assert(n, 4)
@Assert(buffer[..n], [0x78, 0x56, 0x34, 0x12])
}
extend Int64 <: LittleEndianOrder<Int64>
extend Int64 <: LittleEndianOrder<Int64>
Description: Extends the LittleEndianOrder interface for Int64 to implement the conversion between Int64 values and little-endian byte sequences.
Parent Type:
static func readLittleEndian(Array<Byte>)
public static func readLittleEndian(buffer: Array<Byte>): Int64
Description: Reads an Int64 value from a byte array in little-endian mode.
Parameters:
Returns:
Throws:
- IllegalArgumentException: If buffer is insufficient for reading the Int64 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer: Array<Byte> = [0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]
let n = Int64.readLittleEndian(buffer)
@Assert(n, 0x1234567890123456i64)
}
func writeLittleEndian(Array<Byte>)
public func writeLittleEndian(buffer: Array<Byte>): Int64
Description: Writes an Int64 value to a byte array in little-endian mode.
Parameters:
Returns:
- Int64: number of bytes of the written data
Throws:
- IllegalArgumentException: If buffer is insufficient for storing the Int64 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer = Array<Byte>(8, item: 0)
let n = 0x1234567890123456i64.writeLittleEndian(buffer)
@Assert(n, 8)
@Assert(buffer[..n], [0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12])
}
extend Int8 <: LittleEndianOrder<Int8>
extend Int8 <: LittleEndianOrder<Int8>
Description: Extends the LittleEndianOrder interface for Int8 to implement the conversion between Int8 values and little-endian byte sequences.
Parent Type:
static func readLittleEndian(Array<Byte>)
public static func readLittleEndian(buffer: Array<Byte>): Int8
Description: Reads an Int8 value from a byte array in little-endian mode.
Parameters:
Returns:
Throws:
- IllegalArgumentException: If buffer is insufficient for reading the Int8 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer: Array<Byte> = [0x12]
let n = Int8.readLittleEndian(buffer)
@Assert(n, 0x12)
}
func writeLittleEndian(Array<Byte>)
public func writeLittleEndian(buffer: Array<Byte>): Int64
Description: Writes an Int8 value to a byte array in little-endian mode.
Parameters:
Returns:
- Int64: number of bytes of the written data
Throws:
- IllegalArgumentException: If buffer is insufficient for storing the Int8 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer = Array<Byte>(8, item: 0)
let n = 0x12i8.writeLittleEndian(buffer)
@Assert(n, 1)
@Assert(buffer[..n], [0x12])
}
extend UInt16 <: LittleEndianOrder<UInt16>
extend UInt16 <: LittleEndianOrder<UInt16>
Description: Extends the LittleEndianOrder interface for UInt16 to implement the conversion between UInt16 values and little-endian byte sequences.
Parent Type:
static func readLittleEndian(Array<Byte>)
public static func readLittleEndian(buffer: Array<Byte>): UInt16
Description: Reads a UInt16 value from a byte array in little-endian mode.
Parameters:
Returns:
Throws:
- IllegalArgumentException: If buffer is insufficient for reading the UInt16 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer: Array<Byte> = [0x34, 0x12]
let n = UInt16.readLittleEndian(buffer)
@Assert(n, 0x1234u16)
}
func writeLittleEndian(Array<Byte>)
public func writeLittleEndian(buffer: Array<Byte>): Int64
Description: Writes a UInt16 value to a byte array in little-endian mode.
Parameters:
Returns:
- Int64: number of bytes of the written data
Throws:
- IllegalArgumentException: If buffer is insufficient for storing the UInt16 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer = Array<Byte>(8, item: 0)
let n = 0x1234u16.writeLittleEndian(buffer)
@Assert(n, 2)
@Assert(buffer[..n], [0x34, 0x12])
}
extend UInt32 <: LittleEndianOrder<UInt32>
extend UInt32 <: LittleEndianOrder<UInt32>
Description: Extends the LittleEndianOrder interface for UInt32 to implement the conversion between UInt32 values and little-endian byte sequences.
Parent Type:
static func readLittleEndian(Array<Byte>)
public static func readLittleEndian(buffer: Array<Byte>): UInt32
Description: Reads a UInt32 value from a byte array in little-endian mode.
Parameters:
Returns:
Throws:
- IllegalArgumentException: If buffer is insufficient for reading the UInt32 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer: Array<Byte> = [0x78, 0x56, 0x34, 0x12]
let n = UInt32.readLittleEndian(buffer)
@Assert(n, 0x12345678i32)
}
func writeLittleEndian(Array<Byte>)
public func writeLittleEndian(buffer: Array<Byte>): Int64
Description: Writes a UInt32 value to a byte array in little-endian mode.
Parameters:
Returns:
- Int64: number of bytes of the written data
Throws:
- IllegalArgumentException: If buffer is insufficient for storing the UInt32 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer = Array<Byte>(8, item: 0)
let n = 0x12345678u32.writeLittleEndian(buffer)
@Assert(n, 4)
@Assert(buffer[..n], [0x78, 0x56, 0x34, 0x12])
}
extend UInt64 <: LittleEndianOrder<UInt64>
extend UInt64 <: LittleEndianOrder<UInt64>
Description: Extends the LittleEndianOrder interface for UInt64 to implement the conversion between UInt64 values and little-endian byte sequences.
Parent Type:
static func readLittleEndian(Array<Byte>)
public static func readLittleEndian(buffer: Array<Byte>): UInt64
Description: Reads a UInt64 value from a byte array in little-endian mode.
Parameters:
Returns:
Throws:
- IllegalArgumentException: If buffer is insufficient for reading the UInt64 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer: Array<Byte> = [0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]
let n = UInt64.readLittleEndian(buffer)
@Assert(n, 0x1234567890123456i64)
}
func writeLittleEndian(Array<Byte>)
public func writeLittleEndian(buffer: Array<Byte>): Int64
Description: Writes a UInt64 value to a byte array in little-endian mode.
Parameters:
Returns:
- Int64: number of bytes of the written data
Throws:
- IllegalArgumentException: If buffer is insufficient for storing the UInt64 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer = Array<Byte>(8, item: 0)
let n = 0x1234567890123456u64.writeLittleEndian(buffer)
@Assert(n, 8)
@Assert(buffer[..n], [0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12])
}
extend UInt8 <: LittleEndianOrder<UInt8>
extend UInt8 <: LittleEndianOrder<UInt8>
Description: Extends the LittleEndianOrder interface for UInt8 to implement the conversion between UInt8 values and little-endian byte sequences.
Parent Type:
static func readLittleEndian(Array<Byte>)
public static func readLittleEndian(buffer: Array<Byte>): UInt8
Description: Reads a UInt8 value from a byte array in little-endian mode.
Parameters:
Returns:
Throws:
- IllegalArgumentException: If buffer is insufficient for reading the UInt8 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer: Array<Byte> = [0x12]
let n = UInt8.readLittleEndian(buffer)
@Assert(n, 0x12)
}
func writeLittleEndian(Array<Byte>)
public func writeLittleEndian(buffer: Array<Byte>): Int64
Description: Writes a UInt8 value to a byte array in little-endian mode.
Parameters:
Returns:
- Int64: number of bytes of the written data
Throws:
- IllegalArgumentException: If buffer is insufficient for storing the UInt8 value, this exception is thrown.
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let buffer = Array<Byte>(8, item: 0)
let n = 0x12u8.writeLittleEndian(buffer)
@Assert(n, 1)
@Assert(buffer[..n], [0x12])
}
interface SwapEndianOrder<T>
public interface SwapEndianOrder<T> {
func swapBytes(): T
}
Description: Specifies the byte order reversion interface.
func swapBytes()
func swapBytes(): T
Description: Reverses the byte order of the T value.
Returns:
- T: T value
extend Int16 <: SwapEndianOrder<Int16>
extend Int16 <: SwapEndianOrder<Int16>
Description: Extends the SwapEndianOrder interface for Int16 to reverse the byte order of an Int16 value.
Parent Type:
func swapBytes()
public func swapBytes(): Int16
Description: Reverses the byte order of an Int16 value.
Returns:
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let n = 0x1234i16
let m = n.swapBytes()
@Assert(m, 0x3412)
}
extend Int32 <: SwapEndianOrder<Int32>
extend Int32 <: SwapEndianOrder<Int32>
Description: Extends the SwapEndianOrder interface for Int32 to reverse the byte order of an Int32 value.
Parent Type:
func swapBytes()
public func swapBytes(): Int32
Description: Reverses the byte order of an Int32 value.
Returns:
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let n = 0x12345678i32
let m = n.swapBytes()
@Assert(m, 0x78563412)
}
extend Int64 <: SwapEndianOrder<Int64>
extend Int64 <: SwapEndianOrder<Int64>
Description: Extends the SwapEndianOrder interface for Int64 to reverse the byte order of an Int64 value.
Parent Type:
func swapBytes()
public func swapBytes(): Int64
Description: Reverses the byte order of an Int64 value.
Returns:
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let n = 0x1234567890123456i64
let m = n.swapBytes()
@Assert(m, 0x5634129078563412)
}
extend Int8 <: SwapEndianOrder<Int8>
extend Int8 <: SwapEndianOrder<Int8>
Description: Extends the SwapEndianOrder interface for Int8 to reverse the byte order of an Int8 value.
Parent Type:
func swapBytes()
public func swapBytes(): Int8
Description: Reverses the byte order of an Int8 value.
Returns:
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let n = 0x12i8
let m = n.swapBytes()
@Assert(m, 0x12)
}
extend UInt16 <: SwapEndianOrder<UInt16>
extend UInt16 <: SwapEndianOrder<UInt16>
Description: Extends the SwapEndianOrder interface for UInt16 to reverse the byte order of a UInt16 value.
Parent Type:
func swapBytes()
public func swapBytes(): UInt16
Description: Reverses the byte order of a UInt16 value.
Returns:
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let n = 0x1234u16
let m = n.swapBytes()
@Assert(m, 0x3412)
}
extend UInt32 <: SwapEndianOrder<UInt32>
extend UInt32 <: SwapEndianOrder<UInt32>
Description: Extends the SwapEndianOrder interface for UInt32 to reverse the byte order of a UInt32 value.
Parent Type:
func swapBytes()
public func swapBytes(): UInt32
Description: Reverses the byte order of a UInt32 value.
Returns:
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let n = 0x12345678u32
let m = n.swapBytes()
@Assert(m, 0x78563412)
}
extend UInt64 <: SwapEndianOrder<UInt64>
extend UInt64 <: SwapEndianOrder<UInt64>
Description: Extends the SwapEndianOrder interface for UInt64 to reverse the byte order of a UInt64 value.
Parent Type:
func swapBytes()
public func swapBytes(): UInt64
Description: Reverses the byte order of a UInt64 value.
Returns:
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let n = 0x1234567890123456u64
let m = n.swapBytes()
@Assert(m, 0x5634129078563412)
}
extend UInt8 <: SwapEndianOrder<UInt8>
extend UInt8 <: SwapEndianOrder<UInt8>
Description: Extends the SwapEndianOrder interface for UInt8 to reverse the byte order of a UInt8 value.
Parent Type:
func swapBytes()
public func swapBytes(): UInt8
Description: Reverses the byte order of a UInt8 value.
Returns:
Example:
import std.binary.*
import std.unittest.*
import std.unittest.testmacro.*
main() {
let n = 0x12u8
let m = n.swapBytes()
@Assert(m, 0x12)
}
std.collection Package
Function Description
The collection package provides efficient implementation of common data structures, definitions of related abstract interfaces, and common functions in collection types.
This package implements the following common data structures:
-
ArrayList: variable-length continuous array used when an uncertain amount of data needs to be stored or when the array size needs to be dynamically adjusted based on running conditions. Using ArrayList may increase the overhead of memory allocation and release. Therefore, exercise caution when using ArrayList.
-
LinkedList: linked list structure. The advantage of LinkedList is that it can dynamically add or delete elements without moving other elements. This makes it very useful when elements need to be frequently added or deleted. LinkedList can also easily modify or delete elements and store multiple elements in a list. The disadvantage of LinkedList is that it requires extra memory to store references to each element, which may cause memory waste.
-
HashMap: hash table that stores key-value pairs and allows quick access to values based on keys. HashMap is used when mapping relationships need to be used and quick search is required.
-
HashSet: collection data structure implemented based on a hash table. It can be used to quickly search for and delete elements and supports efficient insertion, deletion, and search operations.
-
TreeMap: ordered mapping table implemented based on the red-black tree. Generally, TreeMap is used when elements need to be sorted in natural or user-defined order.
The collection types provided by the collection package do not support concurrency security. For details about the collections that support concurrency security, see collection.concurrent package.
API List
Function
| Name | Description |
|---|---|
| all<T>((T) -> Bool) | Checks whether all elements of an iterator meet the conditions. |
| any<T>((T) -> Bool) | Checks whether an element that meets the conditions exists in an iterator. |
| at<T>(Int64) | Obtains the element at a specified location of an iterator. |
| collectArrayList<T>(Iterable<T>) | Converts an iterator to an instance of the ArrayList type. |
| collectArray<T>(Iterable<T>) | Converts an iterator to an instance of the Array type. |
| collectHashMap<K, V>(Iterable<(K, V)>) where K <: Hashable & Equatable<K> | Converts an iterator to an instance of the HashMap type. |
| collectHashSet<T>(Iterable<T>) where T <: Hashable & Equatable<T> | Converts an iterator to an instance of the HashSet type. |
| collectString<T>(String) where T <: ToString | Converts an iterator whose elements implement the ToString API to an instance of the String type. |
| concat<T>(Iterable<T>) | Concatenates two iterators in series. |
| contains<T>(T) where T <: Equatable<T> | Traverses all elements, checks whether a specified element is included, and returns the element. |
| count<T>(Iterable<T>) | Counts the number of elements included in an iterator. |
| enumerate<T>(Iterable<T>) | Obtains an iterator with indexes. |
| filter<T>((T) -> Bool) | Filters out elements that meet the conditions. |
| filterMap<T, R>((T) -> ?R) | Creates an iterator that both filters and maps |
| first<T>(Iterable<T>) | Obtains the first element. |
| flatMap<T, R>( (T) -> Iterable<R>) | Creates a mapping with the flatten function. |
| flatten<T, R>(Iterable<T>) where T <: Iterable<R> | Unfolds one layer of a nested iterator. |
| fold<T, R>(R, (R, T) -> R) | Uses a specified initial value to calculate from left to right. |
| forEach<T>((T) -> Unit) | Traverses all elements and specifies a specified operation. |
| inspect<T>((T) -> Unit) | Performs an extra operation on the current element each time the iterator calls next() (without consuming elements in the iterator). |
| isEmpty<T>(Iterable<T>) | Checks whether an iterator is empty. |
| last<T>(Iterable<T>) | Obtains the last element. |
| map<T, R>((T) -> R) | Creates a mapping. |
| max<T>(Iterable<T>) where T <: Comparable<T> | Filters out a maximum element. |
| min<T>(Iterable<T>) where T <: Comparable<T> | Filters out a minimum element. |
| none<T>((T) -> Bool) | Checks whether an iterator does not meet any conditions. |
| reduce<T>((T, T) -> T) | Uses the first element as the initial value to calculate from left to right. |
| skip<T>(Int64) | Skips a specific number of elements in an iterator. |
| step<T>(Int64) | Each time next() is called, a specific number of elements in the iterator are skipped. |
| take<T>(Int64) | Obtains a specific number of elements from an iterator. |
| zip<T, R>(Iterable<R>) | Combines two iterators into one (the length depends on the shorter iterator). |
Interface
| Name | Description |
|---|---|
| Map<K, V> where K <: Equatable<K> | Provides a way to map keys to values. |
| Set<T> where T <: Equatable<T> | Specifies a collection without duplicate elements. |
| EquatableCollection<T> where T <: Equatable<T> | Defines the types of collections that support the comparison operation. |
Class
| Name | Description |
|---|---|
| ArrayList<T> | Provides variable-length arrays. |
| ArrayListIterator<T> | Implements the iterator function of ArrayList<T>. |
| HashMapIterator<K, V> where K <: Hashable & Equatable<K> | Implements the iterator function of HashMap. |
| HashMap<K, V> where K <: Hashable & Equatable<K> | Specifies the hash table implementation of the Map<K, V> where K <: Equatable<K> interface. |
| HashSet<T> where T <: Hashable & Equatable<T> | Specifies the class of the Set<T> where T <: Equatable<T> interface that is implemented based on HashMap<K, V> where K <: Hashable & Equatable<K>. |
| LinkedListNode<T> | Specifies a node on LinkedList<T>. |
| LinkedList<T> | Specifies the data structure with doubly linked list mode implemented. |
| TreeMap<K, V> where K <: Comparable<K> | Specifies the class of the Map<K, V> where K <: Equatable<K> interface implemented based on the balanced binary search tree. |
Struct
| Name | Description |
|---|---|
| EntryView<K, V> where K <: Hashable & Equatable<K> | Specifies the view of a key in HashMap<K, V> where K <: Hashable & Equatable<K>. |
| TreeMapNode<K, V> where K <: Comparable<K> | Specifies the node structure of TreeMap<K, V> where K <: Comparable<K>. |
Exception Class
| Name | Description |
|---|---|
| ConcurrentModificationException | Specifies an exception thrown upon concurrent modification. |
Function
func all<T>((T) -> Bool)
public func all<T>(predicate: (T) -> Bool): (Iterable<T>) -> Bool
Description: Checks whether all elements of the iterator meet a specified condition.
Parameters:
- predicate: (T) -> Bool: specified condition
Returns:
func any<T>((T) -> Bool)
public func any<T>(predicate: (T) -> Bool): (Iterable<T>) -> Bool
Description: Checks whether an element that meets a specified condition exists in the iterator.
Parameters:
- predicate: (T) -> Bool: specified condition
Returns:
func at<T>(Int64)
public func at<T>(n: Int64): (Iterable<T>) -> Option<T>
Description: Obtains the element at the specified location of an iterator.
Parameters:
- n: Int64: specified location
Returns:
- (Iterable<T>) -> Option<T>: function that obtains the element at the specified location. If the iterator is empty, the function returns None.
func collectArrayList<T>(Iterable<T>)
public func collectArrayList<T>(it: Iterable<T>): ArrayList<T>
Description: Converts an iterator to an ArrayList instance.
Parameters:
- it: Iterable<T>: specified iterator
Returns:
func collectArray<T>(Iterable<T>)
public func collectArray<T>(it: Iterable<T>): Array<T>
Description: Converts an iterator to an Array instance.
Parameters:
- it: Iterable<T>: specified iterator
Returns:
- Array<T>: array
func collectHashMap<K, V>(Iterable<(K, V)>) where K <: Hashable & Equatable<K>
public func collectHashMap<K, V>(it: Iterable<(K, V)>): HashMap<K, V> where K <: Hashable & Equatable<K>
Description: Converts an iterator to a HashMap instance.
Parameters:
- it: Iterable<(K, V)>: specified iterator
Returns:
func collectHashSet<T>(Iterable<T>) where T <: Hashable & Equatable<T>
public func collectHashSet<T>(it: Iterable<T>): HashSet<T> where T <: Hashable & Equatable<T>
Description: Converts an iterator to a HashSet instance.
Parameters:
- it: Iterable<T>: specified iterator
Returns:
func collectString<T>(String) where T <: ToString
public func collectString<T>(delimiter!: String = ""): (Iterable<T>) -> String where T <: ToString
Description: Converts an iterator whose elements implement the ToString interface to a String instance.
Parameters:
- delimiter!: String: string concatenation delimiter
Returns:
func concat<T>(Iterable<T>)
public func concat<T>(other: Iterable<T>): (Iterable<T>) -> Iterator<T>
Description: Concatenates two iterators in series.
Parameters:
- other: Iterable<T>: iterator to be concatenated behind
Returns:
func contains<T>(T) where T <: Equatable<T>
public func contains<T>(element: T): (Iterable<T>) -> Bool where T <: Equatable<T>
Description: Traverses all elements, checks whether a specified element is included, and returns the element.
Parameters:
- element: T: element to be searched for
Returns:
func count<T>(Iterable<T>)
public func count<T>(it: Iterable<T>): Int64
Description: Counts the number of elements contained in an iterator.
Parameters:
- it: Iterable<T>: specified iterator
Returns:
- Int64: number of elements contained in the iterator
func enumerate<T>(Iterable<T>)
public func enumerate<T>(it: Iterable<T>): Iterator<(Int64, T)>
Description: Obtains an iterator with indexes.
Parameters:
- it: Iterable<T>: specified iterator
Returns:
func filter<T>((T) -> Bool)
public func filter<T>(predicate: (T) -> Bool): (Iterable<T>) -> Iterator<T>
Description: Filters out elements that meet a specified condition.
Parameters:
- predicate: (T) -> Bool: specified condition
Returns:
func filterMap<T, R>((T) -> ?R)
public func filterMap<T, R>(transform: (T)-> ?R): (Iterable<T>) ->Iterator<R>
Description: Performs filter and map operations at the same time and returns a new iterator.
Parameters:
- transform: (T) -> ?R: specified mapping function If the return value of this function is Some, predicate of the filter is true; otherwise, predicate of the filter is false.
Returns:
func first<T>(Iterable<T>)
public func first<T>(it: Iterable<T>): Option<T>
Description: Obtains the first element.
Parameters:
- it: Iterable<T>: specified iterator
Returns:
- Option<T>: The element (if there is) is returned. Otherwise, None is returned.
func flatMap<T, R>( (T) -> Iterable<R>)
public func flatMap<T, R>(transform: (T) -> Iterable<R>): (Iterable<T>) -> Iterator<R>
Description: Creates a mapping with the flatten function.
Parameters:
- transform: (T) -> Iterable<R>: specified mapping function
Returns:
func flatten<T, R>(Iterable<T>) where T <: Iterable<R>
public func flatten<T, R>(it: Iterable<T>): Iterator<R> where T <: Iterable<R>
Description: Unfolds one layer of a nested iterator.
Parameters:
- it: Iterable<T>: specified iterator
Returns:
- Iterator<R>: iterator after one layer is expanded
func fold<T, R>(R, (R, T) -> R)
public func fold<T, R>(initial: R, operation: (R, T) -> R): (Iterable<T>) -> R
Description: Uses a specified initial value to calculate from left to right.
Parameters:
- initial: R: specified initial value of the R type
- operation: (R, T) -> R: specified calculation function
Returns:
- (Iterable<T>) -> R: folding function
func forEach<T>((T) -> Unit)
public func forEach<T>(action: (T) -> Unit): (Iterable<T>) -> Unit
Description: Traverses all elements in an iterator to complete a specified operation.
Parameters:
- action: (T) -> Unit: specified operation function
Returns:
func inspect<T>((T) -> Unit)
public func inspect<T>(action: (T)->Unit): (Iterable<T>) ->Iterator<T>
Description: Performs an extra operation on the current element each time the iterator calls next() (without consuming elements in the iterator).
Parameters:
- action: (T) -> Unit: specified operation function
Returns:
- (Iterable<T>) -> Iterator<T>: function that can perform an extra operation on each element of the iterator
func isEmpty<T>(Iterable<T>)
public func isEmpty<T>(it: Iterable<T>): Bool
Description: Checks whether an iterator is empty.
Parameters:
- it: Iterable<T>: specified iterator
Returns:
- Bool: result of whether the iterator is empty
func last<T>(Iterable<T>)
public func last<T>(it: Iterable<T>): Option<T>
Description: Obtains the last element.
Parameters:
- it: Iterable<T>: specified iterator
Returns:
- Option<T>: The element (if there is) is returned. Otherwise, None is returned.
func map<T, R>((T) -> R)
public func map<T, R>(transform: (T) -> R): (Iterable<T>) -> Iterator<R>
Description: Create a mapping.
Parameters:
- transform: (T) ->R: specified mapping function
Returns:
func max<T>(Iterable<T>) where T <: Comparable<T>
public func max<T>(it: Iterable<T>): Option<T> where T <: Comparable<T>
Description: Filters out the element of the maximum value.
Parameters:
- it: Iterable<T>: specified iterator
Returns:
- Option<T>: The element (if there is) is returned. Otherwise, None is returned.
func min<T>(Iterable<T>) where T <: Comparable<T>
public func min<T>(it: Iterable<T>): Option<T> where T <: Comparable<T>
Description: Filters out the element of the minimum value.
Parameters:
- it: Iterable<T>: specified iterator
Returns:
- Option<T>: The element (if there is) is returned. Otherwise, None is returned.
func none<T>((T) -> Bool)
public func none<T>(predicate: (T) -> Bool): (Iterable<T>) -> Bool
Description: Checks whether no element of the iterator meets a specified condition.
Parameters:
- predicate: (T) -> Bool: specified condition
Returns:
func reduce<T>((T, T) -> T)
public func reduce<T>(operation: (T, T) -> T): (Iterable<T>) -> Option<T>
Description: Uses the first element as the initial value to calculate from left to right.
Parameters:
- operation: (T, T) -> T: specified operation function
Returns:
func skip<T>(Int64)
public func skip<T>(count: Int64): (Iterable<T>) -> Iterator<T>
Description: Skips a specific number of elements in an iterator.
If the value of count is less than 0, an exception is thrown. If the value of count is 0, no element is skipped and the original iterator is returned. If the value of count is greater than 0 and less than the size of the iterator, count elements are skipped and a new iterator containing the remaining elements is returned. If the value of count is greater than or equal to the size of the iterator, all elements are skipped and an empty iterator is returned.
Parameters:
- count: Int64: number of elements to be skipped
Returns:
Throws:
- IllegalArgumentException: If the value of count is less than 0, this exception is thrown.
func step<T>(Int64)
public func step<T>(count: Int64): (Iterable<T>) -> Iterator<T>
Description: Each time next() is called, a specified number of elements in the iterator are skipped.
If the value of count is less than or equal to 0, an exception is thrown. If the value of count is greater than 0, next() is called to skip count elements until the iterator becomes empty.
Parameters:
- count: Int64: number of elements to be skipped each time next() is called
Returns:
- (Iterable<T>) -> Iterator<T>: function after a specific number of elements are skipped each time the iterator calls next()
Throws:
- IllegalArgumentException: If the value of count is less than or equal to 0, this exception is thrown.
func take<T>(Int64)
public func take<T>(count: Int64): (Iterable<T>) -> Iterator<T>
Description: Takes a specified number of elements from an iterator.
If the value of count is less than 0, an exception is thrown. If the value of count is 0, no element is taken and an empty iterator is returned. If the value of count is greater than 0 and less than the size of the iterator, the first count elements are taken and a new iterator is returned. If the value of count is greater than or equal to the size of the iterator, all elements are taken and the original iterator is returned.
Parameters:
- count: Int64: number of elements to be taken
Returns:
Throws:
- IllegalArgumentException: If the value of count is less than 0, this exception is thrown.
func zip<T, R>(Iterable<R>)
public func zip<T, R>(other: Iterable<R>): (Iterable<T>) -> Iterator<(T, R)>
Description: Combines two iterators into one (the length depends on the shorter iterator).
Parameters:
- other: Iterable<R>: one iterator for the combination
Returns:
Interface
interface EquatableCollection<T> where T <: Equatable<T>
public interface EquatableCollection<T> <: Collection<T> where T <: Equatable<T> {
func contains(element: T): Bool
func containsAll(elements: Collection<T>): Bool
}
Description: Defines the types of collections that support the comparison operation.
Parent Type:
- Collection<T>
func contains(T)
func contains(element: T): Bool
Description: Checks whether keys contain a specified element.
Parameters:
- element: T: specified element, which is to be determined whether keys contain the element.
Returns:
- Bool: If the element is contained, true is returned. Otherwise, false is returned.
func containsAll(Collection<T>)
func containsAll(elements: Collection<T>): Bool
Description: Checks whether keys contain all elements of a specified collection.
Parameters:
- elements: Collection<T>: collection to be checked
Returns:
- Bool: If all elements are contained, true is returned. Otherwise, false is returned.
interface Map<K, V> where K <: Equatable<K>
Description: Provides a method of mapping keys to values. The method supports using keys to find values, so it can be used to store and operate key-value pairs.
map cannot contain duplicate keys. Each key can be mapped to only one value.
public interface Map<K, V> <: Collection<(K, V)> where K <: Equatable<K> {
func get(key: K): Option<V>
func contains(key: K): Bool
func containsAll(keys: Collection<K>): Bool
mut func put(key: K, value: V): Option<V>
mut func putAll(elements: Collection<(K, V)>): Unit
mut func remove(key: K): Option<V>
mut func removeAll(keys: Collection<K>): Unit
mut func removeIf(predicate: (K, V) -> Bool): Unit
mut func clear(): Unit
func clone(): Map<K, V>
operator func [](key: K): V
operator func [](key: K, value!: V): Unit
func keys(): EquatableCollection<K>
func values(): Collection<V>
prop size: Int64
func isEmpty(): Bool
func iterator(): Iterator<(K, V)>
}
Parent Type:
- Collection<(K, V)>
prop size
prop size: Int64
Description: Returns the number of all key-value pairs in a Map instance.
Type: Int64
func clear()
mut func clear(): Unit
Description: Clears all key-value pairs.
func clone()
func clone(): Map<K, V>
Description: Clones a Map instance.
Returns:
func contains(K)
func contains(key: K): Bool
Description: Checks whether the mapping of a specified key is included.
Parameters:
- key: K: key to be checked
Returns:
- Bool: If the mapping is included, true is returned. Otherwise, false is returned.
func containsAll(Collection<K>)
func containsAll(keys: Collection<K>): Bool
Description: Checks whether the mappings of keys of a specified collection are included.
Parameters:
- keys: Collection<K>: collection of keys to be checked
Returns:
- Bool: If the mappings are included, true is returned. Otherwise, false is returned.
func get(K)
func get(key: K): Option<V>
Description: Obtains the mapping value in a Map instance according to key.
Parameters:
- key: K: key used to obtain a value
Returns:
func isEmpty()
func isEmpty(): Bool
Description: Checks whether a Map instance is empty.
Returns:
func iterator()
func iterator(): Iterator<(K, V)>
Description: Returns the iterator of a Map instance.
Returns:
func keys()
func keys(): EquatableCollection<K>
Description: Returns all keys in a Map instance and stores them in an EquatableCollection<K> container.
Returns:
- EquatableCollection<K>: all keys stored
func put(K, V)
mut func put(key: K, value: V): Option<V>
Description: Puts a passed key-value pair into a Map instance. For an existing key in a Map instance that is the same as the new key to be passed, the value mapped to the key is replaced with the new value.
Parameters:
- key: K: key to be put
- value: V: value to be allocated
Returns:
- Option<V>: If key exists before value allocation, the old value corresponding to key is encapsulated with Option. Otherwise, Option<V>.None is returned.
func putAll(Collection<(K, V)>)
mut func putAll(elements: Collection<(K, V)>): Unit
Description: Puts new key-value pairs into a Map instance. For an existing key in a Map instance that is the same as the new key to be passed, the value mapped to the key is replaced with the new value.
Parameters:
- elements: Collection<(K, V)>: collection of key-value pairs to be put into the Map instance
func remove(K)
mut func remove(key: K): Option<V>
Description: Deletes the mapping (if any) of the specified key from a Map instance.
Parameters:
- key: K: key to be deleted
Returns:
- Option<V>: value corresponding to the key to be removed from the Map instance, which is encapsulated by Option
func removeAll(Collection<K>)
mut func removeAll(keys: Collection<K>): Unit
Description: Deletes the mapping (if any) of a specified collection from a mapping.
Parameters:
- keys: Collection<K>: collection to be deleted
func removeIf((K, V) -> Bool)
mut func removeIf(predicate: (K, V) -> Bool): Unit
Description: Passes a lambda expression. If the conditions are met, the corresponding key-value pair is deleted.
Parameters:
- predicate: (K, V) ->Bool: lambda expression used for judgment
func values()
func values(): Collection<V>
Description: Returns all values in a Map instance and stores them in a Collection<V> container.
Returns:
- Collection<V>: all values stored
operator func [](K)
operator func [](key: K): V
Description: Overrides the indexing operator. If key exists, the value corresponding to key is returned. If key does not exist, an exception is thrown.
Parameters:
- key: K: key to be searched for
Returns:
- V: value corresponding to key
operator func [](K, V)
operator func [](key: K, value!: V): Unit
Description: Overrides the indexing operator. If key exists, the new value overwrites the old value. If key does not exist, the key-value pair is added.
Parameters:
- key: K: key to be set
- value!: V: value to be set
interface Set<T> where T <: Equatable<T>
public interface Set<T> <: Collection<T> where T <: Equatable<T> {
func contains(element: T): Bool
func subsetOf(other: Set<T>): Bool
func containsAll(elements: Collection<T>): Bool
mut func put(element: T): Bool
mut func putAll(elements: Collection<T>): Unit
mut func remove(element: T): Bool
mut func removeAll(elements: Collection<T>): Unit
mut func removeIf(predicate: (T) -> Bool): Unit
mut func clear(): Unit
mut func retainAll(elements: Set<T>): Unit
func clone(): Set<T>
}
Description: Specifies the collection without duplicate elements.
The Set interface does not specify the internal implementation mode. In an instance of the Set interface, the internal elements are usually unordered and cannot be accessed through indexes. In addition, the element insertion order cannot be ensured.
Parent Type:
- Collection<T>
func clear()
mut func clear(): Unit
Description: Clears all key-value pairs.
func clone()
func clone(): Set<T>
Description: Clones a Set instance and returns a new Set instance.
Returns:
func contains(T)
func contains(element: T): Bool
Description: Returns true if a collection contains a specified element.
Parameters:
- element: T: element to be checked
Returns:
- Bool: If the specified element is contained, true is returned. Otherwise, false is returned.
func containsAll(Collection<T>)
func containsAll(elements: Collection<T>): Bool
Description: Checks whether a collection contains a specified collection.
Parameters:
- elements: Collection<T>: specified collection
Returns:
- Bool: If the collection contains the specified collection, true is returned. Otherwise, false is returned.
func put(T)
mut func put(element: T): Bool
Description: Adds an element. If the element already exists, it is not added.
Parameters:
- element: T: element to be added
Returns:
- Bool: If the element is added successfully, true is returned. Otherwise, false is returned.
func putAll(Collection<T>)
mut func putAll(elements: Collection<T>): Unit
Description: Adds all elements in a Collection instance to a Set instance. If elements to be added already exist in the HashSet instance, they are not added.
Parameters:
- elements: Collection<T>: collection of elements to be added
func remove(T)
mut func remove(element: T): Bool
Description: Removes a specified element (if any) from a collection.
Parameters:
- element: T: element to be deleted
Returns:
- Bool: If the specified element exists in the collection and is deleted successfully,
trueis returned. Otherwise,falseis returned.
func removeAll(Collection<T>)
mut func removeAll(elements: Collection<T>): Unit
Description: Removes all elements that are contained in a specified Collection instance from a Set instance.
Parameters:
- elements: Collection<T>: passed Collection<T> instance
func removeIf((T) -> Bool)
mut func removeIf(predicate: (T) -> Bool): Unit
Description: Passes a lambda expression. If the condition of predicate is met, the corresponding element is deleted.
Parameters:
- predicate: (T) ->Bool: lambda expression used for judgment
func retainAll(Set<T>)
mut func retainAll(elements: Set<T>): Unit
Description: Retains only the elements in a Set instance that are the same as those in elements.
Parameters:
- elements: Set<T>: set of elements to be stored
func subsetOf(Set<T>)
func subsetOf(other: Set<T>): Bool
Description: Checks whether a set is a subset of other.
Parameters:
- other: Set<T>: another set
Returns:
- Bool: If the set is a subset of the specified set, true is returned. Otherwise, false is returned.
Class
class ArrayList<T>
public class ArrayList<T> <: Collection<T> {
public init()
public init(capacity: Int64)
public init(size: Int64, initElement: (Int64) -> T)
public init(elements: Array<T>)
public init(elements: Collection<T>)
}
Description: Provides variable-length arrays.
ArrayList is a linear dynamic array. Different from Array, ArrayList has a size that can be automatically adjusted as required and does not need to be specified during creation.
Note:
- When an element is added to a dynamic array, if the array is full, a larger memory space is reallocated, and original elements are copied to the new memory space.
- The advantage of dynamic arrays is that they can reduce memory usage and can be automatically resized as required. Therefore, dynamic arrays are suitable for scenarios where elements need to be frequently added or deleted. However, the disadvantage of dynamic arrays is that performance may deteriorate when memory space is reallocated. Therefore, performance needs to be considered when dynamic arrays are used.
Parent Type:
- Collection<T>
prop size
public prop size: Int64
Description: Returns the number of elements in an ArrayList instance.
Type: Int64
init()
public init()
Description: Constructs an ArrayList instance whose initial capacity is the default value 16.
init(Array<T>)
public init(elements: Array<T>)
Description: Constructs an ArrayList instance that contains all elements in a specified array.
Note:
When the type of T is Int64, the syntax sugar version of the variable-length parameter of this constructor may be ambiguous with
public init(Int64). For example,ArrayList<Int64>(8, 9)represents constructing an ArrayList instance containing two elements, andArrayList<Int64>(8)represents constructing an ArrayList instance whose capacity is 8.
Parameters:
- elements: Array<T>: passed array
init(Collection<T>)
public init(elements: Collection<T>)
Description: Constructs an ArrayList instance that contains all elements in a specified collection. These elements are arranged in the order returned from the iterator of the collection.
Parameters:
- elements: Collection<T>: passed collection
init(Int64)
public init(capacity: Int64)
Description: Constructs an ArrayList instance with initial capacity of a specified size.
Parameters:
- capacity: Int64: specified initial capacity
Throws:
- IllegalArgumentException: If the size of a parameter is less than 0, this exception is thrown.
init(Int64, (Int64) -> T)
public init(size: Int64, initElement: (Int64) -> T)
Description: Constructs an ArrayList instance with a specified initial element quantity and a specified rule function. This constructor sets the capacity of ArrayList based on the size parameter.
Parameters:
- size: Int64: initial function element quantity
- initElement: (Int64) ->T: passed initialization function
Throws:
- IllegalArgumentException: If size is less than 0, this exception is thrown.
func append(T)
public func append(element: T): Unit
Description: Adds a specified element to the end of an ArrayList instance.
Parameters:
- element: T: inserted element; type: T
Example:
For details, see [append and insert functions of ArrayList] (../collection_package_samples/sample_arraylist_append_insert.md).
func appendAll(Collection<T>)
public func appendAll(elements: Collection<T>): Unit
Description: Adds all elements in a specified collection to the end of an ArrayList instance.
This function traverses the collection in the input parameter in the iterator order and inserts all elements to the end of the ArrayList instance.
Parameters:
- elements: Collection<T>: collection of elements to be inserted
func capacity()
public func capacity(): Int64
Description: Returns the capacity of an ArrayList instance.
Returns:
func clear()
public func clear(): Unit
Description: Deletes all elements in an ArrayList instance.
Example:
For details, see [remove, clear, and slice functions of ArrayList] (../collection_package_samples/sample_arraylist_remove_clear_slice.md).
func clone()
public func clone(): ArrayList<T>
Description: Returns a copy (shallow copy) of an ArrayList instance.
Returns:
func get(Int64)
public func get(index: Int64): ?T
Description: Returns the element at a specified location in an ArrayList instance.
Parameters:
- index: Int64: index of the element to be returned
Returns:
- ?T: element at the specified location. If index is less than 0 or greater than or equal to the number of elements in the ArrayList instance, None is returned.
Example:
For details, see [get and set functions of ArrayList] (../collection_package_samples/sample_arraylist_get_set.md).
func getRawArray()
public unsafe func getRawArray(): Array<T>
Description: Returns the raw data of an ArrayList instance.
Note:
This is an unsafe interface, which must be used in the unsafe context.
Raw data refers to an array implemented at the bottom layer of ArrayList. Its size is greater than or equal to the number of elements in ArrayList, and its locations where indexes are greater than or equal to the size of ArrayList may contain uninitialized elements. Accessing the locations may cause undefined behavior.
Returns:
func insert(Int64, T)
public func insert(index: Int64, element: T): Unit
Description: Inserts a specified element to a specified location in an ArrayList instance.
Parameters:
- index: Int64: target index of the element to be inserted
- element: T: T-type element to be inserted
Throws:
- IndexOutOfBoundsException: If index is out of range, this exception is thrown.
Example:
For details, see [append and insert functions of ArrayList] (../collection_package_samples/sample_arraylist_append_insert.md).
func insertAll(Int64, Collection<T>)
public func insertAll(index: Int64, elements: Collection<T>): Unit
Description: Inserts all elements in a specified collection from a specified location into an ArrayList instance.
This function traverses the collection in the input parameter in the iterator order and inserts all elements to the specified location.
Parameters:
- index: Int64: target index of the collection to be inserted
- elements: Collection<T>: T-type element collection to be inserted
Throws:
- IndexOutOfBoundsException: If index is out of range, this exception is thrown.
Example:
For details, see [remove, clear, and slice functions of ArrayList] (../collection_package_samples/sample_arraylist_remove_clear_slice.md).
func isEmpty()
public func isEmpty(): Bool
Description: Checks whether an ArrayList instance is empty.
Returns:
- Bool: If the instance is empty,
trueis returned. Otherwise,falseis returned.
func iterator()
public func iterator(): Iterator<T>
Description: Returns the iterator of elements in an ArrayList instance.
Returns:
func prepend(T)
public func prepend(element: T): Unit
Description: Inserts a specified element into an ArrayList instance at the start location.
Parameters:
- element: T: T-type element to be inserted
func prependAll(Collection<T>)
public func prependAll(elements: Collection<T>): Unit
Description: Inserts all elements in a specified collection from the start location into an ArrayList instance.
This function traverses the collection in the input parameter in the iterator order and inserts all elements to the specified location.
Parameters:
- elements: Collection<T>: T-type element collection to be inserted
func remove(Int64)
public func remove(index: Int64): T
Description: Deletes the element at a specified location in an ArrayList instance.
Parameters:
- index: Int64: index of the element to be deleted
Returns:
- T: deleted element
Throws:
- IndexOutOfBoundsException: If index is out of range, this exception is thrown.
Example:
For details, see [remove, clear, and slice functions of ArrayList] (../collection_package_samples/sample_arraylist_remove_clear_slice.md).
func remove(Range<Int64>)
public func remove(range: Range<Int64>): Unit
Description: Deletes all elements contained in the Range range of an ArrayList instance.
Note:
If the range parameter is a Range instance constructed using the constructor of Range and hasEnd is false, the value of end does not take effect and is not affected by the value of isClosed passed during construction. The last element of the original array is included.
Parameters:
Throws:
- IllegalArgumentException: If step of range is not 1, this exception is thrown.
- IndexOutOfBoundsException: If start or end of range is less than 0 or end is greater than the length of Array, this exception is thrown.
func removeIf((T) -> Bool)
public func removeIf(predicate: (T) -> Bool): Unit
Description: Deletes all elements that meet a specified lambda expression or function from an ArrayList instance.
Parameters:
- predicate: (T) ->Bool: condition used for determining deletion
func reserve(Int64)
public func reserve(additional: Int64): Unit
Description: Increases the capacity of an ArrayList instance.
Expands the capacity of ArrayList by additional. When additional is less than or equal to 0, capacity is not expanded. When the remaining capacity of ArrayList is greater than or equal to the additional capacity, capacity is not expanded. When the remaining capacity of ArrayList is less than the additional capacity, capacity is expanded to the larger value of (1.5 times the rounded-down original capacity) and (additional + used capacity).
Parameters:
- additional: Int64: size to which capacity is expanded
Throws:
- OverflowException: If the sum of additional capacity and used capacity exceeds Int64.Max, this exception is thrown.
func reverse()
public func reverse(): Unit
Description: Reverses the order of elements in an ArrayList instance.
func set(Int64, T)
public func set(index: Int64, element: T): Unit
Description: Replaces the element at the specified location in an ArrayList instance with a specified element.
Parameters:
- index: Int64: index to be set
- element: T: T-type element
Throws:
- IndexOutOfBoundsException: If index is less than 0 or greater than or equal to the number of elements in ArrayList, this exception is thrown.
Example:
For details, see [get and set functions of ArrayList] (../collection_package_samples/sample_arraylist_get_set.md).
func slice(Range<Int64>)
public func slice(range: Range<Int64>): ArrayList<T>
Description: Returns the ArrayList<T> corresponding to the passed parameter range index.
Note:
If the range parameter is a Range instance constructed using the constructor of Range, the behaviors are as follows:
- The value of start is the value passed to the constructor and is not affected by the value of hasStart passed in during construction.
- When hasEnd is false, the value of end does not take effect and is not affected by the value of isClosed passed in during construction, and the last element of the original array is included.
Parameters:
Returns:
- ArrayList<T>: array obtained after slicing
Throws:
- IllegalArgumentException: If step of range is not 1, this exception is thrown.
- IndexOutOfBoundsException: If range is invalid, this exception is thrown.
Example:
For details, see [remove, clear, and slice functions of ArrayList] (../collection_package_samples/sample_arraylist_remove_clear_slice.md).
func sortBy(Bool, (T, T) -> Ordering)
public func sortBy(stable!: Bool = false, comparator!: (T, T) -> Ordering): Unit
Description: Sorts elements in an array.
The passed comparison function comparator: (t1: T, t2: T) -> Ordering can be used to sort an array based on the return value of the Ordering type. If the return value of comparator is Ordering.GT, t1 is after t2 after sorting. If the return value of comparator is Ordering.LT, t1 is before t2 after sorting. If the return value of comparator is Ordering.EQ and the sorting is stable, t1 is before t2. If the return value of comparator is Ordering.EQ and the sorting is unstable, the order of t1 and t2 is uncertain.
Parameters:
- stable!: Bool: whether to use stable sorting
- comparator!: (T, T) ->Ordering: (T, T) -> Ordering type
func toArray()
public func toArray(): Array<T>
Description: Returns an array that contains all elements in the correct order in a list.
Returns:
- Array<T>: T-type array
operator func [](Int64)
public operator func [](index: Int64): T
Description: Overrides the get method.
Parameters:
- index: Int64: index of the get API
Returns:
- T: value of the element at the location specified by the index
Throws:
- IndexOutOfBoundsException: If index is out of range, this exception is thrown.
operator func [](Int64, T)
public operator func [](index: Int64, value!: T): Unit
Description: Overrides the set method, that is, replaces the element at the specified location in a list with the specified element using an index operator.
Parameters:
- index: Int64: index to be set
- value!: T: T-type value to be set
Throws:
- IndexOutOfBoundsException: If index is out of range, this exception is thrown.
operator func [](Range<Int64>)
public operator func [](range: Range<Int64>): ArrayList<T>
Description: Overrides the slice method.
Note:
If the range parameter is a Range instance constructed using the constructor of Range, the behaviors are as follows:
- The value of start is the value passed to the constructor and is not affected by the value of hasStart passed in during construction.
- When hasEnd is false, the value of end does not take effect and is not affected by the value of isClosed passed in during construction, and the last element of the original array is included.
The ArrayList object returned by the slice operation is a new object and has no reference relationship with the original ArrayList object.
Parameters:
Returns:
- ArrayList<T>: array obtained after slicing
Throws:
- IllegalArgumentException: If step of range is not 1, this exception is thrown.
- IndexOutOfBoundsException: If range is invalid, this exception is thrown.
extend<T> ArrayList<T> <: Equatable<ArrayList<T>> where T <: Equatable<T>
extend<T> ArrayList<T> <: Equatable<ArrayList<T>> where T <: Equatable<T>
Description: Extends the Equatable<ArrayList<T>> interface for the ArrayList<T> type to support the equality check operation.
Parent Type:
operator func ==(ArrayList<T>)
public operator func ==(that: ArrayList<T>): Bool
Description: Checks whether the current instance is equal to the ArrayList instance specified by the that parameter.
Two arrays being equal means that elements at corresponding locations of the two arrays are respectively equal.
Parameters:
- that: ArrayList<T>: instance to be compared with
Returns:
- Bool: If the two instances are equal, true is returned. Otherwise, false is returned.
operator func !=(ArrayList<T>)
public operator func !=(that: ArrayList<T>): Bool
Description: Checks whether the current instance is not equal to the ArrayList instance specified by the that parameter.
Parameters:
- that: ArrayList<T>: instance to be compared with
Returns:
- Bool: If the two instances are not equal, true is returned. Otherwise, false is returned.
func contains(T)
public func contains(element: T): Bool
Description: Checks whether the current array contains the specified element element.
Parameters:
- element: T: element to be searched for
Returns:
- Bool: If the array contains the specified element, true is returned. Otherwise, false is returned.
extend<T> ArrayList<T> <: SortExtension where T <: Comparable<T>
extend<T> ArrayList<T> <: SortExtension where T <: Comparable<T>
Description: Extends the SortExtension interface for ArrayList<T> to support array sorting.
Parent Type:
func sort(Bool)
public func sort(stable!: Bool = false): Unit
Description: Sorts elements in the current array in ascending order.
Parameters:
- stable!: Bool: whether to use stable sorting
func sortDescending(Bool)
public func sortDescending(stable!: Bool = false): Unit
Description: Sorts elements in the current array in descending order.
Parameters:
- stable!: Bool: whether to use stable sorting
extend<T> ArrayList<T> <: ToString where T <: ToString
extend<T> ArrayList<T> <: ToString where T <: ToString
Description: Extends the ToString interface for ArrayList<T> to support string conversion.
Parent Type:
func toString()
public func toString(): String
Description: Converts the current array to a string.
The string contains the string representation of each element in the array, for example, "[elem1, elem2, elem3]".
Returns:
- String: string after conversion
class ArrayListIterator<T>
public class ArrayListIterator<T> <: Iterator<T> {
public init(data: ArrayList<T>)
}
Description: Implements the iterator function of ArrayList.
Parent Type:
- Iterator<T>
init(ArrayList<T>)
public init(data: ArrayList<T>)
Description: Creates an ArrayListIterator<T> instance.
Parameters:
- date: passed ArrayList<T>
func next()
public func next(): Option<T>
Description: Returns the next element in an iterator.
Returns:
- ?T: next element in the iterator, which is encapsulated by Option
Throws:
- ConcurrentModificationException: If the function detects an asynchronous concurrent modification, this exception is thrown.
func iterator()
public func iterator(): Iterator<T>
Description: Returns an iterator itself.
Returns:
- Iterator<T>: iterator itself
class HashMapIterator<K, V> where K <: Hashable & Equatable<K>
public class HashMapIterator<K, V> <: Iterator<(K, V)> where K <: Hashable & Equatable<K> {
public init(map: HashMap<K, V>)
}
Description: Implements the iterator function of HashMap.
Parent Type:
- Iterator<(K, V)>
init(HashMap<K, V>)
public init(map: HashMap<K, V>)
Description: Creates a HashMapIterator<K, V> instance.
Parameters:
func iterator()
public func iterator(): Iterator<(K, V)>
Description: Returns an iterator instance itself.
Returns:
- Iterator <(K, V) >: iterator instance itself
func next()
public func next(): ?(K, V)
Description: Returns the next element in an iterator.
Returns:
- ?(K, V): next element in the iterator, which is encapsulated by Option
Throws:
- ConcurrentModificationException: If the function detects an asynchronous concurrent modification, this exception is thrown.
func remove()
public func remove(): Option<(K, V)>
Description: Deletes the elements returned by the next function of the iterator of HashMap. This function can be called only once when the next function is called.
Returns:
- Option <(K, V) >: deleted elements
Throws:
- ConcurrentModificationException: If the function detects an asynchronous concurrent modification, this exception is thrown.
class HashMap<K, V> where K <: Hashable & Equatable<K>
public class HashMap<K, V> <: Map<K, V> where K <: Hashable & Equatable<K> {
public init()
public init(elements: Collection<(K, V)>)
public init(elements: Array<(K, V)>)
public init(capacity: Int64)
public init(size: Int64, initElement: (Int64) -> (K, V))
}
Description: Specifies the hash table implementation of the Map interface.
A hash table is a common data structure that can be used to quickly search for, insert, and delete data. The basic principle of a hash table is to map data to an array, which is called a hash table. Each data element has a corresponding hash value, and the hash value can be used to determine a location of the element in a hash table.
The features of hash tables are fast search, insertion, and deletion operations, and the time complexity is usually O(1). Since the array size at the bottom layer of a hash table is dynamic, the hash table cannot ensure that the order of elements is immutable.
Parent Type:
- Map<K, V>
prop size
public prop size: Int64
Description: Returns the number of key-value pairs.
Type: Int64
init()
public init()
Description: Constructs a HashMap instance whose default initial capacity is 16 and default load factor is empty.
init(Array<(K, V)>)
public init(elements: Array<(K, V)>)
Description: Constructs a HashMap instance based on the passed key-value pair array.
This constructor sets the capacity of HashMap based on the size of the passed array. Duplicate keys are not allowed in HashMap. Therefore, when duplicate keys exist in Array, the key-value pair that appears later overwrites the key-value pair of the duplicate key based on the iterator order.
Parameters:
init(Collection<(K, V)>)
public init(elements: Collection<(K, V)>)
Description: Constructs a HashMap instance based on the passed key-value pair collection.
This constructor sets the capacity of HashMap based on the size of the passed collection elements. Duplicate keys are not allowed in HashMap. Therefore, when duplicate keys exist in Array, the key-value pair that appears later overwrites the key-value pair of the duplicate key based on the iterator order.
Parameters:
- elements: Collection<(K, V)>: key-value pair collection used to initialize the HashMap instance
init(Int64)
public init(capacity: Int64)
Description: Constructs a HashMap instance with a passed capacity.
Parameters:
- capacity: Int64: initial capacity
Throws:
- IllegalArgumentException: If capacity is less than 0, this exception is thrown.
init(Int64, (Int64) -> (K, V))
public init(size: Int64, initElement: (Int64) -> (K, V))
Description: Constructs a HashMap instance based on the passed element quantity size and function rule.
The capacity of the constructed HashMap instance is affected by size. Duplicate keys are not allowed in HashMap. Therefore, when the initElement function generates a duplicate key, the key-value pair constructed later overwrites the key-value pair of the duplicate key.
Parameters:
- size: Int64: function rule used to initialize the HashMap instance
- initElement: (Int64) ->(K, V): function rule used to initialize the HashMap instance
Throws:
- IllegalArgumentException: If size is less than 0, this exception is thrown.
func capacity()
public func capacity(): Int64
Description: Returns the capacity of a HashMap instance.
Returns:
func clear()
public func clear(): Unit
Description: Clears all key-value pairs.
Example:
For details, see [putAll, remove, and clear functions of HashMap] (../collection_package_samples/sample_hashmap_putall_remove_clear.md).
func clone()
public func clone(): HashMap<K, V>
Description: Clones a HashMap instance.
Returns:
func contains(K)
public func contains(key: K): Bool
Description: Checks whether the mapping of a specified key is included.
Parameters:
- key: K: key to be checked
Returns:
- Bool: If key is included, true is returned. Otherwise, false is returned.
Example:
For details, see [get, put, and contains functions of Hashmap] (../collection_package_samples/sample_hashmap_get_put_contains.md).
func containsAll(Collection<K>)
public func containsAll(keys: Collection<K>): Bool
Description: Checks whether the mappings of all keys in a specified collection are included.
Parameters:
- keys: Collection<K>: keys to be checked
Returns:
- Bool: If all mappings are included, true is returned. Otherwise, false is returned.
func entryView(K)
public func entryView(key: K): EntryView<K, V>
Description: Returns an empty reference view if a specific key is not included. If the specific key is included, the reference view of the element corresponding to the key is returned.
For details about how to use EntryView, see EntryView.
Parameters:
- key: K: key of the key-value pair to be added
Returns:
- EntryView < K, V >: reference view
func get(K)
public func get(key: K): Option<V>
Description: Returns the value mapped to a specified key. If HashMap does not contain the mapping of the specified key, Option<V>.None is returned.
Parameters:
- key: K: passed key
Returns:
Example:
For details, see [get, put, and contains functions of Hashmap] (../collection_package_samples/sample_hashmap_get_put_contains.md).
func isEmpty()
public func isEmpty(): Bool
Description: Checks whether a HashMap instance is empty. If yes, true is returned. If no, false is returned.
Returns:
func iterator()
public func iterator(): HashMapIterator<K, V>
Description: Returns an iterator of Hashmap.
Returns:
- HashMapIterator < K, V >: iterator of HashMap
func keys()
public func keys(): EquatableCollection<K>
Description: Returns all keys in a HashMap instance and stores them in a Keys container.
Returns:
- EquatableCollection<K>: all keys stored
func put(K, V)
public func put(key: K, value: V): Option<V>
Description: Puts a key-value pair into a HashMap instance.
For an existing key in the HashMap instance that is the same as the new key to be passed, the value of the existing key is replaced with the new value and the old existing value is returned.
Parameters:
- key: K: key to be put
- value: V: value to be allocated
Returns:
- Option<V>: If key exists before value allocation, the old value corresponding to key is encapsulated with Option. Otherwise, Option<V>.None is returned.
Example:
For details, see [get, put, and contains functions of Hashmap] (../collection_package_samples/sample_hashmap_get_put_contains.md).
func putAll(Collection<(K, V)>)
public func putAll(elements: Collection<(K, V)>): Unit
Description: Puts a new key-value pair collection into a HashMap instance based on the iterator order of elements.
For an existing key in the HashMap instance that is the same as the new key to be passed, the value of the key is replaced with the new value.
Parameters:
- elements: Collection<(K, V)>: key-value pair collection to be added to the HashMap instance
Example:
For details, see [putAll, remove, and clear functions of HashMap] (../collection_package_samples/sample_hashmap_putall_remove_clear.md).
func putIfAbsent(K, V)
public func putIfAbsent(key: K, value: V): Bool
Description: Inserts a key-value pair (key, value) into a HashMap instance if key does not exist in the HashMap instance.
Parameters:
- key: K: key to be put
- value: V: value to be allocated
Returns:
- Bool: If key exists before value allocation,
falseis returned. Otherwise,trueis returned.
func remove(K)
public func remove(key: K): Option<V>
Description: Deletes the mapping (if any) of the specified key from a HashMap instance.
Parameters:
- key: K: key to be deleted
Returns:
- Option<V>: value corresponding to the key removed from the HashMap instance, which is encapsulated with Option. If key does not exist in the HashMap instance, None is returned.
Example:
For details, see [putAll, remove, and clear functions of HashMap] (../collection_package_samples/sample_hashmap_putall_remove_clear.md).
func removeAll(Collection<K>)
public func removeAll(keys: Collection<K>): Unit
Description: Deletes the mappings (if any) of keys in a specified collection from a HashMap instance.
Parameters:
- keys: Collection<K>: collection of keys to be deleted
func removeIf((K, V) -> Bool)
public func removeIf(predicate: (K, V) -> Bool): Unit
Description: Passes a lambda expression. If the conditions are met, the corresponding key-value pair is deleted.
This function traverses the entire HashMap instance and deletes all key-value pairs that meet predicate(K, V) = = true.
Parameters:
- predicate: (K, V) ->Bool: lambda expression used for judgment
Throws:
- ConcurrentModificationException: If addition, deletion, or modification of key-value pairs is performed on HashMap through
predicate, this exception is thrown.
func reserve(Int64)
public func reserve(additional: Int64): Unit
Description: Expands the capacity of the current HashMap instance.
Expands the capacity of HashMap by additional. When additional is less than or equal to 0, capacity is not expanded. When the remaining capacity of HashMap is greater than or equal to additional, capacity is not expanded. When the remaining capacity of HashMap is less than additional, capacity is expanded to the larger value of (1.5 times the rounded-down original capacity) and (additional + used capacity).
Parameters:
- additional: Int64: size to which capacity is expanded
Throws:
- OverflowException: If the sum of additional capacity and used capacity exceeds Int64.Max, this exception is thrown.
func toArray()
public func toArray(): Array<(K, V)>
Description: Constructs an array containing key-value pairs in a HashMap instance and returns the array.
Returns:
- Array <(K, V) >: array containing all key-value pairs in the container
func values()
public func values(): Collection<V>
Description: Returns all values contained in a HashMap instance and stores them in a Values container.
Returns:
- Collection<V>: all values stored
operator func [](K, V)
public operator func [](key: K, value!: V): Unit
Description: Overrides the put method. If key exists, the new value overwrites the old value. If key does not exist, the key-value pair is added.
Parameters:
- key: K: key used for judgment
- value!: V: value to be set
operator func [](K)
public operator func [](key: K): V
Description: Overrides the get method. If key exists, the value corresponding to key is returned.
Parameters:
- key: K: key used for judgment
Returns:
- V: value corresponding to the key
Throws:
- NoneValueException: If key does not exist in the HashMap instance, this exception is thrown.
extend<K, V> HashMap<K, V> <: Equatable<HashMap<K, V>> where V <: Equatable<V>
extend<K, V> HashMap<K, V> <: Equatable<HashMap<K, V>> where V <: Equatable<V>
Description: Extends the Equatable<HashMap<K, V>> interface for the HashMap<K, V> type to support the equality check operation.
Parent Type:
operator func ==(HashMap<K, V>)
public operator func ==(right: HashMap<K, V>): Bool
Description: Checks whether the current instance is equal to the HashMap<K, V> instance specified by the right parameter.
Two HashMap<K, V> instances being equal means that key-value pairs included the two instances are completely equal.
Parameters:
- right: HashMap<K, V>: objects to be compared
Returns:
- Bool: If the two instances are equal, true is returned. Otherwise, false is returned.
operator func !=(HashMap<K, V>)
public operator func !=(right: HashMap<K, V>): Bool
Description: Checks whether the current instance is not equal to the HashMap<K, V> instance specified by the right parameter.
Parameters:
- right: HashMap<K, V>: objects to be compared
Returns:
- Bool: If the two instances are not equal, true is returned. Otherwise, false is returned.
extend<K, V> HashMap<K, V> <: ToString where V <: ToString, K <: ToString
extend<K, V> HashMap<K, V> <: ToString where V <: ToString, K <: ToString
Description: Extends the ToString interface for HashMap<K, V> to support string conversion.
Parent Type:
func toString()
public func toString(): String
Description: Converts the current HashMap<K, V> instance to a string.
The string contains the string representation of each key-value pair in the HashMap<K, V> instance, for example, "[(k1, v1), (k2, v2), (k3, v3)]".
Returns:
- String: string after conversion
class HashSet<T> where T <: Hashable & Equatable<T>
public class HashSet<T> <: Set<T> where T <: Hashable & Equatable<T> {
public init()
public init(elements: Collection<T>)
public init(elements: Array<T>)
public init(capacity: Int64)
public init(size: Int64, initElement: (Int64) -> T)
}
Description: Specifies the instance of the Set interface implemented based on HashMap.
The elements in HashSet are unordered and cannot contain duplicate elements. When an element is added to HashSet, HashSet determines the location of the element in the hash table based on the hash value of the element.
Note:
HashSet is implemented based on HashMap. Therefore, the capacity, memory layout, and time performance of HashSet are the same as those of HashMap.
Parent Type:
- Set<T>
prop size
public prop size: Int64
Description: Returns the number of elements of a HashSet instance.
Type: Int64
init(Int64, Int64 -> T)
public init(size: Int64, initElement: (Int64) -> T)
Description: Constructs a HashSet instance based on the passed function element quantity size and function rule. The capacity of the constructed HashSet instance is affected by size.
Parameters:
Throws:
- IllegalArgumentException: If size is less than 0, this exception is thrown.
init()
public init()
Description: Constructs an empty HashSet instance with an initial capacity of 16.
init(Array<T>)
public init(elements: Array<T>)
Description: Constructs a HashSet instance using a passed array. This constructor sets the capacity of HashSet based on size of the passed elements array.
Parameters:
init(Collection<T>)
public init(elements: Collection<T>)
Description: Constructs a HashSet instance using a passed collection. This constructor sets the capacity of HashSet based on size of the passed elements collection.
Parameters:
- elements: Collection<T>: collection used to initialize the HashSet instance
init(Int64)
public init(capacity: Int64)
Description: Constructs a HashSet instance using a passed capacity.
Parameters:
- capacity: Int64: initial capacity
Throws:
- IllegalArgumentException: If capacity is less than 0, this exception is thrown.
func capacity()
public func capacity(): Int64
Description: Returns the internal array capacity of a HashSet instance.
Note:
The capacity may not be equal to the size of the HashSet instance.
Returns:
func clear()
public func clear(): Unit
Description: Removes all elements from a HashSet instance.
func clone()
public func clone(): HashSet<T>
Description: Clones a HashSet instance.
Returns:
func contains(T)
public func contains(element: T): Bool
Description: Checks whether a HashSet instance contains a specified element.
Parameters:
- element: T: specified element
Returns:
- Bool: If the instance contains the specified element, true is returned. Otherwise, false is returned.
func containsAll(Collection<T>)
public func containsAll(elements: Collection<T>): Bool
Description: Checks whether a HashSet instance contains all elements in the specified Collection instance.
Parameters:
- elements: Collection<T>: specified element collection
Returns:
- Bool: If the HashSet instance contains all elements in the specified Collection instance, true is returned. Otherwise, false is returned.
func isEmpty()
public func isEmpty(): Bool
Description: Checks whether a HashSet instance is empty.
Returns:
- Bool: If the instance is empty, true is returned. Otherwise, false is returned.
func iterator()
public func iterator(): Iterator<T>
Description: Returns the iterator of a HashSet instance.
Returns:
Example:
For details, see [put, iterator, and remove functions of HashSet] (../collection_package_samples/sample_hashset_put_iterator_remove.md).
func put(T)
public func put(element: T): Bool
Description: Adds a specified element to a HashSet instance. If the element to be added exists in the HashSet instance, the element fails to be added.
Parameters:
- element: T: specified element
Returns:
- Bool: If the element is added successfully, true is returned. Otherwise, false is returned.
Example:
For details, see [put, iterator, and remove functions of HashSet] (../collection_package_samples/sample_hashset_put_iterator_remove.md).
func putAll(Collection<T>)
public func putAll(elements: Collection<T>): Unit
Description: Adds all elements in a Collection instance to a HashSet instance. If elements to be added already exist in the HashSet instance, they are not added.
Parameters:
- elements: Collection<T>: collection of elements to be added
func remove(T)
public func remove(element: T): Bool
Description: Removes a specified element if it exists in a HashSet instance.
Parameters:
- element: T: element to be removed
Returns:
- Bool: true indicating that the removal is successful; false indicating that the removal fails
Example:
For details, see [put, iterator, and remove functions of HashSet] (../collection_package_samples/sample_hashset_put_iterator_remove.md).
func removeAll(Collection<T>)
public func removeAll(elements: Collection<T>): Unit
Description: Removes all elements that are contained in a specified Collection instance from a HashSet instance.
Parameters:
- elements: Collection<T>: collection of elements to be removed from the HashSet instance
func removeIf((T) -> Bool)
public func removeIf(predicate: (T) -> Bool): Unit
Description: Passes a lambda expression. If the condition of predicate is met, the corresponding element is deleted.
Parameters:
- predicate: (T) ->Bool: condition for determining whether to delete an element
Throws:
- ConcurrentModificationException: If addition, deletion, or modification of key-value pairs is performed on [HashSet](collection_package_class.md#class-hashsett-where-t--hashable--equatablet) through
predicate, this exception is thrown.
func reserve(Int64)
public func reserve(additional: Int64): Unit
Description: Expands the capacity of HashSet by additional. When additional is less than or equal to 0, capacity is not expanded. When the remaining capacity of HashSet is greater than or equal to additional, capacity is not expanded. When the remaining capacity of HashSet is less than additional, capacity is expanded to the larger value of (1.5 times the rounded-down original capacity) and (additional + used capacity).
Parameters:
- additional: Int64: size to which capacity is expanded
Throws:
- OverflowException: If the sum of additional capacity and used capacity exceeds Int64.Max, this exception is thrown.
func retainAll(Set<T>)
public func retainAll(elements: Set<T>): Unit
Description: Retains the elements in a Set instance from a HashSet instance.
Parameters:
func subsetOf(Set<T>)
public func subsetOf(other: Set<T>): Bool
Description: Checks whether a set is a subset of other Set instances.
Parameters:
- other: Set<T>: set to be passed. This function checks whether the current set is a subset of other.
Returns:
- Bool: If the Set instance is a subset of the specified Set instance, true is returned. Otherwise, false is returned.
func toArray()
public func toArray(): Array<T>
Description: Returns an array containing all elements in a container.
Returns:
- Array<T>: T-type array
extend<T> HashSet<T> <: Equatable<HashSet<T>>
extend<T> HashSet<T> <: Equatable<HashSet<T>>
Description: Extends the Equatable<HashSet<T>> interface for the HashSet<T> type to support the equality check operation.
Parent Type:
operator func ==(HashSet<T>)
public operator func ==(that: HashSet<T>): Bool
Description: Checks whether the current instance is equal to the HashSet<T> instance specified by the that parameter.
Two HashSet<T> instances being equal means that elements included in the two instances are completely equal.
Parameters:
- that: HashSet<T>: instance to be compared with
Returns:
- Bool: If the two instances are equal, true is returned. Otherwise, false is returned.
operator func !=(HashSet<T>)
public operator func !=(that: HashSet<T>): Bool
Description: Checks whether the current instance is not equal to the HashSet<T> instance specified by the that parameter.
Parameters:
- that: HashSet<T>: instance to be compared with
Returns:
- Bool: If the two instances are not equal, true is returned. Otherwise, false is returned.
extend<T> HashSet<T> <: ToString where T <: ToString
extend<T> HashSet<T> <: ToString where T <: ToString
Description: Extends the ToString interface for HashSet<T> to support string conversion.
Parent Type:
func toString()
public func toString(): String
Description: Converts the current HashSet<T> instance to a string.
The string contains the string representation of each element in a HashSet<T> instance, for example, "[elem1, elem2, elem3]".
Returns:
- String: string after conversion
class LinkedListNode<T>
public class LinkedListNode<T>
Description: a LinkedListNode instance is a node on a LinkedList instance.
LinkedListNode can be used to traverse forward and backward LinkedList to access and modify element values.
LinkedListNode can be obtained only through 'nodeAt', 'firstNode', and 'lastNode' of the corresponding LinkedList instance. When the corresponding node is deleted from the LinkedList instance, a dangling node is generated. Any operation on the dangling node triggers an 'IllegalStateException' exception.
prop next
public prop next: Option<LinkedListNode<T>>
Description: Obtains the next node of the current node. If there is no next node, None is returned.
Type: Option<LinkedListNode<T>>
Throws:
- IllegalStateException: If the node does not belong to any linked list instance, this exception is thrown.
prop prev
public prop prev: Option<LinkedListNode<T>>
Description: Obtains the previous node of the current node. If there is no previous node, None is returned.
Type: Option<LinkedListNode<T>>
Throws:
- IllegalStateException: If the node does not belong to any linked list instance, this exception is thrown.
prop value
public mut prop value: T
Description: Obtains or modifies the value of an element.
Type: T
Throws:
- IllegalStateException: If the node does not belong to any linked list instance, this exception is thrown.
func backward()
public func backward(): Iterator<T>
Description: Obtains an iterator of all elements from the current node to the last node of the corresponding linked list.
Returns:
- Iterator<T>: iterator of the corresponding elements
Throws:
- IllegalStateException: If the node does not belong to any linked list instance, this exception is thrown.
func forward()
public func forward(): Iterator<T>
Description: Obtains an iterator of all elements from the current node to the first node of the corresponding linked list.
Returns:
- Iterator<T>: iterator of the corresponding elements
Throws:
- IllegalStateException: If the node does not belong to any linked list instance, this exception is thrown.
class LinkedList<T>
public class LinkedList<T> <: Collection<T> {
public init()
public init(elements: Collection<T>)
public init(elements: Array<T>)
public init(size: Int64, initElement: (Int64)-> T)
}
Description: Specifies the data structure with doubly linked list mode implemented.
A doubly linked list is a common data structure. It consists of a series of nodes. Each node contains two pointers, one pointing to the previous node and the other pointing to the next node. This structure allows bidirectional traversal on any node. The traversal can start from the first node or may start from the last node.
LinkedList does not support concurrent operations. Modifying elements in LinkedList does not invalidate the iterator. The iterator becomes invalid only when elements are added or deleted.
Parent Type:
- Collection<T>
prop first
public prop first: ?T
Description: Returns the value of the first element in a linked list. If the linked list is empty, None is returned.
Type: ?T
prop last
public prop last: ?T
Description: Returns the value of the last element in a linked list. If the linked list is empty, None is returned.
Type: ?T
prop size
public prop size: Int64
Description: Obtains the number of elements in a linked list.
Type: Int64
init
public init()
Description: Constructs an empty linked list.
init(Array<T>)
public init(elements: Array<T>)
Description: Constructs a LinkedList instance that contains elements of a specified collection based on the traversal order of an array.
Parameters:
- elements: Array<T>: element array to be put into the linked list
init(Collection<T>)
public init(elements: Collection<T>)
Description: Constructs a linked list that contains elements of a specified collection based on the order of elements returned from the iterator of a collection.
Parameters:
- elements: Collection<T>: element collection to be put into the linked list
init(Int64, (Int64)-> T)
public init(size: Int64, initElement: (Int64)-> T)
Description: Creates a linked list that contains size elements and in which the nth element meets the (Int64)-> T condition.
Parameters:
- size: Int64: number of linked list elements to be created
- initElement: (Int64) ->T: initialization parameter of elements
func append(T)
public func append(element: T): LinkedListNode<T>
Description: Adds an element to the end of a linked list and returns the node of the element.
Parameters:
- element: T: element to be added to the linked list
Returns:
- LinkedListNode<T>: node pointing to the element
func clear()
public func clear(): Unit
Description: Deletes all elements in a linked list.
func firstNode()
public func firstNode(): Option<LinkedListNode<T>>
Description: Obtains the node of the first element in a linked list.
Returns:
- Option < LinkedListNode<T>>: node of the first element. If the linked list is empty, None is returned.
func insertAfter(LinkedListNode<T>,T)
public func insertAfter(node: LinkedListNode<T>, element: T): LinkedListNode<T>
Description: Inserts an element after a specified node in a linked list and returns the node of the element.
Parameters:
- node: LinkedListNode<T>: specified node
- element: T: element to be added to the linked list
Returns:
- LinkedListNode<T>: node pointing to the inserted element
Throws:
- IllegalArgumentException: If the specified node does not belong to the original linked list, this exception is thrown.
func insertBefore(LinkedListNode<T>,T)
public func insertBefore(node: LinkedListNode<T>, element: T): LinkedListNode<T>
Description: Inserts an element before a specified node in a linked list and returns the node of the element.
Parameters:
- node: LinkedListNode<T>: specified node
- element: T: element to be added to the linked list
Returns:
- LinkedListNode<T>: node pointing to the inserted element
Throws:
- IllegalArgumentException: If the specified node does not belong to the original linked list, this exception is thrown.
func isEmpty()
public func isEmpty(): Bool
Description: Checks whether a linked list is empty.
Returns:
- Bool: true is returned if the linked list does not contain any element.
func iterator()
public func iterator(): Iterator<T>
Description: Returns the iterator of elements in the current collection. Its order is from the first node of the linked list to the last node of the linked list.
Returns:
- Iterator<T>: iterator of elements in the current collection
func lastNode()
public func lastNode(): Option<LinkedListNode<T>>
Description: Obtains the node of the last element in a linked list.
Returns:
- Option < LinkedListNode<T>>: node of the last element. If the linked list is empty, None is returned.
func nodeAt(Int64)
public func nodeAt(index: Int64): Option<LinkedListNode<T>>
Description: Obtains the node of the element with the number of index in a linked list. The number starts from 0.
Time complexity of this function is O(n).
Parameters:
- index: Int64: index specifying the node of the element to be obtained
Returns:
- Option < LinkedListNode<T>>: node with the number of index. If there is no node with the number of index, None is returned.
func popFirst()
public func popFirst() : ?T
Description: Removes the first element of a linked list and returns the value of this element.
Returns:
- ?T: value of the deleted element. If the linked list is empty, None is returned.
func popLast()
public func popLast() : ?T
Description: Removes the last element of a linked list and returns the value of this element.
Returns:
- ?T: value of the deleted element. If the linked list is empty, None is returned.
func prepend(T)
public func prepend(element: T): LinkedListNode<T>
Description: Inserts an element into the head of a linked list and returns the node of the element.
Parameters:
- element: T: element to be added to the linked list
Returns:
- LinkedListNode<T>: node pointing to the element
func remove(LinkedListNode<T>)
public func remove(node: LinkedListNode<T>): T
Description: Deletes a specified node in a linked list.
Parameters:
- node: LinkedListNode<T>: node to be deleted
Returns:
- T: value of the deleted node
Throws:
- IllegalArgumentException: If the specified node does not belong to the original linked list, this exception is thrown.
func removeIf((T)-> Bool)
public func removeIf(predicate: (T)-> Bool): Unit
Description: Deletes all elements that meet the specified lambda expression or function in a linked list.
Parameters:
- predicate: (T) ->Bool: true for the element to be deleted
func reverse()
public func reverse(): Unit
Description: Reverses the order of elements in a linked list.
func splitOff(LinkedListNode<T>)
public func splitOff(node: LinkedListNode<T>): LinkedList<T>
Description: Splits a linked list into two linked lists starting from a node specified by node. If the splitting is successful, node is not in the current linked list but exists in the new linked list as the first node.
Parameters:
- node: LinkedListNode<T>: splitting location
Returns:
- LinkedList<T>: linked list generated after the original linked list is split
Throws:
- IllegalArgumentException: If the specified node does not belong to the original linked list, this exception is thrown.
func toArray()
public func toArray(): Array<T>
Description: Returns an array that contains all elements in a linked list in the same order as the linked list.
Returns:
- Array<T>: T-type array
extend<T> LinkedList<T> <: Equatable<LinkedList<T>> where T <: Equatable<T>
extend<T> LinkedList<T> <: Equatable<LinkedList<T>> where T <: Equatable<T>
Description: Extends the Equatable<LinkedList<T>> interface for the LinkedList<T> type to support the equality check operation.
Parent Type:
- Equatable<LinkedList<T>>
operator func ==(LinkedList<T>)
public operator func ==(right: LinkedList<T>): Bool
Description: Checks whether the current instance is equal to the LinkedList<T> instance specified by the right parameter.
Two LinkedList<T> instances being equal means that elements included in the two instances are completely equal.
Parameters:
- right: HashSet<T>: objects to be compared
Returns:
- Bool: If the two instances are equal, true is returned. Otherwise, false is returned.
operator func !=(LinkedList<T>)
public operator func !=(right: LinkedList<T>): Bool
Description: Checks whether the current instance is not equal to the LinkedList<T> instance specified by the right parameter.
Parameters:
- right: LinkedList<T>: objects to be compared
Returns:
- Bool: If the two instances are not equal, true is returned. Otherwise, false is returned.
extend<T> LinkedList<T> <: ToString where T <: ToString
extend<T> LinkedList<T> <: ToString where T <: ToString
Description: Extends the ToString interface for LinkedList<T> to support string conversion.
Parent Type:
func toString()
public func toString(): String
Description: Converts the current LinkedList<T> instance to a string.
The string contains the string representation of each element in a LinkedList<T> instance, for example, "[elem1, elem2, elem3]".
Returns:
- String: string after conversion
class TreeMap<K, V> where K <: Comparable<K>
public class TreeMap<K, V> <: Map<K, V> where K <: Comparable<K> {
public init()
public init(elements: Collection<(K, V)>)
public init(elements: Array<(K,V)>)
public init(size: Int64, initElement: (Int64) -> (K, V))
}
Description: Specifies the class of Map interface implemented based on the balanced binary search tree.
This class provides an ordered key-value storage structure, which supports quickly inserting, deleting, and searching for elements.
TreeMap can be used in any scenario where ordered key-value pair storage is required, such as databases, caches, and lookup tables.
Parent Type:
- Map<K, V>
prop size
public prop size: Int64
Description: Returns the number of key-value pairs.
Type: Int64
init()
public init()
Description: Constructs an empty TreeMap instance.
init(Array<(K,V)>)
public init(elements: Array<(K,V)>)
Description: Constructs a TreeMap instance based on the passed key-value pair array.
Inserts elements into a TreeMap instance in the order of elements. Duplicate keys are not allowed in the TreeMap instance. If elements contain duplicate keys, the key-value pair that appears earlier is overwritten.
Parameters:
init(Collection<(K, V)>)
public init(elements: Collection<(K, V)>)
Description: Constructs a TreeMap instance based on the passed key-value pair collection.
Inserts elements into a TreeMap instance in the iterator order of elements. Duplicate keys are not allowed in the TreeMap instance. If elements contain duplicate keys, the key-value pair that appears earlier (determined based on the iterator order) is overwritten
Parameters:
- elements: Collection<(K, V)>: key-value pair collection used to initialize the TreeMap instance
init(Int64, (Int64) -> (K, V))
public init(size: Int64, initElement: (Int64) -> (K, V))
Description: Constructs a TreeMap instance based on the passed element quantity size and function rule.
Parameters:
- size: Int64: passed element quantity
- initElement: (Int64) ->(K, V): function rule used to initialize the TreeMap instance
Throws:
- IllegalArgumentException: If size is less than 0, this exception is thrown.
func clear()
public func clear(): Unit
Description: Clears all key-value pairs.
func clone()
public func clone(): TreeMap<K, V>
Description: Clones a TreeMap instance.
Returns:
func contains(K)
public func contains(key: K): Bool
Description: Checks whether the mapping of a specified key is included.
Parameters:
- key: K: key to be checked
Returns:
- Bool: If key is included, true is returned. Otherwise, false is returned.
func containsAll(Collection<K>)
public func containsAll(keys: Collection<K>): Bool
Description: Checks whether the mappings of keys of a specified collection are included.
Parameters:
- keys: Collection<K>: collection of keys
Returns:
- Bool: If the mappings are included, true is returned. Otherwise, false is returned.
func findLower(K, Bool)
public func findLower(bound: K, inclusive!: Bool = false): Option<TreeMapNode<K, V>>
Description: Returns the maximum element that is smaller than the value of the passed key.
Parameters:
- bound: K: passed key
- inclusive!: Bool: whether to contain the passed key itself; default value: false (no)
Returns:
- Option < TreeMapNode < K, V >>: The element (if there is) is returned after encapsulated with Option<TreeMapNode<K, V>>. Otherwise, Option<TreeMapNode<K, V>>.None is returned.
func findUpper(K, Bool)
public func findUpper(bound: K, inclusive!: Bool = false): Option<TreeMapNode<K, V>>
Description: Returns the minimum element that is greater than the value of the passed key.
Parameters:
- bound: K: passed key
- inclusive!: Bool: whether to contain the passed key itself; default value: false (no)
Returns:
- Option < TreeMapNode < K, V >>: The element (if there is) is returned after encapsulated with Option<TreeMapNode<K, V>>. Otherwise, Option<TreeMapNode<K, V>>.None is returned.
func firstEntry()
public func firstEntry(): Option<(K, V)>
Description: Obtains the first element of a TreeMap instance.
Returns:
- Option <(K, V): The element (if there is) is returned after encapsulated with Option. Otherwise, Option<(K, V)>.None is returned.
func get(K)
public func get(key: K): Option<V>
Description: Returns the value of a specified key mapping.
Parameters:
- key: K: specified key
Returns:
- Option<V>: The value (if there is) is returned after encapsulated with Option. Otherwise, Option<V>.None is returned.
func isEmpty()
public func isEmpty(): Bool
Description: Check whether a TreeMap instance is empty.
Returns:
- Bool: If the instance is empty, true is returned. Otherwise, false is returned.
func iterator()
public func iterator(): Iterator<(K, V)>
Description: Returns the iterator of a TreeMap instance. The iterator iterates in ascending order of Key values.
Returns:
func keys()
public func keys(): EquatableCollection<K>
Description: Returns all keys in a TreeMap instance and stores them in a container.
Returns:
- EquatableCollection<K>: collection containing all keys
func lastEntry()
public func lastEntry(): Option<(K, V)>
Description: Obtains the last element of a TreeMap instance.
Returns:
- Option <(K, V): The element (if there is) is returned after encapsulated with Option. Otherwise, Option<(K, V)>.None is returned.
func popFirstEntry()
public func popFirstEntry(): Option<(K, V)>
Description: Deletes the first element of a TreeMap instance.
Returns:
- Option <(K, V): The element (if there is) is deleted and returned after encapsulated with Option. Otherwise, Option<(K, V)>.None is returned.
func popLastEntry()
public func popLastEntry(): Option<(K, V)>
Description: Deletes the last element of a TreeMap instance.
Returns:
- Option <(K, V): The element (if there is) is deleted and returned after encapsulated with Option. Otherwise, Option<(K, V)>.None is returned.
func put(K, V)
public func put(key: K, value: V): Option<V>
Description: Puts a new key-value pair into a TreeMap instance. For an existing key in the TreeMap instance that is the same as the new key to be passed, the value of the key is replaced with the new value.
Parameters:
- key: K: key to be put
- value: V: value to be allocated
Returns:
- Option<V>: If key exists before value allocation, the old value corresponding to key is returned after encapsulated with Option. Otherwise, Option<V>.None is returned.
func putAll(Collection<K, V>)
public func putAll(elements: Collection<(K, V)>): Unit
Description: Puts a new key-value pair collection into a TreeMap instance. For an existing key in the TreeMap instance that is the same as the new key to be passed, the value of the key is replaced with the new value.
Parameters:
- elements: Collection<(K, V)>: key-value pair collection to be added to the TreeMap instance
func remove(K)
public func remove(key: K): Option<V>
Description: Deletes the mapping (if any) of a specified key from a mapping.
Parameters:
- key: K: key to be deleted
Returns:
- Option<V>: The value of the removed mapping is encapsulated with Option. If the specified key does not exist in TreeMap, None is returned.
func removeAll(Collection<K>)
public func removeAll(keys: Collection<K>): Unit
Description: Deletes the mapping (if any) of a specified collection from a mapping.
Parameters:
- keys: Collection<K>: collection of keys to be deleted
func removeIf((K, V) -> Bool)
public func removeIf(predicate: (K, V) -> Bool): Unit
Description: Passes a lambda expression. If the conditions are met, the corresponding key-value pair is deleted.
Parameters:
- predicate: (K, V) ->Bool: lambda expression used for judgment
func values()
public func values(): Collection<V>
Description: Returns all values in a TreeMap instance and stores them in a container.
Returns:
- Collection<V>: collection containing all values
operator func [](K, V)
public operator func [](key: K, value!: V): Unit
Description: Overrides the indexing operator. If key exists, the new value overwrites the old value. If key does not exist, the key-value pair is added.
Parameters:
- key: K: key used for judgment
- value!: V: value to be set
operator func [](K)
public operator func [](key: K): V
Description: Overrides the indexing operator. If key exists, the value corresponding to key is returned.
Parameters:
- key: K: key used for judgment
Returns:
- V: value corresponding to the key
Throws:
- NoneValueException: If key does not exist in the HashMap instance, this exception is thrown.
extend<K, V> TreeMap<K, V> <: Equatable<TreeMap<K, V>> where V <: Equatable<V>
extend<K, V> TreeMap<K, V> <: Equatable<TreeMap<K, V>> where V <: Equatable<V>
Description: Extends the Equatable<TreeMap<K, V>> interface for the TreeMap<K, V> type to support the equality check operation.
Parent Type:
operator func ==(TreeMap<K, V>)
public operator func ==(right: TreeMap<K, V>): Bool
Description: Checks whether the current instance is equal to the TreeMap<K, V> instance specified by the right parameter.
Two TreeMap<K, V> instances being equal means that key-value pairs included the two instances are completely equal.
Parameters:
- right: TreeMap<K, V>: objects to be compared
Returns:
- Bool: If the two instances are equal, true is returned. Otherwise, false is returned.
operator func !=(TreeMap<K, V>)
public operator func !=(right: TreeMap<K, V>): Bool
Description: Checks whether the current instance is not equal to the TreeMap<K, V> instance specified by the right parameter.
Parameters:
- right: TreeMap<K, V>: objects to be compared
Returns:
- Bool: If the two instances are not equal, true is returned. Otherwise, false is returned.
extend<K, V> TreeMap<K, V> <: ToString where V <: ToString, K <: ToString & Comparable<K>
extend<K, V> TreeMap<K, V> <: ToString where V <: ToString, K <: ToString & Comparable<K>
Description: Extends the ToString interface for TreeMap<K, V> to support string conversion.
Parent Type:
func toString()
public func toString(): String
Description: Converts the current TreeMap<K, V> instance to a string.
The string contains the string representation of each key-value pair in the TreeMap<K, V> instance, for example, "[(k1, v1), (k2, v2), (k3, v3)]".
Returns:
- String: string after conversion
Struct
struct EntryView<K, V> where K <: Hashable & Equatable<K>
public struct EntryView<K, V> where K <: Hashable & Equatable<K>
Description: Specifies the view of a Key in HashMap.
By modifying the view, you can quickly obtain or modify the value of Value corresponding to Key in HashMap. In the process of using the view, if some elements are modified, added, or deleted in a collection, the view becomes invalid and ConcurrentModificationException is thrown.
The instance of this struct can be obtained only by using the func entryView(K) method of the corresponding HashMap instance.
func getKey()
public func getKey(): K
Description: Obtains the key in a view. The time complexity is O(1).
Returns:
- K: key of the view
Throws:
- ConcurrentModificationException: In the process of using the view, if the corresponding HashMap instance is modified by other operations, this exception is thrown.
func getValue()
public func getValue(): ?V
Description: Obtains the value in a view. The time complexity is O(1).
If the view is empty, None is returned. Otherwise, the value of the key is returned.
Returns:
- ?V: value of the view
Throws:
- ConcurrentModificationException: In the process of using the view, if the corresponding HashMap instance is modified by other operations, this exception is thrown.
func isAbsent()
public func isAbsent(): Bool
Description: Checks whether a view is empty.
If the view is empty, the corresponding HashMap instance does not contain the (Key, Value) combination whose Key value is the same as the Key value of the view.
Returns:
- Bool: If the view is empty, true is returned. Otherwise, false is returned.
func setValue(V)
public mut func setValue(v: V): V
Description: Sets the value in a view. The time complexity is O(1).
If the view is empty, a specified key-value pair is inserted and the inserted value is returned. Otherwise, the value before the setting is returned.
Parameters:
- v: V: specified value
Returns:
- V: value of the view or newly inserted value
Throws:
- ConcurrentModificationException: In the process of using the view, if the corresponding HashMap instance is modified by other operations, this exception is thrown.
struct TreeMapNode<K, V> where K <: Comparable<K>
public struct TreeMapNode<K, V> where K <: Comparable<K>
Description: Specifies the node structure of TreeMap.
Note:
When a TreeMapNode instance is used to perform node operations, if an insertion or a deletion operation is performed on the corresponding TreeMap instance, the TreeMapNode instance becomes invalid. If the invalid TreeMapNode instance is operated, a ConcurrentModificationException exception is thrown.
prop key
public prop key: K
Description: Obtains the key of the current node.
Type: K
Throws:
- ConcurrentModificationException: If the TreeMapNode instance is invalid, this exception is thrown.
prop value
public mut prop value: V
Description: Obtains or sets the value of the current node.
Type: V
Throws:
- ConcurrentModificationException: If the TreeMapNode instance is invalid, this exception is thrown.
func backward(K, Bool)
public func backward(bound: K, inclusive!:Bool = true): Iterator<(K, V)>
Description: Generates a positive-order iterator from the current node to bound.
Parameters:
- bound: K: passed key
- inclusive!: Bool: whether to contain the passed key; default value: true (yes)
Returns:
- Iterator <(K, V) >: positive-order iterator from the current node to bound
Throws:
- ConcurrentModificationException: If the TreeMapNode instance is invalid, this exception is thrown.
func forward(K, Bool)
public func forward(bound: K, inclusive!:Bool = true): Iterator<(K, V)>
Description: Generates a reverse-order iterator from the current node to bound.
Parameters:
- bound: K: passed key
- inclusive!: Bool: whether to contain the passed key; default value: true (yes)
Returns:
- Iterator <(K, V) >: reverse-order iterator from the current node to bound
Throws:
- ConcurrentModificationException: If the TreeMapNode instance is invalid, this exception is thrown.
func next()
public func next(): Option<TreeMapNode<K, V>>
Description: Access the successor nodes.
Returns:
- Option < TreeMapNode < K, V >>: If there are successor nodes, they are returned after encapsulated with Option<TreeMapNode<K, V>>. Otherwise, Option<TreeMapNode<K, V>>.None is returned.
Throws:
- ConcurrentModificationException: If the TreeMapNode instance is invalid, this exception is thrown.
func prev()
public func prev(): Option<TreeMapNode<K, V>>
Description: Access the predecessor nodes.
Returns:
- Option < TreeMapNode < K, V >>: If there are predecessor nodes, they are returned after encapsulated with Option<TreeMapNode<K, V>>. Otherwise, Option<TreeMapNode<K, V>>.None is returned.
Throws:
- ConcurrentModificationException: If the TreeMapNode instance is invalid, this exception is thrown.
Exception
class ConcurrentModificationException
public class ConcurrentModificationException <: Exception {
public init()
public init(message: String)
}
Description: Specifies a concurrent modification exception class. Its instance is thrown if a function detects an asynchronous concurrent modification.
The container classes provided by the collection package do not support concurrent modification. Therefore, ConcurrentModificationException is thrown when some operations are performed.
Exceptions are thrown in the following typical scenarios:
- A container is modified during the process of traversing the container using for-in (except the remove() method of HashMapIterator).
- Content of the container where an instance of the type with short declaration period is located is modified, such as EntryView and TreeMapNode.
Parent Type:
init()
public init()
Description: Constructs an instance without exception information.
init(String)
public init(message: String)
Description: Construct an exception instance based on exception information.
Parameters:
- message: String: exception information
append and insert functions of ArrayList
Adding elements to ArrayList:
import std.collection.*
main() {
var list: ArrayList<Int64> = ArrayList<Int64>(10) //Creates an **ArrayList** instance with capacity of 10.
var arr: Array<Int64> = [1, 2, 3]
list.appendAll(arr) // list: [1, 2, 3]
list.set(1, 120) // list: [1, 120, 3]
var b = list.get(2)
print("b=${b.getOrThrow()},")
list.insert(1, 12) // list: [1, 12, 120, 3]
var c = list.get(2)
print("c=${c.getOrThrow()},")
var arr1: Array<Int64> = [1,2,3]
list.insertAll(1, arr1) // list: [1, 1, 2, 3, 12, 120, 3]
var d = list.get(2)
print("d=${d.getOrThrow()}")
return 0
}
Running result:
b=3,c=120,d=2
get and set functions of ArrayList
This case shows how to use the get method to obtain the value of an index in an ArrayList instance and how to use the set method to change the value.
Code:
import std.collection.*
main() {
var list = ArrayList<Int64>([97, 100]) // list: [97, 100]
list.set(1, 120) // list: [97, 120]
var b = list.get(1)
print("b=${b.getOrThrow()}")
return 0
}
Running result:
b=120
remove, clear, and slice functions of ArrayList
This case shows how to use the remove, clear, and slice functions of ArrayList.
Code:
import std.collection.*
main() {
var list: ArrayList<Int64> = ArrayList<Int64>(97, 100, 99) // Function call syntactic sugar of variable-length
list.remove(1) // list: [97, 99]
var b = list.get(1)
print("b=${b.getOrThrow()},")
list.clear()
list.append(11) // list: [97, 99, 11]
var arr: Array<Int64> = [1, 2, 3]
list.insertAll(0, arr) // list: [1, 2, 3, 97, 99]
var g = list.get(0)
print("g=${g.getOrThrow()},")
let r: Range<Int64> = 1..=2 : 1
var sublist: ArrayList<Int64> = list.slice(r) // sublist: [2, 3]
var m = sublist.get(0)
print("m=${m.getOrThrow()}")
return 0
}
Running result:
b=99,g=1,m=2
get, put, and contains functions of HashMap
This use case shows the basic usage of HashMap.
Code:
import std.collection.*
main() {
var map: HashMap<String, Int64> = HashMap<String, Int64>()
map.put("a", 99) // map : [("a", 99)]
map.put("b", 100) // map : [("a", 99), ("b", 100)]
var a = map.get("a")
var bool = map.contains("a")
print("a=${a.getOrThrow()} ")
print("bool=${bool.toString()}")
return 0
}
Running result:
a=99 bool=true
putAll, remove, and clear functions of HashMap
This use case shows the basic usage of HashMap.
Code:
import std.collection.*
main() {
var map: HashMap<String, Int64> = HashMap<String, Int64>()
var arr: Array<(String, Int64)> = [("d", 11), ("e", 12)]
map.putAll(arr) // map : [("d", 11), ("e", 12)]
var d = map.get("d")
print("d=${d.getOrThrow()} ")
map.remove("d") // map : [("e", 12)]
var bool = map.contains("d")
print("bool=${bool.toString()} ")
map.clear() // map: []
var bool1 = map.contains("e")
print("bool1=${bool1.toString()}")
return 0
}
Running result:
d=11 bool=false bool1=false
put, iterator, and remove functions of HashSet
This use case shows the basic usage of HashSet.
Code:
import std.collection.*
/*Test*/
main() {
var set: HashSet<String> = HashSet<String>() // set: []
set.put("apple") // set: ["apple"]
set.put("banana") // set: ["apple", "banana"], not in order
set.put("orange") // set: ["apple", "banana", "orange"], not in order
set.put("peach") // set: ["apple", "banana", "orange", "peach"], not in order
var itset = set.iterator()
while(true) {
var value = itset.next()
match(value) {
case Some(v) =>
if (!set.contains(v)) {
print("Operation failed")
return 1
} else { println(v) }
case None => break
}
}
set.remove("apple") // set: ["banana", "orange", "peach"], not in order
println(set)
return 0
}
The order in Set is not fixed. Therefore, the running result may be as follows:
apple
banana
orange
peach
[banana, orange, peach]
Iterator Operation Function
This case shows how to use the iterator operation function together with the pipeline expression.
Code:
import std.collection.*
main() {
let arr = [-1, 2, 3, 4, 5, 6, 7, 8, 9]
arr |> filter{a: Int64 => a > 0} |> // filter -1
step<Int64>(2) |> // [2, 4, 6, 8]
skip<Int64>(2) |> // [6, 8]
forEach<Int64>(println)
let str = arr |> filter{a: Int64 => a % 2 == 1} |> collectString<Int64>(delimiter: ">")
println(str)
println(arr |> contains(6_i64))
return 0
}
Running result:
6
8
3>5>7>9
true
std.collection.concurrent Package
Function Description
The collection.concurrent package provides concurrency-safe collection types.
This package implements the following concurrency-safe collection types:
-
ArrayBlockingQueue: bounded queue of a fixed size, which is implemented in the form of arrays
-
BlockingQueue: thread-safe queue, which supports blocking element obtaining when the queue is empty and blocking element addition when the queue is full
-
ConcurrentHashMap: thread-safe hash table implementation, which supports high-concurrency read and write operations
-
NonBlockingQueue: thread-safe queue data structure (When an element is added, if the number of elements in the tail block reaches the maximum, a new block is created. In this way, the element addition is not blocked. Therefore, in a multi-thread environment, thread blocking caused by blocked operations on the queue can be prevented, thereby improving program performance.)
API List
Interface
| Name | Description |
|---|---|
| ConcurrentMap<K, V> where K <: Equatable<K> | Guarantees thread security and operation atomicity. |
Class
| Name | Description |
|---|---|
| ArrayBlockingQueue<E> | Implements the BlockingQueue data structure and related operation functions based on arrays. |
| BlockingQueue<E> | Implements a concurrent queue with a blocking mechanism, which allows users to specify the upper limit of capacity. |
| ConcurrentHashMapIterator<K, V> where K <: Hashable & Equatable<K> | Implements the iterator functions of ConcurrentHashMap. |
| ConcurrentHashMap<K, V> where K <: Hashable & Equatable<K> | Implements the thread-safe ConcurrentHashMap hash table data structure and related operation functions in concurrency scenarios. |
| NonBlockingQueue<E> | Provides thread-safe queues supporting safe addition and deletion of elements in a multi-thread environment. |
Interface
interface ConcurrentMap<K, V> where K <: Equatable<K>
public interface ConcurrentMap<K, V> where K <: Equatable<K> {
func get(key: K): Option<V>
func contains(key: K): Bool
mut func put(key: K, value: V): Option<V>
mut func putIfAbsent(key: K, value: V): Option<V>
mut func remove(key: K): Option<V>
mut func remove(key: K, predicate: (V) -> Bool): Option<V>
mut func replace(key: K, value: V): Option<V>
mut func replace(key: K, eval: (V) -> V): Option<V>
mut func replace(key: K, predicate: (V) -> Bool, eval: (V) -> V): Option<V>
}
Description: Specifies a definition of the Map interface that ensures thread security and operation atomicity.
The ConcurrentMap interface declares thread-safe methods of Map in concurrency scenarios, and the methods ensures atomicity. All defined thread-safe classes of Map should implement the ConcurrentMap interface. For example, ConcurrentHashMap defined in the package implements the ConcurrentMap interface and implements the methods declared in ConcurrentMap. These methods ensure atomicity.
The ConcurrentMap interface declares methods of concurrent Map that needs to ensure atomicity in concurrency scenarios.
The concurrent Map is mappings from keys to values, where **K **is a key, and V is a value.
func contains(K)
func contains(key: K): Bool
Description: Checks whether a Map instance contains the association of the specified key.
Parameters:
- key: K: key to be checked
Returns:
- Bool: If key exists, true is returned. If key does not exist, false is returned.
func get(K)
func get(key: K): Option<V>
Description: Returns the value associated with key in a Map instance.
Parameters:
- key: K: key used to obtain a value
Returns:
- Option<V>: If key exists, the associated value Some(V) of key is returned. If key does not exist, None is returned.
func put(K, V)
mut func put(key: K, value: V): Option<V>
Description: Associates the specified value with the key specified in a Map instance. If the Map instance already contains the association of key, the old value is replaced. If the Map instance does not contain the association of key, the association between key and value is added.
Parameters:
- key: K: key to be put
- value: V: value to be associated
Returns:
- Option<V>: If key exists before value assignment, the old value Some(V) is returned. If key does not exist before value assignment, None is returned.
func putIfAbsent(K, V)
mut func putIfAbsent(key: K, value: V): Option<V>
Description: Adds the association between the specified value and the specified key to a Map instance if the Map instance does not contain key. Does not perform value assignment if the Map instance contain key.
Parameters:
- key: K: key to be put
- value: V: value to be allocated
Returns:
- Option<V>: If key exists before value assignment, the value Some(V) corresponding to the current key is returned and no value is assigned. If key does not exist before value assignment, None is returned.
func remove(K)
mut func remove(key: K): Option<V>
Description: Deletes the mapping (if any) of the specified key from a mapping.
Parameters:
- key: K: key to be deleted
Returns:
- Option<V>: If key exists before deletion, the value Some(V) corresponding to key is returned. If key does not exist before deletion, None is returned.
func remove(K, (V) -> Bool)
mut func remove(key: K, predicate: (V) -> Bool): Option<V>
Description: Deletes the association of key from a Map instance if the Map instance contains key and the value v associated with key meets the condition of predicate.
Parameters:
- key: K: key to be deleted
- predicate: (V) ->Bool: lambda expression used for judgment
Returns:
- Option<V>: If the Map instance contains key, the old value Some(V) corresponding to key is returned. If the Map instance does not contain key or the value associated with key does not meet the condition of predicate, None is returned.
func replace(K, (V) -> Bool, (V) -> V)
mut func replace(key: K, predicate: (V) -> Bool, eval: (V) -> V): Option<V>
Description: Replaces the value associated with key in a Map instance with the calculation result of eval(v) if the Map instance contains key (assuming that the associated value of key is v) and v meets the condition of predicate. Does not modify the Map instance if the Map instance does not contain key or key exists but the associated value of key does not meet the condition of predicate.
Parameters:
- key: K: key of the associated value to be replaced
- predicate: (V) ->Bool: lambda expression used for judgment
- eval: (V) ->V: function used to determine whether to replace with a new value
Returns:
- Option<V>: If key exists, the old value Some(V) corresponding to key is returned. If key does not exist or the value associated with key does not meet the condition of predicate, None is returned.
func replace(K, (V) -> V)
mut func replace(key: K, eval: (V) -> V): Option<V>
Description: Replaces the value associated with key in a Map instance with the calculation result of eval(v) if the Map instance contains key (assuming that the associated value of key is v). Does not modify the Map instance if the Map instance does not contain key.
Parameters:
- key: K: key of the associated value to be replaced
- eval: (V) ->V: function used to determine whether to replace with a new value
Returns:
- Option<V>: If key exists, the old value Some(V) corresponding to key is returned. If key does not exist, None is returned.
func replace(K, V)
mut func replace(key: K, value: V): Option<V>
Description: Replaces the value associated with key in a Map instance with value if the Map instance contains key. Does not modify the Map instance if the Map instance does not contain key.
Parameters:
- key: K: key of the associated value to be replaced
- value: V: new value used for replacement
Returns:
- Option<V>: If key exists, the old value Some(V) corresponding to key is returned. If key does not exist, None is returned.
Class
class ArrayBlockingQueue<E>
public class ArrayBlockingQueue<E> {
public init(capacity: Int64)
public init(capacity: Int64, elements: Collection<E>)
}
Description: Implements the Blocking Queue data structure and related operation functions based on arrays.
ArrayBlockingQueue is a concurrent queue with the blocking mechanism and requires users to specify the upper limit of capacity.
prop size
public prop size: Int64
Description: Returns the number of elements of an ArrayBlockingQueue instance.
Note:
This method does not ensure atomicity in concurrency scenarios. This method should be called when no other thread concurrently modifies the ArrayBlockingQueue instance in the environment.
Type: Int64
capacity
public let capacity: Int64
Description: Obtains the capacity of an ArrayBlockingQueue instance.
Type: Int64
init(Int64)
public init(capacity: Int64)
Description: Constructs an ArrayBlockingQueue instance with capacity specified by capacity.
Parameters:
- capacity: Int64: initial capacity
Throws:
- IllegalArgumentException: If capacity is less than or equal to 0, this exception is thrown.
init(Int64, Collection<E>)
public init(capacity: Int64, elements: Collection<E>)
Description: Constructs an ArrayBlockingQueue instance with capacity specified by capacity and a collection passed.
Parameters:
- capacity: Int64: initial capacity
- elements: Collection<E>: collection of initialization elements
Throws:
- IllegalArgumentException: If capacity is less than or equal to 0 or less than the size of elements, this exception is thrown.
func dequeue()
public func dequeue(): E
Description: Specifies a blocked dequeue operation, that is, obtains the first element of a queue and delete it.
Returns:
- E: first element of the queue
func dequeue(Duration)
public func dequeue(timeout: Duration): Option<E>
Description: Specifies a blocked dequeue operation that, specifically, obtains the first element (if there is) of a queue and deletes it or waits for the time specified by timeout if the queue is empty. If timeout is negative, the dequeue operation is performed immediately and the operation result is returned.
Parameters:
- timeout: Duration: waiting time
Returns:
- Option<E>: first element of the queue. If the first element of the queue is not obtained within the waiting time, None is returned.
func enqueue(E)
public func enqueue(element: E): Unit
Description: Specifies the blocked enqueue operation, that is, adds an element to the end of a queue.
Parameters:
- element: E: element to be added
func enqueue(E, Duration)
public func enqueue(element: E, timeout: Duration): Bool
Description: Specifies a blocked enqueue operation that, specifically, adds an element to the end of a queue or waits for the time specified by timeout if the queue is full. If timeout is negative, the enqueue operation is performed immediately and the operation result is returned.
Parameters:
- element: E: element to be added
- timeout: Duration: waiting time
Returns:
- Bool: If the element is successfully added, true is returned. If the element is not successfully added within the waiting time, false is returned.
func head()
public func head(): Option<E>
Description: Obtains the first element of a queue.
Note:
This function is non-blocked.
Returns:
- Option<E>: first element of the queue. If the queue is empty, None is returned.
func tryDequeue()
public func tryDequeue(): Option<E>
Description: Specifies a non-blocked dequeue operation, that is, obtains the first element of a queue and delete it.
Returns:
- Option<E>: first element of the queue. If the queue is empty, None is returned.
func tryEnqueue(E)
public func tryEnqueue(element: E): Bool
Description: Specifies a non-blocked enqueue operation, that is, adds an element to the end of a queue.
Parameters:
- element: E: element to be added
Returns:
- Bool: If the element is successfully added, true is returned. If the queue is full, false is returned.
class BlockingQueue<E>
public class BlockingQueue<E> {
public init()
public init(capacity: Int64)
public init(capacity: Int64, elements: Array<E>)
public init(capacity: Int64, elements: Collection<E>)
}
Description: Implements a concurrent queue with a blocking mechanism, which supports users to specify the upper limit of capacity.
A feature of a blocked queue is that when the queue is full, a thread that attempts to add an element to the queue is blocked until there is a vacant position in the queue; and when the queue is empty, a thread that attempts to obtain an element from the queue is blocked until there is an available element in the queue.
let capacity
public let capacity: Int64
Description: Returns the capacity of a BlockingQueue instance.
Type: Int64
prop size
public prop size: Int64
Description: Returns the number of elements of a BlockingQueue instance.
Note:
This method does not ensure atomicity in concurrency scenarios. This method should be called when no other thread concurrently modifies the BlockingQueue instance in the environment.
Type: Int64
init()
public init()
Description: Constructs a BlockingQueue instance with the default initial capacity of (Int64.Max).
init(Int64)
public init(capacity: Int64)
Description: Constructs a BlockingQueue instance with capacity specified by capacity.
Parameters:
- capacity: Int64: initial capacity
Throws:
- IllegalArgumentException: If capacity is less than or equal to 0, this exception is thrown.
init(Int64, Array<E>)
public init(capacity: Int64, elements: Array<E>)
Description: Constructs a BlockingQueue instance with capacity specified by capacity and an array of elements passed.
Parameters:
Throws:
- IllegalArgumentException: If capacity is less than or equal to 0 or less than the size of elements, this exception is thrown.
init(Int64, Collection<E>)
public init(capacity: Int64, elements: Collection<E>)
Description: Constructs a BlockingQueue instance with capacity specified by capacity and a collection passed.
Parameters:
- capacity: Int64: initial capacity
- elements: Collection<E>: collection of initialization elements
Throws:
- IllegalArgumentException: If capacity is less than or equal to 0 or less than the size of elements, this exception is thrown.
func dequeue()
public func dequeue(): E
Description: Specifies a blocked dequeue operation, that is, obtains the first element of a queue and delete it.
Returns:
- E: first element of the queue
func dequeue(Duration)
public func dequeue(timeout: Duration): Option<E>
Description: Specifies a blocked dequeue operation that, specifically, obtains the first element (if there is) of a queue and deletes it or waits for the time specified by timeout if the queue is empty. If timeout is negative, the dequeue operation is performed immediately and the operation result is returned.
Parameters:
- timeout: Duration: waiting time
Returns:
- Option<E>: first element of the queue. If the first element of the queue is not obtained within the waiting time, None is returned.
func enqueue(E)
public func enqueue(element: E): Unit
Description: Specifies a blocked enqueue operation that, specifically, adds an element to the end of a queue.
Parameters:
- element: E: element to be added
func enqueue(E, Dureation)
public func enqueue(element: E, timeout: Duration): Bool
Description: Specifies a blocked enqueue operation that, specifically, adds an element to the end of a queue or waits for the time specified by timeout if the queue is full. If timeout is negative, the enqueue operation is performed immediately and the operation result is returned.
Parameters:
- element: E: element to be added
- timeout: Duration: waiting time
Returns:
- Bool: If the element is successfully added, true is returned. If the element is not successfully added within the waiting time, false is returned.
func head()
public func head(): Option<E>
Description: Obtains the first element of a queue.
Note:
This function is non-blocked.
Returns:
- Option<E>: first element of the queue. If the queue is empty, None is returned.
func tryDequeue()
public func tryDequeue(): Option<E>
Description: Specifies a non-blocked dequeue operation, that is, obtains the first element of a queue and delete it.
Returns:
- Option<E>: first element of the queue. If the queue is empty, None is returned.
func tryEnqueue(E)
public func tryEnqueue(element: E): Bool
Description: Specifies a non-blocked enqueue operation, that is, adds an element to the end of a queue.
Parameters:
- element: E: element to be added
Returns:
- Bool: If the element is successfully added, true is returned. If the queue is full, false is returned.
class ConcurrentHashMapIterator<K, V> where K <: Hashable & Equatable<K>
public class ConcurrentHashMapIterator<K, V> <: Iterator<(K, V)> where K <: Hashable & Equatable<K> {
public init(cmap: ConcurrentHashMap<K, V>)
}
Description: Implements the iterator function of ConcurrentHashMap.
Note:
The ConcurrentHashMap iterator is defined as follows:
- The iteration result may not be a snapshot of the concurrent HashMap at a certain time point. You are advised to call this interface when ConcurrentHashMap is not being modified by another thread in the environment.
- During iteration, the iterator may not be aware of the modification of the target ConcurrentHashMap by an environment thread.
Parent Type:
- Iterator<(K, V)>
init(ConcurrentHashMap<K, V>)
public init(cmap: ConcurrentHashMap<K, V>)
Description: Creates a ConcurrentHashMapIterator<K, V> instance.
Parameters:
- cmap: ConcurrentHashMap<K, V>: ConcurrentHashMap<K, V> instance whose iterator is to be obtained
func iterator()
public func iterator(): Iterator<(K, V)>
Description: Obtains the ConcurrentHashMap<K, V> iterator itself.
Returns:
- Iterator <(K, V) >: iterator itself
func next()
public func next(): Option<(K, V)>
Description: Returns the next element in an iterator.
Returns:
class ConcurrentHashMap<K, V> where K <: Hashable & Equatable<K>
public class ConcurrentHashMap<K, V> <: ConcurrentMap<K, V> & Collection<(K, V)> where K <: Hashable & Equatable<K> {
public init(concurrencyLevel!: Int64 = 16)
public init(capacity: Int64, concurrencyLevel!: Int64 = 16)
public init(elements: Collection<(K, V)>, concurrencyLevel!: Int64 = 16)
public init(size: Int64, initElement: (Int64) -> (K, V), concurrencyLevel!: Int64 = 16)
}
Description: Implements the thread-safe hash table data structure and related operation functions in concurrent scenarios.
If the number of key-value pairs in a ConcurrentHashMap instance is greater than the number of buckets, capacity is expanded.
The concurrencyLevel parameter in the constructor indicates the concurrency level, that is, the maximum number of threads that are allowed to concurrently modify a ConcurrentHashMap instance. The operation of querying key-value pairs is non-blocked and is not restricted by the specified concurrencyLevel. The default value of concurrencyLevel is 16. It affects only the performance of ConcurrentHashMap in concurrent scenarios and does not affect functions.
Note:
If the value of concurrencyLevel is less than 16, the concurrency level is set to 16.
The larger concurrencyLevel is not the better. A larger concurrencyLevel results in higher memory overhead (or even out of memory exceptions). You need to balance the memory overhead and running efficiency.
Parent Type:
- ConcurrentMap<K, V>
- Collection<(K, V)>
Example:
For details, see [ConcurrentHashMap Usage Example] (../collection_concurrent_samples/sample_concurrenthashmap.md).
prop size
public prop size: Int64
Description: Returns the number of key-value pairs.
Note:
This method does not ensure atomicity in concurrency scenarios. This method should be called when no other thread concurrently modifies the ConcurrentHashMap instance in the environment.
Type: Int64
init(Collection<(K, V)>, Int64)
public init(elements: Collection<(K, V)>, concurrencyLevel!: Int64 = 16)
Description: Constructs a ConcurrentHashMap instance with a passed iterator and a specified concurrency level. This constructor sets the capacity of the ConcurrentHashMap instance according to the size of elements.
Parameters:
- elements: Collection<(K, V)>: collection of initialization elements
- concurrencyLevel!: Int64: specified concurrency level
init(Int64)
public init(concurrencyLevel!: Int64 = 16)
Description: Constructs a ConcurrentHashMap instance with the capacity of 16 and a specified concurrency level (16 by default).
Parameters:
- concurrencyLevel!: Int64: specified concurrency level
init(Int64, (Int64) -> (K, V), Int64)
public init(size: Int64, initElement: (Int64) -> (K, V), concurrencyLevel!: Int64 = 16)
Description: Constructs a ConcurrentHashMap instance with a passed capacity, initialization function elements, and a specified concurrency level. This constructor sets the capacity of the ConcurrentHashMap instance according to the size parameter.
Parameters:
- size: Int64: initial element capacity
- initElement: (Int64) ->(K, V) initialization function elements
- concurrencyLevel!: Int64: specified concurrency level
Throws:
- IllegalArgumentException: If size is less than 0, this exception is thrown.
init(Int64, Int64)
public init(capacity: Int64, concurrencyLevel!: Int64 = 16)
Description: Constructs a ConcurrentHashMap instance with a passed capacity and a specified concurrency level (16 by default).
Parameters:
Throws:
- IllegalArgumentException: If capacity is less than 0, this exception is thrown.
func contains(K)
public func contains(key: K): Bool
Description: Checks whether a mapping contains the mapping of the specified key.
Parameters:
- key: K: key to be checked
Returns:
- Bool: whether the mapping of the specified key is contained. true is returned if the mapping of the specified key is contained, and false is returned if the mapping of the specified key is not contained.
func get(K)
public func get(key: K): ?V
Description: Returns the value associated with key in a mapping.
Parameters:
- key: K: key used to obtain a value
Returns:
- Option<V>: value associated with key in the mapping
func isEmpty()
public func isEmpty(): Bool
Description: Checks whether ConcurrentHashMap is empty.
Note:
This method does not ensure atomicity in concurrency scenarios. This method should be called when no other thread concurrently modifies the ConcurrentHashMap instance in the environment.
Returns:
- Bool: If the instance is empty,
trueis returned. Otherwise,falseis returned.
func iterator()
public func iterator(): ConcurrentHashMapIterator<K, V>
Description: Obtains the iterator of a ConcurrentHashMap instance.
Returns:
- ConcurrentHashMapIterator < K, V >: iterator of ConcurrentHashMap
func put(K, V)
public func put(key: K, value: V): ?V
Description: Associates a specified value with the specified key in ConcurrentHashMap. If ConcurrentHashMap contains an association with the key, the existing value is replaced. If ConcurrentHashMap does not contain an association with the key, the association between the key and the value is added.
Parameters:
- key: K: key to be put
- value: V: value to be associated
Returns:
- Option<V>: If key exists before value assignment, the old value Some(V) is returned. If key does not exist before value assignment, None is returned.
func putIfAbsent(K, V)
public func putIfAbsent(key: K, value: V): ?V
Description: Adds an association between a specified value and a specified key to ConcurrentHashMap if the key does not exist in ConcurrentHashMap. If ConcurrentHashMap already contains the key, value assignment is not performed.
Parameters:
- key: K: key to be put
- value: V: value to be allocated
Returns:
- Option<V>: If key exists before value assignment, the value Some(V) corresponding to the current key is returned and no value is assigned. If key does not exist before value assignment, None is returned.
func remove((K, (V) -> Bool))
public func remove(key: K, predicate: (V) -> Bool): ?V
Description: If key exists in the mapping and the value v mapped to key meets the condition of predicate, the mapping of key is deleted.
Parameters:
- key: K: key to be deleted
- predicate: (V) ->Bool: lambda expression used for judgment
Returns:
- Option<V>: If key exists in the mapping, the old value corresponding to key is returned. If key does not exists in the mapping or the value associated with key does not meet the condition of predicate, None is returned.
func remove(K)
public func remove(key: K): ?V
Description: Deletes the mapping (if any) of the specified key from a mapping.
Parameters:
- key: K: key to be deleted
Returns:
- Option<V>: If key exists before deletion, the value Some(V) corresponding to key is returned. If key does not exist before deletion, None is returned.
func replace(K, (V) -> Bool, (V) -> V)
public func replace(key: K, predicate: (V) -> Bool, eval: (V) -> V): ?V
Description: Replaces the value associated with a key in ConcurrentHashMap with the calculation result of eval(v) if the key exists in ConcurrentHashMap (assuming that the key is associated with a value v) and v meets the condition of predicate. If the key does not exist in ConcurrentHashMap, or the key exists but the value associated with the key does not meet the condition of predicate, ConcurrentHashMap is not modified. Parameters:
- key: K: key of the associated value to be replaced
- predicate: (V) ->Bool: lambda expression used for judgment
- eval: (V) ->V: function used to determine whether to replace with a new value
Returns:
- Option<V>: If key exists, the old value Some(V) corresponding to key is returned. If key does not exist or the value associated with key does not meet the condition of predicate, None is returned.
func replace(K, (V) -> V)
public func replace(key: K, eval: (V) -> V): ?V
Description: Replaces the value associated with a key in ConcurrentHashMap with the calculation result of eval(v) if the key exists in ConcurrentHashMap (assuming that the key is associated with a value v). If the key does not exist in ConcurrentHashMap, ConcurrentHashMap is not modified.
Parameters:
- key: K: key of the associated value to be replaced
- eval: (V) ->V: function used to determine whether to replace with a new value
Returns:
- Option<V>: If key exists, the old value Some(V) corresponding to key is returned. If key does not exist, None is returned.
func replace(K, V)
public func replace(key: K, value: V): ?V
Description: Replaces the value associated with a key in ConcurrentHashMap with value if the key exists in ConcurrentHashMap. If the key does not exist in ConcurrentHashMap, ConcurrentHashMap is not modified.
Parameters:
- key: K: key of the associated value to be replaced
- value: V: new value used for replacement
Returns:
- Option<V>: If key exists, the old value Some(V) corresponding to key is returned. If key does not exist, None is returned.
operator func [](K)
public operator func [](key: K): V
Purpose: Overrides the indexing operator. If key exists, the value corresponding to key is returned. If key does not exist, an exception is thrown.
Parameters:
- key: K: key used for judgment
Returns:
- V: value corresponding to the key
Throws:
- NoneValueException: If key does not exist in associations, this exception is thrown.
operator func [](K, V)
public operator func [](key: K, value!: V): Unit
Description: Overrides the indexing operator. If key exists, the new value overwrites the old value. If key does not exist, the key-value pair is added.
Parameters:
- key: K: key used for judgment
- value!: V: value to be set
class NonBlockingQueue<E>
public class NonBlockingQueue<E> {
public init()
public init(elements: Collection<E>)
}
Description: Provides thread-safe queues to safely add and delete elements in a multi-thread environment.
A purpose of the non-blocked queue is to resolve a synchronization problem in a multi-thread environment, so that a plurality of threads can concurrently perform queue operations, and no data conflict or deadlock problem occurs.
Non-blocked queues are common in multi-thread programming. They can be used in any scenario where thread-safe queues are required, such as the producer-consumer model, task scheduling, and thread pool.
Example:
For details, see [NonBlockingQueue Usage Example] (../collection_concurrent_samples/sample_noblocking_queue.md).
prop size
public prop size: Int64
Description: Obtains the number of elements of a NonBlockingQueue instance.
Note:
This method does not ensure atomicity in concurrency scenarios. This method should be called when no other thread concurrently modifies the NonBlockingQueue instance in the environment.
Type: Int64
init()
public init()
Description: Constructs a default NonBlockingQueue instance.
init(Collection<E>)
public init(elements: Collection<E>)
Description: Constructs a NonBlockingQueue instance based on a Collection<E> instance.
Parameters:
- elements: Collection<E>: elements in the container to be put into the newly constructed NonBlockingQueue instance
func dequeue()
public func dequeue(): Option<E>
Description: Obtains and deletes the first element of a queue.
Returns:
- Option<E>: If the element is deleted successfully, the element is returned. If the queue is empty, None is returned.
func enqueue(E)
public func enqueue(element: E): Bool
Description: Specifies a non-blocked enqueue operation, that is, adds an element to the end of a queue.
Note:
This function does not return false.
Parameters:
- element: E: element to be added
Returns:
- Bool: If the element is successfully added, true is returned.
func head()
public func head(): Option<E>
Description: Obtains the first element of a queue but not delete it.
Returns:
- Option<E>: If the element is obtained successfully, the element is returned. If the queue is empty, None is returned.
ConcurrentHashMap Usage Example
import std.collection.*
import std.collection.concurrent.*
import std.sync.*
main() {
let threads = 8
let M = 1024
let cmap = ConcurrentHashMap<Int64, Int64>(concurrencyLevel: 64)
let jobs = Array<Future<Unit>>(threads, item: unsafe { zeroValue<Future<Unit>>() })
for (t in 0..threads) {
jobs[t] = spawn {
for (i in t..M : threads) {
cmap.put(i, i + 3)
}
}
}
for (t in 0..threads) {
jobs[t].get()
}
println("Size after put: ${cmap.size}")
for (t in 0..threads) {
jobs[t] = spawn {
for (i in t..M : threads) {
cmap.remove(i, {v => v % 2 == 0})
}
}
}
for (t in 0..threads) {
jobs[t].get()
}
println("Size after remove first: ${cmap.size}")
for (t in 0..threads) {
jobs[t] = spawn {
for (i in t..M : threads) {
cmap.remove(i)
}
}
}
for (t in 0..threads) {
jobs[t].get()
}
println("Size after remove second: ${cmap.size}")
}
The result is as follows:
Size after put: 1024
Size after remove first: 512
Size after remove second: 0
NonBlockingQueue Usage Example
import std.collection.*
import std.collection.concurrent.*
import std.sync.*
main() {
let threads = 8
let total: Int64 = 128
let bq = NonBlockingQueue<Int64>(Array<Int64>(total, {i => i}))
println("Total ${bq.size} after init")
let jobs = Array<Future<Unit>>(threads, item: unsafe { zeroValue<Future<Unit>>() })
for (t in 0..threads) {
jobs[t] = spawn {
for (i in t..total : threads) {
bq.dequeue()
}
}
}
for (t in 0..threads) {
jobs[t].get()
}
println("Total ${bq.size} after dequeue")
}
The result is as follows:
Total 128 after init
Total 0 after dequeue
std.console Package
Function Description
The console package provides methods for interacting with standard input, standard output, and standard error streams.
This package provides the Console class for obtaining the three standard streams.
- ConsoleReader encapsulates the functions related to standard input streams. You can use the
readmethod to read data from standard input streams. - ConsoleWriter encapsulates functions related to standard output and standard error streams. ConsoleWriter encapsulates a series of
writemethods and provides the capability of writing data to standard output and standard error streams.
Standard input (stdin), standard output (stdout), and standard error (stderr) are three common streams in computer operating systems.
A standard input stream is that a program obtains input data from a user, and is usually a keyboard input. A standard output stream is that a program outputs results to a user, and is usually a screen output. A standard error stream is that a program outputs error information when an error occurs, and is usually a screen output.
On Unix or Linux, standard input, standard output, and standard error correspond to file descriptors 0, 1, and 2, respectively. Programs can use these file descriptors to read and write data. For example, redirection symbols can be used to redirect a standard output to a file, or to redirect a standard error output to a standard input of another program.
API List
Class
| Name | Description |
|---|---|
| Console | Provides APIs for obtaining standard input, standard output, and standard error streams. |
| ConsoleReader | Provides functions of reading characters or strings from standard input streams. |
| ConsoleWriter | Provides functions of writing characters or strings to standard output or standard error streams. |
Class
class Console
public class Console
Description: Provides APIs for obtaining standard input, standard output, and standard error streams.
static prop stdErr
public static prop stdErr: ConsoleWriter
Description: This member attribute is of the ConsoleWriter type and provides the function of obtaining standard error streams.
Type: ConsoleWriter
static prop stdIn
public static prop stdIn: ConsoleReader
Description: This member attribute is of the ConsoleReader type and provides the function of obtaining standard input streams.
Type: ConsoleReader
static prop stdOut
public static prop stdOut: ConsoleWriter
Description: This member attribute is of the ConsoleWriter type and provides the function of obtaining standard output streams.
Type: ConsoleWriter
class ConsoleReader
public class ConsoleReader <: InputStream
Description: Reads data from the console and converts the data into characters or strings.
This type does not support constructing instances. Its instances can be obtained only through Console.stdIn.
The read operation is synchronous. There is a buffer in ConsoleReader used to store the content input from the console. When the end of the input stream of the console is reached, the read function of the console returns None.
Note:
ConsoleReader has only one instance, and all methods share the same buffer. The
readmethod returnsNonein the following scenarios:
- When a standard input stream is redirected to a file, the end-of-file (EOF) mark is read.
- On Linux,
Ctrl+Dis pressed.- On Windows, Enter is pressed after
Ctrl+Zis pressed.The ConsoleReader supports only the UTF-8 encoding. In the Windows environment, you need to manually run the
chcp 65001command. (Change encoding of Windows terminal to UTF-8) If the system code is inconsistent with the code required by the API, garbled characters may be generated. As a result, an exception occurs when the system code is read from the'Rune` and IllegalArgumentException is thrown.
Parent Type:
func read()
public func read(): ?Rune
Description: Reads the next character from a standard input stream.
Returns:
- ?Rune: ?Rune is returned if a character is read. Otherwise,
Noneis returned.
Throws:
- IllegalArgumentException: If a string that does not comply with the
UTF-8encoding format is input, this exception is thrown.
func read(Array<Byte>)
public func read(arr: Array<Byte>): Int64
Description: Reads data from a standard input stream and puts the data into arr.
Note:
This function has risks. The read result may truncate
UTF-8 code point. If truncation occurs, the result of converting the Array<Byte> instance into a string is incorrect or an exception is thrown.
Parameters:
Returns:
- Int64: length of the read bytes
func readToEnd()
public func readToEnd(): ?String
Description: Reads all characters from a standard input stream.
The reading continues until the EOF mark is read, or Ctrl+D is entered on Linux or Ctrl+Z + Enter is pressed on Windows. If all characters are read, ?String is returned. Otherwise, None is returned. If the read operation fails, None is returned. This API does not throw any exception. Even if a string that does not comply with the UTF-8 encoding format is entered, a String instance is constructed and returned. The behavior is the same as String.fromUtf8Uncheck(Array<Byte>).
Returns:
func readUntil((Rune) -> Bool)
public func readUntil(predicate: (Rune) -> Bool): ?String
Description: Reads data from a standard input stream until the read characters meet the condition of predicate.
The characters that meet the condition of predicate: (Rune) -> Bool are contained in the result. If the reading fails, None is returned.
Parameters:
- predicate: (Rune) ->Bool: condition for stopping reading
Returns:
func readUntil(Rune)
public func readUntil(ch: Rune): ?String
Description: Reads data from a standard input stream until the character ch is read.
The character ch is contained in the result. If the EOF mark is read, all the read information is returned. If the reading fails, None is returned.
Parameters:
- ch: Rune: end character
Returns:
func readln()
public func readln(): ?String
Description: Reads a line of characters from a standard input stream.
If characters are read, a ?String instance is returned. The result does not contain newline characters. This API does not throw any exception. Even if a string that does not comply with the UTF-8 encoding format is entered, a String instance is constructed and returned. The behavior is the same as String.fromUtf8Uncheck(Array<Byte>).
Returns:
- ?String: read line data. If the reading fails,
Noneis returned.
class ConsoleWriter
public class ConsoleWriter <: OutputStream
Description: Provides the standard output function that ensures thread security.
The result written to the console is complete each time the write function is called. The results of different write function calls are not mixed. This type does not support constructing instances. Standard output instances can be obtained only through Console.stdOut and standard error instances can be obtained only through Console.stdErr.
Parent Type:
func flush()
public func flush(): Unit
Description: Refreshes the output stream.
func write(Array<Byte>)
public func write(buffer: Array<Byte>): Unit
Description: Writes the byte array specified by buffer to a standard output or standard error stream.
Parameters:
func write(Bool)
public func write(v: Bool): Unit
Description: Writes the text representation of a specified Boolean value to a standard output or standard error stream.
Parameters:
- v: Bool: value to be written
func write(Float16)
public func write(v: Float16): Unit
Description: Writes the text representation of a specified 16-bit floating-point number value to a standard output or standard error stream.
Parameters:
- v: Float16: value to be written
func write(Float32)
public func write(v: Float32): Unit
Description: Writes the text representation of a specified 32-bit floating-point number value to a standard output or standard error stream.
Parameters:
- v: Float32: value to be written
func write(Float64)
public func write(v: Float64): Unit
Description: Writes the text representation of a specified 64-bit floating-point number value to a standard output or standard error stream.
Parameters:
- v: Float64: value to be written
func write(Int16)
public func write(v: Int16): Unit
Description: Writes the text representation of a specified 16-bit signed integer value to a standard output or standard error stream.
Parameters:
- v: Int16: value to be written
func write(Int32)
public func write(v: Int32): Unit
Description: Writes the text representation of a specified 32-bit signed integer value to a standard output or standard error stream.
Parameters:
- v: Int32: value to be written
func write(Int64)
public func write(v: Int64): Unit
Description: Writes the text representation of a specified 64-bit signed integer value to a standard output or standard error stream.
Parameters:
- v: Int64: value to be written
func write(Int8)
public func write(v: Int8): Unit
Description: Writes the text representation of a specified 8-bit signed integer value to a standard output or standard error stream.
Parameters:
- v: Int8: value to be written
func write(Rune)
public func write(v: Rune): Unit
Description: Writes the Unicode character value of a specified Rune to a standard output or standard error stream.
Parameters:
- v: Rune: value to be written
func write(String)
public func write(v: String): Unit
Description: Writes a specified string value to a standard output or standard error stream.
Parameters:
- v: String: value to be written
func write(UInt16)
public func write(v: UInt16): Unit
Description: Writes the text representation of a specified 16-bit unsigned integer value to a standard output or standard error stream.
Parameters:
- v: UInt16: value to be written
func write(UInt32)
public func write(v: UInt32): Unit
Description: Writes the text representation of a specified 32-bit unsigned integer value to a standard output or standard error stream.
Parameters:
- v: UInt32: value to be written
func write(UInt64)
public func write(v: UInt64): Unit
Description: Writes the text representation of a specified 64-bit unsigned integer value to a standard output or standard error stream.
Parameters:
- v: UInt64: value to be written
func write(UInt8)
public func write(v: UInt8): Unit
Description: Writes the text representation of a specified 8-bit unsigned integer value to a standard output or standard error stream.
Parameters:
- v: UInt8: value to be written
func write<T>(T) where T <: ToString
public func write<T>(v: T): Unit where T <: ToString
Description: Writes the data type that implements the ToString interface to a standard output or standard error stream.
Parameters:
- v: T: instance of the ToString type to be written
func writeln(Array<Byte>)
public func writeln(buffer: Array<Byte>): Unit
Description: Writes the byte array specified by buffer (followed by a newline character) to a standard output or standard error stream.
Parameters:
func writeln(Bool)
public func writeln(v: Bool): Unit
Description: Writes the text representation (followed by a newline character) of a specified Boolean value to a standard output or standard error stream.
Parameters:
- v: Bool: value to be written
func writeln(Float16)
public func writeln(v: Float16): Unit
Description: Writes the text representation (followed by a newline character) of a specified 16-bit floating-point number value to a standard output or standard error stream.
Parameters:
- v: Float16: value to be written
func writeln(Float32)
public func writeln(v: Float32): Unit
Description: Writes the text representation (followed by a newline character) of a specified 32-bit floating-point number value to a standard output or standard error stream.
Parameters:
- v: Float32: value to be written
func writeln(Float64)
public func writeln(v: Float64): Unit
Description: Writes the text representation (followed by a newline character) of a specified 64-bit floating-point number value to a standard output or standard error stream.
Parameters:
- v: Float64: value to be written
func writeln(Int16)
public func writeln(v: Int16): Unit
Description: Writes the text representation (followed by a newline character) of a specified 16-bit signed integer value to a standard output or standard error stream.
Parameters:
- v: Int16: value to be written
func writeln(Int32)
public func writeln(v: Int32): Unit
Description: Writes the text representation (followed by a newline character) of a specified 32-bit signed integer value to a standard output or standard error stream.
Parameters:
- v: Int32: value to be written
func writeln(Int64)
public func writeln(v: Int64): Unit
Description: Writes the text representation (followed by a newline character) of a specified 64-bit signed integer value to a standard output or standard error stream.
Parameters:
- v: Int64: value to be written
func writeln(Int8)
public func writeln(v: Int8): Unit
Description: Writes the text representation (followed by a newline character) of a specified 8-bit signed integer value to a standard output or standard error stream.
Parameters:
- v: Int8: value to be written
func writeln(Rune)
public func writeln(v: Rune): Unit
Description: Writes the specified Unicode character value (followed by a newline character) to a standard output or standard error stream.
Parameters:
- v: Rune: value to be written
func writeln(String)
public func writeln(v: String): Unit
Description: Writes the specified string value (followed by a newline character) to a standard output or standard error stream.
Parameters:
- v: String: value to be written
func writeln(UInt16)
public func writeln(v: UInt16): Unit
Description: Writes the text representation (followed by a newline character) of a specified 16-bit unsigned integer value to a standard output or standard error stream.
Parameters:
- v: UInt16: value to be written
func writeln(UInt32)
public func writeln(v: UInt32): Unit
Description: Writes the text representation (followed by a newline character) of a specified 32-bit unsigned integer value to a standard output or standard error stream. Parameters:
- v: UInt32: value to be written
func writeln(UInt64)
public func writeln(v: UInt64): Unit
Description: Writes the text representation (followed by a newline character) of a specified 64-bit unsigned integer value to a standard output or standard error stream.
Parameters:
- v: UInt64: value to be written
func writeln(UInt8)
public func writeln(v: UInt8): Unit
Description: Writes the text representation (followed by a newline character) of a specified 8-bit unsigned integer value to a standard output or standard error stream.
Parameters:
- v: UInt8: value to be written
func writeln<T>(T) where T <: ToString
public func writeln<T>(v: T): Unit where T <: ToString
Description: Writes the string (followed by a newline character) converted from a data type that implements the ToString interface to a standard output or standard error stream.
Parameters:
- v: T: value to be written
Console Example
The following is an example of Console. In the example, two pieces of information entered by a user are received and returned to the user through standard output streams.
import std.console.*
main() {
Console.stdOut.write("Please enter information 1: ")
var c = Console.stdIn.readln() //Input: Hello. What day is it today?
var r = c.getOrThrow()
Console.stdOut.writeln("Input information 1: " + r)
Console.stdOut.write("Please enter information 2: ")
c = Console.stdIn.readln() // Input: Hello. What's the date today?
r = c.getOrThrow()
Console.stdOut.writeln("Input information 2: " + r)
return
}
Running result:
Please enter information 1: Hello. What day is it today?
Input information 1: Hello. What day is it today?
Please enter information 2: Hello. What's the date today?
Input information 2: Hello. What's the date today?
std.convert Package
Function Description
The convert package provides a series of Convert functions for converting strings to specific types.
For example, the string "true" is converted to the Boolean type true.
API List
Interface
| Name | Description |
|---|---|
| Parsable<T> | Parses a string into a specific type. |
Interface
interface Parsable<T>
public interface Parsable<T> {
static func parse(value: String): T
static func tryParse(value: String): Option<T>
}
Description: Provides unified methods to parse strings to specific types.
This interface provides two methods: parse and tryParse. The parse method throws an exception when parsing fails. The tryParse method returns the result encapsulated with Option. If parsing fails, the tryParse method returns None. In this package, the basic types, such as Bool, Rune, Float16, and Int64, have implemented this interface. This interface can be used to convert strings to these types.
static func parse(String)
static func parse(value: String): T
Description: Parses a string into a specific type.
Parameters:
- value: String: string to be parsed
Returns:
- T: value after conversion
static func tryParse(String)
static func tryParse(value: String): Option<T>
Description: Parses a string into a specific type.
Parameters:
- value: String: string to be parsed
Returns:
extend Bool <: Parsable<Bool>
extend Bool <: Parsable<Bool>
Description: Implements related operation functions of converting a Bool literal string to a Bool value.
Parent Type:
static func parse(String)
public static func parse(data: String): Bool
Description: Converts a Bool literal string to a Bool value.
Parameters:
- data: String: string to be converted
Returns:
Throws:
- IllegalArgumentException: If the string is empty or conversion fails, this exception is thrown.
static func tryParse(String)
public static func tryParse(data: String): Option<Bool>
Description: Converts a Bool literal string to an Option<Bool> value.
Parameters:
- data: String: string to be converted
Returns:
- Option<Bool>: Option<Bool> value after conversion. If the conversion fails, Option<Bool>.None is returned.
extend Float16 <: Parsable<Float16>
extend Float16 <: Parsable<Float16>
Description: Implements related operation functions of converting a Float16 literal string to a Float16 value.
Parent Type:
static func parse(String)
public static func parse(data: String): Float16
Description: Converts a Float16 literal string to a Float16 value.
Parameters:
- data: String: string to be converted
Returns:
Throws:
- IllegalArgumentException: If the string does not comply with the floating-point number syntax, this exception is thrown.
static func tryParse(String)
public static func tryParse(data: String): Option<Float16>
Description: Converts a Float16 literal string to an Option<Float16> value.
Parameters:
- data: String: string to be converted
Returns:
- Option<Float16>: Option<Float16> value after conversion. If the conversion fails, Option<Float16>.None is returned.
extend Float32 <: Parsable<Float32>
extend Float32 <: Parsable<Float32>
Description: Implements related operation functions of converting a Float32 literal string to a Float32 value.
Parent Type:
static func parse(String)
public static func parse(data: String): Float32
Description: Converts a Float32 literal string to a Float32 value.
Parameters:
- data: String: string to be converted
Returns:
Throws:
- IllegalArgumentException: If the string does not comply with the floating-point number syntax, this exception is thrown.
static func tryParse(String)
public static func tryParse(data: String): Option<Float32>
Description: Converts a Float32 literal string to an Option<Float32> value.
Parameters:
- data: String: string to be converted
Returns:
- Option<Float32>: Option<Float32> value after conversion. If the conversion fails, Option<Float32>.None is returned.
extend Float64 <: Parsable<Float64>
extend Float64 <: Parsable<Float64>
Description: Implements related operation functions of converting a Float64 literal string to a Float64 value.
Parent Type:
static func parse(String)
public static func parse(data: String): Float64
Description: Converts a Float64 literal string to a Float64 value.
Parameters:
- data: String: string to be converted
Returns:
Throws:
- IllegalArgumentException: If the string does not comply with the floating-point number syntax, this exception is thrown.
static func tryParse(String)
public static func tryParse(data: String): Option<Float64>
Description: Converts a Float64 literal string to an Option<Float64> value.
Parameters:
- data: String: string to be converted
Returns:
- Option<Float64>: Option<Float64> value after conversion. If the conversion fails, Option<Float64>.None is returned.
extend Int16 <: Parsable<Int16>
extend Int16 <: Parsable<Int16>
Description: Implements related operation functions of converting an Int16 literal string to an Int16 value.
Parent Type:
static func parse(String)
public static func parse(data: String): Int16
Description: Converts an Int16 literal string to an Int16 value.
Parameters:
- data: String: string to be converted
Returns:
Throws:
- IllegalArgumentException: If the string is empty, the first character of the string is
+, the conversion fails, the value after conversion exceeds the range of Int16, or the string contains an invalid UTF-8 character, this exception is thrown.
static func tryParse(String)
public static func tryParse(data: String): Option<Int16>
Description: Converts an Int16 literal string to an Option<Int16> value.
Parameters:
- data: String: string to be converted
Returns:
- Option<Int16>: Option<Int16> value after conversion. If the conversion fails, Option<Int16>.None is returned.
extend Int32 <: Parsable<Int32>
extend Int32 <: Parsable<Int32>
Description: Implements related operation functions of converting an Int32 literal string to an Int32 value.
Parent Type:
static func parse(String)
public static func parse(data: String): Int32
Description: Converts an Int32 literal string to an Int32 value.
Parameters:
- data: String: string to be converted
Returns:
Throws:
- IllegalArgumentException: If the string is empty, the first character of the string is
+, the conversion fails, the value after conversion exceeds the range of Int32, or the string contains an invalid UTF-8 character, this exception is thrown.
static func tryParse(String)
public static func tryParse(data: String): Option<Int32>
Description: Converts an Int32 literal string to an Option<Int32> value.
Parameters:
- data: String: string to be converted
Returns:
- Option<Int32>: Option<Int32> value after conversion. If the conversion fails, Option<Int32>.None is returned.
extend Int64 <: Parsable<Int64>
extend Int64 <: Parsable<Int64>
Description: Implements related operation functions of converting an Int64 literal string to an Int64 value.
Parent Type:
static func parse(String)
public static func parse(data: String): Int64
Description: Converts an Int64 literal string to an Int64 value.
Parameters:
- data: String: string to be converted
Returns:
Throws:
- IllegalArgumentException: If the string is empty, the first character of the string is
+, the conversion fails, the value after conversion exceeds the range of Int64, or the string contains an invalid UTF-8 character, this exception is thrown.
static func tryParse(String)
public static func tryParse(data: String): Option<Int64>
Description: Converts an Int64 literal string to an Option<Int64> value.
Parameters:
- data: String: string to be converted
Returns:
- Option<Int64>: Option<Int64> value after conversion. If the conversion fails, Option<Int64>.None is returned.
extend Int8 <: Parsable<Int8>
extend Int8 <: Parsable<Int8>
Description: Implements related operation functions of converting an Int8 literal string to an Int8 value.
Parent Type:
static func parse(String)
public static func parse(data: String): Int8
Description: Converts an Int8 literal string to an Int8 value.
Parameters:
- data: String: string to be converted
Returns:
Throws:
- IllegalArgumentException: If the string is empty, the first character of the string is
+, the conversion fails, the value after conversion exceeds the range of Int8, or the string contains an invalid UTF-8 character, this exception is thrown.
static func tryParse(String)
public static func tryParse(data: String): Option<Int8>
Description: Converts an Int8 literal string to an Option<Int8> value.
Parameters:
- data: String: string to be converted
Returns:
- Option<Int8>: Option<Int8> value after conversion. If the conversion fails, Option<Int8>.None is returned.
extend Rune <: Parsable<Rune>
extend Rune <: Parsable<Rune>
Description: Implements related operation functions of converting a Rune literal string to a Rune value.
Parent Type:
static func parse(String)
public static func parse(data: String): Rune
Description: Converts a Rune literal string to a Rune value.
Parameters:
- data: String: string to be converted
Returns:
Throws:
- IllegalArgumentException: If the string is empty, the conversion fails, or the string contains an invalid UTF-8 character, this exception is thrown.
static func tryParse(String)
public static func tryParse(data: String): Option<Rune>
Description: Converts a Rune literal string to an Option<Rune> value.
Parameters:
- data: String: string to be converted
Returns:
- Option<Rune>: Option<Rune> value after conversion. If the conversion fails, Option<Rune>.None is returned.
extend UInt16 <: Parsable<UInt16>
extend UInt16 <: Parsable<UInt16>
Description: Implements related operation functions of converting a UInt16 literal string to a UInt16 value.
Parent Type:
static func parse(String)
public static func parse(data: String): UInt16
Description: Converts a UInt16 literal string to a UInt16 value.
Parameters:
- data: String: string to be converted
Returns:
Throws:
- IllegalArgumentException: If the string is empty, the first character of the string is
+or-, the conversion fails, the value after conversion exceeds the range of UInt16, or the string contains an invalid UTF-8 character, this exception is thrown.
static func tryParse(String)
public static func tryParse(data: String): Option<UInt16>
Description: Converts a UInt16 literal string to an Option<UInt16> value.
Parameters:
- data: String: string to be converted
Returns:
- Option<UInt16>: Option<UInt16> value after conversion. If the conversion fails, Option<UInt16>.None is returned.
extend UInt32 <: Parsable<UInt32>
extend UInt32 <: Parsable<UInt32>
Description: Implements related operation functions of converting a UInt32 literal string to a UInt32 value.
Parent Type:
static func parse(String)
public static func parse(data: String): UInt32
Description: Converts a UInt32 literal string to a UInt32 value.
Parameters:
- data: String: string to be converted
Returns:
Throws:
- IllegalArgumentException: If the string is empty, the first character of the string is
+or-, the conversion fails, the value after conversion exceeds the range of UInt32, or the string contains an invalid UTF-8 character, this exception is thrown.
static func tryParse(String)
public static func tryParse(data: String): Option<UInt32>
Description: Converts a UInt32 literal string to an Option<UInt32> value.
Parameters:
- data: String: string to be converted
Returns:
- Option<UInt32>: Option<UInt32> value after conversion. If the conversion fails, Option<UInt32>.None is returned.
extend UInt64 <: Parsable<UInt64>
extend UInt64 <: Parsable<UInt64>
Description: Implements related operation functions of converting a UInt64 literal string to a UInt64 value.
Parent Type:
static func parse(String)
public static func parse(data: String): UInt64
Description: Converts a UInt64 literal string to a UInt64 value.
Parameters:
- data: String: string to be converted
Returns:
Throws:
- IllegalArgumentException: If the string is empty, the first character of the string is
+or-, the conversion fails, the value after conversion exceeds the range of UInt64, or the string contains an invalid UTF-8 character, this exception is thrown.
static func tryParse(String)
public static func tryParse(data: String): Option<UInt64>
Description: Converts a UInt64 literal string to an Option<UInt64> value.
Parameters:
- data: String: string to be converted
Returns:
- Option<UInt64>: Option<UInt64> value after conversion. If the conversion fails, Option<UInt64>.None is returned.
extend UInt8 <: Parsable<UInt8>
extend UInt8 <: Parsable<UInt8>
Description: Implements related operation functions of converting a UInt8 literal string to a UInt8 value.
Parent Type:
static func parse(String)
public static func parse(data: String): UInt8
Description: Converts a UInt8 literal string to a UInt8 value.
Parameters:
- data: String: string to be converted
Returns:
Throws:
- IllegalArgumentException: If the string is empty, the first character of the string is
+or-, the conversion fails, the value after conversion exceeds the range of UInt8, or the string contains an invalid UTF-8 character, this exception is thrown.
static func tryParse(String)
public static func tryParse(data: String): Option<UInt8>
Description: Converts a UInt8 literal string to an Option<UInt8> value.
Parameters:
- data: String: string to be converted
Returns:
- Option<UInt8>: Option<UInt8> value after conversion. If the conversion fails, Option<UInt8>.None is returned.
convert Usage Example
Code:
import std.convert.*
main():Int64 {
var strBool_parse : String = "true"
var strBool_tryParse : String = "false"
var strChar_parse : String = "'a'"
var strChar_tryParse : String = "'\\u{00e2}'"
var strInt8_parse : String = "-128"
var strInt8_tryParse : String = "127"
var strInt16_parse : String = "-32768"
var strInt16_tryParse : String = "32767"
var strInt32_parse : String = "-2147483648"
var strInt32_tryParse : String = "2147483647"
var strInt64_parse : String = "-9223372036854775808"
var strInt64_tryParse : String = "9223372036854775807"
var strFloat16_parse : String = "-65504.0"
var strFloat16_tryParse : String = "65504.0"
var strFloat32_parse : String = "-3.14159"
var strFloat32_tryParse : String = "3.14159"
var strFloat64_parse : String = "-3.1415926"
var strFloat64_tryParse : String = "3.1415926"
var strUInt8_parse : String = "255"
var strUInt8_tryParse : String = "255"
var strUInt16_parse : String = "65535"
var strUInt16_tryParse : String = "65535"
var strUInt32_parse : String = "4294967295"
var strUInt32_tryParse : String = "4294967295"
var strUInt64_parse : String = "18446744073709551615"
var strUInt64_tryParse : String = "18446744073709551615"
println("After the conversion of parse, \"true\" became ${Bool.parse(strBool_parse)}")
println("After the conversion of tryParse, \"false\" became ${Bool.tryParse(strBool_tryParse)}")
println("After the conversion of parse, \"'a'\" became ${Rune.parse(strChar_parse)}")
println("After the conversion of tryParse, \"'\\u{00e2}'\" became ${Rune.tryParse(strChar_tryParse)}")
println("After the conversion of parse, \"-128\" became ${Int8.parse(strInt8_parse)}")
println("After the conversion of tryParse, \"127\" became ${Int8.tryParse(strInt8_tryParse)}")
println("After the conversion of parse, \"-32768\" became ${Int16.parse(strInt16_parse)}")
println("After the conversion of tryParse, \"32767\" became ${Int16.tryParse(strInt16_tryParse)}")
println("After the conversion of parse, \"-2147483648\" became ${Int32.parse(strInt32_parse)}")
println("After the conversion of tryParse, \"2147483647\" became ${Int32.tryParse(strInt32_tryParse)}")
println("After the conversion of parse, \"-9223372036854775808\" became ${Int64.parse(strInt64_parse)}")
println("After the conversion of tryParse, \"9223372036854775807\" became ${Int64.tryParse(strInt64_tryParse)}")
println("After the conversion of parse, \"-65504.0\" became ${Float16.parse(strFloat16_parse)}")
println("After the conversion of tryParse, \"65504.0\" became ${Float16.tryParse(strFloat16_tryParse)}")
println("After the conversion of parse, \"-3.14159\" became ${Float32.parse(strFloat32_parse)}")
println("After the conversion of tryParse, \"3.14159\" became ${Float32.tryParse(strFloat32_tryParse)}")
println("After the conversion of parse, \"-3.1415926\" became ${Float64.parse(strFloat64_parse)}")
println("After the conversion of tryParse, \"3.1415926\" became ${Float64.tryParse(strFloat64_tryParse)}")
println("After the conversion of parse, \"255\" became ${UInt8.parse(strUInt8_parse)}")
println("After the conversion of tryParse, \"255\" became ${UInt8.tryParse(strUInt8_tryParse)}")
println("After the conversion of parse, \"65535\" became ${UInt16.parse(strUInt16_parse)}")
println("After the conversion of tryParse, \"65535\" became ${UInt16.tryParse(strUInt16_tryParse)}")
println("After the conversion of parse, \"4294967295\" became ${UInt32.parse(strUInt32_parse)}")
println("After the conversion of tryParse, \"4294967295\" became ${UInt32.tryParse(strUInt32_tryParse)}")
println("After the conversion of parse, \"18446744073709551615\" became ${UInt64.parse(strUInt64_parse)}")
println("After the conversion of tryParse, \"18446744073709551615\" became ${UInt64.tryParse(strUInt64_tryParse)}")
return 0
}
Running result:
After the conversion of parse, "true" became true
After the conversion of tryParse, "false" became Some(false)
After the conversion of parse, "'a'" became a
After the conversion of tryParse, "'\u{00e2}'" became Some(â)
After the conversion of parse, "-128" became -128
After the conversion of tryParse, "127" became Some(127)
After the conversion of parse, "-32768" became -32768
After the conversion of tryParse, "32767" became Some(32767)
After the conversion of parse, "-2147483648" became -2147483648
After the conversion of tryParse, "2147483647" became Some(2147483647)
After the conversion of parse, "-9223372036854775808" became -9223372036854775808
After the conversion of tryParse, "9223372036854775807" became Some(9223372036854775807)
After the conversion of parse, "-65504.0" became -65504.000000
After the conversion of tryParse, "65504.0" became Some(65504.000000)
After the conversion of parse, "-3.14159" became -3.141590
After the conversion of tryParse, "3.14159" became Some(3.141590)
After the conversion of parse, "-3.1415926" became -3.141593
After the conversion of tryParse, "3.1415926" became Some(3.141593)
After the conversion of parse, "255" became 255
After the conversion of tryParse, "255" became Some(255)
After the conversion of parse, "65535" became 65535
After the conversion of tryParse, "65535" became Some(65535)
After the conversion of parse, "4294967295" became 4294967295
After the conversion of tryParse, "4294967295" became Some(4294967295)
After the conversion of parse, "18446744073709551615" became 18446744073709551615
After the conversion of tryParse, "18446744073709551615" became Some(18446744073709551615)
std.crypto.cipher Package
Function Description
The std.crypto.cipher package provides universal APIs for symmetric encryption and decryption.
API List
Interface
| Name | Description |
|---|---|
| BlockCipher | Specifies a universal interface for the digest algorithm. |
Interface
interface BlockCipher
public interface BlockCipher {
prop blockSize: Int64
func encrypt(input: Array<Byte>): Array<Byte>
func decrypt(input: Array<Byte>): Array<Byte>
}
Description: Specifies a block encryption and decryption algorithm interface. Any class, interface, and struct inherited from this interface must comply with the definitions of the input parameters and return values of the functions in this interface.
prop blockSize
prop blockSize: Int64
Description: Obtains the size of a block, in bytes.
Type: Int64
func encrypt(Array<Byte>)
func encrypt(input: Array<Byte>): Array<Byte>
Description: Provides an encryption function.
Parameters:
Returns:
func decrypt(Array<Byte>)
func decrypt(input: Array<Byte>): Array<Byte>
Description: Provides a decryption function.
Parameters:
Returns:
std.crypto.digest Package
Function Description
The std.crypto.digest package provides universal APIs for common digest algorithms, including MD5, SHA1, SHA224, SHA256, SHA384, SHA512, HMAC, and SM3.
API List
Function
| Name | Description |
|---|---|
| digest<T>(T, Array<Byte>) where T <: Digest | Provides the digest generic function to perform digest operation using a specified digest algorithm. |
| digest<T>(T, String) where T <: Digest | Provides the digest generic function to perform digest operation using a specified digest algorithm. |
API
| Name | Description |
|---|---|
| Digest | Specifies a universal interface for the digest algorithm. |
Function
func digest<T>(T, Array<Byte>) where T <: Digest
public func digest<T>(algorithm: T, data: Array<Byte>): Array<Byte> where T <: Digest
Description: Provides the digest generic function to perform digest operation using a specified digest algorithm.
Parameters:
- algorithm: T: specific digest algorithm
- data: Array<Byte>: data for which digest operation is to be performed
Returns:
func digest<T>(T, String) where T <: Digest
public func digest<T>(algorithm: T, data: String): Array<Byte> where T <: Digest
Description: Provides the digest generic function to perform digest operation using a specified digest algorithm.
Parameters:
- algorithm: T: specific digest algorithm
- data: String: data for which digest operation is to be performed
Returns:
Interface
interface Digest
public interface Digest {
prop size: Int64
prop blockSize: Int64
}
Description: Specifies a digest algorithm interface. Any class, interface, and struct inherited from this interface must comply with the definitions of the input parameters and return values of the functions in this interface.
prop blockSize
prop blockSize: Int64
Description: Returns the Block size, in bytes.
Type: Int64
prop size
prop size: Int64
Description: Returns the size of the generated digest, in bytes.
Type: Int64
func finish()
func finish(): Array<Byte>
Description: Returns the generated digest value.
Returns:
func reset()
mut func reset(): Unit
Description: Resets the digest object to the initial state.
func write(Array<Byte>)
mut func write(buffer: Array<Byte>): Unit
Description: Updates the digest object using a specified buffer.
std.database.sql Package
Function Description
The database.sql package provides the interface for accessing the database.
This package provides universal SQL/CLI interfaces and works with the database driver to perform operations on the database.
Notes:
Currently, only SQL/CLI interfaces are supported.
The following table lists the mapping between SQL data types and Cangjie data types.
| SQL | CDBC/Cangjie | SqlDataType | Description |
|---|---|---|---|
RUNE | String | SqlChar | - |
VARCHAR | String | SqlVarchar | - |
CLOB | io.InputStream | SqlClob | - |
BINARY | Array<Byte> | SqlBinary | - |
VARBINARY | Array<Byte> | SqlVarBinary | - |
BLOB | io.InputStream | SqlBlob | - |
NUMERIC | Decimal | sqlDecimal | - |
DECIMAL | Decimal | sqlDecimal | - |
BOOLEAN | Bool | SqlBool | - |
TINYINT | Int8 | SqlByte | - |
SMALLINT | Int16 | SqlSmallInt | - |
INTEGER | Int32 | SqlInteger | - |
BIGINT | Int64 | SqlBigInt | - |
REAL | Float32 | SqlReal | - |
DOUBLE | Float64 | SqlDouble | - |
DATE | time.DateTime | SqlDate | The value can be YEAR, MONTH, or DAY. |
TIME | time.DateTime | SqlTime | The value can be HOUR, MINUTE, or SECOND but cannot be TIME ZONE. |
TIMETZ | time.DateTime | SqlTimeTz | The value can be HOUR, MINUTE, SECOND, or TIME ZONE. |
TIMESTAMP | time.DateTime | SqlTimestamp | The value can be YEAR, MONTH, DAY, HOUR, MINUTE, SECOND or TIME ZONE. |
INTERVAL | time.Duration | SqlInterval | Interval in year-month format or day-time format. |
API List
Interface
| Name | Description |
|---|---|
| ColumnInfo | Specifies the column information of the result returned by executing the Select/Query statement. |
| Connection | Specifies the database connection interface. |
| Datasource | Specifies the data source interface. |
| Driver | Specifies the database driver interface. |
| QueryResult | Specifies the interface used to query the result generated by executing the Select statement. |
| SqlDbType | Specifies the parent class of all SQL data types. |
| SqlNullableDbType | Specifies the parent class of the SQL data type that allows null values. |
| Statement | Specifies the interface of SQL statement pre-execution. |
| Transaction | Defines the core behavior of database transactions. |
| UpdateResult | Specifies the interface used to update the result generated by executing the Insert, Update, and Delete statements. |
Class
| Name | Description |
|---|---|
| DriverManager | Obtains the database driver instance according to the driver name during running. |
| PooledDatasource | Specifies a database connection pool class, which provides the database connection pool capability. |
| SqlOption | Specifies the predefined SQL option name and value. |
| SqlBigInt | Specifies a large integer corresponding to the Cangjie Int64 type. |
| SqlBinary | Specifies a fixed-length binary string corresponding to the Cangjie Array<Byte> type. |
| SqlBlob | Specifies an excessively large variable-length binary string (BINARY LARGE OBJECT) corresponding to the Cangjie InputStream type. |
| SqlBool | Specifies the Boolean type corresponding to the Cangjie Bool type. |
| SqlByte | Specifies a byte corresponding to the Cangjie Int8 type. |
| SqlChar | Specifies a fixed-length string corresponding to the Cangjie String type. |
| SqlClob | Specifies an excessively large variable-length string (RUNE LARGE OBJECT) corresponding to the Cangjie InputStream type. |
| SqlDate | Specifies a date, which must be in the format of dd-mm-yyyy and corresponds to the Cangjie DateTime type. |
| SqlDecimal | Specifies a high-precision number corresponding to the Cangjie Decimal type. |
| SqlDouble | Specifies a double-precision floating-point number corresponding to the Cangjie Float64 type. |
| SqlInteger | Specifies a medium integer corresponding to the Cangjie Int32 type. |
| SqlInterval | Specifies the time interval corresponding to the Cangjie Duration type. |
| SqlReal | Specifies a floating-point number corresponding to the Cangjie Float32 type. |
| SqlSmallInt | Specifies a small integer corresponding to the Cangjie Int16 type. |
| SqlTime | Specifies the time, which must be in the format of hhmmss.ms and corresponds to the Cangjie DateTime type. |
| SqlTimestamp | Specifies a timestamp corresponding to the Cangjie DateTime type. |
| SqlTimeTz | Specifies the time with a time zone, which must be in the format of hhmmss.ms and corresponds to the Cangjie DateTime type. |
| SqlVarBinary | Specifies a variable-length binary string corresponding to the Cangjie Array<Byte> type. |
| SqlVarchar | Specifies a variable-length string corresponding to the Cangjie String type. |
| SqlNullableBigInt | Specifies a large integer corresponding to the Cangjie Int64 type, which can be a Null value in the database. |
| SqlNullableBinary | Specifies a fixed-length binary string corresponding to the Cangjie Array<Byte> type, which can be a Null value in the database. |
| SqlNullableBlob | Specifies an excessively large variable-length binary string (BINARY LARGE OBJECT) corresponding to the Cangjie InputStream type, which can be a Null value in the database. |
| SqlNullableBool | Specifies the Boolean type corresponding to the Cangjie Bool type, which can be a Null value in the database. |
| SqlNullableByte | Specifies a byte corresponding to the Cangjie Int8 type, which can be a Null value in the database. |
| SqlNullableChar | Specifies a fixed-length binary string corresponding to the Cangjie String type, which can be a Null value in the database. |
| SqlNullableClob | Specifies an excessively large variable-length string (RUNE LARGE OBJECT) corresponding to the Cangjie InputStream type, which can be a Null value in the database. |
| SqlNullableDate | Specifies a date, which must be in the format of dd-mm-yyyy and corresponds to the Cangjie DateTime type. It can be a Null value in the database. |
| SqlNullableDecimal | Specifies a high-precision number corresponding to the Cangjie Decimal type, which can be a Null value in the database. |
| SqlNullableDouble | Specifies a double-precision float-point number corresponding to the Cangjie Float64 type, which can be a Null value in the database. |
| SqlNullableInteger | Specifies a medium integer corresponding to the Cangjie Int32 type, which can be a Null value in the database. |
| SqlNullableInterval | Specifies the time interval corresponding to the Cangjie Duration type, which can be a Null value in the database. |
| SqlNullableReal | Specifies a floating-point number corresponding to the Cangjie Float32 type, which can be a Null value in the database. |
| SqlNullableSmallInt | Specifies a small integer corresponding to the Cangjie Int16 type, which can be a Null value in the database. |
| SqlNullableTime | Specifies the time, which must be in the format of hhmmss.ms and corresponds to the Cangjie DateTime type. It can be a Null value in the database. |
| SqlNullableTimestamp | Specifies a timestamp corresponding to the Cangjie DateTime type, which can be a Null value in the database. |
| SqlNullableTimeTz | Specifies the time with a time zone, which must be in the format of hhmmss.ms and corresponds to the Cangjie DateTime type. It can be a Null value in the database. |
| SqlNullableVarBinary | Specifies a variable-length binary string corresponding to the Cangjie Array<Byte> type, which can be a Null value in the database. |
| SqlNullableVarchar | Specifies a variable-length string corresponding to the Cangjie String type, which can be a Null value in the database. |
Enumeration
| Name | Description |
|---|---|
| ConnectionState | Describes the current status of the connection to the data source. |
| TransactionAccessMode | Specifies the transaction read/write mode. |
| TransactionDeferrableMode | Specifies the transaction delay mode. |
| TransactionIsoLevel | Defines when and how the result of an operation in a transaction is visible to other concurrent transaction operations in the database system. |
Exception Class
| Name | Description |
|---|---|
| SqlException | Handles SQL-related exceptions. |
Interface
interface ColumnInfo
public interface ColumnInfo {
prop displaySize: Int64
prop length: Int64
prop name: String
prop nullable: Bool
prop scale: Int64
prop typeName: String
}
Description: Specifies the column information of the result returned by executing the Select/Query statement.
prop displaySize
prop displaySize: Int64
Description: Obtains the maximum display length of a column value. If the length is not limited, Int64.Max is returned (The length is restricted by the database).
Type: Int64
prop length
prop length: Int64
Description: Obtains the length of a column value.
Note:
- For numeric data type, it indicates the maximum precision.
- For character data type, it indicates the length in characters.
- For the date and time data type, it indicates the maximum length of a string.
- For binary data type, it indicates the length in bytes.
- For the ROWID data type, it indicates the length in bytes.
- For any data type which cannot be represented in the form of a column value, 0 is returned.
Type: Int64
prop name
prop name: String
Description: Specifies a column name or alias.
Type: String
prop nullable
prop nullable: Bool
Description: Specifies whether the column value can be a Null value in the database.
Type: Bool
prop scale
prop scale: Int64
Description: Obtains the decimal place of a column value. If there is no decimal part, 0 is returned.
Type: Int64
prop typeName
prop typeName: String
Description: Obtains the column type name. If the corresponding data type is defined in Cangjie, the return value of the toString function of the corresponding type is returned. If not defined, the data type is defined by the database driver.
Type: String
interface Connection
public interface Connection <: Resource {
prop state: ConnectionState
func createTransaction(): Transaction
func getMetaData(): Map<String, String>
func prepareStatement(sql: String): Statement
}
Description: Specifies the database connection interface.
Any class, interface, and struct inherited from this interface must comply with the definitions of the input parameters and return values of the functions in this interface.
Parent Type:
prop state
prop state: ConnectionState
Description: Describes the current status of the connection to the data source.
Type: ConnectionState
func createTransaction()
func createTransaction(): Transaction
Description: Creates a transaction object.
Returns:
- Transaction: transaction object
Throws:
- SqlException: If a transaction is in progress and parallel transactions are not supported, this exception is thrown.
func getMetaData()
func getMetaData(): Map<String, String>
Description: Returns the metadata of the connected data source.
Returns:
func prepareStatement(String)
func prepareStatement(sql: String): Statement
Description: Returns a pre-executed Statement object instance through the input SQL statement.
Parameters:
- sql: String: the pre-executed SQL statement whose parameter must be in the form of the
?symbol placeholder
Returns:
- Statement: an instance object that can execute SQL statements.
Throws:
- SqlException: If the SQL statement contains unknown characters, this exception is thrown.
interface Datasource
public interface Datasource <: Resource {
func connect(): Connection
func setOption(key: String, value: String): Unit
}
Description: Specifies the data source interface.
Any class, interface, and struct inherited from this interface must comply with the definitions of the input parameters and return values of the functions in this interface.
Parent Type:
func connect()
func connect(): Connection
Description: Returns an available connection.
Returns:
- Connection: database connection instance
func setOption(String, String)
func setOption(key: String, value: String): Unit
Description: Sets a connection option.
Parameters:
interface Driver
public interface Driver {
prop name: String
prop preferredPooling: Bool
prop version: String
func open(connectionString: String, opts: Array<(String, String)>): Datasource
}
Description: Specifies the database driver interface.
Any class, interface, and struct inherited from this interface must comply with the definitions of the input parameters and return values of the functions in this interface.
prop name
prop name: String
Description: Specifies the driver name.
Type: String
prop preferredPooling
prop preferredPooling: Bool
Description: Specifies whether the driver has affinity with the connection pool.
If not, the connection pool is not recommended. For example, if the benefits of the SQLite driver connection pooling are not obvious, the connection pool is not recommended.
Type: Bool
prop version
prop version: String
Description: Specifies the driver version.
Type: String
func open(String, Array<(String, String)>)
func open(connectionString: String, opts: Array<(String, String)>): Datasource
Description: Opens a data source using connectionString and options.
Parameters:
- connectionString: String: database connection string
- opts: Array<(String, String)>: key: tuple array of the value, an option used to enable the data source
Returns:
- Datasource: data source instance
interface QueryResult
public interface QueryResult <: Resource {
prop columnInfos: Array<ColumnInfo>
func next(values: Array<SqlDbType>): Bool
}
Description: Obtains the interface used to query the result generated by executing the Select statement.
Any class, interface, and struct inherited from this interface must comply with the definitions of the input parameters and return values of the functions in this interface.
Parent Type:
prop columnInfos
prop columnInfos: Array<ColumnInfo>
Description: Returns the column information of the result set, such as the column name, column type, column length, and whether NULL values in the database are supported.
Type: Array<ColumnInfo>
func next(Array<SqlDbType>)
func next(values: Array<SqlDbType>): Bool
Description: Moves to the next row. Calls next once to move to the first row, calls next for the second time to move to the second row, and so on. When true is returned, the driver fills in the row data in values. When false is returned, the operation ends and the content of values is not modified.
Parameters:
Returns:
- Bool: If the next row contains data,
trueis returned. Otherwise,falseis returned.
interface SqlDbType
public interface SqlDbType {
prop name: String
}
Description: Specifies the parent class of all SQL data types.
To extend user-defined types, inherit SqlDbType or SqlNullableDbType.
Note:
All implementation types of the SqlDbType interface must have the public
valueattribute. The implementation class of each SQL data type must meet the following conditions:
- For a constructor with only one parameter, the parameter type is
T, which is supported in Cangjie.- The type of the
valueattribute modified bypublicmust be the same as that of the parameter specified in the previous sentence. The value is the value of the corresponding Cangjie type.- If a data type supports
nullvalues, SqlNullableDbType is inherited. If thenullvalues are contained, the value of thevaluefield is Option<T>.None.
prop name
prop name: String
Description: Obtains the type name.
Type: String
interface SqlNullableDbType
public interface SqlNullableDbType <: SqlDbType
Description: Specifies the parent class of the SQL data type that supports null values.
If the value is null, the value of value attribute is Option.None.
Parent Type:
interface Statement
public interface Statement <: Resource {
prop parameterColumnInfos: Array<ColumnInfo>
func query(params: Array<SqlDbType>): QueryResult
func setOption(key: String, value: String): Unit
func update(params: Array<SqlDbType>): UpdateResult
}
Description: Specifies the interface of SQL statement pre-execution.
Statement is bound to Connection. Any class, interface, and struct inherited from this interface must comply with the definitions of the input parameters and return values of the functions in this interface.
Parent Type:
prop parameterColumnInfos
prop parameterColumnInfos: Array<ColumnInfo>
Description: Specifies the column information of placeholder parameters in the pre-executed SQL statement, such as the column name, column type, column length, and whether Null values in the database are supported.
Type: Array<ColumnInfo>
func query(Array<SqlDbType>)
func query(params: Array<SqlDbType>): QueryResult
Description: Executes the SQL statement to obtain the query result.
Parameters:
- params: Array<SqlDbType>: data list of the SQL data type, which is used to replace the
?placeholder in the SQL statement
Returns:
- QueryResult: query result
Throws:
- SqlException: If an exception occurs during the execution, for example, the network is disconnected, the server times out, or the number of parameters is incorrect, this exception is thrown.
func setOption(String, String)
func setOption(key: String, value: String): Unit
Description: Sets options for pre-executed SQL statements.
Parameters:
func update(Array<SqlDbType>)
func update(params: Array<SqlDbType>): UpdateResult
Description: Executes the SQL statement to obtain the update result.
Parameters:
- params: Array<SqlDbType>: data list of the SQL data type, which is used to replace the
?placeholder in the SQL statement
Returns:
- UpdateResult: update result
Throws:
- SqlException: If an exception occurs during the execution, for example, the network is disconnected, the server times out, or the number of parameters is incorrect, this exception is thrown.
interface Transaction
public interface Transaction {
mut prop accessMode: TransactionAccessMode
mut prop deferrableMode: TransactionDeferrableMode
mut prop isoLevel: TransactionIsoLevel
func begin(): Unit
func commit(): Unit
func release(savePointName: String): Unit
func rollback(): Unit
func rollback(savePointName: String): Unit
func save(savePointName: String): Unit
}
Description: Defines the core behavior of database transactions.
Any class, interface, and struct inherited from this interface must comply with the definitions of the input parameters and return values of the functions in this interface.
prop accessMode
mut prop accessMode: TransactionAccessMode
Description: Obtains the access mode of database transactions.
Type: TransactionAccessMode
prop deferrableMode
mut prop deferrableMode: TransactionDeferrableMode
Description: Obtains the delay mode of database transactions.
Type: TransactionDeferrableMode
prop isoLevel
mut prop isoLevel: TransactionIsoLevel
Description: Obtains the isolation level of database transactions.
Type: TransactionIsoLevel
func begin()
func begin(): Unit
Description: Starts a database transaction.
Throws:
- SqlException: If an error occurs on the server, or a transaction is committed or rolled back, or the connection is interrupted, this exception is thrown.
func commit()
func commit(): Unit
Description: Submits a database transaction.
Throws:
- SqlException: If an error occurs on the server, or a transaction is committed or rolled back, or the connection is interrupted, this exception is thrown.
func release(String)
func release(savePointName: String): Unit
Description: Destroys a savepoint previously defined in the current transaction. This allows the system to reclaim some resources before the transaction ends.
Parameters:
- savePointName: String: savepoint name
Throws:
- SqlException: If an error occurs on the server, or a transaction is committed or rolled back, or the connection is interrupted, this exception is thrown.
func rollback()
func rollback(): Unit
Description: Rolls back a transaction from the suspended state.
Throws:
- SqlException: If an error occurs on the server, or a transaction is committed or rolled back, or the connection is interrupted, this exception is thrown.
func rollback(String)
func rollback(savePointName: String): Unit
Description: Rolls back a transaction to a specified savepoint name.
Parameters:
- savePointName: String: savepoint name
Throws:
- SqlException: If an error occurs on the server, or a transaction is committed or rolled back, or the connection is interrupted, this exception is thrown.
func save(String)
func save(savePointName: String): Unit
Description: Creates a savepoint with a specified name in a transaction to roll back transactions after the savepoint.
Parameters:
- savePointName: String: savepoint name
Throws:
- SqlException: If an error occurs on the server, or a transaction is committed or rolled back, or the connection is interrupted, this exception is thrown.
interface UpdateResult
public interface UpdateResult {
prop lastInsertId: Int64
prop rowCount: Int64
}
Description: Specifies the interface used to update the result generated by executing the Insert, Update, and Delete statements.
Any class, interface, and struct inherited from this interface must comply with the definitions of the input parameters and return values of the functions in this interface.
prop lastInsertId
prop lastInsertId: Int64
Description: Obtains the last row ID automatically generated by executing the Insert statement. If the row ID cannot be obtained in this way, the row ID is 0.
Type: Int64
prop rowCount
prop rowCount: Int64
Description: Specifies the number of rows affected by executing the INSERT, UPDATE, or DELETE statements.
Type: Int64
Class
class DriverManager
public class DriverManager
Description: Obtains the database driver instance according to a driver name during running.
static func deregister(String)
public static func deregister(driverName: String): Unit
Description: Deregisters a database driver by name (if any). This function is secure in concurrency.
Parameters:
- driverName: String: driver name
static func drivers()
public static func drivers(): Array<String>
Description: Returns the list of registered database driver names (sorted in lexicographic order). This method is secure in concurrency.
Returns:
static func getDriver(String)
public static func getDriver(driverName: String): Option<Driver>
Description: Obtains a registered database driver by name. If the database driver does not exist, None is returned. This function is secure in concurrency.
Parameters:
- driverName: String: driver name
Returns:
- Option<Driver>: If the driver exists, the driver instance wrapped by Option is returned. Otherwise,
Noneis returned.
static func register(String, Driver)
public static func register(driverName: String, driver: Driver): Unit
Description: Registers a database driver by name and driver instance. Each name corresponds to one instance. This method is secure in concurrency.
Parameters:
Throws:
- SqlException: If the name is duplicate and has been registered, this exception is thrown.
class PooledDatasource
public class PooledDatasource <: Datasource {
public init(datasource: Datasource)
}
Description: Specifies a database connection pool class, which provides the database connection pool capability.
Parent Type:
prop connectionTimeout
public mut prop connectionTimeout: Duration
Description: Obtains or sets the timeout for obtaining a connection from the pool.
Type: Duration
Throws:
- ArithmeticException: If the attribute is set to Duration.Max or Duration.Min, this exception is thrown.
- SqlException: Upon timeout, this exception is thrown.
prop idleTimeout
public mut prop idleTimeout: Duration
Description: Obtains or sets the maximum duration that a connection can be idle in the pool. If this duration is exceeded, the connection may be reclaimed.
Type: Duration
prop keepaliveTime
public mut prop keepaliveTime: Duration
Description: Obtains or sets the interval for checking the health status of an idle connection to prevent it from being timed out by the database or network infrastructure.
Type: Duration
prop maxIdleSize
public mut prop maxIdleSize: Int32
Description: Obtains or sets the maximum number of idle connections. If the number of idle connections exceeds the maximum, the excess connections will be closed. A negative number or 0 indicates that the number is not limited.
Type: Int32
prop maxLifeTime
public mut prop maxLifeTime: Duration
Description: Obtains or sets the duration since a connection is created. After the duration, the connection is automatically closed.
Type: Duration
prop maxSize
public mut prop maxSize: Int32
Description: Obtains or sets the maximum number of connections in the connection pool. A negative number or 0 indicates that the number is not limited.
Type: Int32
init(DataSource)
public init(datasource: Datasource)
Description: Constructs a PooledDatasource instance using the datasource. The input parameter must be a Datasource object.
Parameters:
- datasource: Datasource: datasource
func close()
public func close(): Unit
Description: Closes all connections in a connection pool and blocks other connection requests. If this function is called, all connections are blocked until they are closed and returned to the connection pool.
func connect()
public func connect(): Connection
Description: Obtains a connection.
Returns:
- Connection: obtained connection
func isClosed()
public func isClosed(): Bool
Description: Checks whether a connection is closed.
Returns:
- Bool: whether the connection is closed.
func setOption(String, String)
public func setOption(key: String, value: String): Unit
Description: Sets the database driver connection option (the public key is predefined in SqlOption).
Parameters:
class SqlBigInt
public class SqlBigInt <: SqlDbType {
public init(v: Int64)
}
Description: Specifies a large integer corresponding to the Cangjie Int64 type.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlBigInt.
Type: String
prop value
public mut prop value: Int64
Description: Obtains or sets the value of the data.
Type: Int64
init(Int64)
public init(v: Int64)
Description: Constructs a SqlBigInt instance based on the input parameter v.
Parameters:
- v: Int64: data passed
class SqlBinary
public class SqlBinary <: SqlDbType {
public init(v: Array<Byte>)
}
Description: Specifies a fixed-length binary string corresponding to the Cangjie Array<Byte> type.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlBinary.
Type: String
prop value
public mut prop value: Array<Byte>
Description: Obtains or sets the value of the data.
init(Array<Byte>)
public init(v: Array<Byte>)
Description: Constructs a SqlBinary instance based on the input parameter v.
Parameters:
class SqlBlob
public class SqlBlob <: SqlDbType {
public init(v: InputStream)
}
Description: Specifies an excessively large variable-length binary string (binary large object) corresponding to the Cangjie InputStream type.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlBlob.
Type: String
prop value
public mut prop value: InputStream
Description: Obtains or sets the value of the data.
Type: InputStream
init(InputStream)
public init(v: InputStream)
Description: Constructs a SqlBlob instance based on the input parameter v.
Parameters:
- v: InputStream: data passed
class SqlBool
public class SqlBool <: SqlDbType {
public init(v: Bool)
}
Description: Specifies a Boolean type corresponding to the Cangjie Bool type.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlBool.
Type: String
prop value
public mut prop value: Bool
Description: Obtains or sets the value of the data.
Type: Bool
init(Bool)
public init(v: Bool)
Description: Constructs a SqlBool instance based on the input parameter v.
Parameters:
- v: Bool: data passed
class SqlByte
public class SqlByte <: SqlDbType {
public init(v: Int8)
}
Description: Specifies a byte corresponding to the Cangjie Int8 type.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlByte.
Type: String
prop value
public mut prop value: Int8
Description: Obtains or sets the value of the data.
Type: Int8
init(Int8)
public init(v: Int8)
Description: Constructs a SqlByte instance based on the input parameter v.
Parameters:
- v: Int8: data passed
class SqlChar
public class SqlChar <: SqlDbType {
public init(v: String)
}
Description: Specifies a fixed-length string corresponding to the Cangjie String type.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlChar.
Type: String
prop value
public mut prop value: String
Description: Obtains or sets the value of the data.
Type: String
init(String)
public init(v: String)
Description: Constructs a SqlChar instance based on the input parameter v.
Parameters:
- v: String: data passed
class SqlClob
public class SqlClob <: SqlDbType {
public init(v: InputStream)
}
Description: Specifies an excessively large variable-length string (rune large object) corresponding to the Cangjie InputStream type.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlClob.
Type: String
prop value
public mut prop value: InputStream
Description: Obtains or sets the value of the data.
Type: InputStream
init(InputStream)
public init(v: InputStream)
Description: Constructs a SqlClob instance based on the input parameter v.
Parameters:
- v: InputStream: data passed
class SqlDate
public class SqlDate <: SqlDbType {
public init(v: DateTime)
}
Description: Specifies a date, which must be in the format of YYYY-MM-DD and corresponds to the Cangjie DateTime type.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlDate.
Type: String
prop value
public mut prop value: DateTime
Description: Obtains or sets the value of the data.
Type: DateTime
init(DateTime)
public init(v: DateTime)
Description: Constructs a SqlDate instance based on the input parameter v.
Parameters:
- v: DateTime: data passed
class SqlDecimal
public class SqlDecimal <: SqlDbType {
public init(v: Decimal)
}
Description: Specifies a high-precision number corresponding to the Cangjie Decimal type.
Parent Type:
prop name
public prop name: String
Description: Specifies a type name, that is, SqlDecimal.
Type: String
prop value
public mut prop value: Decimal
Description: Obtains the value of the data.
Type: Decimal
init(Decimal)
public init(v: Decimal)
Description: Constructs an SqlDecimal instance based on the input parameter v.
Parameters:
- v: Decimal: input data
class SqlDouble
public class SqlDouble <: SqlDbType {
public init(v: Float64)
}
Description: Specifies a double-precision number corresponding to the Cangjie Float64 type.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlDouble.
Type: String
prop value
public mut prop value: Float64
Description: Obtains or sets the value of the data.
Type: Float64
init(Float64)
public init(v: Float64)
Description: Constructs a SqlDouble instance based on the input parameter v.
Parameters:
- v: Float64: data passed
class SqlInteger
public class SqlInteger <: SqlDbType {
public init(v: Int32)
}
Description: Specifies a medium integer corresponding to the Cangjie Int32 type.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlInteger.
Type: String
prop value
public mut prop value: Int32
Description: Obtains or sets the value of the data.
Type: Int32
init(Int32)
public init(v: Int32)
Description: Constructs a SqlInteger instance based on the input parameter v.
Parameters:
- v: Int32: data passed
class SqlInterval
public class SqlInterval <: SqlDbType {
public init(v: Duration)
}
Description: Specifies the time interval corresponding to the Cangjie Duration type.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlInterval.
Type: String
prop value
public mut prop value: Duration
Description: Obtains or sets the value of the data.
Type: Duration
init(Duration)
public init(v: Duration)
Description: Constructs a SqlInterval instance based on the input parameter v.
Parameters:
- v: Duration: data passed
class SqlNullableBigInt
public class SqlNullableBigInt <: SqlNullableDbType {
public init(v: ?Int64)
}
Description: Specifies a large integer corresponding to the Cangjie Int64 type, which can be a Null value in the database.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlNullableBigInt.
Type: String
prop value
public mut prop value: ?Int64
Description: Obtains or sets the value of the data.
Type: ?Int64
init(?Int64)
public init(v: ?Int64)
Description: Constructs a SqlNullableBigInt instance based on the input parameter v.
Parameters:
- v: ?Int64: data passed
class SqlNullableBinary
public class SqlNullableBinary <: SqlNullableDbType {
public init(v: ?Array<Byte>)
}
Description: Specifies a fixed-length binary string corresponding to the Cangjie Array<Byte> type, which can be a Null value in the database.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlNullableBinary.
Type: String
prop value
public mut prop value: ?Array<Byte>
Description: Obtains or sets the value of the data.
init(?Array<Byte>)
public init(v: ?Array<Byte>)
Description: Constructs a SqlNullableBinary instance based on the input parameter v.
Parameters:
class SqlNullableBlob
public class SqlNullableBlob <: SqlNullableDbType {
public init(v: ?InputStream)
}
Description: Specifies an excessively large variable-length binary string (binary large object) corresponding to the Cangjie InputStream type, which can be a Null value in the database.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlNullableBlob.
Type: String
prop value
public mut prop value: ?InputStream
Description: Obtains or sets the value of the data.
Type: ?InputStream
init(?InputStream)
public init(v: ?InputStream)
Description: Constructs a SqlNullableBlob instance based on the input parameter v.
Parameters:
- v: ?InputStream: data passed
class SqlNullableBool
public class SqlNullableBool <: SqlNullableDbType {
public init(v: ?Bool)
}
Description: Specifies a Boolean type corresponding to the Cangjie Bool type, which can be a Null value in the database.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlNullableBool.
Type: String
prop value
public mut prop value: ?Bool
Description: Obtains or sets the value of the data.
Type: ?Bool
init(?Bool)
public init(v: ?Bool)
Description: Constructs a SqlNullableBool instance based on the input parameter v.
Parameters:
- v: ?Bool: data passed
class SqlNullableByte
public class SqlNullableByte <: SqlNullableDbType {
public init(v: ?Int8)
}
Description: Specifies a byte corresponding to the Cangjie Int8 type, which can be a Null value in the database.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlNullableByte.
Type: String
prop value
public mut prop value: ?Int8
Description: Obtains or sets the value of the data.
Type: ?Int8
init(?Int8)
public init(v: ?Int8)
Description: Constructs a SqlNullableByte instance based on the input parameter v.
Parameters:
- v: ?Int8: data passed
class SqlNullableChar
public class SqlNullableChar <: SqlNullableDbType {
public init(v: ?String)
}
Description: Specifies a fixed-length string corresponding to the Cangjie String type, which can be a Null value in the database.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlNullableChar.
Type: String
prop value
public mut prop value: ?String
Description: Obtains or sets the value of the data.
Type: ?String
init(?String)
public init(v: ?String)
Description: Constructs a SqlNullableChar instance based on the input parameter v.
Parameters:
- v: ?String: data passed
class SqlNullableClob
public class SqlNullableClob <: SqlNullableDbType {
public init(v: ?InputStream)
}
Description: Specifies an excessively large variable-length string (rune large object) corresponding to the Cangjie InputStream type, which can be a Null value in the database.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlNullableClob.
Type: String
prop value
public mut prop value: ?InputStream
Description: Obtains or sets the value of the data.
Type: ?InputStream
init(?InputStream)
public init(v: ?InputStream)
Description: Constructs a SqlNullableClob instance based on the input parameter v.
Parameters:
- v: ?InputStream: data passed
class SqlNullableDate
public class SqlNullableDate <: SqlNullableDbType {
public init(v: ?DateTime)
}
Description: Specifies a date, which must be in the format of YYYY-MM-DD, corresponds to the Cangjie DateTime type, and can be a Null value in the database.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlNullableDate.
Type: String
prop value
public mut prop value: ?DateTime
Description: Obtains or sets the value of the data.
Type: ?DateTime
init(?DateTime)
public init(v: ?DateTime)
Description: Constructs a SqlNullableDate instance based on the input parameter v.
Parameters:
- v: ?DateTime: data passed
class SqlNullableDecimal
public class SqlNullableDecimal <: SqlNullableDbType {
public init(v: ?Decimal)
}
Description: Specifies a high-precision number corresponding to the Cangjie Decimal type, which can be a Null value in the database.
Parent Type:
prop name
public prop name: String
Description: Specifies a type name, that is, SqlNullableDecimal.
Type: String
prop value
public mut prop value: ?Decimal
Description: Obtains the value of the data.
Type: ?Decimal
init(?Decimal)
public init(v: ?Decimal)
Description: Constructs a SqlNullableDecimal instance based on the input parameter v.
Parameters:
- v: ?Decimal: input data
class SqlNullableDouble
public class SqlNullableDouble <: SqlNullableDbType {
public init(v: ?Float64)
}
Description: Specifies a double-precision number corresponding to the Cangjie Float64 type, which can be a Null value in the database.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlNullableDouble.
Type: String
prop value
public mut prop value: ?Float64
Description: Obtains or sets the value of the data.
Type: ?Float64
init(?Float64)
public init(v: ?Float64)
Description: Constructs a SqlNullableDouble instance based on the input parameter v.
Parameters:
- v: ?Float64: data passed
class SqlNullableInteger
public class SqlNullableInteger <: SqlNullableDbType {
public init(v: ?Int32)
}
Description: Specifies a medium integer corresponding to the Cangjie Int32 type, which can be a Null value in the database.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlNullableInteger.
Type: String
prop value
public mut prop value: ?Int32
Description: Obtains or sets the value of the data.
Type: ?Int32
init(?Int32)
public init(v: ?Int32)
Description: Constructs a SqlNullableInteger instance based on the input parameter v.
Parameters:
- v: ?Int32: data passed
class SqlNullableInterval
public class SqlNullableInterval <: SqlNullableDbType {
public init(v: ?Duration)
}
Description: Specifies the time interval corresponding to the Cangjie Duration type, which can be a Null value in the database.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlNullableInterval.
Type: String
prop value
public mut prop value: ?Duration
Description: Obtains or sets the value of the data.
Type: ?Duration
init(?Duration)
public init(v: ?Duration)
Description: Constructs a SqlNullableInterval instance based on the input parameter v.
Parameters:
- v: ?Duration: data passed
class SqlNullableReal
public class SqlNullableReal <: SqlNullableDbType {
public init(v: ?Float32)
}
Description: Specifies a floating-point number corresponding to the Cangjie Float32 type, which can be a Null value in the database.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlNullableReal.
Type: String
prop value
public mut prop value: ?Float32
Description: Obtains or sets the value of the data.
Type: ?Float32
init(?Float32)
public init(v: ?Float32)
Description: Constructs a SqlNullableReal instance based on the input parameter v.
Parameters:
- v: ?Float32: data passed
class SqlNullableSmallInt
public class SqlNullableSmallInt <: SqlNullableDbType {
public init(v: ?Int16)
}
Description: Specifies a small integer corresponding to the Cangjie Int16 type, which can be a Null value in the database.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlNullableSmallInt.
Type: String
prop value
public mut prop value: ?Int16
Description: Obtains or sets the value of the data.
Type: ?Int16
init(?Int16)
public init(v: ?Int16)
Description: Constructs a SqlNullableSmallInt instance based on the input parameter v.
Parameters:
- v: ?Int16: data passed
class SqlNullableTime
public class SqlNullableTime <: SqlNullableDbType {
public init(v: ?DateTime)
}
Description: Specifies the time, which must be in the format of HH:MM:SS.SSS, corresponds to the Cangjie DateTime type, and can be a Null value in the database.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlNullableTime.
Type: String
prop value
public mut prop value: ?DateTime
Description: Obtains or sets the value of the data.
Type: ?DateTime
init(?DateTime)
public init(v: ?DateTime)
Description: Constructs a SqlNullableTime instance based on the input parameter v.
Parameters:
- v: ?DateTime: data passed
class SqlNullableTimeTz
public class SqlNullableTimeTz <: SqlNullableDbType {
public init(v: ?DateTime)
}
Description: Specifies the time with a time zone, which must be in the format of HH:MM:SS.SSS, corresponds to the Cangjie DateTime type, and can be a Null value in the database.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlNullableTimeTz.
Type: String
prop value
public mut prop value: ?DateTime
Description: Obtains or sets the value of the data.
Type: ?DateTime
init(?DateTime)
public init(v: ?DateTime)
Description: Constructs a SqlNullableTimeTz instance based on the input parameter v.
Parameters:
- v: ?DateTime: data passed
class SqlNullableTimestamp
public class SqlNullableTimestamp <: SqlNullableDbType {
public init(v: ?DateTime)
}
Description: Specifies a timestamp corresponding to the Cangjie DateTime type, which can be a Null value in the database.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlNullableTimestamp.
Type: String
prop value
public mut prop value: ?DateTime
Description: Obtains or sets the value of the data.
Type: ?DateTime
init(?DateTime)
public init(v: ?DateTime)
Description: Constructs a SqlNullableTimestamp instance based on the input parameter v.
Parameters:
- v: ?DateTime: data passed
class SqlNullableVarBinary
public class SqlNullableVarBinary <: SqlNullableDbType {
public init(v: ?Array<Byte>)
}
Description: Specifies a variable-length binary string corresponding to the Cangjie Array<Byte> type, which can be a Null value in the database.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlNullableVarBinary.
Type: String
prop value
public mut prop value: ?Array<Byte>
Description: Obtains or sets the value of the data.
init(?Array<Byte>)
public init(v: ?Array<Byte>)
Description: Constructs a SqlNullableVarBinary instance based on the input parameter v.
Parameters:
class SqlNullableVarchar
public class SqlNullableVarchar <: SqlNullableDbType {
public init(v: ?String)
}
Description: Specifies a variable-length string corresponding to the Cangjie String type, which can be a Null value in the database.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlNullableVarchar.
Type: String
prop value
public mut prop value: ?String
Description: Obtains or sets the value of the data. Type: ?String
init(?String)
public init(v: ?String)
Description: Constructs a SqlNullableVarchar instance based on the input parameter v.
Parameters:
- v: ?String: data passed
class SqlOption
public class SqlOption
Description: Specifies the predefined SQL option names and values. If extension is required, do not conflict with these names and values.
static const ConnectionTimeout
public static const ConnectionTimeout = "connection_timeout"
Description: Obtains the timeout of the connect operation, in ms.
Type: String
static const Database
public static const Database = "database"
Description: Obtains the database name.
Type: String
static const Driver
public static const Driver = "driver"
Description: Obtains the database driver name, for example, postgres or opengauss.
Type: String
static const Encoding
public static const Encoding = "encoding"
Description: Obtains the database character set encoding type.
Type: String
static const FetchRows
public static const FetchRows = "fetch_rows"
Description: Obtains the number of rows extracted from the database when extra rows need to be obtained.
Type: String
static const Host
public static const Host = "host"
Description: Obtains the host name or IP address of a database server.
Type: String
static const Password
public static const Password = "password"
Description: Obtains the password for connecting to a database.
Type: String
static const QueryTimeout
public static const QueryTimeout = "query_timeout"
Description: Obtains the timeout of the query operation, in ms.
Type: String
static const SSLCA
public static const SSLCA = "ssl.ca"
Description: Specifies the path of the certificate authority (CA) certificate file.
Type: String
static const SSLCert
public static const SSLCert = "ssl.cert"
Description: Specifies the path of the client SSL public key certificate file.
Type: String
static const SSLKey
public static const SSLKey = "ssl.key"
Description: Specifies the path of the client SSL private key file.
Type: String
static const SSLKeyPassword
public static const SSLKeyPassword = "ssl.key.password"
Description: Specifies the password of the client SSL private key file.
Type: String
static const SSLMode
public static const SSLMode = "ssl.mode"
Description: Obtains the transport layer encryption mode SSLMode.
Type: String
static const SSLModeDisabled
public static const SSLModeDisabled = "ssl.mode.disabled"
Description: Establishes an unencrypted connection.
Type: String
static const SSLModePreferred
public static const SSLModePreferred = "ssl.mode.preferred"
Description: Establishes an encrypted connection if the server supports an encrypted connection; and rolls back to an unencrypted connection if the encrypted connection cannot be established. This is the default value of SSLMode.
Type: String
static const SSLModeRequired
public static const SSLModeRequired = "ssl.mode.required"
Description: Establishes an encrypted connection if the server supports an encrypted connection. If the encrypted connection cannot be established, the connection fails.
Type: String
static const SSLModeVerifyCA
public static const SSLModeVerifyCA = "ssl.mode.verify_ca"
Description: Specifies that SSLModeVerifyCA is similar to SSLModeRequired, with server certificate verification added. If the verification fails, the connection fails.
Type: String
static const SSLModeVerifyFull
public static const SSLModeVerifyFull = "ssl.mode.verify_full"
Description: Specifies that SSLModeVerifyFull is similar to SSLModeVerifyCA, with host name authentication being performed by checking the host name used by the client to connect to the server against the identifier in the certificate sent by the server to the client.
Type: String
static const SSLSni
public static const SSLSni = "ssl.sni"
Description: Identifies the host name to which a client attempts to connect using the identifier upon handshake.
Type: String
static const Tls12Ciphersuites
public static const Tls12Ciphersuites = "tls1.2.ciphersuites"
Description: Specifies the cipher suites that can be used by a client for encrypted connections using TLSv1.2 or later. The value is a string separated by colons, for example, "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:TLS_DHE_RSA_WITH_AES_128_CBC_SHA".
Type: String
static const Tls13Ciphersuites
public static const Tls13Ciphersuites = "tls1.3.ciphersuites"
Description: Specifies the cipher suites that can be used by a client for encrypted connections using TLSv1.3. The value is a string separated by colons, for example, "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256".
Type: String
static const TlsVersion
public static const TlsVersion = "tls.version"
Description: Specifies the supported TLS version. The value is a string separated by commas, for example, "TLSv1.2,TLSv1.3".
Type: String
static const URL
public static const URL = "url"
Description: Obtains the URL string of a database connection.
Type: String
static const UpdateTimeout
public static const UpdateTimeout = "update_timeout"
Description: Obtains the timeout of the update operation, in ms.
Type: String
static const Username
public static const Username = "username"
Description: Obtains the username for connecting to a database.
Type: String
class SqlReal
public class SqlReal <: SqlDbType {
public init(v: Float32)
}
Description: Specifies a floating-point number corresponding to the Cangjie Float32 type.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlReal.
Type: String
prop value
public mut prop value: Float32
Description: Obtains or sets the value of the data.
Type: Float32
init(Float32)
public init(v: Float32)
Description: Constructs a SqlReal instance based on the input parameter v.
Parameters:
- v: Float32: data passed
class SqlSmallInt
public class SqlSmallInt <: SqlDbType {
public init(v: Int16)
}
Description: Specifies a small integer corresponding to the Cangjie Int16 type.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlSmallInt.
Type: String
prop value
public mut prop value: Int16
Description: Obtains or sets the value of the data.
Type: Int16
init(Int16)
public init(v: Int16)
Description: Constructs a SqlSmallInt instance based on the input parameter v.
Parameters:
- v: Int16: data passed
class SqlTime
public class SqlTime <: SqlDbType {
public init(v: DateTime)
}
Description: Specifies the time, which must be in the format of HH:MM:SS.SSS and corresponds to the Cangjie DateTime type.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlTime.
Type: String
prop value
public mut prop value: DateTime
Description: Obtains or sets the value of the data.
Type: DateTime
init(DateTime)
public init(v: DateTime)
Description: Constructs a SqlTime instance based on the input parameter v.
Parameters:
- v: DateTime: data passed
class SqlTimeTz
public class SqlTimeTz <: SqlDbType {
public init(v: DateTime)
}
Description: Specifies the time with a time zone, which must be in the format of HH:MM:SS.SSS and corresponds to the Cangjie DateTime type.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlTimeTz.
Type: String
prop value
public mut prop value: DateTime
Description: Obtains or sets the value of the data.
Type: DateTime
init(DateTime)
public init(v: DateTime)
Description: Constructs a SqlTimeTz instance based on the input parameter v.
Parameters:
- v: DateTime: data passed
class SqlTimestamp
public class SqlTimestamp <: SqlDbType {
public init(v: DateTime)
}
Description: Specifies a timestamp corresponding to the Cangjie DateTime type.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlTimestamp.
Type: String
prop value
public mut prop value: DateTime
Description: Obtains or sets the value of the data.
Type: DateTime
init(DateTime)
public init(v: DateTime)
Description: Constructs a SqlTimestamp instance based on the input parameter v.
Parameters:
- v: DateTime: data passed
class SqlVarBinary
public class SqlVarBinary <: SqlDbType {
public init(v: Array<Byte>)
}
Description: Specifies a variable-length binary string corresponding to the Cangjie Array<Byte> type.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlVarBinary.
Type: String
prop value
public mut prop value: Array<Byte>
Description: Obtains or sets the value of the data.
init(Array<Byte>)
public init(v: Array<Byte>)
Description: Constructs a SqlVarBinary instance based on the input parameter v.
Parameters:
class SqlVarchar
public class SqlVarchar <: SqlDbType {
public init(v: String)
}
Description: Specifies a variable-length string corresponding to the Cangjie String type.
Parent Type:
prop name
public prop name: String
Description: Obtains the type name, that is, SqlVarchar.
Type: String
prop value
public mut prop value: String
Description: Obtains or sets the value of the data.
Type: String
init(String)
public init(v: String)
Description: Constructs a SqlVarchar instance based on the input parameter v.
Parameters:
- v: String: data passed
Enumeration
enum ConnectionState
public enum ConnectionState <: Equatable<ConnectionState> {
| Broken
| Closed
| Connecting
| Connected
}
Description: Describes the current status of the connection to the data source.
Parent Type:
Broken
Broken
Description: Indicates that the connection to the data source is interrupted. This situation may occur only after the connection is set up.
Closed
Closed
Description: Indicates that the connection object is closed.
Connected
Connected
Description: Indicates that the connection object has been connected to the data source.
Connecting
Connecting
Description: Indicates that the connection object is connecting to the data source.
operator func !=(ConnectionState)
public operator func !=(rhs: ConnectionState): Bool
Description: Checks whether the passed connection status of a data source is different from the current status.
Parameters:
- rhs: ConnectionState: connection status of a data source
Returns:
- Bool: If the passed connection status of the data source is the same as the current status,
falseis returned. Otherwise,trueis returned.
operator func ==(ConnectionState)
public operator func ==(rhs: ConnectionState): Bool
Description: Checks whether the passed connection status of a data source is the same as the current status.
Parameters:
- rhs: ConnectionState: connection status of a data source
Returns:
- Bool: If the passed connection status of the data source is the same as the current status,
trueis returned. Otherwise,falseis returned.
enum TransactionAccessMode
public enum TransactionAccessMode <: ToString & Hashable & Equatable<TransactionAccessMode> {
| ReadOnly
| ReadWrite
| Unspecified
}
Description: Indicates the transaction read/write mode.
Parent Type:
ReadOnly
ReadOnly
Description: Indicates the read-only mode.
ReadWrite
ReadWrite
Description: Indicates the read/write mode.
Unspecified
Unspecified
Description: Indicates an unspecified transaction read/write mode whose behaviors depend on the specific database server.
func hashCode()
public func hashCode(): Int64
Description: Obtains the hash value of the transaction read/write mode.
Returns:
- Int64: hash value of the transaction read/write mode
func toString()
public func toString(): String
Description: Returns the string representation of the transaction read/write mode. The following table lists the mapping between enumerated values and strings.
| Enumerated Value | String |
|---|---|
| ReadOnly | "Read Only" |
| ReadWrite | "Read Write" |
| Unspecified | "Unspecified" |
Returns:
- String: string of the transaction read/write mode
operator func !=(TransactionAccessMode)
public operator func != (rhs: TransactionAccessMode): Bool
Description: Checks whether two TransactionAccessMode instances are not equal.
Parameters:
- rhs: TransactionAccessMode: enumerated value of TransactionAccessMode
Returns:
- Bool: If the two instances are not equal,
trueis returned. Otherwise,falseis returned.
operator func ==(TransactionAccessMode)
public operator func == (rhs: TransactionAccessMode): Bool
Description: Checks whether two TransactionAccessMode instances are equal.
Parameters:
- rhs: TransactionAccessMode: enumerated value of TransactionAccessMode
Returns:
- Bool: If the two instances are equal,
trueis returned. Otherwise,falseis returned.
enum TransactionDeferrableMode
public enum TransactionDeferrableMode <: ToString & Hashable & Equatable<TransactionDeferrableMode> {
| Deferrable
| NotDeferrable
| Unspecified
}
Description: Indicates the transaction delay mode.
Parent Type:
Deferrable
Deferrable
Description: Indicates that a transaction is deferrable.
Note:
A delayed transaction is a transaction that is not committed at the end of the rollforward phase and encounters an error that prevents it from being rolled back. The transaction is delayed because it cannot be rolled back.
NotDeferrable
NotDeferrable
Description: Indicates that a transaction is not deferrable.
Unspecified
Unspecified
Description: Indicates an unspecified transaction delay mode whose behaviors depend on the specific database server.
func hashCode()
public func hashCode(): Int64
Description: Obtains the hash value of the transaction delay mode.
Returns:
- Int64: hash value of the transaction delay mode
func toString()
public func toString(): String
Description: Returns the string representation of the transaction delay mode. The following table lists the mapping between enumerated values and strings.
| Enumerated Value | String |
|---|---|
| Deferrable | "Deferrable" |
| NotDeferrable | "Not Deferrable" |
| Unspecified | "Unspecified" |
Returns:
- String: string of the transaction delay mode
operator func !=(TransactionDeferrableMode)
public operator func != (rhs: TransactionDeferrableMode): Bool
Description: Checks whether two TransactionDeferrableMode instances are not equal.
Parameters:
- rhs: TransactionDeferrableMode: enumerated value of TransactionDeferrableMode.
Returns:
- Bool: If the two instances are not equal,
trueis returned. Otherwise,falseis returned.
operator func ==(TransactionDeferrableMode)
public operator func == (rhs: TransactionDeferrableMode): Bool
Description: Checks whether two TransactionDeferrableMode instances are equal.
Parameters:
- rhs: TransactionDeferrableMode: enumerated value of TransactionDeferrableMode.
Returns:
- Bool: If the two instances are equal,
trueis returned. Otherwise,falseis returned.
enum TransactionIsoLevel
public enum TransactionIsoLevel <: ToString & Hashable & Equatable<TransactionIsoLevel> {
| Chaos
| Linearizable
| ReadCommitted
| ReadUncommitted
| RepeatableRead
| Serializable
| Snapshot
| Unspecified
}
Description: Indicates the transaction isolation level.
Note:
Transaction isolation defines when and how the result of an operation in a transaction is visible to other concurrent transaction operations in the database system.
Parent Type:
Chaos
Chaos
Description: Indicates that suspended changes from a transaction with a higher isolation level cannot be overwritten.
Linearizable
Linearizable
Description: Linearizes a transaction.
Note:
Different from serialization (Serializable), linearization focuses on a group of single operations (such as a series of read and write operations) on a single object (that is, a db row or nosql record) and ensures that these operations are performed in the actual time sequence. For example, when you view a subset of operations on a single object that is linearized, you will find out that these operations are relevant.
ReadCommitted
ReadCommitted
Description: Indicates that a transaction waits until the row locked by another transaction is unlocked. This prevents the transaction from reading any dirty data.
ReadUncommitted
ReadUncommitted
Description: Indicates that transactions are not isolated from each other.
RepeatableRead
RepeatableRead
Description: Indicates that a transaction can be read repeatedly. The results of multiple reads on the same field are the same unless the data is modified by the transaction itself.
Serializable
Serializable
Description: Serializes a transaction. All transactions of this isolation level are executed in sequence. Therefore, dirty reads, non-repeatable reads, and phantom reads do not occur.
Snapshot
Snapshot
Description: Indicates that a transaction of the snapshot isolation level avoids most locks and blocks by using row versioning.
Unspecified
Unspecified
Description: Indicates an unspecified transaction isolation level whose behaviors depend on the specific database server.
func hashCode()
public func hashCode(): Int64
Description: Obtains the hash value of a transaction isolation level.
Returns:
- Int64: hash value of the transaction isolation level
func toString()
public func toString(): String
Description: Returns the string representation of a transaction isolation level. The following table lists the mapping between enumerated values and strings.
| Enumerated Value | String |
|---|---|
| Chaos | "Chaos" |
| Linearizable | "Linearizable" |
| ReadCommitted | "Read Committed" |
| ReadUncommitted | "Read Uncommitted" |
| RepeatableRead | "Repeatable Read" |
| Serializable | "Serializable" |
| Snapshot | "Snapshot" |
| Unspecified | "Unspecified" |
Returns:
- String: string of the transaction isolation level
operator func !=(TransactionIsoLevel)
public operator func != (rhs: TransactionIsoLevel): Bool
Description: Checks whether two TransactionIsoLevel instances are not equal.
Parameters:
- rhs: TransactionIsoLevel: TransactionIsoLevel passed
Returns:
- Bool: If the two instances are not equal,
trueis returned. Otherwise,falseis returned.
operator func ==(TransactionIsoLevel)
public operator func == (rhs: TransactionIsoLevel): Bool
Description: Checks whether two TransactionIsoLevel instances are equal.
Parameters:
- rhs: TransactionIsoLevel: TransactionIsoLevel passed
Returns:
- Bool: If the two instances are equal,
trueis returned. Otherwise,falseis returned.
Exception Class
class SqlException
public open class SqlException <: Exception
Description: Handles SQL-related exceptions.
Parent Type:
prop errorCode
public prop errorCode: Int64
Description: Obtains an integer error code returned by the database vendor.
Type: Int64
prop message
public override prop message: String
Description: Obtains the exception information string.
Type: String
prop sqlState
public prop sqlState: String
Description: Obtains a string of five characters indicating the status of the last SQL statement returned by the database system.
Type: String
init()
public init()
Description: Specifies a constructor without parameters.
init(String)
public init(message: String)
Description: Creates a SqlException instance according to exception information.
Parameters:
- message: String: exception information
init(String, String, Int64)
public init(message: String, sqlState: String, errorCode: Int64)
Description: Creates a SqlException instance according to exception information, SQL statement status, and error code information.
Parameters:
- message: String: exception information
- sqlState: String: string of five characters indicating the status of the last SQL statement returned by the database system
- errorCode: Int64: integer error code returned by the database vendor
Example of Implementing the Query Function for A Database Driver
For the database driver provider, the sample code for implementing the query function is as follows:
import std.database.sql.*
import std.sync.*
// Implements the QueryResult interface.
public class Rows <: QueryResult {
let closed = AtomicBool(false)
public func close(): Unit {
if (isClosed()) {
return
}
closed.store(true)
}
public func isClosed(): Bool {
closed.load()
}
public prop columnInfos: Array<ColumnInfo> {
get() {
[]
}
}
public func next(values: Array<SqlDbType>): Bool {
for (idx in 0..values.size) {
match (values[idx]) {
case v: SqlBigInt => v.value = 100
case v: SqlVarchar => v.value = "foo"
case v: SqlNullableTimestamp => v.value = None
case _ => ()
}
}
return false
}
}
Example of Obtaining Database Connection
import std.database.sql.*
main() {
// Obtains the registered driver.
let drv = DriverManager.getDriver("opengauss") ?? return
// Sets options for opening the data source.
let opts = [
("cachePrepStmts", "true"),
("prepStmtCacheSize", "250"),
("prepStmtCacheSqlLimit", "2048")
]
// Opens the data source using the connection path and options.
let ds = drv.open("opengauss://testuser:testpwd@localhost:5432/testdb", opts)
// Sets connection options.
ds.setOption(SqlOption.SSLMode, SqlOption.SSLModeVerifyCA)
ds.setOption(SqlOption.SSLCA, "ca.crt")
ds.setOption(SqlOption.SSLCert, "server.crt")
ds.setOption(SqlOption.SSLKey, "server.key")
ds.setOption(SqlOption.SSLKeyPassword, "key_password")
ds.setOption(SqlOption.TlsVersion, "TLSv1.2,TLSv1.3")
// Returns an available connection.
let conn = ds.connect()
}
Example of Deleting and Creating a Table
import std.database.sql.*
main() {
// Example of obtaining the database connection
let drv = DriverManager.getDriver("opengauss") ?? return
let opts = [
("cachePrepStmts", "true"),
("prepStmtCacheSize", "250"),
("prepStmtCacheSqlLimit", "2048")
]
let ds = drv.open("opengauss://testuser:testpwd@localhost:5432/testdb", opts)
let conn = ds.connect()
// Deletes and creates a table.
var stmt = conn.prepareStatement("DROP TABLE IF EXISTS test")
var ur = stmt.update()
println("Update Result: ${ur.rowCount} ${ur.lastInsertId}")
stmt.close()
stmt = conn.prepareStatement("CREATE TABLE test(id SERIAL PRIMARY KEY, name VARCHAR(20) NOT NULL, age INT)")
ur = stmt.update()
println("Update Result: ${ur.rowCount} ${ur.lastInsertId}")
stmt.close()
}
Example of Executing Database Operation Statements
Inserting Data
import std.database.sql.*
main() {
// Example of obtaining the database connection
let drv = DriverManager.getDriver("opengauss") ?? return
let ds = drv.open("opengauss://testuser:testpwd@localhost:5432/testdb", [])
let conn = ds.connect()
// Example of inserting data
var stmt = conn.prepareStatement("INSERT INTO test VALUES(?, ?)")
var name = SqlVarchar("li lei")
var age = SqlNullableInteger(12)
var ur = stmt.update(name, age)
println("Update Result: ${ur.rowCount} ${ur.lastInsertId}")
name.value = "han meimei"
age.value = 13
ur = stmt.update(name, age)
println("Update Result: ${ur.rowCount} ${ur.lastInsertId}")
// Performs the following operations to return the inserted ID after data is inserted:
let sql = "INSERT INTO test (name, age) VALUES (?,?) RETURNING id, name"
try (stmt = conn.prepareStatement(sql)) {
var name = SqlVarchar("li hua")
var age = SqlNullableInteger(12)
let qr = stmt.query(name, age)
let id = SqlInteger(0)
while (qr.next(id, name)) {
println("id = ${id.value}, name=${name.value}")
}
} catch (e: Exception) {
e.printStackTrace()
}
stmt.close()
}
Querying Data
import std.database.sql.*
main() {
// Example of obtaining the database connection
let drv = DriverManager.getDriver("opengauss") ?? return
let ds = drv.open("opengauss://testuser:testpwd@localhost:5432/testdb", [])
let conn = ds.connect()
// Example of the query operation
var stmt = conn.prepareStatement("select * from test where name = ?")
var name = SqlNullableVarchar("li lei")
let id = SqlInteger(0)
let qr = stmt.query(name)
var age = SqlNullableInteger(0)
while (qr.next(id, name, age)) {
println("id = ${id.value}, name = ${name.value}, age=${age.value}")
}
stmt.close()
}
Updating Data
import std.database.sql.*
main() {
// Example of obtaining the database connection
let drv = DriverManager.getDriver("opengauss") ?? return
let ds = drv.open("opengauss://testuser:testpwd@localhost:5432/testdb", [])
let conn = ds.connect()
// Example of the update operation
var stmt = conn.prepareStatement("update test set age = ? where name = ?")
var age = SqlNullableInteger(15)
var name = SqlNullableVarchar("li lei")
var ur = stmt.update(age, name)
println("Update Result: ${ur.rowCount} ${ur.lastInsertId}")
stmt.close()
}
Deleting Data
import std.database.sql.*
main() {
// Example of obtaining the database connection
let drv = DriverManager.getDriver("opengauss") ?? return
let ds = drv.open("opengauss://testuser:testpwd@localhost:5432/testdb", [])
let conn = ds.connect()
// Example of the deletion operation
var stmt = conn.prepareStatement("delete from test where name = ?")
var name = SqlNullableVarchar("li lei")
var ur = stmt.update(name)
println("Update Result: ${ur.rowCount} ${ur.lastInsertId}")
stmt.close()
}
Example of Executing Transaction Control Statements
Common Database Transaction
import std.database.sql.*
import std.time.*
func test_transaction() {
let SQL_INSERT = "INSERT INTO EMPLOYEE (NAME, SALARY, CREATED_DATE) VALUES (?, ?, ?)"
let SQL_UPDATE = "UPDATE EMPLOYEE SET SALARY=? WHERE NAME=?"
let drv = DriverManager.getDriver("opengauss").getOrThrow()
let db = drv.open("opengauss://localhost:5432/testdb")
try(cn = db.connect()) {
let psInsert = cn.prepareStatement(SQL_INSERT)
let psUpdate = cn.prepareStatement(SQL_UPDATE)
// Creates a transaction object.
let tx = cn.createTransaction()
try {
psInsert.update(SqlChar("mkyong"), SqlBinary(Array<Byte>([10])), SqlTime(DateTime.now()))
psInsert.update(SqlChar("kungfu"), SqlBinary(Array<Byte>([20])), SqlTime(DateTime.now()))
// error, test rollback SQLException: No value specified for parameter 3.
psInsert.update(SqlVarchar("mkyong"), SqlBinary(Array<Byte>([1, 2, 3, 4, 5])))
// Commits the transaction.
tx.commit()
} catch (e1: SqlException) {
e1.printStackTrace()
try {
// Rolls back all transactions when an exception occurs.
tx.rollback()
} catch (e2: SqlException) {
e2.printStackTrace()
}
}
} catch (e: SqlException) {
e.printStackTrace()
}
}
Transaction Savepoint
If the database transaction supports savepoints, refer to the following example:
import std.database.sql.*
import std.time.*
func test_savepoint() {
let SQL_INSERT = "INSERT INTO EMPLOYEE (NAME, SALARY, CREATED_DATE) VALUES (?, ?, ?)"
let SQL_UPDATE = "UPDATE EMPLOYEE SET SALARY=? WHERE NAME=?"
let drv = DriverManager.getDriver("opengauss").getOrThrow()
let db = drv.open("opengauss://localhost:5432/testdb")
try(cn = db.connect()) {
let psInsert = cn.prepareStatement(SQL_INSERT)
let psUpdate = cn.prepareStatement(SQL_UPDATE)
let tx = cn.createTransaction()
try {
// Creates savepoint 1.
tx.save("save1")
psInsert.update([SqlChar("mkyong"), SqlBinary(Array<Byte>([10])), SqlTime(DateTime.now())])
// Creates savepoint 2.
tx.save("save2")
psInsert.update([SqlChar("kungfu"), SqlBinary(Array<Byte>([20])), SqlTime(DateTime.now())])
// Creates savepoint 3.
tx.save("save3")
psInsert.update([SqlVarchar("mkyong"), SqlBinary(Array<Byte>([1, 2, 3, 4, 5]))])
// Rolls back to savepoint 2.
tx.rollback("save2")
// Commits the transaction.
tx.commit()
} catch (e1: SqlException) {
e1.printStackTrace()
try {
// Rolls back all transactions when an exception occurs.
tx.rollback()
} catch (e2: SqlException) {
e2.printStackTrace()
}
}
} catch (e: SqlException) {
e.printStackTrace()
}
}
std.ffi.python Package
Function Description
The ffi.python package provides the interoperability between Cangjie and Python to be compatible with powerful computing and AI ecosystems.
This package:
-
Provides a global interpreter object
Pythonof thePythonBuiltinstype, which can be used to:- Load and unload interpreter resources.
- Obtain the version of the Python interpreter in use.
- Import and use third-party modules of Python.
For the detailed description and use of this package, see Cangjie Programming Language Developer Guide (Cross-Language Interoperability/Interoperability with Python/PythonBuiltins Class).
-
Provides the conversion between Python data types and Cangjie data types. For example, PyBool, PyLong, PyFloat, PyString, PyTuple, PyList, PyDict, and PySet are inherited from the
PyObjecttype. ThePyObjecttype provides universal interfaces for all types, such as member variable access, function access, and conversion to Cangjie types. The subclasses of thePyObjecttype provide function interfaces specific to each type.For the detailed description and use of the mapping relationship, see Cangjie Programming Language Developer Guide (Cross-Language Interoperability/Interoperability with Python/Type Mapping).
-
Supports simple function registration and Python's callback of Cangjie functions. Python calls back the Cangjie code through C language and using its third-party libraries,
ctypesand_ctypes.For the detailed description and use of the mapping relationship, see Cangjie Programming Language Developer Guide (Cross-Language Interoperability/Interoperability with Python/Callback Registration of Cangjie and Python). This section describes the type mapping between parameters and return values for callback, as well as the calling methods.
Note:
- This package is not supported on Windows.
API List
Constants and Variables
| Name | Description |
|---|---|
| PYLOG | Specifies the ffi.python log object, which is used for printing control and output. |
| Python | Specifies the global resource of the Python interpreter. |
Interface
| Name | Description |
|---|---|
| CjObj | Provides a function for converting a Cangjie type to a Python Object type. |
| PyFFIType | Indicates the type that supports interoperability with Python. |
Class
| Name | Description |
|---|---|
| PyBool | Indicates the Boolean type of Python. |
| PyCFunc | Indicates the C-style function type of Python. |
| PyDict<K, V> where K <: Hashable & Equatable<K> & PyFFIType | Indicates the dictionary type of Python. |
| PyFloat | Indicates the floating-point number type of Python. |
| PyList<T> where T <: PyFFIType | Indicates the list type of Python. |
| PyLong | Indicates the integer type of Python. |
| PyObj | Indicates the parent class of all Python types. |
| PyObjIterator | Indicates the iterator type of PyObj. |
| PyString | Indicates the string type of Python. |
| PySet<T> where T <: Hashable & Equatable<T> & PyFFIType | Indicates the set type of Python. |
| PySlice<T> where T <: Countable<T> & Comparable<T> & Equatable<T> & CjObj | Indicates the interval type of Python. |
| PyTuple | Indicates the tuple type of Python. |
| PythonLogger | Indicates the log type of the ffi.python package. |
| PythonBuiltins | Indicates the built-in function set of Python. |
Exception Class
| Name | Description |
|---|---|
| PythonException | Indicates the exception type from the ffi.python package. |
Constants and Variables
let PYLOG
public let PYLOG: PythonLogger = PythonLogger()
Description: Specifies the global log instance of the ffi.python package used to control and output the printing of logs related to the package.
This global variable can be used to statically access the print function of PythonLogger to output logs of different levels. For details, see the "PythonLogger" section.
Type: PythonLogger
let Python
public let Python: PythonBuiltins = PythonBuiltins()
Description: Specifies the global resource of the Python interpreter.
This global variable can be used to create and destroy the Python interpreter and call built-in functions of Python. For details, see the "PythonBuiltins" section.
Type: PythonBuiltins
Interface
interface CjObj
public interface CjObj <: PyFFIType
Description: Provides a function for converting a Cangjie type to a Python type.
Parent Type:
interface PyFFIType
public interface PyFFIType
Description: Indicates the type that supports interoperability with Python.
Class
class PyBool
public class PyBool <: PyObj
Description: Specifies the Boolean type of Python and supports conversion with the Cangjie Bool type.
For the detailed description of this type, see Cangjie Programming Language Developer Guide (Cross-Language Interoperability/Interoperability with Python/Type Mapping/Mapping Between PyBool and Bool).
Parent Type:
class PyCFunc
public class PyCFunc <: PyObj
Description: Registers the Cangjie CFunc function for Python and allows Python to call back the CFunc function.
For the detailed description of this type, see Cangjie Programming Language Developer Guide (Cross-Language Interoperability/Interoperability with Python/Callback Registration of Cangjie and Python/PyCFunc Class Prototype).
Parent Type:
class PyDict<K, V> where K <: Hashable & Equatable<K> & PyFFIType
public class PyDict<K, V> <: PyObj where K <: Hashable & Equatable<K> & PyFFIType
Description: Specifies a Python dictionary type and supports conversion with the Cangjie HashMap type.
For the detailed description of this type, see Cangjie Programming Language Developer Guide (Cross-Language Interoperability/Interoperability with Python/Type Mapping/Mapping Between PyDict and HashMap).
Parent Type:
class PyFloat
public class PyFloat <: PyObj
Description Specifies the floating point number type in Python and supports conversion with the Cangjie Float32/Float64 type.
For the detailed description of this type, see Cangjie Programming Language Developer Guide (Cross-Language Interoperability/Interoperability with Python/Type Mapping/Mapping Between PyFloat and Floating Point).
Parent Type:
class PyList<T> where T <: PyFFIType
public class PyList<T> <: PyObj where T <: PyFFIType
Description: Specifies the list type in Python and supports conversion with the Cangjie Array type.
For the detailed description of this type, see Cangjie Programming Language Developer Guide (Cross-Language Interoperability/Interoperability with Python/Type Mapping/Mapping Between PyList and Array).
Parent Type:
class PyLong
public class PyLong <: PyObj
Description: Specifies the integer type in Python and maps to the Cangjie UInt8, Int8, Int16, UInt16, Int32, UInt32, Int64, and UInt64 types.
For the detailed description of this type, see Cangjie Programming Language Developer Guide (Cross-Language Interoperability/Interoperability with Python/Type Mapping/Mapping Between PyLong and Integer Type).
Parent Type:
class PyObj
public open class PyObj <: ToString & PyFFIType & Hashable & Equatable<PyObj>
Description: Specifies the base class of all types that support interoperability with Python.
For the detailed description of this type, see Cangjie Programming Language Developer Guide (Cross-Language Interoperability/Interoperability with Python/Type Mapping/PyObj Class).
Parent Type:
class PyObjIterator
public class PyObjIterator <: Iterator<PyObj>
Description: Specifies an iterator of the PyObj type.
For the detailed description of this type, see Cangjie Programming Language Developer Guide (Cross-Language Interoperability/Interoperability with Python/Type Mapping/PyObjIterator.
Parent Type:
class PySet<T> where T <: Hashable & Equatable<T> & PyFFIType
public class PySet<T> <: PyObj where T <: Hashable & Equatable<T> & PyFFIType
Description: Specifies the set type in Python and supports conversion with the Cangjie HashSet type.
For the detailed description of this type, see Cangjie Programming Language Developer Guide (Cross-Language Interoperability/Interoperability with Python/Type Mapping/Mapping Between PySet and HashSet).
Parent Type:
class PySlice<T> where T <: Countable<T> & Comparable<T> & Equatable<T> & CjObj
public class PySlice<T> <: PyObj where T <: Countable<T> & Comparable<T> & Equatable<T> & CjObj
Description: Specifies the range type in Python and supports conversion with the Cangjie Range type.
For the detailed description of this type, see Cangjie Programming Language Developer Guide (Cross-Language Interoperability/Interoperability with Python/Type Mapping/PySlice Type).
Parent Type:
class PyString
public class PyString <: PyObj
Description: Specifies the string type in Python and supports conversion with the Cangjie PyString type.
For the detailed description of this type, see Cangjie Programming Language Developer Guide (Cross-Language Interoperability/Interoperability with Python/Type Mapping/Mapping Between PyString and Character or String).
Parent Type:
class PyTuple
public class PyTuple <: PyObj
Description: Specifies the tuple type of Python.
For the detailed description of this type, see Cangjie Programming Language Developer Guide (Cross-Language Interoperability/Interoperability with Python/Type Mapping//PyTuple Type).
Parent Type:
class PythonBuiltins
public class PythonBuiltins
Description: Provides interfaces for creating and destroying interpreters and common built-in functions of Python.
For the detailed description of this type, see Cangjie Programming Language Developer Guide (Cross-Language Interoperability/Interoperability with Python/PythonBuiltins).
class PythonLogger
public class PythonLogger <: Logger
Description: Specifies the log type in the ffi.python package.
For the detailed description and use of this class, see Cangjie Programming Language Developer Guide (Cross-Language Interoperability/Interoperability with Python/Global Resources of Python and Their Usage/PythonLogger Class).
Parent Type:
Exception Class
class PythonException
public class PythonException <: Exception
Description: Specifies an exception type in the ffi.python package.
For the detailed description and use of this class, see Cangjie Programming Language Developer Guide (Cross-Language Interoperability/Interoperability with Python/Global Resources of Python and Their Usage/PythonException Classes).
Parent Type:
std.format Package
Function Description
The format package provides the formatting capability to convert Cangjie instances to formatted strings.
This package defines the Formatter interface to specify a unified formatting method and implements the Formatter interface for a series of Cangjie types such as Rune and Int8. Users can also implement the Formatter interface for other types to obtain the formatting function.
When a Cangjie type is converted to a string, the string format, such as the width and alignment mode, can be specified according to the formatting parameter. (In the Formatter interface method, the formatting parameter is used as the input parameter of the function).
The syntax of the formatting parameter is described as follows:
format_spec := [flags][width][.precision][specifier]
flags := '-' | '+' | '#' | '0'
width := integer
precision := integer
specifier := 'b' | 'B' | 'o' | 'O' | 'x' | 'X' | 'e' | 'E' | 'g' | 'G'
flags parameter:
-
'-' applies to the Int, UInt, Rune, and Float types, indicating left alignment.
Code:
import std.format.* main() { var c : Int32 = -20 print("\"${c.format("-10")}\"") }Running result:
"-20 " -
'+' applies to the Int, UInt, and Float types. If the value is a positive number, '+' is used. If the value is a negative number, ignore it.
Code:
import std.format.* main() { var c: Int32 = 20 print("\"${c.format("+10")}\"") }Running result:
" +20" -
'#' is used for printing in binary format. For printing in binary format, '0b' or '0B' is added. For printing in octal format, '0o' or '0O' is added. For printing in hexadecimal format, '0x' or '0X' is added.
Code:
import std.format.* main() { var c: Int32 = 1 print("\"${c.format("#10x")}\"") }Running result:
" 0x1" -
'0' applies to the Int, UInt, and Float types and empty data bits are padded with 0s.
Code:
import std.format.* main() { var c: Int32 = -20 print("\"${c.format("010")}\"") }Running result:
"-000000020"
width parameter:
-
The width parameter must be a positive integer and applies to the Int, UInt, Rune, and Float types. The width parameter with a negative sign (–) indicates left-aligned output. If there is no minus sign (–), it indicates right-aligned output. If the value of width is less than that of the parameter to be formatted, no truncation occurs. If the prefix contains
+or-, the prefix occupies one character. If the prefix contains0xor0o, the prefix occupies two characters.Code:
import std.format.* main() { var c: Int32 = 20 println("\"${c.format("1")}\"") println("\"${c.format("+4")}\"") }Running result:
"20" " +20"
precision parameter:
-
The precision parameter must be a positive integer and applies to the Int, UInt, and Float types. For a floating-point number, it indicates the number of valid digits after the decimal point. If this parameter is not specified, six decimal places are printed. If the value of precision is less than that of the parameter to be formatted, the floating-point number is rounded off. If the value of precision is greater than that of the parameter to be formatted, the decimal places of the floating-point number are supplemented by values which are not necessarily 0s.
-
For an integer, if this parameter is not specified or the specified value is less than that of the parameter to be formatted, the output is the same as the original number. If the value of precision is greater than that of the parameter to be formatted, '0' is padded before the integer.
Code:
import std.format.* main() { var e: Float32 = 1234.1 println("\"${e.format("20.20")}\"") var c: Int32 = -20 println("\"${c.format("10.8")}\"") }Running result:
"1234.09997558593750000000" " -00000020"
specifier parameter:
-
'b' | 'B', 'o' | 'O', and 'x' | 'X' apply to the Int and UInt types.
'b'|'B' indicates printing in binary format.
'o'|'O' indicates printing in octal format.
'x'|'X' indicates printing in hexadecimal format.
Code:
import std.format.* main() { var a = 20 println("\"${a.format("b")}\"") println("\"${a.format("o")}\"") println("\"${a.format("x")}\"") println("\"${a.format("X")}\"") println("\"${a.format("#X")}\"") }Running result:
"10100" "24" "14" "14" "0X14" -
'e' | 'E' and 'g' | 'G' apply to the Float type.
'e' | 'E': scientific notation, lowercase and uppercase
'g' | 'G': general, expressed in decimal or scientific notation, with the simplified notation used for printing
Code:
import std.format.* main() { var f: Float32 = 1234.1 var c: Float32 = 123412341234.1 println("\"${f.format("20.2e")}\"") println("\"${f.format("20G")}\"") println("\"${c.format("20G")}\"") println("\"${f.format("20")}\"") println("\"${c.format("20")}\"") }Running result:
" 1.23e+03" " 1234.1" " 1.23412E+11" " 1234.099976" " 123412340736.000000"
API List
Interface
| Name | Description |
|---|---|
| Formatter | Defines the formatting function, that is, converting an instance of a specified type to a string in the corresponding format according to the formatting parameter. |
Interface
interface Formatter
public interface Formatter {
func format(fmt: String): String
}
Description: Defines the formatting function, that is, converting an instance of a specified type to a string in the corresponding format according to the formatting parameter.
For details about the formatting parameters, see "Function Description" (./../format_package_overview.md#Function Description) in the format package.
For other types, this interface can be implemented to provide the formatting function.
func format(String)
func format(fmt: String): String
Description: Formats the current instance into a string in the corresponding format according to the formatting parameter.
Parameters:
- fmt: String: formatting parameter
Returns:
- String: string obtained after the current instance is formatted
extend Float16 <: Formatter
extend Float16 <: Formatter
Description: Extends the Formatter interface for Float16 to convert the Float16 instance to a formatted string.
Parent Type:
func format(String)
public func format(fmt: String): String
Description: Formats the current Float16 instance into a string in the corresponding format according to the formatting parameter.
Parameters:
- fmt: String: formatting parameter
Returns:
Throws:
- IllegalArgumentException: If fmt is invalid, this exception is thrown.
extend Float32 <: Formatter
extend Float32 <: Formatter
Description: Extends the Formatter interface for Float32 to convert the Float32 instance to a formatted string.
Parent Type:
func format(String)
public func format(fmt: String): String
Description: Formats the current Float32 instance into a string in the corresponding format according to the formatting parameter.
Parameters:
- fmt: String: formatting parameter
Returns:
Throws:
- IllegalArgumentException: If fmt is invalid, this exception is thrown.
extend Float64 <: Formatter
extend Float64 <: Formatter
Description: Extends the Formatter interface for Float64 to convert the Float64 instance to a formatted string.
Parent Type:
func format(String)
public func format(fmt: String): String
Description: Formats the current Float64 instance into a string in the corresponding format according to the formatting parameter.
Parameters:
- fmt: String: formatting parameter
Returns:
Throws:
- IllegalArgumentException: If fmt is invalid, this exception is thrown.
extend Int16 <: Formatter
extend Int16 <: Formatter
Description: Extends the Formatter interface for Int16 to convert the Int16 instance to a formatted string.
Parent Type:
func format(String)
public func format(fmt: String): String
Description: Formats the current Int16 instance into a string in the corresponding format according to the formatting parameter.
Parameters:
- fmt: String: formatting parameter
Returns:
Throws:
- IllegalArgumentException: If fmt is invalid, this exception is thrown.
extend Int32 <: Formatter
extend Int32 <: Formatter
Description: Extends the Formatter interface for Int32 to convert the Int32 instance to a formatted string.
Parent Type:
func format(String)
public func format(fmt: String): String
Description: Formats the current Int32 instance into a string in the corresponding format according to the formatting parameter.
Parameters:
- fmt: String: formatting parameter
Returns:
Throws:
- IllegalArgumentException: If fmt is invalid, this exception is thrown.
extend Int64 <: Formatter
extend Int64 <: Formatter
Description: Extends the Formatter interface for Int64 to convert the Int64 instance to a formatted string.
Parent Type:
func format(String)
public func format(fmt: String): String
Description: Formats the current Int64 instance into a string in the corresponding format according to the formatting parameter.
Parameters:
- fmt: String: formatting parameter
Returns:
Throws:
- IllegalArgumentException: If fmt is invalid, this exception is thrown.
extend Int8 <: Formatter
extend Int8 <: Formatter
Description: Extends the Formatter interface for Int8 to convert the Int8 instance to a formatted string.
Parent Type:
func format(String)
public func format(fmt: String): String
Description: Formats the current Int8 instance into a string in the corresponding format according to the formatting parameter.
Parameters:
- fmt: String: formatting parameter
Returns:
Throws:
- IllegalArgumentException: If fmt is invalid, this exception is thrown.
extend Rune <: Formatter
extend Rune <: Formatter
Description: Extends the Formatter interface for Rune to convert the Rune instance to a formatted string.
Parent Type:
func format(String)
public func format(fmt: String): String
Description: Formats the current Rune instance into a string in the corresponding format according to the formatting parameter.
Parameters:
- fmt: String: formatting parameter
Returns:
Throws:
- IllegalArgumentException: If fmt is invalid, this exception is thrown.
extend UInt16 <: Formatter
extend UInt16 <: Formatter
Description: Extends the Formatter interface for UInt16 to convert the UInt16 instance to a formatted string.
Parent Type:
func format(String)
public func format(fmt: String): String
Description: Formats the current UInt16 instance into a string in the corresponding format according to the formatting parameter.
Parameters:
- fmt: String: formatting parameter
Returns:
Throws:
- IllegalArgumentException: If fmt is invalid, this exception is thrown.
extend UInt32 <: Formatter
extend UInt32 <: Formatter
Description: Extends the Formatter interface for UInt32 to convert the UInt32 instance to a formatted string.
Parent Type:
func format(String)
public func format(fmt: String): String
Description: Formats the current UInt32 instance into a string in the corresponding format according to the formatting parameter.
Parameters:
- fmt: String: formatting parameter
Returns:
Throws:
- IllegalArgumentException: If fmt is invalid, this exception is thrown.
extend UInt64 <: Formatter
extend UInt64 <: Formatter
Description: Extends the Formatter interface for UInt64 to convert the UInt64 instance to a formatted string.
Parent Type:
func format(String)
public func format(fmt: String): String
Description: Formats the current UInt64 instance into a string in the corresponding format according to the formatting parameter.
Parameters:
- fmt: String: formatting parameter
Returns:
Throws:
- IllegalArgumentException: If fmt is invalid, this exception is thrown.
extend UInt8 <: Formatter
extend UInt8 <: Formatter
Description: Extends the Formatter interface for UInt8 to convert the UInt8 instance to a formatted string.
Parent Type:
func format(String)
public func format(fmt: String): String
Description: Formats the current UInt8 instance into a string in the corresponding format according to the formatting parameter.
Parameters:
- fmt: String: formatting parameter
Returns:
Throws:
- IllegalArgumentException: If fmt is invalid, this exception is thrown.
format Usage Example
Formatting an Integer
The following is an example of formatting an integer.
Code:
import std.format.*
main(): Int64 {
var a: Int32 = -20
var res1 = a.format("-10")
var res2 = a.format("+10")
var res3 = (-20).format("10")
var res4 = a.format("-")
println("\"${res1}\"")
println("\"${res2}\"")
println("\"${res3}\"")
println("\"${res4}\"")
return 0
}
Running result:
"-20 "
" -20"
" -20"
"-20"
Formatting a Floating-Point Number
The following is an example of formatting a floating-point number.
Code:
import std.format.*
/* flags '-' */
main(): Int64 {
var a: Float16 = -0.34
var b: Float32 = .34
var c: Float64 = 3_0.3__4_
var d: Float64 = 20.00
/* left align */
var res1 = a.format("-20")
/* right align */
var res2 = b.format("+20")
/* left align */
var res3 = c.format("10")
/* left align */
var res4 = d.format("-10")
/* left align */
var res5 = d.format("-")
println("\"${res1}\"")
println("\"${res2}\"")
println("\"${res3}\"")
println("\"${res4}\"")
println("\"${res5}\"")
return 0
}
Running result:
"-0.340088 "
" +0.340000"
" 30.340000"
"20.000000 "
"20.000000"
Formatting a Character
The following is an example of formatting a character.
Code:
import std.format.*
main(): Int64 {
var a: Rune = 'a'
var b: Rune = '-'
/* left align */
var res1 = a.format("-10")
/* right align */
var res2 = b.format("-10")
/* left align */
var res3 = a.format("10")
/* left align */
var res4 = b.format("10")
println("\"${res1}\"")
println("\"${res2}\"")
println("\"${res3}\"")
println("\"${res4}\"")
return 0
}
Running result:
"a "
"- "
" a"
" -"
std.fs Package
Function Description
The file system (fs) package provides functions for operating files, folders, paths, and file metadata.
Currently, the fs package can be used in Linux, macOS, and Windows.
API List
Class
| Name | Description |
|---|---|
| Directory | Provides capabilities such as creating, moving, copying, deleting, querying, and traversing a directory in a file system. |
| File | Provides functions for performing operations on files, including opening, creating, closing, moving, copying, and deleting files, reading and writing files using a stream, and querying attributes. |
Enumeration
| Name | Description |
|---|---|
| OpenOption | Indicates different file opening options. |
Struct
| Name | Description |
|---|---|
| FileDescriptor | Obtains the file handle information. |
| FileInfo | Provides functions for querying and setting file attributes for file metadata in a file system. |
| Path | Provides path-related functions. |
Exception Class
| Name | Description |
|---|---|
| FSException | Specifies the file stream exception class and inherits the exception class. |
Class
class Directory
public class Directory <: Iterable<FileInfo> {
public init(path: Path)
public init(path: String)
}
Description: Provides capabilities such as creating, moving, copying, deleting, querying, and traversing a directory in a file system.
Note:
An invalid path is one of the following:
- A path containing invalid characters, such as spaces, tabs, and newline characters
- A path containing invalid characters, such as special characters and control characters
- A path containing a directory or file that does not exist
- A path containing a directory or file that cannot be accessed due to insufficient permissions or lock status.
Enter a valid path without invalid characters so that the target file or directory can be accessed correctly.
Parent Type:
prop info
public prop info: FileInfo
Description: Obtains the metadata of the current directory.
Type: FileInfo
init(Path)
public init(path: Path)
Description: Creates a Directory instance.
Parameters:
Throws:
- FSException: If the path is invalid, this exception is thrown.
init(String)
public init(path: String)
Description: Creates a Directory instance that can be an absolute path or a relative path. If the path is invalid, an exception is thrown.
Parameters:
- path: String: directory path in the string format
Throws:
- FSException: If the path does not exist or is empty, this exception is thrown.
static func copy(Path, Path, Bool)
public static func copy(sourceDirPath: Path, destinationDirPath: Path, overwrite: Bool): Unit
Description: Copies the directory, files, and subfolders to a new location.
Parameters:
- sourceDirPath: Path: source directory path in the Path format
- destinationDirPath: Path: destination directory path in the Path format
- overwrite: Bool: whether to overwrite: true: yes, false: no
Throws:
- FSException: If the source directory does not exist, the destination directory exists when overwrite is set to false, the destination directory is in the source directory, or the copy fails, this exception is thrown.
- IllegalArgumentException: If the source or destination directory name contains null characters, this exception is thrown.
static func copy(String, String, Bool)
public static func copy(sourceDirPath: String, destinationDirPath: String, overwrite: Bool): Unit
Description: Copies the directory, files, and subfolders to a new location. If the copy fails, an exception is thrown.
Parameters:
- sourceDirPath: String: source directory path in the string format
- destinationDirPath: String: destination directory path in the string format
- overwrite: Bool: whether to overwrite: true: yes, false: no
Throws:
- FSException: If the source directory does not exist, the destination directory exists when overwrite is set to false, the destination directory is in the source directory, or the copy fails, this exception is thrown.
- IllegalArgumentException: If the source or destination directory name contains null characters, this exception is thrown.
static func create(Path, Bool)
public static func create(path: Path, recursive!: Bool = false): Directory
Description: Creates a directory.
You can specify whether to create directories recursively. If yes, create directories that do not exist in the path level by level.
Parameters:
- path: Path: path of the directory to be created
- recursive!: Bool: whether to create directories recursively: true: yes, false (default): no
Returns:
Throws:
- FSException: If the directory already exists or if the intermediate directory does not exist in non-recursive creation mode, this exception is thrown.
- IllegalArgumentException: If the directory is empty, the directory is the current directory, the directory is the root directory, or the directory contains null characters, this exception is thrown.
static func create(String, Bool)
public static func create(path: String, recursive!: Bool = false): Directory
Description: Creates a directory.
You can specify whether to create directories recursively. If yes, create directories that do not exist in the path level by level.
Parameters:
- path: String: path of the directory to be created
- recursive!: Bool: whether to create directories recursively: true: yes, false (default): no
Returns:
Throws:
- FSException: If the directory already exists or if the intermediate directory does not exist in non-recursive creation mode, this exception is thrown.
- IllegalArgumentException: If the directory is empty, the directory is the current directory, the directory is the root directory, or the directory contains null characters, this exception is thrown.
static func createTemp(Path)
public static func createTemp(directoryPath: Path): Directory
Description: Creates a temporary directory in a specified directory.
Parameters:
Returns:
Throws:
- FSException: If the directory does not exist or fails to be created, this exception is thrown.
- IllegalArgumentException: If the directory is empty or contains null characters, this exception is thrown.
static func createTemp(String)
public static func createTemp(directoryPath: String): Directory
Description: Creates a temporary directory in a specified directory.
Parameters:
- directoryPath: String: directory path in the string format
Returns:
Throws:
- FSException: If the directory does not exist or fails to be created, this exception is thrown.
- IllegalArgumentException: If the directory is empty or contains null characters, this exception is thrown.
static func delete(Path, Bool)
public static func delete(path: Path, recursive!: Bool = false): Unit
Description: Deletes a directory.
You can specify whether to delete directories recursively. If yes, directories are deleted level by level.
Parameters:
- path: Path: specified directory path in the Path format
- recursive!: Bool: whether to delete directories recursively: true: yes, false (default): no
Throws:
- FSException: If the directory does not exist or the recursive deletion fails, this exception is thrown.
- IllegalArgumentException: If path is an empty string, contains null characters, or contains more than 4096 characters, this exception is thrown.
static func delete(String, Bool)
public static func delete(path: String, recursive!: Bool = false): Unit
Description: Deletes a directory.
You can specify whether to delete directories recursively. If yes, directories are deleted level by level.
Parameters:
- path: String: specified directory path in the string format
- recursive!: Bool: whether to delete directories recursively: true: yes, false (default): no
Throws:
- FSException: If the directory does not exist or the recursive deletion fails, this exception is thrown.
- IllegalArgumentException: If path is an empty string, contains null characters, or contains more than 4096 characters, this exception is thrown.
static func exists(Path)
public static func exists(path: Path): Bool
Description: Checks whether the directory corresponding to a path exists.
Parameters:
Returns:
- Bool: If the path does not exist or does not correspond to a directory, false is returned. If the path corresponds to a directory or a soft link that points to a directory, true is returned.
static func exists(String)
public static func exists(path: String): Bool
Description: Checks whether the directory corresponding to a path exists.
Parameters:
- path: String: directory path in the string format
Returns:
- Bool: If the path does not exist or does not correspond to a directory, false is returned. If the path corresponds to a directory or a soft link that points to a directory, true is returned.
static func move(Path, Path, Bool)
public static func move(sourceDirPath: Path, destinationDirPath: Path, overwrite: Bool): Unit
Description: Moves the directory, files, and subfolders to a specified path.
Parameters:
- sourceDirPath: Path: source directory path in the Path format
- destinationDirPath: Path: destination directory path in the Path format
- overwrite: Bool: whether to overwrite: true: all subfolders and files in the destination path are overwritten, false: no
Throws:
- IllegalArgumentException: If the destination directory name is empty or contains null characters, this exception is thrown.
- FSException: If the source directory does not exist, the destination directory already exists when overwrite is set to false, or the moving fails, this exception is thrown.
static func move(String, String, Bool)
public static func move(sourceDirPath: String, destinationDirPath: String, overwrite: Bool): Unit
Description: Moves the directory, files, and subfolders to a specified path.
Parameters:
- sourceDirPath: String: source directory path in the string format
- destinationDirPath: String: destination directory path in the string format
- overwrite: Bool: whether to overwrite: true: all subfolders and files in the destination path are overwritten, false: no
Throws:
- IllegalArgumentException: If the destination directory name is empty or contains null characters, this exception is thrown.
- FSException: If the source directory does not exist, the destination directory already exists when overwrite is set to false, or the moving fails, this exception is thrown.
func createFile(String)
public func createFile(name: String): File
Description: Creates a subfile with a specified name in the current Directory.
Parameters:
- name: String: subfile name. The parameter must be a string without a path prefix.
Returns:
Throws:
- FSException: If the subfile name contains path information or the file name already exists, this exception is thrown.
- IllegalArgumentException: If the file name contains null characters, this exception is thrown.
func createSubDirectory(String)
public func createSubDirectory(name: String): Directory
Description: Creates a subdirectory with a specified name in the current Directory.
Parameters:
- name: String: subdirectory name. The parameter must be a string without a path prefix.
Returns:
Throws:
- FSException: If the subdirectory name contains path information, the path already exists, or the directory fails to be created, this exception is thrown.
- IllegalArgumentException: If the directory name contains null characters, this exception is thrown.
func directories()
public func directories(): Iterator<FileInfo>
Description: Returns the subdirectory iterator of the current directory.
Returns:
Returns: If the directory is empty, true is returned. Otherwise, false is returned.
Throws:
- FSException: If the member information of the directory fails to be obtained, this exception is thrown.
func directoryList()
public func directoryList(): ArrayList<FileInfo>
Description: Returns the subdirectory list of the current directory.
Returns:
Throws:
- FSException: If the member information of the directory fails to be obtained, this exception is thrown.
func entryList()
public func entryList(): ArrayList<FileInfo>
Description: Returns the file or subdirectory list of the current directory.
Returns:
Throws:
- FSException: If the member information of the directory fails to be obtained, this exception is thrown.
func fileList()
public func fileList(): ArrayList<FileInfo>
Description: Returns the subfile list of the current directory.
Returns:
Throws:
- FSException: If the member information of the directory fails to be obtained, this exception is thrown.
func files()
public func files(): Iterator<FileInfo>
Description: Returns the subfile iterator of the current directory.
Returns:
Throws:
- FSException: If the member information of the directory fails to be obtained, this exception is thrown.
func isEmpty()
public func isEmpty(): Bool
Description: Checks whether the current directory is empty.
Returns:
- Bool: If the current directory is empty, true is returned. Otherwise, false is returned.
Throws:
- FSException: If an error occurs in the system interface called at the bottom layer, this exception is thrown.
func iterator()
public func iterator(): Iterator<FileInfo>
Description: Returns the file or subdirectory iterator of the current directory.
Returns:
Throws:
- FSException: If the member information of the directory fails to be obtained, this exception is thrown.
class File
public class File <: Resource & IOStream & Seekable {
public init(path: Path, openOption: OpenOption)
public init(path: String, openOption: OpenOption)
}
Description: Provides functions for performing operations on files, including opening, creating, closing, moving, copying, deleting, and querying files, and reading and writing files using a stream.
Note:
An invalid path is one of the following:
- A path containing invalid characters, such as spaces, tabs, and newline characters
- A path containing invalid characters, such as special characters and control characters
- A path containing a directory or file that does not exist
- A path containing a directory or file that cannot be accessed due to insufficient permissions or lock status.
Enter a valid path without invalid characters so that the target file or directory can be accessed correctly.
Note:
Parent Type:
prop fileDescriptor
public prop fileDescriptor: FileDescriptor
Description: Obtains the file descriptor information.
Type: FileDescriptor
prop info
public prop info: FileInfo
Description: Obtains the file metadata.
Type: FileInfo
prop length
public prop length: Int64
Description: Obtains the number of bytes from the file header to the file trailer.
Type: Int64
prop position
public prop position: Int64
Description: Obtains the current cursor position of a file.
Type: Int64
prop remainLength
public prop remainLength: Int64
Description: Obtains the number of bytes of a file from the current cursor position to the file trailer.
Type: Int64
init(Path, OpenOption)
public init(path: Path, openOption: OpenOption)
Description: Creates a File object.
The file path and file opening mode (read and write permissions) must be specified, and the path can be a relative path or an absolute path.
Parameters:
- path: Path: file path
- openOption: OpenOption: file opening option
Throws:
- FSException: If the file already exists when the creation is performed, the file does not exist when other operations are performed, the parent directory of the file does not exist, or the file cannot be opened due to other reasons, this exception is thrown.
- IllegalArgumentException: If path is empty or contains null characters, this exception is thrown.
init(String, OpenOption)
public init(path: String, openOption: OpenOption)
Description: Creates a File object.
The file path and file opening mode (read and write permissions) must be specified, and the path can be a relative path or an absolute path.
Parameters:
- path: String: file path string
- openOption: OpenOption: file opening option
Throws:
- FSException: If the file already exists when the creation is performed, the file does not exist when other operations are performed, the parent directory of the file does not exist, or the file cannot be opened due to other reasons, this exception is thrown.
- IllegalArgumentException: If the path is an empty string or contains null characters, this exception is thrown.
static func copy(Path, Path, Bool)
public static func copy(sourcePath: Path, destinationPath: Path, overwrite: Bool): Unit
Description: Copies a file to a new location. If the copy fails, an exception is thrown.
Parameters:
- sourcePath: Path: source path of the file
- destinationPath: Path: destination path of the file
- overwrite: Bool: whether to overwrite: true: yes, false: no
Throws:
- FSException: If the file path is empty, the read permission on the source path file is not granted, or the destination path file exists but the write permission is not granted, this exception is thrown.
- IllegalArgumentException: If the file path contains null characters, this exception is thrown.
static func copy(String, String, Bool)
public static func copy(sourcePath: String, destinationPath: String, overwrite: Bool): Unit
Description: Copies a file to a new location. If the copy fails, an exception is thrown.
Parameters:
- sourcePath: String: source path of the file
- destinationPath: String: destination path of the file
- overwrite: Bool: whether to overwrite: true: yes, false: no
Throws:
- FSException: If the file path is empty, the read permission on the source path file is not granted, or the destination path file exists but the write permission is not granted, this exception is thrown.
- IllegalArgumentException: If the file path contains null characters, this exception is thrown.
static func create(Path)
public static func create(path: Path): File
Description: Creates a file in a specified path in write-only mode.
Parameters:
- path: Path: file path
Returns:
Throws:
- FSException: If the upper-level directory of the file to which the path points does not exist or the file already exists, this exception is thrown.
- IllegalArgumentException: If the file path is empty or contains null characters, this exception is thrown.
static func create(String)
public static func create(path: String): File
Description: Creates a file in a specified path in write-only mode.
Parameters:
- path: String: file path string
Returns:
Throws:
- FSException: If the upper-level directory of the file to which the path points does not exist or the file already exists, this exception is thrown.
- IllegalArgumentException: If the file path is an empty string or contains null characters, this exception is thrown.
static func createTemp(Path)
public static func createTemp(directoryPath: Path): File
Description: Creates a temporary file in a specified directory.
The name of the created file is tmpFileXXXXXX. The temporary files that are not used must be deleted manually.
Parameters:
- directoryPath: Path: directory path
Returns:
Throws:
- FSException: If the file fails to be created or the path does not exist, this exception is thrown.
- IllegalArgumentException: If the file path is empty or contains null characters, this exception is thrown.
static func createTemp(String)
public static func createTemp(directoryPath: String): File
Description: Creates a temporary file in a specified directory.
The name of the created file is tmpFileXXXXXX. The temporary files that are not used must be deleted manually.
Parameters:
- directoryPath: String: directory path string
Returns:
Throws:
- FSException: If the file fails to be created or the path does not exist, this exception is thrown.
- IllegalArgumentException: If the file path is an empty string or contains null characters, this exception is thrown.
static func delete(Path)
public static func delete(path: Path): Unit
Description: Deletes a file in a specified path.
Before deleting a file, ensure that the file exists and is closed. Otherwise, the deletion may fail.
Parameters:
- path: Path: file path
Throws:
- FSException: If the specified file does not exist or fails to be deleted, this exception is thrown.
static func delete(String)
public static func delete(path: String): Unit
Description: Deletes a file in a specified path.
Before deleting a file, ensure that the file exists and is closed. Otherwise, the deletion may fail.
Parameters:
- path: String: file path string
Throws:
- FSException: If the specified file does not exist or fails to be deleted, this exception is thrown.
static func exists(Path)
public static func exists(path: Path): Bool
Description: Checks whether the file corresponding to a path exists.
Parameters:
- path: Path: file path
Returns:
- Bool: If the path does not exist or the path does not correspond to a file, false is returned. If the path corresponds to a file or a soft link to a file, true is returned.
static func exists(String)
public static func exists(path: String): Bool
Description: Checks whether the file corresponding to a path exists.
Parameters:
- path: String: file path string
Returns:
- Bool: If the path does not exist or the path does not correspond to a file, false is returned. If the path corresponds to a file or a soft link to a file, true is returned.
static func move(Path, Path, Bool)
public static func move(sourcePath: Path, destinationPath: Path, overwrite: Bool): Unit
Description: Moves a file.
If overwrite is set to true and a file with the same name exists in the specified path, the existing file is overwritten. If overwrite is set to false, the existing file is not overwritten. If the destination directory already exists, an exception is thrown.
Parameters:
- sourcePath: Path: source path of the file
- destinationPath: Path: destination path of the file
- overwrite: Bool: whether to overwrite: true: yes, false: no
Throws:
- IllegalArgumentException: If the destination directory name is empty or contains null characters, this exception is thrown.
- FSException: If the source directory does not exist, the destination directory already exists when overwrite is set to false, or the moving fails, this exception is thrown.
static func move(String, String, Bool)
public static func move(sourcePath: String, destinationPath: String, overwrite: Bool): Unit
Description: Moves a file.
If overwrite is set to true and a file with the same name exists in the specified path, the existing file is overwritten. If overwrite is set to false, the existing file is not overwritten. If the destination directory already exists, an exception is thrown.
Parameters:
- sourcePath: String: source path of the file
- destinationPath: String: destination path of the file
- overwrite: Bool: whether to overwrite: true: the file in the destination path is overwritten, false: no
Throws:
- IllegalArgumentException: If the destination directory name is empty or contains null characters, this exception is thrown.
- FSException: If the source directory does not exist, the destination directory already exists when overwrite is set to false, or the moving fails, this exception is thrown.
static func openRead(Path)
public static func openRead(path: Path): File
Description: Opens a file in a specified path in read-only mode.
Parameters:
- path: Path: file path
Returns:
Throws:
- FSException: If the file does not exist or is unreadable, this exception is thrown.
- IllegalArgumentException: If the file path contains null characters, this exception is thrown.
static func openRead(String)
public static func openRead(path: String): File
Description: Opens a file in a specified path in read-only mode.
Parameters:
- path: String: file path string
Returns:
Throws:
- FSException: If the file does not exist or is unreadable, this exception is thrown.
- IllegalArgumentException: If the file path contains null characters, this exception is thrown.
static func readFrom(Path)
public static func readFrom(path: Path): Array<Byte>
Description: Reads all content of a file in a specified path and returns the content in the form of a byte array.
Parameters:
- path: Path: file path
Returns:
Throws:
- FSException: If the file path is empty, the file is unreadable, or the file fails to be read, this exception is thrown.
- IllegalArgumentException: If the file path contains null characters, this exception is thrown.
static func readFrom(String)
public static func readFrom(path: String): Array<Byte>
Description: Reads all content of a file in a specified path and returns the content in the form of a byte array.
Parameters:
- path: String: file path string
Returns:
Throws:
- FSException: If the file fails to be read or closed, the file path is empty, or the file is unreadable, this exception is thrown.
- IllegalArgumentException: If the file path contains null characters, this exception is thrown.
static func writeTo(Path, Array<Byte>, OpenOption)
public static func writeTo(path: Path, buffer: Array<Byte>, openOption!: OpenOption = CreateOrAppend): Unit
Description: Opens a file in a specified path by using openOption and writes the buffer.
Parameters:
- path: Path: file path
- buffer: Array<Byte>: bytes to be written
- openOption: OpenOption: file opening option. The default value is CreateOrAppend.
Throws:
- FSException: If the file path is empty, this exception is thrown.
- IllegalArgumentException: If the file path is empty or contains null characters, this exception is thrown.
static func writeTo(String, Array<Byte>, OpenOption)
public static func writeTo(path: String, buffer: Array<Byte>, openOption!: OpenOption = CreateOrAppend): Unit
Description: Opens a file in a specified path by using openOption and writes the buffer.
Parameters:
- path: String: file path string
- buffer: Array<Byte>: bytes to be written
- openOption: OpenOption: file opening option. The default value is CreateOrAppend.
Throws:
- FSException: If the file path is empty, this exception is thrown.
- IllegalArgumentException: If the file path is an empty string or contains null characters, this exception is thrown.
func canRead()
public func canRead(): Bool
Description: Checks whether the current File object is readable.
The return value of this function is determined by openOption used to create the file object. After the file object is closed, false is returned.
Returns:
- Bool: If the object is readable, true is returned. If the object is unreadable or the file object is closed, false is returned.
func canWrite()
public func canWrite(): Bool
Description: Checks whether the current File object is writable.
The return value of this function is determined by openOption used to create the file object. After the file object is closed, false is returned.
Returns:
- Bool: If the object is writable, true is returned. If the object is not writable or the file object is closed, false is returned.
func close()
public func close(): Unit
Description: Closes the current File object.
Throws:
- FSException: If the object fails to be closed, this exception is thrown.
func copyTo(OutputStream)
public func copyTo(out: OutputStream): Unit
Description: Writes all data that has not been read by File to a specified OutputStream.
Parameters:
- out: OutputStream:OutputStream to be written
Throws:
- FSException: If the file is not opened or the read permission on the file is not granted, this exception is thrown.
func flush()
public func flush(): Unit
Description: Writes buffer data to a stream. Because File does not have a buffer, this function does not work.
func isClosed()
public func isClosed(): Bool
Description: Checks whether the current File object is closed.
Returns:
- Bool: If the object is closed, true is returned. Otherwise, false is returned.
func read(Array<Byte>)
public func read(buffer: Array<Byte>): Int64
Description: Reads data from a file to the buffer.
Parameters:
Returns:
- Int64: If the data is read successfully, the number of read bytes is returned. If all data in the file is read, 0 is returned.
Throws:
- IllegalArgumentException: If buffer is empty, this exception is thrown.
- FSException: If the data fails to be read, the file is closed, or the file is unreadable, this exception is thrown.
func readToEnd()
public func readToEnd(): Array<Byte>
Description: Reads all remaining data of the current File and returns the remaining bytes in Array<Byte> format.
Returns:
Throws:
- FSException: If the data fails to be read or the file is unreadable, this exception is thrown.
func seek(SeekPosition)
public func seek(sp: SeekPosition): Int64
Description: Moves the cursor to a specified position.
The specified position cannot be before the file header but can exceed the file trailer. However, the maximum offset from the specified position to the file header cannot exceed the maximum value allowed by the current file system. The maximum value is close to the maximum file size allowed by the current file system and generally equals to the maximum file size minus 4096 bytes.
Parameters:
- sp: SeekPosition: the position to which the cursor is moved
Returns:
- Int64: the offset (in bytes) from the file header to the position to which the cursor is moved
Throws:
- FSException: If the specified position does not meet the preceding requirements or the file cannot be sought, this exception is thrown.
func write(Array<Byte>)
public func write(buffer: Array<Byte>): Unit
Description: Writes the data in the buffer to a file.
Parameters:
- buffer: Array<Byte>: buffer to which data is to be written. If buffer is empty, no operation is performed.
Throws:
- FSException: If the data fails to be written, only part of data is written, the file is closed, or the file is not writable, this exception is thrown.
Enumeration
enum OpenOption
public enum OpenOption {
| Append
| Create(Bool)
| CreateOrAppend
| CreateOrTruncate(Bool)
| Open(Bool, Bool)
| Truncate(Bool)
}
Description: Indicates different file opening options.
Append
Append
Description: Constructs an OpenOption instance which specifies that the file system should open an existing file and seek to the end of the file. By default, only the write permission is granted on File created using this option. If you attempt to find a location before the file trailer, FSException is thrown. Any read attempt will fail in which case FSException is thrown. If the file does not exist, FSException is thrown.
Create(Bool)
Create(Bool)
Description: Constructs an OpenOption instance which specifies that the file system should create a new file. The write permission is granted on File created using this option by default. You can specify whether the read permission on File is granted by setting parameters. If the file already exists, FSException is thrown.
CreateOrAppend
CreateOrAppend
Description: Constructs an OpenOption instance which specifies that the file system should open a file (if the file exists). Otherwise, a new file should be created. By default, only the write permission is granted on File created using this option. If you attempt to find a location before the file trailer, FSException is thrown. If the file does not exist, Create is used. Otherwise, Append is used.
CreateOrTruncate(Bool)
CreateOrTruncate(Bool)
Description: Constructs an OpenOption instance which specifies that the file system should create a new file. If the file already exists, it will be overwritten. By default, the write permission is granted on File created using this option. You can specify whether the read permission is granted by setting parameters. If the file does not exist, Create is used. Otherwise, Truncate is used.
Open(Bool, Bool)
Open(Bool, Bool)
Description: Constructs an OpenOption instance which specifies that the file system should open an existing file. The first parameter specifies whether the read permission is granted on the file, and the second parameter specifies whether the write permission is granted on the file. If the file does not exist, FSException is thrown.
Truncate(Bool)
Truncate(Bool)
Description: Constructs an OpenOption instance which specifies that the file system should open an existing file. If the file is already opened, it is truncated to zero bytes. By default, the write permission is granted on File created using this option. You can specify whether the read permission is granted by setting parameters. If the file does not exist, FSException is thrown.
Struct
struct FileDescriptor
public struct FileDescriptor
Description: Obtains the file handle information.
Note:
A file handle is a data structure allocated by an operating system to trace a file, and is used to identify an instance for opening the file. A file handle contains the metadata (such as the file name, path, size, and modification time) of a file and the physical location of the file data on the disk. The file handle format may vary according to the operating system. In Unix and Linux, the file handle is usually a non-negative integer, which is allocated by the operating system kernel and returned to the application when the file is opened. In Windows, the file handle is usually a pointer to a file object. It is allocated by the operating system kernel and returned to the application when the file is opened. A file handle, regardless of its format, can be used by applications to read, write, and modify files.
prop fileHandle
public prop fileHandle: CPointer<Unit>
Description: Obtains the file handle information in Windows.
prop fileHandle
public prop fileHandle: Int32
Description: Obtains the file handle information in Linux.
Type: Int32
struct FileInfo
public struct FileInfo <: Equatable<FileInfo> {
public init(path: Path)
public init(path: String)
}
Description: Obtains the file metadata in a file system.
Note:
File metadata refers to file-related information in a file system, including the name, size, creation time, modification time, access time, and owner of as well as permissions on a file.
The underlying implementation of FileInfo does not support direct file attribute cache. Each API calling FileInfo obtains the latest file attribute.
Note that when the file attribute is obtained twice by using the same FileInfo instance, if the file entity is modified or replaced by another user or process, the file attribute obtained later may not be the expected one. For the same FileInfo instance, the corresponding file entity may be modified or replaced by another user or process during the interval between two adjacent operations of obtaining the file attribute of the instance, so that the file attribute obtained later may not be the expected one. To avoid this problem, you can set file permissions or lock key file operations.
Parent Type:
prop creationTime
public prop creationTime: DateTime
Description: Obtains the creation time.
Type: DateTime
Throws:
- FSException: If an error occurs in the system interface called at the underlying layer, this exception is thrown.
prop lastAccessTime
public prop lastAccessTime: DateTime
Description: Obtains the last access time.
Type: DateTime
Throws:
- FSException: If an error occurs in the system interface called at the underlying layer, this exception is thrown.
prop lastModificationTime
public prop lastModificationTime: DateTime
Description: Obtains the last modification time.
Type: DateTime
Throws:
- FSException: If an error occurs in the system interface called at the underlying layer, this exception is thrown.
prop length
public prop length: Int64
Description: Returns the current file size.
- For a file, the value indicates the disk space occupied by a single file.
- For a directory, it indicates the disk space occupied by all files in the directory.
Type: Int64
Throws:
- FSException: If an error occurs in the system interface called at the underlying layer, this exception is thrown.
prop parentDirectory
public prop parentDirectory: Option<FileInfo>
Description: Obtains the metadata of the parent directory and returns the metadata in Option<FileInfo> format. If there is a parent directory, Option<FileInfo>.Some(v) is returned. Otherwise, Option<FileInfo>.None is returned.
prop path
public prop path: Path
Description: Obtains the file path and returns it in Path format.
Type: Path
prop symbolicLinkTarget
public prop symbolicLinkTarget: Option<Path>
Description: Obtains the target path of a link and returns the path in Option<Path> format. For a symbolic link, Option<Path>.Some(v) is returned. Otherwise, Option<Path>.None is returned.
init(Path)
public init(path: Path)
Description: Creates a FileInfo instance.
Parameters:
Throws:
- FSException: If the path is invalid, this exception is thrown.
init(String)
public init(path: String)
Description: Creates a FileInfo instance.
Parameters:
Throws:
- FSException: If the path is invalid, this exception is thrown.
func canExecute()
public func canExecute(): Bool
Description: Checks whether a user has the permission to execute the file corresponding to the instance.
- For a file, checks whether a user has the permission to execute the file.
- For a directory, checks whether a user has the permission to access the directory.
- In Windows, the file name extension determines a user's permission to execute files. The user always has the permission to execute a directory. No operation is performed and true is returned.
- In Linux and macOS, this function works normally.
Returns:
- Bool: If the user has the permission. true is returned. If the user has no permission, false is returned.
Throws:
- FSException: If an error occurs in the system interface called at the underlying layer, this exception is thrown.
func canRead()
public func canRead(): Bool
Description: Checks whether a user has the permission to read the file corresponding to the instance.
- For a file, checks whether a user has the permission to read the file.
- For a directory, checks whether a user has the permission to browse the directory.
- In Windows, a user always has the read permission on the file and directory. No operation is performed and true is returned.
- In Linux and macOS, this function works normally.
Returns:
- Bool: If the user has the permission. true is returned. If the user has no permission, false is returned.
Throws:
- FSException: If an error occurs in the system interface called at the underlying layer, this exception is thrown.
func canWrite()
public func canWrite(): Bool
Description: Checks whether a user has the permission to write the file corresponding to the instance.
- For a file, checks whether a user has the permission to write the file.
- For a directory, checks whether a user has the permission to delete, move, and create files in a directory.
- In Windows, a user can write files normally and always has the write permission on the directory. No operation is performed and true is returned.
- In Linux and macOS, this function works normally.
Returns:
- Bool: If the user has the permission. true is returned. If the user has no permission, false is returned.
Throws:
- FSException: If an error occurs in the system interface called at the underlying layer, this exception is thrown.
func isDirectory()
public func isDirectory(): Bool
Description: Checks whether a file is a directory.
Returns:
- Bool: true: yes, false: no
Throws:
- FSException: If an error occurs in the system interface called at the underlying layer, this exception is thrown.
func isFile()
public func isFile(): Bool
Description: Checks whether a file is a common file.
Returns:
- Bool: true: yes, false: no
Throws:
- FSException: If an error occurs in the system interface called at the underlying layer, this exception is thrown.
func isHidden()
public func isHidden(): Bool
Description: Checks whether a file is hidden.
Returns:
- Bool: true: yes, false: no
func isReadOnly()
public func isReadOnly(): Bool
Description: Checks whether a file is read-only.
- In Windows, the read-only permission on a file is effective and a user always has the permission to delete or modify the directory. No operation is performed and false is returned.
- In Linux and macOS, this function works normally.
Returns:
- Bool: true: yes, false: no
Throws:
- FSException: If an error occurs in the system interface called at the underlying layer, this exception is thrown.
func isSymbolicLink()
public func isSymbolicLink(): Bool
Description: Checks whether a file is a soft link.
Returns:
- Bool: If the file is a soft link, true is returned; if the file is not a soft link, false is returned.
Throws:
- FSException: If an error occurs in the system interface called at the underlying layer, this exception is thrown.
func setExecutable(Bool)
public func setExecutable(executable: Bool): Bool
Description: Sets whether the permission to execute a file corresponding to the current instance is granted for a user. If the user does not have the permission to modify the system permissions, an exception is thrown.
- For a file, whether the permission to execute the file is granted for a user. For a directory, whether the permission to access the directory is granted for a user.
- In Windows, the file name extension determines a user's permission to execute the file, and the user always has the permission to execute a directory. No operation is performed and false is returned.
- In Linux and macOS, this function works normally. If the file entity corresponding to FileInfo is modified by other users or processes when this function is called, other modifications may not take effect due to the race condition.
Parameters:
- executable: Bool: whether the user can execute the file
Returns:
- Bool: If the operation is successful, true is returned. If the operation fails, false is returned.
func setReadable(Bool)
public func setReadable(readable: Bool): Bool
Description: Sets whether the read permission on a file corresponding to the current instance is granted for a user. If the user does not have the permission to modify the system permissions, an exception is thrown.
- For a file, sets whether a user has the permission to read the file.
- For a directory, sets whether a user has the permission to browse the directory.
- In Windows, a user always has the read permission on files and directories and such read permission cannot be modified. No operation is performed. If readable is set to true, true is returned. If readable is set to false, false is returned.
- In Linux and macOS, this function works normally. If the file entity corresponding to FileInfo is modified by other users or processes when this function is called, other modifications may not take effect due to the race condition.
Parameters:
- readable: Bool: whether a user can read the file
Returns:
- Bool: If the operation is successful, true is returned. If the operation fails, false is returned.
func setWritable(Bool)
public func setWritable(writable: Bool): Bool
Description: Sets whether the write permission on a file corresponding to the current instance is granted for a user. If the user does not have the permission to modify the system permissions, an exception is thrown.
- For a file, sets whether a user has the permission to write the file.
- For a directory, sets whether a user has the permission to delete, move, and create files in a directory.
- In Windows, a user can write files normally and always has the write permission on directories and such write permission cannot be modified. No operation is performed and false is returned.
- In Linux and macOS, this function works normally. If the file entity corresponding to FileInfo is modified by other users or processes when this function is called, other modifications may not take effect due to the race condition.
Parameters:
- writable: Bool: whether a user can write the file
Returns:
- Bool: If the operation is successful, true is returned. If the operation fails, false is returned.
operator func !=(FileInfo)
public operator func !=(that: FileInfo): Bool
Description: Checks whether the current FileInfo and the other FileInfo correspond to different files.
Parameters:
Returns:
- Bool: true: yes, false: no
operator func ==(FileInfo)
public operator func ==(that: FileInfo): Bool
Description: Checks whether the current FileInfo and the other FileInfo correspond to the same file.
Parameters:
Returns:
- Bool: true: yes, false: no
struct Path
public struct Path <: Equatable<Path> & Hashable & ToString {
public init(rawPath: String)
}
Description: Provides path-related functions.
Path indicates the local path. (Windows supports the DOS device path and UNC path. The length limit is the same as that set in system settings.) The path string can contain a maximum of 4096 bytes (including the terminator\0).
Note:
An invalid path is one of the following:
- A path containing invalid characters, such as spaces, tabs, and newline characters
- A path containing invalid characters, such as special characters and control characters
- A path containing a directory or file that does not exist
- A path containing a directory or file that cannot be accessed. For example, the permission is insufficient or the directory or file is locked.
Enter a valid path without invalid characters so that the target file or directory can be accessed correctly.
Parent Type:
prop directoryName
public prop directoryName: Option<Path>
Description: Obtains the directory portion of Path and returns the result in Option<Path> format.
- For the path "/a/b/c", Some (Path ("/a/b")) is returned.
- For the path "/a/b/", Some(Path("/a/b")) is returned.
- For the path "/a", Some(Path("/")) is returned.
- For the path "/", Some(Path("/")) is returned.
- For the path "./a/b", Some(Path("./a")) is returned.
- For the path "./", Some(Path(".")) is returned.
- For the path ".",
Noneis returned. - For the path ".gitignore",
Noneis returned. - For the path "a.txt",
Noneis returned. - For the path "C:\a\b\c", Some(Path("C:\a\b")) is returned.
- For the path "C:\a\b", Some(Path("C:\a\b")) is returned.
Returns: directory portion of the path input during construction. If the path input during construction does not contain any directory portion, None is returned.
Throws:
- IllegalArgumentException: If the path is empty or contains a string terminator, this exception is thrown.
prop extensionName
public prop extensionName: Option<String>
Description: Obtains the file name extension of Path and returns the result in the Option<String> format.
- For the path "./NewFile.txt",
Some("txt")is returned. - For the path "./.gitignore",
Some("gitignore")is returned. - For the path "./noextension",
Noneis returned. - For the path "./a.b.c",
Some("c")is returned. - For the path "./NewDir/",
Noneis returned. - For the path "./NewDir/NewFile.",
Noneis returned.
Returns: file name extension in the path input during construction. If the path input during construction does not contain the file name extension, None is returned.
Throws:
- IllegalArgumentException: If the path is empty or contains a string terminator, this exception is thrown.
prop fileName
public prop fileName: Option<String>
Description: Obtains the file name (including the file name extension) of Path and returns the result in the Option<String> format.
- For the path "./NewFile.txt",
Some("NewFile.txt")is returned. - For the path "./.gitignore",
Some(".gitignore")is returned. - For the path "./noextension",
Some("noextension")is returned. - For the path "./a.b.c",
Some("a.b.c")is returned. - For the path "./NewDir/",
Noneis returned.
Returns: file name (including the file name extension) in the path input during construction. If the path input during construction does not contain the file name (including the file name extension), None is returned.
Throws:
- IllegalArgumentException: If the path is empty or contains a string terminator, this exception is thrown.
prop fileNameWithoutExtension
public prop fileNameWithoutExtension: Option<String>
Description: Obtains the file name (excluding the file name extension) of Path and returns the result in the Option<String> format.
- For the path "./NewFile.txt",
Some("NewFile")is returned. - For the path "./.gitignore",
Noneis returned. - For the path "./noextension",
Some("noextension")is returned. - For the path "./a.b.c",
Some("a.b")is returned. - For the path "./NewDir/",
Noneis returned.
Returns: file name (excluding the file name extension) in the path input during construction. If the path input during construction does not contain the file name (excluding the file name extension), None is returned.
Throws:
- IllegalArgumentException: If the path is empty or contains a string terminator, this exception is thrown.
init(String)
public init(rawPath: String)
Description: When a Path instance is created, the validity of the path (including the absolute and relative path) string is not checked.
Parameters:
- rawPath: String: string of the path
func hashCode()
public func hashCode(): Int64
Description: Obtains the hash value of Path.
Returns:
func isAbsolute()
public func isAbsolute(): Bool
Description: Checks whether Path is an absolute path. In Unix, the path starting with / is an absolute path.
Returns:
- Bool: true: yes, false: no
Throws:
- IllegalArgumentException: If the path is empty or contains a string terminator, this exception is thrown.
func isDirectory()
public func isDirectory(): Bool
Description: Checks whether Path is a directory. This function is mutually exclusive with isFile and isSymbolicLink.
Returns:
- Bool: true: yes, false: no
Throws:
- FSException: If the path does not exist or an error occurs in the system interface called at the underlying layer, this exception is thrown.
- IllegalArgumentException: If the path is empty or contains a string terminator, this exception is thrown.
func isFile()
public func isFile(): Bool
Description: Checks whether Path is a file. This function is mutually exclusive with isSymbolicLink and isDirectory.
Returns:
- Bool: true: yes, false: no
Throws:
- FSException: If the path does not exist or an error occurs in the system interface called at the underlying layer, this exception is thrown.
- IllegalArgumentException: If the path is empty or contains a string terminator, this exception is thrown.
func isRelative()
public func isRelative(): Bool
Description: Checks whether Path is a relative path. The result is opposite to that of the isAbsolute function.
Returns:
- Bool: true: yes, false: no
Throws:
- IllegalArgumentException: If the path is empty or contains a string terminator, this exception is thrown.
func isSymbolicLink()
public func isSymbolicLink(): Bool
Description: Checks whether Path is a soft link. This function is mutually exclusive with isFile and isDirectory.
Returns:
- Bool: true: yes, false: no
Throws:
- FSException: If the path does not exist or an error occurs in the system interface called at the underlying layer, this exception is thrown.
- IllegalArgumentException: If the path is empty or contains a string terminator, this exception is thrown.
func join(Path)
public func join(path: Path): Path
Description: Concatenates another path string after the current path to form a new path.
- If "c" is concatenated after "a/b", "a/b/c" is returned.
- If "b/c" is concatenated after "a", "a/b/c" is returned.
Returns:
Throws:
- FSException: If path is an absolute path, this exception is thrown.
- IllegalArgumentException: If the current path is empty or the current path or input parameter path is invalid, this exception is thrown.
func join(String)
public func join(path: String): Path
Description: Concatenates another path string after the current path to form a new path.
- If "c" is concatenated after "a/b", "a/b/c" is returned.
- If "b/c" is concatenated after "a", "a/b/c" is returned.
Returns:
Throws:
- FSException: If path is an absolute path, this exception is thrown.
- IllegalArgumentException: If the current path is empty or the current path or input parameter path is invalid, this exception is thrown.
func split()
public func split(): (Option<Path>, Option<String>)
Description: Splits Path into a directory and a file name and returns the splitting result (directoryName, fileName) in tuple format.
Returns:
- (Option<Path>, Option<String>): tuple value. The first element indicates the path. If the path is obtained successfully, Option<Path>.Some(p) is returned. If the path fails to be obtained, Option<Path>.None is returned. The second element indicates the file name. If the file name is obtained successfully, Option<String>.Some(s) is returned. If the file name fails to be obtained, Option<String>.None is returned.
Throws:
- IllegalArgumentException: If the path is empty or contains a string terminator, this exception is thrown.
func toCanonical()
public func toCanonical(): Path
Description: Normalizes Path and returns a normalized path in absolute path format.
All intermediate references and soft links are removed (soft links in the UNC path cannot be removed). For example, for the path "/foo/test/../test/bar.txt", "/foo/test/bar.txt" is returned after normalization.
Returns:
Throws:
- FSException: If the path does not exist or cannot be normalized, this exception is thrown.
- IllegalArgumentException: If the path is empty or contains a string terminator, this exception is thrown.
func toString()
public func toString(): String
Description: Obtains the path string of Path.
Returns:
operator func !=(Path)
public operator func !=(that: Path): Bool
Description: Checks whether two Path instances are different.
Parameters:
Returns:
- Bool: true: yes, false: no
operator func ==(Path)
public operator func ==(that: Path): Bool
Description: Checks whether two Path instances are the same.
Parameters:
Returns:
- Bool: true: yes, false: no
Exception Class
class FSException
Specifies the file stream exception class and inherits the exception class.
public class FSException <: Exception {
public init()
public init(message: String)
}
Parent Type:
init()
public init()
Description: Constructs a file exception instance without exception information.
init(String)
public init(message: String)
Description: Constructs a file exception instance with exception information.
Parameters:
- message: String: error information
Directory Example
Demonstration of Basic Operations of Directory
Code:
import std.fs.*
main() {
let testDirPath: Path = Path("./testDir")
let subDirPath: Path = Path("./testDir/subDir")
if (Directory.exists(testDirPath)) {
Directory.delete(testDirPath, recursive: true)
}
/* Recursively creates a directory and "./testDir/subDir". */
let subDir: Directory = Directory.create(subDirPath, recursive: true)
if (Directory.exists(subDirPath)) {
println("The directory './testDir/subDir' is successfully created recursively in current directory.")
}
/* Creates the subdirectory "dir1" in "./testDir/subDir". */
subDir.createSubDirectory("dir1")
if (Directory.exists("./testDir/subDir/dir1")) {
println("The directory 'dir1' is created successfully in directory './testDir/subDir'.")
}
/* Creates the subfile "file1" in "./testDir/subDir". */
subDir.createFile("file1")
if (File.exists("./testDir/subDir/file1")) {
println("The file 'file1' is created successfully in directory './testDir/subDir'.")
}
/* Creates a temporary directory in "./testDir". */
let tempDir: Directory = Directory.createTemp(testDirPath)
let tempDirPath: Path = tempDir.info.path
if (Directory.exists(tempDirPath)) {
println("The temporary directory is created successfully in directory './testDir'.")
}
/* Moves "subDir" to the temporary directory and renames it "subDir_new". */
let newSubDirPath: Path = tempDirPath.join("subDir_new")
Directory.move(subDirPath, newSubDirPath, false)
if (Directory.exists(newSubDirPath) && !Directory.exists(subDirPath)) {
println("The directory './testDir/subDir' is moved successfully to the temporary directory and renamed 'subDir_new'.")
}
/* Copies "subDir_new" to "./testDir" and renames it "subDir". */
Directory.copy(newSubDirPath, subDirPath, false)
if (Directory.exists(subDirPath) && Directory.exists(newSubDirPath)) {
println("The directory 'subDir_new' is copied successfully to directory './testDir' and renamed 'subDir'.")
}
Directory.delete(testDirPath, recursive: true)
return 0
}
Running result:
The directory './testDir/subDir' is successfully created recursively in current directory.
The directory 'dir1' is created successfully in directory './testDir/subDir'.
The file 'file1' is created successfully in directory './testDir/subDir'.
The temporary directory is created successfully in directory './testDir'.
The directory './testDir/subDir' is moved successfully to the temporary directory and renamed 'subDir_new'.
The directory 'subDir_new' is copied successfully to directory './testDir' and renamed 'subDir'.
File Example
Common File Operations Including Creation, Deletion, Reading, Writing, and Closing
Code:
import std.fs.*
import std.io.SeekPosition
main() {
let filePath: Path = Path("./tempFile.txt")
if (File.exists(filePath)) {
File.delete(filePath)
}
/* Creates a new file **'tempFile.txt'** in the current directory in write-only mode, writes "123456789\n" to the file three times, and closes the file. */
var file: File = File(filePath, OpenOption.Create(false))
if (File.exists(filePath)) {
println("The file 'tempFile.txt' is created successfully in current directory.\n")
}
let bytes: Array<Byte> = "123456789\n".toArray()
for (_ in 0..3) {
file.write(bytes)
}
file.close()
/* Opens the **'./tempFile.txt'** file in append mode, writes "abcdefghi\n" to the file, and closes the file. */
file = File(filePath, OpenOption.Append)
file.write("abcdefghi\n".toArray())
file.close()
/* Opens the **'./tempFile.txt'** file in read-only mode, reads data in the file as required, and closes the file. */
file = File(filePath, OpenOption.Open(true, false))
let bytesBuf: Array<Byte> = Array<Byte>(10, item: 0)
// Reads a piece of data of 10 bytes after the 10th byte in the file header.
file.seek(SeekPosition.Begin(10))
file.read(bytesBuf)
println("Data of the 10th byte after the 10th byte: ${String.fromUtf8(bytesBuf)}")
// Reads a piece of data of 10 bytes in the file trailer.
file.seek(SeekPosition.End(-10))
file.read(bytesBuf)
println("Data of the last 10 bytes: ${String.fromUtf8(bytesBuf)}")
file.close()
/* Opens the **'./tempFile.txt'** file in truncation mode, writes "The file was truncated to an empty file!" to the file, and closes the file. */
file = File(filePath, OpenOption.Truncate(true))
file.write("The file was truncated to an empty file!".toArray())
file.seek(SeekPosition.Begin(0))
let allBytes: Array<Byte> = file.readToEnd()
file.close()
println("Data written newly: ${String.fromUtf8(allBytes)}")
File.delete(filePath)
return 0
}
Running result:
The file 'tempFile.txt' is created successfully in current directory.
Data of the 10th byte after the 10th byte: 123456789
Data of the last 10 bytes: abcdefghi
Data written newly: The file was truncated to an empty file!
Demonstration of static Functions of File
Code:
import std.fs.*
main() {
let filePath: Path = Path("./tempFile.txt")
if (File.exists(filePath)) {
File.delete(filePath)
}
/* Creates a file in write-only mode, writes "123456789\n" to the file, and closes the file. */
var file: File = File.create(filePath)
file.write("123456789\n".toArray())
file.close()
/* Writes "abcdefghi\n" to the file in append mode. */
File.writeTo(filePath, "abcdefghi".toArray(), openOption: OpenOption.Append)
/* Directly reads all data in the file. */
let allBytes: Array<Byte> = File.readFrom(filePath)
println(String.fromUtf8(allBytes))
File.delete(filePath)
return 0
}
Running result:
123456789
abcdefghi
FileInfo Example
Demonstration of Basic Operations of FileInfo
Code:
import std.fs.*
import std.time.DateTime
main() {
// Creates a temporary file in the current directory for the following demonstration of FileInfo.
let curDirPath: Path = Path("./").toCanonical()
let file: File = File.createTemp(curDirPath)
file.write("123456789\n".toArray())
let fileInfo: FileInfo = file.info
file.close()
/* Obtains FileInfo of the parent directory of the file. The parent directory of the file is the current directory. */
let parentDirectory: Option<FileInfo> = fileInfo.parentDirectory
checkResult(parentDirectory == Some(FileInfo(curDirPath)), "The 'parentFileInfo' is obtained successfully.")
/* Obtains the path of the file. */
/*
let filePath: Path = fileInfo.path
*/
/* Obtains the path of the link file if the file is a soft link. Since this file is not a soft link, Option<Path>.None is obtained. */
let symbolicLinkTarget: Option<Path> = fileInfo.symbolicLinkTarget
checkResult(symbolicLinkTarget == None, "It's not a symbolic link, there's no `symbolicLinkTarget`.")
/* Obtains the creation time, last access time, and last modification time of the file. */
/*
let creationTime: DateTime = fileInfo.creationTime
let lastAccessTime: DateTime = fileInfo.lastAccessTime
let lastModificationTime: DateTime = fileInfo.lastModificationTime
*/
/*
* Obtains the length of the file.
* For a file, obtains the disk space occupied by the file.
* For a directory, obtains the disk space occupied by all files in the directory (excluding subdirectories).
*/
/*
let length: Int64 = fileInfo.length
*/
/* Checks whether the file is a soft link, common file, or directory. */
checkResult(fileInfo.isSymbolicLink(), "The file is a symbolic link.")
checkResult(fileInfo.isFile(), "The file is a common file.")
checkResult(fileInfo.isDirectory(), "The file is a directory.")
/* Checks whether the file is read-only, hidden, executable, readable, or writable by the current user. */
checkResult(fileInfo.isReadOnly(), "This file is read-only.")
checkResult(fileInfo.isHidden(), "The file is hidden.")
checkResult(fileInfo.canExecute(), "The file is executable.")
checkResult(fileInfo.canRead(), "The file is readable.")
checkResult(fileInfo.canWrite(), "The file is writable.")
/* Modifies the permission of the current user on the file. In this example, the read-only permission on the file is granted. */
checkResult(fileInfo.setExecutable(false), "The file was successfully set to executable.")
checkResult(fileInfo.setReadable(true), "The file was successfully set to readable.")
checkResult(fileInfo.setWritable(false), "The file was successfully set to writable.")
checkResult(fileInfo.isReadOnly(), "This file is now read-only.")
return 0
}
func checkResult(result: Bool, message: String): Unit {
if (result) {
println(message)
}
}
Running result:
The 'parentFileInfo' is obtained successfully.
It's not a symbolic link, there's no `symbolicLinkTarget`.
The file is a common file.
The file is readable.
The file is writable.
The file was successfully set to executable.
The file was successfully set to readable.
The file was successfully set to writable.
This file is now read-only.
Path Example
Attributes of Different Path Instances
Prints the directory portion, full file name (with a file name extension), file name extension, or file name (without a file name extension) of a Path instance, and determines whether the Path instance is an absolute path or a relative path.
Code:
import std.fs.Path
main() {
let pathStrArr: Array<String> = [
// Absolute path
"/a/b/c",
"/a/b/",
"/a/b/c.cj",
"/a",
"/",
// Relative path
"./a/b/c",
"./a/b/",
"./a/b/c.cj",
"./",
".",
"123."
]
for (i in 0..pathStrArr.size) {
let path: Path = Path(pathStrArr[i])
// Prints the entire path string.
println("Path${i}: ${path.toString()}")
// Prints the directory path.
println("Path.directoryName: ${path.directoryName}")
// Prints the full file name of the path (with a file name extension).
println("Path.fileName: ${path.fileName}")
// Prints the path file name extension.
println("Path.extensionName: ${path.extensionName}")
// Prints the file name of the path (without a file name extension).
println("Path.fileNameWithoutExtension: ${path.fileNameWithoutExtension}")
// Prints the directory path and full file name after the path is split.
var (directoryName, fileName): (Option<Path>, Option<String>) = path.split()
println("Path.split: (${directoryName}, ${fileName})")
// Prints whether the path is an absolute path or a relative path.
println("Path.isAbsolute: ${path.isAbsolute()}; Path.isRelative: ${path.isRelative()}")
println()
}
return 0
}
Running result:
Path0: /a/b/c
Path.directoryName: Some(/a/b)
Path.fileName: Some(c)
Path.extensionName: None
Path.fileNameWithoutExtension: Some(c)
Path.split: (Some(/a/b), Some(c))
Path.isAbsolute: true; Path.isRelative: false
Path1: /a/b/
Path.directoryName: Some(/a/b)
Path.fileName: None
Path.extensionName: None
Path.fileNameWithoutExtension: None
Path.split: (Some(/a/b), None)
Path.isAbsolute: true; Path.isRelative: false
Path2: /a/b/c.cj
Path.directoryName: Some(/a/b)
Path.fileName: Some(c.cj)
Path.extensionName: Some(cj)
Path.fileNameWithoutExtension: Some(c)
Path.split: (Some(/a/b), Some(c.cj))
Path.isAbsolute: true; Path.isRelative: false
Path3: /a
Path.directoryName: Some(/)
Path.fileName: Some(a)
Path.extensionName: None
Path.fileNameWithoutExtension: Some(a)
Path.split: (Some(/), Some(a))
Path.isAbsolute: true; Path.isRelative: false
Path4: /
Path.directoryName: Some(/)
Path.fileName: None
Path.extensionName: None
Path.fileNameWithoutExtension: None
Path.split: (Some(/), None)
Path.isAbsolute: true; Path.isRelative: false
Path5: ./a/b/c
Path.directoryName: Some(./a/b)
Path.fileName: Some(c)
Path.extensionName: None
Path.fileNameWithoutExtension: Some(c)
Path.split: (Some(./a/b), Some(c))
Path.isAbsolute: false; Path.isRelative: true
Path6: ./a/b/
Path.directoryName: Some(./a/b)
Path.fileName: None
Path.extensionName: None
Path.fileNameWithoutExtension: None
Path.split: (Some(./a/b), None)
Path.isAbsolute: false; Path.isRelative: true
Path7: ./a/b/c.cj
Path.directoryName: Some(./a/b)
Path.fileName: Some(c.cj)
Path.extensionName: Some(cj)
Path.fileNameWithoutExtension: Some(c)
Path.split: (Some(./a/b), Some(c.cj))
Path.isAbsolute: false; Path.isRelative: true
Path8: ./
Path.directoryName: Some(.)
Path.fileName: None
Path.extensionName: None
Path.fileNameWithoutExtension: None
Path.split: (Some(.), None)
Path.isAbsolute: false; Path.isRelative: true
Path9: .
Path.directoryName: None
Path.fileName: Some(.)
Path.extensionName: None
Path.fileNameWithoutExtension: None
Path.split: (None, Some(.))
Path.isAbsolute: false; Path.isRelative: true
Path10: 123.
Path.directoryName: None
Path.fileName: Some(123.)
Path.extensionName: None
Path.fileNameWithoutExtension: Some(123)
Path.split: (None, Some(123.))
Path.isAbsolute: false; Path.isRelative: true
Operations such as Path Concatenation, Equality Check, and Normalization
Code:
import std.fs.*
main() {
let dirPath: Path = Path("./a/b/c")
if (!Directory.exists(dirPath)) {
Directory.create(dirPath, recursive: true)
}
let filePath: Path = dirPath.join("d.cj") // ./a/b/c/d.cj
if (filePath == Path("./a/b/c/d.cj")) {
println("filePath.join: success")
}
if (!File.exists(filePath)) {
File.create(filePath).close()
}
let curNormalizedPath: Path = Path(".").toCanonical()
let fileNormalizedPath: Path = Path("././././a/./../a/b/../../a/b/c/.././../../a/b/c/d.cj").toCanonical()
if (fileNormalizedPath == filePath &&
fileNormalizedPath.toString() == curNormalizedPath.toString() + "/a/b/c/d.cj") {
println("filePath.toCanonical: success")
}
Directory.delete(dirPath, recursive: true)
return 0
}
Running result:
filePath.join: success
filePath.toCanonical: success
Creating Files and Directories Using Path
Code:
import std.fs.*
main() {
let curPath: Path = Path("./")
let dirPath: Path = curPath.join("tempDir")
let filePath: Path = dirPath.join("tempFile.txt")
if (Directory.exists(dirPath)) {
Directory.delete(dirPath, recursive: true)
}
Directory.create(dirPath)
if (Directory.exists(dirPath)) {
println("Directory 'tempDir' is created successfully.")
}
File.create(filePath).close()
if (File.exists(filePath)) {
println("File 'tempFile.txt' is created successfully in directory 'tempDir'.")
}
Directory.delete(dirPath, recursive: true)
return 0
}
Running result:
Directory 'tempDir' is created successfully.
File 'tempFile.txt' is created successfully in directory 'tempDir'.
std.io Package
Function Description
The io package provides the capability of data exchange between a program and an external device.
I/O operation refers to an operation of exchanging data between a program and an external device. Cangjie provides universal interfaces and some special implementations for streaming I/O operations. An input or output stream is similar to a data channel and carries a segment of ordered data. A program reads data (from a file or network) in the input stream and writes data to the output stream (to a file or network).
API List
Interface
| Name | Description |
|---|---|
| InputStream | Specifies input stream interface. |
| IOStream | Specifies input and output stream interface. |
| OutputStream | Specifies output stream interface. |
| Seekable | Moves the cursor. |
Class
| Name | Description |
|---|---|
| BufferedInputStream<T> where T <: InputStream | Provides input streams with buffers. |
| BufferedOutputStream<T> where T <: OutputStream | Provides output streams with buffers. |
| ByteArrayStream | Input stream interface. |
| ChainedInputStream<T> where T <: InputStream | Reads data from the InputStream array in sequence. |
| MultiOutputStream<T> where T <: OutputStream | Writes data to each output stream in the OutputStream array at the same time. |
| StringReader<T> where T <: InputStream | Reads data from the InputStream input stream and converts the data into characters or a string. |
| StringWriter<T> where T <: OutputStream | Converts strings and some ToString types to strings in a specified encoding format and byte order and writes the strings to the output stream. |
Enumeration
| Name | Description |
|---|---|
| SeekPosition | Input stream interface. |
Exception Class
| Name | Description |
|---|---|
| ContentFormatException | Handles exceptions related to character formats. |
| IOException | Handles exceptions related to I/O streams. |
Interface
interface IOStream
public interface IOStream <: InputStream & OutputStream {}
Description: Represents the I/O stream interface.
Parent Type:
interface InputStream
public interface InputStream {
func read(buffer: Array<Byte>): Int64
}
Description: Represents the input stream interface.
func read(Array<Byte>)
func read(buffer: Array<Byte>): Int64
Description: Reads data from the input stream and stores the data in buffer.
Parameters:
Returns:
- Int64: number of bytes of the read data
interface OutputStream
public interface OutputStream {
func write(buffer: Array<Byte>): Unit
func flush(): Unit
}
Description: Represents the output stream interface.
func flush()
func flush(): Unit
Description: Clears the buffer. This function provides default implementation. The function body is empty by default.
func write(Array<Byte>)
func write(buffer: Array<Byte>): Unit
Description: Writes data in buffer to the output stream.
Parameters:
interface Seekable
public interface Seekable {
prop length: Int64
prop position: Int64
prop remainLength: Int64
func seek(sp: SeekPosition): Int64
}
Description: Moves the cursor.
prop length
prop length: Int64
Description: Returns the total data volume of the current stream.
Type: Int64
prop position
prop position: Int64
Description: Returns the current cursor position.
Type: Int64
prop remainLength
prop remainLength: Int64
Description: Returns the unread data volume in the current stream.
Type: Int64
func seek(SeekPosition)
func seek(sp: SeekPosition): Int64
Description: Moves the cursor to a specified position.
Parameters:
- sp: SeekPosition: the position to which the cursor is to be moved
Returns:
- Int64: the offset (in bytes) from the start point of the data in the stream to the position after the cursor is moved
Class
class BufferedInputStream<T> where T <: InputStream
public class BufferedInputStream<T> <: InputStream where T <: InputStream {
public init(input: T)
public init(input: T, buffer: Array<Byte>)
public init(input: T, capacity: Int64)
}
Description: Provides input streams with buffers.
This class supports binding the input stream of other InputStream types (such as ByteArrayStream) to the BufferedInputStream instance. When data is read from the instance, the data is read from the bound stream to the buffer for temporary storage, and then the required data is read from the buffer.
Parent Type:
init(T)
public init(input: T)
Description: Creates a BufferedInputStream instance. The default buffer size is 4096.
Parameters:
- input: T: bound input stream
init(T, Array<Byte>)
public init(input: T, buffer: Array<Byte>)
Description: Creates a BufferedInputStream instance.
The internal buffer is determined by the input parameter. In performance-oriented scenarios, the input buffer can be reused to reduce the number of memory allocation times for better performance.
Parameters:
- input: T: bound input stream
- buffer: Array<Byte>: internal buffer used by BufferedInputStream
Throws:
- IllegalArgumentException: If the buffer size is equal to 0, this exception is thrown.
init(T, Int64)
public init(input: T, capacity: Int64)
Description: Creates a BufferedInputStream instance.
Parameters:
- input: T: bound input stream
- capacity: Int64: size of the internal buffer
Throws:
- IllegalArgumentException: If the value of capacity is less than or equal to 0, this exception is thrown.
func read(Array<Byte>)
public func read(buffer: Array<Byte>): Int64
Description: Reads data from the bound input stream to buffer.
Parameters:
Returns:
- Int64: number of bytes of the read data
Throws:
- IllegalArgumentException: If buffer is empty, this exception is thrown.
func reset(T)
public func reset(input: T): Unit
Description: Binds a new input stream and resets the status without resetting capacity.
Parameters:
- input: T: input stream to be bound
extend<T> BufferedInputStream<T> <: Resource where T <: Resource
extend<T> BufferedInputStream<T> <: Resource where T <: Resource
Description: Implements the Resource interface for BufferedInputStream. This type of object can implement automatic resource release in the try-with-resource syntax context.
Parent Type:
func close()
public func close(): Unit
Description: Closes the current stream.
Note:
- After this method is called, other interfaces of BufferedInputStream cannot be called. Otherwise, unexpected problems may occur.
func isClosed()
public func isClosed(): Bool
Description: Checks whether the current stream is closed.
Returns:
- Bool: true: yes, false: no
extend<T> BufferedInputStream<T> <: Seekable where T <: Seekable
extend<T> BufferedInputStream<T> <: Seekable where T <: Seekable
Description: Implements the Seekable interface for BufferedInputStream to implement operations such as querying data length and moving the cursor.
Parent Type:
prop length
public prop length: Int64
Description: Returns the total data volume of the current stream.
Type: Int64
prop position
public prop position: Int64
Description: Returns the current cursor position.
Type: Int64
prop remainLength
public prop remainLength: Int64
Description: Returns the unread data volume in the current stream.
Type: Int64
func seek(SeekPosition)
public func seek(sp: SeekPosition): Int64
Description: Moves the cursor to a specified position.
Note:
- The specified position cannot be before the data header in the stream.
- The specified position can be after the end of the data in the stream.
- If this function is called, the buffer is cleared before the cursor is moved.
Parameters:
- sp: SeekPosition: the position to which the cursor is to be moved
Returns:
- Int64: the offset (in bytes) from the start point of the data in the stream to the position after the cursor is moved
class BufferedOutputStream<T> where T <: OutputStream
public class BufferedOutputStream<T> <: OutputStream where T <: OutputStream {
public init(output: T)
public init(output: T, buffer: Array<Byte>)
public init(output: T, capacity: Int64)
}
Description: Provides output streams with buffers.
This class supports binding the input stream of the OutputStream type (such as ByteArrayStream) to a BufferedOutputStream instance. When data is written by using the instance, the data is written to the buffer for temporary storage, and then written from the buffer to the stream.
Parent Type:
init(T)
public init(output: T)
Description: Creates a BufferedOutputStream instance. The default buffer size is 4096.
Parameters:
- output: T: bound output stream
init(T, Array<Byte>)
public init(output: T, buffer: Array<Byte>)
Description: Creates a BufferedOutputStream instance.
The internal buffer is determined by the input parameter. In performance-oriented scenarios, the input buffer can be reused to reduce the number of memory allocation times for better performance.
Parameters:
- output: T: bound output stream
- buffer: Array<Byte>: internal buffer used by BufferedOutputStream
Throws:
- IllegalArgumentException: If the buffer size is equal to 0, this exception is thrown.
init(T, Int64)
public init(output: T, capacity: Int64)
Description: Creates a BufferedOutputStream instance.
Parameters:
- output: T: bound output stream
- capacity: Int64: size of the internal buffer
Throws:
- IllegalArgumentException: If the value of capacity is less than or equal to 0, this exception is thrown.
func flush()
public func flush(): Unit
Description: Refreshes BufferedOutputStream. Writes the remaining data in the internal buffer to the bound output stream and refreshes BufferedOutputStream.
func reset(T)
public func reset(output: T): Unit
Description: Binds a new output stream and resets the status without resetting capacity.
Parameters:
- output: T: output stream to be bound
func write(Array<Byte>)
public func write(buffer: Array<Byte>): Unit
Description: Writes data in buffer to the bound output stream.
Parameters:
extend<T> BufferedOutputStream<T> <: Resource where T <: Resource
extend<T> BufferedOutputStream<T> <: Resource where T <: Resource
Description: Implements the Resource interface for BufferedOutputStream. This type of object can implement automatic resource release in the try-with-resource syntax context.
Parent Type:
func close()
public func close(): Unit
Description: Closes the current stream.
Note:
- After this method is called, other interfaces of BufferedOutputStream cannot be called. Otherwise, unexpected problems may occur.
func isClosed()
public func isClosed(): Bool
Description: Checks whether the current stream is closed.
Returns:
- Bool: true: yes, false: no
extend<T> BufferedOutputStream<T> <: Seekable where T <: Seekable
extend<T> BufferedOutputStream<T> <: Seekable where T <: Seekable
Description: Implements the Seekable interface for BufferedOutputStream to implement operations such as querying data length and moving the cursor.
Parent Type:
prop length
public prop length: Int64
Description: Returns the total data volume of the current stream.
Type: Int64
prop position
public prop position: Int64
Description: Returns the current cursor position.
Type: Int64
prop remainLength
public prop remainLength: Int64
Description: Returns the unread data volume in the current stream.
Type: Int64
func seek(SeekPosition)
public func seek(sp: SeekPosition): Int64
Description: Moves the cursor to a specified position.
Note:
- The specified position cannot be before the data header in the stream.
- The specified position can be after the end of the data in the stream.
- When this function is called, the data in the buffer is written to the bound output stream before the cursor is moved.
Parameters:
- sp: SeekPosition: the position to which the cursor is to be moved
Returns:
- Int64: the offset (in bytes) from the start point of the data in the stream to the position after the cursor is moved
class ByteArrayStream
public class ByteArrayStream <: IOStream & Seekable {
public init()
public init(capacity: Int64)
}
Description: Writes and reads byte streams based on the Array<Byte> data type.
Parent Type:
prop length
public prop length: Int64
Description: Returns the total data volume of the current stream.
Type: Int64
prop position
public prop position: Int64
Description: Obtains the current cursor position.
Type: Int64
prop remainLength
public prop remainLength: Int64
Description: Obtains the unread data volume in the current stream.
Type: Int64
init()
public init()
Description: Creates a ByteArrayStream instance with a default initial capacity of 32.
init(Int64)
public init(capacity: Int64)
Description: Creates a ByteArrayStream instance.
Parameters:
- capacity: Int64: specified initial capacity
Throws:
- IllegalArgumentException: If the value of capacity is less than 0, this exception is thrown.
static func fromString(String)
public static func fromString(data: String): ByteArrayStream
Description: Constructs a ByteArrayStream using the String type.
Parameters:
- data: String: initial data of a new ByteArrayStream
Returns:
- ByteArrayStream: ByteArrayStream constructed by using data
func bytes()
public func bytes(): Array<Byte>
Description: Obtains the slice of the unread data in the current ByteArrayStream.
Note:
- Modifications such as reading, writing, or resetting the buffer will invalidate the slice.
- Modifications to a slice affect the content of the buffer.
Returns:
func capacity()
public func capacity(): Int64
Description: Obtains the size of the current buffer.
Returns:
- Int64: size of the current buffer
func clear()
public func clear(): Unit
Description: Clears all data in the current ByteArrayStream.
func clone()
public func clone(): ByteArrayStream
Description: Constructs a new ByteArrayStream using the data in the current ByteArrayStream.
Returns:
- ByteArrayStream: new ByteArrayStream object
func copyTo(OutputStream)
public func copyTo(output: OutputStream): Unit
Description: Copies the unread data in the current ByteArrayStream to the output stream.
Parameters:
- output: OutputStream: stream to which the data is to be copied
func read(Array<Byte>)
public func read(buffer: Array<Byte>): Int64
Description: Reads data from the input stream and stores the data in buffer.
Parameters:
Returns:
- Int64: number of bytes of the read data
Throws:
- IllegalArgumentException: If buffer is empty, this exception is thrown.
func readString()
public func readString(): String
Description: Reads the remaining data in the stream, converts the data to the String type, and checks whether the data complies with the UTF-8 encoding rule.
Returns:
Throws:
- ContentFormatException: If the remaining bytes do not comply with the UTF-8 encoding rule, this exception is thrown.
func readStringUnchecked()
public unsafe func readStringUnchecked(): String
Description: Reads the remaining data in the stream and converts the data to the String type without checking whether the data complies with the UTF-8 encoding rule.
Returns:
func readToEnd()
public func readToEnd(): Array<Byte>
Description: Obtains the unread data in the current ByteArrayStream.
Returns:
func reserve(Int64)
public func reserve(additional: Int64): Unit
Description: Expands the buffer by a specified size.
Note:
- If the number of remaining bytes in the buffer is greater than or equal to
additional, capacity expansion is not performed.- If the number of remaining bytes in the buffer is less than
additional, the buffer is expanded to the larger value between (additional+capacity) and (1.5 times the rounded-down value ofcapacity).
Parameters:
- additional: Int64: size by which the buffer is to be expanded
Throws:
- IllegalArgumentException: If the value of additional is less than 0, this exception is thrown.
- OverflowException: If the buffer size after capacity expansion is greater than the maximum value of Int64, this exception is thrown.
func seek(SeekPosition)
public func seek(sp: SeekPosition): Int64
Description: Moves the cursor to a specified position.
Note:
- The specified position cannot be before the data header in the stream.
- The specified position can be after the end of the data in the stream.
Parameters:
- sp: SeekPosition: the position to which the cursor is to be moved
Returns:
- Int64: the offset (in bytes) from the data header in the stream to the position to which the cursor is moved
Throws:
- IOException: If the specified position is before the data header in the stream, this exception is thrown.
func write(Array<Byte>)
public func write(buffer: Array<Byte>): Unit
Description: Writes data in buffer to the output stream.
Parameters:
Throws:
- IllegalArgumentException: If data fails to be written or only part of data is written, this exception is thrown.
class ChainedInputStream<T> where T <: InputStream
public class ChainedInputStream<T> <: InputStream where T <: InputStream {
public init(input: Array<T>)
}
Description: Reads data from the InputStream array in sequence.
Parent Type:
init(Array<T>)
public init(input: Array<T>)
Description: Creates a ChainedInputStream instance.
Parameters:
- input: Array<T>: bound input stream array
Throws:
- IllegalArgumentException: If input is empty, this exception is thrown.
func read(Array<Byte>)
public func read(buffer: Array<Byte>): Int64
Description: Reads data from the bound InputStream array and writes the data to buffer in sequence.
Parameters:
Returns:
- Int64: number of bytes read
Throws:
- IllegalArgumentException: If buffer is empty, this exception is thrown.
class MultiOutputStream<T> where T <: OutputStream
public class MultiOutputStream<T> <: OutputStream where T <: OutputStream {
public init(output: Array<T>)
}
Description: Writes data to each output stream in the OutputStream array at the same time.
Parent Type:
init(Array<T>)
public init(output: Array<T>)
Description: Creates a MultiOutputStream instance.
Parameters:
- output: Array<T>: bound output stream array
Throws:
- IllegalArgumentException: If output is empty, this exception is thrown.
func flush()
public func flush(): Unit
Description: Refreshes each output stream in the bound output stream array.
func write(Array<Byte>)
public func write(buffer: Array<Byte>): Unit
Description: Writes the value of buffer to each output stream in the bound OutputStream array.
Parameters:
class StringReader<T> where T <: InputStream
public class StringReader<T> where T <: InputStream {
public init(input: T)
}
Description: Reads data from the InputStream input stream and converts the data to characters or a string.
Note:
- By default, StringReader has a buffer with a size of 4096 bytes.
- Currently, StringReader supports only UTF-8 encoding.
init(T)
public init(input: T)
Description: Creates a StringReader instance.
Parameters:
- input: T: input stream from which the data to be read
func lines()
public func lines(): Iterator<String>
Description: Obtains the line iterator of StringReader.
It is equivalent to cyclically calling func readln(). If there is an invalid character, an exception is thrown.
Note:
- Each line ends with a newline character.
- The newline character can be
\n,\r, or\r\n.- The read line string does not contain the newline character at the end.
Returns:
Throws:
- ContentFormatException: If the
for-insyntax is used to traverse the iterator or an invalid character is read when thenext()method is called, this exception is thrown.
func read()
public func read(): ?Rune
Description: Reads data in a stream by character.
Returns:
- ?Rune: If data is read successfully, Option<Rune>.Some(c) is returned, where c is the character read. Otherwise, Option<Rune>.None is returned.
Throws:
- ContentFormatException: If an invalid character is read, this exception is thrown.
func readToEnd()
public func readToEnd(): String
Description: Reads the remaining data in a stream.
Returns:
- String: remaining data in the stream
Throws:
- ContentFormatException: If an invalid character is read, this exception is thrown.
func readUntil((Rune)->Bool)
public func readUntil(predicate: (Rune)->Bool): Option<String>
Description: Reads data in a stream to the character position (including the character) that makes predicate return true or to the end of the stream.
Parameters:
- predicate: (Rune)->Bool: expression for returning true under certain conditions
Returns:
- Option<String>: If data is read successfully, Option<String>.Some(str) is returned, where str is the string read. Otherwise, Option<String>.None is returned.
Throws:
- ContentFormatException: If an invalid character is read, this exception is thrown.
func readUntil(Rune)
public func readUntil(v: Rune): Option<String>
Description: Reads data in a stream to a specified character (including the character) or to the end of the stream.
Parameters:
- v: Rune: the specified character
Returns:
- Option<String>: If data is read successfully, Option<String>.Some(str) is returned, where str is the string read. Otherwise, Option<String>.None is returned.
Throws:
- ContentFormatException: If an invalid character is read, this exception is thrown.
func readln()
public func readln(): Option<String>
Description: Reads data in a stream by row.
Note:
- The original newline characters are removed from the read data.
Returns:
- Option<String>: If data is read successfully, Option<String>.Some(str) is returned, where str is the string read. Otherwise, Option<String>.None is returned.
Throws:
- ContentFormatException: If an invalid character is read, this exception is thrown.
func runes()
public func runes(): Iterator<Rune>
Description: Obtains the Rune iterator of StringReader.
Returns:
Throws:
- ContentFormatException: If an invalid character is read when
for-inornext()is called, this exception is thrown.
extend<T> StringReader<T> <: Resource where T <: Resource
extend<T> StringReader<T> <: Resource where T <: Resource
Description: Implements the Resource interface for StringReader. This type of object can implement automatic resource release in the try-with-resource syntax context.
Parent Type:
func close()
public func close(): Unit
Description: Closes the current stream.
Note:
- After this method is called, other interfaces of StringReader cannot be called. Otherwise, unexpected problems may occur.
func isClosed()
public func isClosed(): Bool
Description: Checks whether the current stream is closed.
Returns:
- Bool: true: yes, false: no
extend<T> StringReader<T> <: Seekable where T <: Seekable
extend<T> StringReader<T> <: Seekable where T <: Seekable
Description: Implements the Seekable interface for StringReader to implement operations such as querying data length and moving the cursor.
Parent Type:
prop length
public prop length: Int64
Description: Returns the total data volume of the current stream.
Type: Int64
prop position
public prop position: Int64
Description: Returns the current cursor position.
Type: Int64
prop remainLength
public prop remainLength: Int64
Description: Returns the unread data volume in the current stream.
Type: Int64
func seek(SeekPosition)
public func seek(sp: SeekPosition): Int64
Description: Moves the cursor to a specified position.
Note:
- The specified position cannot be before the data header in the stream.
- The specified position can be after the end of the data in the stream.
Parameters:
- sp: SeekPosition: the position to which the cursor is to be moved
Returns:
- Int64: the offset (in bytes) from the start point of the data in the stream to the position after the cursor is moved
class StringWriter<T> where T <: OutputStream
public class StringWriter<T> where T <: OutputStream {
public init(output: T)
}
Description: Converts String and some ToString types to strings in the specified encoding format and byte order and writes the strings to the output stream.
Note:
- By default, StringWriter has a buffer with a size of 4096 bytes.
- Currently, StringWriter supports only UTF-8 encoding.
init(T)
public init(output: T)
Description: Creates a StringWriter instance.
Parameters:
- output: T: output stream to which data is to be written
func flush()
public func flush(): Unit
Description: Refreshes the internal buffer, writes the data in the buffer to output, and refreshes output.
func write(Bool)
public func write(v: Bool): Unit
Description: Writes the Bool type.
Parameters:
func write(Float16)
public func write(v: Float16): Unit
Description: Writes the Float16 type.
Parameters:
func write(Float32)
public func write(v: Float32): Unit
Description: Writes the Float32 type.
Parameters:
func write(Float64)
public func write(v: Float64): Unit
Description: Writes the Float64 type.
Parameters:
func write(Int16)
public func write(v: Int16): Unit
Description: Writes the Int16 type.
Parameters:
func write(Int32)
public func write(v: Int32): Unit
Description: Writes the Int32 type.
Parameters:
func write(Int64)
public func write(v: Int64): Unit
Description: Writes the Int64 type.
Parameters:
func write(Int8)
public func write(v: Int8): Unit
Description: Writes the Int8 type.
Parameters:
func write(Rune)
public func write(v: Rune): Unit
Description: Writes the Rune type.
Parameters:
func write(String)
public func write(v: String): Unit
Description: Writes a string.
Parameters:
- v: String: string to be written
func write(UInt16)
public func write(v: UInt16): Unit
Description: Writes the UInt16 type.
Parameters:
func write(UInt32)
public func write(v: UInt32): Unit
Description: Writes the UInt32 type.
Parameters:
func write(UInt64)
public func write(v: UInt64): Unit
Description: Writes the UInt64 type.
Parameters:
func write(UInt8)
public func write(v: UInt8): Unit
Description: Writes the UInt8 type.
Parameters:
func write<T>(T) where T <: ToString
public func write<T>(v: T): Unit where T <: ToString
Description: Writes the ToString type.
Parameters:
- v: T: instance of the ToString type
func writeln()
public func writeln(): Unit
Description: Writes a newline character.
func writeln(Bool)
public func writeln(v: Bool): Unit
Description: Writes the Bool type and newline characters.
Parameters:
func writeln(Float16)
public func writeln(v: Float16): Unit
Description: Writes the Float16 type and newline characters.
Parameters:
func writeln(Float32)
public func writeln(v: Float32): Unit
Description: Writes the Float32 type and newline characters.
Parameters:
func writeln(Float64)
public func writeln(v: Float64): Unit
Description: Writes the Float64 type and newline characters.
Parameters:
func writeln(Int16)
public func writeln(v: Int16): Unit
Description: Writes the Int16 type and newline characters.
Parameters:
func writeln(Int32)
public func writeln(v: Int32): Unit
Description: Writes the Int32 type and newline characters.
Parameters:
func writeln(Int64)
public func writeln(v: Int64): Unit
Description: Writes the Int64 type and newline characters.
Parameters:
func writeln(Int8)
public func writeln(v: Int8): Unit
Description: Writes the Int8 type and newline characters.
Parameters:
func writeln(Rune)
public func writeln(v: Rune): Unit
Description: Writes the Rune type and newline characters.
Parameters:
func writeln(String)
public func writeln(v: String): Unit
Description: Writes a string and a newline character.
Parameters:
- v: String: string to be written
func writeln(UInt16)
public func writeln(v: UInt16): Unit
Description: Writes the UInt16 type and newline characters.
Parameters:
func writeln(UInt32)
public func writeln(v: UInt32): Unit
Description: Writes the UInt32 type and newline characters.
Parameters:
func writeln(UInt64)
public func writeln(v: UInt64): Unit
Description: Writes the UInt64 type and newline characters.
Parameters:
func writeln(UInt8)
public func writeln(v: UInt8): Unit
Description: Writes the UInt8 type and newline characters.
Parameters:
func writeln<T>(T) where T <: ToString
public func writeln<T>(v: T): Unit where T <: ToString
Description: Writes the ToString type and newline characters.
Parameters:
- v: T: instance of the ToString type
extend<T> StringWriter<T> <: Resource where T <: Resource
extend<T> StringWriter<T> <: Resource where T <: Resource
Description: Implements the Resource interface for StringWriter. This type of object can implement automatic resource release in the try-with-resource syntax context.
Parent Type:
func close()
public func close(): Unit
Description: Closes the current stream.
Note:
- After this method is called, other interfaces of StringWriter cannot be called. Otherwise, unexpected problems may occur.
func isClosed()
public func isClosed(): Bool
Description: Checks whether the current stream is closed.
Returns:
- Bool: true: yes, false: no
extend<T> StringWriter<T> <: Seekable where T <: Seekable
extend<T> StringWriter<T> <: Seekable where T <: Seekable
Description: Implements the Seekable interface for StringWriter to implement operations such as querying data length and moving the cursor.
Parent Type:
prop length
public prop length: Int64
Description: Returns the total data volume of the current stream.
Type: Int64
prop position
public prop position: Int64
Description: Returns the current cursor position.
Type: Int64
prop remainLength
public prop remainLength: Int64
Description: Returns the unread data volume in the current stream.
Type: Int64
func seek(SeekPosition)
public func seek(sp: SeekPosition): Int64
Description: Moves the cursor to a specified position.
Note:
- The specified position cannot be before the data header in the stream.
- The specified position can be after the end of the data in the stream.
Parameters:
- sp: SeekPosition: the position to which the cursor is to be moved
Returns:
- Int64: the offset (in bytes) from the start point of the data in the stream to the position after the cursor is moved
Enumeration
enum SeekPosition
public enum SeekPosition {
| Begin(Int64)
| Current(Int64)
| End(Int64)
}
Description: Indicates the position of the cursor in the file.
Begin(Int64)
Begin(Int64)
Description: Moves the cursor from the start point.
Current(Int64)
Current(Int64)
Description: Moves the cursor from the current position.
End(Int64)
End(Int64)
Description: Moves the cursor from the end.
Exception
class ContentFormatException
public class ContentFormatException <: Exception {
public init()
public init(message: String)
}
Description: Handles exceptions related to character formats.
Parent Type:
init()
public init()
Description: Creates a ContentFormatException instance.
init(String)
public init(message: String)
Description: Creates a ContentFormatException instance according to exception information.
Parameters:
- message: String: exception information
class IOException
public class IOException <: Exception {
public init()
public init(message: String)
}
Description: Provides I/O stream-related exception processing.
Parent Type:
init()
public init()
Description: Creates an IOException instance.
init(String)
public init(message: String)
Description: Creates an IOException instance according to exception information.
Parameters:
- message: String: exception information
BufferedInputStream Example
The following is an example of reading data from a stream using BufferedInputStream.
import std.io.*
main(): Unit {
let arr1 = "0123456789".toArray()
let byteArrayStream = ByteArrayStream()
byteArrayStream.write(arr1)
let bufferedInputStream = BufferedInputStream(byteArrayStream)
let arr2 = Array<Byte>(20, item: 0)
/* Reads the data in the stream and returns the length of the read data. */
let readLen = bufferedInputStream.read(arr2)
println(String.fromUtf8(arr2[..readLen]))
}
Running result:
0123456789
BufferedOutputStream Example
The following is an example of writing data to a stream using BufferedOutputStream.
import std.io.*
main(): Unit {
let arr1 = "01234".toArray()
let byteArrayStream = ByteArrayStream()
byteArrayStream.write(arr1)
let bufferedInputStream = BufferedOutputStream(byteArrayStream)
let arr2 = "56789".toArray()
/* Writes data in the buffer of an external stream to a stream. */
bufferedInputStream.write(arr2)
/* Calls the flush function to write data to the internal stream. */
bufferedInputStream.flush()
println(String.fromUtf8(byteArrayStream.readToEnd()))
}
Running result:
0123456789
ByteArrayStream Example
The following is an example of writing data to and reading data from a stream using ByteArrayStream.
import std.io.*
main(): Unit {
let arr1 = "test case".toArray()
let byteArrayStream = ByteArrayStream()
/* Writes the data in **arr1** to the stream. */
byteArrayStream.write(arr1)
/* Reads a piece of data of 4 bytes to **arr2**. */
let arr2 = Array<Byte>(4, item: 0)
byteArrayStream.read(arr2)
println(String.fromUtf8(arr2))
/* Points the flow index to the start point. */
byteArrayStream.seek(Begin(0))
/* Reads all data in the stream. */
let arr3 = byteArrayStream.readToEnd()
println(String.fromUtf8(arr3))
/* Points the flow index to the letter c. */
byteArrayStream.seek(End(-4))
/* Reads the remaining data in the stream. */
let str = byteArrayStream.readString()
println(str)
}
Running result:
test
test case
case
ChainedInputStream Example
The following is an example of reading data from a bound stream cyclically using ChainedInputStream.
import std.io.*
import std.collection.ArrayList
main(): Unit {
const size = 2
/* Creates two ByteArrayStream instances and writes data to them. */
let streamArr = Array<InputStream>(size, {_ => ByteArrayStream()})
for (i in 0..size) {
match (streamArr[i]) {
case v: OutputStream =>
let str = "now ${i}"
v.write(str.toArray())
case _ => throw Exception()
}
}
/* Binds the two ByteArrayStream instances to ChainedInputStream. */
let chainedInputStream = ChainedInputStream(streamArr)
let res = ArrayList<Byte>()
let buffer = Array<Byte>(20, item: 0)
var readLen = chainedInputStream.read(buffer)
/* Reads data from chainedInputStream cyclically. */
while (readLen != 0) {
res.appendAll(buffer[..readLen])
readLen = chainedInputStream.read(buffer)
}
println(String.fromUtf8(res.toArray()))
}
Running result:
now 0now 1
MultiOutputStream Example
The following is an example of writing data to all bound streams using MultiOutputStream.
import std.io.*
main(): Unit {
const size = 2
/* Binds two ByteArrayStream instances to MultiOutputStream. */
let streamArr = Array<OutputStream>(size, {_ => ByteArrayStream()})
let multiOutputStream = MultiOutputStream(streamArr)
/* Writes data to MultiOutputStream. The data is written to the two bound ByteArrayStream instances at the same time. */
multiOutputStream.write("test".toArray())
/* Reads data from ByteArrayStream and verifies the result. */
for (i in 0..size) {
match (streamArr[i]) {
case v: ByteArrayStream =>
println(String.fromUtf8(v.readToEnd()))
case _ => throw Exception()
}
}
}
Running result:
test
test
StringReader Example
The following is an example of reading data from a stream using StringReader.
import std.io.*
main(): Unit {
let arr1 = "012\n346789".toArray()
let byteArrayStream = ByteArrayStream()
byteArrayStream.write(arr1)
let stringReader = StringReader(byteArrayStream)
/* Reads a byte. */
let ch = stringReader.read()
println(ch ?? 'a')
/* Reads a row of data. */
let line = stringReader.readln()
println(line ?? "error")
/* Reads data until character 6 is read. */
let until = stringReader.readUntil(r'6')
println(until ?? "error")
/* Reads all data. */
let all = stringReader.readToEnd()
println(all)
}
Running result:
0
12
346
789
StringWriter Example
The following is an example of writing data to a stream using StringWriter.
import std.io.*
main(): Unit {
let byteArrayStream = ByteArrayStream()
let stringWriter = StringWriter(byteArrayStream)
/* Writes a string.*/
stringWriter.write("number")
/* Writes a string and enters a newline character. */
stringWriter.writeln(" is:")
/* Writes a number. */
stringWriter.write(100.0f32)
stringWriter.flush()
println(String.fromUtf8(byteArrayStream.readToEnd()))
}
Running result:
number is:
100.000000
std.log Package
Function Description
The log package provides the log management and printing functions. (This package has been discarded. Use the log package.)
API List
Interface
| Name | Description |
|---|---|
| Logger | Manages and prints logs. |
Class
| Name | Description |
|---|---|
| SimpleLogger | Implements the Logger interface and provides basic log printing and management functions. |
Enumeration
| Name | Description |
|---|---|
| LogLevel | Provides basic log printing and management functions. |
Interface
interface Logger
public interface Logger {
mut prop level: LogLevel
func setOutput(output: OutputStream): Unit
func trace(msg: String): Unit
func debug(msg: String): Unit
func info(msg: String): Unit
func warn(msg: String): Unit
func error(msg: String): Unit
func log(level: LogLevel, msg: String): Unit
}
This interface is used to manage and print logs.
prop level
mut prop level: LogLevel
Description: Obtains and modifies the logging level. Only logs whose levels are lower than or equal to the value of LogLevel are printed.
Type: LogLevel
func debug(String)
func debug(msg: String): Unit
Description: Prints DEBUG-level logs.
Parameters:
- msg: String: log content
func error(String)
func error(msg: String): Unit
Description: Prints ERROR-level logs.
Parameters:
- msg: String: log content
func info(String)
func info(msg: String): Unit
Description: Prints INFO-level logs.
Parameters:
- msg: String: log content
func log(LogLevel, String)
func log(level: LogLevel, msg: String): Unit
Description: Prints logs. The log level must be specified.
Parameters:
func setOutput(OutputStream)
func setOutput(output: OutputStream): Unit
Description: Sets the log output stream to which log information is printed.
Parameters:
- output: OutputStream: output stream
func trace(String)
func trace(msg: String): Unit
Description: Prints TRACE-level logs. If the print level is lower than TRACE, the log information is ignored. Otherwise, the log information is printed to the output stream. This rule applies to the following log printing functions.
Parameters:
- msg: String: log content
func warn(String)
func warn(msg: String): Unit
Description: Prints WARN-level logs.
Parameters:
- msg: String: log content
Class
class SimpleLogger
public class SimpleLogger <: Logger {
public init()
public init(name: String, level: LogLevel, output: OutputStream)
}
Description: Implements the Logger interface and provides basic log printing and management functions.
This class supports customizing the log name, logging level, and output stream. By default, the log name is "Logger", the print level is INFO, and the output stream is stdOut.
Parent Type:
prop level
public mut prop level: LogLevel
Description: Obtains and modifies the logging level.
Type: LogLevel
init()
public init()
Description: Creates a default SimpleLogger instance.
init(String, LogLevel, OutputStream)
public init(name: String, level: LogLevel, output: OutputStream)
Description: Creates a SimpleLogger instance and specifies the log name, logging level, and output stream.
Parameters:
- name: String: log name
- level: LogLevel: log level
- output: OutputStream: output stream
func debug(String)
public func debug(msg: String): Unit
Description: Prints DEBUG-level logs.
Parameters:
- msg: String: log content
func error(String)
public func error(msg: String): Unit
Description: Prints ERROR-level logs.
Parameters:
- msg: String: log content
func flush()
public func flush(): Unit
Description: Refreshes the output stream.
func info(String)
public func info(msg: String): Unit
Description: Prints INFO-level logs.
Parameters:
- msg: String: log content
func log(LogLevel, String)
public func log(level: LogLevel, msg: String): Unit
Description: Prints logs. The log level must be specified.
Parameters:
func setOutput(OutputStream)
public func setOutput(output: OutputStream): Unit
Description: Sets the output stream to which log information is printed.
Parameters:
- output: OutputStream: output stream
func trace(String)
public func trace(msg: String): Unit
Description: Prints TRACE-level logs.
Parameters:
- msg: String: log content
func warn(String)
public func warn(msg: String): Unit
Description: Prints WARN-level logs.
Parameters:
- msg: String: log content
Enumeration
enum LogLevel
public enum LogLevel <: ToString {
| OFF
| ERROR
| WARN
| INFO
| DEBUG
| TRACE
| ALL
}
Description: Indicates the print level.
Seven logging levels are defined, which are OFF, ERROR, WARN, INFO, DEBUG, TRACE, and ALL in ascending order.
In the implementation of the SimpleLogger class, the logging level and the level of each log are specified. Only the logs whose levels are lower than or equal to the specified print level are printed to the output stream.
Parent Type:
ALL
ALL
Description: Constructs an enumeration instance of the logging level of ALL.
DEBUG
DEBUG
Description: Constructs an enumeration instance of the logging level of DEBUG.
ERROR
ERROR
Description: Constructs an enumeration instance of the logging level of ERROR.
INFO
INFO
Description: Constructs an enumeration instance of the logging level of INFO.
OFF
OFF
Description: Constructs an enumeration instance of the logging level of OFF.
TRACE
TRACE
Description: Constructs an enumeration instance of the logging level of TRACE.
WARN
WARN
Description: Constructs an enumeration instance of the logging level of WARN.
func level()
public func level(): Int64
Description: Obtains the number corresponding to a log level, such as 1 for OFF and 2 for ERROR. The number increases by 1 in sequence.
Returns:
- Int64: number corresponding to the current log level
func toString()
public func toString(): String
Description: Obtains the name of a log level.
Returns:
- String: name of the current log level
operator func >=(LogLevel)
public operator func >=(target: LogLevel): Bool
Description: Compares two log levels.
Parameters:
- target: LogLevel:
targetto be compared with the current log level
Returns:
- Bool: If the current log level is higher than or equal to
target,trueis returned. Otherwise,falseis returned.
Log Printing Example
Printing ALL-level Logs
The following is an example of printing ALL-level logs.
Code:
import std.log.*
main(): Int64 {
let logger: SimpleLogger = SimpleLogger()
logger.level = LogLevel.ALL
logger.log(LogLevel.ALL, "============== The log level is ALL.================")
logger.log(LogLevel.TRACE,
"=============="+logger.level.toString()+"================")
logger.log (LogLevel.OFF, "Print OFF-level logs!")
logger.log(LogLevel.ERROR, "Print ERROR-level logs!")
logger.log(LogLevel.WARN, "Print WARN-level logs!")
logger.log(LogLevel.INFO, "Print INFO-level logs!")
logger.log(LogLevel.DEBUG, "Print DEBUG-level logs!")
logger.log(LogLevel.TRACE, "Print TRACE-level logs!")
logger.log(LogLevel.ALL, "Print ALL-level logs!")
logger.flush()
0
}
Running result:
2021/08/05 08:20:42.692770 ALL Logger ============== The log level is ALL.================
2021/08/05 08:20:42.696645 TRACE Logger ==============ALL================
2021/08/05 08:20:42.700188 ERROR Logger Print ERROR-level logs!
2021/08/05 08:20:42.703576 WARN Logger Print WARN-level logs!
2021/08/05 08:20:42.706920 INFO Logger Print INFO-level logs!
2021/08/05 08:20:42.710268 DEBUG Logger Print DEBUG-level logs!
2021/08/05 08:20:42.713602 TRACE Logger Print TRACE-level logs!
2021/08/05 08:20:42.716940 ALL Logger Print ALL-level logs!
Specifying the Log Level and Output Stream
In the following example, the first part specifies the print level as ERROR and the output stream as the error_log.txt file, and the second part specifies the print level as WARN and the output stream as the warn_log.txt file.
Code:
import std.fs.*
import std.log.*
main(): Int64 {
let logger: SimpleLogger = SimpleLogger()
logger.level = LogLevel.ERROR
var s = File("./error_log.txt", OpenOption.CreateOrTruncate(false))
logger.setOutput(s)
logger.log(LogLevel.ERROR, "============== The log level is ERROR.================")
logger.log(LogLevel.ERROR,
"=============="+logger.level.toString()+"================")
logger.log (LogLevel.OFF, "Print OFF-level logs!")
logger.log(LogLevel.ERROR, "Print ERROR-level logs!")
logger.log(LogLevel.WARN, "Print WARN-level logs!")
logger.log(LogLevel.INFO, "Print INFO-level logs!")
logger.log(LogLevel.DEBUG, "Print DEBUG-level logs!")
logger.log(LogLevel.TRACE, "Print TRACE-level logs!")
logger.log(LogLevel.ALL, "Print ALL-level logs!")
logger.flush()
s.close()
logger.level = LogLevel.WARN
s = File("./warn_log.txt", OpenOption.CreateOrTruncate(false))
logger.setOutput(s)
logger.log(LogLevel.WARN, "============== The log level is WARN.================")
logger.log(LogLevel.WARN,
"=============="+logger.level.toString()+"================")
logger.log (LogLevel.OFF, "Print OFF-level logs!")
logger.log(LogLevel.ERROR, "Print ERROR-level logs!")
logger.log(LogLevel.WARN, "Print WARN-level logs!")
logger.log(LogLevel.INFO, "Print INFO-level logs!")
logger.log(LogLevel.DEBUG, "Print DEBUG-level logs!")
logger.log(LogLevel.TRACE, "Print TRACE-level logs!")
logger.log(LogLevel.ALL, "Print ALL-level logs!")
logger.flush()
s.close()
0
}
Running result:
$ cat error_log.txt
2021/08/05 08:28:29.667441 ERROR Logger ============== The log level is ERROR.================
2021/08/05 08:28:29.671402 ERROR Logger ==============ERROR================
2021/08/05 08:28:29.674891 ERROR Logger Print ERROR-level logs!
$ cat warn_log.txt
2021/08/05 08:28:29.678978 WARN Logger ============== The log level is WARN.================
2021/08/05 08:28:29.682635 WARN Logger ==============WARN================
2021/08/05 08:28:29.686126 ERROR Logger Print ERROR-level logs!
2021/08/05 08:28:29.689561 WARN Logger Print WARN-level logs!
std.math Package
Function Description
The math package provides common functions such as mathematical operations, constant definition, and floating-point number processing.
The following capabilities are included:
- Definition of scientific constants and type constants
- Judgment and normalization of floating-point numbers
- Common bitwise operations
- General mathematical functions, such as absolute value, trigonometric function, exponent, and logarithmic calculation
- Greatest common divisor and least common multiple
API List
Function
| Name | Description |
|---|---|
| abs(Float16) | Obtains the absolute value of a half-precision floating-point number through calculation. |
| abs(Float32) | Obtains the absolute value of a single-precision floating-point number through calculation. |
| abs(Float64) | Obtains the absolute value of a double-precision floating-point number through calculation. |
| abs(Int8) | Obtains the absolute value of an 8-bit signed integer through calculation. |
| abs(Int16) | Obtains the absolute value of a 16-bit signed integer through calculation. |
| abs(Int32) | Obtains the absolute value of a 32-bit signed integer through calculation. |
| abs(Int64) | Obtains the absolute value of a 64-bit signed integer through calculation. |
| acos(Float16) | Obtains the arc cosine function value of a half-precision floating-point number through calculation, in radians. |
| acos(Float32) | Obtains the arc cosine function value of a single-precision floating-point number through calculation, in radians. |
| acos(Float64) | Obtains the arc cosine function value of a double-precision floating-point number through calculation, in radians. |
| acosh(Float16) | Obtains the inverse hyperbolic cosine function value of a half-precision floating-point number through calculation. |
| acosh(Float32) | Obtains the inverse hyperbolic cosine function value of a single-precision floating-point number through calculation. |
| acosh(Float64) | Obtains the inverse hyperbolic cosine function value of a double-precision floating-point number through calculation. |
| asin(Float16) | Obtains the arc sine function value of a half-precision floating-point number through calculation, in radians. |
| asin(Float32) | Obtains the arc sine function value of a single-precision floating-point number through calculation, in radians. |
| asin(Float64) | Obtains the arc sine function value of a double-precision floating-point number through calculation, in radians. |
| asinh(Float16) | Obtains the inverse hyperbolic sine function value of a half-precision floating-point number through calculation. |
| asinh(Float32) | Obtains the inverse hyperbolic sine function value of a single-precision floating-point number through calculation. |
| asinh(Float64) | Obtains the inverse hyperbolic sine function value of a double-precision floating-point number through calculation. |
| atan(Float16) | Obtains the arc tangent function value of a half-precision floating-point number through calculation, in radians. |
| atan(Float32) | Obtains the arc tangent function value of a single-precision floating-point number through calculation, in radians. |
| atan(Float64) | Obtains the arc tangent function value of a double-precision floating-point number through calculation, in radians. |
| atanh(Float16) | Obtains the inverse hyperbolic tangent function value of a half-precision floating-point number through calculation. |
| atanh(Float32) | Obtains the inverse hyperbolic tangent function value of a single-precision floating-point number through calculation. |
| atanh(Float64) | Obtains the inverse hyperbolic tangent function value of a double-precision floating-point number through calculation. |
| cbrt(Float16) | Obtains the cube root of a half-precision floating-point number through calculation. |
| cbrt(Float32) | Obtains the cube root of a single-precision floating-point number through calculation. |
| cbrt(Float64) | Obtains the cube root of a double-precision floating-point number through calculation. |
| ceil(Float16) | Obtains the rounded-up value of a half-precision floating-point number through calculation. |
| ceil(Float32) | Obtains the rounded-up value of a single-precision floating-point number through calculation. |
| ceil(Float64) | Obtains the rounded-up value of a double-precision floating-point number through calculation. |
| checkedAbs(Int8) | Checks and obtains the absolute value of an 8-bit signed integer through calculation. If the input parameter is the minimum value of the 8-bit signed integer, None is returned. Otherwise, Some(abs(x)) is returned. |
| checkedAbs(Int16) | Checks and obtains the absolute value of a 16-bit signed integer through calculation. If the input parameter is the minimum value of the 16-bit signed integer, None is returned. Otherwise, Some(abs(x)) is returned. |
| checkedAbs(Int32) | Checks and obtains the absolute value of a 32-bit signed integer through calculation. If the input parameter is the minimum value of the 32-bit signed integer, None is returned. Otherwise, Some(abs(x)) is returned. |
| checkedAbs(Int64) | Checks and obtains the absolute value of a 64-bit signed integer through calculation. If the input parameter is the minimum value of the 64-bit signed integer, None is returned. Otherwise, Some(abs(x)) is returned. |
| clamp(Float16, Float16, Float16) | Obtains the value of a floating-point number to which the clamp function with a given range is applied. If the floating-point number is within the range, the floating-point number is returned. If the floating-point number is less than the minimum value in the range, the minimum value is returned. If the floating-point number is greater than the maximum value in the range, the maximum value is returned. If the floating-point number is NaN, NaN is returned. |
| clamp(Float32, Float32, Float32) | Obtains the value of a floating-point number to which the clamp function with a given range is applied. If the floating-point number is within the range, the floating-point number is returned. If the floating-point number is less than the minimum value in the range, the minimum value is returned. If the floating-point number is greater than the maximum value in the range, the maximum value is returned. If the floating-point number is NaN, NaN is returned. |
| clamp(Float64, Float64, Float64) | Obtains the value of a floating-point number to which the clamp function with a given range is applied. If the floating-point number is within the range, the floating-point number is returned. If the floating-point number is less than the minimum value in the range, the minimum value is returned. If the floating-point number is greater than the maximum value in the range, the maximum value is returned. If the floating-point number is NaN, NaN is returned. |
| cos(Float16) | Obtains the cosine function value of a half-precision floating-point number through calculation, in radians. |
| cos(Float32) | Obtains the cosine function value of a single-precision floating-point number through calculation, in radians. |
| cos(Float64) | Obtains the cosine function value of a double-precision floating-point number through calculation, in radians. |
| cosh(Float16) | Obtains the hyperbolic cosine function value of a half-precision floating-point number through calculation. |
| cosh(Float32) | Obtains the hyperbolic cosine function value of a single-precision floating-point number through calculation. |
| cosh(Float64) | Obtains the hyperbolic cosine function value of a double-precision floating-point number through calculation. |
| countOne(Int8) | Obtains the number of bits of 1s in the binary expression of an 8-bit integer. |
| countOne(Int16) | Obtains the number of bits of 1s in the binary expression of a 16-bit integer. |
| countOne(Int32) | Obtains the number of bits of 1s in the binary expression of a 32-bit integer. |
| countOne(Int64) | Obtains the number of bits of 1s in the binary expression of a 64-bit integer. |
| countOne(UInt8) | Obtains the number of bits of 1s in the binary expression of an 8-bit unsigned integer. |
| countOne(UInt16) | Obtains the number of bits of 1s in the binary expression of a 16-bit unsigned integer. |
| countOne(UInt32) | Obtains the number of bits of 1s in the binary expression of a 32-bit unsigned integer. |
| countOne(UInt64) | Obtains the number of bits of 1s in the binary expression of a 64-bit unsigned integer. |
| erf(Float16) | Obtains the error value of a half-precision floating-point number through calculation. |
| erf(Float32) | Obtains the error value of a single-precision floating-point number through calculation. |
| erf(Float64) | Obtains the error value of a double-precision floating-point number through calculation. |
| exp(Float16) | Obtains the natural constant e raised to the power of x. |
| exp(Float32) | Obtains the natural constant e raised to the power of x. |
| exp(Float64) | Obtains the natural constant e raised to the power of x. |
| exp2(Float16) | Obtains 2 raised to the power of x. |
| exp2(Float32) | Obtains 2 raised to the power of x. |
| exp2(Float64) | Obtains 2 raised to the power of x. |
| floor(Float16) | Obtains the rounded-down value of a floating-point number through calculation. |
| floor(Float32) | Obtains the rounded-down value of a floating-point number through calculation. |
| floor(Float64) | Obtains the rounded-down value of a floating-point number through calculation. |
| gamma(Float16) | Obtains the gamma value of a floating-point number through calculation. |
| gamma(Float32) | Obtains the gamma value of a floating-point number through calculation. |
| gamma(Float64) | Obtains the gamma value of a floating-point number through calculation. |
| gcd(Int8, Int8) | Obtains the greatest common divisor of two 8-bit signed integers through calculation. |
| gcd(Int16, Int16) | Obtains the greatest common divisor of two 16-bit signed integers through calculation. |
| gcd(Int32, Int32) | Obtains the greatest common divisor of two 32-bit signed integers through calculation. |
| gcd(Int64, Int64) | Obtains the greatest common divisor of two 64-bit signed integers through calculation. |
| gcd(UInt16, UInt16) | Obtains the greatest common divisor of two 16-bit unsigned integers through calculation. |
| gcd(UInt32, UInt32) | Obtains the greatest common divisor of two 32-bit unsigned integers through calculation. |
| gcd(UInt64, UInt64) | Obtains the greatest common divisor of two 64-bit unsigned integers through calculation. |
| gcd(UInt8, UInt8) | Obtains the greatest common divisor of two 8-bit unsigned integers through calculation. |
| lcm(Int8, Int8) | Obtains the non-negative least common multiple of two 8-bit signed integers through calculation. The value 0 is returned only when any input parameter is 0. |
| lcm(Int16, Int16) | Obtains the non-negative least common multiple of two 16-bit signed integers through calculation. The value 0 is returned only when any input parameter is 0. |
| lcm(Int32, Int32) | Obtains the non-negative least common multiple of two 32-bit signed integers through calculation. The value 0 is returned only when any input parameter is 0. |
| lcm(Int64, Int64) | Obtains the non-negative least common multiple of two 64-bit signed integers through calculation. The value 0 is returned only when any input parameter is 0. |
| lcm(UInt8, UInt8) | Obtains the non-negative least common multiple of two 8-bit unsigned integers through calculation. The value 0 is returned only when any input parameter is 0. |
| lcm(UInt16, UInt16) | Obtains the non-negative least common multiple of two 16-bit unsigned integers through calculation. The value 0 is returned only when any input parameter is 0. |
| lcm(UInt32, UInt32) | Obtains the non-negative least common multiple of two 32-bit unsigned integers through calculation. The value 0 is returned only when any input parameter is 0. |
| lcm(UInt64, UInt64) | Obtains the non-negative least common multiple of two 64-bit unsigned integers through calculation. The value 0 is returned only when any input parameter is 0. |
| leadingZeros(Int8) | Obtains the number of consecutive 0s starting from the most significant bit (including signs) in the binary expression of an 8-bit signed integer. If the most significant bit is not 0, the value 0 is returned. |
| leadingZeros(Int16) | Obtains the number of consecutive 0s starting from the most significant bit in the binary expression of a 16-bit signed integer. If the most significant bit is not 0, the value 0 is returned. |
| leadingZeros(Int32) | Obtains the number of consecutive 0s starting from the most significant bit in the binary expression of a 32-bit signed integer. If the most significant bit is not 0, the value 0 is returned. |
| leadingZeros(Int64) | Obtains the number of consecutive 0s starting from the most significant bit in the binary expression of a 64-bit signed integer. If the most significant bit is not 0, the value 0 is returned. |
| leadingZeros(UInt8) | Obtains the number of consecutive 0s starting from the most significant bit in the binary expression of an 8-bit unsigned integer. |
| leadingZeros(UInt16) | Obtains the number of consecutive 0s starting from the most significant bit in the binary expression of a 16-bit unsigned integer. |
| leadingZeros(UInt32) | Obtains the number of consecutive 0s starting from the most significant bit in the binary expression of a 32-bit unsigned integer. |
| leadingZeros(UInt64) | Obtains the number of consecutive 0s starting from the most significant bit in the binary expression of a 64-bit unsigned integer. |
| log(Float16) | Obtains the logarithm of x with base e. |
| log(Float32) | Obtains the logarithm of x with base e. |
| log(Float64) | Obtains the logarithm of x with base e. |
| log10(Float16) | Obtains the logarithm of x with base 10. |
| log10(Float32) | Obtains the logarithm of x with base 10. |
| log10(Float64) | Obtains the logarithm of x with base 10. |
| log2(Float16) | Obtains the logarithm of x with base 2. |
| log2(Float32) | Obtains the logarithm of x with base 2. |
| log2(Float64) | Obtains the logarithm of x with base 2. |
| logBase(Float16, Float16) | Obtains the logarithm of x with base base. |
| logBase(Float32, Float32) | Obtains the logarithm of x with base base. |
| logBase(Float64, Float64) | Obtains the logarithm of x with base base. |
| max(Float16, Float16) | Obtains the larger value between two numbers. |
| max(Float32, Float32) | Obtains the larger value between two numbers. |
| max(Float64, Float64) | Obtains the larger value between two numbers. |
| max(Int8, Int8) | Obtains the larger value between two numbers. |
| max(Int16, Int16) | Obtains the larger value between two numbers. |
| max(Int32, Int32) | Obtains the larger value between two numbers. |
| max(Int64, Int64) | Obtains the larger value between two numbers. |
| max(UInt8, UInt8) | Obtains the larger value between two numbers. |
| max(UInt16, UInt16) | Obtains the larger value between two numbers. |
| max(UInt32, UInt32) | Obtains the larger value between two numbers. |
| max(UInt64, UInt64) | Obtains the larger value between two numbers. |
| maxNaN(Float16, Float16) | Obtains the larger value between two numbers. |
| maxNaN(Float32, Float32) | Obtains the larger value between two numbers. |
| maxNaN(Float64, Float64) | Obtains the larger value between two numbers. |
| min(Float16, Float16) | Obtains the smaller value between two numbers. |
| min(Float32, Float32) | Obtains the smaller value between two numbers. |
| min(Float64, Float64) | Obtains the smaller value between two numbers. |
| min(Int8, Int8) | Obtains the smaller value between two numbers. |
| min(Int16, Int16) | Obtains the smaller value between two numbers. |
| min(Int32, Int32) | Obtains the smaller value between two numbers. |
| min(Int64, Int64) | Obtains the smaller value between two numbers. |
| min(UInt8, UInt8) | Obtains the smaller value between two numbers. |
| min(UInt16, UInt16) | Obtains the smaller value between two numbers. |
| min(UInt32, UInt32) | Obtains the smaller value between two numbers. |
| min(UInt64, UInt64) | Obtains the smaller value between two numbers. |
| minNaN(Float16, Float16) | Obtains the smaller value between two numbers. |
| minNaN(Float32, Float32) | Obtains the smaller value between two numbers. |
| minNaN(Float64, Float64) | Obtains the smaller value between two numbers. |
| pow(Float32, Float32) | Obtains the floating-point number base raised to the power of exponent. |
| pow(Float32, Int32) | Obtains the floating-point number base raised to the power of exponent. |
| pow(Float64, Float64) | Obtains the floating-point number base raised to the power of exponent. |
| pow(Float64, Int64) | Obtains the floating-point number base raised to the power of exponent. |
| reverse(UInt8) | Obtains the number after bitwise inversion of an unsigned integer. |
| reverse(UInt16) | Obtains the number after bitwise inversion of an unsigned integer. |
| reverse(UInt32) | Obtains the number after bitwise inversion of an unsigned integer. |
| reverse(UInt64) | Obtains the number after bitwise inversion of an unsigned integer. |
| rotate(Int16, Int8) | Obtains the result of bitwise rotation of an integer. |
| rotate(Int32, Int8) | Obtains the result of bitwise rotation of an integer. |
| rotate(Int64, Int8) | Obtains the result of bitwise rotation of an integer. |
| rotate(Int8, Int8) | Obtains the result of bitwise rotation of an integer. |
| rotate(UInt16, Int8) | Obtains the result of bitwise rotation of an integer. |
| rotate(UInt32, Int8) | Obtains the result of bitwise rotation of an integer. |
| rotate(UInt64, Int8) | Obtains the result of bitwise rotation of an integer. |
| rotate(UInt8, Int8) | Obtains the result of bitwise rotation of an integer. |
| round(Float16) | Obtains the rounded-off value of a floating-point number through calculation based on the round-off rule in IEEE-754. |
| round(Float32) | Obtains the rounded-off value of a floating-point number through calculation based on the round-off rule in IEEE-754. |
| round(Float64) | Obtains the rounded-off value of a floating-point number through calculation based on the round-off rule in IEEE-754. |
| sin(Float16) | Obtains the sine function value of a half-precision floating-point number through calculation, in radians. |
| sin(Float32) | Obtains the sine function value of a single-precision floating-point number through calculation, in radians. |
| sin(Float64) | Obtains the sine function value of a double-precision floating-point number through calculation, in radians. |
| sinh(Float16) | Obtains the hyperbolic sine function value of a half-precision floating-point number through calculation. |
| sinh(Float32) | Obtains the hyperbolic sine function value of a single-precision floating-point number through calculation. |
| sinh(Float64) | Obtains the hyperbolic sine function value of a double-precision floating-point number through calculation. |
| sqrt(Float16) | Obtains the arithmetic square root of a floating-point number through calculation. |
| sqrt(Float32) | Obtains the arithmetic square root of a floating-point number through calculation. |
| sqrt(Float64) | Obtains the arithmetic square root of a floating-point number through calculation. |
| tan(Float16) | Obtains the tangent function value of a half-precision floating-point number through calculation, in radians. |
| tan(Float32) | Obtains the tangent function value of a single-precision floating-point number through calculation, in radians. |
| tan(Float64) | Obtains the tangent function value of a double-precision floating-point number through calculation, in radians. |
| tanh(Float16) | Obtains the hyperbolic tangent function value of a half-precision floating-point number through calculation. |
| tanh(Float32) | Obtains the hyperbolic tangent function value of a single-precision floating-point number through calculation. |
| tanh(Float64) | Obtains the hyperbolic tangent function value of a double-precision floating-point number through calculation. |
| throwIllegalArgumentException() | Throws an invalid parameter exception. |
| trailingZeros(Int8) | Obtains the number of consecutive 0s starting from the least significant bit in the binary expression of a 16-bit signed integer. If the least significant bit is not 0, the value 0 is returned. |
| trailingZeros(Int16) | Obtains the number of consecutive 0s starting from the least significant bit in the binary expression of a 16-bit signed integer. If the least significant bit is not 0, the value 0 is returned. |
| trailingZeros(Int32) | Obtains the number of consecutive 0s starting from the least significant bit in the binary expression of a 32-bit signed integer. If the least significant bit is not 0, the value 0 is returned. |
| trailingZeros(Int64) | Obtains the number of consecutive 0s starting from the least significant bit in the binary expression of a 64-bit signed integer. If the least significant bit is not 0, the value 0 is returned. |
| trailingZeros(UInt8) | Obtains the number of consecutive 0s starting from the least significant bit in the binary expression of an 8-bit unsigned integer. If the least significant bit is not 0, the value 0 is returned. |
| trailingZeros(UInt16) | Obtains the number of consecutive 0s starting from the least significant bit in the binary expression of a 16-bit unsigned integer. If the least significant bit is not 0, the value 0 is returned. |
| trailingZeros(UInt32) | Obtains the number of consecutive 0s starting from the least significant bit in the binary expression of a 32-bit unsigned integer. If the least significant bit is not 0, the value 0 is returned. |
| trailingZeros(UInt64) | Obtains the number of consecutive 0s starting from the least significant bit in the binary expression of a 64-bit unsigned integer. If the least significant bit is not 0, the value 0 is returned. |
| trunc(Float16) | Obtains the value after truncation of a floating-point number through calculation. |
| trunc(Float32) | Obtains the value after truncation of a floating-point number through calculation. |
| trunc(Float64) | Obtains the value after truncation of a floating-point number through calculation. |
Interface
| Name | Description |
|---|---|
| MathExtension | Specifies the auxiliary interface which is used to export prop attributes, such as PI and Max |
| Float16 | Extends half-precision floating-point numbers to support some mathematical constants. |
| Float32 | Extends single-precision floating-point numbers to support some mathematical constants. |
| Float64 | Extends double-precision floating-point numbers to support some mathematical constants. |
| Int8 | Extends 8-bit signed integers to support some mathematical constants. |
| Int16 | Extends 16-bit signed integers to support some mathematical constants. |
| Int32 | Extends 32-bit signed integers to support some mathematical constants. |
| Int64 | Extends 64-bit signed integers to support some mathematical constants. |
| UInt8 | Extends 8-bit unsigned integers to support some mathematical constants. |
| UInt16 | Extends 16-bit unsigned integers to support some mathematical constants. |
| UInt32 | Extends 32-bit unsigned integers to support some mathematical constants. |
| UInt64 | Extends 64-bit unsigned integers to support some mathematical constants. |
| IntNative | Extends platform-dependent signed integers to support some mathematical constants. |
| UIntNative | Extends platform-dependent unsigned integers to support some mathematical constants. |
Enumeration
| Enumeration | Description |
|---|---|
| RoundingMode | Specifies the enumeration class of rounding rules, including six rounding rules. In addition to the five rounding rules of floating-point numbers specified in IEEE 754, the most commonly used rounding off rule is provided. |
Functions
func abs(Float16)
public func abs(x: Float16): Float16
Description: Obtains the absolute value of a half-precision floating-point number.
Parameters:
- x: Float16: half-precision floating-point number input
Returns:
- Float16: The absolute value of the input parameter is returned.
Example:
import std.math.abs
main() {
let n: Float16 = -23.0
let abs = abs(n)
println(abs)
}
Running result:
23.000000
func abs(Float32)
public func abs(x: Float32): Float32
Description: Obtains the absolute value of a single-precision floating-point number.
Parameters:
- x: Float32: single-precision floating-point number input
Returns:
- Float32: The absolute value of the input parameter is returned.
Example:
import std.math.abs
main() {
let n: Float32 = -23.0
let abs = abs(n)
println(abs)
}
Running result:
23.000000
func abs(Float64)
public func abs(x: Float64): Float64
Description: Obtains the absolute value of a double-precision floating-point number.
Parameters:
- x: Float64: double-precision floating-point number input
Returns:
- Float64: The absolute value of the input parameter is returned.
Example:
import std.math.abs
main() {
let n: Float64 = -23.0
let abs = abs(n)
println(abs)
}
Running result:
23.000000
func abs(Int16)
public func abs(x: Int16): Int16
Description: Obtains the absolute value of a 16-bit signed integer.
Parameters:
- x: Int16: 16-bit signed integer input
Returns:
- Int16: The absolute value of the input parameter is returned.
Throws:
- OverflowException: When the input parameter is the minimum value of the signed integer, this exception is thrown.
Example:
import std.math.abs
main() {
let n: Int16 = -23
let abs = abs(n)
println(abs)
}
Running result:
23
func abs(Int32)
public func abs(x: Int32): Int32
Description: Obtains the absolute value of a 32-bit signed integer.
Parameters:
- x: Int32: 32-bit signed integer input
Returns:
- Int32: The absolute value of the input parameter is returned.
Throws:
- OverflowException: When the input parameter is the minimum value of the signed integer, this exception is thrown.
Example:
import std.math.abs
main() {
let n: Int32 = -23
let abs = abs(n)
println(abs)
}
Running result:
23
func abs(Int64)
public func abs(x: Int64): Int64
Description: Obtains the absolute value of a 64-bit signed integer.
Parameters:
- x: Int64: 64-bit signed integer input
Returns:
- Int64: The absolute value of the input parameter is returned.
Throws:
- OverflowException: When the input parameter is the minimum value of the signed integer, this exception is thrown.
Example:
import std.math.abs
main() {
let n: Int64 = -23
let abs = abs(n)
println(abs)
}
Running result:
23
func abs(Int8)
public func abs(x: Int8): Int8
Description: Obtains the absolute value of an 8-bit signed integer.
Parameters:
- x: Int8: 8-bit signed integer input
Returns:
- Int8: The absolute value of the input parameter is returned.
Throws:
- OverflowException: When the input parameter is the minimum value of the signed integer, this exception is thrown.
Example:
import std.math.abs
main() {
let n: Int8 = -23
let abs = abs(n)
println(abs)
}
Running result:
23
func acos(Float16)
public func acos(x: Float16): Float16
Description: Obtains the arc cosine function value of a half-precision floating-point number through calculation.
Parameters:
- x: Float16: half-precision floating-point number input (–1.0 ≤
x≤ 1.0)
Returns:
- Float16: The arc cosine function value of the input parameter, in radians, is returned.
Throws:
- IllegalArgumentException: When the value of parameter
xis greater than 1.0 or less than –1.0, this exception is thrown.
Example:
import std.math.acos
main() {
let n: Float16 = 1.0
let acos = acos(n)
println(acos)
}
Running result:
0.000000
func acos(Float32)
public func acos(x: Float32): Float32
Description: Obtains the arc cosine function value of a single-precision floating-point number through calculation.
Parameters:
- x: Float32: single-precision floating-point number input (–1.0 ≤
x≤ 1.0)
Returns:
- Float32: The arc cosine function value of the input parameter, in radians, is returned.
Throws:
- IllegalArgumentException: When the value of parameter
xis greater than 1.0 or less than –1.0, this exception is thrown.
Example:
import std.math.acos
main() {
let n: Float32 = 1.0
let acos = acos(n)
println(acos)
}
Running result:
0.000000
func acos(Float64)
public func acos(x: Float64): Float64
Description: Obtains the arc cosine function value of a double-precision floating-point number through calculation.
Parameters:
- x: Float64: double-precision floating-point number input (–1.0 ≤
x≤ 1.0)
Returns:
- Float64: The arc cosine function value of the input parameter, in radians, is returned.
Throws:
- IllegalArgumentException: When the value of parameter
xis greater than 1.0 or less than –1.0, this exception is thrown.
Example:
import std.math.acos
main() {
let n: Float64 = 1.0
let acos = acos(n)
println(acos)
}
Running result:
0.000000
func acosh(Float16)
public func acosh(x: Float16): Float16
Description: Obtains the inverse hyperbolic cosine function value of a half-precision floating-point number through calculation.
Parameters:
- x: Float16: half-precision floating-point number input
Returns:
- Float16: The inverse hyperbolic cosine function value of the input parameter is returned. (
x≥ 1.0)
Throws:
- IllegalArgumentException: When the value of parameter
xis less than 1.0, this exception is thrown.
Example:
import std.math.acosh
main() {
let n: Float16 = 1.0
let acosh = acosh(n)
println(acosh)
}
Running result:
0.000000
func acosh(Float32)
public func acosh(x: Float32): Float32
Description: Obtains the inverse hyperbolic cosine function value of a single-precision floating-point number through calculation.
Parameters:
- x: Float32: single-precision floating-point number input; (
x≥ 1.0)
Returns:
- Float32: The inverse hyperbolic cosine function value of the input parameter is returned.
Throws:
- IllegalArgumentException: When the value of parameter
xis less than 1.0, this exception is thrown.
Example:
import std.math.acosh
main() {
let n: Float32 = 1.0
let acosh = acosh(n)
println(acosh)
}
Running result:
0.000000
func acosh(Float64)
public func acosh(x: Float64): Float64
Description: Obtains the inverse hyperbolic cosine function value of a double-precision floating-point number through calculation.
Parameters:
- x: Float64: double-precision floating-point number input (
x≥ 1.0)
Returns:
- Float64: The inverse hyperbolic cosine function value of the input parameter is returned.
Throws:
- IllegalArgumentException: When the value of parameter
xis less than 1.0, this exception is thrown.
Example:
import std.math.acosh
main() {
let n: Float64 = 1.0
let acosh = acosh(n)
println(acosh)
}
Running result:
0.000000
func asin(Float16)
public func asin(x: Float16): Float16
Description: Obtains the arc sine function value of a half-precision floating-point number through calculation.
Parameters:
- x: Float16: half-precision floating-point number input (–1.0 ≤
x≤ 1.0)
Returns:
- Float16: The arc sine function value of the input parameter, in radians, is returned.
Throws:
- IllegalArgumentException: When the value of parameter
xis greater than 1.0 or less than –1.0, this exception is thrown.
Example:
import std.math.asin
main() {
let n: Float16 = 0.0
let asin = asin(n)
println(asin)
}
Running result:
0.000000
func asin(Float32)
public func asin(x: Float32): Float32
Description: Obtains the arc sine function value of a single-precision floating-point number through calculation.
Parameters:
- x: Float32: single-precision floating-point number input (–1.0 ≤
x≤ 1.0)
Returns:
- Float32: The arc sine function value of the input parameter, in radians, is returned.
Throws:
- IllegalArgumentException: When the value of parameter
xis greater than 1.0 or less than –1.0, this exception is thrown.
Example:
import std.math.asin
main() {
let n: Float32 = 0.0
let asin = asin(n)
println(asin)
}
Running result:
0.000000
func asin(Float64)
public func asin(x: Float64): Float64
Description: Obtains the arc sine function value of a double-precision floating-point number through calculation.
Parameters:
- x: Float64: double-precision floating-point number input (–1.0 ≤
x≤ 1.0)
Returns:
- Float64: The arc sine function value of the input parameter, in radians, is returned.
Throws:
- IllegalArgumentException: When the value of parameter
xis greater than 1.0 or less than –1.0, this exception is thrown.
Example:
import std.math.asin
main() {
let n: Float64 = 0.0
let asin = asin(n)
println(asin)
}
Running result:
0.000000
func asinh(Float16)
public func asinh(x: Float16): Float16
Description: Obtains the inverse hyperbolic sine function value of a half-precision floating-point number through calculation.
Parameters:
- x: Float16: half-precision floating-point number input
Returns:
- Float16: The inverse hyperbolic sine function value of the input parameter is returned.
Example:
import std.math.asinh
main() {
let n: Float16 = 0.0
let asinh = asinh(n)
println(asinh)
}
Running result:
0.000000
func asinh(Float32)
public func asinh(x: Float32): Float32
Description: Obtains the inverse hyperbolic sine function value of a single-precision floating-point number through calculation.
Parameters:
- x: Float32: single-precision floating-point number input
Returns:
- Float32: The inverse hyperbolic sine function value of the input parameter is returned.
Example:
import std.math.asinh
main() {
let n: Float32 = 0.0
let asinh = asinh(n)
println(asinh)
}
Running result:
0.000000
func asinh(Float64)
public func asinh(x: Float64): Float64
Description: Obtains the inverse hyperbolic sine function value of a double-precision floating-point number through calculation.
Parameters:
- x: Float64: double-precision floating-point number input
Returns:
- Float64: The inverse hyperbolic sine function value of the input parameter is returned.
Example:
import std.math.asinh
main() {
let n: Float64 = 0.0
let asinh = asinh(n)
println(asinh)
}
Running result:
0.000000
func atan(Float16)
public func atan(x: Float16): Float16
Description: Obtains the arc tangent function value of a half-precision floating-point number through calculation.
Parameters:
- x: Float16: half-precision floating-point number input
Returns:
- Float16: The arc tangent function value of the input parameter, in radians, is returned.
Example:
import std.math.atan
main() {
let n: Float16 = 0.0
let atan = atan(n)
println(atan)
}
Running result:
0.000000
func atan(Float32)
public func atan(x: Float32): Float32
Description: Obtains the arc tangent function value of a single-precision floating-point number through calculation.
Parameters:
- x: Float32: single-precision floating-point number input
Returns:
- Float32: The arc tangent function value of the input parameter, in radians, is returned.
Example:
import std.math.atan
main() {
let n: Float32 = 0.0
let atan = atan(n)
println(atan)
}
Running result:
0.000000
func atan(Float64)
public func atan(x: Float64): Float64
Description: Obtains the arc tangent function value of a double-precision floating-point number through calculation.
Parameters:
- x: Float64: double-precision floating-point number input
Returns:
- Float64: The arc tangent function value of the input parameter, in radians, is returned.
Example:
import std.math.atan
main() {
let n: Float64 = 0.0
let atan = atan(n)
println(atan)
}
Running result:
0.000000
func atanh(Float16)
public func atanh(x: Float16): Float16
Description: Obtains the inverse hyperbolic tangent function value of a half-precision floating-point number through calculation.
Parameters:
- x: Float16: half-precision floating-point number input (–1.0 < <idp:inline displayname="code" id="office_0fcbbb77-0be7-41d0-8fee-614748367052" tempcmdid="office_0fcbbb77-0be7-41d0-8fee-614748367052">x</idp:inline> < 1.0)
Returns:
- Float16: The inverse hyperbolic tangent function value of the input parameter is returned.
Throws:
- IllegalArgumentException: When the value of parameter
xis greater than or equal to 1.0 or is less than or equal to –1.0, this exception is thrown.
Example:
import std.math.atanh
main() {
let n: Float16 = 0.0
let atanh = atanh(n)
println(atanh)
}
Running result:
0.000000
func atanh(Float32)
public func atanh(x: Float32): Float32
Description: Obtains the inverse hyperbolic tangent function value of a single-precision floating-point number through calculation.
Parameters:
- x: Float32: single-precision floating-point number input (–1.0 <
x< 1.0)
Returns:
- Float32: The inverse hyperbolic tangent function value of the input parameter is returned.
Throws:
- IllegalArgumentException: When the value of parameter
xis greater than or equal to 1.0 or is less than or equal to –1.0, this exception is thrown.
Example:
import std.math.atanh
main() {
let n: Float32 = 0.0
let atanh = atanh(n)
println(atanh)
}
Running result:
0.000000
func atanh(Float64)
public func atanh(x: Float64): Float64
Description: Obtains the inverse hyperbolic tangent function value of a double-precision floating-point number through calculation.
Parameters:
- x: Float64: double-precision floating-point number input (–1.0 <
x< 1.0)
Returns:
- Float64: The inverse hyperbolic tangent function value of the input parameter is returned.
Throws:
- IllegalArgumentException: When the value of parameter
xis greater than or equal to 1.0 or is less than or equal to –1.0, this exception is thrown.
Example:
import std.math.atanh
main() {
let n: Float64 = 0.0
let atanh = atanh(n)
println(atanh)
}
Running result:
0.000000
func cbrt(Float16)
public func cbrt(x: Float16): Float16
Description: Obtains the cube root of a half-precision floating-point number.
Parameters:
- x: Float16: half-precision floating-point number input
Returns:
- Float16: The cube root of the input parameter is returned.
Example:
import std.math.cbrt
main() {
let n: Float16 = -1000.0
let cbrt = cbrt(n)
println(cbrt)
}
Running result:
-10.000000
func cbrt(Float32)
public func cbrt(x: Float32): Float32
Description: Obtains the cube root of a single-precision floating-point number.
Parameters:
- x: Float32: single-precision floating-point number input
Returns:
- Float32: The cube root of the input parameter is returned.
Example:
import std.math.cbrt
main() {
let n: Float32 = -1000.0
let cbrt = cbrt(n)
println(cbrt)
}
Running result:
-10.000000
func cbrt(Float64)
public func cbrt(x: Float64): Float64
Description: Obtains the cube root of a double-precision floating-point number.
Parameters:
- x: Float64: double-precision floating-point number input
Returns:
- Float64: The cube root of the input parameter is returned.
Example:
import std.math.cbrt
main() {
let n: Float64 = -1000.0
let cbrt = cbrt(n)
println(cbrt)
}
Running result:
-10.000000
func ceil(Float16)
public func ceil(x: Float16): Float16
Description: Obtains the rounded-up value of a half-precision floating-point number.
Parameters:
- x: Float16: half-precision floating-point number input
Returns:
- Float16: The rounded-up value of the input parameter is returned.
Example:
import std.math.ceil
main() {
let n: Float16 = 0.7
let ceil = ceil(n)
println(ceil)
}
Running result:
1.000000
func ceil(Float32)
public func ceil(x: Float32): Float32
Description: Obtains the rounded-up value of a single-precision floating-point number.
Parameters:
- x: Float32: single-precision floating-point number input
Returns:
- Float32: The rounded-up value of the input parameter is returned.
Example:
import std.math.ceil
main() {
let n: Float32 = 0.7
let ceil = ceil(n)
println(ceil)
}
Running result:
1.000000
func ceil(Float64)
public func ceil(x: Float64): Float64
Description: Obtains the rounded-up value of a double-precision floating-point number.
Parameters:
- x: Float64: double-precision floating-point number input
Returns:
- Float64: The rounded-up value of the input parameter is returned.
Example:
import std.math.ceil
main() {
let n: Float64 = 0.7
let ceil = ceil(n)
println(ceil)
}
Running result:
1.000000
func checkedAbs(Int16)
public func checkedAbs(x: Int16): Option<Int16>
Description: Obtains the absolute value of a 16-bit signed integer. If the input parameter is the minimum value of the 16-bit signed integer, the function returns None. Otherwise, the function returns Some(abs(x)).
Parameters:
- x: Int16: 16-bit signed integer input
Returns:
Example:
import std.math.checkedAbs
main() {
let n: Int16 = -23
let checkedAbs = checkedAbs(n)
println(checkedAbs)
}
Running result:
Some(23)
func checkedAbs(Int32)
public func checkedAbs(x: Int32): Option<Int32>
Description: Obtains the absolute value of a 32-bit signed integer. If the input parameter is the minimum value of the 32-bit signed integer, the function returns None. Otherwise, the function returns Some(abs(x)).
Parameters:
- x: Int32: 32-bit signed integer input
Returns:
Example:
import std.math.checkedAbs
main() {
let n: Int32 = -23
let checkedAbs = checkedAbs(n)
println(checkedAbs)
}
Running result:
Some(23)
func checkedAbs(Int64)
public func checkedAbs(x: Int64): Option<Int64>
Description: Obtains the absolute value of a 64-bit signed integer. If the input parameter is the minimum value of the 64-bit signed integer, the function returns None. Otherwise, the function returns Some(abs(x)).
Parameters:
- x: Int64: 64-bit signed integer input
Returns:
Example:
import std.math.checkedAbs
main() {
let n: Int64 = -23
let checkedAbs = checkedAbs(n)
println(checkedAbs)
}
Running result:
Some(23)
func checkedAbs(Int8)
public func checkedAbs(x: Int8): Option<Int8>
Description: Obtains the absolute value of an 8-bit signed integer. If the input parameter is the minimum value of the 8-bit signed integer, the function returns None. Otherwise, the function returns Some(abs(x)).
Parameters:
- x: Int8: 8-bit signed integer input
Returns:
Example:
import std.math.checkedAbs
main() {
let n: Int8 = -23
let checkedAbs = checkedAbs(n)
println(checkedAbs)
}
Running result:
Some(23)
func clamp(Float16, Float16, Float16)
public func clamp(v: Float16, min: Float16, max: Float16): Float16
Description: Obtains the value of a floating-point number to which the clamp function with a given range is applied. If the floating-point number is within the range, the floating-point number is returned. If the floating-point number is less than the minimum value in the range, the minimum value is returned. If the floating-point number is greater than the maximum value in the range, the maximum value is returned. If the floating-point number is NaN, NaN is returned.
Parameters:
- v: Float16: floating-point number input
- min: Float16: specified minimum value
- max: Float16: specified maximum value
Returns:
- Float16: If
vis betweenminandmax,vis returned. Ifvis less than or equal tomin,minis returned. Ifvis greater than or equal tomax,maxis returned. IfvisNaN,NaNis returned.
Example:
import std.math.clamp
main() {
let n: Float16 = -23.0
let clamp = clamp(n, -100.0, 100.0)
println(clamp)
}
Running result:
-23.000000
func clamp(Float32, Float32, Float32)
public func clamp(v: Float32, min: Float32, max: Float32): Float32
Description: Obtains the value of a floating-point number to which the clamp function with a given range is applied. If the floating-point number is within the range, the floating-point number is returned. If the floating-point number is less than the minimum value in the range, the minimum value is returned. If the floating-point number is greater than the maximum value in the range, the maximum value is returned. If the floating-point number is NaN, NaN is returned.
Parameters:
- v: Float32: floating-point number input
- min: Float32: specified minimum value
- max: Float32: specified maximum value
Returns:
- Float32: If
vis betweenminandmax,vis returned. Ifvis less than or equal tomin,minis returned. Ifvis greater than or equal tomax,maxis returned. IfvisNaN,NaNis returned.
Example:
import std.math.clamp
main() {
let n: Float32 = -23.0
let clamp = clamp(n, -100.0, 100.0)
println(clamp)
}
Running result:
-23.000000
func clamp(Float64, Float64, Float64)
public func clamp(v: Float64, min: Float64, max: Float64): Float64
Description: Obtains the value of a floating-point number to which the clamp function with a given range is applied. If the floating-point number is within the range, the floating-point number is returned. If the floating-point number is less than the minimum value in the range, the minimum value is returned. If the floating-point number is greater than the maximum value in the range, the maximum value is returned. If the floating-point number is NaN, NaN is returned.
Parameters:
- v: Float64: floating-point number input
- min: Float64: specified minimum value
- max: Float64: specified maximum value
Returns:
- Float64: If
vis betweenminandmax,vis returned. Ifvis less than or equal tomin,minis returned. Ifvis greater than or equal tomax,maxis returned. IfvisNaN,NaNis returned.
Example:
import std.math.clamp
main() {
let n: Float64 = -23.0
let clamp = clamp(n, -100.0, 100.0)
println(clamp)
}
Running result:
-23.000000
func cos(Float16)
public func cos(x: Float16): Float16
Description: Obtains the cosine function value of a half-precision floating-point number through calculation.
Parameters:
- x: Float16: half-precision floating-point number input, in radians
Returns:
- Float16: The cosine function value of the input parameter is returned.
Example:
import std.math.cos
main() {
let n: Float16 = 3.14159265
let cos = cos(n)
println(cos)
}
Running result:
-1.000000
func cos(Float32)
public func cos(x: Float32): Float32
Description: Obtains the cosine function value of a single-precision floating-point number through calculation.
Parameters:
- x: Float32: single-precision floating-point number input, in radians
Returns:
- Float32: The cosine function value of the input parameter is returned.
Example:
import std.math.cos
main() {
let n: Float32 = 3.14159265
let cos = cos(n)
println(cos)
}
Running result:
-1.000000
func cos(Float64)
public func cos(x: Float64): Float64
Description: Obtains the cosine function value of a double-precision floating-point number through calculation.
Parameters:
- x: Float64: double-precision floating-point number input, in radians
Returns:
- Float64: The cosine function value of the input parameter is returned.
Example:
import std.math.cos
main() {
let n: Float64 = 3.14159265
let cos = cos(n)
println(cos)
}
Running result:
-1.000000
func cosh(Float16)
public func cosh(x: Float16): Float16
Description: Obtains the hyperbolic cosine function value of a half-precision floating-point number through calculation.
Parameters:
- x: Float16: half-precision floating-point number input
Returns:
- Float16: The hyperbolic cosine function value of the input parameter is returned.
Example:
import std.math.cosh
main() {
let n: Float16 = 0.0
let cosh = cosh(n)
println(cosh)
}
Running result:
1.000000
func cosh(Float32)
public func cosh(x: Float32): Float32
Description: Obtains the hyperbolic cosine function value of a single-precision floating-point number through calculation.
Parameters:
- x: Float32: single-precision floating-point number input
Returns:
- Float32: The hyperbolic cosine function value of the input parameter is returned.
Example:
import std.math.cosh
main() {
let n: Float32 = 0.0
let cosh = cosh(n)
println(cosh)
}
Running result:
1.000000
func cosh(Float64)
public func cosh(x: Float64): Float64
Description: Obtains the hyperbolic cosine function value of a double-precision floating-point number through calculation.
Parameters:
- x: Float64: double-precision floating-point number input
Returns:
- Float64: The hyperbolic cosine function value of the input parameter is returned.
Example:
import std.math.cosh
main() {
let n: Float64 = 0.0
let cosh = cosh(n)
println(cosh)
}
Running result:
1.000000
func countOne(Int16)
public func countOne(x: Int16): Int8
Description: Obtains the number of 1s in the binary expression of a 16-bit integer.
Parameters:
- x: Int16: 16-bit signed integer input
Returns:
- Int8: The number of bits of 1s in the binary representation of the input parameter is returned.
Example:
import std.math.countOne
main() {
let n: Int16 = 15
let countOne = countOne(n)
println(countOne)
}
Running result:
4
func countOne(Int32)
public func countOne(x: Int32): Int8
Description: Obtains the number of 1s in the binary expression of a 32-bit integer.
Parameters:
- x: Int32: 32-bit signed integer input
Returns:
- Int8: The number of bits of 1s in the binary representation of the input parameter is returned.
Example:
import std.math.countOne
main() {
let n: Int32 = 15
let countOne = countOne(n)
println(countOne)
}
Running result:
4
func countOne(Int64)
public func countOne(x: Int64): Int8
Description: Obtains the number of 1s in the binary expression of a 64-bit integer.
Parameters:
- x: Int64: 64-bit signed integer input
Returns:
- Int8: The number of bits of 1s in the binary representation of the input parameter is returned.
Example:
import std.math.countOne
main() {
let n: Int64 = 15
let countOne = countOne(n)
println(countOne)
}
Running result:
4
func countOne(Int8)
public func countOne(x: Int8): Int8
Description: Obtains the number of 1s in the binary expression of an 8-bit integer.
Parameters:
- x: Int8: 8-bit signed integer input
Returns:
- Int8: The number of bits of 1s in the binary representation of the input parameter is returned.
Example:
import std.math.countOne
main() {
let n: Int8 = 15
let countOne = countOne(n)
println(countOne)
}
Running result:
4
func countOne(UInt16)
public func countOne(x: UInt16): Int8
Description: Obtains the number of bits of 1s in the binary expression of a 16-bit unsigned integer.
Parameters:
- x: UInt16: 16-bit unsigned integer input
Returns:
- Int8: The number of bits of 1s in the binary representation of the input parameter is returned.
Example:
import std.math.countOne
main() {
let n: UInt16 = 15
let countOne = countOne(n)
println(countOne)
}
Running result:
4
func countOne(UInt32)
public func countOne(x: UInt32): Int8
Description: Obtains the number of bits of 1s in the binary expression of a 32-bit unsigned integer.
Parameters:
- x: UInt32: 32-bit unsigned integer input
Returns:
- Int8: The number of bits of 1s in the binary representation of the input parameter is returned.
Example:
import std.math.countOne
main() {
let n: UInt32 = 15
let countOne = countOne(n)
println(countOne)
}
Running result:
4
func countOne(UInt64)
public func countOne(x: UInt64): Int8
Description: Obtains the number of bits of 1s in the binary expression of a 64-bit unsigned integer.
Parameters:
- x: UInt64: 64-bit unsigned integer input
Returns:
- Int8: The number of bits of 1s in the binary representation of the input parameter is returned.
Example:
import std.math.countOne
main() {
let n: UInt64 = 15
let countOne = countOne(n)
println(countOne)
}
Running result:
4
func countOne(UInt8)
public func countOne(x: UInt8): Int8
Description: Obtains the number of bits of 1s in the binary expression of an 8-bit unsigned integer.
Parameters:
- x: UInt8: 8-bit unsigned integer input
Returns:
- Int8: The number of bits of 1s in the binary representation of the input parameter is returned.
Example:
import std.math.countOne
main() {
let n: UInt8 = 15
let countOne = countOne(n)
println(countOne)
}
Running result:
4
func erf(Float16)
public func erf(x: Float16): Float16
Description: Obtains the error value of a half-precision floating-point number. Related definition: $$erf(x) = \frac{2}{\sqrt{\pi}}\int_0^xe^{-t^2}dt$$
Parameters:
- x: Float16: half-precision floating-point number input
Returns:
- Float16: The error value of the half-precision floating-point number of the input parameter is returned.
Example:
import std.math.erf
main() {
let n: Float16 = 5.0
let erf = erf(n)
println(erf)
}
Running result:
1.000000
func erf(Float32)
public func erf(x: Float32): Float32
Description: Obtains the error value of a single-precision floating-point number. Related definition: $$erf(x) = \frac{2}{\sqrt{\pi}}\int_0^xe^{-t^2}dt$$
Parameters:
- x: Float32: single-precision floating-point number input
Returns:
- Float32: The error value of the single-precision floating-point number of the input parameter is returned.
Example:
import std.math.erf
main() {
let n: Float32 = 5.0
let erf = erf(n)
println(erf)
}
Running result:
1.000000
func erf(Float64)
public func erf(x: Float64): Float64
Description: Obtains the error value of a double-precision floating-point number. Related definition: $$erf(x) = \frac{2}{\sqrt{\pi}}\int_0^xe^{-t^2}dt$$
Parameters:
- x: Float64: double-precision floating-point number input
Returns:
- Float64: The error value of the double-precision floating-point number of the input parameter is returned.
Example:
import std.math.erf
main() {
let n: Float64 = 5.0
let erf = erf(n)
println(erf)
}
Running result:
1.000000
func exp(Float16)
public func exp(x: Float16): Float16
Description: Obtains the natural constant e raised to the power of x.
Parameters:
- x: Float16: half-precision floating-point number exponent input
Returns:
- Float16: The natural constant e raised to the power of
xis returned.
Example:
import std.math.exp
main() {
let n: Float16 = 1.0
let exp = exp(n)
println(exp)
}
Running result:
2.718750
func exp(Float32)
public func exp(x: Float32): Float32
Description: Obtains the natural constant e raised to the power of x.
Parameters:
- x: Float32: single-precision floating-point number exponent input
Returns:
- Float32: The natural constant e raised to the power of
xis returned.
Example:
import std.math.exp
main() {
let n: Float32 = 1.0
let exp = exp(n)
println(exp)
}
Running result:
2.718282
func exp(Float64)
public func exp(x: Float64): Float64
Description: Obtains the natural constant e raised to the power of x.
Parameters:
- x: Float64: double-precision floating-point number exponent input
Returns:
- Float64: The natural constant e raised to the power of
xis returned.
Example:
import std.math.exp
main() {
let n: Float64 = 1.0
let exp = exp(n)
println(exp)
}
Running result:
2.718282
func exp2(Float16)
public func exp2(x: Float16): Float16
Description: Obtains 2 raised to the power of x.
Parameters:
- x: Float16: half-precision floating-point number exponent input
Returns:
- Float16: 2 raised to the power of
xis returned.
Example:
import std.math.exp2
main() {
let n: Float16 = 10.0
let exp2 = exp2(n)
println(exp2)
}
Running result:
1024.000000
func exp2(Float32)
public func exp2(x: Float32): Float32
Description: Obtains 2 raised to the power of x.
Parameters:
- x: Float32: single-precision floating-point number exponent input
Returns:
- Float32: 2 raised to the power of
xis returned.
Example:
import std.math.exp2
main() {
let n: Float32 = 10.0
let exp2 = exp2(n)
println(exp2)
}
Running result:
1024.000000
func exp2(Float64)
public func exp2(x: Float64): Float64
Description: Obtains 2 raised to the power of x.
Parameters:
- x: Float64: double-precision floating-point number exponent input
Returns:
- Float64: 2 raised to the power of
xis returned.
Example:
import std.math.exp2
main() {
let n: Float64 = 10.0
let exp = exp2(n)
println(exp)
}
Running result:
1024.000000
func floor(Float16)
public func floor(x: Float16): Float16
Description: Obtains the rounded-down value of a floating-point number.
Parameters:
- x: Float16: half-precision floating-point number input to be rounded down
Returns:
- Float16: The rounded-down value of the input floating-point number is returned.
Example:
import std.math.floor
main() {
let n: Float16 = 10.5
let floor = floor(n)
println(floor)
}
Running result:
10.000000
func floor(Float32)
public func floor(x: Float32): Float32
Description: Obtains the rounded-down value of a floating-point number.
Parameters:
- x: Float32: single-precision floating-point number input to be rounded down
Returns:
- Float32: The rounded-down value of the input floating-point number is returned.
Example:
import std.math.floor
main() {
let n: Float32 = 10.5
let floor = floor(n)
println(floor)
}
Running result:
10.000000
func floor(Float64)
public func floor(x: Float64): Float64
Description: Obtains the rounded-down value of a floating-point number.
Parameters:
- x: Float64: double-precision floating-point number input to be rounded down
Returns:
- Float64: The rounded-down value of the input floating-point number is returned.
Example:
import std.math.floor
main() {
let n: Float64 = 10.5
let floor = floor(n)
println(floor)
}
Running result:
10.000000
func gamma(Float16)
public func gamma(x: Float16): Float16
Description: Obtains the gamma function value of a floating-point number. This function is a generalization of the factorial concept on real numbers.
Parameters:
- x: Float16: half-precision floating-point number input whose gamma function value is to be obtained
Returns:
- Float16: The gamma function value of the input floating-point number is returned.
Example:
import std.math.gamma
main() {
let n: Float16 = -1.1
let gamma = gamma(n)
println(gamma)
}
Running result:
9.750000
func gamma(Float32)
public func gamma(x: Float32): Float32
Description: Obtains the gamma function value of a floating-point number. This function is a generalization of the factorial concept on real numbers.
Parameters:
- x: Float32: single-precision floating-point number input whose gamma function value is to be obtained
Returns:
- Float32: The gamma function value of the input floating-point number is returned.
Example:
import std.math.gamma
main() {
let n: Float32 = -1.1
let gamma = gamma(n)
println(gamma)
}
Running result:
9.714804
func gamma(Float64)
public func gamma(x: Float64): Float64
Description: Obtains the gamma function value of a floating-point number. This function is a generalization of the factorial concept on real numbers.
Parameters:
- x: Float64: double-precision floating-point number input whose gamma function value is to be obtained
Returns:
- Float64: The gamma function value of the input floating-point number is returned.
Example:
import std.math.gamma
main() {
let n: Float64 = -1.1
let gamma = gamma(n)
println(gamma)
}
Running result:
9.714806
func gcd(Int16, Int16)
public func gcd(x: Int16, y: Int16): Int16
Description: Obtains the greatest common divisor of two 16-bit signed integers.
Parameters:
- x: Int16: one input integer for the greatest common divisor calculation
- y: Int16: the other input integer for the greatest common divisor calculation
Returns:
- Int16: The greatest common divisor of the two integers is returned.
Throws:
- IllegalArgumentException: When both parameters are the minimum value of a signed integer, or when one parameter is the minimum value of a signed integer and the other parameter is 0, this exception is thrown.
Example:
import std.math.gcd
main() {
let x: Int16 = 15
let y: Int16 = 9
let gcd = gcd(x, y)
println(gcd)
}
Running result:
3
func gcd(Int32, Int32)
public func gcd(x: Int32, y: Int32): Int32
Description: Obtains the greatest common divisor of two 32-bit signed integers.
Parameters:
- x: Int32: one input integer for the greatest common divisor calculation
- y: Int32: the other input integer for the greatest common divisor calculation
Returns:
- Int32: The greatest common divisor of the two integers is returned.
Throws:
- IllegalArgumentException: When both parameters are the minimum value of a signed integer, or when one parameter is the minimum value of a signed integer and the other parameter is 0, this exception is thrown.
Example:
import std.math.gcd
main() {
let x: Int32 = 15
let y: Int32 = 9
let gcd = gcd(x, y)
println(gcd)
}
Running result:
3
func gcd(Int64, Int64)
public func gcd(x: Int64, y: Int64): Int64
Description: Obtains the greatest common divisor of two 64-bit signed integers.
Parameters:
- x: Int64: one input integer for the greatest common divisor calculation
- y: Int64: the other input integer for the greatest common divisor calculation
Returns:
- Int64: The greatest common divisor of the two integers is returned.
Throws:
- IllegalArgumentException: When both parameters are the minimum value of a signed integer, or when one parameter is the minimum value of a signed integer and the other parameter is 0, this exception is thrown.
Example:
import std.math.gcd
main() {
let x: Int64 = 15
let y: Int64 = 9
let gcd = gcd(x, y)
println(gcd)
}
Running result:
3
func gcd(Int8, Int8)
public func gcd(x: Int8, y: Int8): Int8
Description: Obtains the greatest common divisor of two 8-bit signed integers.
Parameters:
- x: Int8: one input integer for the greatest common divisor calculation
- y: Int8: the other input integer for the greatest common divisor calculation
Returns:
- Int8: The greatest common divisor of the two integers is returned.
Throws:
- IllegalArgumentException: When both parameters are the minimum value of a signed integer, or when one parameter is the minimum value of a signed integer and the other parameter is 0, this exception is thrown.
Example:
import std.math.gcd
main() {
let x: Int8 = 15
let y: Int8= 9
let gcd = gcd(x, y)
println(gcd)
}
Running result:
3
func gcd(UInt16, UInt16)
public func gcd(x: UInt16, y: UInt16): UInt16
Description: Obtains the greatest common divisor of two 16-bit unsigned integers.
Parameters:
- x: UInt16: one input integer for the greatest common divisor calculation
- y: UInt16: the other input integer for the greatest common divisor calculation
Returns:
- UInt16: The greatest common divisor of the two integers is returned.
Example:
import std.math.gcd
main() {
let x: UInt16 = 15
let y: UInt16 = 9
let gcd = gcd(x, y)
println(gcd)
}
Running result:
3
func gcd(UInt32, UInt32)
public func gcd(x: UInt32, y: UInt32): UInt32
Description: Obtains the greatest common divisor of two 32-bit unsigned integers.
Parameters:
- x: UInt32: one input integer for the greatest common divisor calculation
- y: UInt32: the other input integer for the greatest common divisor calculation
Returns:
- UInt32: The greatest common divisor of the two integers is returned.
Example:
import std.math.gcd
main() {
let x: UInt32 = 15
let y: UInt32 = 9
let gcd = gcd(x, y)
println(gcd)
}
Running result:
3
func gcd(UInt64, UInt64)
public func gcd(x: UInt64, y: UInt64): UInt64
Description: Obtains the greatest common divisor of two 64-bit unsigned integers.
Parameters:
- x: UInt64: one input integer for the greatest common divisor calculation
- y: UInt64: the other input integer for the greatest common divisor calculation
Returns:
- UInt64: The greatest common divisor of the two integers is returned.
Example:
import std.math.gcd
main() {
let x: UInt64 = 15
let y: UInt64 = 9
let gcd = gcd(x, y)
println(gcd)
}
Running result:
3
func gcd(UInt8, UInt8)
public func gcd(x: UInt8, y: UInt8): UInt8
Description: Obtains the greatest common divisor of two 8-bit unsigned integers.
Parameters:
- x: UInt8: one input integer for the greatest common divisor calculation
- y: UInt8: the other input integer for the greatest common divisor calculation
Returns:
- UInt8: The greatest common divisor of the two integers is returned.
Example:
import std.math.gcd
main() {
let x: UInt8 = 15
let y: UInt8= 9
let gcd = gcd(x, y)
println(gcd)
}
Running result:
3
func lcm(Int16, Int16)
public func lcm(x: Int16, y: Int16): Int16
Description: Obtains the non-negative least common multiple of two 16-bit signed integers. The value 0 is returned only when any input parameter is 0.
Parameters:
- x: Int16: one input integer for the least common multiple calculation
- y: Int16: the other input integer for the least common multiple calculation
Returns:
- Int16: The non-negative least common multiple of the two integers is returned. The value 0 is returned only when any input parameter is 0.
Throws:
- IllegalArgumentException: When the return value exceeds the maximum value of a 16-bit signed integer, this exception is thrown.
Example:
import std.math.lcm
main() {
let x: Int16 = -15
let y: Int16 = 9
let lcm = lcm(x, y)
println(lcm)
}
Running result:
45
func lcm(Int32, Int32)
public func lcm(x: Int32, y: Int32): Int32
Description: Obtains the non-negative least common multiple of two 32-bit signed integers. The value 0 is returned only when any input parameter is 0.
Parameters:
- x: Int32: one input integer for the least common multiple calculation
- y: Int32: the other input integer for the least common multiple calculation
Returns:
- Int32: The non-negative least common multiple of the two integers is returned. The value 0 is returned only when any input parameter is 0.
Throws:
- IllegalArgumentException: When the return value exceeds the maximum value of a 32-bit signed integer, this exception is thrown.
Example:
import std.math.lcm
main() {
let x: Int32 = -15
let y: Int32 = 9
let lcm = lcm(x, y)
println(lcm)
}
Running result:
45
func lcm(Int64, Int64)
public func lcm(x: Int64, y: Int64): Int64
Description: Obtains the non-negative least common multiple of two 64-bit signed integers. The value 0 is returned only when any input parameter is 0.
Parameters:
- x: Int64: one input integer for the least common multiple calculation
- y: Int64: the other input integer for the least common multiple calculation
Returns:
- Int64: The non-negative least common multiple of the two integers is returned. The value 0 is returned only when any input parameter is 0.
Throws:
- IllegalArgumentException: When the return value exceeds the maximum value of a 64-bit signed integer, this exception is thrown.
Example:
import std.math.lcm
main() {
let x: Int64 = 15
let y: Int64 = 9
let lcm = lcm(x, y)
println(lcm)
}
Running result:
45
func lcm(Int8, Int8)
public func lcm(x: Int8, y: Int8): Int8
Description: Obtains the non-negative least common multiple of two 8-bit signed integers. The value 0 is returned only when any input parameter is 0.
Parameters:
- x: Int8: one input integer for the least common multiple calculation
- y: Int8: the other input integer for the least common multiple calculation
Returns:
- Int8: The non-negative least common multiple of the two integers is returned. The value 0 is returned only when any input parameter is 0.
Throws:
- IllegalArgumentException: When the return value exceeds the maximum value of an 8-bit signed integer, this exception is thrown.
Example:
import std.math.lcm
main() {
let x: Int8 = 15
let y: Int8= 9
let lcm = lcm(x, y)
println(lcm)
}
Running result:
45
func lcm(UInt16, UInt16)
public func lcm(x: UInt16, y: UInt16): UInt16
Description: Obtains the non-negative least common multiple of two 16-bit unsigned integers. The value 0 is returned only when any input parameter is 0.
Parameters:
- x: UInt16: one input integer for the least common multiple calculation
- y: UInt16: the other input integer for the least common multiple calculation
Returns:
- UInt16: The non-negative least common multiple of the two integers is returned. The value 0 is returned only when any input parameter is 0.
Throws:
- IllegalArgumentException: When the return value exceeds the maximum value of a 16-bit unsigned integer, this exception is thrown.
Example:
import std.math.lcm
main() {
let x: UInt16 = 15
let y: UInt16 = 9
let lcm = lcm(x, y)
println(lcm)
}
Running result:
45
func lcm(UInt32, UInt32)
public func lcm(x: UInt32, y: UInt32): UInt32
Description: Obtains the non-negative least common multiple of two 32-bit unsigned integers. The value 0 is returned only when any input parameter is 0.
Parameters:
- x: UInt32: one input integer for the least common multiple calculation
- y: UInt32: the other input integer for the least common multiple calculation
Returns:
- UInt32: The non-negative least common multiple of the two integers is returned. The value 0 is returned only when any input parameter is 0.
Throws:
- IllegalArgumentException: When the return value exceeds the maximum value of a 32-bit unsigned integer, this exception is thrown.
Example:
import std.math.lcm
main() {
let x: UInt32 = 15
let y: UInt32 = 9
let lcm = lcm(x, y)
println(lcm)
}
Running result:
45
func lcm(UInt64, UInt64)
public func lcm(x: UInt64, y: UInt64): UInt64
Description: Obtains the non-negative least common multiple of two 64-bit unsigned integers. The value 0 is returned only when any input parameter is 0.
Parameters:
- x: UInt64: one input integer for the least common multiple calculation
- y: UInt64: the other input integer for the least common multiple calculation
Returns:
- UInt64: The non-negative least common multiple of the two integers is returned. The value 0 is returned only when any input parameter is 0.
Throws:
- IllegalArgumentException: When the return value exceeds the maximum value of a 64-bit unsigned integer, this exception is thrown.
Example:
import std.math.lcm
main() {
let x: UInt64 = 15
let y: UInt64 = 9
let lcm = lcm(x, y)
println(lcm)
}
Running result:
45
func lcm(UInt8, UInt8)
public func lcm(x: UInt8, y: UInt8): UInt8
Description: Obtains the non-negative least common multiple of two 8-bit unsigned integers. The value 0 is returned only when any input parameter is 0.
Parameters:
- x: UInt8: one input integer for the least common multiple calculation
- y: UInt8: the other input integer for the least common multiple calculation
Returns:
- UInt8: The non-negative least common multiple of the two integers is returned. The value 0 is returned only when any input parameter is 0.
Throws:
- IllegalArgumentException: When the return value exceeds the maximum value of an 8-bit unsigned integer, this exception is thrown.
Example:
import std.math.lcm
main() {
let x: UInt8 = 15
let y: UInt8= 9
let lcm = lcm(x, y)
println(lcm)
}
Running result:
45
func leadingZeros(Int16)
public func leadingZeros(x: Int16): Int8
Description: Obtains the number of consecutive 0s starting from the most significant bit in the binary expression of a 16-bit signed integer. If the most significant bit is not 0, the value 0 is returned.
Parameters:
- x: Int16: integer of which the number of leading zeros is to be obtained
Returns:
- Int8: The number of leading zeros is returned.
Example:
import std.math.leadingZeros
main() {
let x: Int16 = 512
let leadingZeros = leadingZeros(x)
println(leadingZeros)
}
Running result:
6
func leadingZeros(Int32)
public func leadingZeros(x: Int32): Int8
Description: Obtains the number of consecutive 0s starting from the most significant bit in the binary expression of a 32-bit signed integer. If the most significant bit is not 0, the value 0 is returned.
Parameters:
- x: Int32: integer of which the number of leading zeros is to be obtained
Returns:
- Int8: The number of leading zeros is returned.
Example:
import std.math.leadingZeros
main() {
let x: Int32 = 512
let leadingZeros = leadingZeros(x)
println(leadingZeros)
}
Running result:
22
func leadingZeros(Int64)
public func leadingZeros(x: Int64): Int8
Description: Obtains the number of consecutive 0s starting from the most significant bit in the binary expression of a 64-bit signed integer. If the most significant bit is not 0, the value 0 is returned.
Parameters:
- x: Int64: integer of which the number of leading zeros is to be obtained
Returns:
- Int8: The number of leading zeros is returned.
Example:
import std.math.leadingZeros
main() {
let x: Int64 = 512
let leadingZeros = leadingZeros(x)
println(leadingZeros)
}
Running result:
54
func leadingZeros(Int8)
public func leadingZeros(x: Int8): Int8
Description: Obtains the number of consecutive 0s starting from the most significant bit in the binary expression of an 8-bit signed integer. If the most significant bit is not 0, the value 0 is returned.
Parameters:
- x: Int8: integer of which the number of leading zeros is to be obtained
Returns:
- Int8: The number of leading zeros is returned.
Example:
import std.math.leadingZeros
main() {
let x: Int8 = 4
let leadingZeros = leadingZeros(x)
println(leadingZeros)
}
Running result:
5
func leadingZeros(UInt16)
public func leadingZeros(x: UInt16): Int8
Description: Obtains the number of consecutive 0s starting from the most significant bit in the binary expression of a 16-bit unsigned integer. If the most significant bit is not 0, the value 0 is returned.
Parameters:
- x: UInt16: integer of which the number of leading zeros is to be obtained
Returns:
- Int8: The number of leading zeros is returned.
Example:
import std.math.leadingZeros
main() {
let x: UInt16 = 512
let leadingZeros = leadingZeros(x)
println(leadingZeros)
}
Running result:
6
func leadingZeros(UInt32)
public func leadingZeros(x: UInt32): Int8
Description: Obtains the number of consecutive 0s starting from the most significant bit in the binary expression of a 32-bit unsigned integer. If the most significant bit is not 0, the value 0 is returned.
Parameters:
- x: UInt32: integer of which the number of leading zeros is to be obtained
Returns:
- Int8: The number of leading zeros is returned.
Example:
import std.math.leadingZeros
main() {
let x: UInt32 = 512
let leadingZeros = leadingZeros(x)
println(leadingZeros)
}
Running result:
22
func leadingZeros(UInt64)
public func leadingZeros(x: UInt64): Int8
Description: Obtains the number of consecutive 0s starting from the most significant bit in the binary expression of a 64-bit unsigned integer. If the most significant bit is not 0, the value 0 is returned.
Parameters:
- x: UInt64: integer of which the number of leading zeros is to be obtained
Returns:
- Int8: The number of leading zeros is returned.
Example:
import std.math.leadingZeros
main() {
let x: UInt64 = 512
let leadingZeros = leadingZeros(x)
println(leadingZeros)
}
Running result:
54
func leadingZeros(UInt8)
public func leadingZeros(x: UInt8): Int8
Description: Obtains the number of consecutive 0s starting from the most significant bit in the binary expression of an 8-bit unsigned integer. If the most significant bit is not 0, the value 0 is returned.
Parameters:
- x: UInt8: integer of which the number of leading zeros is to be obtained
Returns:
- Int8: The number of leading zeros is returned.
Example:
import std.math.leadingZeros
main() {
let x: UInt8 = 64
let leadingZeros = leadingZeros(x)
println(leadingZeros)
}
Running result:
1
func log(Float16)
public func log(x: Float16): Float16
Description: Obtains the logarithm of x with base e.
Parameters:
- x: Float16: antilogarithm
Returns:
- Float16: The logarithm of
xwith base e is returned.
Note:
Special scenarios of return values are as follows:
Example:
import std.math.log
main() {
let x: Float16 = 2.718282
let log = log(x)
println(log)
}
Running result:
1.000000
func log(Float32)
public func log(x: Float32): Float32
Description: Obtains the logarithm of x with base e.
Parameters:
- x: Float32: antilogarithm
Returns:
- Float32: The logarithm of
xwith base e is returned.
Note:
Special scenarios of return values are as follows:
Example:
import std.math.log
main() {
let x: Float32 = 2.718282
let log = log(x)
println(log)
}
Running result:
1.000000
func log(Float64)
public func log(x: Float64): Float64
Description: Obtains the logarithm of x with base e.
Parameters:
- x: Float64: antilogarithm
Returns:
- Float64: The logarithm of
xwith base e is returned.
Note:
Special scenarios of return values are as follows:
Example:
import std.math.log
main() {
let x: Float64 = 2.718282
let log = log(x)
println(log)
}
Running result:
1.000000
func log10(Float16)
public func log10(x: Float16): Float16
Description: Obtains the logarithm of x with base 10.
Parameters:
- x: Float16: antilogarithm
Returns:
- Float16: The logarithm of
xwith base 10 is returned.
Note:
Special scenarios of return values are as follows:
Example:
import std.math.log10
main() {
let x: Float16 = 1000.0
let log10 = log10(x)
println(log10)
}
Running result:
3.000000
func log10(Float32)
public func log10(x: Float32): Float32
Description: Obtains the logarithm of x with base 10.
Parameters:
- x: Float32: antilogarithm
Returns:
- Float32: The logarithm of
xwith base 10 is returned.
Note:
Special scenarios of return values are as follows:
Example:
import std.math.log10
main() {
let x: Float32 = 1000.0
let log10 = log10(x)
println(log10)
}
Running result:
3.000000
func log10(Float64)
public func log10(x: Float64): Float64
Description: Obtains the logarithm of x with base 10.
Parameters:
- x: Float64: antilogarithm
Returns:
- Float64: The logarithm of
xwith base 10 is returned.
Note:
Special scenarios of return values are as follows:
Example:
import std.math.log10
main() {
let x: Float64 = 1000.0
let log10 = log10(x)
println(log10)
}
Running result:
3.000000
func log2(Float16)
public func log2(x: Float16): Float16
Description: Obtains the logarithm of x with base 2.
Parameters:
- x: Float16: antilogarithm
Returns:
- Float16: The logarithm of
xwith base 2 is returned.
Note:
Special scenarios of return values are as follows:
Example:
import std.math.log2
main() {
let x: Float16 = 1024.0
let log2 = log2(x)
println(log2)
}
Running result:
10.000000
func log2(Float32)
public func log2(x: Float32): Float32
Description: Obtains the logarithm of x with base 2.
Parameters:
- x: Float32: antilogarithm
Returns:
- Float32: The logarithm of
xwith base 2 is returned.
Note:
Special scenarios of return values are as follows:
Example:
import std.math.log2
main() {
let x: Float32 = 1024.0
let log2 = log2(x)
println(log2)
}
Running result:
10.000000
func log2(Float64)
public func log2(x: Float64): Float64
Description: Obtains the logarithm of x with base 2.
Parameters:
- x: Float64: antilogarithm
Returns:
- Float64: The logarithm of
xwith base 2 is returned.
Note:
Special scenarios of return values are as follows:
Example:
import std.math.log2
main() {
let x: Float64 = 1024.0
let log2 = log2(x)
println(log2)
}
Running result:
10.000000
func logBase(Float16, Float16)
public func logBase(x: Float16, base: Float16): Float16
Description: Obtains the logarithm of x with base base.
Parameters:
- x: Float16: antilogarithm, which must be greater than 0
- base: Float16: base, which must be greater than 0 and cannot be 1
Returns:
- Float16: The logarithm of
xwith basebaseis returned.
Throws:
- IllegalArgumentException: If the antilogarithm or base is not positive or if the base is 1, this exception is thrown.
Example:
import std.math.logBase
main() {
let x: Float16 = 512.0
let base: Float16 = 2.0
let logBase = logBase(x, base)
println(logBase)
}
Running result:
9.000000
func logBase(Float32, Float32)
public func logBase(x: Float32, base: Float32): Float32
Description: Obtains the logarithm of x with base base.
Parameters:
- x: Float32: antilogarithm, which must be greater than 0
- base: Float32: base, which must be greater than 0 and cannot be 1
Returns:
- Float32: The logarithm of
xwith basebaseis returned.
Throws:
- IllegalArgumentException: If the antilogarithm or base is not positive or if the base is 1, this exception is thrown.
Example:
import std.math.logBase
main() {
let x: Float32 = 1024.0
let base: Float32 = 2.0
let logBase = logBase(x, base)
println(logBase)
}
Running result:
10.000000
func logBase(Float64, Float64)
public func logBase(x: Float64, base: Float64): Float64
Description: Obtains the logarithm of x with base base.
Parameters:
- x: Float64: antilogarithm, which must be greater than 0
- base: Float64: base, which must be greater than 0 and cannot be 1
Returns:
- Float64: The logarithm of
xwith basebaseis returned.
Throws:
- IllegalArgumentException: If the antilogarithm or base is not positive or if the base is 1, this exception is thrown.
Example:
import std.math.logBase
main() {
let x: Float64 = 1024.0
let base: Float64 = 2.0
let logBase = logBase(x, base)
println(logBase)
}
Running result:
10.000000
func max(Float16, Float16)
public func max(a: Float16, b: Float16): Float16
Description: Obtains the larger value between two numbers. If any input parameter is NaN, NaN is returned.
Parameters:
Returns:
- Float16: The larger value between the two numbers is returned. If any input parameter is NaN, NaN is returned.
Example:
import std.math.max
main() {
let a: Float16 = 1.0
let b: Float16 = 2.0
let max = max(a, b)
println(max)
}
Running result:
2.000000
func max(Float32, Float32)
public func max(a: Float32, b: Float32): Float32
Description: Obtains the larger value between two numbers. If any input parameter is NaN, NaN is returned.
Parameters:
Returns:
- Float32: The larger value between the two numbers is returned. If any input parameter is NaN, NaN is returned.
Example:
import std.math.max
main() {
let a: Float32 = 1.0
let b: Float32 = 2.0
let max = max(a, b)
println(max)
}
Running result:
2.000000
func max(Float64, Float64)
public func max(a: Float64, b: Float64): Float64
Description: Obtains the larger value between two numbers. If any input parameter is NaN, NaN is returned.
Parameters:
Returns:
- Float64: The larger value between the two numbers is returned. If any input parameter is NaN, NaN is returned.
Example:
import std.math.max
main() {
let a: Float64 = 1.0
let b: Float64 = 2.0
let max = max(a, b)
println(max)
}
Running result:
2.000000
func max(Int16, Int16)
public func max(a: Int16, b: Int16): Int16
Description: Obtains the larger value between two numbers.
Parameters:
Returns:
- Int16: The larger value between the two numbers is returned.
Example:
import std.math.max
main() {
let a: Int16 = -1
let b: Int16 = 2
let max = max(a, b)
println(max)
}
Running result:
2
func max(Int32, Int32)
public func max(a: Int32, b: Int32): Int32
Description: Obtains the larger value between two numbers.
Parameters:
Returns:
- Int32: The larger value between the two numbers is returned.
Example:
import std.math.max
main() {
let a: Int32 = -1
let b: Int32 = 2
let max = max(a, b)
println(max)
}
Running result:
2
func max(Int64, Int64)
public func max(a: Int64, b: Int64): Int64
Description: Obtains the larger value between two numbers.
Parameters:
Returns:
- Int64: The larger value between the two numbers is returned.
Example:
import std.math.max
main() {
let a: Int64 = -1
let b: Int64 = 2
let max = max(a, b)
println(max)
}
Running result:
2
func max(Int8, Int8)
public func max(a: Int8, b: Int8): Int8
Description: Obtains the larger value between two numbers.
Parameters:
Returns:
- Int8: The larger value between the two numbers is returned.
Example:
import std.math.max
main() {
let a: Int8 = -1
let b: Int8 = 2
let max = max(a, b)
println(max)
}
Running result:
2
func max(UInt16, UInt16)
public func max(a: UInt16, b: UInt16): UInt16
Description: Obtains the larger value between two numbers.
Parameters:
Returns:
- UInt16: The larger value between the two numbers is returned.
Example:
import std.math.max
main() {
let a: UInt16 = 1
let b: UInt16 = 2
let max = max(a, b)
println(max)
}
Running result:
2
func max(UInt32, UInt32)
public func max(a: UInt32, b: UInt32): UInt32
Description: Obtains the larger value between two numbers.
Parameters:
Returns:
- UInt32: The larger value between the two numbers is returned.
Example:
import std.math.max
main() {
let a: UInt32 = 1
let b: UInt32 = 2
let max = max(a, b)
println(max)
}
Running result:
2
func max(UInt64, UInt64)
public func max(a: UInt64, b: UInt64): UInt64
Description: Obtains the larger value between two numbers.
Parameters:
Returns:
- UInt64: The larger value between the two numbers is returned.
Example:
import std.math.max
main() {
let a: UInt64 = 1
let b: UInt64 = 2
let max = max(a, b)
println(max)
}
Running result:
2
func max(UInt8, UInt8)
public func max(a: UInt8, b: UInt8): UInt8
Description: Obtains the larger value between two numbers.
Parameters:
Returns:
- UInt8: The larger value between the two numbers is returned.
Example:
import std.math.max
main() {
let a: UInt8 = 1
let b: UInt8 = 2
let max = max(a, b)
println(max)
}
Running result:
2
func maxNaN(Float16, Float16)
public func maxNaN(a: Float16, b: Float16): Float16
Description: Obtains the larger value between two numbers. maxNaN supports only floating-point numbers. If any input parameter is NaN, NaN is returned.
Parameters:
Returns:
- Float16: The larger value between the two numbers is returned. If any input parameter is NaN, NaN is returned.
Example:
import std.math.maxNaN
main() {
let a: Float16 = 1.0
let b: Float16 = 2.0
let maxNaN = maxNaN(a, b)
println(maxNaN)
}
Running result:
2.000000
func maxNaN(Float32, Float32)
public func maxNaN(a: Float32, b: Float32): Float32
Description: Obtains the larger value between two numbers. maxNaN supports only floating-point numbers. If any input parameter is NaN, NaN is returned.
Parameters:
Returns:
- Float32: The larger value between the two numbers is returned. If any input parameter is NaN, NaN is returned.
Example:
import std.math.maxNaN
main() {
let a: Float32 = 1.0
let b: Float32 = 2.0
let maxNaN = maxNaN(a, b)
println(maxNaN)
}
Running result:
2.000000
func maxNaN(Float64, Float64)
public func maxNaN(a: Float64, b: Float64): Float64
Description: Obtains the larger value between two numbers. maxNaN supports only floating-point numbers. If any input parameter is NaN, NaN is returned.
Parameters:
Returns:
- Float64: The larger value between the two numbers is returned. If any input parameter is NaN, NaN is returned.
Example:
import std.math.maxNaN
main() {
let a: Float64 = 1.0
let b: Float64 = 2.0
let maxNaN = maxNaN(a, b)
println(maxNaN)
}
Running result:
2.000000
func min(Float16, Float16)
public func min(a: Float16, b: Float16): Float16
Description: Obtains the smaller value between two numbers. If any input parameter is NaN, NaN is returned.
Parameters:
Returns:
- Float16: The smaller value between the two numbers is returned. If any input parameter is NaN, NaN is returned.
Example:
import std.math.min
main() {
let a: Float16 = 1.0
let b: Float16 = 2.0
let min = min(a, b)
println(min)
}
Running result:
1.000000
func min(Float32, Float32)
public func min(a: Float32, b: Float32): Float32
Description: Obtains the smaller value between two numbers. If any input parameter is NaN, NaN is returned.
Parameters:
Returns:
- Float32: The smaller value between the two numbers is returned. If any input parameter is NaN, NaN is returned.
Example:
import std.math.min
main() {
let a: Float32 = 1.0
let b: Float32 = 2.0
let min = min(a, b)
println(min)
}
Running result:
1.000000
func min(Float64, Float64)
public func min(a: Float64, b: Float64): Float64
Description: Obtains the smaller value between two numbers. If any input parameter is NaN, NaN is returned.
Parameters:
Returns:
- Float64: The smaller value between the two numbers is returned. If any input parameter is NaN, NaN is returned.
Example:
import std.math.min
main() {
let a: Float64 = 1.0
let b: Float64 = 2.0
let min = min(a, b)
println(min)
}
Running result:
1.000000
func min(Int16, Int16)
public func min(a: Int16, b: Int16): Int16
Description: Obtains the smaller value between two numbers.
Parameters:
Returns:
- Int16: The smaller value between the two numbers is returned.
Example:
import std.math.min
main() {
let a: Int16 = -1
let b: Int16 = 2
let min = min(a, b)
println(min)
}
Running result:
-1
func min(Int32, Int32)
public func min(a: Int32, b: Int32): Int32
Description: Obtains the smaller value between two numbers.
Parameters:
Returns:
- Int32: The smaller value between the two numbers is returned.
Example:
import std.math.min
main() {
let a: Int32 = -1
let b: Int32 = 2
let min = min(a, b)
println(min)
}
Running result:
-1
func min(Int64, Int64)
public func min(a: Int64, b: Int64): Int64
Description: Obtains the smaller value between two numbers.
Parameters:
Returns:
- Int64: The smaller value between the two numbers is returned.
Example:
import std.math.min
main() {
let a: Int64 = -1
let b: Int64 = 2
let min = min(a, b)
println(min)
}
Running result:
-1
func min(Int8, Int8)
public func min(a: Int8, b: Int8): Int8
Description: Obtains the smaller value between two numbers.
Parameters:
Returns:
- Int8: The smaller value between the two numbers is returned.
Example:
import std.math.min
main() {
let a: Int8 = -1
let b: Int8 = 2
let min = min(a, b)
println(min)
}
Running result:
-1
func min(UInt16, UInt16)
public func min(a: UInt16, b: UInt16): UInt16
Description: Obtains the smaller value between two numbers.
Parameters:
Returns:
- UInt16: The smaller value between the two numbers is returned.
Example:
import std.math.min
main() {
let a: UInt16 = 1
let b: UInt16 = 2
let min = min(a, b)
println(min)
}
Running result:
1
func min(UInt32, UInt32)
public func min(a: UInt32, b: UInt32): UInt32
Description: Obtains the smaller value between two numbers.
Parameters:
Returns:
- UInt32: The smaller value between the two numbers is returned.
Example:
import std.math.min
main() {
let a: UInt32 = 1
let b: UInt32 = 2
let min = min(a, b)
println(min)
}
Running result:
1
func min(UInt64, UInt64)
public func min(a: UInt64, b: UInt64): UInt64
Description: Obtains the smaller value between two numbers.
Parameters:
Returns:
- UInt64: The smaller value between the two numbers is returned.
Example:
import std.math.min
main() {
let a: UInt64 = 1
let b: UInt64 = 2
let min = min(a, b)
println(min)
}
Running result:
1
func min(UInt8, UInt8)
public func min(a: UInt8, b: UInt8): UInt8
Description: Obtains the smaller value between two numbers.
Parameters:
Returns:
- UInt8: The smaller value between the two numbers is returned.
Example:
import std.math.min
main() {
let a: UInt8 = 1
let b: UInt8 = 2
let min = min(a, b)
println(min)
}
Running result:
1
func minNaN(Float16, Float16)
public func minNaN(a: Float16, b: Float16): Float16
Description: Obtains the smaller value between two numbers. minNaN supports only floating-point numbers. If any input parameter is NaN, NaN is returned.
Parameters:
Returns:
- Float16: The smaller value between the two numbers is returned. If any input parameter is NaN, NaN is returned.
Example:
import std.math.minNaN
main() {
let a: Float16 = 1.0
let b: Float16 = 2.0
let minNaN = minNaN(a, b)
println(minNaN)
}
Running result:
1.000000
func minNaN(Float32, Float32)
public func minNaN(a: Float32, b: Float32): Float32
Description: Obtains the smaller value between two numbers. minNaN supports only floating-point numbers. If any input parameter is NaN, NaN is returned.
Parameters:
Returns:
- Float32: The smaller value between the two numbers is returned. If any input parameter is NaN, NaN is returned.
Example:
import std.math.minNaN
main() {
let a: Float32 = 1.0
let b: Float32 = 2.0
let minNaN = minNaN(a, b)
println(minNaN)
}
Running result:
1.000000
func minNaN(Float64, Float64)
public func minNaN(a: Float64, b: Float64): Float64
Description: Obtains the smaller value between two numbers. minNaN supports only floating-point numbers. If any input parameter is NaN, NaN is returned.
Parameters:
Returns:
- Float64: The smaller value between the two numbers is returned. If any input parameter is NaN, NaN is returned.
Example:
import std.math.minNaN
main() {
let a: Float64 = 1.0
let b: Float64 = 2.0
let minNaN = minNaN(a, b)
println(minNaN)
}
Running result:
1.000000
func pow(Float32, Float32)
public func pow(base: Float32, exponent: Float32): Float32
Description: Obtains the floating-point number base raised to the power of exponent.
Parameters:
Returns:
- Float32: The floating-point number
baseraised to the power ofexponentis returned. If the value does not exist,nanis returned.
Example:
import std.math.pow
main() {
let base: Float32 = -1.0
let exponent: Float32 = 0.5
let pow = pow(base, exponent)
println(pow)
}
Running result:
nan
func pow(Float32, Int32)
public func pow(base: Float32, exponent: Int32): Float32
Description: Obtains the floating-point number base raised to the power of exponent.
Parameters:
Returns:
- Float32: The floating-point number
baseraised to the power ofexponentis returned.
Example:
import std.math.pow
main() {
let base: Float32 = -1.0
let exponent: Int32 = 2
let pow = pow(base, exponent)
println(pow)
}
Running result:
1.000000
func pow(Float64, Float64)
public func pow(base: Float64, exponent: Float64): Float64
Description: Obtains the floating-point number base raised to the power of exponent.
Parameters:
Returns:
- Float64: The floating-point number
baseraised to the power ofexponentis returned. If the value does not exist,nanis returned.
Example:
import std.math.pow
main() {
let base: Float64 = -1.0
let exponent: Float64 = 0.5
let pow = pow(base, exponent)
println(pow)
}
Running result:
nan
func pow(Float64, Int64)
public func pow(base: Float64, exponent: Int64): Float64
Description: Obtains the floating-point number base raised to the power of exponent.
Parameters:
Returns:
- Float64: The floating-point number
baseraised to the power ofexponentis returned.
Example:
import std.math.pow
main() {
let base: Float64 = -1.0
let exponent: Int64 = 2
let pow = pow(base, exponent)
println(pow)
}
Running result:
1.000000
func reverse(UInt16)
public func reverse(x: UInt16): UInt16
Description: Obtains the number after bitwise inversion of an unsigned integer.
Parameters:
- x: UInt16: unsigned integer to be inversed
Returns:
- UInt16: The unsigned number after inversion is returned.
Example:
import std.math.reverse
main() {
let n: UInt16 = 0x8000
let reverse = reverse(n)
println(reverse)
}
Running result:
1
func reverse(UInt32)
public func reverse(x: UInt32): UInt32
Description: Obtains the number after bitwise inversion of an unsigned integer.
Parameters:
- x: UInt32: unsigned integer to be inversed
Returns:
- UInt32: The unsigned number after inversion is returned.
Example:
import std.math.reverse
main() {
let n: UInt32 = 0x8000_0000
let reverse = reverse(n)
println(reverse)
}
Running result:
1
func reverse(UInt64)
public func reverse(x: UInt64): UInt64
Description: Obtains the number after bitwise inversion of an unsigned integer.
Parameters:
- x: UInt64: unsigned integer to be inversed
Returns:
- UInt64: The unsigned number after inversion is returned.
Example:
import std.math.reverse
main() {
let n: UInt64 = 0x8000_0000_0000_0000
let reverse = reverse(n)
println(reverse)
}
Running result:
1
func reverse(UInt8)
public func reverse(x: UInt8): UInt8
Description: Obtains the number after bitwise inversion of an unsigned integer.
Parameters:
- x: UInt8: unsigned integer to be inversed
Returns:
- UInt8: The unsigned number after inversion is returned.
Example:
import std.math.reverse
main() {
let n: UInt8 = 0x80
let reverse = reverse(n)
println(reverse)
}
Running result:
1
func rotate(Int16, Int8)
public func rotate(num: Int16, d: Int8): Int16
Description: Obtains the result of bitwise rotation of an integer.
Parameters:
- num: Int16: integer input
- d: Int8: number of bits for rotation; rules: negative numbers shifted rightwards and positive numbers shifted leftwards
Returns:
- Int16: The integer after rotation is returned.
Example:
import std.math.rotate
main() {
let n: Int16 = 1
let rotate = rotate(n, 2)
println(rotate)
}
Running result:
4
func rotate(Int32, Int8)
public func rotate(num: Int32, d: Int8): Int32
Description: Obtains the result of bitwise rotation of an integer.
Parameters:
- num: Int32: integer input
- d: Int8: number of bits for rotation; rules: negative numbers shifted rightwards and positive numbers shifted leftwards
Returns:
- Int32: The integer after rotation is returned.
Example:
import std.math.rotate
main() {
let n: Int32 = 1
let rotate = rotate(n, 2)
println(rotate)
}
Running result:
4
func rotate(Int64, Int8)
public func rotate(num: Int64, d: Int8): Int64
Description: Obtains the result of bitwise rotation of an integer.
Parameters:
- num: Int64: integer input
- d: Int8: number of bits for rotation; rules: negative numbers shifted rightwards and positive numbers shifted leftwards
Returns:
- Int64: The integer after rotation is returned.
Example:
import std.math.rotate
main() {
let n: Int64 = 1
let rotate = rotate(n, 2)
println(rotate)
}
Running result:
4
func rotate(Int8, Int8)
public func rotate(num: Int8, d: Int8): Int8
Description: Obtains the result of bitwise rotation of an integer.
Parameters:
- num: Int8: integer input
- d: Int8: number of bits for rotation; rules: negative numbers shifted rightwards and positive numbers shifted leftwards
Returns:
- Int8: The integer after rotation is returned.
Example:
import std.math.rotate
main() {
let n: Int8 = 1
let rotate = rotate(n, 2)
println(rotate)
}
Running result:
4
func rotate(UInt16, Int8)
public func rotate(num: UInt16, d: Int8): UInt16
Description: Obtains the result of bitwise rotation of an integer.
Parameters:
- num: UInt16: integer input
- d: Int8: number of bits for rotation; rules: negative numbers shifted rightwards and positive numbers shifted leftwards
Returns:
- UInt16: The integer after rotation is returned.
Example:
import std.math.rotate
main() {
let n: UInt16 = 1
let rotate = rotate(n, 2)
println(rotate)
}
Running result:
4
func rotate(UInt32, Int8)
public func rotate(num: UInt32, d: Int8): UInt32
Description: Obtains the result of bitwise rotation of an integer.
Parameters:
- num: UInt32: integer input
- d: Int8: number of bits for rotation; rules: negative numbers shifted rightwards and positive numbers shifted leftwards
Returns:
- UInt32: The integer after rotation is returned.
Example:
import std.math.rotate
main() {
let n: UInt32 = 1
let rotate = rotate(n, 2)
println(rotate)
}
Running result:
4
func rotate(UInt64, Int8)
public func rotate(num: UInt64, d: Int8): UInt64
Description: Obtains the result of bitwise rotation of an integer.
Parameters:
- num: UInt64: integer input
- d: Int8: number of bits for rotation; rules: negative numbers shifted rightwards and positive numbers shifted leftwards
Returns:
- UInt64: The integer after rotation is returned.
Example:
import std.math.rotate
main() {
let n: UInt64 = 1
let rotate = rotate(n, 2)
println(rotate)
}
Running result:
4
func rotate(UInt8, Int8)
public func rotate(num: UInt8, d: Int8): UInt8
Description: Obtains the result of bitwise rotation of an integer.
Parameters:
- num: UInt8: integer input
- d: Int8: number of bits for rotation; rules: negative numbers shifted rightwards and positive numbers shifted leftwards
Returns:
- UInt8: The integer after rotation is returned.
Example:
import std.math.rotate
main() {
let n: UInt8 = 1
let rotate = rotate(n, 2)
println(rotate)
}
Running result:
4
func round(Float16)
public func round(x: Float16): Float16
Description: Obtains the rounded-off value of a floating-point number through calculation based on the round-off rule in IEEE-754. A floating-point number having two nearest integers is rounded to the even number.
Parameters:
- x: Float16: floating-point number whose rounded-off value is to be obtained through calculation
Returns:
- Float16: The rounded-off value of the floating-point number is returned. If the floating-point number has two nearest integers, the even number is returned.
Example:
import std.math.round
main() {
let n: Float16 = 1.5
let round = round(n)
println(round)
}
Running result:
2.000000
func round(Float32)
public func round(x: Float32): Float32
Description: Obtains the rounded-off value of a floating-point number through calculation based on the round-off rule in IEEE-754. A floating-point number having two nearest integers is rounded to the even number.
Parameters:
- x: Float32: floating-point number whose rounded-off value is to be obtained through calculation
Returns:
- Float32: The rounded-off value of the floating-point number is returned. If the floating-point number has two nearest integers, the even number is returned.
Example:
import std.math.round
main() {
let n: Float32 = 1.5
let round = round(n)
println(round)
}
Running result:
2.000000
func round(Float64)
public func round(x: Float64): Float64
Description: Obtains the rounded-off value of a floating-point number through calculation based on the round-off rule in IEEE-754. A floating-point number having two nearest integers is rounded to the even number.
Parameters:
- x: Float64: floating-point number whose rounded-off value is to be obtained through calculation
Returns:
- Float64: The rounded-off value of the floating-point number is returned. If the floating-point number has two nearest integers, the even number is returned.
Example:
import std.math.round
main() {
let n: Float64 = 1.5
let round = round(n)
println(round)
}
Running result:
2.000000
func sin(Float16)
public func sin(x: Float16): Float16
Description: Obtains the sine function value of a half-precision floating-point number through calculation.
Parameters:
- x: Float16: half-precision floating-point number input, in radians
Returns:
- Float16: The sine function value of the input parameter is returned.
Example:
import std.math.sin
main() {
let n: Float16 = 3.1415926/2.0
let sin = sin(n)
println(sin)
}
Running result:
1.000000
func sin(Float32)
public func sin(x: Float32): Float32
Description: Obtains the sine function value of a single-precision floating-point number through calculation.
Parameters:
- x: Float32: single-precision floating-point number input, in radians
Returns:
- Float32: The sine function value of the input parameter is returned.
Example:
import std.math.sin
main() {
let n: Float32 = 3.1415926/2.0
let sin = sin(n)
println(sin)
}
Running result:
1.000000
func sin(Float64)
public func sin(x: Float64): Float64
Description: Obtains the sine function value of a double-precision floating-point number through calculation.
Parameters:
- x: Float64: double-precision floating-point number input, in radians
Returns:
- Float64: The sine function value of the input parameter is returned.
Example:
import std.math.sin
main() {
let n: Float64 = 3.1415926/2.0
let sin = sin(n)
println(sin)
}
Running result:
1.000000
func sinh(Float16)
public func sinh(x: Float16): Float16
Description: Obtains the hyperbolic sine function value of a half-precision floating-point number through calculation.
Parameters:
- x: Float16: half-precision floating-point number input
Returns:
- Float16: The hyperbolic sine function value of the input parameter is returned.
Example:
import std.math.sinh
main() {
let n: Float16 = 0.0
let sinh = sinh(n)
println(sinh)
}
Running result:
0.000000
func sinh(Float32)
public func sinh(x: Float32): Float32
Description: Obtains the hyperbolic sine function value of a single-precision floating-point number through calculation.
Parameters:
- x: Float32: single-precision floating-point number input
Returns:
- Float32: The hyperbolic sine function value of the input parameter is returned.
Example:
import std.math.sinh
main() {
let n: Float32 = 0.0
let sinh = sinh(n)
println(sinh)
}
Running result:
0.000000
func sinh(Float64)
public func sinh(x: Float64): Float64
Description: Obtains the hyperbolic sine function value of a double-precision floating-point number through calculation.
Parameters:
- x: Float64: double-precision floating-point number input
Returns:
- Float64: The hyperbolic sine function value of the input parameter is returned.
Example:
import std.math.sinh
main() {
let n: Float64 = 0.0
let sinh = sinh(n)
println(sinh)
}
Running result:
0.000000
func sqrt(Float16)
public func sqrt(x: Float16): Float16
Description: Obtains the arithmetic square root of a floating-point number.
Parameters:
- x: Float16: floating-point number whose arithmetic square root is to be obtained through calculation. The value of
xmust be greater than or equal to 0.
Returns:
- Float16: The arithmetic square root of the input floating-point number is returned.
Throws:
- IllegalArgumentException: When the parameter value is negative, this exception is thrown.
Example:
import std.math.sqrt
main() {
let n: Float16 = 16.0
let sqrt = sqrt(n)
println(sqrt)
}
Running result:
4.000000
func sqrt(Float32)
public func sqrt(x: Float32): Float32
Description: Obtains the arithmetic square root of a floating-point number.
Parameters:
- x: Float32: floating-point number whose arithmetic square root is to be obtained through calculation. The value of
xmust be greater than or equal to 0.
Returns:
- Float32: The arithmetic square root of the input floating-point number is returned.
Throws:
- IllegalArgumentException: When the parameter value is negative, this exception is thrown.
Example:
import std.math.sqrt
main() {
let n: Float32 = 16.0
let sqrt = sqrt(n)
println(sqrt)
}
Running result:
4.000000
func sqrt(Float64)
public func sqrt(x: Float64): Float64
Description: Obtains the arithmetic square root of a floating-point number.
Parameters:
- x: Float64: floating-point number whose arithmetic square root is to be obtained through calculation. The value of
xmust be greater than or equal to 0.
Returns:
- Float64: The arithmetic square root of the input floating-point number is returned.
Throws:
- IllegalArgumentException: When the parameter value is negative, this exception is thrown.
Example:
import std.math.sqrt
main() {
let n: Float64 = 16.0
let sqrt = sqrt(n)
println(sqrt)
}
Running result:
4.000000
func tan(Float16)
public func tan(x: Float16): Float16
Description: Obtains the tangent function value of a half-precision floating-point number through calculation.
Parameters:
- x: Float16: half-precision floating-point number input, in radians
Returns:
- Float16: The tangent function value of the input parameter is returned.
Example:
import std.math.tan
main() {
let n: Float16 = 0.0
let tan = tan(n)
println(tan)
}
Running result:
0.000000
func tan(Float32)
public func tan(x: Float32): Float32
Description: Obtains the tangent function value of a single-precision floating-point number through calculation.
Parameters:
- x: Float32: single-precision floating-point number input, in radians
Returns:
- Float32: The tangent function value of the input parameter is returned.
Example:
import std.math.tan
main() {
let n: Float32 = 0.0
let tan = tan(n)
println(tan)
}
Running result:
0.000000
func tan(Float64)
public func tan(x: Float64): Float64
Description: Obtains the tangent function value of a double-precision floating-point number through calculation.
Parameters:
- x: Float64: double-precision floating-point number input, in radians
Returns:
- Float64: The tangent function value of the input parameter is returned.
Example:
import std.math.tan
main() {
let n: Float64 = 0.0
let tan = tan(n)
println(tan)
}
Running result:
0.000000
func tanh(Float16)
public func tanh(x: Float16): Float16
Description: Obtains the hyperbolic tangent function value of a half-precision floating-point number through calculation.
Parameters:
- x: Float16: half-precision floating-point number input
Returns:
- Float16: The hyperbolic tangent function value of the input parameter is returned.
Example:
import std.math.tanh
main() {
let n: Float16 = 0.0
let tanh = tanh(n)
println(tanh)
}
Running result:
0.000000
func tanh(Float32)
public func tanh(x: Float32): Float32
Description: Obtains the hyperbolic tangent function value of a single-precision floating-point number through calculation.
Parameters:
- x: Float32: single-precision floating-point number input
Returns:
- Float32: The hyperbolic tangent function value of the input parameter is returned.
Example:
import std.math.tanh
main() {
let n: Float32 = 0.0
let tanh = tanh(n)
println(tanh)
}
Running result:
0.000000
func tanh(Float64)
public func tanh(x: Float64): Float64
Description: Obtains the hyperbolic tangent function value of a double-precision floating-point number through calculation.
Parameters:
- x: Float64: double-precision floating-point number input
Returns:
- Float64: The hyperbolic tangent function value of the input parameter is returned.
Example:
import std.math.tanh
main() {
let n: Float64 = 0.0
let tanh = tanh(n)
println(tanh)
}
Running result:
0.000000
func throwIllegalArgumentException()
public func throwIllegalArgumentException(): Int64
Description: This function is used to throw an invalid parameter exception.
Returns:
- Int64: The value 0 is returned.
Throws:
- IllegalArgumentException: When the function is called, this exception is thrown.
func trailingZeros(Int16)
public func trailingZeros(x: Int16): Int8
Description: Obtains the number of consecutive 0s starting from the least significant bit in the binary expression of a 16-bit signed integer. If the least significant bit is not 0, the value 0 is returned.
Parameters:
- x: Int16: integer of which the number of trailing zeros is to be obtained
Returns:
- Int8: number of trailing zeros
Example:
import std.math.trailingZeros
main() {
let x: Int16 = 512
let trailingZeros = trailingZeros(x)
println(trailingZeros)
}
Running result:
9
func trailingZeros(Int32)
public func trailingZeros(x: Int32): Int8
Description: Obtains the number of consecutive 0s starting from the least significant bit in the binary expression of a 32-bit signed integer. If the least significant bit is not 0, the value 0 is returned.
Parameters:
- x: Int32: integer of which the number of trailing zeros is to be obtained
Returns:
- Int8: number of trailing zeros
Example:
import std.math.trailingZeros
main() {
let x: Int32 = 512
let trailingZeros = trailingZeros(x)
println(trailingZeros)
}
Running result:
9
func trailingZeros(Int64)
public func trailingZeros(x: Int64): Int8
Description: Obtains the number of consecutive 0s starting from the least significant bit in the binary expression of a 64-bit signed integer. If the least significant bit is not 0, the value 0 is returned.
Parameters:
- x: Int64: integer of which the number of trailing zeros is to be obtained
Returns:
- Int8: number of trailing zeros
Example:
import std.math.trailingZeros
main() {
let x: Int64 = 512
let trailingZeros = trailingZeros(x)
println(trailingZeros)
}
Running result:
9
func trailingZeros(Int8)
public func trailingZeros(x: Int8): Int8
Description: Obtains the number of consecutive 0s starting from the least significant bit in the binary expression of a 16-bit signed integer. If the least significant bit is not 0, the value 0 is returned.
Parameters:
- x: Int8: integer of which the number of trailing zeros is to be obtained
Returns:
- Int8: number of trailing zeros
Example:
import std.math.trailingZeros
main() {
let x: Int8 = 64
let trailingZeros = trailingZeros(x)
println(trailingZeros)
}
Running result:
6
func trailingZeros(UInt16)
public func trailingZeros(x: UInt16): Int8
Description: Obtains the number of consecutive 0s starting from the least significant bit in the binary expression of a 16-bit unsigned integer. If the least significant bit is not 0, the value 0 is returned.
Parameters:
- x: UInt16: integer of which the number of trailing zeros is to be obtained
Returns:
- Int8: number of trailing zeros
Example:
import std.math.trailingZeros
main() {
let x: UInt16 = 512
let trailingZeros = trailingZeros(x)
println(trailingZeros)
}
Running result:
9
func trailingZeros(UInt32)
public func trailingZeros(x: UInt32): Int8
Description: Obtains the number of consecutive 0s starting from the least significant bit in the binary expression of a 32-bit unsigned integer. If the least significant bit is not 0, the value 0 is returned.
Parameters:
- x: UInt32: integer of which the number of trailing zeros is to be obtained
Returns:
- Int8: number of trailing zeros
Example:
import std.math.trailingZeros
main() {
let x: UInt32 = 512
let trailingZeros = trailingZeros(x)
println(trailingZeros)
}
Running result:
9
func trailingZeros(UInt64)
public func trailingZeros(x: UInt64): Int8
Description: Obtains the number of consecutive 0s starting from the least significant bit in the binary expression of a 64-bit unsigned integer. If the least significant bit is not 0, the value 0 is returned.
Parameters:
- x: UInt64: integer of which the number of trailing zeros is to be obtained
Returns:
- Int8: number of trailing zeros
Example:
import std.math.trailingZeros
main() {
let x: UInt64 = 512
let trailingZeros = trailingZeros(x)
println(trailingZeros)
}
Running result:
9
func trailingZeros(UInt8)
public func trailingZeros(x: UInt8): Int8
Description: Obtains the number of consecutive 0s starting from the least significant bit in the binary expression of an 8-bit unsigned integer. If the least significant bit is not 0, the value 0 is returned.
Parameters:
- x: UInt8: integer of which the number of trailing zeros is to be obtained
Returns:
- Int8: number of trailing zeros
Example:
import std.math.trailingZeros
main() {
let x: UInt8 = 64
let trailingZeros = trailingZeros(x)
println(trailingZeros)
}
Running result:
6
func trunc(Float16)
public func trunc(x: Float16): Float16
Description: Obtains the value after truncation of a floating-point number.
Parameters:
- x: Float16: floating-point number to be truncated
Returns:
- Float16: The value after truncation of the input floating-point number is returned.
Example:
import std.math.trunc
main() {
let x: Float16 = 64.555566
let trunc = trunc(x)
println(trunc)
}
Running result:
64.000000
func trunc(Float32)
public func trunc(x: Float32): Float32
Description: Obtains the value after truncation of a floating-point number.
Parameters:
- x: Float32: floating-point number to be truncated
Returns:
- Float32: The value after truncation of the input floating-point number is returned.
Example:
import std.math.trunc
main() {
let x: Float32 = 64.555566
let trunc = trunc(x)
println(trunc)
}
Running result:
64.000000
func trunc(Float64)
public func trunc(x: Float64): Float64
Description: Obtains the value after truncation of a floating-point number.
Parameters:
- x: Float64: floating-point number to be truncated
Returns:
- Float64: The value after truncation of the input floating-point number is returned.
Example:
import std.math.trunc
main() {
let x: Float64 = 64.555566
let trunc = trunc(x)
println(trunc)
}
Running result:
64.000000
Interface
interface MathExtension
public interface MathExtension
Description: Specifies an auxiliary interface for exporting prop and the Max and Min attributes. For floating-point numbers, the NaN, Inf, PI, E, MinDenormal, and MinNormal attributes as well as isInf, isNaN, and isNormal interfaces are exported. This auxiliary interface is empty.
extend Float16 <: MathExtension
extend Float16 <: MathExtension
Description: Extends half-precision floating-point numbers to support some mathematical constants.
Parent Type:
static prop E
public static prop E: Float16
Description: Obtains the natural constant of a half-precision floating-point number.
Type: Float16
static prop Inf
public static prop Inf: Float16
Description: Obtains the infinite number of a half-precision floating-point number.
Type: Float16
static prop Max
public static prop Max: Float16
Description: Obtains the maximum value of a half-precision floating-point number.
Type: Float16
static prop Min
public static prop Min: Float16
Description: Obtains the minimum value of a half-precision floating-point number.
Type: Float16
static prop MinDenormal
public static prop MinDenormal: Float16
Description: Obtains the minimum subnormal number of a half-precision floating-point number. The minimum positive subnormal number is the minimum positive number expressed in the IEEE double-precision format.
Type: Float16
static prop MinNormal
public static prop MinNormal: Float16
Description: Obtains the minimum normal number of a half-precision floating-point number.
Type: Float16
static prop NaN
public static prop NaN: Float16
Description: Obtains the NaN of a half-precision floating-point number.
Type: Float16
static prop PI
public static prop PI: Float16
Description: Obtains the circumference constant of a half-precision floating-point number.
Type: Float16
func isInf()
public func isInf(): Bool
Description: Checks whether a floating-point number of the Float16 type is an infinite value.
Returns:
- Bool: If the value of Float16 is positive infinity or negative infinity,
trueis returned. Otherwise,falseis returned.
func isNaN()
public func isNaN(): Bool
Description: Checks whether a floating-point number of the Float16 type is a non-numeric value.
Returns:
- Bool: If the value of Float16 is a non-numeric value,
trueis returned. Otherwise,falseis returned.
func isNormal()
public func isNormal(): Bool
Description: Checks whether a floating-point number of the Float16 type is a normal value.
Returns:
- Bool: If the value of Float16 is a normal floating-point number,
trueis returned. Otherwise,falseis returned.
extend Float32 <: MathExtension
extend Float32 <: MathExtension
Description: Extends single-precision floating-point numbers to support some mathematical constants.
Parent Type:
static prop E
public static prop E: Float32
Description: Obtains the natural constant of a single-precision floating-point number.
Type: Float32
static prop Inf
public static prop Inf: Float32
Description: Obtains the infinite number of a single-precision floating-point number.
Type: Float32
static prop Max
public static prop Max: Float32
Description: Obtains the maximum value of a single-precision floating-point number.
Type: Float32
static prop Min
public static prop Min: Float32
Description: Obtains the minimum value of a single-precision floating-point number.
Type: Float32
static prop MinDenormal
public static prop MinDenormal: Float32
Description: Obtains the minimum subnormal number of a single-precision floating-point number.
Type: Float32
static prop MinNormal
public static prop MinNormal: Float32
Description: Obtains the minimum normal number of a single-precision floating-point number.
Type: Float32
static prop NaN
public static prop NaN: Float32
Description: Obtains the NaN of a single-precision floating-point number.
Type: Float32
static prop PI
public static prop PI: Float32
Description: Obtains the circumference constant of a single-precision floating-point number.
Type: Float32
func isInf()
public func isInf(): Bool
Description: Checks whether a floating-point number of the Float32 type is an infinite value.
Returns:
- Bool: If the value of Float32 is positive infinity or negative infinity,
trueis returned. Otherwise,falseis returned.
func isNaN()
public func isNaN(): Bool
Description: Checks whether a floating-point number of the Float32 type is a non-numeric value.
Returns:
- Bool: If the value of Float32 is a non-numeric value,
trueis returned. Otherwise,falseis returned.
func isNormal()
public func isNormal(): Bool
Description: Checks whether a floating-point number of the Float32 type is a normal value.
Returns:
- Bool: If the value of Float32 is a normal floating-point number,
trueis returned. Otherwise,falseis returned.
extend Float64 <: MathExtension
extend Float64 <: MathExtension
Description: Extends double-precision floating-point numbers to support some mathematical constants.
Parent Type:
static prop E
public static prop E: Float64
Description: Obtains the natural constant of a double-precision floating-point number.
Type: Float64
static prop Inf
public static prop Inf: Float64
Description: Obtains the infinite number of a double-precision floating-point number.
Type: Float64
static prop Max
public static prop Max: Float64
Description: Obtains the maximum value of a double-precision floating-point number.
Type: Float64
static prop Min
public static prop Min: Float64
Description: Obtains the minimum value of a double-precision floating-point number.
Type: Float64
static prop MinDenormal
public static prop MinDenormal: Float64
Description: Obtains the minimum subnormal number of a double-precision floating-point number.
Type: Float64
static prop MinNormal
public static prop MinNormal: Float64
Description: Obtains the minimum normal number of a double-precision floating-point number.
Type: Float64
static prop NaN
public static prop NaN: Float64
Description: Obtains the NaN of a double-precision floating-point number.
Type: Float64
static prop PI
public static prop PI: Float64
Description: Obtains the circumference constant of a double-precision floating-point number.
Type: Float64
func isInf()
public func isInf(): Bool
Description: Checks whether a floating-point number of the Float64 type is an infinite value.
Returns:
- Bool: If the value of Float64 is positive infinity or negative infinity,
trueis returned. Otherwise,falseis returned.
func isNaN()
public func isNaN(): Bool
Description: Checks whether a floating-point number of the Float64 type is a non-numeric value.
Returns:
- Bool: If the value of Float64 is a non-numeric value,
trueis returned. Otherwise,falseis returned.
func isNormal()
public func isNormal(): Bool
Description: Checks whether a floating-point number of the Float64 type is a normal value.
Returns:
- Bool: If the value of Float64 is a normal floating-point number,
trueis returned. Otherwise,falseis returned.
extend Int16 <: MathExtension
extend Int16 <: MathExtension
Description: Extends 16-bit signed integers to support some mathematical constants.
Parent Type:
static prop Max
public static prop Max: Int16
Description: Obtains the maximum value of a 16-bit signed integer.
Type: Int16
static prop Min
public static prop Min: Int16
Description: Obtains the minimum value of a 16-bit signed integer.
Type: Int16
extend Int32 <: MathExtension
extend Int32 <: MathExtension
Description: Extends 32-bit signed integers to support some mathematical constants.
Parent Type:
static prop Max
public static prop Max: Int32
Description: Obtains the maximum value of a 32-bit signed integer.
Type: Int32
static prop Min
public static prop Min: Int32
Description: Obtains the minimum value of a 32-bit signed integer.
Type: Int32
extend Int64 <: MathExtension
extend Int64 <: MathExtension
Description: Extends 64-bit signed integers to support some mathematical constants.
Parent Type:
static prop Max
public static prop Max: Int64
Description: Obtains the maximum value of a 64-bit signed integer.
Type: Int64
static prop Min
public static prop Min: Int64
Description: Obtains the minimum value of a 64-bit signed integer.
Type: Int64
extend Int8 <: MathExtension
extend Int8 <: MathExtension
Description: Extends 8-bit signed integers to support some mathematical constants.
Parent Type:
static prop Max
public static prop Max: Int8
Description: Obtains the maximum value of an 8-bit signed integer.
Type: Int8
static prop Min
public static prop Min: Int8
Description: Obtains the minimum value of an 8-bit signed integer.
Type: Int8
extend IntNative <: MathExtension
extend IntNative <: MathExtension
Description: Extends platform-dependent signed integers to support some mathematical constants.
Parent Type:
static prop Max
public static prop Max: IntNative
Description: Obtains the maximum value of a platform-dependent signed integer.
Type: IntNative
static prop Min
public static prop Min: IntNative
Description: Obtains the minimum value of a platform-dependent signed integer.
Type: IntNative
extend UInt16 <: MathExtension
extend UInt16 <: MathExtension
Description: Extends 16-bit unsigned integers to support some mathematical constants.
Parent Type:
static prop Max
public static prop Max: UInt16
Description: Obtains the maximum value of a 16-bit unsigned integer.
Type: UInt16
static prop Min
public static prop Min: UInt16
Description: Obtains the minimum value of a 16-bit unsigned integer.
Type: UInt16
extend UInt32 <: MathExtension
extend UInt32 <: MathExtension
Description: Extends 32-bit unsigned integers to support some mathematical constants.
Parent Type:
static prop Max
public static prop Max: UInt32
Description: Obtains the maximum value of a 32-bit unsigned integer.
Type: UInt32
static prop Min
public static prop Min: UInt32
Description: Obtains the minimum value of a 32-bit unsigned integer.
Type: UInt32
extend UInt64 <: MathExtension
extend UInt64 <: MathExtension
Description: Extends 64-bit unsigned integers to support some mathematical constants.
Parent Type:
static prop Max
public static prop Max: UInt64
Description: Obtains the maximum value of a 64-bit unsigned integer.
Type: UInt64
static prop Min
public static prop Min: UInt64
Description: Obtains the minimum value of a 64-bit unsigned integer.
Type: UInt64
extend UInt8 <: MathExtension
extend UInt8 <: MathExtension
Description: Extends 8-bit unsigned integers to support some mathematical constants.
Parent Type:
static prop Max
public static prop Max: UInt8
Description: Obtains the maximum value of an 8-bit unsigned integer.
Type: UInt8
static prop Min
public static prop Min: UInt8
Description: Obtains the minimum value of an 8-bit unsigned integer.
Type: UInt8
extend UIntNative <: MathExtension
extend UIntNative <: MathExtension
Description: Extends platform-dependent unsigned integers to support some mathematical constants.
Parent Type:
static prop Max
public static prop Max: UIntNative
Description: Obtains the maximum value of a platform-dependent unsigned integer.
Type: UIntNative
static prop Min
public static prop Min: UIntNative
Description: Obtains the minimum value of a platform-dependent unsigned integer.
Type: UIntNative
Enumeration
enum RoundingMode
public enum RoundingMode {
| CEILING
| DOWN
| FLOOR
| HALF_EVEN
| HALF_UP
| UP
}
Specifies the enumeration class of rounding rules, including six rounding rules. In addition to the five rounding rules of floating-point numbers specified in IEEE 754, the most commonly used rounding off rule is provided.
| Decimal number | UP | DOWN | CEILING | FLOOR | HALF_UP | HALF_EVEN |
|---|---|---|---|---|---|---|
| 7.5 | 8 | 7 | 8 | 7 | 8 | 8 |
| 4.5 | 5 | 4 | 5 | 4 | 5 | 4 |
| -1.1 | -2 | -1 | -1 | -2 | -1 | -1 |
| -4.5 | -5 | -4 | -4 | -5 | -5 | -4 |
| -7.5 | -8 | -7 | -7 | -8 | -8 | -8 |
CEILING
CEILING
Description: Rounds towards positive infinity.
DOWN
DOWN
Description: Rounds towards zero.
FLOOR
FLOOR
Description: Rounds towards negative infinity.
HALF_EVEN
HALF_EVEN
Description: Rounds a number using the rounding half to even method, which is also called "banker's rounding".
HALF_UP
HALF_UP
Description: Rounds off a number.
UP
UP
Description: Rounds away from zero.
Example of Basic Mathematical Operations
import std.math.clamp
import std.math.gcd
import std.math.lcm
import std.math.rotate
// Limits the range of a number through the clamp function.
func clampTest() {
let min: Float16 = -0.123
let max: Float16 = 0.123
let v: Float16 = 0.121
let c = clamp(v, min, max)
println("${c==v}")
let min2: Float16 = -0.999
let max2: Float16 = 10.123
let v2: Float16 = 11.121
let c2 = clamp(v2, min2, max2)
println("${c2==max2}")
let min3: Float16 = -0.999
let max3: Float16 = 10.123
let v3: Float16 = -1.121
let c3 = clamp(v3, min3, max3)
println("${c3==min3}")
}
// Obtains the greatest common divisor of two numbers through calculation.
func gcdTest() {
let c2 = gcd(0, -60)
println("c2=${c2}")
let c4 = gcd(-33, 27)
println("c4=${c4}")
}
// Obtains the least common multiple of two numbers through calculation.
func lcmTest() {
let a: Int8 = lcm(Int8(-3), Int8(5))
println("a=${a}")
}
// Reserves an integer by a bit in the binary system.
func rotateTest() {
let a: Int8 = rotate(Int8(92), Int8(4))
println("a=${a}")
let b: Int32 = rotate(Int32(1), Int8(4))
println("b=${b}")
}
main(): Unit {
println("/*********************** clampTest **********************/")
clampTest()
println("/*********************** gcdTest ************************/")
gcdTest()
println("/*********************** lcmTest ************************/")
lcmTest()
println("/*********************** rotateTest *********************/")
rotateTest()
}
Running result:
/*********************** clampTest **********************/
true
true
true
/*********************** gcdTest ************************/
c2=60
c4=3
/*********************** lcmTest ************************/
a=15
/*********************** rotateTest *********************/
a=-59
b=16
std.math.numeric Package
Function Description
The math.numeric package provides extensions for basic types.
For example:
- Big integer (BigInt) is supported.
- High-precision decimal numbers are supported.
- Common mathematical calculation capabilities, including high-precision calculation rules, are provided.
API List
Function
| Name | Description |
|---|---|
| abs(BigInt) | Obtains the absolute value of a BigInt instance through calculation. |
| abs(Decimal) | Calculates the absolute value of Decimal. |
| sqrt(BigInt) | Calculates the arithmetic square root of BigInt and rounds down the result. |
| sqrt(Decimal) | Calculates the arithmetic square root of Decimal. If the result is an infinite decimal, IEEE 754-2019 decimal128 is used to round the result by default. |
| gcd(BigInt, BigInt) | Obtains the greatest common divisor of two BigInt instances through calculation. A non-negative number (equivalent to the absolute value of the greatest common divisor) is returned. |
| lcm(BigInt, BigInt) | Obtains the least common multiple of two BigInt instances through calculation. A positive number (equivalent to the least common multiple of the absolute value) is returned. The value 0 is returned only when any input parameter is 0. |
| max(BigInt, BigInt) | Calculates and returns the larger one between two BigInt instances. |
| min(BigInt, BigInt) | Calculates and returns the smaller one between two BigInt instances. |
| countOne(BigInt) | Calculates and returns the number of 1s in the binary supplemental code of BigInt. |
| round(Decimal, RoundingMode) | Calculates the rounded value of Decimal by rounding it to the nearest integer based on the rounding mode. |
Enumeration
| Name | Description |
|---|---|
| OverflowStrategy | Specifies the enumeration class of overflow policies. A total of three overflow policies are included. When the BigInt and Decimal types are converted to the integer type, different overflow processing policies can be specified. |
Struct
| Name | Description |
|---|---|
| BigInt | Specifies a (binary) signed integer of any precision. Cangjie struct BigInt is used for calculation and type conversion of signed integers of any precision. |
| Decimal | Decimal is used to represent signed decimal numbers of any precision. The context, result precision, and rounding rule can be specified during operation. Conversions between basic types (such as Int, UInt, String, and Float) and the BigInt type are supported. Basic attributes of Decimal objects can be queried. Basic mathematical operations are supported. Basic capabilities such as object comparison, hashing, and string printing are provided. |
Function
func abs(BigInt)
public func abs(i: BigInt): BigInt
Description: Obtains the absolute value of BigInt.
Parameters:
Returns:
Example:
import std.math.numeric.*
main() {
let n: BigInt = BigInt(-23)
let abs = abs(n)
println(abs)
}
Running result:
23
func abs(Decimal)
public func abs(d: Decimal): Decimal
Description: Calculates the absolute value of a Decimal number.
Parameters:
Returns:
Example
import std.math.numeric.*
main() {
let d: Decimal = Decimal("-1.23")
let abs = abs(d)
println(abs)
}
Running result:
1.23
func countOne(BigInt)
public func countOne(i: BigInt): Int64
Description: Calculates and returns the number of 1s in the binary supplemental code of the input parameter BigInt.
Parameters:
Returns:
Example:
import std.math.numeric.*
main() {
let i: BigInt = BigInt(255)
let countOne = countOne(i)
println(countOne)
}
Running result:
8
func gcd(BigInt, BigInt)
public func gcd(i1: BigInt, i2: BigInt): BigInt
Description: Obtains the greatest common divisor of two input BigInt parameters. A non-negative number (equivalent to the absolute value of the greatest common divisor) is returned.
Parameters:
Returns:
- BigInt: a non-negative number of the greatest common divisor of
i1andi2
Example:
import std.math.numeric.*
main() {
let i1: BigInt = BigInt(-36)
let i2: BigInt = BigInt(48)
let gcd = gcd(i1, i2)
println(gcd)
}
Running result:
12
func lcm(BigInt, BigInt)
public func lcm(i1: BigInt, i2: BigInt): BigInt
Description: Obtains the least common multiple of two input BigInt parameters. A positive number (equivalent to the absolute value of the least common multiple) is returned. The value 0 is returned only when any input parameter is 0.
Parameters:
Returns:
- BigInt: a positive number of the least common multiple of
i1andi2. However, the value 0 is returned only when any input parameter is 0.
Example:
import std.math.numeric.*
main() {
let i1: BigInt = BigInt(-36)
let i2: BigInt = BigInt(48)
let lcm = lcm(i1, i2)
println(lcm)
}
Running result:
144
func max(BigInt, BigInt)
public func max(i1: BigInt, i2: BigInt): BigInt
Description: Calculates and returns the larger one between the two input BigInt parameters.
Parameters:
Returns:
Example:
import std.math.numeric.*
main() {
let i1: BigInt = BigInt(-36)
let i2: BigInt = BigInt(48)
let max = max(i1, i2)
println(max)
}
Running result:
48
func min(BigInt, BigInt)
public func min(i1: BigInt, i2: BigInt): BigInt
Description: Calculates and returns the smaller one between the two input BigInt parameters.
Parameters:
Returns:
Example:
import std.math.numeric.*
main() {
let i1: BigInt = BigInt(-36)
let i2: BigInt = BigInt(48)
let min = min(i1, i2)
println(min)
}
Running result:
-36
func round(Decimal, RoundingMode)
public func round(d: Decimal, roundingMode!: RoundingMode = RoundingMode.HALF_EVEN): Decimal
Description: Calculates the rounded value of Decimal by rounding it to the nearest integer based on the rounding mode.
Parameters:
- d: Decimal: Decimal number to be rounded
- roundingMode!: RoundingMode: rounding rule
Returns:
Throws:
- OverflowException: If the scale value of the rounding result overflows, this exception is thrown.
func sqrt(BigInt)
public func sqrt(i: BigInt): BigInt
Description: Obtains the arithmetic square root of BigInt through calculation and rounds it down.
Parameters:
- i: BigInt: BigInt for which the arithmetic square root needs to be calculated. The input parameter must be a non-negative number.
Returns:
Throws:
- IllegalArgumentException: If the input parameter is negative, this exception is thrown.
Example:
import std.math.numeric.*
main() {
let n: BigInt = BigInt(23)
let sqrt = sqrt(n)
println(sqrt)
}
Running result:
4
func sqrt(Decimal)
public func sqrt(d: Decimal): Decimal
Description: Calculates the arithmetic square root of Decimal. If the result is an infinite decimal, IEEE 754-2019 decimal128 is used to round the result by default.
Parameters:
- d: Decimal: Decimal number whose arithmetic square root needs to be calculated. The input parameter must be of a non-negative value.
Returns:
Throws:
- IllegalArgumentException: If the value of the input parameter is negative, this exception is thrown.
- OverflowException: If the scale value of the rounding result overflows, this exception is thrown.
Example:
import std.math.numeric.*
main() {
let n: Decimal = Decimal("36")
let sqrt = sqrt(n)
println(sqrt)
}
Running result:
6
Enumeration
enum OverflowStrategy
public enum OverflowStrategy {
| saturating
| throwing
| wrapping
}
Specifies the enumeration class of overflow policies. A total of three overflow policies are included. When the BigInt and Decimal types are converted to the integer type, different overflow processing policies can be specified.
saturating
saturating
Description: Returns the maximum value of the target type if the current value is greater than the maximum value of the target type, or returns the minimum value of the target type if the current value is less than the minimum value of the target type after an overflow occurs.
throwing
throwing
Description: Throws an exception if an overflow occurs.
wrapping
wrapping
Description: Truncates the most significant bits if an overflow occurs.
Struct
struct BigInt
public struct BigInt <: Comparable<BigInt> & Hashable & ToString
Description: Specifies a (binary) signed integer of any precision. Cangjie struct BigInt is used for calculation and type conversion of signed integers of any precision.
Parent Type:
prop bitLen
public prop bitLen: Int64
Description: Obtains the minimum bit length of BigInt. For example, if the value is –3 (101), 3 is returned. If the value is –1 (11), 2 is returned. If the value if 0 (0), 1 is returned.
Type: Int64
prop sign
public prop sign: Int64
Description: Obtains the sign of BigInt. If the value is a positive number, 1 is returned. If the value is 0, 0 is returned. If the value is a negative number, –1 is returned.
Type: Int64
init(Array<Byte>)
public init(bytes: Array<Byte>)
Description: Constructs a BigInt struct in the form of complementary code by using the big-endian Byte array.
There are two data storage methods:
-
Big-endian storage mode: The high-order bytes are stored at the lower-bit address.
-
Little-endian storage mode: The low-order bytes are stored in the upper-bit address.
Parameters:
Throws:
- IllegalArgumentException: If an empty array is passed, this exception is thrown.
init(Bool, Array<Byte>)
public init(sign: Bool, magnitude: Array<Byte>)
Description: Constructs a BigInt struct based on the sign bit and the absolute value of the true value. If an empty array is passed, it is considered as 0.
Parameters:
- sign: Bool: sign true indicates a non-negative number, and false indicates a negative number.
- magnitude: Array<Byte>: original binary code of the absolute value of the true value
Throws:
- IllegalArgumentException: If
signis set to false and the input array is 0, this exception is thrown.
init(Bool, Int64, Random)
public init(sign: Bool, bitLen: Int64, rand!: Random = Random())
Description: Constructs a random BigInt struct by specifying the bit length, random seed and whether the struct is a positive or negative number. The bit length must be greater than 0.
Parameters:
- sign: Bool: Specifies whether the random BigInt is positive or negative.
- bitLen: Int64: Specifies the maximum bit length of the random BigInt.
- rand!: Random: specified random seed
Throws:
- IllegalArgumentException: If the specified bit length is less than or equal to 0, this exception is thrown.
init(Int16)
public init(n: Int16)
Description: Constructs a BigInt struct by using a 16-bit signed integer.
Parameters:
- n: Int16: 16-bit signed integer
init(Int32)
public init(n: Int32)
Description: Constructs a BigInt struct by using a 32-bit signed integer.
Parameters:
- n: Int32: 32-bit signed integer
init(Int64)
public init(n: Int64)
Description: Constructs a BigInt struct by using a 64-bit signed integer.
Parameters:
- n: Int64: 64-bit signed integer
init(Int8)
public init(n: Int8)
Description: Constructs a BigInt struct by using an 8-bit signed integer.
Parameters:
- n: Int8: 8-bit signed integer
init(IntNative)
public init(n: IntNative)
Description: Constructs a BigInt struct by using a platform-dependent signed integer.
Parameters:
- n: IntNative: platform-dependent signed integer
init(String, Int64)
public init(s: String, base!: Int64 = 10)
Description: Constructs a BigInt struct based on the string and number system. Binary numbers to base-36 numbers are supported.
The string rule is as follows: The string starts with an optional sign (positive or negative) and is followed by a string of digits represented by the string.
IntegerString : (SignString)? ValueString
-
SignString : + | -
-
ValueString : Digits
-
Digits: Digit | Digit Digits
-
Digit : '0' ~ '9' | 'A' ~ 'Z' | 'a' ~ 'z'
-
If Digit ranges from '0' to '9', (Digit - '0') < base must be met.
-
If Digit ranges from 'A' to** 'Z'**, (Digit - 'A') + 10 < base must be met.
-
If Digit ranges from 'a' to 'z', (Digit - 'A') + 10 < base must be met.
-
-
-
Parameters:
- s: String: string used to construct a BigInt struct The string can start with a plus sign (+) or minus sign (–) followed by a character sequence consisting of non-null Arabic numbers or uppercase or lowercase Latin letters. The meanings of uppercase and lowercase letters are the same. The size of 'a' or 'A' is equal to 10 in decimal, the size of 'b' or 'B' is equal to 11 in decimal, and so on. The string in the sequence cannot be greater than or equal to the parameter in number system.
- base!: Int64: number system represented by a string. The value range is [2, 36].
Throws:
- IllegalArgumentException: If the string
sdoes not comply with the preceding rules or the number system represented bybaseis not within the range of [2, 36], this exception is thrown.
init(UInt16)
public init(n: UInt16)
Description: Constructs a BigInt struct by using a 16-bit unsigned integer.
Parameters:
- n: UInt16: 16-bit unsigned integer
init(UInt32)
public init(n: UInt32)
Description: Constructs a BigInt struct by using a 32-bit unsigned integer.
Parameters:
- n: UInt32: 32-bit unsigned integer
init(UInt64)
public init(n: UInt64)
Description: Constructs a BigInt struct by using a 64-bit unsigned integer.
Parameters:
- n: UInt64: 64-bit unsigned integer
init(UInt8)
public init(n: UInt8)
Description: Constructs a BigInt struct by using an 8-bit unsigned integer.
Parameters:
- n: UInt8: 8-bit unsigned integer
init(UIntNative)
public init(n: UIntNative)
Description: Constructs a BigInt struct by using a platform-dependent unsigned integer.
Parameters:
- n: UIntNative: platform-dependent unsigned integer
static func randomProbablePrime(Int64, UInt64, Random)
public static func randomProbablePrime(bitLen: Int64, certainty: UInt64, rand!: Random = Random()): BigInt
Description: Constructs a random BigInt prime number using an optional random seed. The bit length of the prime number cannot be greater than the input parameter bitLen.
The prime number must be an integer greater than or equal to 2. Therefore, bitLen must be greater than or equal to 2. The Miller-Rabin test is used for prime number detection. In the Miller-Rabin test, the possibility that a sum is misjudged as a prime number decreases with the increase of certainty.
Parameters:
- bitLen: Int64: maximum bit length of the random prime number to be generated
- certainty: UInt64: number of times that the random prime number generated passes the Miller-Rabin test. A larger number of times that the random prime number passes the test indicates a lower probability that the sum is misjudged as a prime number.
- rand!: Random: specified random seed
Returns:
- BigInt: the generated random prime number
Throws:
- IllegalArgumentException: If the specified bit length is less than or equal to 1, this exception is thrown.
Example:
import std.math.numeric.BigInt
main() {
let randomProbablePrime = BigInt.randomProbablePrime(6, 3)
println(randomProbablePrime)
}
Running result:
11
func clearBit(Int64)
public func clearBit(index: Int64): BigInt
Description: Constructs a new BigInt by changing the bit at a given index to 0.
Parameters:
- index: Int64: index of the bit to be set The value of
indexmust be greater than or equal to 0.
Returns:
Throws:
- IllegalArgumentException: If
indexis less than 0, this exception is thrown.
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt(1024)
let clearBit = bigInt.clearBit(10)
println(clearBit)
}
Running result:
0
func compare(BigInt)
public func compare(that: BigInt): Ordering
Description: Checks the relationship between two BigInt instances
Parameters:
Returns:
- Ordering: relationship between the two BigInt instances If the current BigInt is equal to that, Ordering.EQ is returned. If the current BigInt is less than that, Ordering.LT is returned. If the current BigInt is greater than that, Ordering.GT is returned.
func divAndMod(BigInt)
public func divAndMod(that: BigInt): (BigInt, BigInt)
Description: Performs a division operation on BigInt.
Divides the current BigInt by the other BigInt and returns the quotient and modulus. The behavior of the division operation is the same as that of the basic type. That is, the quotient is rounded close to 0, and the sign of the modulus is the same as that of the dividend.
Parameters:
- that: BigInt: divisor The divisor cannot be 0.
Returns:
Throws:
- ArithmeticException: If the divisor is 0, this exception is thrown.
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt(1025)
let that = BigInt(512)
let (div, mod) = bigInt.divAndMod(that)
println(div)
println(mod)
}
Running result:
2
1
func flipBit(Int64)
public func flipBit(index: Int64): BigInt
Description: Constructs a new BigInt by flipping the bit at a given index.
Parameters:
- index: Int64: index of the bit to be flipped The value of
indexmust be greater than or equal to 0.
Returns:
Throws:
- IllegalArgumentException: If
indexis less than 0, this exception is thrown.
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt(1024)
let flipBit = bigInt.flipBit(10)
println(flipBit)
}
Running result:
0
func hashCode()
public func hashCode(): Int64
Description: Calculates and returns the hash value of BigInt.
Returns:
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt(1024)
let hashCode = bigInt.hashCode()
println(hashCode)
}
Running result:
1024
func isProbablePrime(UInt64)
public func isProbablePrime(certainty: UInt64): Bool
Description: Checks whether a number is a prime number.
Note:
This function uses the Miller-Rabin test, whose accuracy increases with the increase of certainty. If the number is a prime number, true is returned. If the number is a sum (false is expected), the probability of returning true is less than 1/4certainty. A prime number must be a positive integer greater than or equal to 2, that is, a prime number cannot be a negative number, 0, or 1.
Parameters:
- certainty: UInt64: number of the Miller-Rabin tests to be performed Note that if the number of tests is 0, it indicates that the test is not performed. In this case, true is returned (that is, true is returned even the number is not a prime number).
Returns:
- Bool: If the number is a prime number, true is returned. Otherwise, false is returned.
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt(1024)
let isProbablePrime = bigInt.isProbablePrime(10)
println(isProbablePrime)
}
Running result:
false
func lowestOneBit()
public func lowestOneBit(): Int64
Description: Checks the position of the least significant bit of 1.
Returns:
- Int64: the position of the least significant bit of 1 If the bits are all 0s, –1 is returned.
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt(-1)
let lowestOneBit = bigInt.lowestOneBit()
println(lowestOneBit)
}
Running result:
0
func modInverse(BigInt)
public func modInverse(that: BigInt): BigInt
Description: Calculates the modular inverse.
The modulus inverse element r satisfies $(this * r) % that == 1$. this and that must be mutually prime. When that is ±1, the result is always 0.
Parameters:
- that: BigInt: the other BigInt to be compared with The input parameter cannot be 0 and must be mutually prime to
this.
Returns:
- BigInt: modular inverse
Throws:
- IllegalArgumentException: If
thisandthatare not mutually prime orthatis 0, this exception is thrown.
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt(1025)
let that = BigInt(512)
let modInverse = bigInt.modInverse(that)
println(modInverse)
}
Running result:
1
func modPow
public func modPow(n: BigInt, m!: ?BigInt = None): BigInt
Description: Calculates the result of the nth power modulo m of BigInt and returns the result.
The rule of the modulus is the same as that of the basic type. That is, the sign of the modulus is the same as that of the divisor.
Parameters:
Returns:
- BigInt: result of the modulo operation after multiplication
Throws:
- ArithmeticException: If the divisor is 0, this exception is thrown.
- IllegalArgumentException: If the exponent is negative, this exception is thrown.
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt(2)
let n = BigInt(10)
let modPow = bigInt.modPow(n)
println(modPow)
}
Running result:
1024
func quo(BigInt)
public func quo(that: BigInt): BigInt
Description: Performs a division operation on BigInt.
Divides the BigInt by the other BigInt and returns the result. The behavior of this division operation is different from that of operator overloading function. Specifically, if the divisor is a negative number, the result of this function is rounded away from 0 to ensure that the remainder is greater than or equal to 0.
Parameters:
- that: BigInt: divisor The divisor cannot be 0.
Returns:
Throws:
- ArithmeticException: If the divisor is 0, this exception is thrown.
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt(1025)
let that = BigInt(512)
let quo = bigInt.quo(that)
println(quo)
}
Running result:
2
func quoAndRem(BigInt)
public func quoAndRem(that: BigInt): (BigInt, BigInt)
Description: Performs a division operation on BigInt.
Divides the BigInt by the other BigInt and returns the quotient and remainder. The behavior of this division operation is different from that of the divAndMod function. Specifically, if the divisor is a negative number, the result of this function is rounded away from 0 to ensure that the remainder is always greater than or equal to 0.
Parameters:
- that: BigInt: divisor The divisor cannot be 0.
Returns:
Throws:
- ArithmeticException: If the divisor is 0, this exception is thrown.
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt(1025)
let that = BigInt(512)
let (quo, rem) = bigInt.quoAndRem(that)
println(quo)
println(rem)
}
Running result:
2
1
func rem(BigInt)
public func rem(that: BigInt): BigInt
Description: Performs a modulo operation on BigInt.
Divides the BigInt by the other BigInt and returns the remainder. The result of the remainder is greater than or equal to 0.
Parameters:
- that: BigInt: divisor The divisor cannot be 0.
Returns:
Throws:
- ArithmeticException: If the divisor is 0, this exception is thrown.
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt(1025)
let that = BigInt(512)
let rem = bigInt.rem(that)
println(rem)
}
Running result:
1
func setBit(Int64)
public func setBit(index: Int64): BigInt
Description: Constructs a new BigInt by changing the bit at a given index to 1.
Parameters:
- index: Int64: index of the bit to be set The value of
indexmust be greater than or equal to 0.
Returns:
Throws:
- IllegalArgumentException: If
indexis less than 0, this exception is thrown.
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt(0)
let setBit = bigInt.setBit(10)
println(setBit)
}
Running result:
1024
func testBit(Int64)
public func testBit(index: Int64): Bool
Description: Checks the bit information at a given position. If the bit at the given position is 0, false is returned. If the bit at the specified position is 1, true is returned.
Parameters:
- index: Int64: index of the bit to be obtained The value of
indexmust be greater than or equal to 0.
Returns:
- Bool: information of the bit at the given position
Throws:
- IllegalArgumentException: If
indexis less than 0, this exception is thrown.
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt(-1)
let testBit = bigInt.testBit(100)
println(testBit)
}
Running result:
true
func toBytes()
public func toBytes(): Array<Byte>
Description: Calculates and returns the big-endian complementary code byte array of BigInt.
The least significant bit of the lowest index of a byte array is the sign bit. For example, for 128 of the BigInt type, [0, 128] (the sign bit is 0) is returned, and for –128 of the BigInt type, [128] (the sign bit is 1) is returned.
Returns:
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt(0x400)
let toBytes = bigInt.toBytes()
println(toBytes)
}
Running result:
[4, 0]
func toInt16(OverflowStrategy)
public func toInt16(overflowHandling!: OverflowStrategy = throwing): Int16
Description: Converts the current BigInt object to the Int16 type. The overflow policy can be customized.
Parameters:
- overflowHandling!: OverflowStrategy: overflow handling policy for conversion
- "throwing": exception mode If an overflow occurs, an exception is thrown.
- "wrapping": overflow mode If an overflow occurs, the most significant bits are truncated.
- "saturating": boundary value mode Returns the maximum value of the target type if the current value is greater than the maximum value of the target type, or returns the minimum value of the target type if the current value is less than the minimum value of the target type after an overflow occurs.
Returns:
Throws:
- OverflowException: If no overflow policy is specified or the overflow handling policy for conversion is
throwing, this exception is thrown.
Example:
import std.math.numeric.BigInt
import std.math.numeric.OverflowStrategy
main() {
let bigInt = BigInt(0x8000_0000_0000)
let toInt16 = bigInt.toInt16(overflowHandling: saturating)
println(toInt16)
}
Running result:
32767
func toInt32(OverflowStrategy)
public func toInt32(overflowHandling!: OverflowStrategy = throwing): Int32
Description: Converts the current BigInt object to the Int32 type. The overflow policy can be customized.
Parameters:
- overflowHandling!: OverflowStrategy: overflow handling policy for conversion
- "throwing": exception mode If an overflow occurs, an exception is thrown.
- "wrapping": overflow mode If an overflow occurs, the most significant bits are truncated.
- "saturating": boundary value mode Returns the maximum value of the target type if the current value is greater than the maximum value of the target type, or returns the minimum value of the target type if the current value is less than the minimum value of the target type after an overflow occurs.
Returns:
Throws:
- OverflowException: If no overflow policy is specified or the overflow handling policy for conversion is
throwing, this exception is thrown.
Example:
import std.math.numeric.BigInt
import std.math.numeric.OverflowStrategy
main() {
let bigInt = BigInt(0x8000_0000_00FF)
let toInt32 = bigInt.toInt32(overflowHandling: wrapping)
println(toInt32)
}
Running result:
255
func toInt64(OverflowStrategy)
public func toInt64(overflowHandling!: OverflowStrategy = throwing): Int64
Description: Converts the current BigInt object to the Int64 type. The overflow policy can be customized.
Parameters:
- overflowHandling!: OverflowStrategy: overflow handling policy for conversion
- "throwing": exception mode If an overflow occurs, an exception is thrown.
- "wrapping": overflow mode If an overflow occurs, the most significant bits are truncated.
- "saturating": boundary value mode Returns the maximum value of the target type if the current value is greater than the maximum value of the target type, or returns the minimum value of the target type if the current value is less than the minimum value of the target type after an overflow occurs.
Returns:
Throws:
- OverflowException: If no overflow policy is specified or the overflow handling policy for conversion is
throwing, this exception is thrown.
Example:
import std.math.numeric.BigInt
import std.math.numeric.OverflowStrategy
main() {
let bigInt = BigInt("800000000000000000", base: 16)
let toInt64 = bigInt.toInt64(overflowHandling: wrapping)
println(toInt64)
}
Running result:
0
func toInt8(OverflowStrategy)
public func toInt8(overflowHandling!: OverflowStrategy = throwing): Int8
Description: Converts the current BigInt object to the Int8 type. The overflow policy can be customized.
Parameters:
- overflowHandling!: OverflowStrategy: overflow handling policy for conversion
- "throwing": exception mode If an overflow occurs, an exception is thrown.
- "wrapping": overflow mode If an overflow occurs, the most significant bits are truncated.
- "saturating": boundary value mode Returns the maximum value of the target type if the current value is greater than the maximum value of the target type, or returns the minimum value of the target type if the current value is less than the minimum value of the target type after an overflow occurs.
Returns:
Throws:
- OverflowException: If no overflow policy is specified or the overflow handling policy for conversion is
throwing, this exception is thrown.
Example:
import std.math.numeric.BigInt
import std.math.numeric.OverflowStrategy
main() {
let bigInt = BigInt(1024)
let toInt8 = bigInt.toInt8(overflowHandling: saturating)
println(toInt8)
}
Running result:
127
func toIntNative(OverflowStrategy)
public func toIntNative(overflowHandling!: OverflowStrategy = throwing): IntNative
Description: Converts the current BigInt object to the IntNative type. The overflow policy can be customized.
Parameters:
- overflowHandling!: OverflowStrategy: overflow handling policy for conversion
- "throwing": exception mode If an overflow occurs, an exception is thrown.
- "wrapping": overflow mode If an overflow occurs, the most significant bits are truncated.
- "saturating": boundary value mode Returns the maximum value of the target type if the current value is greater than the maximum value of the target type, or returns the minimum value of the target type if the current value is less than the minimum value of the target type after an overflow occurs.
Returns:
Throws:
- OverflowException: If no overflow policy is specified or the overflow handling policy for conversion is
throwing, this exception is thrown.
Example:
import std.math.numeric.BigInt
import std.math.numeric.OverflowStrategy
main() {
let bigInt = BigInt("800000000000000000", base: 16)
let toIntNative = bigInt.toIntNative(overflowHandling: wrapping)
println(toIntNative)
}
Running result:
0
func toString()
public func toString(): String
Description: Calculates and returns the decimal string representation of BigInt.
Returns:
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt(0x400)
let toString = bigInt.toString()
println(toString)
}
Running result:
1024
func toString(Int64)
public func toString(base: Int64): String
Description: Calculates and returns the string representation of BigInt in an arbitrary number system.
Parameters:
- base!: Int64: number system represented by a string. The value range is [2, 36].
Returns:
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt(0x400)
let toString = bigInt.toString(2)
println(toString)
}
Running result:
10000000000
func toUInt16(OverflowStrategy)
public func toUInt16(overflowHandling!: OverflowStrategy = throwing): UInt16
Description: Converts the current BigInt object to UInt16 type. The overflow policy can be customized.
Parameters:
- overflowHandling!: OverflowStrategy: overflow handling policy for conversion
- "throwing": exception mode If an overflow occurs, an exception is thrown.
- "wrapping": overflow mode If an overflow occurs, the most significant bits are truncated.
- "saturating": boundary value mode Returns the maximum value of the target type if the current value is greater than the maximum value of the target type, or returns the minimum value of the target type if the current value is less than the minimum value of the target type after an overflow occurs.
Returns:
Throws:
- OverflowException: If no overflow policy is specified or the overflow handling policy for conversion is
throwing, this exception is thrown.
Example:
import std.math.numeric.BigInt
import std.math.numeric.OverflowStrategy
main() {
let bigInt = BigInt("800000000000000000", base: 16)
let toUInt16 = bigInt.toUInt16(overflowHandling: wrapping)
println(toUInt16)
}
Running result:
0
func toUInt32(OverflowStrategy)
public func toUInt32(overflowHandling!: OverflowStrategy = throwing): UInt32
Description: Converts the current BigInt object to the UInt32 type. The overflow policy can be customized.
Parameters:
- overflowHandling!: OverflowStrategy: overflow handling policy for conversion
- "throwing": exception mode If an overflow occurs, an exception is thrown.
- "wrapping": overflow mode If an overflow occurs, the most significant bits are truncated.
- "saturating": boundary value mode Returns the maximum value of the target type if the current value is greater than the maximum value of the target type, or returns the minimum value of the target type if the current value is less than the minimum value of the target type after an overflow occurs.
Returns:
Throws:
- OverflowException: If no overflow policy is specified or the overflow handling policy for conversion is
throwing, this exception is thrown.
Example:
import std.math.numeric.BigInt
import std.math.numeric.OverflowStrategy
main() {
let bigInt = BigInt("800000000000000000", base: 16)
let toUInt32 = bigInt.toUInt32(overflowHandling: wrapping)
println(toUInt32)
}
Running result:
0
func toUInt64(OverflowStrategy)
public func toUInt64(overflowHandling!: OverflowStrategy = throwing): UInt64
Description: Converts the current BigInt object to the UInt64 type. The overflow policy can be customized.
Parameters:
- overflowHandling!: OverflowStrategy: overflow handling policy for conversion
- "throwing": exception mode If an overflow occurs, an exception is thrown.
- "wrapping": overflow mode If an overflow occurs, the most significant bits are truncated.
- "saturating": boundary value mode Returns the maximum value of the target type if the current value is greater than the maximum value of the target type, or returns the minimum value of the target type if the current value is less than the minimum value of the target type after an overflow occurs.
Returns:
Throws:
- OverflowException: If no overflow policy is specified or the overflow handling policy for conversion is
throwing, this exception is thrown.
Example:
import std.math.numeric.BigInt
import std.math.numeric.OverflowStrategy
main() {
let bigInt = BigInt("-800000000000000000", base: 16)
let toUInt64 = bigInt.toUInt64(overflowHandling: saturating)
println(toUInt64)
}
Running result:
0
func toUInt8(OverflowStrategy)
public func toUInt8(overflowHandling!: OverflowStrategy = throwing): UInt8
Description: Converts the current BigInt object to the UInt8 type. The overflow policy can be customized.
Parameters:
- overflowHandling!: OverflowStrategy: overflow handling policy for conversion
- "throwing": exception mode If an overflow occurs, an exception is thrown.
- "wrapping": overflow mode If an overflow occurs, the most significant bits are truncated.
- "saturating": boundary value mode Returns the maximum value of the target type if the current value is greater than the maximum value of the target type, or returns the minimum value of the target type if the current value is less than the minimum value of the target type after an overflow occurs.
Returns:
Throws:
- OverflowException: If no overflow policy is specified or the overflow handling policy for conversion is
throwing, this exception is thrown.
Example:
import std.math.numeric.BigInt
import std.math.numeric.OverflowStrategy
main() {
let bigInt = BigInt("800000000000000000", base: 16)
try {
bigInt.toUInt8(overflowHandling: throwing)
} catch (e: OverflowException) {
println(e.message)
}
return
}
Running result:
Out of range of the UInt8
func toUIntNative(OverflowStrategy)
public func toUIntNative(overflowHandling!: OverflowStrategy = throwing): UIntNative
Description: Converts the current BigInt object to the UIntNative type. The overflow policy can be customized.
Parameters:
- overflowHandling!: OverflowStrategy: overflow handling policy for conversion
- "throwing": exception mode If an overflow occurs, an exception is thrown.
- "wrapping": overflow mode If an overflow occurs, the most significant bits are truncated.
- "saturating": boundary value mode Returns the maximum value of the target type if the current value is greater than the maximum value of the target type, or returns the minimum value of the target type if the current value is less than the minimum value of the target type after an overflow occurs.
Returns:
- UIntNative: the value of UInt64 after conversion
Throws:
- OverflowException: If no overflow policy is specified or the overflow handling policy for conversion is
throwing, this exception is thrown.
Example:
import std.math.numeric.BigInt
import std.math.numeric.OverflowStrategy
main() {
let bigInt = BigInt("-800000000000000000", base: 16)
let toUIntNative = bigInt.toUIntNative(overflowHandling: saturating)
println(toUIntNative)
}
Running result:
0
operator func !()
public operator func !(): BigInt
Description: Performs the bitwise NOT operation. Changes the binary bit 0 in the operand to 1 and 1 to 0.
Returns:
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt("-1")
let no = !bigInt
println(no)
}
Running result:
0
operator func !=(BigInt)
public operator func !=(that: BigInt): Bool
Description: Performs an inequality check operation.
Parameters:
Returns:
- Bool: result of the inequality check operation If yes, true is returned. Otherwise, false is returned.
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt("-1")
let that = BigInt("-2")
println(bigInt != that)
}
Running result:
true
operator func %(BigInt)
public operator func %(that: BigInt): BigInt
Description: Performs a modulo operation on BigInt.
The behavior of the modulo operation is consistent with that of the basic type, that is, the sign is consistent with that of the dividend.
Parameters:
- that: BigInt: divisor The divisor cannot be 0.
Returns:
- BigInt: a new BigInt, which is the result of the modulo operation between the BigInt and the other BigInt
Throws:
- ArithmeticException: If the divisor is 0, this exception is thrown.
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt("-23456789123456789")
let that = BigInt("-23456789123456789")
let mod = bigInt % that
println(mod)
}
Running result:
0
operator func &(BigInt)
public operator func &(that: BigInt): BigInt
Description: Performs bitwise AND operation. The function is used to perform an AND operation on the binary digits corresponding to the two numbers involved in the operation. The result bit is 1 only when the two binary bits are both 1.
Parameters:
Returns:
- BigInt: the result of the bitwise AND operation
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt("8")
let that = BigInt("7")
let and = bigInt & that
println(and)
}
Running result:
0
operator func *(BigInt)
public operator func *(that: BigInt): BigInt
Description: Performs a multiplication operation on two BigInt variables.
Parameters:
- that: BigInt: multiplier.
Returns:
- BigInt: a new BigInt, which is the result of the multiplication operation on the two BigInt variables
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt("-1")
let that = BigInt("-23456789123456789")
let mul = bigInt * that
println(mul)
}
Running result:
23456789123456789
operator func **(UInt64)
public operator func **(n: UInt64): BigInt
Description: Obtains the value of BigInt raised to the power of n through calculation.
Parameters:
- n: UInt64: exponent
Returns:
- BigInt: result of the exponentiation operation
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt("-2")
let power = bigInt ** 64
println(power.toString(16))
}
Running result:
10000000000000000
operator func +(BigInt)
public operator func +(that: BigInt): BigInt
Description: Performs an addition operation on two BigInt variables.
Parameters:
- that: BigInt: addend
Returns:
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt("123456789123456789")
let that = BigInt("-23456789123456789")
let plus = bigInt + that
println(plus)
}
Running result:
100000000000000000
operator func -()
public operator func -(): BigInt
Description: Obtains the inverse number of BigInt.
Returns:
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt("-23456789123456789")
let opposite = -bigInt
println(opposite)
}
Running result:
23456789123456789
operator func -(BigInt)
public operator func -(that: BigInt): BigInt
Description: Performs a subtraction operation on two BigInt variables.
Parameters:
- that: BigInt: subtrahend
Returns:
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt("100000000000000000")
let that = BigInt("-23456789123456789")
let sub = bigInt - that
println(sub)
}
Running result:
123456789123456789
operator func <(BigInt)
public operator func <(that: BigInt): Bool
Purpose: Checks whether one BigInt variable is less than the other BigInt variable.
Parameters:
Returns:
- Bool: comparison result If yes, true is returned. Otherwise, false is returned.
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt("-1")
let that = BigInt("-2")
println(bigInt < that)
}
Running result:
false
operator func <<(Int64)
public operator func <<(n: Int64): BigInt
Description: Performs left shift operation.
Parameters:
- n: Int64: n bits to shift by leftwards. The value of n must be greater than or equal to 0.
Returns:
Throws:
- ArithmeticException: If the input parameter is less than 0, this exception is thrown.
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt("-1")
let leftShift = bigInt << 64
println(leftShift.toString(16))
}
Running result:
-10000000000000000
operator func <=(BigInt)
public operator func <=(that: BigInt): Bool
Purpose: Checks whether one BigInt variable is less than or equal to the other BigInt variable.
Parameters:
Returns:
- Bool: comparison result If yes, true is returned. Otherwise, false is returned.
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt("-1")
let that = BigInt("-2")
println(bigInt <= that)
}
Running result:
false
operator func ==(BigInt)
public operator func ==(that: BigInt): Bool
Description: Performs an equality check operation.
Parameters:
Returns:
- Bool: result of the equality check operation If yes, true is returned. Otherwise, false is returned.
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt("-1")
let that = BigInt("-2")
println(bigInt == that)
}
Running result:
false
operator func >(BigInt)
public operator func >(that: BigInt): Bool
Purpose: Checks whether one BigInt variable is greater than the other BigInt variable.
Parameters:
Returns:
- Bool: comparison result If yes, true is returned. Otherwise, false is returned.
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt("-1")
let that = BigInt("-2")
println(bigInt > that)
}
Running result:
true
operator func >=(BigInt)
public operator func >=(that: BigInt): Bool
Purpose: Checks whether one BigInt variable is greater than or equal to the other BigInt variable.
Parameters:
Returns:
- Bool: comparison result If yes, true is returned. Otherwise, false is returned.
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt("-1")
let that = BigInt("-2")
println(bigInt >= that)
}
Running result:
true
operator func >>(Int64)
public operator func >>(n: Int64): BigInt
Description: Performs right shift operation.
Parameters:
- n: Int64: n bits to shift by rightwards. The value of n must be greater than or equal to 0.
Returns:
Throws:
- ArithmeticException: If the input parameter is less than 0, this exception is thrown.
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt("-1")
let rightShift = bigInt >> 10000
println(rightShift)
}
Running result:
-1
operator func /(BigInt)
public operator func /(that: BigInt): BigInt
Description: Performs a division operation on two BigInt variables.
The behavior of the division operation is the same as that of the basic type, that is, the result is rounded close to 0.
Parameters:
- that: BigInt: divisor The divisor cannot be 0.
Returns:
Throws:
- ArithmeticException: If the divisor is 0, this exception is thrown.
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt("-23456789123456789")
let that = BigInt("-23456789123456789")
let div = bigInt / that
println(div)
}
Running result:
1
operator func ^(BigInt)
public operator func ^(that: BigInt): BigInt
Description: Performs bitwise XOR operation. The function is used to perform a bitwise XOR operation on the binary digits corresponding to the two numbers involved in the operation. If the binary bit results are different, the result is 1. If the binary bit results are the same, the result is 0.
Parameters:
Returns:
- BigInt: the result of the bitwise XOR operation
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt("-1")
let that = BigInt("7")
let xor = bigInt ^ that
println(xor)
}
Running result:
-8
operator func |(BigInt)
public operator func |(that: BigInt): BigInt
Description: Performs bitwise OR operation. The function is used to perform a bitwise OR operation on the binary digits corresponding to the two numbers involved in the operation. The result bit is 0 only when the two binary bits are both 0.
Parameters:
Returns:
- BigInt: the result of the bitwise OR operation
Example:
import std.math.numeric.BigInt
main() {
let bigInt = BigInt("8")
let that = BigInt("7")
let or = bigInt | that
println(or)
}
Running result:
15
struct Decimal
public struct Decimal <: Comparable<Decimal> & Hashable & ToString
Description: Decimal is used to represent signed decimal numbers of any precision. The result precision and rounding rule can be specified during operation. Conversions between basic types (such as Int, UInt, String, and Float) and the BigInt type are supported. Basic attributes of Decimal objects can be queried. Basic mathematical operations are supported. Basic capabilities such as object comparison, hashing, and string printing are provided.
Parent Type:
prop precision
public prop precision: Int64
Description: Obtains the precision of Decimal, that is, the number of significant decimal digits in the unscaled integer part. The value is not a negative number. If the precision is 0, precision is not limited.
Type: Int64
prop scale
public prop scale: Int32
Description: Obtains the scale value of Decimal.
Type: Int32
prop sign
public prop sign: Int64
Description: Obtains the sign value of a Decimal instance.
- If the Decimal value is greater than 0, 1 is returned.
- If the Decimal value is 0, 0 is returned.
- If the Decimal value is less than 0, -1 is returned.
Type: Int64
prop value
public prop value: BigInt
Description: Obtains the unscaled integer value of Decimal, represented in BigInt format.
Type: BigInt
init(BigInt)
public init(val: BigInt)
Description: Constructs a Deciaml struct by using a signed BigInt. By default, the precision is 0, indicating infinite precision.
Parameters:
- val: BigInt: signed BigInit value
init(BigInt, Int32)
public init(val: BigInt, scale: Int32)
Description: Constructs a Deciaml struct by using a signed BigInt and a scale value. By default, the precision is 0, indicating infinite precision.
Parameters:
init(Float16)
public init(val: Float16)
Description: Constructs a Decimal object by using a 16-bit signed floating-point number. By default, the precision is 0, indicating infinite precision.
Note:
Some decimal fractions cannot be precisely represented by binary floating-point numbers. This constructor uses precise values to construct a Decimal object. The input floating-point number may be different from the printed string of the constructed Decimal object.
Parameters:
- val: Float16: 16-bit signed binary floating-point number
Throws:
- IllegalArgumentException: If the input parameter is
inf,-inf, ornan, this exception is thrown.
init(Float32)
public init(val: Float32)
Description: Constructs a Decimal object by using a 32-bit signed floating-point number. By default, the precision is 0, indicating infinite precision.
Note:
Some decimal fractions cannot be precisely represented by binary floating-point numbers. This constructor uses precise values to construct a Decimal object. The input floating-point number may be different from the printed string of the constructed Decimal object.
Parameters:
- val: Float32: 32-bit signed binary floating-point number
Throws:
- IllegalArgumentException: If the input parameter is
inf,-inf, ornan, this exception is thrown.
init(Float64)
public init(val: Float64)
Description: Constructs a Decimal object by using a 64-bit signed floating-point number. By default, the precision is 0, indicating infinite precision.
Note:
Some decimal fractions cannot be precisely represented by binary floating-point numbers. This constructor uses precise values to construct a Decimal object. The input floating-point number may be different from the printed string of the constructed Decimal object.
Parameters:
- val: Float64: 64-bit signed binary floating-point number
Throws:
- IllegalArgumentException: If the input parameter is
inf,-inf, ornan, this exception is thrown.
init(Int16)
public init(val: Int16)
Description: Constructs a Decimal struct by using a 16-bit signed integer. By default, the precision is 0, indicating infinite precision.
Parameters:
- val: Int16: 16-bit signed integer
init(Int32)
public init(val: Int32)
Description: Constructs a Decimal object by using a 32-bit signed integer. By default, the precision is 0, indicating infinite precision.
Parameters:
- val: Int32: 32-bit signed integer
init(Int64)
public init(val: Int64)
Description: Constructs a Decimal object by using a 64-bit signed integer. By default, the precision is 0, indicating infinite precision.
Parameters:
- val: Int64: 64-bit signed integer
init(Int8)
public init(val: Int8)
Description: Constructs a Decimal struct by using an 8-bit signed integer. By default, the precision is 0, indicating infinite precision.
Parameters:
- val: Int8: 8-bit signed integer
init(IntNative)
public init(val: IntNative)
Description: Constructs a Decimal object by using a 32-bit or 64-bit signed integer (the length is platform-dependent). By default, the precision is 0, indicating infinite precision.
Parameters:
- val: IntNative: 32-bit or 64-bit signed integer
init(String)
public init(val: String)
Description: Constructs a Decimal struct by using a string in the specified format. By default, the precision is 0, indicating infinite precision. The string must begin with an optional sign (positive or negative), followed by ValueString and then optional ExponentString.
Decimal string: (SignString)? ValueString (ExponentString)?
-
SignString: + | -
-
ValueString: IntegerPart.(FractionPart)? | .FractionPart | IntegerPart
-
IntegerPart: Digits
-
FractionPart: Digits
-
Digits: Digit | Digit Digits
- Digit: 0 to 9
-
-
ExponentString: ExponentIndicator (SignString)? IntegerPart
- ExponentIndicator: e | E
Parameters:
- val: String: string in the specified format
Throws:
- IllegalArgumentException: If the input string is not in the specified format, this exception is thrown.
- OverflowException: If the scale value overflows, this exception is thrown.
init(UInt16)
public init(val: UInt16)
Description: Constructs a Decimal object by using a 16-bit unsigned integer. By default, the precision is 0, indicating infinite precision.
Parameters:
- val: UInt16: 16-bit unsigned integer
init(UInt32)
public init(val: UInt32)
Description: Constructs a Decimal object by using a 32-bit unsigned integer. By default, the precision is 0, indicating infinite precision.
Parameters:
- val: UInt32: 32-bit unsigned integer
init(UInt64)
public init(val: UInt64)
Description: Constructs a Decimal object by using a 64-bit unsigned integer. By default, the precision is 0, indicating infinite precision.
Parameters:
- val: UInt64: 64-bit unsigned integer
init(UInt8)
public init(val: UInt8)
Description: Constructs a Decimal object by using an 8-bit unsigned integer. By default, the precision is 0, indicating infinite precision.
Parameters:
- val: UInt8: 8-bit unsigned integer
init(UIntNative)
public init(val: UIntNative)
Description: Constructs a Decimal object by using a 32-bit or 64-bit unsigned integer (the length is platform-dependent). By default, the precision is 0, indicating infinite precision.
Parameters:
- val: UIntNative: 32-bit or 64-bit unsigned integer
func compare(Decimal)
public func compare(d: Decimal): Ordering
Description: Compares the current object with an input Decimal object and returns the comparison result.
Parameters:
Returns:
- Ordering: comparison result. If the current object is less than the input parameter, Ordering.LT is returned. If the current object is greater than the input parameter, Ordering.GT is returned. Otherwise, Ordering.EQ is returned.
Example:
import std.math.numeric.Decimal
main(): Unit {
let A = Decimal(-5)
let B = Decimal(3)
let C = A.compare(B)
println(C)
}
Running result:
Ordering.LT
func divWithPrecision(Decimal, Int64, RoundingMode)
public func divWithPrecision(d: Decimal, precision: Int64, roundingMode!: RoundingMode = HALF_EVEN): Decimal
Description: Performs a division operation, with an input Decimal object as the divisor, and returns a result. The operation precision and rounding mode can be customized. If the precision of the result exceeds the precision specified by precision, the operation result is rounded based on the specified precision.
Parameters:
- d: Decimal: Decimal object as the divisor
- precision: Int64: precision
- roundingMode!: RoundingMode: rounding rule
Returns:
Throws:
- ArithmeticException: If the divisor is 0, this exception is thrown.
- OverflowException: If the result of division is not within the range of [-(maxValue(precision) * (10Int32.MAX)), maxValue(precision) * (10Int32.MAX)], this exception is thrown.
Example:
import std.math.numeric.Decimal
main(): Unit {
let A = Decimal(2)
let B = Decimal(3)
let C = A.divWithPrecision(B, 0)
println("C = ${C}")
}
Running result:
C = 0.6666666666666666666666666666666667
func divAndRem(Decimal)
public func divAndRem(d: Decimal): (BigInt, Decimal)
Description: Performs a division operation, with the Decimal object as the divisor, and returns an integer quotient and a remainder. The actual precision is retained in the result.
Parameters:
Returns:
Throws:
- IllegalArgumentException: If the divisor is less than 0, this exception is thrown.
- OverflowException: If the result of division is not within the range of [-(maxValue(precision) * (10Int32.MAX)), maxValue(precision) * (10Int32.MAX)], this exception is thrown.
func hashCode()
public func hashCode(): Int64
Description: Obtains the hash value of the current object.
Returns:
- Int64: hash value of the current object
func isInteger()
public func isInteger(): Bool
Description: Checks whether the current Decimal object is an integer.
Returns:
- Bool: whether the current object is an integer. If the current object is an integer, true is returned; otherwise, false is returned.
Example:
import std.math.numeric.Decimal
main(): Unit {
let A = Decimal(100)
println("${A}.isInteger() = ${A.isInteger()}")
}
Running result:
100.isInteger() = true
func powWithPrecision(Int64, Int64, RoundingMode)
public func powWithPrecision(n: Int64, precision: Int64, roundingMode!: RoundingMode = RoundingMode.HALF_EVEN): Decimal
Description: Performs an exponentiation operation, with the current object as the base and an input Int64 as the exponent. The operation precision and rounding mode can be customized. If the precision of the result exceeds the precision specified by precision, the operation result is rounded based on the specified precision.
Parameters:
- n: Int64: exponent of the exponentiation operation
- precision: Int64: precision
- roundingMode!: RoundingMode: rounding rule
Returns:
Throws:
- OverflowException: If the scale value of the result overflows, this exception is thrown.
Example:
import std.math.numeric.Decimal
main(): Unit {
let A = Decimal(2.5)
println("A.powWithPrecision(3, 0) = ${A.powWithPrecision(3, 0, roundingMode: HALF_EVEN)}")
}
Running result:
A.powWithPrecision(3, 0) = 15.625
func reScale(Int32, RoundingMode)
public func reScale(newScale: Int32, roundingMode!: RoundingMode = HALF_EVEN): Decimal
Description: Adjusts the scale value of a Decimal object, and returns a new Decimal object. The rounding rule can be specified.
Parameters:
- newScale: Int32: new scale value
- roundingMode!: RoundingMode: rounding rule
Returns:
Example:
import std.math.numeric.Decimal
main(): Unit {
let A = Decimal(1.234568)
println("A.reScale(3) = ${A.reScale(3)}")
}
Running result:
A.reScale(3) = 1.235
func removeTrailingZeros()
public func removeTrailingZeros(): Decimal
Description: Removes trailing zeros of the current Decimal object without changing the value of the object.
Returns:
Example:
import std.math.numeric.Decimal
main(): Unit {
let A = Decimal(1.00)
println("A.removeTrailingZeros() = ${A.removeTrailingZeros()}")
}
Running result:
A.removeTrailingZeros() = 1
func roundWithPrecision(Int64, RoundingMode)
public func roundWithPrecision(precision: Int64, roundingMode!: RoundingMode = RoundingMode.HALF_EVEN): Decimal
Description: Rounds the current Decimal object based on the specified rounding precision and rounding rules.
Parameters:
- precision: Int64: precision
- roundingMode!: RoundingMode: rounding rule
Returns:
Throws:
- OverflowException: If the scale value of the rounding result overflows, this exception is thrown.
Example:
import std.math.numeric.Decimal
main(): Unit {
let A = Decimal(1.0)
println("A.roundWithPrecision(1.0) = ${A.roundWithPrecision(0, roundingMode: HALF_EVEN)}")
let B = Decimal(0.1f16).roundWithPrecision(5, roundingMode: UP)
println("B = ${B}")
}
Running result:
A.roundWithPrecision(1.0) = 1
B = 0.099976
func scaleUnit()
public func scaleUnit(): Decimal
Description: Returns a scale unit for the current Decimal object. That is, a Decimal object with the same scale value (1) as the current object is returned.
Returns:
Example:
import std.math.numeric.Decimal
main(): Unit {
let A = Decimal(100)
println("A.scaleUnit() = ${A.scaleUnit()}")
}
Running result:
A.scaleUnit() = 1
func shiftPoint(Int32)
public func shiftPoint(n: Int32): Decimal
Description: Moves the decimal point of the current Decimal object by abs(n) places and returns a resulting object. If n is a positive number, the decimal point is moved to the left. If n is a negative number, the decimal point is moved to the right. If n is 0, the current object is returned.
Parameters:
- n: Int32: number of decimal places to move and moving direction
Returns:
- Decimal: new Decimal object generated after the decimal point of the current object is moved by specified places
Example:
import std.math.numeric.Decimal
main(): Unit {
let A = Decimal(25)
println("A.shiftPoint(1) = ${A.shiftPoint(1)}")
}
Running result:
A.shiftPoint(-1) = 2.5
func sqrtWithPrecision(Int64, RoundingMode)
public func sqrtWithPrecision(precision: Int64, roundingMode!: RoundingMode = RoundingMode.HALF_EVEN): Decimal
Description: Performs a rooting operation to obtain the square root of the current object. The operation precision and rounding mode can be customized. If the precision of the result exceeds the precision specified by presision, the operation result is rounded based on the specified precision.
Parameters:
- precision: Int64: precision
- roundingMode!: RoundingMode: rounding rule
Returns:
- Decimal- arithmetic square root of the input Decimal number. The value is rounded based on the input precision and rounding mode.
Throws:
- IllegalArgumentException: If the object whose square root is calculated is a negative number, this exception is thrown.
- OverflowException: If the scale value of the result overflows, this exception is thrown.
Example:
import std.math.numeric.*
main() {
let n: Decimal = Decimal("2")
let s = n.sqrtWithPrecision(2)
println(s)
}
Running result:
1.4
func toBigInt()
public func toBigInt(): BigInt
Description: Converts the current Decimal object to the BigInt type.
Returns:
func toEngString()
public func toEngString(): String
Description: Prints the value of a Decimal object to the exponent of 3 in engineering notation. If the value is less than 0, the object begins with a minus sign (−) followed by a decimal number. If the value is greater than or equal to 0, the number is directly printed without adding a plus sign (+). If the exponent is less than 0, the preceding rules also apply.
Returns:
func toSciString()
public func toSciString(): String
Description: Prints a Decimal object in scientific notation. If the value is less than 0, the object begins with a minus sign (−) followed by a decimal number. If the value is greater than or equal to 0, the number is directly printed without adding a plus sign (+). If the exponent is less than 0, the preceding rules also apply.
Returns:
Example:
import std.math.numeric.Decimal
main(): Unit {
let A = Decimal(6.25)
println("A.toFloat16() = ${A.toFloat16()}")
println("A.toFloat32() = ${A.toFloat32()}")
println("A.toFloat64() = ${A.toFloat64()}")
println("A.toBigInt() = ${A.toBigInt()}")
println("A.toEngString() = ${A.toEngString()}")
println("A.toSciString() = ${A.toSciString()}")
}
Running result:
A.toFloat16() = 6.250000
A.toFloat32() = 6.250000
A.toFloat64() = 6.250000
A.toBigInt() = 6
A.toEngString() = 6.25E0
A.toSciString() = 6.25E0
func toFloat16()
public func toFloat16(): Float16
Description: Converts the current Decimal object to the Float16 type.
Returns:
- Float16: Float16 value obtained after conversion. If an overflow occurs,
infis returned for a positive number, and-infis returned for a negative number.
func toFloat32()
public func toFloat32(): Float32
Description: Converts the current Decimal object to the Float32 type.
Returns:
- Float32: Float32 value obtained after conversion. If an overflow occurs,
infis returned for a positive number, and-infis returned for a negative number.
func toFloat64()
public func toFloat64(): Float64
Description: Converts the current Decimal object to the Float64 type.
Returns:
- Float64: Float64 value obtained after conversion. If an overflow occurs,
infis returned for a positive number, and-infis returned for a negative number.
func toInt16(OverflowStrategy)
public func toInt16(overflowHandling!: OverflowStrategy = throwing): Int16
Description: Converts the current Decimal object to the Int16 type. The overflow policy can be specified.
Input parameters:
- overflowHanding!: OverflowStrategy: overflow policy for conversion
Returns:
Throws:
- OverflowException: If the overflow policy is not specified or the overflow policy is
throwing, this exception is thrown.
func toInt32(OverflowStrategy)
public func toInt32(overflowHandling!: OverflowStrategy = throwing): Int32
Description: Converts the current Decimal object to the Int32 type. The overflow policy can be specified.
Input parameters:
- overflowHanding!: OverflowStrategy: overflow policy for conversion
Returns:
Throws:
- OverflowException: If the overflow policy is not specified or the overflow policy is
throwing, this exception is thrown.
func toInt64(OverflowStrategy)
public func toInt64(overflowHandling!: OverflowStrategy = throwing): Int64
Description: Converts the current Decimal object to the Int64 type. The overflow policy can be specified.
Input parameters:
- overflowHanding!: OverflowStrategy: overflow policy for conversion
Returns:
Throws:
- OverflowException: If the overflow policy is not specified or the overflow policy is
throwing, this exception is thrown.
func toInt8(OverflowStrategy)
public func toInt8(overflowHandling!: OverflowStrategy = throwing): Int8
Description: Converts the current Decimal object to the Int8 type. The overflow policy can be specified.
Input parameters:
- overflowHanding!: OverflowStrategy: overflow policy for conversion
Returns:
Throws:
- OverflowException: If the overflow policy is not specified or the overflow policy is
throwing, this exception is thrown.
func toIntNative(OverflowStrategy)
public func toIntNative(overflowHandling!: OverflowStrategy = throwing): IntNative
Description: Converts the current Decimal object to the IntNative type. The overflow policy can be specified.
Input parameters:
- overflowHanding!: OverflowStrategy: overflow policy for conversion
Returns:
Throws:
- OverflowException: If the overflow policy is not specified or the overflow policy is
throwing, this exception is thrown.
Example:
import std.math.numeric.Decimal
main(): Unit {
let A = Decimal(6.25)
println("A.toInt8() = ${A.toInt8()}")
println("A.toInt16() = ${A.toInt16()}")
println("A.toInt32() = ${A.toInt32()}")
println("A.toInt64() = ${A.toInt64()}")
println("A.toIntNative() = ${A.toIntNative()}")
}
Running result:
A.toInt8() = 6
A.toInt16() = 6
A.toInt32() = 6
A.toInt64() = 6
A.toIntNative() = 6
func toString()
public func toString(): String
Description: Prints a Decimal object in non-exponential notation. If the value is less than 0, the object begins with a minus sign (−) followed by a decimal number. If the value is greater than or equal to 0, the number is directly printed without adding a plus sign (+).
Returns:
Example:
import std.math.numeric.Decimal
main(): Unit {
let A = Decimal(-5)
let B = Decimal(3 ** 5)
println("A.hashCode() = ${A.hashCode()}")
println("B.toString() = ${B.toString()}")
}
Running result:
A.hashCode() = 155
B.toString() = 243
func toUInt16(OverflowStrategy)
public func toUInt16(overflowHandling!: OverflowStrategy = throwing): UInt16
Description: Converts the current Decimal object to the UInt16 type. The overflow policy can be specified.
Input parameters:
- overflowHanding!: OverflowStrategy: overflow policy for conversion
Returns:
Throws:
- OverflowException: If the overflow policy is not specified or the overflow policy is
throwing, this exception is thrown.
func toUInt32(OverflowStrategy)
public func toUInt32(overflowHandling!: OverflowStrategy = throwing): UInt32
Description: Converts the current Decimal object to the UInt32 type. The overflow policy can be specified.
Input parameters:
- overflowHanding!: OverflowStrategy: overflow policy for conversion
Returns:
Throws:
- OverflowException: If the overflow policy is not specified or the overflow policy is
throwing, this exception is thrown.
func toUInt64(OverflowStrategy)
public func toUInt64(overflowHandling!: OverflowStrategy = throwing): UInt64
Description: Converts the current Decimal object to the UInt64 type. The overflow policy can be specified.
Input parameters:
- overflowHanding!: OverflowStrategy: overflow policy for conversion
Returns:
Throws:
- OverflowException: If the overflow policy is not specified or the overflow policy is
throwing, this exception is thrown.
func toUInt8(OverflowStrategy)
public func toUInt8(overflowHandling!: OverflowStrategy = throwing): UInt8
Description: Converts the current Decimal object to the UInt8 type. The overflow policy can be specified.
Input parameters:
- overflowHanding!: OverflowStrategy: overflow policy for conversion
Returns:
Throws:
- OverflowException: If the overflow policy is not specified or the overflow policy is
throwing, this exception is thrown.
func toUIntNative(OverflowStrategy)
public func toUIntNative(overflowHandling!: OverflowStrategy = throwing): UIntNative
Description: Converts the current Decimal object to the UIntNative type. The overflow policy can be specified.
Input parameters:
- overflowHandling!: OverflowStrategy: overflow policy for conversion
Returns:
- UIntNative: UIntNative value obtained after conversion
Throws:
- OverflowException: If the overflow policy is not specified or the overflow policy is
throwing, this exception is thrown.
Example:
import std.math.numeric.Decimal
main(): Unit {
let A = Decimal(6.25)
println("A.toUInt8() = ${A.toUInt8()}")
println("A.toUInt16() = ${A.toUInt16()}")
println("A.toUInt32() = ${A.toUInt32()}")
println("A.toUInt64() = ${A.toUInt64()}")
println("A.toUIntNative() = ${A.toUIntNative()}")
}
Running result:
A.toUInt8() = 6
A.toUInt16() = 6
A.toUInt32() = 6
A.toUInt64() = 6
A.toUIntNative() = 6
operator func !=(Decimal)
public operator func !=(d: Decimal): Bool
Description: Checks whether an input Decimal object is not equal to the current object, and returns the comparison result. This function is used for inequality comparison operation and inequality operator overloading.
Parameters:
Returns:
- Bool: result of the inequality comparison operation If the current object is not equal to the input parameter, true is returned; otherwise, false is returned.
Example:
import std.math.numeric.Decimal
main(): Unit {
let A = Decimal(-5)
let B = Decimal(3)
println(" -A = ${-A}")
println(" A <= B = ${ A <= B}")
println(" A != B = ${ A != B}")
}
Running result:
-A = 5
A <= B = true
A != B = true
operator func *(Decimal)
public operator func *(d: Decimal): Decimal
Description: Multiplies an input Decimal object and returns the result. This function is used for multiplication operation and multiplication operator overloading. The actual precision of the multiplication result is retained.
Parameters:
Returns:
Throws:
- OverflowException: If an overflow occurs when scale values of the two multipliers are added, this exception is thrown.
Example:
import std.math.numeric.Decimal
main(): Unit {
let A = Decimal(2)
let B = Decimal(3)
let C = A * B
println("C = ${C}")
}
Running result:
C = 6
operator func **(Int64)
public operator func **(n: Int64): Decimal
Description: Obtains the result of an exponentiation operation, with the current object as the base and an input Int64 as the exponent, in which the exponent is the integer part of the input Decimal object. This function is used for exponentiation operation and exponentiation operator overloading.
Note:
If the exponent is a negative value and the result is an infinite decimal, IEEE 754-2019 decimal128 is used to round the result by default.
Parameters:
- n: Int64: exponent of the exponentiation operation
Returns:
Throws:
- OverflowException: If the scale value of the result overflows, this exception is thrown.
Example:
import std.math.numeric.Decimal
main(): Unit {
let A = Decimal(2.5)
println("A ** 3 = ${A ** 3}")
}
Running result:
A ** 3 = 15.625
operator func +(Decimal)
public operator func +(d: Decimal): Decimal
Description: Adds an input Decimal object and returns the result. This function is used for addition operation and addition operator overloading. The actual precision is retained in the result.
Parameters:
Throws:
- OverflowException: If an overflow occurs when the scale value of one addend is subtracted by that of the other addend, this exception is thrown.
Example:
import std.math.numeric.Decimal
main(): Unit {
let A = Decimal(2)
let B = Decimal(3)
let C = A + B
println("C = ${C}")
}
Running result:
C = 5
operator func -()
public operator func -(): Decimal
Description: Negates the current Decimal object and returns the result. This function is used for negation operation and unary negation operator overloading. The actual precision of the negation result is retained.
Returns:
operator func -(Decimal)
public operator func -(d: Decimal): Decimal
Description: Subtracts an input Decimal object and returns the result. This function is used for subtraction operation and subtraction operator overloading. The actual precision of the subtraction result is retained.
Parameters:
Returns:
Throws:
- OverflowException: If an overflow occurs when the scale value of the minuend is subtracted by that of the subtrahend, this exception is thrown.
Example:
import std.math.numeric.Decimal
main(): Unit {
let A = Decimal(2)
let B = Decimal(3)
let C = A - B
println("C = ${C}")
}
Running result:
C = -1
operator func <(Decimal)
public operator func <(d: Decimal): Bool
Description: Checks whether an input Decimal object is less than the current object, and returns the comparison result. This function is used for less-than comparison and less-than operator overloading.
Parameters:
Returns:
- Bool: result of the less-than comparison operation If the current object is less than the input parameter, true is returned; otherwise, false is returned.
operator func <=(Decimal)
public operator func <=(d: Decimal): Bool
Description: Checks whether an input Decimal object is less than or equal to the current object, and returns the comparison result. This function is used for less-than or equal comparison and less-than or equal operator overloading.
Parameters:
Returns:
- Bool: result of the less-than or equal comparison operation If the current object is less than or equal to the input parameter, true is returned; otherwise, false is returned.
operator func ==(Decimal)
public operator func ==(d: Decimal): Bool
Description: Checks whether an input Decimal object is equal to the current object, and returns the comparison result. This function is used for equality comparison operation and equality operator overloading.
Parameters:
Returns:
- Bool: result of the equality comparison operation If the current object is equal to the input parameter, true is returned; otherwise, false is returned.
operator func >(Decimal)
public operator func >(d: Decimal): Bool
Description: Checks whether an input Decimal object is greater than the current object, and returns the comparison result. This function is used for greater-than comparison and greater-than operator overloading.
Parameters:
Returns:
- Bool: result of the greater-than comparison operation If the current object is greater than the input parameter, true is returned; otherwise, false is returned
operator func >=(Decimal)
public operator func >=(d: Decimal): Bool
Description: Checks whether an input Decimal object is greater than or equal to the current object, and returns the comparison result. This function is used for greater-than or equal comparison and greater-than or equal operator overloading.
Parameters:
Returns:
- Bool: result of the greater-than or equal comparison operation If the current object is greater than or equal to the input parameter, true is returned; otherwise, false is returned.
operator func /(Decimal)
public operator func /(d: Decimal): Decimal
Description: Divides an object by an input Decimal object and returns the result. This function is used for division operation and division operator overloading.
Note:
If the result is an infinite decimal, IEEE 754-2019 decimal128 is used to round the result by default.
Parameters:
Returns:
Throws:
- IllegalArgumentException: If the divisor is less than 0, this exception is thrown.
- OverflowException: If the result of division is not within the range of [-(maxValue(precision) * (10Int32.MAX)), maxValue(precision) * (10Int32.MAX)], this exception is thrown.
Example:
import std.math.numeric.Decimal
main(): Unit {
let A = Decimal(2)
let B = Decimal(3)
let C = A / B
println("C = ${C}")
}
Running result:
C = 0.6666666666666666666666666666666667
Example of Basic Mathematical Operations of BigInt
The following is an example of initializing the BigInt object by using different constructors and performing basic mathematical operations:
import std.math.numeric.*
main() {
let int1: BigInt = BigInt("123456789")
let int2: BigInt = BigInt("987654321")
println("${int1} + ${int2} = ${int1 + int2}")
println("${int1} - ${int2} = ${int1 - int2}")
println("${int1} * ${int2} = ${int1 * int2}")
println("${int1} / ${int2} = ${int1 / int2}")
let (quo, mod) = int1.divAndMod(int2)
println("${int1} / ${int2} = ${quo} .. ${mod}")
return 0
}
Running result:
123456789 + 987654321 = 1111111110
123456789 - 987654321 = -864197532
123456789 * 987654321 = 121932631112635269
123456789 / 987654321 = 0
123456789 / 987654321 = 0 .. 123456789
Example of Basic Attributes of BigInt
The following is an example of initializing the BigInt object and querying the basic attributes of the object:
import std.math.numeric.*
main() {
let int = BigInt("-123456")
println("BigInt: ${int}")
println("BigInt sign: ${int.sign}")
println("BigInt bitLen: ${int.bitLen}")
return 0
}
Running result:
BigInt: -123456
BigInt sign: -1
BigInt bitLen: 18
Example of Size Comparison of BigInt
The following is an example of initializing multiple BigInt objects and comparing their sizes:
import std.math.numeric.*
main() {
let int1 = BigInt("123456789")
let int2 = BigInt("987654321")
println("${int1} > ${int2} = ${int1 > int2}")
println("${int1} < ${int2} = ${int1 < int2}")
println("${int1} == ${int2} = ${int1 == int2}")
println("${int1} != ${int2} = ${int1 != int2}")
println("${int1} <= ${int2} = ${int1 <= int2}")
println("${int1} >= ${int2} = ${int1 >= int2}")
println("${int1}.compare(${int2}) = ${int1.compare(int2)}")
return 0
}
Running result:
123456789 > 987654321 = false
123456789 < 987654321 = true
123456789 == 987654321 = false
123456789 != 987654321 = true
123456789 <= 987654321 = true
123456789 >= 987654321 = false
123456789.compare(987654321) = Ordering.LT
Example of Basic Mathematical Operations of Decimal
The following is an example of initializing the Decimal object by using different constructors and performing basic mathematical operations:
import std.math.*
import std.math.numeric.*
main() {
let decimal1: Decimal = Decimal("12345.6789")
let decimal2: Decimal = Decimal(BigInt("987654321"), 6)
println("${decimal1} + ${decimal2} = ${decimal1 + decimal2}")
println("${decimal1} - ${decimal2} = ${decimal1 - decimal2}")
println("${decimal1} * ${decimal2} = ${decimal1 * decimal2}")
println("${decimal1} / ${decimal2} = ${decimal1 / decimal2}")
println("${decimal1} / ${decimal2} with precision 10 and rounding mode HALF_EVEN = ${decimal1.divWithPrecision(decimal2, 10, roundingMode: HALF_EVEN)}")
let (quo, rem) = decimal1.divAndRem(decimal2)
println("${decimal1} / ${decimal2} = ${quo} .. ${rem}")
return 0
}
Running result:
12345.6789 + 987.654321 = 13333.333221
12345.6789 - 987.654321 = 11358.024579
12345.6789 * 987.654321 = 12193263.1112635269
12345.6789 / 987.654321 = 12.49999988609375000142382812498220
12345.6789 / 987.654321 with precision 10 and rounding mode HALF_EVEN = 12.49999989
12345.6789 / 987.654321 = 12 .. 493.827048
Example of Basic Attributes of Decimal
The following is an example of initializing the Decimal object and querying the basic attributes of the object:
import std.math.*
import std.math.numeric.*
main() {
let decimalProperties = Decimal("-123456.7890123456789")
println("decimal: ${decimalProperties}")
println("decimal sign: ${decimalProperties.sign}")
println("decimal scale: ${decimalProperties.scale}")
println("decimal value: ${decimalProperties.value}")
println("decimal precision: ${decimalProperties.precision}")
// To initialize a Decimail object for which the precision and rounding mode are specified, the following method can be used:
let decimalProperties2 = Decimal("-123456.7890123456789").roundWithPrecision(10, roundingMode: HALF_EVEN)
println("decimal2: ${decimalProperties2}")
println("decimal2 sign: ${decimalProperties2.sign}")
println("decimal2 scale: ${decimalProperties2.scale}")
println("decimal2 value: ${decimalProperties2.value}")
println("decimal2 precision: ${decimalProperties2.precision}")
return 0
}
Running result:
decimal: -123456.7890123456789
decimal sign: -1
decimal scale: 13
decimal value: -1234567890123456789
decimal precision: 19
decimal2: -123456.7890
decimal2 sign: -1
decimal2 scale: 4
decimal2 value: -1234567890
decimal2 precision: 10
Example of Size Comparison of Decimal
The following is an example of initializing multiple Decimal objects and comparing their sizes:
import std.math.*
import std.math.numeric.*
main() {
let decimal1 = Decimal("12345.6789")
let decimal2 = Decimal("987.654321")
println("${decimal1} > ${decimal2} = ${decimal1 > decimal2}")
println("${decimal1} < ${decimal2} = ${decimal1 < decimal2}")
println("${decimal1} == ${decimal2} = ${decimal1 == decimal2}")
println("${decimal1} != ${decimal2} = ${decimal1 != decimal2}")
println("${decimal1} <= ${decimal2} = ${decimal1 <= decimal2}")
println("${decimal1} >= ${decimal2} = ${decimal1 >= decimal2}")
println("${decimal1}.compare(${decimal2}) = ${decimal1.compare(decimal2)}")
return 0
}
Running result:
12345.6789 > 987.654321 = true
12345.6789 < 987.654321 = false
12345.6789 == 987.654321 = false
12345.6789 != 987.654321 = true
12345.6789 <= 987.654321 = false
12345.6789 >= 987.654321 = true
12345.6789.compare(987.654321) = Ordering.GT
std.objectpool Package
Function Description
The objectpool package provides functions for object cache and reuse.
In object-oriented languages, the application and release of objects are complex and time-consuming, which may become the performance bottleneck of applications. The application and release of Cangjie objects also face the same problem. The object pool improves program performance through caching and reusing objects to reduce object application and release.
This package ObjectPool class is used to cache and reuse objects of a specified type. The put method can be called to put used objects into the object pool cache, and the get method can be called to obtain the objects to be used from the object pool cache.
In addition, to reduce contention and further improve object access efficiency, ObjectPool object access is performed in different arrays based on a current Cangjie thread id.
Note:
1. During
ObjectPoolimplementation, access is performed based on a Cangjie threadid. As a result, when an object is obtained and stored by different Cangjie threads, it is difficult to obtain a stored object. Therefore, the object pool should be used in scenarios in which an object is obtained and stored by the same Cangjie thread.2. Automatic capacity reduction is not supported.
API List
Class
| Name | Description |
|---|---|
| ObjectPool | Provides a concurrent-secure object cache type, which can store objects that have been allocated memory but are not in use. |
Class
class ObjectPool<T> where T <: Object
public class ObjectPool<T> where T <: Object
Description: Provides a concurrent-secure object cache type, which can store objects that have been allocated memory but are not in use.
Notes:
- When an object is not needed, it can be stored in ObjectPool, and when the object is needed, it can be obtained from ObjectPool.
- Objects stored in ObjectPool must be of the same type.
- Before the lifecycle of an ObjectPool object ends, objects stored in the ObjectPool object are not released.
Example:
import std.objectpool.*
class City {
var id: Int64 = 0
var name: String = ""
}
func resetCity(c: City): City {
let city = c
city.id = 0
city.name = ""
return city
}
main() {
let cityPool = ObjectPool({ => City()}, resetFunc: resetCity)
let cityA = cityPool.get()
cityA.id = 30
cityA.name = "A"
println("id: ${cityA.id}, name: ${cityA.name}")
cityPool.put(cityA)
}
Running result:
id: 30, name: A
init(() -> T, Option<(T) -> T>)
public init(newFunc: () -> T, resetFunc!: Option<(T) -> T> = None)
Description: Creates a new ObjectPool object.
Parameters:
- newFunc: () ->T: When the get method is called, if the method fails to obtain an object from ObjectPool, the newFn function is called to create a new object. The newFunc function must ensure concurrency security.
- resetFunc!: Option<(T) ->T>: When the get method is called, the resetFunc function is called to reset the object status. If resetFunc is None, the object status is not reset. The resetFunc must ensure concurrency security.
func get()
public func get(): T
Description: Attempts to obtain an object from ObjectPool. If obtaining an object from ObjectPool fails, the newFunc is called to create a new object and return it. If an object obtained using the get method is no longer needed, it should be returned to ObjectPool using the put method.
Returns:
- T: object obtained from ObjectPool or created by calling newFunc
func put(T)
public func put(item: T): Unit
Description: Attempts to place an object into ObjectPool but does not guarantee that the object is added to ObjectPool. After put is called on an object, no further operations should be performed on the object, as it may lead to unexpected issues.
Parameters:
- item: T: object to be put into ObjectPool
std.os Package
Function Description
The OS package provides capabilities such as obtaining or operating on information about the current process (such as process parameters, environment variables, and directory information), registering callback functions, and exiting the current process.
Currently, the OS package is supported on the Linux, macOS, Windows, and HarmonyOS platforms.
API List
Function
| Name | Description | Supported on |
|---|---|---|
| currentDir() | Obtains the current working directory. | Linux, Windows, macOS, and HarmonyOS |
| envVars() | Obtains all environment variables. | Linux, Windows, macOS, and HarmonyOS |
| getArgs() | Obtains the command line parameter list, for example, running a.out ab cd ef in the command line, where a.out is the program name. The returned list contains three elements: ab, cd, and ef. | Linux, Windows, macOS, and HarmonyOS |
| getEnv(String) | Obtains the value of a specified environment variable. | Linux, Windows, macOS, and HarmonyOS |
| homeDir() | Obtains the home directory. | Linux, Windows, and macOS |
| processorCount() | Obtains the number of processors. | Linux, Windows, macOS, and HarmonyOS |
| removeEnv(String) | Removes an environment variable by specifying its name. | Linux, Windows, macOS, and HarmonyOS |
| setEnv(String, String) | Sets a pair of environment variables. | Linux, Windows, macOS, and HarmonyOS |
| tempDir() | Obtains the temporary directory. | Linux, Windows, macOS, and HarmonyOS |
Function
func currentDir()
public func currentDir(): Directory
Description: Obtains the current working directory.
Notes:
Returns:
- Directory: current working directory
func envVars()
public func envVars(): HashMap<String, String>
Description: Obtains all environment variables.
Notes:
- The return value is HashMap, which stores environment variables in the form of
keyandvalue.
Returns:
func getArgs()
public func getArgs(): Array<String>
Description: Obtains the command line parameter list, for example, running a.out ab cd ef in the command line, where a.out is the program name. The returned list contains three elements: ab, cd, and ef.
Notes:
- When the C language is used to call the Cangjie dynamic library, the first parameter set by int SetCJCommandLineArgs(int argc, const char* argv[]) is discarded when getArgs() is used to obtain the command line parameters.
Returns:
func getEnv(String)
public func getEnv(k: String): Option<String>
Description: Obtains the value of a specified environment variable.
Parameters:
- k: String: environment variable name
Returns:
Throws:
- IllegalArgumentException: When the function parameter
kcontains null characters, this exception is thrown.
func homeDir()
public func homeDir(): Directory
Description: Obtains the home directory.
Notes:
Returns:
- Directory:
homedirectory
func processorCount()
public func processorCount(): Int64
Description: Obtains the number of processors.
Returns:
- Int64: number of processors
func removeEnv(String)
public func removeEnv(k: String): Unit
Description: Removes an environment variable by specifying its name.
Parameters:
- k: String: environment variable name
Throws:
- IllegalArgumentException: When the function parameter
kcontains null characters, this exception is thrown.
func setEnv(String, String)
public func setEnv(k: String, v: String): Unit
Description: Sets a pair of environment variables. If an environment variable with the same name is set, the original environment variable value is overwritten.
Parameters:
Throws:
- IllegalArgumentException: When the function parameter
korvcontains null characters, this exception is thrown.
func tempDir()
public func tempDir(): Directory
Description: Obtains the temporary directory. Obtains the TMPDIR, TMP, TEMP, and TEMPDIR environment variables from the environment variables. If the preceding values do not exist in the environment variables, the directory /tmp is returned to by default.
Notes:
Returns:
- Directory: temporary directory
std.os.posix Package
Function Description
The os.posix package is used to adapt to POSIX APIs.
This package provides unified control capabilities for multiple platforms, including Linux, macOS, Windows, and HarmonyOS.
API List
Functions
| Name | Description | Supported on |
|---|---|---|
| open(String, Int32) | Opens a file and returns a new file descriptor, or returns -1 when the operation fails. | Linux, Windows, macOS, and HarmonyOS |
| open(String, Int32, UInt32) | Opens a file and returns a new file descriptor, or returns -1 when the operation fails. | Linux, Windows, macOS, and HarmonyOS |
| access(String, Int32) | Checks whether a file has certain permission. If yes, 0 is returned; otherwise, -1 is returned. | Linux, Windows, macOS, and HarmonyOS |
| chdir(String) | Changes the current working directory of the calling process by specifying a path. | Linux, Windows, macOS, and HarmonyOS |
| chmod(String, UInt32) | Modifies the file access permission. | Linux, Windows, macOS, and HarmonyOS |
| chown(String, UInt32, UInt32) | Modifies the file owner and the group to which the file owner belongs. | Linux, macOS, and HarmonyOS |
| close(Int32) | Closes a file. close causes data to be written back to the disk and resources occupied by the file to be released. | Linux, Windows, macOS, and HarmonyOS |
| creat(String, UInt32) | Creates a file and returns a file descriptor, or returns -1 when the operation fails. | Linux, Windows, macOS, and HarmonyOS |
| dup(Int32) | Copies and returns the file descriptor specified by the original fd parameter. | Linux, Windows, macOS, and HarmonyOS |
| dup2(Int32, Int32) | Copies the file descriptor specified by oldfd and returns it to the newfd parameter. | Linux, Windows, macOS, and HarmonyOS |
| faccessat(Int32, String, Int32, Int32) | Checks whether the file specified by fd has certain permission. If yes, 0 is returned; otherwise, -1 is returned. | Linux, macOS, and HarmonyOS |
| fchdir(Int32) | Changes the current working directory of the calling process by specifying the descriptor of a file path. | Linux, macOS, and HarmonyOS |
| fchmod(Int32, UInt32) | Modifies the file access permission corresponding to the file descriptor. | Linux, Windows, macOS, and HarmonyOS |
| fchmodat(Int32, String, UInt32, Int32) | Modifies the file access permission corresponding to the file descriptor. | Linux, Windows, macOS, and HarmonyOS |
| fchown(Int32, UInt32, UInt32) | Modifies the file owner corresponding to fd and the group to which the file owner belongs. | Linux, macOS, and HarmonyOS |
| fchownat(Int32, String, UInt32, UInt32, Int32) | Modifies the file owner corresponding to the file descriptor and the group to which the file owner belongs. | Linux, macOS, and HarmonyOS |
| getcwd() | Obtains the absolute path of the working directory of the current process. | Linux, Windows, macOS, and HarmonyOS |
| getgid() | Obtains the user group ID. | Linux, macOS, and HarmonyOS |
| getgroups(Int32, CPointer<UInt32>) | Obtains the code of the group to which the current user belongs. | Linux, macOS, and HarmonyOS |
| gethostname() | Obtains the host name, which is usually the name of a host on the TCP/IP network. | Linux, macOS, and HarmonyOS |
| getlogin() | Obtains the current login name. | Linux, macOS, and HarmonyOS |
| getos() | Obtains the Linux system information from the file in /proc/version. | Linux |
| getpgid(Int32) | Obtains PGID of the process specified by pid. If pid is 0, ID of the calling process is returned. | Linux, macOS, and HarmonyOS |
| getpgrp() | Obtains ID of the parent process of the calling process. | Linux, macOS, and HarmonyOS |
| getpid() | Obtains ID(PID) of the calling process. | Linux, Windows, macOS, and HarmonyOS |
| getppid() | Obtains ID of the parent process of the calling process. | Linux, macOS, and HarmonyOS |
| getuid() | Obtains the real user ID of the calling process. | Linux, macOS, and HarmonyOS |
| isBlk(String) | Checks whether the input object is a block device and returns a Boolean value. | Linux, Windows, macOS, and HarmonyOS |
| isChr(String) | Checks whether the input object is a character device and returns a Boolean value. | Linux, Windows, macOS, and HarmonyOS |
| isDir(String) | Checks whether the input object is a folder and returns a Boolean value. | Linux, Windows, macOS, and HarmonyOS |
| isFIFO(String) | Checks whether the input object is a FIFO file and returns a Boolean value. | Linux, macOS, and HarmonyOS |
| isLnk(String) | Checks whether the input object is a soft link and returns a Boolean value. | Linux, macOS, and HarmonyOS |
| isReg(String) | Checks whether the input object is a regular file and returns a Boolean value. | Linux, Windows, macOS, and HarmonyOS |
| isSock(String) | Checks whether the input object is a socket file and returns a Boolean value. | Linux, macOS, and HarmonyOS |
| isType(String, UInt32) | Checks whether a file is in the specified mode. | Linux, macOS, and HarmonyOS |
| isatty(Int32) | Tests whether the file descriptor references the terminal. If the test is successful, true is returned; otherwise, false is returned. | Linux, Windows, macOS, and HarmonyOS |
| kill(Int32, Int32) | Sends any signal to any process group or process. | Linux, macOS, and HarmonyOS |
| killpg(Int32, Int32) | Sends sig to the process group pgrp. If pgrp is 0, killpg() sends the signal to the process group to which the calling process belongs. | Linux, macOS, and HarmonyOS |
| lchown(String, UInt32, UInt32) | Modifies the file link owner and the group to which the owner belongs. | Linux and macOS |
| link(String, String) | Creates a link for an existing file. A file can have multiple directory entries pointing to i-node. | Linux, macOS, and HarmonyOS |
| linkat(Int32, String, Int32, String, Int32) | Creates a file link relative to the directory file descriptor. | Linux, macOS, and HarmonyOS |
| lseek(Int32, Int64, Int32) | Increases the read or write location accordingly in file reading or writing. | Linux, Windows, macOS, and HarmonyOS |
| nice(Int32) | Changes the priority of the current thread. | Linux, macOS, and HarmonyOS |
| open64(String, Int32) | Opens a file and returns a new file descriptor, or returns -1 when the operation fails. | Linux and HarmonyOS |
| open64(String, Int32, UInt32) | Opens a file and returns a new file descriptor, or returns -1 when the operation fails. | Linux and HarmonyOS |
| openat(Int32, String, Int32) | Opens a file and returns a new file descriptor, or returns -1 when the operation fails. | Linux, macOS, and HarmonyOS |
| openat(Int32, String, Int32, UInt32) | Opens a file and returns a new file descriptor, or returns -1 when the operation fails. | Linux, macOS, and HarmonyOS |
| openat64(Int32, String, Int32) | Opens a file and returns a new file descriptor, or returns -1 when the operation fails. | Linux, macOS, and HarmonyOS |
| openat64(Int32, String, Int32, UInt32) | Opens a file and returns a new file descriptor, or returns -1 when the operation fails. | Linux, macOS, and HarmonyOS |
| pread(Int32, CPointer<UInt8>, UIntNative, Int32) | Transfers nbyte of the file specified by fd to the memory specified by buffer. | Linux, macOS, and HarmonyOS |
| pwrite(Int32, CPointer<UInt8>, UIntNative, Int32) | Writes nbyte in the memory specified by buffer to the file specified by fd, starting from the specified offset location. | Linux, macOS, and HarmonyOS |
| read(Int32, CPointer<UInt8>, UIntNative) | Transfers nbyte of the file specified by fd to the memory specified by buffer. | Linux, Windows, macOS, and HarmonyOS |
| remove(String) | Deletes a file or directory. | Linux, Windows, macOS, and HarmonyOS |
| rename(String, String) | Renames a file. If necessary, the directory where the file is located is moved. | Linux, Windows, macOS, and HarmonyOS |
| renameat(Int32, String, Int32, String) | Renames a file. If necessary, the directory where the file is located is moved. | Linux, macOS, and HarmonyOS |
| setgid(UInt32) | Sets the valid group ID of the calling process. Permissions are required to run this function. | Linux and macOS |
| sethostname(String) | Sets the host name. Only the super user can call this function. | Linux and macOS |
| setpgid(Int32, Int32) | Sets the group ID specified by pid to the group ID specified by pgrp. | Linux, macOS, and HarmonyOS |
| setpgrp() | Sets ID of the group to which the current process belongs to ID of the process of the current process. This function is equivalent to calling setpgid(0, 0). | Linux, macOS, and HarmonyOS |
| setuid(UInt32) | Sets the valid user ID of the calling process. Permissions are required to run this function. | Linux and macOS |
| symlink(String, String) | Creates a link named symPath to the file specified by path. | Linux, macOS, and HarmonyOS |
| symlinkat(String, Int32, String) | Creates a link named symPath to the file specified by path and fd. | Linux, macOS, and HarmonyOS |
| ttyname(Int32) | Returns the terminal name. | Linux, Windows, macOS, and HarmonyOS |
| umask(UInt32) | Sets the permission mask. | Linux, Windows, macOS, and HarmonyOS |
| unlink(String) | Deletes a file from the file system. | Linux, macOS, and HarmonyOS |
| unlinkat(Int32, String, Int32) | Deletes a file from the file system. | Linux, macOS, and HarmonyOS |
| write(Int32, CPointer<UInt8>, UIntNative) | Writes nbyte in the memory specified by buffer to the file specified by fd. | Linux, Windows, macOS, and HarmonyOS |
Constants
| Name | Description | Supported on |
|---|---|---|
| AT_EMPTY_PATH | Specifies the file descriptor returned when no file or directory is specified in the file system. This constant is applicable to the open, open64, openat, and openat64 functions, and belongs to the function parameter oflag. | Linux, Windows, and HarmonyOS |
| AT_REMOVEDIR | Performs an operation equivalent to rmdir(2) on pathname if the AT_REMOVEDIR flag is specified. This constant is applicable to the open, open64, openat, and openat64 functions and belongs to the function parameter oflag. | Linux, Windows, macOS, and HarmonyOS |
| O_CLOEXEC | Mandatory in some multi-thread programs. This is because when one thread opens the file descriptor and another thread executes fork(2) followed by execve(2), using a separate fcntl(2) F_SETFD operation to set the FD_CLOEXEC flag is not enough to prevent contention. This constant is applicable to the open, open64, openat, and openat64 functions and belongs to the function parameter oflag. | Linux, macOS, and HarmonyOS |
| O_DIRECTORY | If the file specified by pathname is not a directory, the file fails to be opened. This constant is applicable to the open, open64, openat, and openat64 functions and belongs to the function parameter oflag. | Linux, macOS, and HarmonyOS |
| O_CREAT | If the file to be opened does not exist, automatically creates the file. This constant is applicable to the open, open64, openat, and openat64 functions and belongs to the function parameter oflag. | Linux, Windows, macOS, and HarmonyOS |
| O_DSYNC | Waits for the physical I/O to complete upon each write operation. However, if the write operation does not affect reading of the data just written, it is unnecessary to wait for the file attribute to update. This constant is applicable to the open, open64, openat, and openat64 functions and belongs to the function parameter oflag. | Linux, macOS, and HarmonyOS |
| O_EXCL | If O_CREAT is also set, checks whether the file exists; if the file does not exist, creates the file. Otherwise, a file opening error is displayed. In addition, if both O_CREAT and O_EXCL are set and the file to be opened is a symbolic link, the file fails to be opened. This constant is applicable to the open, open64, openat, and openat64 functions and belongs to the function parameter oflag. | Linux, Windows, macOS, and HarmonyOS |
| O_NOCTTY | If the file to be opened is a terminal device, the file is not the control terminal of the process. This constant is applicable to the open, open64, openat, and openat64 functions and belongs to the function parameter oflag. | Linux, macOS, and HarmonyOS |
| O_NOFOLLOW | If the file specified by pathname is a single symbolic link, the file fails to be opened. This constant is applicable to the open, open64, openat, and openat64 functions and belongs to the function parameter oflag. | Linux, macOS, and HarmonyOS |
| O_NONBLOCK | Opens a file in non-blocking mode. That is, the I/O operation does not cause the calling process to wait. This constant is applicable to the open, open64, openat, and openat64 functions and belongs to the function parameter oflag. | Linux, macOS, and HarmonyOS |
| O_SYNC | Opens a file synchronously. This constant is applicable to the open, open64, openat, and openat64 functions and belongs to the function parameter oflag. | Linux, macOS, and HarmonyOS |
| O_RDONLY | Opens a file in read-only mode. This constant is applicable to the open, open64, openat, and openat64 functions and belongs to the function parameter oflag. | Linux, Windows, macOS, and HarmonyOS |
| O_RDWR | Opens a file in read/write mode. This constant is applicable to the open, open64, openat, and openat64 functions and belongs to the function parameter oflag. | Linux, Windows, macOS, and HarmonyOS |
| O_WRONLY | Opens a file in write-only mode. This constant is applicable to the open, open64, openat, and openat64 functions, and belongs to the function parameter oflag. | Linux, Windows, macOS, and HarmonyOS |
| O_APPEND | Moves data from the end of a file in file reading or writing, that is, appends the data to be written to the end of the file. This constant is applicable to the open, open64, openat, and openat64 functions, and belongs to the function parameter oflag. | Linux, Windows, macOS, and HarmonyOS |
| O_RSYNC | This flag affects only the read operation and needs to be used together with O_SYNC or O_DSYNC. If necessary, this flag blocks the read call until the data being read (and possibly metadata) is flushed to the disk. This constant is applicable to the open, open64, openat, and openat64 functions and belongs to the function parameter oflag. | Linux and HarmonyOS |
| O_TRUNC | If the file exists and is writable, clears the file length to 0, making the data previously stored in the file disappear. This constant is applicable to the open, open64, openat, and openat64 functions, and belongs to the function parameter oflag. | Linux, Windows, macOS, and HarmonyOS |
| R_OK | Tests the read permission on a file. This constant is applicable to the access and faccessat functions and belongs to the function parameter mode. | Linux, Windows, macOS, and HarmonyOS |
| W_OK | Tests the write permission on a file. This constant is applicable to the access and faccessat functions and belongs to the function parameter mode. | Linux, Windows, macOS, and HarmonyOS |
| X_OK | Tests the execute permission on a file. This constant is applicable to the access and faccessat functions and belongs to the function parameter mode. | Linux, Windows, macOS, and HarmonyOS |
| F_OK | Tests whether a file exists. This constant is applicable to the access and faccessat functions and belongs to the function parameter mode. | Linux, Windows, macOS, and HarmonyOS |
| SEEK_SET | Specifies the new read/write location. This constant is applicable to the lseek function and belongs to the function parameter whence. | Linux, Windows, macOS, and HarmonyOS |
| SEEK_CUR | Adds an offset to the current read or write location. This constant is applicable to the lseek function and belongs to the function parameter whence. | Linux, Windows, macOS, and HarmonyOS |
| SEEK_END | Sets the read/write location to the end of the file and adds an offset. This constant is applicable to the lseek function and belongs to the function parameter whence. | Linux, Windows, macOS, and HarmonyOS |
| SIGABRT | Specifies an abnormal abortion. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig. | Linux, Windows, macOS, and HarmonyOS |
| SIGBUS | Specifies a hardware fault. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig. | Linux, Windows, macOS, and HarmonyOS |
| SIGFPE | Specifies an arithmetic error. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig. | Linux, Windows, macOS, and HarmonyOS |
| SIGKILL | Specifies a kill signal. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig. | Linux, Windows, macOS, and HarmonyOS |
| SIGCONT | Continues a stopped process. The default action is continue or ignore. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig. | Linux, Windows, macOS, and HarmonyOS |
| SIGHUP | Specifies that the connection is broken. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig. | Linux, Windows, macOS, and HarmonyOS |
| SIGINT | Specifies a terminal interrupt character. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig. | Linux, Windows, macOS, and HarmonyOS |
| SIGQUIT | Specifies a terminal quit character. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig. | Linux, Windows, macOS, and HarmonyOS |
| SIGILL | Specifies that the hardware instruction is invalid. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig. | Linux, Windows, macOS, and HarmonyOS |
| SIGTRAP | Specifies a hardware fault. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig. | Linux, Windows, macOS, and HarmonyOS |
| SIGIOT | Specifies a hardware fault. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig. | Linux, Windows, macOS, and HarmonyOS |
| SIGIO | Specifies an asynchronous IO. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig. | Linux, Windows, macOS, and HarmonyOS |
| SIGPIPE | Writes data to the pipe of an unread process. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig. | Linux, Windows, macOS, and HarmonyOS |
| SIGALRM | Specifies that the timer expires. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig. | Linux, Windows, macOS, and HarmonyOS |
| SIGPWR | Specifies power failure or restart. The system call is invalid. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig. | Linux, Windows, and HarmonyOS |
| SIGSEGV | Specifies invalid memory reference. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig. | Linux, Windows, macOS, and HarmonyOS |
| SIGSTOP | Specifies a stop signal. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig. | Linux, Windows, macOS, and HarmonyOS |
| SIGTERM | Specifies a terminate signal. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig. | Linux, Windows, macOS, and HarmonyOS |
| SIGSTKFLT | Specifies a coprocessor stack fault. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig. | Linux, Windows, and HarmonyOS |
| SIGCHLD | Specifies that the subprocess status is changed. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig. | Linux, Windows, macOS, and HarmonyOS |
| SIGTSTP | Specifies a terminal stop signal. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig. | Linux, Windows, macOS, and HarmonyOS |
| SIGTTIN | Reads the control tty on the background. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig. | Linux, Windows, macOS, and HarmonyOS |
| SIGTTOU | Writes the control tty on the background. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig. | Linux, Windows, macOS, and HarmonyOS |
| SIGURG | Specifies an emergency (socket). The default action is ignore. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig. | Linux, Windows, macOS, and HarmonyOS |
| SIGUSR1 | Specifies a user-defined signal. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig. | Linux, Windows, macOS, and HarmonyOS |
| SIGUSR2 | Specifies a user-defined signal. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig. | Linux, Windows, macOS, and HarmonyOS |
| SIGVTALRM | Specifies a virtual time alarm. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig. | Linux, Windows, macOS, and HarmonyOS |
| SIGPROF | Specifies digest timeout. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig. | Linux, Windows, macOS, and HarmonyOS |
| SIGWINCH | Changes the terminal window size. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig. | Linux, Windows, macOS, and HarmonyOS |
| SIGXCPU | Specifies that CPU usage exceeds the upper limit. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig. | Linux, Windows, macOS, and HarmonyOS |
| SIGXFSZ | Specifies that the file length exceeds the upper limit. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig. | Linux, Windows, macOS, and HarmonyOS |
| S_IRUSR | Specifies that the file owner has read permission on the file. This constant is applicable to the open, open64, openat, openat64, chmod(mode), fchmod(mode), fchmodat(mode), and creat functions, and belongs to the function parameter flag. | Linux, Windows, macOS, and HarmonyOS |
| S_IWUSR | Specifies that the file owner has write permission on the file. This constant is applicable to the open, open64, openat, openat64, chmod(mode), fchmod(mode), fchmodat(mode), and creat functions, and belongs to the function parameter flag. | Linux, Windows, macOS, and HarmonyOS |
| S_IRGRP | Specifies that the file user group has read permission on the file. This constant is applicable to the open, open64, openat, openat64, chmod(mode), fchmod(mode), fchmodat(mode), and creat functions, and belongs to the function parameter flag. | Linux, Windows, macOS, and HarmonyOS |
| S_IWGRP | Specifies that the file user group has write permission on the file. This constant is applicable to the open, open64, openat, openat64, chmod(mode), fchmod(mode), fchmodat(mode), and creat functions, and belongs to the function parameter flag. | Linux, Windows, macOS, and HarmonyOS |
| S_IFREG | Specifies that the file type is regular. This constant is applicable to the isType function and belongs to the function parameter mode. | Linux, Windows, macOS, and HarmonyOS |
| S_IFBLK | Specifies that the file type is block device. This constant is applicable to the isType function and belongs to the function parameter mode. | Linux, Windows, macOS, and HarmonyOS |
| S_IFDIR | Specifies that the file type is directory. This constant is applicable to the isType function and belongs to the function parameter mode. | Linux, Windows, macOS, and HarmonyOS |
| S_IFCHR | Specifies that the file type is character device. This constant is applicable to the isType function and belongs to the function parameter mode. | Linux, Windows, macOS, and HarmonyOS |
| S_IFIFO | Specifies that the file type is FIFO. This constant is applicable to the isType function and belongs to the function parameter mode. | Linux, Windows, macOS, and HarmonyOS |
| S_IFLNK | Specifies that the file type is soft link. This constant is applicable to the isType function and belongs to the function parameter mode. | Linux, Windows, macOS, and HarmonyOS |
| S_IFSOCK | Specifies that the file type is socket. This constant is applicable to the isType function and belongs to the function parameter mode. | Linux, Windows, macOS, and HarmonyOS |
| S_IROTH | Specifies that other users have read permission on the file. This constant is applicable to the open, open64, openat, openat64, chmod(mode), fchmod(mode), fchmodat(mode), and creat functions, and belongs to the function parameter flag. | Linux, Windows, macOS, and HarmonyOS |
| S_IRWXG | Specifies that the file user group has read, write, and execute permissions on the file. This constant is applicable to the open, open64, openat, openat64, chmod(mode), fchmod(mode), fchmodat(mode), and creat functions, and belongs to the function parameter flag. | Linux, Windows, macOS, and HarmonyOS |
| S_IRWXU | Specifies that the file owner has read, write, and execute permissions on the file. This constant is applicable to the open, open64, openat, openat64, chmod(mode), fchmod(mode), fchmodat(mode), and creat functions, and belongs to the function parameter flag. | Linux, Windows, macOS, and HarmonyOS |
| S_IWOTH | Specifies that other users have write permission on the file. This constant is applicable to the open, open64, openat, openat64, chmod(mode), fchmod(mode), fchmodat(mode), and creat functions, and belongs to the function parameter flag. | Linux, Windows, macOS, and HarmonyOS |
| S_IXOTH | Specifies that other users have execute permission on the file. This constant is applicable to the open, open64, openat, openat64, chmod(mode), fchmod(mode), fchmodat(mode), and creat functions, and belongs to the function parameter flag. | Linux, Windows, macOS, and HarmonyOS |
| S_IRWXO | Specifies that other users have read, write, and execute permissions on the file. This constant is applicable to the open, open64, openat, openat64, chmod(mode), fchmod(mode), fchmodat(mode), and creat functions, and belongs to the function parameter flag. | Linux, Windows, macOS, and HarmonyOS |
| S_IXGRP | Specifies that the file user group has execute permission on the file. This constant is applicable to the open, open64, openat, openat64, chmod(mode), fchmod(mode), fchmodat(mode), and creat functions, and belongs to the function parameter flag. | Linux, Windows, macOS, and HarmonyOS |
| S_IXUSR | Specifies that the file owner has execute permission on the file. This constant is applicable to the open, open64, openat, openat64, chmod(mode), fchmod(mode), fchmodat(mode), and creat functions, and belongs to the function parameter flag. | Linux, Windows, macOS, and HarmonyOS |
Constants and Variables
const AT_EMPTY_PATH
public const AT_EMPTY_PATH: Int32
Description: Specifies the file descriptor returned when no file or directory is specified in the file system. This constant is applicable to the open, open64, openat, and openat64 functions and belongs to the function parameter oflag.
Type: Int32
const AT_REMOVEDIR
public const AT_REMOVEDIR: Int32
Description: Performs an operation equivalent to rmdir(2) on pathname if the AT_REMOVEDIR flag is specified. This constant is applicable to the open, open64, openat, and openat64 functions and belongs to the function parameter oflag.
Type: Int32
const F_OK
public const F_OK: Int32
Description: Tests whether a file exists. This constant is applicable to the access and faccessat functions and belongs to the function parameter mode.
Type: Int32
const O_APPEND
public const O_APPEND: Int32
Description: Moves data from the end of a file in file reading or writing. that is, appends the data to be written to the end of the file. This constant is applicable to the open, open64, openat, and openat64 functions and belongs to the function parameter oflag.
Type: Int32
const O_CLOEXEC
public const O_CLOEXEC: Int32
Description: Mandatory in some multi-thread programs. This is because when one thread opens the file descriptor and another thread executes fork(2) followed by execve(2), using a separate fcntl(2) F_SETFD operation to set the FD_CLOEXEC flag is not enough to prevent contention. This constant is applicable to the open, open64, openat, and openat64 functions and belongs to the function parameter oflag.
Type: Int32
const O_CREAT
public const O_CREAT: Int32
Description: If the file to be opened does not exist, automatically creates the file. This constant is applicable to the open, open64, openat, and openat64 functions and belongs to the function parameter oflag.
Type: Int32
const O_DIRECTORY
public const O_DIRECTORY: Int32
Description: If the file specified by pathname is not a directory, the file fails to be opened. This constant is applicable to the open, open64, openat, and openat64 functions and belongs to the function parameter oflag.
Type: Int32
const O_DSYNC
public const O_DSYNC: Int32
Description: Waits for the physical I/O to complete upon each write operation. However, if the write operation does not affect reading of the data just written, it is unnecessary to wait for the file attribute to update. This constant is applicable to the open, open64, openat, and openat64 functions and belongs to the function parameter oflag.
Type: Int32
const O_EXCL
public const O_EXCL: Int32
Description: If O_CREAT is also set, checks whether the file exists; if the file does not exist, creates the file. Otherwise, a file opening error is displayed. In addition, if both O_CREAT and O_EXCL are set and the file to be opened is a symbolic link, the file fails to be opened. This constant is applicable to the open, open64, openat, and openat64 functions and belongs to the function parameter oflag.
Type: Int32
const O_NOCTTY
public const O_NOCTTY: Int32
Description: If the file to be opened is a terminal device, the file is not the control terminal of the process. This constant is applicable to the open, open64, openat, and openat64 functions and belongs to the function parameter oflag.
Type: Int32
const O_NOFOLLOW
public const O_NOFOLLOW: Int32
Description: If the file specified by pathname is a single symbolic link, the file fails to be opened. This constant is applicable to the open, open64, openat, and openat64 functions and belongs to the function parameter oflag.
Type: Int32
const O_NONBLOCK
public const O_NONBLOCK: Int32
Description: Opens a file in non-blocking mode. That is, the I/O operation does not cause the calling process to wait. This constant is applicable to the open, open64, openat, and openat64 functions and belongs to the function parameter oflag.
Type: Int32
const O_RDONLY
public const O_RDONLY: Int32
Description: Opens a file in read-only mode. This constant is applicable to the open, open64, openat, and openat64 functions and belongs to the function parameter oflag.
Type: Int32
const O_RDWR
public const O_RDWR: Int32
Description: Opens a file in read/write mode. This constant is applicable to the open, open64, openat, and openat64 functions and belongs to the function parameter oflag.
Type: Int32
const O_RSYNC
public const O_RSYNC: Int32
Description: This flag affects only the read operation and needs to be used together with O_SYNC or O_DSYNC. If necessary, this flag blocks the read call until the data being read (and possibly metadata) is flushed to the disk. This constant is applicable to the open, open64, openat, and openat64 functions and belongs to the function parameter oflag.
Type: Int32
const O_SYNC
public const O_SYNC: Int32
Description: Opens a file synchronously. This constant is applicable to the open, open64, openat, and openat64 functions and belongs to the function parameter oflag.
Type: Int32
const O_TRUNC
public const O_TRUNC: Int32
Description: If the file exists and is writable, clears the file length to 0, making data previously stored in the file disappear. This constant is applicable to the open, open64, openat, and openat64 functions and belongs to the function parameter oflag.
Type: Int32
const O_WRONLY
public const O_WRONLY: Int32
Description: Opens a file in write-only mode. This constant is applicable to the open, open64, openat, and openat64 functions and belongs to the function parameter oflag.
Type: Int32
const R_OK
public const R_OK: Int32
Description: Tests the read permission on a file. This constant is applicable to the access and faccessat functions and belongs to the function parameter mode.
Type: Int32
const SEEK_CUR
public const SEEK_CUR: Int32
Description: Adds an offset to the current read or write location. This constant is applicable to the lseek function and belongs to the function parameter whence.
Type: Int32
const SEEK_END
public const SEEK_END: Int32
Description: Sets the read/write location to the end of the file and adds an offset. This constant is applicable to the lseek function and belongs to the function parameter whence.
Type: Int32
const SEEK_SET
public const SEEK_SET: Int32
Description: Specifies the new read/write location. This constant is applicable to the lseek function and belongs to the function parameter whence.
Type: Int32
const SIGABRT
public const SIGABRT: Int32
Description: Specifies an abnormal abortion. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig.
Type: Int32
const SIGALRM
public const SIGALRM: Int32
Description: Specifies that the timer expires. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig.
Type: Int32
const SIGBUS
public const SIGBUS: Int32
Description: Specifies a hardware fault. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig.
Type: Int32
const SIGCHLD
public const SIGCHLD: Int32
Description: Specifies that the subprocess status is changed. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig.
Type: Int32
const SIGCONT
public const SIGCONT: Int32
Description: Continues a stopped process. The default action is continue or ignore. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig.
Type: Int32
const SIGFPE
public const SIGFPE: Int32
Description: Specifies an arithmetic error. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig.
Type: Int32
const SIGHUP
public const SIGHUP: Int32
Description: Specifies that the connection is broken. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig.
Type: Int32
const SIGILL
public const SIGILL: Int32
Description: Specifies that the hardware instruction is invalid. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig.
Type: Int32
const SIGINT
public const SIGINT: Int32
Description: Specifies a terminal interrupt character. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig.
Type: Int32
const SIGIO
public const SIGIO: Int32
Description: Specifies an asynchronous IO. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig.
Type: Int32
const SIGIOT
public const SIGIOT: Int32
Description: Specifies a hardware fault. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig.
Type: Int32
const SIGKILL
public const SIGKILL: Int32
Description: Specifies a kill signal. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig.
Type: Int32
const SIGPIPE
public const SIGPIPE: Int32
Description: Writes data to the pipe of an unread process. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig.
Type: Int32
const SIGPROF
public const SIGPROF: Int32
Description: Specifies digest timeout. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig.
Type: Int32
const SIGPWR
public const SIGPWR: Int32
Description: Specifies power failure or restart. The system call is invalid. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig.
Type: Int32
const SIGQUIT
public const SIGQUIT: Int32
Description: Specifies a terminal quit character. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig.
Type: Int32
const SIGSEGV
public const SIGSEGV: Int32
Description: Specifies invalid memory reference. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig.
Type: Int32
const SIGSTKFLT
public const SIGSTKFLT: Int32
Description: Specifies a coprocessor stack fault. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig.
Type: Int32
const SIGSTOP
public const SIGSTOP: Int32
Description: Specifies a stop signal. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig.
Type: Int32
const SIGTERM
public const SIGTERM: Int32
Description: Specifies a terminate signal. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig.
Type: Int32
const SIGTRAP
public const SIGTRAP: Int32
Description: Specifies a hardware fault. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig.
Type: Int32
const SIGTSTP
public const SIGTSTP: Int32
Description: Specifies a terminal stop signal. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig.
Type: Int32
const SIGTTIN
public const SIGTTIN: Int32
Description: Reads the control tty on the background. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig.
Type: Int32
const SIGTTOU
public const SIGTTOU: Int32
Description: Writes the control tty on the background. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig.
Type: Int32
const SIGURG
public const SIGURG: Int32
Description: Specifies an emergency (socket). The default action is ignore. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig.
Type: Int32
const SIGUSR1
public const SIGUSR1: Int32
Description: Specifies a user-defined signal. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig.
Type: Int32
const SIGUSR2
public const SIGUSR2: Int32
Description: Specifies a user-defined signal. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig.
Type: Int32
const SIGVTALRM
public const SIGVTALRM: Int32
Description: Specifies a virtual time alarm. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig.
Type: Int32
const SIGWINCH
public const SIGWINCH: Int32
Description: Changes the terminal window size. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig.
Type: Int32
const SIGXCPU
public const SIGXCPU: Int32
Description: Specifies that CPU usage exceeds the upper limit. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig.
Type: Int32
const SIGXFSZ
public const SIGXFSZ: Int32
Description: Specifies that the file length exceeds the upper limit. The default action is terminate. This constant is applicable to the kill and killpg functions and belongs to the function parameter sig.
Type: Int32
const S_IFBLK
public const S_IFBLK: UInt32
Description: Specifies that the file type is block device. This constant is applicable to the isType function and belongs to the function parameter mode.
Type: UInt32
const S_IFCHR
public const S_IFCHR: UInt32
Description: Specifies that the file type is character device. This constant is applicable to the isType function and belongs to the function parameter mode.
Type: UInt32
const S_IFDIR
public const S_IFDIR: UInt32
Description: Specifies that the file type is directory. This constant is applicable to the isType function and belongs to the function parameter mode.
Type: UInt32
const S_IFIFO
public const S_IFIFO: UInt32
Description: Specifies that the file type is FIFO. This constant is applicable to the isType function and belongs to the function parameter mode.
Type: UInt32
const S_IFLNK
public const S_IFLNK: UInt32
Description: Specifies that the file type is soft link. This constant is applicable to the isType function and belongs to the function parameter mode.
Type: UInt32
const S_IFREG
public const S_IFREG: UInt32
Description: Specifies that the file type is regular. This constant is applicable to the isType function and belongs to the function parameter mode.
Type: UInt32
const S_IFSOCK
public const S_IFSOCK: UInt32
Description: Specifies that the file type is socket. This constant is applicable to the isType function and belongs to the function parameter mode.
Type: UInt32
const S_IRGRP
public const S_IRGRP: UInt32
Description: Specifies that the file user group has read permission on the file. This constant is applicable to the open, open64, openat, openat64, chmod(mode), fchmod(mode), fchmodat(mode), and creat functions and belongs to the function parameter flag.
Type: UInt32
const S_IROTH
public const S_IROTH: UInt32
Description: Specifies that other users have read permission on the file. This constant is applicable to the open, open64, openat, openat64, chmod(mode), fchmod(mode), fchmodat(mode), and creat functions and belongs to the function parameter flag.
Type: UInt32
const S_IRUSR
public const S_IRUSR: UInt32
Description: Specifies that the file owner has read permission on the file. This constant is applicable to the open, open64, openat, openat64, chmod(mode), fchmod(mode), fchmodat(mode), and creat functions and belongs to the function parameter flag.
Type: UInt32
const S_IRWXG
public const S_IRWXG: UInt32
Description: Specifies that the file user group has read, write, and execute permissions on the file. This constant is applicable to the open, open64, openat, openat64, chmod(mode), fchmod(mode), fchmodat(mode), and creat functions and belongs to the function parameter flag.
Type: UInt32
const S_IRWXO
public const S_IRWXO: UInt32
Description: Specifies that other users have read, write, and execute permissions on the file. This constant is applicable to the open, open64, openat, openat64, chmod(mode), fchmod(mode), fchmodat(mode), and creat functions and belongs to the function parameter flag.
Type: UInt32
const S_IRWXU
public const S_IRWXU: UInt32
Description: Specifies that the file owner has read, write, and execute permissions on the file. This constant is applicable to the open, open64, openat, openat64, chmod(mode), fchmod(mode), fchmodat(mode), and creat functions and belongs to the function parameter flag.
Type: UInt32
const S_IWGRP
public const S_IWGRP: UInt32
Description: Specifies that the file user group has write permission on the file. This constant is applicable to the open, open64, openat, openat64, chmod(mode), fchmod(mode), fchmodat(mode), and creat functions and belongs to the function parameter flag.
Type: UInt32
const S_IWOTH
public const S_IWOTH: UInt32
Description: Specifies that other users have write permission on the file. This constant is applicable to the open, open64, openat, openat64, chmod(mode), fchmod(mode), fchmodat(mode), and creat functions and belongs to the function parameter flag.
Type: UInt32
const S_IWUSR
public const S_IWUSR: UInt32
Description: Specifies that the file owner has write permission on the file. This constant is applicable to the open, open64, openat, openat64, chmod(mode), fchmod(mode), fchmodat(mode), and creat functions and belongs to the function parameter flag.
Type: UInt32
const S_IXGRP
public const S_IXGRP: UInt32
Description: Specifies that the file user group has execute permission on the file. This constant is applicable to the open, open64, openat, openat64, chmod(mode), fchmod(mode), fchmodat(mode), and creat functions and belongs to the function parameter flag.
Type: UInt32
const S_IXOTH
public const S_IXOTH: UInt32
Description: Specifies that other users have execute permission on the file. This constant is applicable to the open, open64, openat, openat64, chmod(mode), fchmod(mode), fchmodat(mode),d belongs to the function parameter flag.
Type: UInt32
const S_IXUSR
public const S_IXUSR: UInt32
Description: Specifies that the file owner has execute permission on the file. This constant is applicable to the open, open64, openat, openat64, chmod(mode), fchmod(mode), fchmodat(mode), and creat functions and belongs to the function parameter flag.
const W_OK
public const W_OK: Int32
Description: Tests the write permission on a file. This constant is applicable to the access and faccessat functions and belongs to the function parameter mode.
Type: UInt32
const X_OK
public const X_OK: Int32
Description: Tests the execute permission on a file. This constant is applicable to the access and faccessat functions and belongs to the function parameter mode.
Type: Int32
Functions
func open(String, Int32)
public func `open`(path: String, oflag: Int32): Int32
Description: Opens a file and returns a new file descriptor, or returns -1 when the operation fails.
Note:
Parameters:
Returns:
- Int32: A new file descriptor is returned, or
-1is returned when the operation fails.
Throws:
- IllegalArgumentException: If the function parameter
pathcontains null characters, this exception is thrown.
func open(String, Int32, UInt32)
public func `open`(path: String, oflag: Int32, flag: UInt32): Int32
Description: Opens a file and returns a new file descriptor, or returns -1 when the operation fails. path indicates the file path, and oflag indicates the file opening mode. O_RDONLY, O_RDWR, and O_WRONLY as the values of oflag are mutually exclusive, but they can be used together with other operation identifiers, such as O_APPEND.
Note:
Parameters:
- path: String: file path
- oflag: Int32: file opening mode
- flag: UInt32: If
oflagis set to O_CREAT and a new file needs to be created, theflagparameter indicates the permission on the new file. Otherwise,flagdoes not change the file permission.
Returns:
- Int32: A new file descriptor is returned, or
-1is returned when the operation fails.
Throws:
- IllegalArgumentException: If the function parameter
pathcontains null characters, this exception is thrown.
func access(String, Int32)
public func access(path: String, mode: Int32): Int32
Description: Checks whether a file has certain permission. If yes, 0 is returned; otherwise, -1 is returned.
Note:
Parameters:
Returns:
- Int32: If the file has the permission to be checked,
0is returned; otherwise,-1is returned.
Throws:
- IllegalArgumentException: If the function parameter
pathcontains null characters, this exception is thrown.
func chdir(String)
public func chdir(path: String): Int32
Description: Changes the current working directory of the calling process by specifying a path.
Parameters:
- path: String: changed path
Returns:
- Int32: If the setting is successful,
0is returned; otherwise,-1is returned.
func chmod(String, UInt32)
public func chmod(path: String, mode: UInt32): Int32
Description: Modifies the file access permission.
Note:
- In
Windowsenvironments, all files and directories are readable. chmod() cannot be used to change the read permission on files.- In
Windowsenvironments, the execute permission on a file is set through the file name extension. All directories are executable, and chmod() cannot be used to change the execute permission on files and directories.
Parameters:
Returns:
- Int32: If the operation is successful,
0is returned; otherwise,-1is returned. If themodeparameter is invalid, chmod ignores the parameter and0is returned.
Throws:
- IllegalArgumentException: If the function parameter
pathcontains null characters, this exception is thrown.
func chown(String, UInt32, UInt32)
public func chown(path: String, owner: UInt32, group: UInt32): Int32
Description: Modifies the file owner and the group to which the file owner belongs.
Parameters:
Returns:
- Int32: If the operation is successful,
0is returned; otherwise,-1is returned.
Throws:
- IllegalArgumentException: If the function parameter
pathcontains null characters, this exception is thrown.
func close(Int32)
public func close(fd: Int32): Int32
Description: Closes a file. close causes data to be written back to the disk and resources occupied by the file to be released.
Parameters:
- fd: Int32: file descriptor
Returns:
- Int32: If the operation is successful,
0is returned; otherwise,-1is returned.
func creat(String, UInt32)
public func creat(path: String, flag: UInt32): Int32
Description: Creates a file and returns a file descriptor, or returns -1 when the operation fails.
Parameters:
Returns:
- Int32: A file descriptor is returned, or
-1is returned when the operation fails.
Throws:
- IllegalArgumentException: If the function parameter
pathcontains null characters, this exception is thrown.
func dup(Int32)
public func dup(fd: Int32): Int32
Description: Copies and returns the file descriptor specified by the original fd parameter. The new file descriptor and the original fd parameter reference the same file, share the file states, and share all lock, read and write locations, and permissions or flags.
Parameters:
- fd: Int32: file descriptor
Returns:
- Int32: The smallest unused file descriptor is returned, or
-1is returned when the operation fails.
func dup2(Int32, Int32)
public func dup2(fd: Int32, fd2: Int32): Int32
Description: Copies the file descriptor specified by the oldfd parameter and returns it to the newfd parameter. If the newfd parameter is an open file descriptor, the file specified by newfd is closed first.
Parameters:
- fd: Int32: file descriptor specified by the
oldfdparameter - fd2: Int32: file descriptor specified by the
newfdparameter
Returns:
- Int32:
fd2file descriptor
func faccessat(Int32, String, Int32, Int32)
public func faccessat(fd: Int32, path: String, mode: Int32, flag: Int32): Int32
Description: Checks whether the file specified by fd has certain permission. If yes, 0 is returned; otherwise, -1 is returned.
Note:
Parameters:
- fd: Int32: file descriptor
- path: String: file path
- mode: Int32: permission to be checked
- flag: Int32: Obtains one or more of the following values by bitwise OR.
(512)Access check is performed using a valid user or groupID. By default, a validIDis used.(256)If the path name is a symbolic link, the reference is not canceled but information about the link is returned.
Returns:
- Int32: If the file has the permission to be checked,
0is returned; otherwise,-1is returned.
Throws:
- IllegalArgumentException: If the function parameter
pathcontains null characters, this exception is thrown.
func fchdir(Int32)
public func fchdir(fd: Int32): Int32
Description: Changes the current working directory of the calling process by specifying the descriptor of a file path.
Parameters:
- fd: Int32: descriptor of the changed file path
Returns:
- Int32: If the setting is successful,
0is returned; otherwise,-1is returned.
func fchmod(Int32, UInt32)
public func fchmod(fd: Int32, mode: UInt32): Int32
Description: Modifies the file access permission corresponding to the file descriptor.
Parameters:
Returns:
- Int32: If the operation is successful,
0is returned; otherwise,-1is returned.
Throws:
- IllegalArgumentException: If the function parameter
pathcontains null characters, this exception is thrown.
func fchmodat(Int32, String, UInt32, Int32)
public func fchmodat(fd: Int32, path: String, mode: UInt32, flag: Int32): Int32
Description: Modifies the file access permission corresponding to the file descriptor.
Note:
- If
pathis a relative path andfdis set to a special valueAT_FDCWD, the path is relative to the current working directory of the calling process.- If
pathis a relative path andfdis notAT_FDCWD, the path is relative to the directory to which the file referenced byfdbelongs.- If
pathis an absolute path, thefdparameter is ignored.
Parameters:
- fd: Int32: file descriptor
- path: String: file path
- mode: UInt32: permission to be modified
- flag: Int32: The value can be
0, or(256)if the path name is a symbolic link, the reference to it is not cancelled, but information about the link is returned.
Returns:
- Int32: If the operation is successful,
0is returned; otherwise,-1is returned.
Throws:
- IllegalArgumentException: If the function parameter
pathcontains null characters, this exception is thrown.
func fchown(Int32, UInt32, UInt32)
public func fchown(fd: Int32, owner: UInt32, group: UInt32): Int32
Description: Modifies the file owner corresponding to fd and the group to which the file owner belongs.
Parameters:
Returns:
- Int32: If the operation is successful,
0is returned; otherwise,-1is returned.
func fchownat(Int32, String, UInt32, UInt32, Int32)
public func fchownat(fd: Int32, path: String, owner: UInt32, group: UInt32, flag: Int32): Int32
Description: Modifies the file owner corresponding to the file descriptor and the group to which the file owner belongs.
Note:
- If
pathis a relative path andfdis set to a special valueAT_FDCWD, the path is relative to the current working directory of the calling process.- If
pathis a relative path andfdis notAT_FDCWD, the path is relative to the directory to which the file referenced byfdbelongs.- If
pathis an absolute path, thefdparameter is ignored.
Parameters:
- fd: Int32: file descriptor
- path: String: file path
- owner: UInt32: owner
uid - group: UInt32: specified
gidparameter - flag: Int32: The value can be
0, or(256)if the path name is a symbolic link, the reference to it is not cancelled, but information about the link is returned.
Returns:
- Int32: If the operation is successful,
0is returned; otherwise,-1is returned.
Throws:
- IllegalArgumentException: If the function parameter
pathcontains null characters, this exception is thrown.
func getcwd()
public func getcwd(): String
Description: Obtains the absolute path of the working directory of the current process.
Returns:
- String: If the operation is successful, a string containing the path information is returned; otherwise, an empty string is returned.
func getgid()
public func getgid(): UInt32
Description: Obtains the user group ID.
Returns:
- UInt32: current user group
ID
func getgroups(Int32, CPointer<UInt32>)
public unsafe func getgroups(size: Int32, gidArray: CPointer<UInt32>): Int32
Description: Obtains the code of the group to which the current user belongs.
Note:
- If the size parameter of
gidArrayis 0, the function returns only the number of groups to which the user belongs, and does not addgidintogidArray.
Parameters:
Returns:
- Int32: If the operation is successful, the group code is returned; otherwise,
-1is returned.
func gethostname()
public func gethostname(): String
Description: Obtains the host name, which is usually the name of a host on the TCP/IP network.
Returns:
- String: obtained host name string. If the host name fails to be obtained, an empty string is returned.
func getlogin()
public func getlogin(): String
Description: Obtains the current login name.
Returns:
- String: If the operation is successful, the login name is returned; otherwise, an empty string is returned.
func getos()
public func getos(): String
Description: Obtains the Linux system information from the file in /proc/version, for example, Linux version 4.15.0-142-generic (buildd@lgw01-amd64-036) (gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)) #146-Ubuntu SMP Tue Apr 13 01:11:19 UTC 2021.
Returns:
- String: obtained Linux system information string
func getpgid(Int32)
public func getpgid(pid: Int32): Int32
Description: Obtains PGID of the process specified by pid. If pid is 0, ID of the calling process is returned.
Parameters:
- pid: Int32: target process
ID
Returns:
- Int32: If the operation is successful, the process group
IDis returned; otherwise,-1is returned.
func getpgrp()
public func getpgrp(): Int32
Description: Obtains ID of the parent process of the calling process.
Returns:
- Int32:
IDof the parent process of the calling process
func getpid()
public func getpid(): Int32
Description: Obtains ID(PID) of the calling process.
Returns:
- Int32:
ID(PID)of the calling process
func getppid()
public func getppid(): Int32
Description: Obtains ID of the parent process of the calling process.
Returns:
- Int32:
IDof the parent process of the calling process.
func getuid()
public func getuid(): UInt32
Description: Obtains the real user ID of the calling process.
Returns:
- UInt32: current real user
ID
func isBlk(String)
public func isBlk(path: String): Bool
Description: Checks whether the input object is a block device and returns a Boolean value.
Parameters:
- path: String: file path
Returns:
- Bool: If yes,
trueis returned; otherwise,falseis returned.
func isChr(String)
public func isChr(path: String): Bool
Description: Checks whether the input object is a character device and returns a Boolean value.
Parameters:
- path: String: file path
Returns:
- Bool: If yes,
trueis returned; otherwise,falseis returned.
func isDir(String)
public func isDir(path: String): Bool
Description: Checks whether the input object is a folder and returns a Boolean value.
Parameters:
- path: String: file path
Returns:
- Bool: If yes,
trueis returned; otherwise,falseis returned.
func isFIFO(String)
public func isFIFO(path: String): Bool
Description: Checks whether the input object is a FIFO file and returns a Boolean value.
Parameters:
- path: String: file path
Returns:
- Bool: If yes,
trueis returned; otherwise,falseis returned.
func isLnk(String)
public func isLnk(path: String): Bool
Description: Checks whether the input object is a soft link and returns a Boolean value.
Parameters:
- path: String: file path
Returns:
- Bool: If yes,
trueis returned; otherwise,falseis returned.
func isReg(String)
public func isReg(path: String): Bool
Description: Checks whether the input object is a regular file and returns a Boolean value.
Parameters:
- path: String: file path
Returns:
- Bool: If yes,
trueis returned; otherwise,falseis returned.
func isSock(String)
public func isSock(path: String): Bool
Description: Checks whether the input object is a socket file and returns a Boolean value.
Parameters:
- path: String: file path
Returns:
- Bool: If yes,
trueis returned; otherwise,falseis returned.
func isType(String, UInt32)
public func isType(path: String, mode: UInt32): Bool
Description: Checks whether a file is in the specified mode. If yes, ture is returned; otherwise, false is returned. Different types are determined based on different modes.
Parameters:
Returns:
- Bool: If the file is in the specified mode,
trueis returned; otherwise,falseis returned.
func isatty(Int32)
public func isatty(fd: Int32): Bool
Description: Tests whether the file descriptor references the terminal. If the test is successful, true is returned; otherwise, false is returned.
Parameters:
- fd: Int32: file descriptor
Returns:
- Bool: If the operation is successful,
trueis returned; otherwise,falseis returned.
func kill(Int32, Int32)
public func kill(pid: Int32, sig: Int32): Int32
Description: Sends any signal to any process group or process.
Note:
- If
pidis greater than0,sigis sent to the process corresponding topid.- If
pidis equal to0,sigis sent to each process in the process group to which the calling process belongs.- If
pidis equal to-1,sigis sent to each process to which the calling process has permission to send signals.- If
pidis less than-1,sigis sent to each process in the process group whoseIDis-pid.
Parameters:
Returns:
- Int32: If the operation is successful,
0is returned; otherwise,-1is returned.
func killpg(Int32, Int32)
public func killpg(pgid: Int32, sig: Int32): Int32
Description: Sends sig to the process group pgrp. If pgrp is 0, killpg() sends the signal to the process group to which the calling process belongs.
Parameters:
Returns:
- Int32: If the operation is successful,
0is returned; otherwise,-1is returned.
func lchown(String, UInt32, UInt32)
public func lchown(path: String, owner: UInt32, group: UInt32): Int32
Description: Modifies the file link owner and the group to which the owner belongs.
Parameters:
- path: String: file path in string format
- owner: UInt32: owner
uid - group: UInt32: specified
gidparameter
Returns:
- Int32: If the operation is successful,
0is returned; otherwise,-1is returned.
Throws:
- IllegalArgumentException: If the function parameter
pathcontains null characters, this exception is thrown.
func link(String, String)
public func link(path: String, newpath: String): Int32
Description: Creates a link for an existing file. A file can have multiple directory entries pointing to i-node.
Parameters:
Returns:
- Int32: If the operation is successful,
0is returned; otherwise,-1is returned.
Throws:
- IllegalArgumentException: If the function parameter
pathornewPathcontains null characters, this exception is thrown.
func linkat(Int32, String, Int32, String, Int32)
public func linkat(fd: Int32, path: String, nfd: Int32, newPath: String, lflag: Int32): Int32
Description: Creates a file link relative to the directory file descriptor.
Note:
- If
pathis a relative path andfdis set to a special valueAT_FDCWD, the path is relative to the current working directory of the calling process.- If
pathis a relative path andfdis notAT_FDCWD, the path is relative to the directory to which the file referenced byfdbelongs.- If
pathis an absolute path, thefdparameter is ignored.newPathis similar topath. The only difference is that whennewPathis a relative path, the path is the directory to which the file referenced bynfdbelongs.
Parameters:
- fd: Int32: file descriptor
- path: String: file path
- nfd: Int32: other file descriptor
- newPath: String: other file path. If
newpathexists, it is not overwritten. - lflag: Int32: AT_EMPTY_PATH,
AT_SYMLINK_FOLLOWor0
Returns:
- Int32: If the operation is successful,
0is returned; otherwise,-1is returned.
Throws:
- IllegalArgumentException: If the function parameter
pathornewPathcontains null characters, this exception is thrown.
func lseek(Int32, Int64, Int32)
public func lseek(fd: Int32, offset: Int64, whence: Int32): Int64
Description: Increases the read or write location accordingly in file reading or writing. This function is used to control the read or write location of a file. If the call is successful, the current read/write location, that is, the number of bytes from the start of the file, is returned; otherwise, -1 is returned.
Parameters:
Returns:
- Int64: If the call is successful, the current read/write location, that is, the number of bytes from the start of the file, is returned.
func nice(Int32)
public func nice(inc: Int32): Int32
Description: Changes the priority of the current thread.
Note:
- Only the super user can use a negative
incvalue, which indicates a higher priority and faster process execution.incindicates the priority of the current process, ranging from+19(low priority) to-20.- If the operation is successful, a new value is returned; otherwise,
-1is returned. If the value ofincis greater than19,19is returned.
Parameters:
- inc: Int32: priority of the current process. The value ranges from
+19(low priority) to-20.
Returns:
- Int32: new priority value
func open64(String, Int32)
public func open64(path: String, oflag: Int32): Int32
Description: Opens a file and returns a new file descriptor, or returns -1 when the operation fails.
Note:
Parameters:
Returns:
- Int32: A new file descriptor is returned, or
-1is returned when the operation fails.
Throws:
- IllegalArgumentException: If the function parameter
pathcontains null characters, this exception is thrown.
func open64(String, Int32, UInt32)
public func open64(path: String, oflag: Int32, flag: UInt32): Int32
Description: Opens a file and returns a new file descriptor, or returns -1 when the operation fails.
Note:
Parameters:
- path: String: file path
- oflag: Int32: file opening mode
- flag: UInt32: If
oflagis set to O_CREAT and a new file needs to be created, theflagparameter indicates the permission on the new file. Otherwise,flagdoes not change the file permission.
Returns:
- Int32: A new file descriptor is returned, or
-1is returned when the operation fails.
Throws:
- IllegalArgumentException: If the function parameter
pathcontains null characters, this exception is thrown.
func openat(Int32, String, Int32)
public func openat(fd: Int32, path: String, oflag: Int32): Int32
Description: Opens a file and returns a new file descriptor, or returns -1 when the operation fails.
Note:
Parameters:
Returns:
- Int32: A new file descriptor is returned, or
-1is returned when the operation fails.
Throws:
- IllegalArgumentException: If the function parameter
pathcontains null characters, this exception is thrown.
func openat(Int32, String, Int32, UInt32)
public func openat(fd: Int32, path: String, oflag: Int32, flag: UInt32): Int32
Description: Opens a file and returns a new file descriptor, or returns -1 when the operation fails.
Note:
Parameters:
- fd: Int32: file descriptor of the path
- path: String: file path
- oflag: Int32: file opening mode
- flag: UInt32: If
oflagis set to O_CREAT and a new file needs to be created, theflagparameter indicates the permission on the new file. Otherwise,flagdoes not change the file permission.
Returns:
- Int32: A new file descriptor is returned, or
-1is returned when the operation fails.
Throws:
- IllegalArgumentException: If the function parameter
pathcontains null characters, this exception is thrown.
func openat64(Int32, String, Int32)
public func openat64(fd: Int32, path: String, oflag: Int32): Int32
Description: Opens a file and returns a new file descriptor, or returns -1 when the operation fails.
Note:
Parameters:
Returns:
- Int32: A new file descriptor is returned, or
-1is returned when the operation fails.
Throws:
- IllegalArgumentException: If the function parameter
pathcontains null characters, this exception is thrown.
func openat64(Int32, String, Int32, UInt32)
public func openat64(fd: Int32, path: String, oflag: Int32, flag: UInt32): Int32
Description: Opens a file and returns a new file descriptor, or returns -1 when the operation fails.
Note:
Parameters:
- fd: Int32: file descriptor of the path
- path: String: file path
- oflag: Int32: file opening mode
- flag: UInt32: If
oflagis set to O_CREAT and a new file needs to be created, theflagparameter indicates the permission on the new file. Otherwise,flagdoes not change the file permission.
Returns:
- Int32: A new file descriptor is returned, or
-1is returned when the operation fails.
Throws:
- IllegalArgumentException: If the function parameter
pathcontains null characters, this exception is thrown.
func pread(Int32, CPointer<UInt8>, UIntNative, Int32)
public unsafe func pread(fd: Int32, buffer: CPointer<UInt8>, nbyte: UIntNative, offset: Int32): IntNative
Description: Transfers nbyte of the file specified by fd to the memory specified by buffer. If nbyte is 0, the function does not work and 0 is returned. The return value is the number of bytes that are actually read. If the return value is 0, the end of the file is reached or data cannot be read. In addition, the read/write location of the file varies with the byte read.
Note:
- It is recommended that the size of
nbytebe the same as that ofbuffer, and the size ofbufferbe less than or equal to150000bytes.
Parameters:
- fd: Int32: file descriptor of the file to be read
- buffer: CPointer<UInt8>: buffer container
- nbyte: UIntNative: number of read bytes.
buffer.sizeis recommended. - offset: Int32: offset of the read location
Returns:
- IntNative: The number of actually read bytes is returned. If the read operation is invalid,
-1is returned.
func pwrite(Int32, CPointer<UInt8>, UIntNative, Int32)
public unsafe func pwrite(fd: Int32, buffer: CPointer<UInt8>, nbyte: UIntNative, offset: Int32): IntNative
Description: Writes nbyte in the memory specified by buffer to the file specified by fd, starting from the specified offset location. The read and write locations of the specified file move accordingly.
Note:
- It is recommended that the size of
nbytebe the same as that ofbuffer, and the size ofbufferbe less than or equal to150000bytes.
Parameters:
- fd: Int32: file descriptor of the file to be read
- buffer: CPointer<UInt8>: buffer container
- nbyte: UIntNative: number of read bytes.
buffer.sizeis recommended. - offset: Int32: offset of the read location
Returns:
- IntNative: The number of actually written bytes is returned. If the operation fails,
-1is returned.
func read(Int32, CPointer<UInt8>, UIntNative)
public unsafe func read(fd: Int32, buffer: CPointer<UInt8>, nbyte: UIntNative): IntNative
Description: Transfers nbyte of the file specified by fd to the memory specified by buffer. If nbyte is 0, the function does not work and 0 is returned. The return value is the number of bytes that are actually read. If the return value is 0, the end of the file is reached or data cannot be read. In addition, the read/write location of the file varies with the byte read.
Note:
- It is recommended that the size of
nbytebe the same as that ofbuffer, and the size ofbufferbe less than or equal to150000bytes.
Parameters:
- fd: Int32: file descriptor of the file to be read
- buffer: CPointer<UInt8>: buffer container
- nbyte: UIntNative: number of read bytes.
buffer.sizeis recommended.
Returns:
- IntNative: The number of actually read bytes is returned. If the read operation is invalid,
-1is returned.
func remove(String)
public func remove(path: String): Int32
Description: Deletes a file or directory.
Note:
Parameters:
- path: String: file path
Returns:
- Int32: If the operation is successful,
0is returned; otherwise,-1is returned.
Throws:
- IllegalArgumentException: If the function parameter
pathcontains null characters, this exception is thrown.
func rename(String, String)
public func rename(oldName: String, newName: String): Int32
Description: Renames a file. If necessary, the directory where the file is located is moved. Any other hard links of the file are not affected. The file descriptors opened in the old path are not affected.
Note:
The constraints determine whether the rename operation is successful. The specific scenarios are as follows:
- If
newNamealready exists, it is replaced atomically so that another process trying to accessnewNamedoes not find it lost, but there may be a window where both the old and new paths reference the file to be renamed.- If the old and new paths are existing hard links that reference the same file, the rename operation is not performed and success is returned.
- If
newNameexists but the operation fails for some reason, the instance that retainsnewNameis renamed.oldNamecan specify a directory. In this case,newNameneeds to be inexistent or needs to specify an empty directory.- If the old path references a symbolic link, the link is renamed. If the new path references a symbolic link, the link is overwritten.
Parameters:
Returns:
- Int32: If the operation is successful,
0is returned; otherwise,-1is returned.
Throws:
- IllegalArgumentException: If the function parameter
oldNameornewNamecontains null characters, this exception is thrown.
func renameat(Int32, String, Int32, String)
public func renameat(oldfd: Int32, oldName: String, newfd: Int32, newName: String): Int32
Description: Renames a file. If necessary, the directory where the file is located is moved.
Note:
The processing of renameat() is basically the same as that of rename(). The following describes only the differences between them.
- If
oldNameis a relative path andoldfdis set to a special valueAT_FDCWD, the path is relative to the current working directory of the calling process.- If
oldNameis a relative path andoldfdis notAT_FDCWD, the path is relative to the directory to which the file referenced byoldfdbelongs.- If
oldNameis an absolute path, theoldfdparameter is ignored.newNameis similar tooldName. The only difference is that whennewNameis a relative path, the path is the directory to which the file referenced bynewfdbelongs.
Parameters:
- oldfd: Int32: file descriptor
- oldName: String: file name
- newName: String: file name
- newfd: Int32: file descriptor
Returns:
- Int32: If the operation is successful,
0is returned; otherwise,-1is returned.
Throws:
- IllegalArgumentException: If the function parameter
oldNameornewNamecontains null characters, this exception is thrown.
func setgid(UInt32)
public func setgid(id: UInt32): Int32
Description: Sets the valid group ID of the calling process. Permissions are required to run this function.
Parameters:
- id: UInt32: valid group
IDof the calling process
Returns:
- Int32: If the setting is successful,
0is returned; otherwise,-1is returned.
func sethostname(String)
public func sethostname(buf: String): Int32
Description: Sets the host name. Only the super user can call this function.
Parameters:
- buf: String: host name to be set
Returns:
- Int32: If the setting is successful,
0is returned; otherwise,-1is returned.
Throws:
- IllegalArgumentException: If the
bufparameter contains null characters, this exception is thrown.
func setpgid(Int32, Int32)
public func setpgid(pid: Int32, pgrp: Int32): Int32
Description: Sets the group ID specified by pid to the group ID specified by pgrp. If pid is set to 0, the group ID of the current process is used.
Parameters:
Returns:
- Int32: If the operation is successful, the group
IDis returned; otherwise,-1is returned.
func setpgrp()
public func setpgrp(): Int32
Description: Sets ID of the group to which the current process belongs to ID of the process of the current process. This function is equivalent to calling setpgid(0, 0).
Returns:
- Int32: If the operation is successful, the group
IDof the current process is returned; otherwise,-1is returned.
func setuid(UInt32)
public func setuid(id: UInt32): Int32
Description: Sets the valid user ID of the calling process. Permissions are required to run this function.
Parameters:
- id: UInt32: valid user
IDof the calling process
Returns:
- Int32: If the setting is successful,
0is returned; otherwise,-1is returned.
func symlink(String, String)
public func symlink(path: String, symPath: String): Int32
Description: Creates a link named symPath to the file specified by path.
Note:
- The content of a symbolic link interpreted at run time as a link has been replaced by the path of the file or directory to be found.
- Symbolic links may contain .. path components. Such components (if used at the start of the link) reference the parent directory of the directory where the link is located.
- A symbolic link (also called a soft link) can point to an existing file or a file that does not exist. The latter is called a dangling link.
- The permissions of symbolic links are unrelated. When a link is traced, all permissions are ignored. However, when a request for deleting or renaming the link is initiated and the link is in a directory with the sticky bit set, all permissions are checked.
- If symPath already exists, it is not overwritten.
Parameters:
Returns:
- Int32: If the operation is successful,
0is returned; otherwise,-1is returned.
Throws:
- IllegalArgumentException: If the function parameter
pathorsymPathcontains null characters, this exception is thrown.
func symlinkat(String, Int32, String)
public func symlinkat(path: String, fd: Int32, symPath: String): Int32
Description: Creates a link named symPath to the file specified by path and fd.
Note:
- If
symPathis a relative path andfdis set to a special valueAT_FDCWD, the path is relative to the current working directory of the calling process.- If
symPathis a relative path andfdis notAT_FDCWD, the path is relative to the directory to which the file referenced byfdbelongs.- If
symPathis an absolute path, thefdparameter is ignored.
Parameters:
Returns:
- Int32: If the operation is successful,
0is returned; otherwise,-1is returned.
Throws:
- IllegalArgumentException: If the function parameter
pathorsymPathcontains null characters, this exception is thrown.
func ttyname(Int32)
public func ttyname(fd: Int32): String
Description: Returns the terminal name.
Parameters:
- fd: Int32: file descriptor
Returns:
- String: If the operation is successful, the path name is returned; otherwise,
NULLis returned.
func umask(UInt32)
public func umask(cmask: UInt32): UInt32
Description: Sets the permission mask.
Parameters:
- cmask: UInt32: file permission mask
Returns:
- UInt32: The previous mask of the file is returned.
func unlink(String)
public func unlink(path: String): Int32
Description: Deletes a file from the file system.
Note:
- If
pathis the last link to a file and no process opens the file, the file is deleted and the space used by the file can be reused.- If
pathis the last link to a file but the file is still opened by a process, the file exists until the last file descriptor that references it is closed.- If
pathreferences a symbolic link, the link is deleted.- If
pathreferences a socket, FIFO, or device, the file is deleted, but it may still be used by the process that opens the object.
Parameters:
- path: String: file path
Returns:
- Int32: If the operation is successful,
0is returned; otherwise,-1is returned.
Throws:
- IllegalArgumentException: If the function parameter
pathcontains null characters, this exception is thrown.
func unlinkat(Int32, String, Int32)
public func unlinkat(fd: Int32, path: String, ulflag: Int32): Int32
Description: Deletes a file from the file system.
Note:
The system call method of this function is the basically same as that of unlink, except for the differences described below.
- If
pathis a relative path andfdis set to a special valueAT_FDCWD, the path is relative to the current working directory of the calling process.- If
pathis a relative path andfdis notAT_FDCWD, the path is relative to the directory to which the file referenced byfdbelongs.- If
pathis an absolute path, thefdparameter is ignored.
Parameters:
- fd: Int32: file descriptor
- path: String: file path
- ulflag: Int32: specified as
0or set to control the bitwise OR operation of the flag of the unlinkat() operation. Currently, the value can only be AT_REMOVEDIR.
Returns:
- Int32: If the operation is successful,
0is returned; otherwise,-1is returned.
Throws:
- IllegalArgumentException: If the function parameter
pathcontains null characters, this exception is thrown.
func write(Int32, CPointer<UInt8>, UIntNative)
public unsafe func write(fd: Int32, buffer: CPointer<UInt8>, nbyte: UIntNative): IntNative
Description: Writes nbyte in the memory specified by buffer to the file specified by fd. The read and write locations of the specified file move accordingly.
Note:
It is recommended that the size of
nbytebe the same as that ofbuffer, and the size ofbufferbe less than or equal to150000bytes.
Parameters:
- fd: Int32: file descriptor of the file to be written
- buffer: CPointer<UInt8>: buffer container
- nbyte: UIntNative: number of read bytes.
buffer.sizeis recommended.
Returns:
- IntNative: number of bytes actually read. If the read operation is ineffective,
-1is returned.
Operations Related to File Content
The following is an example of operations related to file content.
The code is as follows:
import std.os.posix.*
main(): Int64 {
var fd = `open`("textcase.txt", O_RDWR | O_APPEND | O_CREAT, S_IRWXU)
println("fd ==> ${fd}")
close(fd)
var fd2 = `open`("textcase.txt", O_RDWR)
var len = lseek(fd2, 0, SEEK_END)
println("len ==> ${len}")
close(fd2)
var str1 = unsafe{LibC.mallocCString(" ")}
var buf = str1.getChars()
var fd3 = `open`("textcase.txt", O_RDWR)
var readNum = unsafe { read(fd3, buf, 2) }
unsafe{ LibC.free(str1)}
println("readNum ==> ${readNum}")
close(fd3)
var str2 = unsafe{LibC.mallocCString("123456")}
var buf2 = str2.getChars()
var fd4 = `open`("textcase.txt", O_RDWR)
var fd5 = dup(fd4)
var writeNum = unsafe { write(fd5, buf2, UIntNative(str2.size())) }
unsafe { LibC.free(str2)}
println("writeNum ==> ${writeNum}")
close(fd4)
return 0
}
The possible result is as follows:
fd ==> 3
len ==> 6
readNum ==> 2
writeNum ==> 6
Operations Related to File Information
The following is an example of operations related to file information, which is not applicable to Windows.
The code is as follows:
import std.os.posix.*
main(): Int64 {
var result1: Bool = isType("/notdirs", S_IFDIR)
println("result ==> ${result1}")
var result2: Bool = isDir("/dev")
println("result ==> ${result2}")
var result3 = access("./oscfg.cfg", F_OK)
println("result ==> ${result3}")
var result4 = chmod("oscfg.cfg", UInt32(S_IXUSR))
println("result ==> ${result4}")
return 0
}
The running result is as follows:
result ==> false
result ==> true
result ==> -1
result ==> -1
Obtaining System Information
The following is an example of obtaining system information, which is not applicable to Windows.
The code is as follows:
import std.os.posix.*
main(): Int64 {
/* obtaining system name */
var os_info = getos()
println("os info ==> ${os_info}")
var hostname = gethostname()
println("hostname ==> ${hostname}")
var logname: String = getlogin()
println("logname ==> ${logname}")
/* function related to program path */
var chagePath = "/"
var chdir_restlt = chdir(chagePath)
println("chdir_restlt ==> ${chdir_restlt}")
var cwd_path: String = getcwd()
println("cwd_path ==> ${cwd_path}")
/* system ID-related function getpgid */
var arr: CString = unsafe { LibC.mallocCString(" ") }
var a: CPointer<UInt8> = arr.getChars()
var cp: CPointer<UInt32> = CPointer<UInt32>(a)
var getg = unsafe{ getgroups(0, cp)}
var s: String = " "
for (_ in 0..getg) {
s = s + "\0"
}
println(getg)
var local: UInt32 = 0
for (temp in 0..getg) {
unsafe { local = cp.read(Int64(temp)) }
println("getgroups ==> ${local.toString()}")
}
unsafe { LibC.free(arr)}
return 0
}
The running result is as follows (the result varies depending on the system):
Linux version 4.15.0-159-generic (buildd@lgw01-amd64-055) (gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)) #167-Ubuntu SMP Tue Sep 21 08:55:05 UTC 2021
hostname ==> e124e6e0fe0f
logname ==> root
chdir_restlt ==> 0
cwd_path ==> /
1
getgroups ==> 1309868064
Operations on Process Information
The following is an example of operations on process information, which is not applicable to Windows.
The code is as follows:
import std.os.posix.*
main(): Int64 {
var result = nice(200)
print("${result}")
var result1 = kill(0, SIGCHLD)
println(result1)
var result2 = killpg(0, SIGURG)
println("result ==> ${result2}")
if (isatty(0) && isatty(1) && isatty(2)) {
print("true01 ")
} else {
print("false01 ")
}
if (isatty(-23) || isatty(4) || isatty(455) || isatty(43332)) {
print("true02 ")
} else {
println("false02")
}
return 0
}
The running result is as follows:
190
result ==> 0
true01 false02
std.os.process Package
Function Description
The os.process package provides process operation interfaces, including process creation, standard stream obtaining, process waiting, and process information query.
This package provides unified control capabilities for multiple platforms, including Linux, macOS, Windows, and HarmonyOS.
API List
Class
| Name | Description |
|---|---|
| CurrentProcess | Specifies the current process class inherited from the Process class and providing functions related to operations on the current process. |
| Process | Specifies a process class which provides functions related to process operations. |
| SubProcess | Specifies a subprocess class inherited from the Process class and providing functions related to subprocess operations. |
Enumeration
| Name | Description |
|---|---|
| ProcessRedirect | Sets the redirection mode of the subprocess standard stream when a process is created. |
Exception Class
| Name | Description |
|---|---|
| ProcessException | Specifies an exception class of the os.process package. |
Compatibility
class Process
| Member | Supported on |
|---|---|
| current | Linux, Windows, macOS, and HarmonyOS |
| pid | Linux, Windows, macOS, and HarmonyOS |
| name | Linux, Windows, macOS, and HarmonyOS |
| command | Linux, Windows, macOS, and HarmonyOS |
| arguments | Linux, macOS, and HarmonyOS |
| commandLine | Linux, macOS, and HarmonyOS |
| workingDirectory | Linux, macOS, and HarmonyOS |
| environment | Linux and HarmonyOS |
| of(Int64) | Linux, Windows, macOS, and HarmonyOS |
| start(String, Array | Linux, Windows, macOS, and HarmonyOS |
| run(String, Array | Linux, Windows, macOS, and HarmonyOS |
| runOutput(String, Array | Linux, Windows, macOS, and HarmonyOS |
| terminate(Bool) | Linux, Windows, macOS, and HarmonyOS |
class CurrentProcss
| Member | Supported on |
|---|---|
| stdIn | Linux, Windows, macOS, and HarmonyOS |
| stdOut | Linux, Windows, macOS, and HarmonyOS |
| stdErr | Linux, Windows, macOS, and HarmonyOS |
| atExit(() -> Unit) | Linux, Windows, macOS, and HarmonyOS |
| exit(Int64) | Linux, Windows, macOS, and HarmonyOS |
class SubProcess
| Member | Supported on |
|---|---|
| stdIn | Linux, Windows, macOS, and HarmonyOS |
| stdOut | Linux, Windows, macOS, and HarmonyOS |
| stdErr | Linux, Windows, macOS, and HarmonyOS |
| wait(Duration) | Linux, Windows, macOS, and HarmonyOS |
| waitOutput() | Linux, Windows, macOS, and HarmonyOS |
Class
class CurrentProcess
public class CurrentProcess <: Process
Description: Specifies the current process class inherited from the Process class and providing functions related to operations on the current process.
Note:
The following functions are provided:
- Provides the mechanism for obtaining the standard streams (
stdIn,stdOut, andstdErr) of the current process.- Provides the callback function mechanism for exiting the current process.
- Provides the mechanism for exiting the current process. The exit status code can be set.
Parent Type:
prop stdErr
public prop stdErr: OutputStream
Description: Obtains the standard error stream of the current process.
Type: OutputStream
prop stdIn
public prop stdIn: InputStream
Description: Obtains the standard input stream of the current process.
Type: InputStream
prop stdOut
public prop stdOut: OutputStream
Description: Obtains the standard output stream of the current process.
Type: OutputStream
func atExit(() -> Unit)
public func atExit(callback: () -> Unit): Unit
Description: Registers a callback function. The registration function is executed when the current process exits.
Note:
Do not use the atexit function of the C language, otherwise unpredictable problems may occur.
Parameters:
- callback: () ->Unit: function to be registered and called back
func exit(Int64)
public func exit(code: Int64): Nothing
Description: Specifies a process-exiting function which ends the current process and sets the return status code through input parameters code.
Parameters:
- code: Int64: exit status code of the current process
class Process
public open class Process
Description: Specifies a process class which provides functions related to process operations.
Note:
The following functions are provided:
- Provides the function of obtaining the current process instance.
- Provides the function of binding process instances based on process
id.- Creates a subprocess based on the input information.
- Provides the function of obtaining process information.
- Provides the function of stopping processes. Whether to forcibly stop processes can be set.
static prop current
public static prop current: CurrentProcess
Description: Obtains the current process instance.
Type: CurrentProcess
prop arguments
public prop arguments: Array<String>
Description: Obtains process parameters. This attribute cannot be obtained in non-privileged API mode on Windows.
Throws:
- ProcessException: When the process parameters cannot be obtained because the process does not exist, the process is a zombie process, or the scenario is not supported on
Windows, this exception is thrown.
prop command
public prop command: String
Description: Obtains a process command.
Type: String
Throws:
- ProcessException: When the process command cannot be obtained because the process does not exist or the process is a zombie process, this exception is thrown.
prop commandLine
public prop commandLine: Array<String>
Description: Obtains a process command line. This attribute can be obtained by the current process on Windows. In other scenarios, this attribute cannot be obtained in non-privileged API mode.
Throws:
- ProcessException: When the process command line cannot be obtained because the process does not exist, the process is a zombie process, or the scenario is not supported on
Windows, this exception is thrown.
prop environment
public prop environment: Map<String, String>
Description: Obtains the environment variables of a process. This attribute can be obtained by the current process on Windows. In other scenarios, this attribute cannot be obtained in non-privileged API mode.
Throws:
- ProcessException: When the environment variables of the process cannot be obtained because the process does not exist, the process is a zombie process, or the scenario is not supported on
Windows, this exception is thrown.
prop name
public prop name: String
Description: Obtains a process name.
Type: String
Throws:
- ProcessException: When the process name cannot be obtained because the process does not exist or the process is a zombie process, this exception is thrown.
prop pid
public prop pid: Int64
Description: Obtains a process id.
Type: Int64
prop workingDirectory
public prop workingDirectory: Path
Description: Obtains the working path of a process. This attribute can be obtained by the current process on Windows . In other scenarios, this attribute cannot be obtained in non-privileged API mode.
Type: Path
Throws:
- ProcessException: When the working path of the process cannot be obtained because the process does not exist, the corresponding process is a zombie process, or the scenario is not supported on
Windows, this exception is thrown.
static func of(Int64)
public static func of(pid: Int64): Process
Description: Binds a process instance based on the input process id.
Parameters:
- pid: Int64: process
id
Returns:
- Process: process instance corresponding to a process
id
Throws:
- IllegalArgumentException: When the input process
idis greater than Int32 or less than0, this exception is thrown. - ProcessException: When memory allocation fails or the process corresponding to
piddoes not exist, this exception is thrown.
static func run(String, Array<String>, ?Path, ?Map<String, String>, ProcessRedirect, ProcessRedirect,ProcessRedirect, ?Duration)
public static func run(command: String,
arguments: Array<String>,
workingDirectory!: ?Path = None,
environment!: ?Map<String, String> = None,
stdIn!: ProcessRedirect = Inherit,
stdOut!: ProcessRedirect = Inherit,
stdErr!: ProcessRedirect = Inherit,
timeout!: ?Duration = None): Int64
Description: Creates and runs a subprocess based on input parameters, waits until the subprocess is complete, and returns the exit status of the subprocess.
Note:
- On
Windows, if the executable file of a subprocess is deleted immediately after the subprocess is executed, the deletion may fail and an exception is thrown. The exception information isAccess is denied. If this problem occurs, the file can be deleted again after a short delay. For details, see the example.
Parameters:
- command: String: specified subprocess command. Null characters are not allowed in
command. - arguments: Array<String>: specified subprocess parameter. The
argumentsstring in the array cannot contain null characters. - workingDirectory!: ?Path: named optional parameter, which specifies the working path of the subprocess. By default, the working path of the current process is inherited. The path must exist and cannot be empty or contain null characters.
- environment!: ?Map<String, String>: named optional parameter, which specifies the environment variable of the subprocess. By default, the environment variable of the current process is inherited.
keyThe character string cannot contain null characters or'='. The value cannot contain null characters. - stdIn!: ProcessRedirect: named optional parameter, which specifies the standard input for subprocess redirection. By default, the standard input of the current process is inherited.
- stdOut!: ProcessRedirect: named optional parameter, which specifies the standard output of the subprocess redirection. By default, the standard output of the current process is inherited.
- stdErr!: ProcessRedirect: named optional parameter, which specifies the subprocess redirection standard error. By default, the standard error of the current process is inherited.
- timeout!: ?Duration: named optional parameter, which specifies the timeout interval for waiting for a subprocess. The default value indicates no timeout. If this parameter is set to
0or a negative value, the subprocess does not time out.
Returns:
- Int64: exit status of the subprocess. If the subprocess exits normally, the exit code of the subprocess is returned. If the subprocess is killed by a signal, the number of the signal that causes the subprocess to terminate is returned.
Throws:
- IllegalArgumentException: When the input parameter
commandcontains null characters, the character string in theargumentsarray contains null characters, theworkingDirectorydirectory does not exist, the path is empty, thekeycharacter string in theenvironmenttable contains null characters or'=', thevaluecharacter string contains null characters, orstdIn,stdOut, andstdErrinput is in file mode and the input file has been closed or deleted, this exception is thrown. - ProcessException: When memory allocation fails, the
commandcorresponding command does not exist, or the waiting times out, this exception is thrown.
static func runOutput(String, Array<String>, ?Path, ?Map<String, String>, ProcessRedirect, ProcessRedirect, ProcessRedirect)
public static func runOutput(command: String,
arguments: Array<String>,
workingDirectory!: ?Path = None,
environment!: ?Map<String, String> = None,
stdIn!: ProcessRedirect = Inherit,
stdOut!: ProcessRedirect = Pipe,
stdErr!: ProcessRedirect = Pipe): (Int64, Array<Byte>, Array<Byte>)
Description: Creates and runs a subprocess based on input parameters, waits until the subprocess is complete, and returns the exit status, standard output, and standard error of the subprocess. This function is not applicable to the scenario where the output stream and error stream contain a large amount of output. It is recommended that the standard stream attributes provided in SubProcess and the wait function be used to process the output stream and error stream.
Parameters:
- command: String: specified subprocess command. Null characters are not allowed in
command. - arguments: Array<String>: specified subprocess parameter. The
argumentsstring in the array cannot contain null characters. - workingDirectory!: ?Path: named optional parameter, which specifies the working path of the subprocess. By default, the working path of the current process is inherited. The path must exist and cannot be empty or contain null characters.
- environment!: ?Map<String, String>: named optional parameter, which specifies the environment variable of the subprocess. By default, the environment variable of the current process is inherited.
keyThe character string cannot contain null characters or'='. The value cannot contain null characters. - stdIn!: ProcessRedirect: named optional parameter, which specifies the standard input for subprocess redirection. By default, the standard input of the current process is inherited.
- stdOut!: ProcessRedirect: named optional parameter, which specifies the standard output of the subprocess redirection. By default, the standard output of the current process is inherited.
- stdErr!: ProcessRedirect: named optional parameter, which specifies the subprocess redirection standard error. By default, the standard error of the current process is inherited.
Returns:
- (Int64, Array<Byte>, Array<Byte>): result returned after the subprocess is executed, including the subprocess exit status (if the subprocess exits normally, the subprocess exit code is returned; if the subprocess is killed by a signal, the signal number that causes the subprocess to terminate is returned), standard process output result, and process error result.
Throws:
- IllegalArgumentException: When the input parameter
commandcontains null characters, the character string in theargumentsarray contains null characters, theworkingDirectorydirectory does not exist, the path is empty, thekeycharacter string in theenvironmenttable contains null characters or'=', thevaluecharacter string contains null characters, orstdIn,stdOut, andstdErrinput is in file mode and the input file has been closed or deleted, this exception is thrown. - ProcessException: When memory allocation fails, the corresponding
commanddoes not exist, the subprocess does not exist, or an exception occurs when the standard stream is read, this exception is thrown.
static func start(String, Array<String>, ?Path, ?Map<String, String>, ProcessRedirect, ProcessRedirect, ProcessRedirect)
public static func start(command: String,
arguments: Array<String>,
workingDirectory!: ?Path = None,
environment!: ?Map<String, String> = None,
stdIn!: ProcessRedirect = Inherit,
stdOut!: ProcessRedirect = Inherit,
stdErr!: ProcessRedirect = Inherit): SubProcess
Description: Creates and runs a subprocess based on input parameters and returns a subprocess instance. After this function is called to create a subprocess, the wait or waitOutput function needs to be called. Otherwise, the resources of the zombie process after the subprocess ends will not be reclaimed.
Parameters:
- command: String: specified subprocess command. Null characters are not allowed in
command. - arguments: Array<String>: specified subprocess parameter. The
argumentsstring in the array cannot contain null characters. - workingDirectory!: ?Path: named optional parameter, which specifies the working path of the subprocess. By default, the working path of the current process is inherited. The path must exist and cannot be empty or contain null characters.
- environment!: ?Map<String, String>: named optional parameter, which specifies the environment variable of the subprocess. By default, the environment variable of the current process is inherited.
keyThe character string cannot contain null characters or'='. The value cannot contain null characters. - stdIn!: ProcessRedirect: named optional parameter, which specifies the standard input for subprocess redirection. By default, the standard input of the current process is inherited.
- stdOut!: ProcessRedirect: named optional parameter, which specifies the standard output of the subprocess redirection. By default, the standard output of the current process is inherited.
- stdErr!: ProcessRedirect: named optional parameter, which specifies the subprocess redirection standard error. By default, the standard error of the current process is inherited.
Returns:
- SubProcess: subprocess instance
Throws:
- IllegalArgumentException: When the input parameter
commandcontains null characters, the character string in theargumentsarray contains null characters, theworkingDirectorydirectory does not exist, the path is empty, thekeycharacter string in theenvironmenttable contains null characters or'=', thevaluecharacter string contains null characters, orstdIn,stdOut, andstdErrinput is in file mode and the input file has been closed or deleted, this exception is thrown. - ProcessException: When memory allocation fails or the corresponding
commanddoes not exist, this exception is thrown.
func terminate(Bool)
public func terminate(force!: Bool = false): Unit
Description: Terminates a process. The result of the subprocess execution includes the exit status of the subprocess (if the subprocess exits normally, the exit code of the subprocess is returned; if the subprocess is killed by a signal, the number of that signal is returned), standard output result of the process, and error result of the process.
Parameters:
- force!: Bool: named optional parameter, which specifies whether to forcibly stop a process. The default value is
false. If this parameter is set tofalse, the process can be stopped after resources are released. If this parameter is set totrue, the process is directly killed. OnWindows, the process is forcibly stopped.
Throws:
- ProcessException: If the process does not exist and cannot be terminated, this exception is thrown.
class SubProcess
public class SubProcess <: Process
Description: Specifies a subprocess class inherited from the Process class and providing functions related to subprocess operations.
Note:
The following functions are provided:
- Provides the mechanism for obtaining the standard streams (
stdIn,stdOut, andstdErr) of subprocesses.- Provides the mechanism for waiting for the subprocess to return the exit status code is provided. The waiting timeout interval can be set.
- Provides the mechanism for waiting for the output (including expected results and abnormal results) of the subprocess execution. The waiting timeout duration can be set.
Parent Type:
prop stdErr
public prop stdErr: InputStream
Description: Obtains the input stream and connects it to the standard error stream of a subprocess.
Type: InputStream
prop stdIn
public prop stdIn: OutputStream
Description: Obtains the output stream and connects it to the standard input stream of a subprocess.
Type: OutputStream
prop stdOut
public prop stdOut: InputStream
Description: Obtains the input stream and connects it to the standard output stream of a subprocess.
Type: InputStream
func wait(?Duration)
public func wait(timeout!: ?Duration = None): Int64
Description: Blocks the current process, waits for the completion of the subprocess task, and returns the exit status code of the subprocess. The waiting timeout duration can be specified. In the scenario where standard streams need to be operated (in pipe mode), the standard streams need to be processed first to prevent deadlock if the function is called when the standard stream buffer of the subprocess is full.
Note:
Timeout processing mechanism:
- If no parameter is transferred, and the
timeoutvalue isNoneor less than or equal to Duration.Zero, block the subprocess and wait until the subprocess returns.- If the
timeoutvalue is greater than Duration.Zero, block the subprocess and wait for the subprocess to return or throw a timeout exception after the waiting times out.
Parameters:
- timeout!: ?Duration: named optional parameter, which specifies the timeout duration for waiting for a subprocess. The default value is
None.
Returns:
- Int64: exit status of the subprocess. If the subprocess exits normally, the exit code of the subprocess is returned. If the subprocess is killed by a signal, the number of the signal that causes the subprocess to terminate is returned.
Throws:
- ProcessException: When the waiting times out and the subprocess does not exit, this exception is thrown.
func waitOutput()
public func waitOutput(): (Int64, Array<Byte>, Array<Byte>)
Description: Blocks the current process, waits until the subprocess task is complete, and returns the subprocess exit status code and result (including the output stream and error stream). This function is not applicable to the scenario where the output stream and error stream contain a large amount of output. It is recommended that the standard stream attributes provided in SubProcess and the wait function be used to process the output stream and error stream.
Returns:
- (Int64, Array<Byte>, Array<Byte>): result returned after the subprocess is executed, including the subprocess exit status (if the subprocess exits normally, the subprocess exit code is returned; if the subprocess is killed by a signal, the signal number that causes the subprocess to terminate is returned), standard process output result, and process error result.
Throws:
- ProcessException: When the subprocess does not exist or an exception occurs when the standard stream is read, this exception is thrown.
Enumeration
enum ProcessRedirect
public enum ProcessRedirect {
| Inherit
| Pipe
| FromFile(File)
| Discard
}
Description: Sets the redirection mode of the subprocess standard stream when a process is created.
Discard
Discard
Description: Constructs an enumeration instance of standard stream redirection, indicating that the standard stream of the subprocess is discarded. In this mode, the standard stream attributes cannot be read or written.
FromFile(File)
FromFile(File)
Description: Constructs an enumeration instance of standard stream redirection, indicating that the standard stream of the subprocess is redirected to the specified file. The redirected standard input stream is read from a specified file, and the redirected standard output stream or standard error stream is written to the specified file. Ensure that the redirection file exists and is not closed. Otherwise, redirection is not allowed. In this mode, the standard stream attributes cannot be read or written. The parameter File specifies the file instance that exists and is not closed. When a subprocess is created, the standard stream is redirected to the specified file.
Inherit
Inherit
Description: Constructs an enumeration instance of standard stream redirection, indicating that the standard stream of the subprocess inherits the standard stream of the current process. In this mode, the standard stream attributes cannot be read or written.
Pipe
Pipe
Description: Constructs an enumeration instance of standard stream redirection, indicating that the standard stream of the subprocess is redirected to the pipe and connected to the current process through the pipe. The redirected standard input stream can write data to the subprocess through a pipe, and the redirected standard output stream or standard error stream can read the output result of the subprocess through a pipe. In this mode, data can be read or written through the standard stream attributes.
Exception
class ProcessException
public class ProcessException <: Exception {
init(message: String)
}
Description: Specifies an exception class of the os.process package.
Parent Type:
init(String)
public init(message: String)
Description: Creates a ProcessException instance.
Parameters:
- message: String: exception information
Operation Related to the Current Process
The following is an example of operations related to the current process. The following example is not supported on Windows.
The code is as follows:
import std.os.process.*
main(): Int64 {
let curProcess = Process.current
println(curProcess.pid)
println(curProcess.name)
println(curProcess.command)
println(curProcess.arguments.toString())
println(curProcess.commandLine.toString())
println(curProcess.workingDirectory.toString())
curProcess.atExit(printText)
curProcess.exit(0)
return 0
}
func printText(): Unit {
println("hello cangjie!")
}
The running result may be as follows: (In the output result, main is the command name of the current process. After the callback is complete, the current process exits.)
75590
./main
./main
[]
[./main]
/root/code/Process/test
hello cangjie!
Deleting the Executable File after the Subprocess Ends on Windows
The following is an example of handling the failure in deleting the executable file of a subprocess after the subprocess ends on Windows.
The code is as follows:
import std.os.process.*
import std.io.*
import std.fs.*
import std.time.*
import std.sync.*
// Takes Windows command as an example. For the following example, a "test.exe" file needs to be created in advance in the current directory.
main(): Int64 {
Process.runOutput("cmd.exe", "/c", "test.exe")
for (_ in 0..5) {
try {
File.delete(".\\test.exe")
break
} catch (e: FSException) {
if (e.message != "Failed to recursive delete directory: \"Access is denied.\".") {
throw e
}
sleep(Duration.millisecond * 5)
}
}
println("delete file success.")
return 0
}
The running result may be as follows:
delete file success.
Operation Related to Any Process
The following is an example of operations related to any process. The following example is not supported on Windows.
The code is as follows:
import std.os.process.*
import std.fs.*
main(): Int64 {
let echoProcess: SubProcess = Process.start("sleep", "10s")
let ofProcess: Process = Process.of(echoProcess.pid)
println(ofProcess.pid)
println(ofProcess.name)
println(ofProcess.command)
println(ofProcess.arguments.toString())
println(ofProcess.commandLine.toString())
ofProcess.terminate(force: true)
return 0
}
The running result may be as follows:
78980
sleep
sleep
[10s]
[sleep, 10s]
Operation Related to Subprocess
The following is an example of subprocess operations. The following example is not supported on Windows.
The code is as follows:
import std.os.process.*
import std.io.*
import std.fs.*
// Takes Linux command as an example. For the following example, a "/root/code/Process/test" directory needs to be created in advance.
main(): Int64 {
let sleepProcess: SubProcess = Process.start("sleep", "10s", workingDirectory: Path("/root/code/Process/test"))
println(sleepProcess.pid)
println(sleepProcess.name)
println(sleepProcess.command)
println(sleepProcess.arguments.toString())
println(sleepProcess.commandLine.toString())
println(sleepProcess.workingDirectory.toString())
sleepProcess.terminate(force: true)
let rtnCode = sleepProcess.wait()
println("sleepProcess rtnCode: ${rtnCode}")
let echoProcess: SubProcess = Process.start("echo", "hello cangjie!", stdOut: ProcessRedirect.Pipe)
let strReader: StringReader<InputStream> = StringReader(echoProcess.stdOut)
println(strReader.readToEnd())
return 0
}
The running result may be as follows:
45090
sleep 10s
sleep
[10s]
[sleep, 10s]
/root/code/Process/test
sleepProcess rtnCode: 9
hello cangjie!
std.overflow Package
Function Description
The overflow package provides the capability of processing overflows in integer operations.
In an integer operation, an overflow occurs if the operation result is greater than the maximum value of a type or less than the minimum value of a type. By default, an exception is thrown when an overflow occurs.
The overflow package provides four overflow processing policies and defines corresponding interfaces as follows:
| Policy | Interface | Description |
|---|---|---|
| Returning Option | CheckedOp | When an overflow occurs in an integer operation, None is returned. |
| Saturating | SaturatingOp | If the operation result is greater than the MAX value of the target type, the MAX value is returned. If the operation result is less than the MIN value of the target type, the MIN value is returned. |
| Throwing exception | ThrowingOp | When an overflow occurs in an integer operation, an exception is thrown. |
| Most significant bit truncation | WrappingOp | When an overflow occurs in an integer operation, the most significant bits exceeding the number of bits of the target type in the operation result are truncated. |
The overflow package implements these interfaces for all integer types through extension. Users can implement the overflow interfaces for other types in the same way.
API List
Interface
| Name | Description |
|---|---|
| CheckedOp | Returns None when an overflow occurs in an integer operation. |
| SaturatingOp | Performs saturation processing when an overflow occurs in an integer operation. |
| ThrowingOp | Throws an exception when an overflow occurs in an integer operation. |
| WrappingOp | When an overflow occurs in an integer operation, the most significant bits exceeding the number of bits of the target type in the operation result are truncated. |
Exception Class
| Name | Description |
|---|---|
| OvershiftException | Specifies an exception thrown when the number of shifted bits exceeds the number of operand bits in a shift operation. |
| UndershiftException | Specifies an exception thrown when the number of shifted bits is less than 0 in a shift operation. |
Interface
interface CheckedOp<T>
public interface CheckedOp<T> {
func checkedAdd(y: T): ?T
func checkedDec(): ?T
func checkedDiv(y: T): ?T
func checkedInc(): ?T
func checkedMod(y: T): ?T
func checkedMul(y: T): ?T
func checkedNeg(): ?T
func checkedShl(y: T): ?T
func checkedShr(y: T): ?T
func checkedSub(y: T): ?T
}
Description: Returns None when an overflow occurs in an integer operation.
func checkedAdd(T)
func checkedAdd(y: T): ?T
Description: Performs addition operation using the policy of returning Option.
When an overflow occurs in an operation, ?T.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: T: addend
Returns:
- ?T: addition operation result
func checkedDec()
func checkedDec(): ?T
Description: Performs auto-decrement operation using the policy of returning Option.
When an overflow occurs in an operation, ?T.None is returned. Otherwise, the operation result is returned.
Returns:
- ?T: auto-decrement operation result
func checkedDiv(T)
func checkedDiv(y: T): ?T
Description: Performs division operation using the policy of returning Option.
When an overflow occurs in an operation, ?T.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: T: divisor
Returns:
- ?T: division operation result
func checkedInc()
func checkedInc(): ?T
Description: Performs auto-increment operation using the policy of returning Option.
When an overflow occurs in an operation, ?T.None is returned. Otherwise, the operation result is returned.
Returns:
- ?T: auto-increment operation result
func checkedMod(T)
func checkedMod(y: T): ?T
Description: Performs modulo operation using the policy of returning Option.
When an overflow occurs in an operation, ?T.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: T: divisor
Returns:
- ?T: modulo operation result
func checkedMul(T)
func checkedMul(y: T): ?T
Description: Performs multiplication operation using the policy of returning Option.
When an overflow occurs in an operation, ?T.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: T: multiplier
Returns:
- ?T: multiplication operation result
func checkedNeg()
func checkedNeg(): ?T
Description: Performs negation operation using the policy of returning Option.
When an overflow occurs in an operation, ?T.None is returned. Otherwise, the operation result is returned.
Returns:
- ?T: negation operation result
func checkedShl(T)
func checkedShl(y: T): ?T
Description: Performs left shift operation using the policy of returning Option.
When the number of bits to shift by is greater than or equal to that of operand bits or is less than 0, ?T.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: T: number of bits to shift by
Returns:
- ?T: left shift operation result
func checkedShr(T)
func checkedShr(y: T): ?T
Description: Performs right shift operation using the policy of returning Option.
When the number of bits to shift by is greater than or equal to that of operand bits or is less than 0, ?T.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: T: number of bits to shift by
Returns:
- ?T: right shift operation result
func checkedSub(T)
func checkedSub(y: T): ?T
Description: Performs subtraction operation using the policy of returning Option.
When an overflow occurs in an operation, ?T.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: T: subtrahend
Returns:
- ?T: subtraction operation result
extend Int16 <: CheckedOp<Int16>
extend Int16 <: CheckedOp<Int16>
Description: Implements the CheckedOp interface for Int16.
Parent Type:
func checkedAdd(Int16)
public func checkedAdd(y: Int16): ?Int16
Description: Performs addition operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int16.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int16: addend
Returns:
- ?Int16: addition operation result
func checkedDec()
public func checkedDec(): ?Int16
Description: Performs auto-decrement operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int16.None is returned. Otherwise, the operation result is returned.
Returns:
- ?Int16: auto-decrement operation result
func checkedDiv(Int16)
public func checkedDiv(y: Int16): ?Int16
Description: Performs division operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int16.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int16: divisor
Returns:
- ?Int16: division operation result
func checkedInc()
public func checkedInc(): ?Int16
Description: Performs auto-increment operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int16.None is returned. Otherwise, the operation result is returned.
Returns:
- ?Int16: auto-increment operation result
func checkedMod(Int16)
public func checkedMod(y: Int16): ?Int16
Description: Performs modulo operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int16.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int16: divisor
Returns:
- ?Int16: modulo operation result
func checkedMul(Int16)
public func checkedMul(y: Int16): ?Int16
Description: Performs multiplication operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int16.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int16: multiplier
Returns:
- ?Int16: multiplication operation result
func checkedNeg()
public func checkedNeg(): ?Int16
Description: Performs negation operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int16.None is returned. Otherwise, the operation result is returned.
Returns:
- ?Int16: negation operation result
func checkedShl(Int16)
public func checkedShl(y: Int16): ?Int16
Description: Performs left shift operation using the policy of returning Option.
When the number of bits to shift by is greater than or equal to that of operand bits or is less than 0, ?Int16.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int16: number of bits to shift by
Returns:
- ?Int16: left shift operation result
func checkedShr(Int16)
public func checkedShr(y: Int16): ?Int16
Description: Performs right shift operation using the policy of returning Option.
When the number of bits to shift by is greater than or equal to that of operand bits or is less than 0, ?Int16.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int16: number of bits to shift by
Returns:
- ?Int16: right shift operation result
func checkedSub(Int16)
public func checkedSub(y: Int16): ?Int16
Description: Performs subtraction operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int16.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int16: subtrahend
Returns:
- ?Int16: subtraction operation result
extend Int32 <: CheckedOp<Int32>
extend Int32 <: CheckedOp<Int32>
Description: Implements the CheckedOp interface for Int32.
Parent Type:
func checkedAdd(Int32)
public func checkedAdd(y: Int32): ?Int32
Description: Performs addition operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int32.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int32: addend
Returns:
- ?Int32: addition operation result
func checkedDec()
public func checkedDec(): ?Int32
Description: Performs auto-decrement operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int32.None is returned. Otherwise, the operation result is returned.
Returns:
- ?Int32: auto-decrement operation result
func checkedDiv(Int32)
public func checkedDiv(y: Int32): ?Int32
Description: Performs division operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int32.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int32: divisor
Returns:
- ?Int32: division operation result
func checkedInc()
public func checkedInc(): ?Int32
Description: Performs auto-increment operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int32.None is returned. Otherwise, the operation result is returned.
Returns:
- ?Int32: auto-increment operation result
func checkedMod(Int32)
public func checkedMod(y: Int32): ?Int32
Description: Performs modulo operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int32.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int32: divisor
Returns:
- ?Int32: modulo operation result
func checkedMul(Int32)
public func checkedMul(y: Int32): ?Int32
Description: Performs multiplication operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int32.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int32: multiplier
Returns:
- ?Int32: multiplication operation result
func checkedNeg()
public func checkedNeg(): ?Int32
Description: Performs negation operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int32.None is returned. Otherwise, the operation result is returned.
Returns:
- ?Int32: negation operation result
func checkedShl(Int32)
public func checkedShl(y: Int32): ?Int32
Description: Performs left shift operation using the policy of returning Option.
When the number of bits to shift by is greater than or equal to that of operand bits or is less than 0, ?Int32.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int32: number of bits to shift by
Returns:
- ?Int32: left shift operation result
func checkedShr(Int32)
public func checkedShr(y: Int32): ?Int32
Description: Performs right shift operation using the policy of returning Option.
When the number of bits to shift by is greater than or equal to that of operand bits or is less than 0, ?Int32.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int32: number of bits to shift by
Returns:
- ?Int32: right shift operation result
func checkedSub(Int32)
public func checkedSub(y: Int32): ?Int32
Description: Performs subtraction operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int32.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int32: subtrahend
Returns:
- ?Int32: subtraction operation result
extend Int64 <: CheckedOp<Int64>
extend Int64 <: CheckedOp<Int64>
Description: Implements the CheckedOp interface for Int64.
Parent Type:
func checkedAdd(Int64)
public func checkedAdd(y: Int64): ?Int64
Description: Performs addition operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int64.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int64: addend
Returns:
- ?Int64: addition operation result
func checkedDec()
public func checkedDec(): ?Int64
Description: Performs auto-decrement operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int64.None is returned. Otherwise, the operation result is returned.
Returns:
- ?Int64: auto-decrement operation result
func checkedDiv(Int64)
public func checkedDiv(y: Int64): ?Int64
Description: Performs division operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int64.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int64: divisor
Returns:
- ?Int64: division operation result
func checkedInc()
public func checkedInc(): ?Int64
Description: Performs auto-increment operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int64.None is returned. Otherwise, the operation result is returned.
Returns:
- ?Int64: auto-increment operation result
func checkedMod(Int64)
public func checkedMod(y: Int64): ?Int64
Description: Performs modulo operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int64.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int64: divisor
Returns:
- ?Int64: modulo operation result
func checkedMul(Int64)
public func checkedMul(y: Int64): ?Int64
Description: Performs multiplication operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int64.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int64: multiplier
Returns:
- ?Int64: multiplication operation result
func checkedNeg()
public func checkedNeg(): ?Int64
Description: Performs negation operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int64.None is returned. Otherwise, the operation result is returned.
Returns:
- ?Int64: negation operation result
func checkedPow(UInt64)
public func checkedPow(y: UInt64): ?Int64
Description: Performs exponentiation operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int64.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt64: exponent
Returns:
- ?Int64: exponentiation operation result
func checkedShl(Int64)
public func checkedShl(y: Int64): ?Int64
Description: Performs left shift operation using the policy of returning Option.
When the number of bits to shift by is greater than or equal to that of operand bits or is less than 0, ?Int64.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int64: number of bits to shift by
Returns:
- ?Int64: left shift operation result
func checkedShr(Int64)
public func checkedShr(y: Int64): ?Int64
Description: Performs right shift operation using the policy of returning Option.
When the number of bits to shift by is greater than or equal to that of operand bits or is less than 0, ?Int64.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int64: number of bits to shift by
Returns:
- ?Int64: right shift operation result
func checkedSub(Int64)
public func checkedSub(y: Int64): ?Int64
Description: Performs subtraction operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int64.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int64: subtrahend
Returns:
- ?Int64: subtraction operation result
extend Int8 <: CheckedOp<Int8>
extend Int8 <: CheckedOp<Int8>
Description: Implements the CheckedOp interface for Int8.
Parent Type:
func checkedAdd(Int8)
public func checkedAdd(y: Int8): ?Int8
Description: Performs addition operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int8.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int8: addend
Returns:
- ?Int8: addition operation result
func checkedDec()
public func checkedDec(): ?Int8
Description: Performs auto-decrement operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int8.None is returned. Otherwise, the operation result is returned.
Returns:
- ?Int8: auto-decrement operation result
func checkedDiv(Int8)
public func checkedDiv(y: Int8): ?Int8
Description: Performs division operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int8.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int8: divisor
Returns:
- ?Int8: division operation result
func checkedInc()
public func checkedInc(): ?Int8
Description: Performs auto-increment operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int8.None is returned. Otherwise, the operation result is returned.
Returns:
- ?Int8: auto-increment operation result
func checkedMod(Int8)
public func checkedMod(y: Int8): ?Int8
Description: Performs modulo operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int8.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int8: divisor
Returns:
- ?Int8: modulo operation result
func checkedMul(Int8)
public func checkedMul(y: Int8): ?Int8
Description: Performs multiplication operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int8.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int8: multiplier
Returns:
- ?Int8: multiplication operation result
func checkedNeg()
public func checkedNeg(): ?Int8
Description: Performs negation operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int8.None is returned. Otherwise, the operation result is returned.
Returns:
- ?Int8: negation operation result
func checkedShl(Int8)
public func checkedShl(y: Int8): ?Int8
Description: Performs left shift operation using the policy of returning Option.
When the number of bits to shift by is greater than or equal to that of operand bits or is less than 0, ?Int8.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int8: number of bits to shift by
Returns:
- ?Int8: left shift operation result
func checkedShr(Int8)
public func checkedShr(y: Int8): ?Int8
Description: Performs right shift operation using the policy of returning Option.
When the number of bits to shift by is greater than or equal to that of operand bits or is less than 0, ?Int8.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int8: number of bits to shift by
Returns:
- ?Int8: right shift operation result
func checkedSub(Int8)
public func checkedSub(y: Int8): ?Int8
Description: Performs subtraction operation using the policy of returning Option.
When an overflow occurs in an operation, ?Int8.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int8: subtrahend
Returns:
- ?Int8: subtraction operation result
extend IntNative <: CheckedOp<IntNative>
extend IntNative <: CheckedOp<IntNative>
Description: Implements the CheckedOp interface for IntNative.
Parent Type:
func checkedAdd(IntNative)
public func checkedAdd(y: IntNative): ?IntNative
Description: Performs addition operation using the policy of returning Option.
When an overflow occurs in an operation, ?IntNative.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: IntNative: addend
Returns:
- ?IntNative: addition operation result
func checkedDec()
public func checkedDec(): ?IntNative
Description: Performs auto-decrement operation using the policy of returning Option.
When an overflow occurs in an operation, ?IntNative.None is returned. Otherwise, the operation result is returned.
Returns:
- ?IntNative: auto-decrement operation result
func checkedDiv(IntNative)
public func checkedDiv(y: IntNative): ?IntNative
Description: Performs division operation using the policy of returning Option.
When an overflow occurs in an operation, ?IntNative.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: IntNative: divisor
Returns:
- ?IntNative: division operation result
func checkedInc()
public func checkedInc(): ?IntNative
Description: Performs auto-increment operation using the policy of returning Option.
When an overflow occurs in an operation, ?IntNative.None is returned. Otherwise, the operation result is returned.
Returns:
- ?IntNative: auto-increment operation result
func checkedMod(IntNative)
public func checkedMod(y: IntNative): ?IntNative
Description: Performs modulo operation using the policy of returning Option.
When an overflow occurs in an operation, ?IntNative.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: IntNative: divisor
Returns:
- ?IntNative: modulo operation result
func checkedMul(IntNative)
public func checkedMul(y: IntNative): ?IntNative
Description: Performs multiplication operation using the policy of returning Option.
When an overflow occurs in an operation, ?IntNative.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: IntNative: multiplier
Returns:
- ?IntNative: multiplication operation result
func checkedNeg()
public func checkedNeg(): ?IntNative
Description: Performs negation operation using the policy of returning Option.
When an overflow occurs in an operation, ?IntNative.None is returned. Otherwise, the operation result is returned.
Returns:
- ?IntNative: negation operation result
func checkedShl(IntNative)
public func checkedShl(y: IntNative): ?IntNative
Description: Performs left shift operation using the policy of returning Option.
When the number of bits to shift by is greater than or equal to that of operand bits or is less than 0, ?IntNative.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: IntNative: number of bits to shift by
Returns:
- ?IntNative: left shift operation result
func checkedShr(IntNative)
public func checkedShr(y: IntNative): ?IntNative
Description: Performs right shift operation using the policy of returning Option.
When the number of bits to shift by is greater than or equal to that of operand bits or is less than 0, ?IntNative.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: IntNative: number of bits to shift by
Returns:
- ?IntNative: right shift operation result
func checkedSub(IntNative)
public func checkedSub(y: IntNative): ?IntNative
Description: Performs subtraction operation using the policy of returning Option.
When an overflow occurs in an operation, ?IntNative.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: IntNative: subtrahend
Returns:
- ?IntNative: subtraction operation result
extend UInt16 <: CheckedOp<UInt16>
extend UInt16 <: CheckedOp<UInt16>
Description: Implements the CheckedOp interface for UInt16.
Parent Type:
func checkedAdd(UInt16)
public func checkedAdd(y: UInt16): ?UInt16
Description: Performs addition operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt16.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt16: addend
Returns:
- ?UInt16: addition operation result
func checkedDec()
public func checkedDec(): ?UInt16
Description: Performs auto-decrement operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt16.None is returned. Otherwise, the operation result is returned.
Returns:
- ?UInt16: auto-decrement operation result
func checkedDiv(UInt16)
public func checkedDiv(y: UInt16): ?UInt16
Description: Performs division operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt16.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt16: divisor
Returns:
- ?UInt16: division operation result
func checkedInc()
public func checkedInc(): ?UInt16
Description: Performs auto-increment operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt16.None is returned. Otherwise, the operation result is returned.
Returns:
- ?UInt16: auto-increment operation result
func checkedMod(UInt16)
public func checkedMod(y: UInt16): ?UInt16
Description: Performs modulo operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt16.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt16: divisor
Returns:
- ?UInt16: modulo operation result
func checkedMul(UInt16)
public func checkedMul(y: UInt16): ?UInt16
Description: Performs multiplication operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt16.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt16: multiplier
Returns:
- ?UInt16: multiplication operation result
func checkedNeg()
public func checkedNeg(): ?UInt16
Description: Performs negation operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt16.None is returned. Otherwise, the operation result is returned.
Returns:
- ?UInt16: negation operation result
func checkedShl(UInt16)
public func checkedShl(y: UInt16): ?UInt16
Description: Performs left shift operation using the policy of returning Option.
When the number of bits to shift by is greater than or equal to that of operand bits, ?UInt16.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt16: number of bits to shift by
Returns:
- ?UInt16: left shift operation result
func checkedShr(UInt16)
public func checkedShr(y: UInt16): ?UInt16
Description: Performs right shift operation using the policy of returning Option.
When the number of bits to shift by is greater than or equal to that of operand bits, ?UInt16.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt16: number of bits to shift by
Returns:
- ?UInt16: right shift operation result
func checkedSub(UInt16)
public func checkedSub(y: UInt16): ?UInt16
Description: Performs subtraction operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt16.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt16: subtrahend
Returns:
- ?UInt16: subtraction operation result
extend UInt32 <: CheckedOp<UInt32>
extend UInt32 <: CheckedOp<UInt32>
Description: Implements the CheckedOp interface for UInt32.
Parent Type:
func checkedAdd(UInt32)
public func checkedAdd(y: UInt32): ?UInt32
Description: Performs addition operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt32.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt32: addend
Returns:
- ?UInt32: addition operation result
func checkedDec()
public func checkedDec(): ?UInt32
Description: Performs auto-decrement operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt32.None is returned. Otherwise, the operation result is returned.
Returns:
- ?UInt32: auto-decrement operation result
func checkedDiv(UInt32)
public func checkedDiv(y: UInt32): ?UInt32
Description: Performs division operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt32.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt32: divisor
Returns:
- ?UInt32: division operation result
func checkedInc()
public func checkedInc(): ?UInt32
Description: Performs auto-increment operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt32.None is returned. Otherwise, the operation result is returned.
Returns:
- ?UInt32: auto-increment operation result
func checkedMod(UInt32)
public func checkedMod(y: UInt32): ?UInt32
Description: Performs modulo operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt32.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt32: divisor
Returns:
- ?UInt32: modulo operation result
func checkedMul(UInt32)
public func checkedMul(y: UInt32): ?UInt32
Description: Performs multiplication operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt32.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt32: multiplier
Returns:
- ?UInt32: multiplication operation result
func checkedNeg()
public func checkedNeg(): ?UInt32
Description: Performs negation operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt32.None is returned. Otherwise, the operation result is returned.
Returns:
- ?UInt32: negation operation result
func checkedShl(UInt32)
public func checkedShl(y: UInt32): ?UInt32
Description: Performs left shift operation using the policy of returning Option.
When the number of bits to shift by is greater than or equal to that of operand bits, ?UInt32.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt32: number of bits to shift by
Returns:
- ?UInt32: left shift operation result
func checkedShr(UInt32)
public func checkedShr(y: UInt32): ?UInt32
Description: Performs right shift operation using the policy of returning Option.
When the number of bits to shift by is greater than or equal to that of operand bits, ?UInt32.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt32: number of bits to shift by
Returns:
- ?UInt32: right shift operation result
func checkedSub(UInt32)
public func checkedSub(y: UInt32): ?UInt32
Description: Performs subtraction operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt32.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt32: subtrahend
Returns:
- ?UInt32: subtraction operation result
extend UInt64 <: CheckedOp<UInt64>
extend UInt64 <: CheckedOp<UInt64>
Description: Implements the CheckedOp interface for UInt64.
Parent Type:
func checkedAdd(UInt64)
public func checkedAdd(y: UInt64): ?UInt64
Description: Performs addition operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt64.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt64: addend
Returns:
- ?UInt64: addition operation result
func checkedDec()
public func checkedDec(): ?UInt64
Description: Performs auto-decrement operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt64.None is returned. Otherwise, the operation result is returned.
Returns:
- ?UInt64: auto-decrement operation result
func checkedDiv(UInt64)
public func checkedDiv(y: UInt64): ?UInt64
Description: Performs division operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt64.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt64: divisor
Returns:
- ?UInt64: division operation result
func checkedInc()
public func checkedInc(): ?UInt64
Description: Performs auto-increment operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt64.None is returned. Otherwise, the operation result is returned.
Returns:
- ?UInt64: auto-increment operation result
func checkedMod(UInt64)
public func checkedMod(y: UInt64): ?UInt64
Description: Performs modulo operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt64.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt64: divisor
Returns:
- ?UInt64: modulo operation result
func checkedMul(UInt64)
public func checkedMul(y: UInt64): ?UInt64
Description: Performs multiplication operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt64.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt64: multiplier
Returns:
- ?UInt64: multiplication operation result
func checkedNeg()
public func checkedNeg(): ?UInt64
Description: Performs negation operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt64.None is returned. Otherwise, the operation result is returned.
Returns:
- ?UInt64: negation operation result
func checkedShl(UInt64)
public func checkedShl(y: UInt64): ?UInt64
Description: Performs left shift operation using the policy of returning Option.
When the number of bits to shift by is greater than or equal to that of operand bits, ?UInt64.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt64: number of bits to shift by
Returns:
- ?UInt64: left shift operation result
func checkedShr(UInt64)
public func checkedShr(y: UInt64): ?UInt64
Description: Performs right shift operation using the policy of returning Option.
When the number of bits to shift by is greater than or equal to that of operand bits, ?UInt64.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt64: number of bits to shift by
Returns:
- ?UInt64: right shift operation result
func checkedSub(UInt64)
public func checkedSub(y: UInt64): ?UInt64
Description: Performs subtraction operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt64.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt64: subtrahend
Returns:
- ?UInt64: subtraction operation result
extend UInt8 <: CheckedOp<UInt8>
extend UInt8 <: CheckedOp<UInt8>
Description: Implements the CheckedOp interface for UInt8.
Parent Type:
func checkedAdd(UInt8)
public func checkedAdd(y: UInt8): ?UInt8
Description: Performs addition operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt8.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt8: addend
Returns:
- ?UInt8: addition operation result
func checkedDec()
public func checkedDec(): ?UInt8
Description: Performs auto-decrement operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt8.None is returned. Otherwise, the operation result is returned.
Returns:
- ?UInt8: auto-decrement operation result
func checkedDiv(UInt8)
public func checkedDiv(y: UInt8): ?UInt8
Description: Performs division operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt8.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt8: divisor
Returns:
- ?UInt8: division operation result
func checkedInc()
public func checkedInc(): ?UInt8
Description: Performs auto-increment operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt8.None is returned. Otherwise, the operation result is returned.
Returns:
- ?UInt8: auto-increment operation result
func checkedMod(UInt8)
public func checkedMod(y: UInt8): ?UInt8
Description: Performs modulo operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt8.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt8: divisor
Returns:
- ?UInt8: modulo operation result
func checkedMul(UInt8)
public func checkedMul(y: UInt8): ?UInt8
Description: Performs multiplication operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt8.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt8: multiplier
Returns:
- ?UInt8: multiplication operation result
func checkedNeg()
public func checkedNeg(): ?UInt8
Description: Performs negation operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt8.None is returned. Otherwise, the operation result is returned.
Returns:
- ?UInt8: negation operation result
func checkedShl(UInt8)
public func checkedShl(y: UInt8): ?UInt8
Description: Performs left shift operation using the policy of returning Option.
When the number of bits to shift by is greater than or equal to that of operand bits, ?UInt8.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt8: number of bits to shift by
Returns:
- ?UInt8: left shift operation result
func checkedShr(UInt8)
public func checkedShr(y: UInt8): ?UInt8
Description: Performs right shift operation using the policy of returning Option.
When the number of bits to shift by is greater than or equal to that of operand bits, ?UInt8.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt8: number of bits to shift by
Returns:
- ?UInt8: right shift operation result
func checkedSub(UInt8)
public func checkedSub(y: UInt8): ?UInt8
Description: Performs subtraction operation using the policy of returning Option.
When an overflow occurs in an operation, ?UInt8.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt8: subtrahend
Returns:
- ?UInt8: subtraction operation result
extend UIntNative <: CheckedOp<UIntNative>
extend UIntNative <: CheckedOp<UIntNative>
Description: Implements the CheckedOp interface for UIntNative.
Parent Type:
func checkedAdd(UIntNative)
public func checkedAdd(y: UIntNative): ?UIntNative
Description: Performs addition operation using the policy of returning Option.
When an overflow occurs in an operation, ?UIntNative.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UIntNative: addend
Returns:
- ?UIntNative: addition operation result
func checkedDec()
public func checkedDec(): ?UIntNative
Description: Performs auto-decrement operation using the policy of returning Option.
When an overflow occurs in an operation, ?UIntNative.None is returned. Otherwise, the operation result is returned.
Returns:
- ?UIntNative: auto-decrement operation result
func checkedDiv(UIntNative)
public func checkedDiv(y: UIntNative): ?UIntNative
Description: Performs division operation using the policy of returning Option.
When an overflow occurs in an operation, ?UIntNative.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UIntNative: divisor
Returns:
- ?UIntNative: division operation result
func checkedInc()
public func checkedInc(): ?UIntNative
Description: Performs auto-increment operation using the policy of returning Option.
When an overflow occurs in an operation, ?UIntNative.None is returned. Otherwise, the operation result is returned.
Returns:
- ?UIntNative: auto-increment operation result
func checkedMod(UIntNative)
public func checkedMod(y: UIntNative): ?UIntNative
Description: Performs modulo operation using the policy of returning Option.
When an overflow occurs in an operation, ?UIntNative.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UIntNative: divisor
Returns:
- ?UIntNative: modulo operation result
func checkedMul(UIntNative)
public func checkedMul(y: UIntNative): ?UIntNative
Description: Performs multiplication operation using the policy of returning Option.
When an overflow occurs in an operation, ?UIntNative.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UIntNative: multiplier
Returns:
- ?UIntNative: multiplication operation result
func checkedNeg()
public func checkedNeg(): ?UIntNative
Description: Performs negation operation using the policy of returning Option.
When an overflow occurs in an operation, ?UIntNative.None is returned. Otherwise, the operation result is returned.
Returns:
- ?UIntNative: negation operation result
func checkedShl(UIntNative)
public func checkedShl(y: UIntNative): ?UIntNative
Description: Performs left shift operation using the policy of returning Option.
When the number of bits to shift by is greater than or equal to that of operand bits, ?UIntNative.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UIntNative: number of bits to shift by
Returns:
- ?UIntNative: left shift operation result
func checkedShr(UIntNative)
public func checkedShr(y: UIntNative): ?UIntNative
Description: Performs right shift operation using the policy of returning Option.
When the number of bits to shift by is greater than or equal to that of operand bits, ?UIntNative.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UIntNative: number of bits to shift by
Returns:
- ?UIntNative: right shift operation result
func checkedSub(UIntNative)
public func checkedSub(y: UIntNative): ?UIntNative
Description: Performs subtraction operation using the policy of returning Option.
When an overflow occurs in an operation, ?UIntNative.None is returned. Otherwise, the operation result is returned.
Parameters:
- y: UIntNative: subtrahend
Returns:
- ?UIntNative: subtraction operation result
interface SaturatingOp<T>
public interface SaturatingOp<T> {
func saturatingAdd(y: T): T
func saturatingDec(): T
func saturatingDiv(y: T): T
func saturatingInc(): T
func saturatingMod(y: T): T
func saturatingMul(y: T): T
func saturatingNeg(): T
func saturatingShl(y: T): T
func saturatingShr(y: T): T
func saturatingSub(y: T): T
}
Description: Performs saturation operation when an overflow occurs in an integer operation.
func saturatingAdd(T)
func saturatingAdd(y: T): T
Description: Performs addition operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: T: addend
Returns:
- T: addition operation result
func saturatingDec()
func saturatingDec(): T
Description: Performs auto-decrement operation using the saturation policy.
When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- T: auto-decrement operation result
func saturatingDiv(T)
func saturatingDiv(y: T): T
Description: Performs division operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: T: divisor
Returns:
- T: division operation result
func saturatingInc()
func saturatingInc(): T
Description: Performs auto-increment operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- T: auto-increment operation result
func saturatingMod(T)
func saturatingMod(y: T): T
Description: Performs modulo operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: T: divisor
Returns:
- T: modulo operation result
func saturatingMul(T)
func saturatingMul(y: T): T
Description: Performs multiplication operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: T: multiplier
Returns:
- T: multiplication operation result
func saturatingNeg()
func saturatingNeg(): T
Description: Performs negation operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- T: negation operation result
func saturatingShl(T)
func saturatingShl(y: T): T
Description: Performs left shift operation using the saturation policy.
When the number of bits to shift by is greater than or equal to that of operand bits, the number of bits to shift by is set to the number of operand bits minus 1. When the number of bits to shift by is less than 0, it is set to 0. Otherwise, the operation result is returned.
Parameters:
- y: T: number of bits to shift by
Returns:
- T: left shift operation result
func saturatingShr(T)
func saturatingShr(y: T): T
Description: Performs right shift operation using the saturation policy.
When the number of bits to shift by is greater than or equal to that of operand bits, the number of bits to shift by is set to the number of operand bits minus 1. When the number of bits to shift by is less than 0, it is set to 0. Otherwise, the operation result is returned.
Parameters:
- y: T: number of bits to shift by
Returns:
- T: right shift operation result
func saturatingSub(T)
func saturatingSub(y: T): T
Description: Performs subtraction operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: T: subtrahend
Returns:
- T: subtraction operation result
extend Int16 <: SaturatingOp<Int16>
extend Int16 <: SaturatingOp<Int16>
Description: Implements the SaturatingOp interface for Int16.
Parent Type:
func saturatingAdd(Int16)
public func saturatingAdd(y: Int16): Int16
Description: Performs addition operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int16: addend
Returns:
- Int16: addition operation result
func saturatingDec()
public func saturatingDec(): Int16
Description: Performs auto-decrement operation using the saturation policy.
When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- Int16: auto-decrement operation result
func saturatingDiv(Int16)
public func saturatingDiv(y: Int16): Int16
Description: Performs division operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int16: divisor
Returns:
- Int16: division operation result
func saturatingInc()
public func saturatingInc(): Int16
Description: Performs auto-increment operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- Int16: auto-increment operation result
func saturatingMod(Int16)
public func saturatingMod(y: Int16): Int16
Description: Performs modulo operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int16: divisor
Returns:
- Int16: modulo operation result
func saturatingMul(Int16)
public func saturatingMul(y: Int16): Int16
Description: Performs multiplication operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int16: multiplier
Returns:
- Int16: multiplication operation result
func saturatingNeg()
public func saturatingNeg(): Int16
Description: Performs negation operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- Int16: negation operation result
func saturatingShl(Int16)
public func saturatingShl(y: Int16): Int16
Description: Performs left shift operation using the saturation policy.
When the number of bits to shift by is greater than or equal to that of operand bits, the number of bits to shift by is set to the number of operand bits minus 1. When the number of bits to shift by is less than 0, it is set to 0. Otherwise, the operation result is returned.
Parameters:
- y: Int16: number of bits to shift by
Returns:
- Int16: left shift operation result
func saturatingShr(Int16)
public func saturatingShr(y: Int16): Int16
Description: Performs right shift operation using the saturation policy.
When the number of bits to shift by is greater than or equal to that of operand bits, the number of bits to shift by is set to the number of operand bits minus 1. When the number of bits to shift by is less than 0, it is set to 0. Otherwise, the operation result is returned.
Parameters:
- y: Int16: number of bits to shift by
Returns:
- Int16: right shift operation result
func saturatingSub(Int16)
public func saturatingSub(y: Int16): Int16
Description: Performs subtraction operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int16: subtrahend
Returns:
- Int16: subtraction operation result
extend Int32 <: SaturatingOp<Int32>
extend Int32 <: SaturatingOp<Int32>
Description: Implements the SaturatingOp interface for Int32.
Parent Type:
func saturatingAdd(Int32)
public func saturatingAdd(y: Int32): Int32
Description: Performs addition operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int32: addend
Returns:
- Int32: addition operation result
func saturatingDec()
public func saturatingDec(): Int32
Description: Performs auto-decrement operation using the saturation policy.
When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- Int32: auto-decrement operation result
func saturatingDiv(Int32)
public func saturatingDiv(y: Int32): Int32
Description: Performs division operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int32: divisor
Returns:
- Int32: division operation result
func saturatingInc()
public func saturatingInc(): Int32
Description: Performs auto-increment operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- Int32: auto-increment operation result
func saturatingMod(Int32)
public func saturatingMod(y: Int32): Int32
Description: Performs modulo operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int32: divisor
Returns:
- Int32: modulo operation result
func saturatingMul(Int32)
public func saturatingMul(y: Int32): Int32
Description: Performs multiplication operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int32: multiplier
Returns:
- Int32: multiplication operation result
func saturatingNeg()
public func saturatingNeg(): Int32
Description: Performs negation operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- Int32: negation operation result
func saturatingShl(Int32)
public func saturatingShl(y: Int32): Int32
Description: Performs left shift operation using the saturation policy.
When the number of bits to shift by is greater than or equal to that of operand bits, the number of bits to shift by is set to the number of operand bits minus 1. When the number of bits to shift by is less than 0, it is set to 0. Otherwise, the operation result is returned.
Parameters:
- y: Int32: number of bits to shift by
Returns:
- Int32: left shift operation result
func saturatingShr(Int32)
public func saturatingShr(y: Int32): Int32
Description: Performs right shift operation using the saturation policy.
When the number of bits to shift by is greater than or equal to that of operand bits, the number of bits to shift by is set to the number of operand bits minus 1. When the number of bits to shift by is less than 0, it is set to 0. Otherwise, the operation result is returned.
Parameters:
- y: Int32: number of bits to shift by
Returns:
- Int32: right shift operation result
func saturatingSub(Int32)
public func saturatingSub(y: Int32): Int32
Description: Performs subtraction operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int32: subtrahend
Returns:
- Int32: subtraction operation result
extend Int64 <: SaturatingOp<Int64>
extend Int64 <: SaturatingOp<Int64>
Description: Implements the SaturatingOp interface for Int64.
Parent Type:
func saturatingAdd(Int64)
public func saturatingAdd(y: Int64): Int64
Description: Performs addition operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int64: addend
Returns:
- Int64: addition operation result
func saturatingDec()
public func saturatingDec(): Int64
Description: Performs auto-decrement operation using the saturation policy.
When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- Int64: auto-decrement operation result
func saturatingDiv(Int64)
public func saturatingDiv(y: Int64): Int64
Description: Performs division operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int64: divisor
Returns:
- Int64: division operation result
func saturatingInc()
public func saturatingInc(): Int64
Description: Performs auto-increment operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- Int64: auto-increment operation result
func saturatingMod(Int64)
public func saturatingMod(y: Int64): Int64
Description: Performs modulo operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int64: divisor
Returns:
- Int64: modulo operation result
func saturatingMul(Int64)
public func saturatingMul(y: Int64): Int64
Description: Performs multiplication operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int64: multiplier
Returns:
- Int64: multiplication operation result
func saturatingNeg()
public func saturatingNeg(): Int64
Description: Performs negation operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- Int64: negation operation result
func saturatingPow(UInt64)
public func saturatingPow(y: UInt64): Int64
Description: Performs exponentiation operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt64: exponent
Returns:
- Int64: exponentiation operation result
func saturatingShl(Int64)
public func saturatingShl(y: Int64): Int64
Description: Performs left shift operation using the saturation policy.
When the number of bits to shift by is greater than or equal to that of operand bits, the number of bits to shift by is set to the number of operand bits minus 1. When the number of bits to shift by is less than 0, it is set to 0. Otherwise, the operation result is returned.
Parameters:
- y: Int64: number of bits to shift by
Returns:
- Int64: left shift operation result
func saturatingShr(Int64)
public func saturatingShr(y: Int64): Int64
Description: Performs right shift operation using the saturation policy.
When the number of bits to shift by is greater than or equal to that of operand bits, the number of bits to shift by is set to the number of operand bits minus 1. When the number of bits to shift by is less than 0, it is set to 0. Otherwise, the operation result is returned.
Parameters:
- y: Int64: number of bits to shift by
Returns:
- Int64: right shift operation result
func saturatingSub(Int64)
public func saturatingSub(y: Int64): Int64
Description: Performs subtraction operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int64: subtrahend
Returns:
- Int64: subtraction operation result
extend Int8 <: SaturatingOp<Int8>
extend Int8 <: SaturatingOp<Int8>
Description: Implements the SaturatingOp interface for Int8.
Parent Type:
func saturatingAdd(Int8)
public func saturatingAdd(y: Int8): Int8
Description: Performs addition operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int8: addend
Returns:
- Int8: addition operation result
func saturatingDec()
public func saturatingDec(): Int8
Description: Performs auto-decrement operation using the saturation policy.
When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- Int8: auto-decrement operation result
func saturatingDiv(Int8)
public func saturatingDiv(y: Int8): Int8
Description: Performs division operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int8: divisor
Returns:
- Int8: division operation result
func saturatingInc()
public func saturatingInc(): Int8
Description: Performs auto-increment operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- Int8: auto-increment operation result
func saturatingMod(Int8)
public func saturatingMod(y: Int8): Int8
Description: Performs modulo operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int8: divisor
Returns:
- Int8: modulo operation result
func saturatingMul(Int8)
public func saturatingMul(y: Int8): Int8
Description: Performs multiplication operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int8: multiplier
Returns:
- Int8: multiplication operation result
func saturatingNeg()
public func saturatingNeg(): Int8
Description: Performs negation operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- Int8: negation operation result
func saturatingShl(Int8)
public func saturatingShl(y: Int8): Int8
Description: Performs left shift operation using the saturation policy.
When the number of bits to shift by is greater than or equal to that of operand bits, the number of bits to shift by is set to the number of operand bits minus 1. When the number of bits to shift by is less than 0, it is set to 0. Otherwise, the operation result is returned.
Parameters:
- y: Int8: number of bits to shift by
Returns:
- Int8: left shift operation result
func saturatingShr(Int8)
public func saturatingShr(y: Int8): Int8
Description: Performs right shift operation using the saturation policy.
When the number of bits to shift by is greater than or equal to that of operand bits, the number of bits to shift by is set to the number of operand bits minus 1. When the number of bits to shift by is less than 0, it is set to 0. Otherwise, the operation result is returned.
Parameters:
- y: Int8: number of bits to shift by
Returns:
- Int8: right shift operation result
func saturatingSub(Int8)
public func saturatingSub(y: Int8): Int8
Description: Performs subtraction operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: Int8: subtrahend
Returns:
- Int8: subtraction operation result
extend IntNative <: SaturatingOp<IntNative>
extend IntNative <: SaturatingOp<IntNative>
Description: Implements the SaturatingOp interface for IntNative.
Parent Type:
func saturatingAdd(IntNative)
public func saturatingAdd(y: IntNative): IntNative
Description: Performs addition operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: IntNative: addend
Returns:
- IntNative: addition operation result
func saturatingDec()
public func saturatingDec(): IntNative
Description: Performs auto-decrement operation using the saturation policy.
When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- IntNative: auto-decrement operation result
func saturatingDiv(IntNative)
public func saturatingDiv(y: IntNative): IntNative
Description: Performs division operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: IntNative: divisor
Returns:
- IntNative: division operation result
func saturatingInc()
public func saturatingInc(): IntNative
Description: Performs auto-increment operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- IntNative: auto-increment operation result
func saturatingMod(IntNative)
public func saturatingMod(y: IntNative): IntNative
Description: Performs modulo operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: IntNative: divisor
Returns:
- IntNative: modulo operation result
func saturatingMul(IntNative)
public func saturatingMul(y: IntNative): IntNative
Description: Performs multiplication operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: IntNative: multiplier
Returns:
- IntNative: multiplication operation result
func saturatingNeg()
public func saturatingNeg(): IntNative
Description: Performs negation operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- IntNative: negation operation result
func saturatingShl(IntNative)
public func saturatingShl(y: IntNative): IntNative
Description: Performs left shift operation using the saturation policy.
When the number of bits to shift by is greater than or equal to that of operand bits, the number of bits to shift by is set to the number of operand bits minus 1. When the number of bits to shift by is less than 0, it is set to 0. Otherwise, the operation result is returned.
Parameters:
- y: IntNative: number of bits to shift by
Returns:
- IntNative: left shift operation result
func saturatingShr(IntNative)
public func saturatingShr(y: IntNative): IntNative
Description: Performs right shift operation using the saturation policy.
When the number of bits to shift by is greater than or equal to that of operand bits, the number of bits to shift by is set to the number of operand bits minus 1. When the number of bits to shift by is less than 0, it is set to 0. Otherwise, the operation result is returned.
Parameters:
- y: IntNative: number of bits to shift by
Returns:
- IntNative: right shift operation result
func saturatingSub(IntNative)
public func saturatingSub(y: IntNative): IntNative
Description: Performs subtraction operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: IntNative: subtrahend
Returns:
- IntNative: subtraction operation result
extend UInt16 <: SaturatingOp<UInt16>
extend UInt16 <: SaturatingOp<UInt16>
Description: Implements the SaturatingOp interface for UInt16.
Parent Type:
func saturatingAdd(UInt16)
public func saturatingAdd(y: UInt16): UInt16
Description: Performs addition operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt16: addend
Returns:
- UInt16: addition operation result
func saturatingDec()
public func saturatingDec(): UInt16
Description: Performs auto-decrement operation using the saturation policy.
When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- UInt16: auto-decrement operation result
func saturatingDiv(UInt16)
public func saturatingDiv(y: UInt16): UInt16
Description: Performs division operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt16: divisor
Returns:
- UInt16: division operation result
func saturatingInc()
public func saturatingInc(): UInt16
Description: Performs auto-increment operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- UInt16: auto-increment operation result
func saturatingMod(UInt16)
public func saturatingMod(y: UInt16): UInt16
Description: Performs modulo operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt16: divisor
Returns:
- UInt16: modulo operation result
func saturatingMul(UInt16)
public func saturatingMul(y: UInt16): UInt16
Description: Performs multiplication operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt16: multiplier
Returns:
- UInt16: multiplication operation result
func saturatingNeg()
public func saturatingNeg(): UInt16
Description: Performs negation operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- UInt16: negation operation result
func saturatingShl(UInt16)
public func saturatingShl(y: UInt16): UInt16
Description: Performs left shift operation using the saturation policy.
When the number of bits to shift by is greater than or equal to that of operand bits, the number of bits to shift by is set to the number of operand bits minus 1. When the number of bits to shift by is less than 0, it is set to 0. Otherwise, the operation result is returned.
Parameters:
- y: UInt16: number of bits to shift by
Returns:
- UInt16: left shift operation result
func saturatingShr(UInt16)
public func saturatingShr(y: UInt16): UInt16
Description: Performs right shift operation using the saturation policy.
When the number of bits to shift by is greater than or equal to that of operand bits, the number of bits to shift by is set to the number of operand bits minus 1. When the number of bits to shift by is less than 0, it is set to 0. Otherwise, the operation result is returned.
Parameters:
- y: UInt16: number of bits to shift by
Returns:
- UInt16: right shift operation result
func saturatingSub(UInt16)
public func saturatingSub(y: UInt16): UInt16
Description: Performs subtraction operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt16: subtrahend
Returns:
- UInt16: subtraction operation result
extend UInt32 <: SaturatingOp<UInt32>
extend UInt32 <: SaturatingOp<UInt32>
Description: Implements the SaturatingOp interface for UInt32.
Parent Type:
func saturatingAdd(UInt32)
public func saturatingAdd(y: UInt32): UInt32
Description: Performs addition operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt32: addend
Returns:
- UInt32: addition operation result
func saturatingDec()
public func saturatingDec(): UInt32
Description: Performs auto-decrement operation using the saturation policy.
When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- UInt32: auto-decrement operation result
func saturatingDiv(UInt32)
public func saturatingDiv(y: UInt32): UInt32
Description: Performs division operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt32: divisor
Returns:
- UInt32: division operation result
func saturatingInc()
public func saturatingInc(): UInt32
Description: Performs auto-increment operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- UInt32: auto-increment operation result
func saturatingMod(UInt32)
public func saturatingMod(y: UInt32): UInt32
Description: Performs modulo operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt32: divisor
Returns:
- UInt32: modulo operation result
func saturatingMul(UInt32)
public func saturatingMul(y: UInt32): UInt32
Description: Performs multiplication operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt32: multiplier
Returns:
- UInt32: multiplication operation result
func saturatingNeg()
public func saturatingNeg(): UInt32
Description: Performs negation operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- UInt32: negation operation result
func saturatingShl(UInt32)
public func saturatingShl(y: UInt32): UInt32
Description: Performs left shift operation using the saturation policy.
When the number of bits to shift by is greater than or equal to that of operand bits, the number of bits to shift by is set to the number of operand bits minus 1. When the number of bits to shift by is less than 0, it is set to 0. Otherwise, the operation result is returned.
Parameters:
- y: UInt32: number of bits to shift by
Returns:
- UInt32: left shift operation result
func saturatingShr(UInt32)
public func saturatingShr(y: UInt32): UInt32
Description: Performs right shift operation using the saturation policy.
When the number of bits to shift by is greater than or equal to that of operand bits, the number of bits to shift by is set to the number of operand bits minus 1. When the number of bits to shift by is less than 0, it is set to 0. Otherwise, the operation result is returned.
Parameters:
- y: UInt32: number of bits to shift by
Returns:
- UInt32: right shift operation result
func saturatingSub(UInt32)
public func saturatingSub(y: UInt32): UInt32
Description: Performs subtraction operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt32: subtrahend
Returns:
- UInt32: subtraction operation result
extend UInt64 <: SaturatingOp<UInt64>
extend UInt64 <: SaturatingOp<UInt64>
Description: Implements the SaturatingOp interface for UInt64.
Parent Type:
func saturatingAdd(UInt64)
public func saturatingAdd(y: UInt64): UInt64
Description: Performs addition operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt64: addend
Returns:
- UInt64: addition operation result
func saturatingDec()
public func saturatingDec(): UInt64
Description: Performs auto-decrement operation using the saturation policy.
When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- UInt64: auto-decrement operation result
func saturatingDiv(UInt64)
public func saturatingDiv(y: UInt64): UInt64
Description: Performs division operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt64: divisor
Returns:
- UInt64: division operation result
func saturatingInc()
public func saturatingInc(): UInt64
Description: Performs auto-increment operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- UInt64: auto-increment operation result
func saturatingMod(UInt64)
public func saturatingMod(y: UInt64): UInt64
Description: Performs modulo operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt64: divisor
Returns:
- UInt64: modulo operation result
func saturatingMul(UInt64)
public func saturatingMul(y: UInt64): UInt64
Description: Performs multiplication operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt64: multiplier
Returns:
- UInt64: multiplication operation result
func saturatingNeg()
public func saturatingNeg(): UInt64
Description: Performs negation operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- UInt64: negation operation result
func saturatingShl(UInt64)
public func saturatingShl(y: UInt64): UInt64
Description: Performs left shift operation using the saturation policy.
When the number of bits to shift by is greater than or equal to that of operand bits, the number of bits to shift by is set to the number of operand bits minus 1. When the number of bits to shift by is less than 0, it is set to 0. Otherwise, the operation result is returned.
Parameters:
- y: UInt64: number of bits to shift by
Returns:
- UInt64: left shift operation result
func saturatingShr(UInt64)
public func saturatingShr(y: UInt64): UInt64
Description: Performs right shift operation using the saturation policy.
When the number of bits to shift by is greater than or equal to that of operand bits, the number of bits to shift by is set to the number of operand bits minus 1. When the number of bits to shift by is less than 0, it is set to 0. Otherwise, the operation result is returned.
Parameters:
- y: UInt64: number of bits to shift by
Returns:
- UInt64: right shift operation result
func saturatingSub(UInt64)
public func saturatingSub(y: UInt64): UInt64
Description: Performs subtraction operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt64: subtrahend
Returns:
- UInt64: subtraction operation result
extend UInt8 <: SaturatingOp<UInt8>
extend UInt8 <: SaturatingOp<UInt8>
Description: Implements the SaturatingOp interface for UInt8.
Parent Type:
func saturatingAdd(UInt8)
public func saturatingAdd(y: UInt8): UInt8
Description: Performs addition operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt8: addend
Returns:
- UInt8: addition operation result
func saturatingDec()
public func saturatingDec(): UInt8
Description: Performs auto-decrement operation using the saturation policy.
When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- UInt8: auto-decrement operation result
func saturatingDiv(UInt8)
public func saturatingDiv(y: UInt8): UInt8
Description: Performs division operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt8: divisor
Returns:
- UInt8: division operation result
func saturatingInc()
public func saturatingInc(): UInt8
Description: Performs auto-increment operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- UInt8: auto-increment operation result
func saturatingMod(UInt8)
public func saturatingMod(y: UInt8): UInt8
Description: Performs modulo operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt8: divisor
Returns:
- UInt8: modulo operation result
func saturatingMul(UInt8)
public func saturatingMul(y: UInt8): UInt8
Description: Performs multiplication operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt8: multiplier
Returns:
- UInt8: multiplication operation result
func saturatingNeg()
public func saturatingNeg(): UInt8
Description: Performs negation operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- UInt8: negation operation result
func saturatingShl(UInt8)
public func saturatingShl(y: UInt8): UInt8
Description: Performs left shift operation using the saturation policy.
When the number of bits to shift by is greater than or equal to that of operand bits, the number of bits to shift by is set to the number of operand bits minus 1. When the number of bits to shift by is less than 0, it is set to 0. Otherwise, the operation result is returned.
Parameters:
- y: UInt8: number of bits to shift by
Returns:
- UInt8: left shift operation result
func saturatingShr(UInt8)
public func saturatingShr(y: UInt8): UInt8
Description: Performs right shift operation using the saturation policy.
When the number of bits to shift by is greater than or equal to that of operand bits, the number of bits to shift by is set to the number of operand bits minus 1. When the number of bits to shift by is less than 0, it is set to 0. Otherwise, the operation result is returned.
Parameters:
- y: UInt8: number of bits to shift by
Returns:
- UInt8: right shift operation result
func saturatingSub(UInt8)
public func saturatingSub(y: UInt8): UInt8
Description: Performs subtraction operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: UInt8: subtrahend
Returns:
- UInt8: subtraction operation result
extend UIntNative <: SaturatingOp<UIntNative>
extend UIntNative <: SaturatingOp<UIntNative>
Description: Implements the SaturatingOp interface for UIntNative.
Parent Type:
func saturatingAdd(UIntNative)
public func saturatingAdd(y: UIntNative): UIntNative
Description: Performs addition operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: UIntNative: addend
Returns:
- UIntNative: addition operation result
func saturatingDec()
public func saturatingDec(): UIntNative
Description: Performs auto-decrement operation using the saturation policy.
When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- UIntNative: auto-decrement operation result
func saturatingDiv(UIntNative)
public func saturatingDiv(y: UIntNative): UIntNative
Description: Performs division operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: UIntNative: divisor
Returns:
- UIntNative: division operation result
func saturatingInc()
public func saturatingInc(): UIntNative
Description: Performs auto-increment operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- UIntNative: auto-increment operation result
func saturatingMod(UIntNative)
public func saturatingMod(y: UIntNative): UIntNative
Description: Performs modulo operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: UIntNative: divisor
Returns:
- UIntNative: modulo operation result
func saturatingMul(UIntNative)
public func saturatingMul(y: UIntNative): UIntNative
Description: Performs multiplication operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: UIntNative: multiplier
Returns:
- UIntNative: multiplication operation result
func saturatingNeg()
public func saturatingNeg(): UIntNative
Description: Performs negation operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Returns:
- UIntNative: negation operation result
func saturatingShl(UIntNative)
public func saturatingShl(y: UIntNative): UIntNative
Description: Performs left shift operation using the saturation policy.
When the number of bits to shift by is greater than or equal to that of operand bits, the number of bits to shift by is set to the number of operand bits minus 1. When the number of bits to shift by is less than 0, it is set to 0. Otherwise, the operation result is returned.
Parameters:
- y: UIntNative: number of bits to shift by
Returns:
- UIntNative: left shift operation result
func saturatingShr(UIntNative)
public func saturatingShr(y: UIntNative): UIntNative
Description: Performs right shift operation using the saturation policy.
When the number of bits to shift by is greater than or equal to that of operand bits, the number of bits to shift by is set to the number of operand bits minus 1. When the number of bits to shift by is less than 0, it is set to 0. Otherwise, the operation result is returned.
Parameters:
- y: UIntNative: number of bits to shift by
Returns:
- UIntNative: right shift operation result
func saturatingSub(UIntNative)
public func saturatingSub(y: UIntNative): UIntNative
Description: Performs subtraction operation using the saturation policy.
When an overflow occurs in an operation, the maximum value of the operand type is returned. When an underflow occurs in an operation, the minimum value of the operand type is returned. Otherwise, the operation result is returned.
Parameters:
- y: UIntNative: subtrahend
Returns:
- UIntNative: subtraction operation result
interface ThrowingOp<T>
public interface ThrowingOp<T> {
func throwingAdd(y: T): T
func throwingDec(): T
func throwingDiv(y: T): T
func throwingInc(): T
func throwingMod(y: T): T
func throwingMul(y: T): T
func throwingNeg(): T
func throwingShl(y: T): T
func throwingShr(y: T): T
func throwingSub(y: T): T
}
Description: Throws an exception when an overflow occurs in an integer operation.
func throwingAdd(T)
func throwingAdd(y: T): T
Description: Performs addition operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: T: addend
Returns:
- T: addition operation result
Throws:
- OverflowException: When an overflow occurs in the addition operation, this exception is thrown.
func throwingDec()
func throwingDec(): T
Description: Performs auto-decrement operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- T: auto-decrement operation result
Throws:
- OverflowException: When an overflow occurs in the auto-decrement operation, this exception is thrown.
func throwingDiv(T)
func throwingDiv(y: T): T
Description: Performs division operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: T: divisor
Returns:
- T: division operation result
Throws:
- OverflowException: When an overflow occurs in the division operation, this exception is thrown.
func throwingInc()
func throwingInc(): T
Description: Performs auto-increment operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- T: auto-increment operation result
Throws:
- OverflowException: When an overflow occurs in the auto-increment operation, this exception is thrown.
func throwingMod(T)
func throwingMod(y: T): T
Description: Performs modulo operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: T: divisor
Returns:
- T: modulo operation result
Throws:
- OverflowException: When an overflow occurs in the modulo operation, this exception is thrown.
func throwingMul(T)
func throwingMul(y: T): T
Description: Performs multiplication operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: T: multiplier
Returns:
- T: multiplication operation result
Throws:
- OverflowException: When an overflow occurs in the multiplication operation, this exception is thrown.
func throwingNeg()
func throwingNeg(): T
Description: Performs negation operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- T: negation operation result
Throws:
- OverflowException: When an overflow occurs in the negation operation, this exception is thrown.
func throwingShl(T)
func throwingShl(y: T): T
Description: Performs left shift operation using the exception throwing policy.
When the number of bits to shift by is greater than or equal to that of operand bits or is less than 0, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: T: number of bits to shift by
Returns:
- T: left shift operation result
Throws:
- OvershiftException: When the number of bits to shift by is greater than or equal to that of operand bits, this exception is thrown.
- UndershiftException: When the number of bits to shift by is less than 0, this exception is thrown.
func throwingShr(T)
func throwingShr(y: T): T
Description: Performs right shift operation.
When the number of bits to shift by is greater than or equal to that of operand bits, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: T: number of bits to shift by
Returns:
- T: right shift operation result
Throws:
- OvershiftException: When the number of bits to shift by is greater than or equal to that of operand bits, this exception is thrown.
- UndershiftException: When the number of bits to shift by is less than 0, this exception is thrown.
func throwingSub(T)
func throwingSub(y: T): T
Description: Performs subtraction operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: T: subtrahend
Returns:
- T: subtraction operation result
Throws:
- OverflowException: When an overflow occurs in the subtraction operation, this exception is thrown.
extend Int16 <: ThrowingOp<Int16>
extend Int16 <: ThrowingOp<Int16>
Description: Implements the ThrowingOp interface for Int16.
Parent Type:
func throwingAdd(Int16)
public func throwingAdd(y: Int16): Int16
Description: Performs addition operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: Int16: addend
Returns:
- Int16: addition operation result
Throws:
- OverflowException: When an overflow occurs in the addition operation, this exception is thrown.
func throwingDec()
public func throwingDec(): Int16
Description: Performs auto-decrement operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- Int16: auto-decrement operation result
Throws:
- OverflowException: When an overflow occurs in the auto-decrement operation, this exception is thrown.
func throwingDiv(Int16)
public func throwingDiv(y: Int16): Int16
Description: Performs division operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: Int16: divisor
Returns:
- Int16: division operation result
Throws:
- OverflowException: When an overflow occurs in the division operation, this exception is thrown.
func throwingInc()
public func throwingInc(): Int16
Description: Performs auto-increment operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- Int16: auto-increment operation result
Throws:
- OverflowException: When an overflow occurs in the auto-increment operation, this exception is thrown.
func throwingMod(Int16)
public func throwingMod(y: Int16): Int16
Description: Performs modulo operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: Int16: divisor
Returns:
- Int16: modulo operation result
Throws:
- OverflowException: When an overflow occurs in the modulo operation, this exception is thrown.
func throwingMul(Int16)
public func throwingMul(y: Int16): Int16
Description: Performs multiplication operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: Int16: multiplier
Returns:
- Int16: multiplication operation result
Throws:
- OverflowException: When an overflow occurs in the multiplication operation, this exception is thrown.
func throwingNeg()
public func throwingNeg(): Int16
Description: Performs negation operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- Int16: negation operation result
Throws:
- OverflowException: When an overflow occurs in the negation operation, this exception is thrown.
func throwingShl(Int16)
public func throwingShl(y: Int16): Int16
Description: Performs left shift operation using the exception throwing policy.
When the number of bits to shift by is greater than or equal to that of operand bits or is less than 0, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: Int16: number of bits to shift by
Returns:
- Int16: left shift operation result
Throws:
- OvershiftException: When the number of bits to shift by is greater than or equal to that of operand bits, this exception is thrown.
- UndershiftException: When the number of bits to shift by is less than 0, this exception is thrown.
func throwingShr(Int16)
public func throwingShr(y: Int16): Int16
Description: Performs right shift operation.
When the number of bits to shift by is greater than or equal to that of operand bits, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: Int16: number of bits to shift by
Returns:
- Int16: right shift operation result
Throws:
- OvershiftException: When the number of bits to shift by is greater than or equal to that of operand bits, this exception is thrown.
- UndershiftException: When the number of bits to shift by is less than 0, this exception is thrown.
func throwingSub(Int16)
public func throwingSub(y: Int16): Int16
Description: Performs subtraction operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: Int16: subtrahend
Returns:
- Int16: subtraction operation result
Throws:
- OverflowException: When an overflow occurs in the subtraction operation, this exception is thrown.
extend Int32 <: ThrowingOp<Int32>
extend Int32 <: ThrowingOp<Int32>
Description: Implements the ThrowingOp interface for Int32.
Parent Type:
func throwingAdd(Int32)
public func throwingAdd(y: Int32): Int32
Description: Performs addition operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: Int32: addend
Returns:
- Int32: addition operation result
Throws:
- OverflowException: When an overflow occurs in the addition operation, this exception is thrown.
func throwingDec()
public func throwingDec(): Int32
Description: Performs auto-decrement operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- Int32: auto-decrement operation result
Throws:
- OverflowException: When an overflow occurs in the auto-decrement operation, this exception is thrown.
func throwingDiv(Int32)
public func throwingDiv(y: Int32): Int32
Description: Performs division operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: Int32: divisor
Returns:
- Int32: division operation result
Throws:
- OverflowException: When an overflow occurs in the division operation, this exception is thrown.
func throwingInc()
public func throwingInc(): Int32
Description: Performs auto-increment operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- Int32: auto-increment operation result
Throws:
- OverflowException: When an overflow occurs in the auto-increment operation, this exception is thrown.
func throwingMod(Int32)
public func throwingMod(y: Int32): Int32
Description: Performs modulo operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: Int32: divisor
Returns:
- Int32: modulo operation result
Throws:
- OverflowException: When an overflow occurs in the modulo operation, this exception is thrown.
func throwingMul(Int32)
public func throwingMul(y: Int32): Int32
Description: Performs multiplication operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: Int32: multiplier
Returns:
- Int32: multiplication operation result
Throws:
- OverflowException: When an overflow occurs in the multiplication operation, this exception is thrown.
func throwingNeg()
public func throwingNeg(): Int32
Description: Performs negation operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- Int32: negation operation result
Throws:
- OverflowException: When an overflow occurs in the negation operation, this exception is thrown.
func throwingShl(Int32)
public func throwingShl(y: Int32): Int32
Description: Performs left shift operation using the exception throwing policy.
When the number of bits to shift by is greater than or equal to that of operand bits or is less than 0, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: Int32: number of bits to shift by
Returns:
- Int32: left shift operation result
Throws:
- OvershiftException: When the number of bits to shift by is greater than or equal to that of operand bits, this exception is thrown.
- UndershiftException: When the number of bits to shift by is less than 0, this exception is thrown.
func throwingShr(Int32)
public func throwingShr(y: Int32): Int32
Description: Performs right shift operation.
When the number of bits to shift by is greater than or equal to that of operand bits, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: Int32: number of bits to shift by
Returns:
- Int32: right shift operation result
Throws:
- OvershiftException: When the number of bits to shift by is greater than or equal to that of operand bits, this exception is thrown.
- UndershiftException: When the number of bits to shift by is less than 0, this exception is thrown.
func throwingSub(Int32)
public func throwingSub(y: Int32): Int32
Description: Performs subtraction operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: Int32: subtrahend
Returns:
- Int32: subtraction operation result
Throws:
- OverflowException: When an overflow occurs in the subtraction operation, this exception is thrown.
extend Int64 <: ThrowingOp
extend Int64 <: ThrowingOp<Int64>
Description: Implements the ThrowingOp interface for Int64.
Parent Type:
func throwingAdd(Int64)
public func throwingAdd(y: Int64): Int64
Description: Performs addition operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: Int64: addend
Returns:
- Int64: addition operation result
Throws:
- OverflowException: When an overflow occurs in the addition operation, this exception is thrown.
func throwingDec()
public func throwingDec(): Int64
Description: Performs auto-decrement operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- Int64: auto-decrement operation result
Throws:
- OverflowException: When an overflow occurs in the auto-decrement operation, this exception is thrown.
func throwingDiv(Int64)
public func throwingDiv(y: Int64): Int64
Description: Performs division operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: Int64: divisor
Returns:
- Int64: division operation result
Throws:
- OverflowException: When an overflow occurs in the division operation, this exception is thrown.
func throwingInc()
public func throwingInc(): Int64
Description: Performs auto-increment operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- Int64: auto-increment operation result
Throws:
- OverflowException: When an overflow occurs in the auto-increment operation, this exception is thrown.
func throwingMod(Int64)
public func throwingMod(y: Int64): Int64
Description: Performs modulo operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: Int64: divisor
Returns:
- Int64: modulo operation result
Throws:
- OverflowException: When an overflow occurs in the modulo operation, this exception is thrown.
func throwingMul(Int64)
public func throwingMul(y: Int64): Int64
Description: Performs multiplication operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: Int64: multiplier
Returns:
- Int64: multiplication operation result
Throws:
- OverflowException: When an overflow occurs in the multiplication operation, this exception is thrown.
func throwingNeg()
public func throwingNeg(): Int64
Description: Performs negation operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- Int64: negation operation result
Throws:
- OverflowException: When an overflow occurs in the negation operation, this exception is thrown.
func throwingPow(UInt64)
public func throwingPow(y: UInt64): Int64
Description: Performs exponentiation operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UInt64: exponent
Returns:
- Int64: exponentiation operation result
Throws:
- OverflowException: When an overflow occurs in the exponentiation operation, this exception is thrown.
func throwingShl(Int64)
public func throwingShl(y: Int64): Int64
Description: Performs left shift operation using the exception throwing policy.
When the number of bits to shift by is greater than or equal to that of operand bits or is less than 0, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: Int64: number of bits to shift by
Returns:
- Int64: left shift operation result
Throws:
- OvershiftException: When the number of bits to shift by is greater than or equal to that of operand bits, this exception is thrown.
- UndershiftException: When the number of bits to shift by is less than 0, this exception is thrown.
func throwingShr(Int64)
public func throwingShr(y: Int64): Int64
Description: Performs right shift operation.
When the number of bits to shift by is greater than or equal to that of operand bits, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: Int64: number of bits to shift by
Returns:
- Int64: right shift operation result
Throws:
- OvershiftException: When the number of bits to shift by is greater than or equal to that of operand bits, this exception is thrown.
- UndershiftException: When the number of bits to shift by is less than 0, this exception is thrown.
func throwingSub(Int64)
public func throwingSub(y: Int64): Int64
Description: Performs subtraction operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: Int64: subtrahend
Returns:
- Int64: subtraction operation result
Throws:
- OverflowException: When an overflow occurs in the subtraction operation, this exception is thrown.
extend Int8 <: ThrowingOp<Int8>
extend Int8 <: ThrowingOp<Int8>
Description: Implements the ThrowingOp interface for Int8.
Parent Type:
func throwingAdd(Int8)
public func throwingAdd(y: Int8): Int8
Description: Performs addition operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: Int8: addend
Returns:
- Int8: addition operation result
Throws:
- OverflowException: When an overflow occurs in the addition operation, this exception is thrown.
func throwingDec()
public func throwingDec(): Int8
Description: Performs auto-decrement operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- Int8: auto-decrement operation result
Throws:
- OverflowException: When an overflow occurs in the auto-decrement operation, this exception is thrown.
func throwingDiv(Int8)
public func throwingDiv(y: Int8): Int8
Description: Performs division operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: Int8: divisor
Returns:
- Int8: division operation result
Throws:
- OverflowException: When an overflow occurs in the division operation, this exception is thrown.
func throwingInc()
public func throwingInc(): Int8
Description: Performs auto-increment operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- Int8: auto-increment operation result
Throws:
- OverflowException: When an overflow occurs in the auto-increment operation, this exception is thrown.
func throwingMod(Int8)
public func throwingMod(y: Int8): Int8
Description: Performs modulo operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: Int8: divisor
Returns:
- Int8: modulo operation result
Throws:
- OverflowException: When an overflow occurs in the modulo operation, this exception is thrown.
func throwingMul(Int8)
public func throwingMul(y: Int8): Int8
Description: Performs multiplication operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: Int8: multiplier
Returns:
- Int8: multiplication operation result
Throws:
- OverflowException: When an overflow occurs in the multiplication operation, this exception is thrown.
func throwingNeg()
public func throwingNeg(): Int8
Description: Performs negation operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- Int8: negation operation result
Throws:
- OverflowException: When an overflow occurs in the negation operation, this exception is thrown.
func throwingShl(Int8)
public func throwingShl(y: Int8): Int8
Description: Performs left shift operation using the exception throwing policy.
When the number of bits to shift by is greater than or equal to that of operand bits or is less than 0, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: Int8: number of bits to shift by
Returns:
- Int8: left shift operation result
Throws:
- OvershiftException: When the number of bits to shift by is greater than or equal to that of operand bits, this exception is thrown.
- UndershiftException: When the number of bits to shift by is less than 0, this exception is thrown.
func throwingShr(Int8)
public func throwingShr(y: Int8): Int8
Description: Performs right shift operation.
When the number of bits to shift by is greater than or equal to that of operand bits, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: Int8: number of bits to shift by
Returns:
- Int8: right shift operation result
Throws:
- OvershiftException: When the number of bits to shift by is greater than or equal to that of operand bits, this exception is thrown.
- UndershiftException: When the number of bits to shift by is less than 0, this exception is thrown.
func throwingSub(Int8)
public func throwingSub(y: Int8): Int8
Description: Performs subtraction operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: Int8: subtrahend
Returns:
- Int8: subtraction operation result
Throws:
- OverflowException: When an overflow occurs in the subtraction operation, this exception is thrown.
extend IntNative <: ThrowingOp<IntNative>
extend IntNative <: ThrowingOp<IntNative>
Description: Implements the ThrowingOp interface for IntNative.
Parent Type:
func throwingAdd(IntNative)
public func throwingAdd(y: IntNative): IntNative
Description: Performs addition operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: IntNative: addend
Returns:
- IntNative: addition operation result
Throws:
- OverflowException: When an overflow occurs in the addition operation, this exception is thrown.
func throwingDec()
public func throwingDec(): IntNative
Description: Performs auto-decrement operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- IntNative: auto-decrement operation result
Throws:
- OverflowException: When an overflow occurs in the auto-decrement operation, this exception is thrown.
func throwingDiv(IntNative)
public func throwingDiv(y: IntNative): IntNative
Description: Performs division operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: IntNative: divisor
Returns:
- IntNative: division operation result
Throws:
- OverflowException: When an overflow occurs in the division operation, this exception is thrown.
func throwingInc()
public func throwingInc(): IntNative
Description: Performs auto-increment operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- IntNative: auto-increment operation result
Throws:
- OverflowException: When an overflow occurs in the auto-increment operation, this exception is thrown.
func throwingMod(IntNative)
public func throwingMod(y: IntNative): IntNative
Description: Performs modulo operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: IntNative: divisor
Returns:
- IntNative: modulo operation result
Throws:
- OverflowException: When an overflow occurs in the modulo operation, this exception is thrown.
func throwingMul(IntNative)
public func throwingMul(y: IntNative): IntNative
Description: Performs multiplication operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: IntNative: multiplier
Returns:
- IntNative: multiplication operation result
Throws:
- OverflowException: When an overflow occurs in the multiplication operation, this exception is thrown.
func throwingNeg()
public func throwingNeg(): IntNative
Description: Performs negation operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- IntNative: negation operation result
Throws:
- OverflowException: When an overflow occurs in the negation operation, this exception is thrown.
func throwingShl(IntNative)
public func throwingShl(y: IntNative): IntNative
Description: Performs left shift operation using the exception throwing policy.
When the number of bits to shift by is greater than or equal to that of operand bits or is less than 0, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: IntNative: number of bits to shift by
Returns:
- IntNative: left shift operation result
Throws:
- OvershiftException: When the number of bits to shift by is greater than or equal to that of operand bits, this exception is thrown.
- UndershiftException: When the number of bits to shift by is less than 0, this exception is thrown.
func throwingShr(IntNative)
public func throwingShr(y: IntNative): IntNative
Description: Performs right shift operation.
When the number of bits to shift by is greater than or equal to that of operand bits, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: IntNative: number of bits to shift by
Returns:
- IntNative: right shift operation result
Throws:
- OvershiftException: When the number of bits to shift by is greater than or equal to that of operand bits, this exception is thrown.
- UndershiftException: When the number of bits to shift by is less than 0, this exception is thrown.
func throwingSub(IntNative)
public func throwingSub(y: IntNative): IntNative
Description: Performs subtraction operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: IntNative: subtrahend
Returns:
- IntNative: subtraction operation result
Throws:
- OverflowException: When an overflow occurs in the subtraction operation, this exception is thrown.
extend UInt16 <: ThrowingOp<UInt16>
extend UInt16 <: ThrowingOp<UInt16>
Description: Implements the ThrowingOp interface for UInt16.
Parent Type:
func throwingAdd(UInt16)
public func throwingAdd(y: UInt16): UInt16
Description: Performs addition operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UInt16: addend
Returns:
- UInt16: addition operation result
Throws:
- OverflowException: When an overflow occurs in the addition operation, this exception is thrown.
func throwingDec()
public func throwingDec(): UInt16
Description: Performs auto-decrement operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- UInt16: auto-decrement operation result
Throws:
- OverflowException: When an overflow occurs in the auto-decrement operation, this exception is thrown.
func throwingDiv(UInt16)
public func throwingDiv(y: UInt16): UInt16
Description: Performs division operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UInt16: divisor
Returns:
- UInt16: division operation result
Throws:
- OverflowException: When an overflow occurs in the division operation, this exception is thrown.
func throwingInc()
public func throwingInc(): UInt16
Description: Performs auto-increment operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- UInt16: auto-increment operation result
Throws:
- OverflowException: When an overflow occurs in the auto-increment operation, this exception is thrown.
func throwingMod(UInt16)
public func throwingMod(y: UInt16): UInt16
Description: Performs modulo operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UInt16: divisor
Returns:
- UInt16: modulo operation result
Throws:
- OverflowException: When an overflow occurs in the modulo operation, this exception is thrown.
func throwingMul(UInt16)
public func throwingMul(y: UInt16): UInt16
Description: Performs multiplication operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UInt16: multiplier
Returns:
- UInt16: multiplication operation result
Throws:
- OverflowException: When an overflow occurs in the multiplication operation, this exception is thrown.
func throwingNeg()
public func throwingNeg(): UInt16
Description: Performs negation operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- UInt16: negation operation result
Throws:
- OverflowException: When an overflow occurs in the negation operation, this exception is thrown.
func throwingShl(UInt16)
public func throwingShl(y: UInt16): UInt16
Description: Performs left shift operation using the exception throwing policy.
When the number of bits to shift by is greater than or equal to that of operand bits or is less than 0, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UInt16: number of bits to shift by
Returns:
- UInt16: left shift operation result
Throws:
- OvershiftException: When the number of bits to shift by is greater than or equal to that of operand bits, this exception is thrown.
func throwingShr(UInt16)
public func throwingShr(y: UInt16): UInt16
Description: Performs right shift operation.
When the number of bits to shift by is greater than or equal to that of operand bits, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UInt16: number of bits to shift by
Returns:
- UInt16: right shift operation result
Throws:
- OvershiftException: When the number of bits to shift by is greater than or equal to that of operand bits, this exception is thrown.
func throwingSub(UInt16)
public func throwingSub(y: UInt16): UInt16
Description: Performs subtraction operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UInt16: subtrahend
Returns:
- UInt16: subtraction operation result
Throws:
- OverflowException: When an overflow occurs in the subtraction operation, this exception is thrown.
extend UInt32 <: ThrowingOp<UInt32>
extend UInt32 <: ThrowingOp<UInt32>
Description: Implements the ThrowingOp interface for UInt32.
Parent Type:
func throwingAdd(UInt32)
public func throwingAdd(y: UInt32): UInt32
Description: Performs addition operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UInt32: addend
Returns:
- UInt32: addition operation result
Throws:
- OverflowException: When an overflow occurs in the addition operation, this exception is thrown.
func throwingDec()
public func throwingDec(): UInt32
Description: Performs auto-decrement operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- UInt32: auto-decrement operation result
Throws:
- OverflowException: When an overflow occurs in the auto-decrement operation, this exception is thrown.
func throwingDiv(UInt32)
public func throwingDiv(y: UInt32): UInt32
Description: Performs division operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UInt32: divisor
Returns:
- UInt32: division operation result
Throws:
- OverflowException: When an overflow occurs in the division operation, this exception is thrown.
func throwingInc()
public func throwingInc(): UInt32
Description: Performs auto-increment operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- UInt32: auto-increment operation result
Throws:
- OverflowException: When an overflow occurs in the auto-increment operation, this exception is thrown.
func throwingMod(UInt32)
public func throwingMod(y: UInt32): UInt32
Description: Performs modulo operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UInt32: divisor
Returns:
- UInt32: modulo operation result
Throws:
- OverflowException: When an overflow occurs in the modulo operation, this exception is thrown.
func throwingMul(UInt32)
public func throwingMul(y: UInt32): UInt32
Description: Performs multiplication operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UInt32: multiplier
Returns:
- UInt32: multiplication operation result
Throws:
- OverflowException: When an overflow occurs in the multiplication operation, this exception is thrown.
func throwingNeg()
public func throwingNeg(): UInt32
Description: Performs negation operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- UInt32: negation operation result
Throws:
- OverflowException: When an overflow occurs in the negation operation, this exception is thrown.
func throwingShl(UInt32)
public func throwingShl(y: UInt32): UInt32
Description: Performs left shift operation using the exception throwing policy.
When the number of bits to shift by is greater than or equal to that of operand bits or is less than 0, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UInt32: number of bits to shift by
Returns:
- UInt32: left shift operation result
Throws:
- OvershiftException: When the number of bits to shift by is greater than or equal to that of operand bits, this exception is thrown.
func throwingShr(UInt32)
public func throwingShr(y: UInt32): UInt32
Description: Performs right shift operation.
When the number of bits to shift by is greater than or equal to that of operand bits, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UInt32: number of bits to shift by
Returns:
- UInt32: right shift operation result
Throws:
- OvershiftException: When the number of bits to shift by is greater than or equal to that of operand bits, this exception is thrown.
func throwingSub(UInt32)
public func throwingSub(y: UInt32): UInt32
Description: Performs subtraction operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UInt32: subtrahend
Returns:
- UInt32: subtraction operation result
Throws:
- OverflowException: When an overflow occurs in the subtraction operation, this exception is thrown.
extend UInt64 <: ThrowingOp<UInt64>
extend UInt64 <: ThrowingOp<UInt64>
Description: Implements the ThrowingOp interface for UInt64.
Parent Type:
func throwingAdd(UInt64)
public func throwingAdd(y: UInt64): UInt64
Description: Performs addition operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UInt64: addend
Returns:
- UInt64: addition operation result
Throws:
- OverflowException: When an overflow occurs in the addition operation, this exception is thrown.
func throwingDec()
public func throwingDec(): UInt64
Description: Performs auto-decrement operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- UInt64: auto-decrement operation result
Throws:
- OverflowException: When an overflow occurs in the auto-decrement operation, this exception is thrown.
func throwingDiv(UInt64)
public func throwingDiv(y: UInt64): UInt64
Description: Performs division operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UInt64: divisor
Returns:
- UInt64: division operation result
Throws:
- OverflowException: When an overflow occurs in the division operation, this exception is thrown.
func throwingInc()
public func throwingInc(): UInt64
Description: Performs auto-increment operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- UInt64: auto-increment operation result
Throws:
- OverflowException: When an overflow occurs in the auto-increment operation, this exception is thrown.
func throwingMod(UInt64)
public func throwingMod(y: UInt64): UInt64
Description: Performs modulo operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UInt64: divisor
Returns:
- UInt64: modulo operation result
Throws:
- OverflowException: When an overflow occurs in the modulo operation, this exception is thrown.
func throwingMul(UInt64)
public func throwingMul(y: UInt64): UInt64
Description: Performs multiplication operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UInt64: multiplier
Returns:
- UInt64: multiplication operation result
Throws:
- OverflowException: When an overflow occurs in the multiplication operation, this exception is thrown.
func throwingNeg()
public func throwingNeg(): UInt64
Description: Performs negation operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- UInt64: negation operation result
Throws:
- OverflowException: When an overflow occurs in the negation operation, this exception is thrown.
func throwingShl(UInt64)
public func throwingShl(y: UInt64): UInt64
Description: Performs left shift operation using the exception throwing policy.
When the number of bits to shift by is greater than or equal to that of operand bits or is less than 0, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UInt64: number of bits to shift by
Returns:
- UInt64: left shift operation result
Throws:
- OvershiftException: When the number of bits to shift by is greater than or equal to that of operand bits, this exception is thrown.
func throwingShr(UInt64)
public func throwingShr(y: UInt64): UInt64
Description: Performs right shift operation.
When the number of bits to shift by is greater than or equal to that of operand bits, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UInt64: number of bits to shift by
Returns:
- UInt64: right shift operation result
Throws:
- OvershiftException: When the number of bits to shift by is greater than or equal to that of operand bits, this exception is thrown.
func throwingSub(UInt64)
public func throwingSub(y: UInt64): UInt64
Description: Performs subtraction operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UInt64: subtrahend
Returns:
- UInt64: subtraction operation result
Throws:
- OverflowException: When an overflow occurs in the subtraction operation, this exception is thrown.
extend UInt8 <: ThrowingOp<UInt8>
extend UInt8 <: ThrowingOp<UInt8>
Description: Implements the ThrowingOp interface for UInt8.
Parent Type:
func throwingAdd(UInt8)
public func throwingAdd(y: UInt8): UInt8
Description: Performs addition operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UInt8: addend
Returns:
- UInt8: addition operation result
Throws:
- OverflowException: When an overflow occurs in the addition operation, this exception is thrown.
func throwingDec()
public func throwingDec(): UInt8
Description: Performs auto-decrement operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- UInt8: auto-decrement operation result
Throws:
- OverflowException: When an overflow occurs in the auto-decrement operation, this exception is thrown.
func throwingDiv(UInt8)
public func throwingDiv(y: UInt8): UInt8
Description: Performs division operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UInt8: divisor
Returns:
- UInt8: division operation result
Throws:
- OverflowException: When an overflow occurs in the division operation, this exception is thrown.
func throwingInc()
public func throwingInc(): UInt8
Description: Performs auto-increment operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- UInt8: auto-increment operation result
Throws:
- OverflowException: When an overflow occurs in the auto-increment operation, this exception is thrown.
func throwingMod(UInt8)
public func throwingMod(y: UInt8): UInt8
Description: Performs modulo operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UInt8: divisor
Returns:
- UInt8: modulo operation result
Throws:
- OverflowException: When an overflow occurs in the modulo operation, this exception is thrown.
func throwingMul(UInt8)
public func throwingMul(y: UInt8): UInt8
Description: Performs multiplication operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UInt8: multiplier
Returns:
- UInt8: multiplication operation result
Throws:
- OverflowException: When an overflow occurs in the multiplication operation, this exception is thrown.
func throwingNeg()
public func throwingNeg(): UInt8
Description: Performs negation operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- UInt8: negation operation result
Throws:
- OverflowException: When an overflow occurs in the negation operation, this exception is thrown.
func throwingShl(UInt8)
public func throwingShl(y: UInt8): UInt8
Description: Performs left shift operation using the exception throwing policy.
When the number of bits to shift by is greater than or equal to that of operand bits or is less than 0, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UInt8: number of bits to shift by
Returns:
- UInt8: left shift operation result
Throws:
- OvershiftException: When the number of bits to shift by is greater than or equal to that of operand bits, this exception is thrown.
func throwingShr(UInt8)
public func throwingShr(y: UInt8): UInt8
Description: Performs right shift operation.
When the number of bits to shift by is greater than or equal to that of operand bits, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UInt8: number of bits to shift by
Returns:
- UInt8: right shift operation result
Throws:
- OvershiftException: When the number of bits to shift by is greater than or equal to that of operand bits, this exception is thrown.
func throwingSub(UInt8)
public func throwingSub(y: UInt8): UInt8
Description: Performs subtraction operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UInt8: subtrahend
Returns:
- UInt8: subtraction operation result
Throws:
- OverflowException: When an overflow occurs in the subtraction operation, this exception is thrown.
extend UIntNative <: ThrowingOp<UIntNative>
extend UIntNative <: ThrowingOp<UIntNative>
Description: Implements the ThrowingOp interface for UIntNative.
Parent Type:
func throwingAdd(UIntNative)
public func throwingAdd(y: UIntNative): UIntNative
Description: Performs addition operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UIntNative: addend
Returns:
- UIntNative: addition operation result
Throws:
- OverflowException: When an overflow occurs in the addition operation, this exception is thrown.
func throwingDec()
public func throwingDec(): UIntNative
Description: Performs auto-decrement operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- UIntNative: auto-decrement operation result
Throws:
- OverflowException: When an overflow occurs in the auto-decrement operation, this exception is thrown.
func throwingDiv(UIntNative)
public func throwingDiv(y: UIntNative): UIntNative
Description: Performs division operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UIntNative: divisor
Returns:
- UIntNative: division operation result
Throws:
- OverflowException: When an overflow occurs in the division operation, this exception is thrown.
func throwingInc()
public func throwingInc(): UIntNative
Description: Performs auto-increment operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- UIntNative: auto-increment operation result
Throws:
- OverflowException: When an overflow occurs in the auto-increment operation, this exception is thrown.
func throwingMod(UIntNative)
public func throwingMod(y: UIntNative): UIntNative
Description: Performs modulo operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UIntNative: divisor
Returns:
- UIntNative: modulo operation result
Throws:
- OverflowException: When an overflow occurs in the modulo operation, this exception is thrown.
func throwingMul(UIntNative)
public func throwingMul(y: UIntNative): UIntNative
Description: Performs multiplication operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UIntNative: multiplier
Returns:
- UIntNative: multiplication operation result
Throws:
- OverflowException: When an overflow occurs in the multiplication operation, this exception is thrown.
func throwingNeg()
public func throwingNeg(): UIntNative
Description: Performs negation operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Returns:
- UIntNative: negation operation result
Throws:
- OverflowException: When an overflow occurs in the negation operation, this exception is thrown.
func throwingShl(UIntNative)
public func throwingShl(y: UIntNative): UIntNative
Description: Performs left shift operation using the exception throwing policy.
When the number of bits to shift by is greater than or equal to that of operand bits or is less than 0, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UIntNative: number of bits to shift by
Returns:
- UIntNative: left shift operation result
Throws:
- OvershiftException: When the number of bits to shift by is greater than or equal to that of operand bits, this exception is thrown.
func throwingShr(UIntNative)
public func throwingShr(y: UIntNative): UIntNative
Description: Performs right shift operation.
When the number of bits to shift by is greater than or equal to that of operand bits, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UIntNative: number of bits to shift by
Returns:
- UIntNative: right shift operation result
Throws:
- OvershiftException: When the number of bits to shift by is greater than or equal to that of operand bits, this exception is thrown.
func throwingSub(UIntNative)
public func throwingSub(y: UIntNative): UIntNative
Description: Performs subtraction operation using the exception throwing policy.
When an overflow occurs in an operation, an exception is thrown. Otherwise, the operation result is returned.
Parameters:
- y: UIntNative: subtrahend
Returns:
- UIntNative: subtraction operation result
Throws:
- OverflowException: When an overflow occurs in the subtraction operation, this exception is thrown.
interface WrappingOp<T>
public interface WrappingOp<T> {
func wrappingAdd(y: T): T
func wrappingDec(): T
func wrappingDiv(y: T): T
func wrappingInc(): T
func wrappingMod(y: T): T
func wrappingMul(y: T): T
func wrappingNeg(): T
func wrappingShl(y: T): T
func wrappingShr(y: T): T
func wrappingSub(y: T): T
}
Description: Truncates the most significant bits when an overflow occurs in an integer operation.
func wrappingAdd(T)
func wrappingAdd(y: T): T
Description: Performs addition operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: T: addend
Returns:
- T: addition operation result
func wrappingDec()
func wrappingDec(): T
Description: Performs auto-decrement operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- T: auto-decrement operation result
func wrappingDiv(T)
func wrappingDiv(y: T): T
Description: Performs division operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: T: divisor
Returns:
- T: division operation result
func wrappingInc()
func wrappingInc(): T
Description: Performs auto-increment operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- T: auto-increment operation result
func wrappingMod(T)
func wrappingMod(y: T): T
Description: Performs modulo operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: T: divisor
Returns:
- T: modulo operation result
func wrappingMul(T)
func wrappingMul(y: T): T
Description: Performs multiplication operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: T: multiplier
Returns:
- T: multiplication operation result
func wrappingNeg()
func wrappingNeg(): T
Description: Performs negation operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- T: negation operation result
func wrappingShl(T)
func wrappingShl(y: T): T
Description: Performs left shift operation using the policy of truncating most significant bits.
When the number of bits to shift by is greater than or equal to that of operand bits or is less than 0, most significant bits are truncated. For example, to shift a number of the Int8 type, when y (the number of bits to shift by) is greater than or equal to 8, only its 3 least significant bits are used as the number of bits to shift by, ensuring that the number of bits to shift by ranges from 0 to 7.
Parameters:
- y: T: number of bits to shift by
Returns:
- T: left shift operation result
func wrappingShr(T)
func wrappingShr(y: T): T
Description: Performs right shift operation using the policy of truncating most significant bits.
When the number of bits to shift by is greater than or equal to that of operand bits or is less than 0, most significant bits are truncated. For example, to shift a number of the Int8 type, when y (the number of bits to shift by) is greater than or equal to 8, only its 3 least significant bits are used as the number of bits to shift by, ensuring that the number of bits to shift by ranges from 0 to 7.
Parameters:
- y: T: number of bits to shift by
Returns:
- T: right shift operation result
func wrappingSub(T)
func wrappingSub(y: T): T
Description: Performs subtraction operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: T: subtrahend
Returns:
- T: subtraction operation result
extend Int16 <: WrappingOp<Int16>
extend Int16 <: WrappingOp<Int16>
Description: Implements the WrappingOp interface for Int16.
Parent Type:
func wrappingAdd(Int16)
public func wrappingAdd(y: Int16): Int16
Description: Performs addition operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: Int16: addend
Returns:
- Int16: addition operation result
func wrappingDec()
public func wrappingDec(): Int16
Description: Performs auto-decrement operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- Int16: auto-decrement operation result
func wrappingDiv(Int16)
public func wrappingDiv(y: Int16): Int16
Description: Performs division operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: Int16: divisor
Returns:
- Int16: division operation result
func wrappingInc()
public func wrappingInc(): Int16
Description: Performs auto-increment operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- Int16: auto-increment operation result
func wrappingMod(Int16)
public func wrappingMod(y: Int16): Int16
Description: Performs modulo operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: Int16: divisor
Returns:
- Int16: modulo operation result
func wrappingMul(Int16)
public func wrappingMul(y: Int16): Int16
Description: Performs multiplication operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: Int16: multiplier
Returns:
- Int16: multiplication operation result
func wrappingNeg()
public func wrappingNeg(): Int16
Description: Performs negation operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- Int16: negation operation result
func wrappingShl(Int16)
public func wrappingShl(y: Int16): Int16
Description: Performs left shift operation using the policy of truncating most significant bits.
When the number of bits of the right operand is greater than or equal to that of the left operand or is less than 0, the 4 least significant bits of the right operand are used as the number of bits to shift by.
Parameters:
- y: Int16: number of bits to shift by
Returns:
- Int16: left shift operation result
func wrappingShr(Int16)
public func wrappingShr(y: Int16): Int16
Description: Performs right shift operation using the policy of truncating most significant bits.
When the number of bits of the right operand is greater than or equal to that of the left operand or is less than 0, the 4 least significant bits of the right operand are used as the number of bits to shift by.
Parameters:
- y: Int16: number of bits to shift by
Returns:
- Int16: right shift operation result
func wrappingSub(Int16)
public func wrappingSub(y: Int16): Int16
Description: Performs subtraction operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: Int16: subtrahend
Returns:
- Int16: subtraction operation result
extend Int32 <: WrappingOp<Int32>
extend Int32 <: WrappingOp<Int32>
Description: Implements the WrappingOp interface for Int32.
Parent Type:
func wrappingAdd(Int32)
public func wrappingAdd(y: Int32): Int32
Description: Performs addition operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: Int32: addend
Returns:
- Int32: addition operation result
func wrappingDec()
public func wrappingDec(): Int32
Description: Performs auto-decrement operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- Int32: auto-decrement operation result
func wrappingDiv(Int32)
public func wrappingDiv(y: Int32): Int32
Description: Performs division operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: Int32: divisor
Returns:
- Int32: division operation result
func wrappingInc()
public func wrappingInc(): Int32
Description: Performs auto-increment operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- Int32: auto-increment operation result
func wrappingMod(Int32)
public func wrappingMod(y: Int32): Int32
Description: Performs modulo operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: Int32: divisor
Returns:
- Int32: modulo operation result
func wrappingMul(Int32)
public func wrappingMul(y: Int32): Int32
Description: Performs multiplication operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: Int32: multiplier
Returns:
- Int32: multiplication operation result
func wrappingNeg()
public func wrappingNeg(): Int32
Description: Performs negation operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- Int32: negation operation result
func wrappingShl(Int32)
public func wrappingShl(y: Int32): Int32
Description: Performs left shift operation using the policy of truncating most significant bits.
When the number of bits of the right operand is greater than or equal to that of the left operand or is less than 0, the 5 least significant bits of the right operand are used as the number of bits to shift by.
Parameters:
- y: Int32: number of bits to shift by
Returns:
- Int32: left shift operation result
func wrappingShr(Int32)
public func wrappingShr(y: Int32): Int32
Description: Performs right shift operation using the policy of truncating most significant bits.
When the number of bits of the right operand is greater than or equal to that of the left operand or is less than 0, the 5 least significant bits of the right operand are used as the number of bits to shift by.
Parameters:
- y: Int32: number of bits to shift by
Returns:
- Int32: right shift operation result
func wrappingSub(Int32)
public func wrappingSub(y: Int32): Int32
Description: Performs subtraction operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: Int32: subtrahend
Returns:
- Int32: subtraction operation result
extend Int64 <: WrappingOp<Int64>
extend Int64 <: WrappingOp<Int64>
Description: Implements the WrappingOp interface for Int64.
Parent Type:
func wrappingAdd(Int64)
public func wrappingAdd(y: Int64): Int64
Description: Performs addition operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: Int64: addend
Returns:
- Int64: addition operation result
func wrappingDec()
public func wrappingDec(): Int64
Description: Performs auto-decrement operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- Int64: auto-decrement operation result
func wrappingDiv(Int64)
public func wrappingDiv(y: Int64): Int64
Description: Performs division operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: Int64: divisor
Returns:
- Int64: division operation result
func wrappingInc()
public func wrappingInc(): Int64
Description: Performs auto-increment operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- Int64: auto-increment operation result
func wrappingMod(Int64)
public func wrappingMod(y: Int64): Int64
Description: Performs modulo operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: Int64: divisor
Returns:
- Int64: modulo operation result
func wrappingMul(Int64)
public func wrappingMul(y: Int64): Int64
Description: Performs multiplication operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: Int64: multiplier
Returns:
- Int64: multiplication operation result
func wrappingNeg()
public func wrappingNeg(): Int64
Description: Performs negation operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- Int64: negation operation result
func wrappingPow(UInt64)
public func wrappingPow(y: UInt64): Int64
Description: Performs exponentiation operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: UInt64: exponent
Returns:
- Int64: exponentiation operation result
func wrappingShl(Int64)
public func wrappingShl(y: Int64): Int64
Description: Performs left shift operation using the policy of truncating most significant bits.
When the number of bits of the right operand is greater than or equal to that of the left operand or is less than 0, the 6 least significant bits of the right operand are used as the number of bits to shift by.
Parameters:
- y: Int64: number of bits to shift by
Returns:
- Int64: left shift operation result
func wrappingShr(Int64)
public func wrappingShr(y: Int64): Int64
Description: Performs right shift operation using the policy of truncating most significant bits.
When the number of bits of the right operand is greater than or equal to that of the left operand or is less than 0, the 6 least significant bits of the right operand are used as the number of bits to shift by.
Parameters:
- y: Int64: number of bits to shift by
Returns:
- Int64: right shift operation result
func wrappingSub(Int64)
public func wrappingSub(y: Int64): Int64
Description: Performs subtraction operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: Int64: subtrahend
Returns:
- Int64: subtraction operation result
extend Int8 <: WrappingOp<Int8>
extend Int8 <: WrappingOp<Int8>
Description: Implements the WrappingOp interface for Int8.
Parent Type:
func wrappingAdd(Int8)
public func wrappingAdd(y: Int8): Int8
Description: Performs addition operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: Int8: addend
Returns:
- Int8: addition operation result
func wrappingDec()
public func wrappingDec(): Int8
Description: Performs auto-decrement operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- Int8: auto-decrement operation result
func wrappingDiv(Int8)
public func wrappingDiv(y: Int8): Int8
Description: Performs division operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: Int8: divisor
Returns:
- Int8: division operation result
func wrappingInc()
public func wrappingInc(): Int8
Description: Performs auto-increment operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- Int8: auto-increment operation result
func wrappingMod(Int8)
public func wrappingMod(y: Int8): Int8
Description: Performs modulo operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: Int8: divisor
Returns:
- Int8: modulo operation result
func wrappingMul(Int8)
public func wrappingMul(y: Int8): Int8
Description: Performs multiplication operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: Int8: multiplier
Returns:
- Int8: multiplication operation result
func wrappingNeg()
public func wrappingNeg(): Int8
Description: Performs negation operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- Int8: negation operation result
func wrappingShl(Int8)
public func wrappingShl(y: Int8): Int8
Description: Performs left shift operation using the policy of truncating most significant bits.
When the number of bits of the right operand is greater than or equal to that of the left operand or is less than 0, the 3 least significant bits of the right operand are used as the number of bits to shift by.
Parameters:
- y: Int8: number of bits to shift by
Returns:
- Int8: left shift operation result
func wrappingShr(Int8)
public func wrappingShr(y: Int8): Int8
Description: Performs right shift operation using the policy of truncating most significant bits.
When the number of bits of the right operand is greater than or equal to that of the left operand or is less than 0, the 3 least significant bits of the right operand are used as the number of bits to shift by.
Parameters:
- y: Int8: number of bits to shift by
Returns:
- Int8: right shift operation result
func wrappingSub(Int8)
public func wrappingSub(y: Int8): Int8
Description: Performs subtraction operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: Int8: subtrahend
Returns:
- Int8: subtraction operation result
extend IntNative <: WrappingOp<IntNative>
extend IntNative <: WrappingOp<IntNative>
Description: Implements the WrappingOp interface for IntNative.
Parent Type:
func wrappingAdd(IntNative)
public func wrappingAdd(y: IntNative): IntNative
Description: Performs addition operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: IntNative: addend
Returns:
- IntNative: addition operation result
func wrappingDec()
public func wrappingDec(): IntNative
Description: Performs auto-decrement operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- IntNative: auto-decrement operation result
func wrappingDiv(IntNative)
public func wrappingDiv(y: IntNative): IntNative
Description: Performs division operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: IntNative: divisor
Returns:
- IntNative: division operation result
func wrappingInc()
public func wrappingInc(): IntNative
Description: Performs auto-increment operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- IntNative: auto-increment operation result
func wrappingMod(IntNative)
public func wrappingMod(y: IntNative): IntNative
Description: Performs modulo operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: IntNative: divisor
Returns:
- IntNative: modulo operation result
func wrappingMul(IntNative)
public func wrappingMul(y: IntNative): IntNative
Description: Performs multiplication operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: IntNative: multiplier
Returns:
- IntNative: multiplication operation result
func wrappingNeg()
public func wrappingNeg(): IntNative
Description: Performs negation operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- IntNative: negation operation result
func wrappingShl(IntNative)
public func wrappingShl(y: IntNative): IntNative
Description: Performs left shift operation using the policy of truncating most significant bits.
When the number of bits of the right operand is greater than or equal to that of the left operand or is less than 0, the least significant bits of the right operand are used as the number of bits to shift by, which depends on the number of IntNative bits in the current system.
Parameters:
- y: IntNative: number of bits to shift by
Returns:
- IntNative: left shift operation result
func wrappingShr(IntNative)
public func wrappingShr(y: IntNative): IntNative
Description: Performs right shift operation using the policy of truncating most significant bits.
When the number of bits of the right operand is greater than or equal to that of the left operand or is less than 0, the least significant bits of the right operand are used as the number of bits to shift by, which depends on the number of IntNative bits in the current system.
Parameters:
- y: IntNative: number of bits to shift by
Returns:
- IntNative: right shift operation result
func wrappingSub(IntNative)
public func wrappingSub(y: IntNative): IntNative
Description: Performs subtraction operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: IntNative: subtrahend
Returns:
- IntNative: subtraction operation result
extend UInt16 <: WrappingOp<UInt16>
extend UInt16 <: WrappingOp<UInt16>
Description: Implements the WrappingOp interface for UInt16.
Parent Type:
func wrappingAdd(UInt16)
public func wrappingAdd(y: UInt16): UInt16
Description: Performs addition operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: UInt16: addend
Returns:
- UInt16: addition operation result
func wrappingDec()
public func wrappingDec(): UInt16
Description: Performs auto-decrement operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- UInt16: auto-decrement operation result
func wrappingDiv(UInt16)
public func wrappingDiv(y: UInt16): UInt16
Description: Performs division operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: UInt16: divisor
Returns:
- UInt16: division operation result
func wrappingInc()
public func wrappingInc(): UInt16
Description: Performs auto-increment operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- UInt16: auto-increment operation result
func wrappingMod(UInt16)
public func wrappingMod(y: UInt16): UInt16
Description: Performs modulo operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: UInt16: divisor
Returns:
- UInt16: modulo operation result
func wrappingMul(UInt16)
public func wrappingMul(y: UInt16): UInt16
Description: Performs multiplication operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: UInt16: multiplier
Returns:
- UInt16: multiplication operation result
func wrappingNeg()
public func wrappingNeg(): UInt16
Description: Performs negation operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- UInt16: negation operation result
func wrappingShl(UInt16)
public func wrappingShl(y: UInt16): UInt16
Description: Performs left shift operation using the policy of truncating most significant bits.
When the number of bits of the right operand is greater than or equal to that of the left operand, the 4 least significant bits of the right operand are used as the number of bits to shift by.
Parameters:
- y: UInt16: number of bits to shift by
Returns:
- UInt16: left shift operation result
func wrappingShr(UInt16)
public func wrappingShr(y: UInt16): UInt16
Description: Performs right shift operation using the policy of truncating most significant bits.
When the number of bits of the right operand is greater than or equal to that of the left operand, the 4 least significant bits of the right operand are used as the number of bits to shift by.
Parameters:
- y: UInt16: number of bits to shift by
Returns:
- UInt16: right shift operation result
func wrappingSub(UInt16)
public func wrappingSub(y: UInt16): UInt16
Description: Performs subtraction operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: UInt16: subtrahend
Returns:
- UInt16: subtraction operation result
extend UInt32 <: WrappingOp<UInt32>
extend UInt32 <: WrappingOp<UInt32>
Description: Implements the WrappingOp interface for UInt32.
Parent Type:
func wrappingAdd(UInt32)
public func wrappingAdd(y: UInt32): UInt32
Description: Performs addition operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: UInt32: addend
Returns:
- UInt32: addition operation result
func wrappingDec()
public func wrappingDec(): UInt32
Description: Performs auto-decrement operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- UInt32: auto-decrement operation result
func wrappingDiv(UInt32)
public func wrappingDiv(y: UInt32): UInt32
Description: Performs division operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: UInt32: divisor
Returns:
- UInt32: division operation result
func wrappingInc()
public func wrappingInc(): UInt32
Description: Performs auto-increment operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- UInt32: auto-increment operation result
func wrappingMod(UInt32)
public func wrappingMod(y: UInt32): UInt32
Description: Performs modulo operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: UInt32: divisor
Returns:
- UInt32: modulo operation result
func wrappingMul(UInt32)
public func wrappingMul(y: UInt32): UInt32
Description: Performs multiplication operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: UInt32: multiplier
Returns:
- UInt32: multiplication operation result
func wrappingNeg()
public func wrappingNeg(): UInt32
Description: Performs negation operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- UInt32: negation operation result
func wrappingShl(UInt32)
public func wrappingShl(y: UInt32): UInt32
Description: Performs left shift operation using the policy of truncating most significant bits.
When the number of bits of the right operand is greater than or equal to that of the left operand, the 5 least significant bits of the right operand are used as the number of bits to shift by.
Parameters:
- y: UInt32: number of bits to shift by
Returns:
- UInt32: left shift operation result
func wrappingShr(UInt32)
public func wrappingShr(y: UInt32): UInt32
Description: Performs right shift operation using the policy of truncating most significant bits.
When the number of bits of the right operand is greater than or equal to that of the left operand, the 5 least significant bits of the right operand are used as the number of bits to shift by.
Parameters:
- y: UInt32: number of bits to shift by
Returns:
- UInt32: right shift operation result
func wrappingSub(UInt32)
public func wrappingSub(y: UInt32): UInt32
Description: Performs subtraction operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: UInt32: subtrahend
Returns:
- UInt32: subtraction operation result
extend UInt64 <: WrappingOp<UInt64>
extend UInt64 <: WrappingOp<UInt64>
Description: Implements the WrappingOp interface for UInt64.
Parent Type:
func wrappingAdd(UInt64)
public func wrappingAdd(y: UInt64): UInt64
Description: Performs addition operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: UInt64: addend
Returns:
- UInt64: addition operation result
func wrappingDec()
public func wrappingDec(): UInt64
Description: Performs auto-decrement operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- UInt64: auto-decrement operation result
func wrappingDiv(UInt64)
public func wrappingDiv(y: UInt64): UInt64
Description: Performs division operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: UInt64: divisor
Returns:
- UInt64: division operation result
func wrappingInc()
public func wrappingInc(): UInt64
Description: Performs auto-increment operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- UInt64: auto-increment operation result
func wrappingMod(UInt64)
public func wrappingMod(y: UInt64): UInt64
Description: Performs modulo operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: UInt64: divisor
Returns:
- UInt64: modulo operation result
func wrappingMul(UInt64)
public func wrappingMul(y: UInt64): UInt64
Description: Performs multiplication operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: UInt64: multiplier
Returns:
- UInt64: multiplication operation result
func wrappingNeg()
public func wrappingNeg(): UInt64
Description: Performs negation operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- UInt64: negation operation result
func wrappingShl(UInt64)
public func wrappingShl(y: UInt64): UInt64
Description: Performs left shift operation using the policy of truncating most significant bits.
When the number of bits of the right operand is greater than or equal to that of the left operand, the 6 least significant bits of the right operand are used as the number of bits to shift by.
Parameters:
- y: UInt64: number of bits to shift by
Returns:
- UInt64: left shift operation result
func wrappingShr(UInt64)
public func wrappingShr(y: UInt64): UInt64
Description: Performs right shift operation using the policy of truncating most significant bits.
When the number of bits of the right operand is greater than or equal to that of the left operand, the 6 least significant bits of the right operand are used as the number of bits to shift by.
Parameters:
- y: UInt64: number of bits to shift by
Returns:
- UInt64: right shift operation result
func wrappingSub(UInt64)
public func wrappingSub(y: UInt64): UInt64
Description: Performs subtraction operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: UInt64: subtrahend
Returns:
- UInt64: subtraction operation result
extend UInt8 <: WrappingOp<UInt8>
extend UInt8 <: WrappingOp<UInt8>
Description: Implements the WrappingOp interface for UInt8.
Parent Type:
func wrappingAdd(UInt8)
public func wrappingAdd(y: UInt8): UInt8
Description: Performs addition operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: UInt8: addend
Returns:
- UInt8: addition operation result
func wrappingDec()
public func wrappingDec(): UInt8
Description: Performs auto-decrement operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- UInt8: auto-decrement operation result
func wrappingDiv(UInt8)
public func wrappingDiv(y: UInt8): UInt8
Description: Performs division operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: UInt8: divisor
Returns:
- UInt8: division operation result
func wrappingInc()
public func wrappingInc(): UInt8
Description: Performs auto-increment operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- UInt8: auto-increment operation result
func wrappingMod(UInt8)
public func wrappingMod(y: UInt8): UInt8
Description: Performs modulo operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: UInt8: divisor
Returns:
- UInt8: modulo operation result
func wrappingMul(UInt8)
public func wrappingMul(y: UInt8): UInt8
Description: Performs multiplication operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: UInt8: multiplier
Returns:
- UInt8: multiplication operation result
func wrappingNeg()
public func wrappingNeg(): UInt8
Description: Performs negation operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- UInt8: negation operation result
func wrappingShl(UInt8)
public func wrappingShl(y: UInt8): UInt8
Description: Performs left shift operation using the policy of truncating most significant bits.
When the number of bits of the right operand is greater than or equal to that of the left operand, the 3 least significant bits of the right operand are used as the number of bits to shift by.
Parameters:
- y: UInt8: number of bits to shift by
Returns:
- UInt8: left shift operation result
func wrappingShr(UInt8)
public func wrappingShr(y: UInt8): UInt8
Description: Performs right shift operation using the policy of truncating most significant bits.
When the number of bits of the right operand is greater than or equal to that of the left operand, the 3 least significant bits of the right operand are used as the number of bits to shift by.
Parameters:
- y: UInt8: number of bits to shift by
Returns:
- UInt8: right shift operation result
func wrappingSub(UInt8)
public func wrappingSub(y: UInt8): UInt8
Description: Performs subtraction operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: UInt8: subtrahend
Returns:
- UInt8: subtraction operation result
extend UIntNative <: WrappingOp<UIntNative>
extend UIntNative <: WrappingOp<UIntNative>
Description: Implements the WrappingOp interface for UIntNative.
Parent Type:
func wrappingAdd(UIntNative)
public func wrappingAdd(y: UIntNative): UIntNative
Description: Performs addition operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: UIntNative: addend
Returns:
- UIntNative: addition operation result
func wrappingDec()
public func wrappingDec(): UIntNative
Description: Performs auto-decrement operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- UIntNative: auto-decrement operation result
func wrappingDiv(UIntNative)
public func wrappingDiv(y: UIntNative): UIntNative
Description: Performs division operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: UIntNative: divisor
Returns:
- UIntNative: division operation result
func wrappingInc()
public func wrappingInc(): UIntNative
Description: Performs auto-increment operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- UIntNative: auto-increment operation result
func wrappingMod(UIntNative)
public func wrappingMod(y: UIntNative): UIntNative
Description: Performs modulo operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: UIntNative: divisor
Returns:
- UIntNative: modulo operation result
func wrappingMul(UIntNative)
public func wrappingMul(y: UIntNative): UIntNative
Description: Performs multiplication operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: UIntNative: multiplier
Returns:
- UIntNative: multiplication operation result
func wrappingNeg()
public func wrappingNeg(): UIntNative
Description: Performs negation operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Returns:
- UIntNative: negation operation result
func wrappingShl(UIntNative)
public func wrappingShl(y: UIntNative): UIntNative
Description: Performs left shift operation using the policy of truncating most significant bits.
When the number of bits of the right operand is greater than or equal to that of the left operand, the least significant bits of the right operand are used as the number of bits to shift by, which depends on the number of UIntNative bits in the current system.
Parameters:
- y: UIntNative: number of bits to shift by
Returns:
- UIntNative: left shift operation result
func wrappingShr(UIntNative)
public func wrappingShr(y: UIntNative): UIntNative
Description: Performs right shift operation using the policy of truncating most significant bits.
When the number of bits of the right operand is greater than or equal to that of the left operand, the least significant bits of the right operand are used as the number of bits to shift by, which depends on the number of UIntNative bits in the current system.
Parameters:
- y: UIntNative: number of bits to shift by
Returns:
- UIntNative: right shift operation result
func wrappingSub(UIntNative)
public func wrappingSub(y: UIntNative): UIntNative
Description: Performs subtraction operation using the policy of truncating most significant bits.
When an overflow occurs in an operation, most significant bits are truncated. Otherwise, the operation result is returned.
Parameters:
- y: UIntNative: subtrahend
Returns:
- UIntNative: subtraction operation result
Exception Class
class OvershiftException
public class OvershiftException <: Exception {
public init()
public init(message: String)
}
Description: Specifies an exception thrown when the number of shifted bits exceeds the number of operand bits in a shift operation.
Parent Type:
init()
public init()
Description: Creates an OvershiftException instance.
init(String)
public init(message: String)
Description: Creates an OvershiftException instance containing an exception message.
Parameters:
- message: String: exception information
class UndershiftException
public class UndershiftException <: Exception {
public init()
public init(message: String)
}
Description: Specifies an exception thrown when the number of shifted bits is less than 0 in a shift operation.
Parent Type:
init()
public init()
Description: Creates an UndershiftException instance.
init(String)
public init(message: String)
Description: Creates an UndershiftException instance containing an exception message.
Parameters:
- message: String: exception information
Example of the Returning Option Policy
The following is an example of the returning Option policy. In this example, an overflow occurs in an attempt to calculate the square of Int64.Max, and None is returned.
import std.overflow.*
import std.math.*
main() {
let a: Int64 = Int64.Max
println(a.checkedPow(UInt64(2)))
}
The running result is as follows:
None
Example of the Saturating Policy
The following is an example of the saturating policy. In this example, the operation result exceeds the maximum value of UInt16 in an attempt to multiply UInt16.Max by 16. An overflow occurs, and the maximum value of UInt16 is returned.
import std.overflow.*
import std.math.*
main() {
let a: UInt16 = UInt16.Max
println(a.saturatingMul(16))
}
The running result is as follows:
65535
Example of the Throwing Exception Policy
The following is an example of the throwing exception policy. In this example, an overflow occurs in an attempt to calculate Int64.Max + 1, and OverflowException is thrown.
import std.overflow.*
import std.math.*
main() {
let a: Int64 = Int64.Max
println(a.throwingAdd(1))
}
The running result is as follows:
An exception has occurred:
OverflowException: add
Example of the Most Significant Bit Truncation Policy
The following is an example of the most significant bit truncation policy. In this example, UInt8.Max + 1 is calculated, where UInt8.Max is expressed as 0b11111111 and UInt8.Max + 1 is expressed as 0b100000000 in binary system. Because UInt8 can store only eight bits, the result of most significant bit truncation is 0.
import std.overflow.*
import std.math.*
main() {
let a: UInt8 = UInt8.Max
println(a.wrappingAdd(1))
}
The running result is as follows:
0
std.random Package
Function Description
The random package provides the capability of generating pseudo-random numbers.
API List
Class
| Name | Description |
|---|---|
| Random | Provides functions related to the generation of pseudo-random numbers. |
Class
class Random
public open class Random
Description: Provides functions related to the generation of pseudo-random numbers.
Example:
import std.random.*
main() {
let m: Random = Random()
/* Creates a Random object and sets a seed for obtaining the random object. */
m.seed = 3
let b: Bool = m.nextBool()
let c: Int8 = m.nextInt8()
print("b=${b is Bool},")/* The object can also be of the Bool type. */
println("c=${c is Int8}")
return 0
}
Running result:
b=true,c=true
prop seed
public open mut prop seed: UInt64
Description: Sets or obtains the size of a seed. If same random seeds are set, the generated pseudo-random number lists are the same.
Type: UInt64
init()
public init()
Description: Creates a new Random object using a non-parameterized constructor by default.
init(UInt64)
public init(seed: UInt64)
Description: Creates a new Random object using a random seed.
Parameters:
- seed:UInt64: random seed. If same random seeds are set, the generated pseudo-random number lists are the same.
func next(UInt64)
public open func next(bits: UInt64): UInt64
Description: Generates a random integer with a user-specified length.
Parameters:
- bits: UInt64: number of bits of the pseudo-random number to be generated. The value range is (0, 64].
Returns:
- UInt64: pseudo-random number with a specified length
Throws:
- IllegalArgumentException: If
bitsis 0 or greater than 64, exceeding the length for UInt64, this exception is thrown.
func nextBool()
public open func nextBool(): Bool
Description: Obtains a pseudo-random value of the Bool type.
Returns:
func nextFloat16()
public open func nextFloat16(): Float16
Description: Obtains a pseudo-random number of the Float16 type. The range is [0.0, 1.0).
Returns:
func nextFloat32()
public open func nextFloat32(): Float32
Description: Obtains a pseudo-random number of the Float32 type. The range is [0.0, 1.0).
Returns:
func nextFloat64()
public open func nextFloat64(): Float64
Description: Obtains a pseudo-random number of the Float64 type. The range is [0.0, 1.0).
Returns:
func nextGaussianFloat16(Float16, Float16)
public func nextGaussianFloat16(mean!: Float16 = 0.0, sigma!: Float16 = 1.0): Float16
Description: Obtains a random number of the Float16 type complying with a Gaussian distribution where the mean and standard deviation are specified.
By default, a random number of the Float16 type is obtained, complying with the Gaussian distribution where the mean is 0.0 and the standard deviation is 1.0. The mean is an expected value and can be interpreted as a location parameter, which determines the location of the distribution. The standard deviation can be interpreted as a scale parameter, which determines the amplitude of the distribution. This function calls the function nextGaussianFloat16Implement to obtain a return value. Therefore, when a subclass inherits Random and overwrites the function nextGaussianFloat64Implement, the return value of the overwritten function is returned when this function of the subclass is called.
Parameters:
Returns:
func nextGaussianFloat16Implement(Float16, Float16)
protected open func nextGaussianFloat16Implement(mean: Float16, sigma: Float16): Float16
Description: Specifies an implementation function of nextGaussianFloat16, used to obtain a random number of the Float16 type complying with a Gaussian distribution where the mean and standard deviation are specified.
A random number of the Float16 type is obtained, complying with a Gaussian distribution where the mean is mean and the standard deviation is sigma. The mean is an expected value and can be interpreted as a location parameter, which determines the location of the distribution. The standard deviation can be interpreted as a scale parameter, which determines the amplitude of the distribution. This function is the implementation function of nextGaussianFloat16 and is not public. When a subclass inherits Random and overwrites this function, the return value of this function is returned when the function nextGaussianFloat16 of the subclass is called.
Parameters:
Returns:
func nextGaussianFloat32(Float32, Float32)
public func nextGaussianFloat32(mean!: Float32 = 0.0, sigma!: Float32 = 1.0): Float32
Description: Obtains a random number of the Float32 type complying with a Gaussian distribution where the mean and standard deviation are specified.
By default, a random number of the Float32 type is obtained, complying with a Gaussian distribution where the mean is 0.0 and the standard deviation is 1.0. The mean is an expected value and can be interpreted as a location parameter, which determines the location of the distribution. The standard deviation can be interpreted as a scale parameter, which determines the amplitude of the distribution. This function calls the function nextGaussianFloat32Implement to obtain a return value. Therefore, when a subclass inherits Random and overwrites the function nextGaussianFloat64Implement, the return value of the overwritten function is returned when this function of the subclass is called.
Parameters:
Returns:
func nextGaussianFloat32Implement(Float32, Float32)
protected open func nextGaussianFloat32Implement(mean: Float32, sigma: Float32): Float32
Description: Specifies an implementation function of nextGaussianFloat32, used to obtain a random number of the Float32 type complying with a Gaussian distribution where the mean and standard deviation are specified.
A random number of the Float32 type is obtained, complying with a Gaussian distribution where the mean is mean and the standard deviation is sigma. The mean is an expected value and can be interpreted as a location parameter, which determines the location of the distribution. The standard deviation can be interpreted as a scale parameter, which determines the amplitude of the distribution. This function is the implementation function of nextGaussianFloat32 and is not public. When a subclass inherits Random and overwrites this function, the return value of this function is returned when the function nextGaussianFloat32 of the subclass is called.
Parameters:
Returns:
func nextGaussianFloat64(Float64, Float64)
public func nextGaussianFloat64(mean!: Float64 = 0.0, sigma!: Float64 = 1.0): Float64
Description: Obtains a random number of the Float64 type complying with a Gaussian distribution where the mean and standard deviation are specified.
By default, a random number of the Float64 type is obtained, complying with a Gaussian distribution where the mean is 0.0 and the standard deviation is 1.0. The mean is an expected value and can be interpreted as a location parameter, which determines the location of the distribution. The standard deviation can be interpreted as a scale parameter, which determines the amplitude of the distribution. This function calls the function nextGaussianFloat64Implement to obtain a return value. Therefore, when a subclass inherits Random and overwrites the function nextGaussianFloat64Implement, the return value of the overwritten function is returned when this function of the subclass is called.
Parameters:
Returns:
func nextGaussianFloat64Implement(Float64, Float64)
protected open func nextGaussianFloat64Implement(mean: Float64, sigma: Float64): Float64
Description: Specifies an implementation function of nextGaussianFloat64, used to obtain a random number of the Float64 type complying with a Gaussian distribution where the mean and standard deviation are specified.
A random number of the Float64 type is obtained, complying with a Gaussian distribution where the mean is mean and the standard deviation is sigma. The mean is an expected value and can be interpreted as a location parameter, which determines the location of the distribution. The standard deviation can be interpreted as a scale parameter, which determines the amplitude of the distribution. This function is the implementation function of nextGaussianFloat64 and is not public. When a subclass inherits Random and overwrites this function, the return value of this function is returned when the function nextGaussianFloat64 of the subclass is called.
Parameters:
Returns:
func nextInt16()
public open func nextInt16(): Int16
Description: Obtains a pseudo-random number of the Int16 type.
Returns:
func nextInt16(Int16)
public open func nextInt16(upper: Int16): Int16
Description: Obtains a pseudo-random number of the Int16 type with the range of [0, upper).
Parameters:
- upper: Int16: upper bound of the generated pseudo-random number (not including
upper). The value range is (0, Int16.Max].
Returns:
Throws:
- IllegalArgumentException: If
upperis less than or equal to 0, this exception is thrown.
func nextInt32()
public open func nextInt32(): Int32
Description: Obtains a pseudo-random number of the Int32 type.
Returns:
func nextInt32(Int32)
public open func nextInt32(upper: Int32): Int32
Description: Obtains a pseudo-random number of the Int32 type with the range of [0, upper).
Parameters:
- upper: Int32: upper bound of the generated pseudo-random number (not including
upper). The value range is (0, Int32.Max].
Returns:
Throws:
- IllegalArgumentException: If
upperis less than or equal to 0, this exception is thrown.
func nextInt64()
public open func nextInt64(): Int64
Description: Obtains a pseudo-random number of the Int64 type.
Returns:
func nextInt64(Int64)
public open func nextInt64(upper: Int64): Int64
Description: Obtains a pseudo-random number of the Int64 type with the range of [0, upper).
Parameters:
- upper: Int64: upper bound of the generated pseudo-random number (not including
upper). The value range is (0, Int64.Max].
Returns:
Throws:
- IllegalArgumentException: If
upperis less than or equal to 0, this exception is thrown.
func nextInt8()
public open func nextInt8(): Int8
Description: Obtains a pseudo-random number of the Int8 type.
Returns:
func nextInt8(Int8): Int8
public open func nextInt8(upper: Int8): Int8
Description: Obtains a pseudo-random number of the Int8 type with the range of [0, upper).
Parameters:
- upper: Int8: upper bound of the generated pseudo-random number (not including
upper). The value range is (0, Int8.Max].
Returns:
Throws:
- IllegalArgumentException: If
upperis less than or equal to 0, this exception is thrown.
func nextUInt16()
public open func nextUInt16(): UInt16
Description: Obtains a pseudo-random number of the UInt16 type.
Returns:
func nextUInt16(UInt16)
public open func nextUInt16(upper: UInt16): UInt16
Description: Obtains a pseudo-random number of the UInt16 type with the range of [0, upper).
Parameters:
- upper: UInt16: upper bound of the generated pseudo-random number (not including
upper). The value range is (0, UInt16.Max].
Returns:
Throws:
- IllegalArgumentException: If
upperis 0, this exception is thrown.
func nextUInt32()
public open func nextUInt32(): UInt32
Description: Obtains a pseudo-random number of the UInt32 type.
Returns:
func nextUInt32(UInt32)
public open func nextUInt32(upper: UInt32): UInt32
Description: Obtains a pseudo-random number of the UInt32 type with the range of [0, upper).
Parameters:
- upper: UInt32: upper bound of the generated pseudo-random number (not including
upper). The value range is (0, UInt32.Max].
Returns:
Throws:
- IllegalArgumentException: If
upperis 0, this exception is thrown.
func nextUInt64()
public open func nextUInt64(): UInt64
Description: Obtains a pseudo-random number of the UInt64 type.
Returns:
func nextUInt64(UInt64)
public open func nextUInt64(upper: UInt64): UInt64
Description: Obtains a pseudo-random number of the UInt64 type with the range of [0, upper).
Parameters:
- upper: UInt64: upper bound of the generated pseudo-random number (not including
upper). The value range is (0, UInt64.Max].
Returns:
Throws:
- IllegalArgumentException: If
upperis 0, this exception is thrown.
func nextUInt8()
public open func nextUInt8(): UInt8
Description: Obtains a pseudo-random number of the UInt8 type.
Returns:
func nextUInt8(UInt8)
public open func nextUInt8(upper: UInt8): UInt8
Description: Obtains a pseudo-random number of the UInt8 type with the range of [0, upper).
Parameters:
- upper: UInt8: upper bound of the generated pseudo-random number (not including
upper). The value range is (0, UInt8.Max].
Returns:
Throws:
- IllegalArgumentException: If
upperis 0, this exception is thrown.
func nextUInt8s(Array<UInt8>)
public open func nextUInt8s(array: Array<UInt8>): Array<UInt8>
Description: Generates a random number to replace each element in an input parameter array.
Parameters:
Returns:
std.reflect Package
Function Description
The reflect package provides reflection functionality, allowing the program to obtain the type information of various instances at runtime and perform various read, write, and call operations.
This package currently does not work on macOS.
Note:
- For global information, the reflection functionality of Cangjie can access only public global variables and global functions.
- For the current package, the reflection functionality of Cangjie can access all globally defined types. For externally imported packages or dynamically loaded modules, it can access only the publicly defined global types within them.
- For member information, the reflection functionality of Cangjie can access only public members (instances/static member variables/attributes/functions) within the type. Members that are decorated with non-
publicmodifiers or default modifiers are invisible.- Currently, the reflection functionality of Cangjie does not support
Nothingtypes, function types, tuple types,enumtypes, or genericstructtypes.
API
Function
| Name | Description |
|---|---|
| parseParameterTypes(String) | Converts a string into a function signature that contains specific type information for use by functions such as getStaticFunction. |
Class
| Name | Description |
|---|---|
| TypeInfo | Provides a common interface for operations on all data types and allows users to perform reflection operations. |
| ClassTypeInfo | Describes information about the class type. |
| InterfaceTypeInfo | Describes information about the interface type. |
| PrimitiveTypeInfo | Describes information about the primitive data type. |
| StructTypeInfo | Describes information about the struct type. |
| InfoList | An information list used to store read-only reflection information. |
| ConstructorInfo | Describes constructor functions. |
| ParameterInfo | Describes function parameters. |
| InstanceFunctionInfo | Describes instance member functions. |
| StaticFunctionInfo | Describes static member functions. |
| InstancePropertyInfo | Describes instance member properties. |
| StaticPropertyInfo | Describes static member properties. |
| InstanceVariableInfo | Describes instance member variables. |
| StaticVariableInfo | Describes static member variables. |
| ModuleInfo | Describes module information, providing the ability for Cangjie dynamic module loading, caching, and querying package information within the module. |
| PackageInfo | Describes package information. |
| GlobalFunctionInfo | Describes global functions. |
| GlobalVariableInfo | Describes global variables. |
Enumeration
| Name | Description |
|---|---|
| ModifierInfo | Describes information about modifiers. |
Exception
| Name | Description |
|---|---|
| ReflectException | Specifies the base exception class for the Reflect package. |
| InfoNotFoundException | Indicates that the corresponding information cannot be found. |
| MisMatchException | Indicates an exception thrown when the corresponding function is called incorrectly. |
| IllegalSetException | Indicates an exception thrown upon an attempt to modify an immutable type. |
| IllegalTypeException | Indicates a type mismatch exception. |
| InvocationTargetException | Indication an exception that wraps a function invocation exception. |
Function
func parseParameterTypes(String)
public func parseParameterTypes(parameterTypes: String): Array<TypeInfo>
Description: Parses parameter types from a string and converts them into an array of types for use by functions such as getStaticFunction.
The qualified name of a function parameter type refers to the parameter type portion of the function type, excluding the parameter names, default values, and outermost parentheses (). Therefore, for the following Cangjie function:
import m1.p1.T1
func f(a: Int64, b: T1, c!: Int64 = 0, d!: Int64 = 0): Int64 { ... }
The qualified name should be "Int64, m1/p1.T1, Int64, Int64". The qualified name of a function without parameters should be "".
Parameters:
- parameterTypes: String: qualified name of the function parameter types
Returns:
Throws:
- IllegalArgumentException: If the string format is incorrect, this exception is thrown.
- InfoNotFoundException: If the type information of the parameters cannot be obtained, this exception is thrown.
Class
class ClassTypeInfo
public class ClassTypeInfo <: TypeInfo
Description: Describes type information of the class type.
Parent Type:
prop constructors
public prop constructors: Collection<ConstructorInfo>
Description: Obtains information about all public constructors of the class corresponding to ClassTypeInfo and returns the corresponding collection.
Note:
- If the
classtype does not have any public constructor, an empty collection is returned.- The collection does not guarantee a constant traversal sequence.
Type: Collection<ConstructorInfo>
prop instanceVariables
public prop instanceVariables: Collection<InstanceVariableInfo>
Description: Obtains information about all public instance variables of the class corresponding to ClassTypeInfo and returns the corresponding collection.
Note:
- If the
classtype does not have any public instance variable, an empty collection is returned.- The collection does not guarantee a constant traversal sequence.
- The collection does not contain any inherited public instance variable.
Type: Collection<InstanceVariableInfo>
prop sealedSubclasses
public prop sealedSubclasses: Collection<ClassTypeInfo>
Description: Obtains the type information of all subclasses in the package to which the class type belongs and returns the corresponding collection if the class type corresponding to ClassTypeInfo has the sealed semantics.
Note:
- If the
classtype does not have thesealedsemantics, an empty collection is returned.- If the
classtype has thesealedsemantics, the obtained collection cannot be an empty collection because theclasstype itself is its own subclass.
Type: Collection<ClassTypeInfo>
prop staticVariables
public prop staticVariables: Collection<StaticVariableInfo>
Description: Obtains information about all public static member variables of the class corresponding to ClassTypeInfo and returns the corresponding collection.
Note:
- If the
classtype does not have any public static member variable, an empty collection is returned.- The collection does not guarantee a constant traversal sequence.
- The collection does not contain any inherited public static member variable.
Type: Collection<StaticVariableInfo>
prop superClass
public prop superClass: Option<ClassTypeInfo>
Description: Obtains the direct parent class of the class type corresponding to the class type information.
Note:
Theoretically, only class Object does not have a direct parent class.
Type: Option<ClassTypeInfo>
func construct(Array<Any>)
public func construct(args: Array<Any>): Any
Description: Searches for and calls a matched constructor based on the actual parameter list in the class type corresponding to ClassTypeInfo, passes the actual parameter list, and returns the call result.
Parameters:
Returns:
- Any: instance of the
classtype
Throws:
- IllegalTypeException: If the
classtype has theabstractsemantics, this exception is thrown whenconstructis called because an abstract class cannot be instantiated. - MisMatchException: If
argsfails to match any public constructor of theclasstype, this exception is thrown. - InvocationTargetException: Any exception thrown inside the called constructor is encapsulated as InvocationTargetException and thrown.
func getConstructor(Array<TypeInfo>)
public func getConstructor(parameterTypes: Array<TypeInfo>): ConstructorInfo
Description: Attempts to obtain information about the public constructor that matches a given formal parameter type information list from the class type corresponding to ClassTypeInfo.
Parameters:
Returns:
- ConstructorInfo: If a match is found, information about the public constructor is returned.
Throws:
- InfoNotFoundException: If no matched public constructor is found, this exception is thrown.
func getInstanceVariable(String)
public func getInstanceVariable(name: String): InstanceVariableInfo
Description: Attempts to obtain information about the matched instance variable in the class type corresponding to ClassTypeInfo based on a given variable name.
Parameters:
- name: String: variable name
Returns:
- InstanceVariableInfo: If a match is found, information about the instance variable is returned.
Throws:
- InfoNotFoundException: If no matched instance variable is found, this exception is thrown.
func getStaticVariable(String)
public func getStaticVariable(name: String): StaticVariableInfo
Description: Attempts to obtain information about the matched static member variable in the class type corresponding to ClassTypeInfo based on a given variable name.
Parameters:
- name: String: variable name
Returns:
- StaticVariableInfo: If a match is found, information about the static member variable is returned.
Throws:
- InfoNotFoundException: If no matched static member variable is found, this exception is thrown.
func isAbstract()
public func isAbstract(): Bool
Description: Checks whether the class type corresponding to ClassTypeInfo is an abstract class.
Returns:
- Bool: If the
classtype corresponding to ClassTypeInfo is an abstract class,trueis returned. Otherwise,falseis returned.
func isOpen()
public func isOpen(): Bool
Description: Checks whether the class type corresponding to ClassTypeInfo has the open semantics.
Note:
It is not necessary that only the
classtype modified by theopenmodifier has theopensemantics. For example,abstract classhas theopensemantics no matter whether it is modified by theopenmodifier.
Returns:
- Bool: If the
classtype corresponding to ClassTypeInfo has theopensemantics,trueis returned. Otherwise,falseis returned.
func isSealed()
public func isSealed(): Bool
Description: Checks whether the class type corresponding to ClassTypeInfo has the sealed semantics.
Returns:
- Bool: If the
classtype corresponding to ClassTypeInfo has thesealedsemantics,trueis returned. Otherwise,falseis returned.
class ConstructorInfo
public class ConstructorInfo <: Equatable<ConstructorInfo> & Hashable & ToString
Description: Describes constructor information.
Parent Type:
prop annotations
public prop annotations: Collection<Annotation>
Description: Obtains all annotations applied to the constructors corresponding to ConstructorInfo and returns the corresponding collection.
Note:
- If no annotation is applied to the constructors corresponding to the constructor information, an empty collection is returned.
- The collection does not guarantee a constant traversal sequence.
Type: Collection<Annotation>
prop parameters
public prop parameters: InfoList<ParameterInfo>
Description: Obtains the formal parameter type list of the constructor corresponding to ConstructorInfo.
Type: InfoList<ParameterInfo>
func apply(Array<Any>)
public func apply(args: Array<Any>): Any
Description: Calls the constructor corresponding to ConstructorInfo, passes the actual parameter list, and returns the call result.
Note:
- Currently, an actual parameter cannot be an instance of the
structtype.- Currently, constructors defined in a
structtype cannot be called.
Parameters:
Returns:
- Any: type instance constructed by the constructor
Throws:
- InvocationTargetException: If the constructor corresponding to the constructor information belongs to an abstract class, this exception is thrown.
- IllegalArgumentException: If the number of actual parameters in the actual parameter list
argsis not equal to that of formal parameters in the formal parameter list of the constructor corresponding to the constructor information, this exception is thrown. - IllegalTypeException: If the runtime type of any actual parameter in the actual parameter list
argsis not a subtype of the declaring type of the corresponding formal parameters of the constructor corresponding to the constructor information, this exception is thrown. - Exception: If an exception is thrown inside the constructor corresponding to the called constructor information, the exception is encapsulated as Exception and thrown.
func findAnnotation<T>() where T <: Annotation
public func findAnnotation<T>(): Option<T> where T <: Annotation
Description: Attempts to obtain the annotation that is applied to the constructors corresponding to ConstructorInfo and has a given qualified name.
Returns:
- Option<T>: If a match is found, the annotation is returned. Otherwise,
Noneis returned.
func hashCode()
public func hashCode(): Int64
Description: Obtains the hash value of the constructor information.
Returns:
- Int64: hash value of the constructor information
func toString()
public func toString(): String
Description: Obtains the constructor information in string format.
Returns:
- String: constructor information in string format
operator func !=(ConstructorInfo)
public operator func !=(that: ConstructorInfo): Bool
Description: Checks whether the constructor information is not equal to given constructor information.
Parameters:
- that: ConstructorInfo: other constructor information that is compared for equality
Returns:
- Bool: If the constructor information is not equal to
that,trueis returned. Otherwise,falseis returned.
operator func ==(ConstructorInfo)
public operator func ==(that: ConstructorInfo): Bool
Description: Checks whether the constructor information is equal to given constructor information.
Parameters:
- that: ConstructorInfo: other constructor information that is compared for equality
Returns:
- Bool: If the constructor information is equal to
that,trueis returned. Otherwise,falseis returned.
class GlobalFunctionInfo
public class GlobalFunctionInfo <: Equatable<GlobalFunctionInfo> & Hashable & ToString
Description: Describes global function information.
Parent Type:
prop name
public prop name: String
Description: Obtains the name of the global function corresponding to GlobalFunctionInfo.
Note:
All global functions that make up an overloading have the same name.
Type: String
prop parameters
public prop parameters: InfoList<ParameterInfo>
Description: Obtains the formal parameter information list of the global function corresponding to GlobalFunctionInfo.
Type: InfoList<ParameterInfo>
prop returnType
public prop returnType: TypeInfo
Description: Obtains the return type information of the global function corresponding to GlobalFunctionInfo.
Type: TypeInfo
func apply(Array<Any>)
public func apply(args: Array<Any>): Any
Description: Calls the global function corresponding to GlobalFunctionInfo, passes the actual parameter list, and returns the call result.
Note:
Currently, an actual parameter cannot be an instance of the
structtype.
Parameters:
Returns:
- Any: call result of the global function
Throws:
- IllegalArgumentException: If the number of actual parameters in the actual parameter list
argsis not equal to that of formal parameters in the formal parameter list of the global function corresponding to the global function information, this exception is thrown. - IllegalTypeException: If the runtime type of any actual parameter in the actual parameter list
argsis not a subtype of the declaring type of the corresponding formal parameters of the global function corresponding to the global function information, this exception is thrown. - Exception: If an exception is thrown inside the global function corresponding to the called global function information, the exception is encapsulated as Exception and thrown.
func hashCode()
public func hashCode(): Int64
Description: Obtains the hash value of the global function information.
Returns:
- Int64: hash value of the global function information
func toString()
public func toString(): String
Description: Obtains the global function information in string format.
Returns:
- String: global function information in string format
operator func ==(GlobalFunctionInfo)
public operator func ==(that: GlobalFunctionInfo): Bool
Description: Checks whether the global function information is equal to given global function information.
Parameters:
- that: GlobalFunctionInfo: other global function information that is compared for equality
Returns:
- Bool: If the global function information is equal to
that,trueis returned. Otherwise,falseis returned.
operator func !=(GlobalFunctionInfo)
public operator func !=(that: GlobalFunctionInfo): Bool
Description: Checks whether the global function information is not equal to given global function information.
Parameters:
- that: GlobalFunctionInfo: other global function information that is compared for equality
Returns:
- Bool: If the global function information is not equal to
that,trueis returned. Otherwise,falseis returned.
class GlobalVariableInfo
public class GlobalVariableInfo <: Equatable<GlobalVariableInfo> & Hashable & ToString
Description: Describes global variable information.
Parent Type:
prop name
public prop name: String
Description: Obtains the name of the global variable corresponding to GlobalVariableInfo.
Type: String
prop typeInfo
public prop typeInfo: TypeInfo
Description: Obtains the declaring type information of the global variable corresponding to GlobalVariableInfo.
Type: TypeInfo
func getValue()
public func getValue(): Any
Description: Obtains the value of the global variable corresponding to GlobalVariableInfo.
Returns:
- Any: value of the global variable
func hashCode()
public func hashCode(): Int64
Description: Obtains the hash value of the global variable information.
Returns:
- Int64: hash value of the global variable information
func isMutable()
public func isMutable(): Bool
Description: Checks whether the global variables corresponding to GlobalVariableInfo can be modified.
Note:
- If an instance variable is modified by the
varmodifier, the global variable can be modified.- If an instance variable is modified by the
letmodifier, the global variable cannot be modified.- Any global variable whose type is
structcannot be modified.
Returns:
- Bool: If the global variable can be modified,
trueis returned. Otherwise,falseis returned.
func setValue(Any)
public func setValue(newValue: Any): Unit
Description: Sets the value of the global variable corresponding to GlobalVariableInfo.
Parameters:
- newValue: Any: new value
Throws:
- IllegalSetException: If the global variable corresponding to the global variable information cannot be modified, this exception is thrown.
- IllegalTypeException: If the runtime type of
newValueis not a subtype of the declaring type of the global variable corresponding to the global variable information, this exception is thrown.
func toString()
public func toString(): String
Description: Obtains the global variable information in string format.
Returns:
- String: global variable information in string format
operator func ==(GlobalVariableInfo)
public operator func ==(that: GlobalVariableInfo): Bool
Description: Checks whether the global variable information is equal to given global variable information.
Parameters:
- that: GlobalVariableInfo: other global variable information that is compared for equality
Returns:
- Bool: If the global variable information is equal to
that,trueis returned. Otherwise,falseis returned.
operator func !=(GlobalVariableInfo)
public operator func !=(that: GlobalVariableInfo): Bool
Description: Checks whether the global variable information is not equal to given global variable information.
Parameters:
- that: GlobalVariableInfo: other global variable information that is compared for equality
Returns:
- Bool: If the global variable information is not equal to
that,trueis returned. Otherwise,falseis returned.
class InfoList
public class InfoList<T> <: Collection<T>
Description: Specifies an information list, which saves read-only reflection information.
Parent Type:
- Collection<T>
prop size
public prop size: Int64
Description: Obtains the number of elements in the information list.
Type: Int64
func get(Int64)
public func get(index: Int64): ?T
Description: Attempts to obtain the element at a specified location in the information list.
Parameters:
- index: Int64: location index
Returns:
- ?T: element at the specified location in the information list
func isEmpty()
public func isEmpty(): Bool
Description: Checks whether the information list is empty.
Returns:
- Bool: If the information list is empty,
trueis returned. Otherwise,falseis returned.
func iterator()
public func iterator(): Iterator<T>
Description: Obtains the iterator of the information list.
Returns:
- Iterator<T>: iterator of the information list
operator func [](Int64)
public operator func [](index: Int64): T
Description: Obtains the element at a specified location in the information list.
Parameters:
- index: Int64: location index
Returns:
- T: element at the specified location in the information list
Throws:
- IndexOutOfBoundsException: If
indexis out of range, this exception is thrown.
class InstanceFunctionInfo
public class InstanceFunctionInfo <: Equatable<InstanceFunctionInfo> & Hashable & ToString
Description: Describes instance function information.
Parent Type:
prop annotations
public prop annotations: Collection<Annotation>
Description: Obtains all annotations applied to the instance functions corresponding to InstanceFunctionInfo and returns the corresponding collection.
Note:
- If no annotation is applied to the instance functions corresponding to the instance function information, an empty collection is returned.
- The collection does not guarantee a constant traversal sequence.
Type: Collection<Annotation>
prop modifiers
public prop modifiers: Collection<ModifierInfo>
Description: Obtains information about all modifiers of the instance function corresponding to InstanceFunctionInfo and returns the corresponding collection.
Note:
- If no modifier information is found, an empty collection is returned.
- The collection does not guarantee a constant traversal sequence.
- Information about a modifier, whether present or not, is included in the collection as long as the modifier semantics is used.
Type: Collection<ModifierInfo>
prop name
public prop name: String
Description: Obtains the name of the instance function corresponding to InstanceFunctionInfo.
Note:
- All instance functions that make up an overloading have the same name.
- The name of an operator overloading function is the symbol of the operator itself, for example, "
+", "*", and "[]".
Type: String
prop parameters
public prop parameters: InfoList<ParameterInfo>
Description: Obtains the formal parameter information list of the instance function corresponding to InstanceFunctionInfo.
Type: InfoList<ParameterInfo>
prop returnType
public prop returnType: TypeInfo
Description: Obtains the return value type information of the instance function corresponding to InstanceFunctionInfo.
Type: TypeInfo
func apply(Any, Array<Any>)
public func apply(instance: Any, args: Array<Any>): Any
Description: Calls the instance function corresponding to InstanceFunctionInfo, specifies an instance, passes the actual parameter list, and returns the call result.
Note:
- Currently,
instancecannot be an instance of thestructtype.- Currently, an actual parameter cannot be an instance of the
structtype.
Parameters:
Returns:
- Any: call result of the instance function
Throws:
- InvocationTargetException: If the instance function corresponding to the instance function information is abstract, this exception is thrown.
- IllegalTypeException: If the runtime type of
instanceis not strictly equal to the type of the instance function corresponding to the instance function information, this exception is thrown. - IllegalArgumentException: If the number of actual parameters in the actual parameter list
argsis not equal to that of formal parameters in the formal parameter list of the instance function corresponding to the instance function information, this exception is thrown. - IllegalTypeException: If the runtime type of any actual parameter in the actual parameter list
argsis not a subtype of the declaring type of the corresponding formal parameters of the instance function corresponding to the instance function information, this exception is thrown. - Exception: If an exception is thrown inside the instance function corresponding to the called instance function information, the exception is encapsulated as Exception and thrown.
func findAnnotation<T>() where T <: Annotation
public func findAnnotation<T>(): Option<T> where T <: Annotation
Description: Attempts to obtain the annotation that is applied to the instance functions corresponding to InstanceFunctionInfo and has a given qualified name.
Returns:
- Option<T>: If a match is found, the annotation is returned. Otherwise,
Noneis returned.
func hashCode()
public func hashCode(): Int64
Description: Obtains the hash value of the instance function information.
Returns:
- Int64: hash value of the instance function information
func isAbstract()
public func isAbstract(): Bool
Description: Checks whether the instance function corresponding to InstanceFunctionInfo has the abstract semantics.
Returns:
- Bool: If the instance function has the
abstractsemantics,trueis returned. Otherwise,falseis returned.
func isOpen()
public func isOpen(): Bool
Description: Checks whether the instance function corresponding to InstanceFunctionInfo has the open semantics.
Returns:
- Bool: If the instance function has the
opensemantics,trueis returned. Otherwise,falseis returned.
Note:
By default, instance functions of the
interfacetype have theopensemantics.
func toString()
public func toString(): String
Description: Obtains the instance function information in string format.
Returns:
- String: instance function information in string format
operator func ==(InstanceFunctionInfo)
public operator func ==(that: InstanceFunctionInfo): Bool
Description: Checks whether the instance function information is equal to given instance function information.
Parameters:
- that: InstanceFunctionInfo: other instance function information that is compared for equality
Returns:
- Bool: If the instance function information is equal to
that,trueis returned. Otherwise,falseis returned.
operator func !=(InstanceFunctionInfo)
public operator func !=(that: InstanceFunctionInfo): Bool
Description: Checks whether the instance function information is not equal to given instance function information.
Parameters:
- that: InstanceFunctionInfo: other instance function information that is compared for equality
Returns:
- Bool: If the instance function information is not equal to
that,trueis returned. Otherwise,falseis returned.
class InstancePropertyInfo
public class InstancePropertyInfo <: Equatable<InstancePropertyInfo> & Hashable & ToString
Description: Describes instance property information.
Parent Type:
prop annotations
public prop annotations: Collection<Annotation>
Description: Obtains all annotations applied to the instance properties corresponding to InstancePropertyInfo and returns the corresponding collection.
Note:
- If no annotation is applied to the instance properties corresponding to the instance property information, an empty collection is returned.
- The collection does not guarantee a constant traversal sequence.
Type: Collection<Annotation>
prop modifiers
public prop modifiers: Collection<ModifierInfo>
Description: Obtains information about all modifiers of the instance property corresponding to InstancePropertyInfo and returns the corresponding collection.
Note:
- If the instance property is not modified by any modifiers, an empty collection is returned.
- The collection does not guarantee a constant traversal sequence.
- Information about a modifier, whether present or not, is included in the collection as long as the modifier semantics is used.
Type: Collection<ModifierInfo>
prop name
public prop name: String
Description: Obtains the name of the instance property corresponding to InstancePropertyInfo.
Type: String
prop typeInfo
public prop typeInfo: TypeInfo
Description: Obtains the declaring type information of the instance property corresponding to InstancePropertyInfo.
Type: TypeInfo
func findAnnotation<T>() where T <: Annotation
public func findAnnotation<T>(): Option<T> where T <: Annotation
Description: Attempts to obtain the annotation that is applied to the instance properties corresponding to InstancePropertyInfo and has a given qualified name.
Returns:
- Option<T>: If a match is found, the annotation is returned. Otherwise,
Noneis returned.
func getValue(Any)
public func getValue(instance: Any): Any
Description: Obtains the value of the instance property corresponding to InstancePropertyInfo in a specified instance.
Note:
Currently,
instancecannot be an instance of thestructtype.
Parameters:
- instance: Any: instance
Returns:
- Any: value of the instance property in
instance
Throws:
- IllegalTypeException: If the runtime type of
instanceis not strictly equal to the type of the instance property corresponding to the instance property information, this exception is thrown.
func hashCode()
public func hashCode(): Int64
Description: Obtains the hash value of the instance property information.
Returns:
- Int64: hash value of the instance property information
func isMutable()
public func isMutable(): Bool
Description: Checks whether the instance properties corresponding to InstancePropertyInfo can be modified.
Note:
- If an instance property is modified by the
mutmodifier, it can be modified. Otherwise, it cannot be modified.- Any instance property of an instance belonging to any
structtype cannot be modified.- Any instance property whose type is
structcannot be modified.
Returns:
- Bool: If the instance properties corresponding to the instance property information can be modified,
trueis returned. Otherwise,falseis returned.
func setValue(Any, Any)
public func setValue(instance: Any, newValue: Any): Unit
Description: Sets the value of the instance property corresponding to InstancePropertyInfo in a specified instance.
Note:
Currently,
instancecannot be an instance of thestructtype.
Parameters:
Throws:
- IllegalSetException: If the instance property corresponding to the instance property information cannot be modified, this exception is thrown.
- IllegalTypeException: If the runtime type of
instanceis not strictly equal to the type of the instance property corresponding to the instance property information, this exception is thrown. - IllegalTypeException: If the runtime type of
newValueis not a subtype of the declaring type of the instance property corresponding to the instance property information, this exception is thrown.
func toString()
public func toString(): String
Description: Obtains the instance property information in string format.
Returns:
- String: instance property information in string format
operator func !=(InstancePropertyInfo)
public operator func !=(that: InstancePropertyInfo): Bool
Description: Checks whether the instance property information is not equal to given instance property information.
Parameters:
- that: InstancePropertyInfo: other instance property information that is compared for equality
Returns:
- Bool: If the instance property information is not equal to
that,trueis returned. Otherwise,falseis returned.
operator func ==(InstancePropertyInfo)
public operator func ==(that: InstancePropertyInfo): Bool
Description: Checks whether the instance property information is equal to given instance property information.
Parameters:
- that: InstancePropertyInfo: other instance property information that is compared for equality
Returns:
- Bool: If the instance property information is equal to
that,trueis returned. Otherwise,falseis returned.
class InstanceVariableInfo
public class InstanceVariableInfo <: Equatable<InstanceVariableInfo> & Hashable & ToString
Description: Describes instance variable information.
Parent Type:
prop annotations
public prop annotations: Collection<Annotation>
Description: Obtains all annotations applied to the instance variables corresponding to InstanceVariableInfo and returns the corresponding collection.
Note:
- If no annotation is applied to the instance variables corresponding to the instance variable information, an empty collection is returned.
- The collection does not guarantee a constant traversal sequence.
Type: Collection<Annotation>
prop modifiers
public prop modifiers: Collection<ModifierInfo>
Description: Obtains information about all modifiers of the instance variable corresponding to InstanceVariableInfo and returns the corresponding collection.
Note:
- If no modifier information is found, an empty collection is returned.
- The collection does not guarantee a constant traversal sequence.
- Information about a modifier, whether present or not, is included in the collection as long as the modifier semantics is used.
Type: Collection<ModifierInfo>
prop name
public prop name: String
Description: Obtains the name of the instance variable corresponding to InstanceVariableInfo.
Type: String
prop typeInfo
public prop typeInfo: TypeInfo
Description: Obtains the declaring type information of the instance variable corresponding to InstanceVariableInfo.
Type: TypeInfo
func findAnnotation<T>() where T <: Annotation
public func findAnnotation<T>(): Option<T> where T <: Annotation
Description: Attempts to obtain the annotation that is applied to the instance variables corresponding to InstanceVariableInfo and has a given qualified name.
Returns:
- Option<T>: If a match is found, the annotation is returned. Otherwise,
Noneis returned.
func getValue(Any)
public func getValue(instance: Any): Any
Description: Obtains the value of the instance variable corresponding to InstanceVariableInfo in a specified instance.
Note:
- Currently,
instancecannot be an instance of thestructtype.- Currently, the return value cannot be an instance of the
structtype.
Parameters:
- instance: Any: instance
Returns:
- Any: value of the instance variable in
instance
Throws:
- IllegalTypeException: If the runtime type of
instanceis not strictly equal to the type of the instance variable corresponding to the instance variable information, this exception is thrown.
func hashCode()
public func hashCode(): Int64
Description: Obtains the hash value of the instance variable information.
Returns:
- Int64: hash value of the instance variable information
func isMutable()
public func isMutable(): Bool
Description: Checks whether the instance variables corresponding to InstanceVariableInfo can be modified.
Note:
- An instance variable modified by the
varmodifier can be modified.- An instance variable modified by the
letmodifier cannot be modified.- Any instance variable of an instance belonging to any
structtype cannot be modified.- Any instance variable whose type is
structcannot be modified.
Returns:
- Bool: If the instance variables corresponding to the instance variable information can be modified,
trueis returned. Otherwise,falseis returned.
func setValue(Any, Any)
public func setValue(instance: Any, newValue: Any): Unit
Description: Sets the value of the instance variable corresponding to InstanceVariableInfo in a specified instance.
Note:
Currently,
instancecannot be an instance of thestructtype.
Parameters:
Throws:
- IllegalSetException: If the instance variable corresponding to the instance variable information cannot be modified, this exception is thrown.
- IllegalTypeException: If the runtime type of
instanceis not strictly equal to the type of the instance variable corresponding to the instance variable information, this exception is thrown. - IllegalTypeException: If the runtime type of
newValueis not a subtype of the declaring type of the instance variables corresponding to the instance variable information, this exception is thrown.
func toString()
public func toString(): String
Description: Obtains the instance variable information in string format.
Returns:
- String: instance variable information in string format
operator func ==(InstanceVariableInfo)
public operator func ==(that: InstanceVariableInfo): Bool
Description: Checks whether the instance variable information is equal to given instance variable information.
Parameters:
- that: InstanceVariableInfo: other instance variable information that is compared for equality
Returns:
- Bool: If the instance variable information is equal to
that,trueis returned. Otherwise,falseis returned.
operator func !=(InstanceVariableInfo)
public operator func !=(that: InstanceVariableInfo): Bool
Description: Checks whether the instance variable information is not equal to given instance variable information.
Parameters:
- that: InstanceVariableInfo: other instance variable information that is compared for equality
Returns:
- Bool: If the instance variable information is not equal to
that,trueis returned. Otherwise,falseis returned.
class InterfaceTypeInfo
public class InterfaceTypeInfo <: TypeInfo
Description: Specifies the interface type information.
Parent Type:
prop sealedSubtypes
public prop sealedSubtypes: Collection<TypeInfo>
Description: Obtains the type information of all subtypes in the package to which the interface type belongs and returns the corresponding collection if the interface type corresponding to InterfaceTypeInfo has the sealed semantics.
Note:
- If the
interfacetype does not have thesealedsemantics, an empty collection is returned.- If the
interfacetype has thesealedsemantics, the obtained collection cannot be an empty collection because theinterfacetype itself is its own subtype.
Type: Collection<TypeInfo>
func isSealed()
public func isSealed(): Bool
Description: Checks whether the interface type corresponding to InterfaceTypeInfo has the sealed semantics.
Returns:
- Bool: If the
interfacetype has thesealedsemantics,trueis returned. Otherwise,falseis returned.
class ModuleInfo
public class ModuleInfo <: Equatable<ModuleInfo> & Hashable & ToString
Description: Describes module information and provides the capabilities of loading and caching Cangjie dynamic modules and querying package information inside the modules.
A Cangjie dynamic module is a special binary file generated by the Cangjie compiler. Such file can be loaded and used by an external Cangjie program at runtime.
Cangjie dynamic library modules exist in shared library (.so file), dynamic link library (.dll file), and other file formats in different operating systems.
Note:
A module cannot contain packages with the same qualified name.
Parent Type:
prop name
public prop name: String
Description: Obtains the name of the module corresponding to ModuleInfo.
Note:
- A module name is determined by the file name of the loaded module. The format of the file name is
lib<module_name>_<package_name>(.<package_name>)*.<module_name>and<package_name>cannot be empty.- Due to the limitations of the current implementation, if
<module_name>contains an underscore "_", unexpected loading errors may occur.
Type: String
prop packages
public prop packages: Collection<PackageInfo>
Description: Obtains all packages contained in the module.
Type: Collection<PackageInfo>
prop version
public prop version: String
Description: Obtains the version number of the module corresponding to ModuleInfo.
Note:
Currently, there is no version information in the dynamic library. Therefore, the obtained version number is always
1.0.
Type: String
static func find(String)
public static func find(moduleName: String): Option<ModuleInfo>
Description: Attempts to obtain information about the module that matches a given module name from all loaded Cangjie dynamic library modules.
Parameters:
- moduleName: String: Cangjie dynamic library module name
Returns:
- Option<ModuleInfo>: If a match is found, information about the module is returned. Otherwise,
Noneis returned.
static func load(String)
public static func load(path: String): ModuleInfo
Description: Dynamically loads a Cangjie dynamic library module in a specified path and obtains information about the module at runtime.
Notes:
- To improve compatibility, the shared library file name in
pathdoes not contain an extension (such as.soand.dll).- Due to the limitations of the current implementation, dynamic libraries with the same module name cannot be loaded at the same time. Otherwise, an exception is thrown. For example, the loading of the shared libraries corresponding to packages
m/a,m/a.b, andm/a.cis mutually exclusive.
Parameters:
- path: String: absolute or relative path of the shared library file
Throws:
- ReflectException: If the shared library fails to be loaded, this exception is thrown.
- UnsupportedException: If shared libraries with the same module name are loaded repeatedly, this exception is thrown.
func getPackageInfo(String)
public func getPackageInfo(packageName: String): PackageInfo
Description: Attempts to obtain information about the package that matches the name or qualified name of a given package in the module corresponding to ModuleInfo.
Parameters:
- packageName: String: name or qualified name of the package
Returns:
- PackageInfo: If a match is found, information about the package is returned.
Throws:
- InfoNotFoundException: If no matched package is found, this exception is thrown.
func hashCode()
public func hashCode(): Int64
Description: Obtains the hash value of the module information.
Returns:
- Int64: hash value of the module information
Note:
The internal implementation is the hash value of the string consisting of the name and version number of the module information.
func toString()
public func toString(): String
Description: Obtains the module information in string format.
Returns:
- String: module information in string format
Note:
The content is the name and version number of the module.
operator func !=(ModuleInfo)
public operator func !=(that: ModuleInfo): Bool
Description: Checks whether the module information is not equal to given module information.
Parameters:
- that: ModuleInfo: other module information that is compared for equality
Returns:
- Bool: If the module information is not equal to
that,trueis returned. Otherwise,falseis returned.
operator func ==(ModuleInfo)
public operator func ==(that: ModuleInfo): Bool
Description: Checks whether the module information is equal to given module information.
Parameters:
- that: ModuleInfo: other module information that is compared for equality
Returns:
- Bool: If the module information is equal to
that,trueis returned. Otherwise,falseis returned.
class PackageInfo
public class PackageInfo <: Equatable<PackageInfo> & Hashable & ToString
Description: Describes package information.
Parent Type:
prop functions
public prop functions: Collection<GlobalFunctionInfo>
Description: Obtains the list consisting of information about all public global functions in the package corresponding to PackageInfo.
Type: Collection<GlobalFunctionInfo>
prop name
public prop name: String
Description: Obtains the name of the package corresponding to the package information.
Note:
A package name does not contain the name of the module where the package is located or the name of its parent package. For example, the name of the package with the qualified name
a/b.c.disd.
Type: String
prop qualifiedName
public prop qualifiedName: String
Description: Obtains the qualified name of the package corresponding to PackageInfo.
Note:
The qualified name of a package is in the format of
(module_name/)?(default|package_name)(.package_name)*. For example, the package with the qualified namea/b.c.dis in packagecin packagebunder modulea.
Type: String
prop typeInfos
public prop typeInfos: Collection<TypeInfo>
Description: Obtains the type information of all globally defined public types in the package corresponding to PackageInfo and returns the corresponding collection.
Note:
Currently, the list does not contain all types that cannot be reflected.
Type: Collection<TypeInfo>
prop variables
public prop variables: Collection<GlobalVariableInfo>
Description: Obtains the list consisting of information about all public global variables in the package corresponding to PackageInfo.
Type: Collection<GlobalVariableInfo>
func getFunction(String, Array<TypeInfo>)
public func getFunction(name: String, parameterTypes: Array<TypeInfo>): GlobalFunctionInfo
Description: Attempts to obtain information about a public global function with a given function name and matching the given formal parameter type information list from the package corresponding to PackageInfo.
Parameters:
- name: String: global function name
- parameterTypes: Array<TypeInfo>: formal parameter type information list
Throws:
- InfoNotFoundException: If no matched globally defined public global function is found, this exception is thrown.
func getTypeInfo(String)
public func getTypeInfo(qualifiedName: String): TypeInfo
Description: Attempts to obtain the type information of the globally defined public type with a given type name from the package corresponding to PackageInfo.
Parameters:
- qualifiedName: String: qualified name of the type
Returns:
- TypeInfo: If a match is found, the type information of the globally defined public type is returned.
Throws:
- InfoNotFoundException: If no matched globally defined public type is found, this exception is thrown.
func getVariable(String)
public func getVariable(name: String): GlobalVariableInfo
Description: Attempts to obtain information about a public global variable with a given variable name from the package corresponding to PackageInfo.
Parameters:
- name: String: global variable name
Throws:
- InfoNotFoundException: If no matched globally defined public global variable is found, this exception is thrown.
func hashCode()
public func hashCode(): Int64
Description: Obtains the hash value of the package information.
Returns:
- Int64: hash value of the package information
func toString()
public func toString(): String
Description: Obtains the package information in string format.
Note:
The internal implementation is the qualified name string of the package information.
Returns:
- String: package information in string format
operator func !=(PackageInfo)
public operator func !=(that: PackageInfo): Bool
Description: Checks whether the package information is not equal to given package information.
Note:
The internal implementation is to compare whether two package information qualified names are equal.
Parameters:
- that: PackageInfo: other package information that is compared for equality
Returns:
- Bool: If the package information is not equal to
that,trueis returned. Otherwise,falseis returned.
operator func ==(PackageInfo)
public operator func ==(that: PackageInfo): Bool
Description: Checks whether the package information is equal to given package information.
Note:
The internal implementation is to compare whether two package information qualified names are equal.
Parameters:
- that: PackageInfo: other package information that is compared for equality
Returns:
- Bool: If the package information is equal to
that,trueis returned. Otherwise,falseis returned.
class ParameterInfo
public class ParameterInfo <: Equatable<ParameterInfo> & Hashable & ToString
Description: Describes formal parameter information of a function.
Parent Type:
prop annotations
public prop annotations: Collection<Annotation>
Description: Obtains all annotations applied to the formal parameters of the function corresponding to ParameterInfo and returns the corresponding collection.
Note:
- If no annotation is applied to the formal parameters of the function corresponding to the function formal parameter information, an empty collection is returned.
- The collection does not guarantee a constant traversal sequence.
Type: Collection<Annotation>
prop index
public prop index: Int64
Description: Obtains the sequence number of the formal parameter corresponding to ParameterInfo in the function.
Note:
indexstarts from 0.
Type: Int64
prop name
public prop name: String
Description: Obtains the name of the formal parameter corresponding to ParameterInfo.
Type: String
prop typeInfo
public prop typeInfo: TypeInfo
Description: Obtains the declaring type information of the formal parameters of the function corresponding to ParameterInfo.
Type: TypeInfo
func findAnnotation<T>() where T <: Annotation
public func findAnnotation<T>(): Option<T> where T <: Annotation
Description: Attempts to obtain the annotation that is applied to the formal parameters of the function corresponding to ParameterInfo and has a given qualified name.
Returns:
- Option<T>: If a match is found, the annotation is returned. Otherwise,
Noneis returned.
func hashCode()
public func hashCode(): Int64
Description: Obtains the hash value of the formal parameter information of the function.
Returns:
- Int64: hash value of the formal parameter information of the function
func toString()
public func toString(): String
Description: Obtains the formal parameter information of the function in string format.
Returns:
- String: formal parameter information of the function in string format
operator func !=(ParameterInfo)
public operator func !=(that: ParameterInfo): Bool
Description: Checks whether the formal parameter information of the function is not equal to that of a given function.
Parameters:
- that: ParameterInfo: formal parameter information of another function that is compared for equality
Returns:
- Bool: If the formal parameter information of the function is not equal to
that,trueis returned. Otherwise,falseis returned.
operator func ==(ParameterInfo)
public operator func ==(that: ParameterInfo): Bool
Description: Checks whether the formal parameter information of the function is equal to that of a given function.
Parameters:
- that: ParameterInfo: formal parameter information of another function that is compared for equality
Returns:
- Bool: If the formal parameter information of the function is equal to
that,trueis returned. Otherwise,falseis returned.
class PrimitiveTypeInfo
public class PrimitiveTypeInfo <: TypeInfo
Description: Describes type information of a primitive data type.
Primitive data types include untyped (Nothing), unit (Unit), character (Rune), Boolean (Bool), integer (Int8, Int16, Int32, Int64, IntNative, UInt8, UInt16, UInt32, UInt64, UIntNative), and floating point (Float16, Float32, Float64) types.
Note:
Currently, the
Nothingprimitive data type is not supported.
Parent Type:
class StaticFunctionInfo
public class StaticFunctionInfo <: Equatable<StaticFunctionInfo> & Hashable & ToString
Description: Describes static member function information.
Parent Type:
prop annotations
public prop annotations: Collection<Annotation>
Description: Obtains all annotations applied to the static member functions corresponding to StaticFunctionInfo and returns the corresponding collection.
Note:
- If no annotation is applied to the static member functions corresponding to StaticFunctionInfo, an empty collection is returned.
- The collection does not guarantee a constant traversal sequence.
Type: Collection<Annotation>
prop modifiers
public prop modifiers: Collection<ModifierInfo>
Description: Obtains information about all modifiers of the static member function corresponding to StaticFunctionInfo and returns the corresponding collection.
Note:
- If the static member function is not modified by any modifiers, an empty collection is returned.
- The collection does not guarantee a constant traversal sequence.
- Information about a modifier, whether present or not, is included in the collection as long as the modifier semantics is used.
Type: Collection<ModifierInfo>
prop name
public prop name: String
Description: Obtains the name of the static member function corresponding to StaticFunctionInfo.
Note:
All static member functions that make up an overloading have the same name.
Type: String
prop parameters
public prop parameters: InfoList<ParameterInfo>
Description: Obtains the formal parameter information list of the static member function corresponding to StaticFunctionInfo.
Type: InfoList<ParameterInfo>
prop returnType
public prop returnType: TypeInfo
Description: Obtains the return value type information of the static member function corresponding to StaticFunctionInfo.
Type: TypeInfo
func apply(Array<Any>)
public func apply(args: Array<Any>): Any
Description: Calls the static member function corresponding to StaticFunctionInfo, passes the actual parameter list, and returns the call result.
Note:
Currently, an actual parameter cannot be an instance of the
structtype.
Parameters:
Returns:
- Any: call result of the static member function
Throws:
- IllegalArgumentException: If the number of actual parameters in the actual parameter list
argsis not equal to that of formal parameters in the formal parameter list of the static member function corresponding to the static member function information, this exception is thrown. - IllegalTypeException: If the runtime type of any actual parameter in the actual parameter list
argsis not a subtype of the declaring type of the corresponding formal parameters of the static member function corresponding to the static member function information, this exception is thrown. - Exception: If an exception is thrown inside the static member function corresponding to the called static member function information, the exception is encapsulated as Exception and thrown.
func findAnnotation<T>() where T <: Annotation
public func findAnnotation<T>(): Option<T> where T <: Annotation
Description: Attempts to obtain the annotation that is applied to the static member functions corresponding to StaticFunctionInfo and has a given qualified name.
Returns:
- Option<T>: If a match is found, the annotation is returned. Otherwise,
Noneis returned.
func hashCode()
public func hashCode(): Int64
Description: Obtains the hash value of the static member function information.
Returns:
- Int64: hash value of the static member function information
func toString()
public func toString(): String
Description: Obtains the static member function information in string format.
Returns:
- String: static member function information in string format
operator func !=(StaticFunctionInfo)
public operator func !=(that: StaticFunctionInfo): Bool
Description: Checks whether the static member function information is not equal to given static member function information.
Parameters:
- that: StaticFunctionInfo: other static member function information that is compared for equality
Returns:
- Bool: If the static member function information is not equal to
that,trueis returned. Otherwise,falseis returned.
operator func ==(StaticFunctionInfo)
public operator func ==(that: StaticFunctionInfo): Bool
Description: Checks whether the static member function information is equal to given static member function information.
Parameters:
- that: StaticFunctionInfo: other static member function information that is compared for equality
Returns:
- Bool: If the static member function information is equal to
that,trueis returned. Otherwise,falseis returned.
class StaticPropertyInfo
public class StaticPropertyInfo <: Equatable<StaticPropertyInfo> & Hashable & ToString
Description: Specifies the static member property information.
Parent Type:
prop annotations
public prop annotations: Collection<Annotation>
Description: Obtains the collection of all annotations applied to the static member properties corresponding to StaticPropertyInfo.
Note:
- If no annotation is applied to the static member properties corresponding to the static member property information, an empty collection is returned.
- The collection does not guarantee a constant traversal sequence.
Type: Collection<Annotation>
prop modifiers
public prop modifiers: Collection<ModifierInfo>
Description: Obtains information about all modifiers of the static member property corresponding to StaticPropertyInfo and returns the corresponding collection.
Note:
- If the static member property is not modified by any modifiers, an empty collection is returned.
- The collection does not guarantee a constant traversal sequence.
- Currently, the content of the obtained modifier collection is disordered and has not been unified.
Type: Collection<ModifierInfo>
prop name
public prop name: String
Description: Obtains the name of the static member property corresponding to StaticPropertyInfo.
Type: String
prop typeInfo
public prop typeInfo: TypeInfo
Description: Obtains the declaring type information of the static member property corresponding to StaticPropertyInfo.
Type: TypeInfo
func findAnnotation<T>() where T <: Annotation
public func findAnnotation<T>(): Option<T> where T <: Annotation
Description: Attempts to obtain the annotation that is applied to the static member properties corresponding to StaticPropertyInfo and has a given qualified name.
Returns:
- Option<T>: If a match is found, the annotation is returned. Otherwise,
Noneis returned.
func getValue()
public func getValue(): Any
Description: Obtains the value of the static member property corresponding to StaticPropertyInfo.
Note:
If the static member property lacks a valid implementation, for example, the abstract static member property of the
interfacetype, UnsupportedException should be thrown. However, this has not been implemented yet due to the lack of support by the backend.
Returns:
- Any: value of the static member property
func hashCode()
public func hashCode(): Int64
Description: Obtains the hash value of the static member property information.
Returns:
- Int64: hash value of the static member property information
func isMutable()
public func isMutable(): Bool
Description: Checks whether the static member properties corresponding to the static member property information can be modified.
Returns:
- Bool: If the static member properties corresponding to the static member property information can be modified,
trueis returned. Otherwise,falseis returned.
Note:
- If a static member property is modified by the
mutmodifier, it can be modified. Otherwise, it cannot be modified.- Any static member property belonging to any
structtype cannot be modified.- Any static member property whose type is
structcannot be modified.
func setValue(Any)
public func setValue(newValue: Any): Unit
Description: Sets the value of the static member property corresponding to StaticPropertyInfo.
Note:
If the static member property lacks a valid implementation, for example, the abstract static member property of the
interfacetype, UnsupportedException should be thrown. However, this has not been implemented yet due to the lack of support by the backend.
Parameters:
- newValue: Any: new value
Throws:
- IllegalSetException: If the static member property corresponding to the static member property information cannot be modified, this exception is thrown.
- IllegalTypeException: If the runtime type of
newValueis not a subtype of the declaring type of the static member property corresponding to the static member property information, this exception is thrown.
func toString()
public func toString(): String
Description: Obtains the static member property information in string format.
Returns:
- String: static member property information in string format
operator func !=(StaticPropertyInfo)
public operator func !=(that: StaticPropertyInfo): Bool
Description: Checks whether the static member property information is not equal to given static member property information.
Parameters:
- that: StaticPropertyInfo: other static member property information that is compared for equality
Returns:
- Bool: If the static member property information is not equal to
that,trueis returned. Otherwise,falseis returned.
operator func ==(StaticPropertyInfo)
public operator func ==(that: StaticPropertyInfo): Bool
Description: Checks whether the static member property information is equal to given static member property information.
Parameters:
- that: StaticPropertyInfo: other static member property information that is compared for equality
Returns:
- Bool: If the static member property information is equal to
that,trueis returned. Otherwise,falseis returned.
class StaticVariableInfo
public class StaticVariableInfo <: Equatable<StaticVariableInfo> & Hashable & ToString
Description: Describes static member variable information.
Parent Type:
prop annotations
public prop annotations: Collection<Annotation>
Description: Obtains all annotations applied to the static member variables corresponding to StaticVariableInfo and returns the corresponding collection.
Note:
- If no annotation is applied to the static member variables corresponding to StaticVariableInfo, an empty collection is returned.
- The collection does not guarantee a constant traversal sequence.
Type: Collection<Annotation>
prop modifiers
public prop modifiers: Collection<ModifierInfo>
Description: Obtains information about all modifiers of the static member variable corresponding to StaticVariableInfo and returns the corresponding collection.
Note:
- If the static member variable is not modified by any modifiers, an empty collection is returned.
- The collection does not guarantee a constant traversal sequence.
- Currently, the content of the obtained modifier collection is disordered and has not been unified.
Type: Collection<ModifierInfo>
prop name
public prop name: String
Description: Obtains the name of the static member variable corresponding to StaticVariableInfo.
Type: String
prop typeInfo
public prop typeInfo: TypeInfo
Description: Obtains the declaring type information of the static member variables corresponding to StaticVariableInfo.
Type: TypeInfo
func findAnnotation<T>() where T <: Annotation
public func findAnnotation<T>(): Option<T> where T <: Annotation
Description: Attempts to obtain the annotation that is applied to the static member variables corresponding to StaticVariableInfo and has a given qualified name.
Returns:
- Option<T>: If a match is found, the annotation is returned. Otherwise,
Noneis returned.
func getValue()
public func getValue(): Any
Description: Obtains the value of the static member variable corresponding to StaticVariableInfo.
Returns:
- Any: value of the static member variable
Note:
- The return value cannot be of the
structtype.
func hashCode()
public func hashCode(): Int64
Description: Obtains the hash value of the static member variable information.
Returns:
- Int64: hash value of the static member variable information
func isMutable()
public func isMutable(): Bool
Description: Checks whether the static member variables corresponding to StaticVariableInfo can be modified.
Note:
- A static member variable modified by the
varmodifier can be modified.- A static member variable modified by the
letmodifier cannot be modified.- Any static member variable belonging to any
structtype cannot be modified.- Any static member variable whose type is
structcannot be modified.
Returns:
- Bool: If the static member variables corresponding to the static member variable information can be modified,
trueis returned. Otherwise,falseis returned.
func setValue(Any)
public func setValue(newValue: Any): Unit
Description: Sets the value of the static member variable corresponding to StaticVariableInfo.
Parameters:
- newValue: Any: new value
Throws:
- IllegalSetException: If the static member variable corresponding to StaticVariableInfo cannot be modified, this exception is thrown.
- IllegalTypeException: If the runtime type of
newValueis not a subtype of the declaring type of the static member variables corresponding to the static member variable information, this exception is thrown.
func toString()
public func toString(): String
Description: Obtains the static member variable information in string format.
Returns:
- String: static member variable information in string format
operator func !=(StaticVariableInfo)
public operator func !=(that: StaticVariableInfo): Bool
Description: Checks whether the static member variable information is not equal to given static member variable information.
Parameters:
- that: StaticVariableInfo: other static member variable information that is compared for equality
Returns:
- Bool: If the static member variable information is not equal to
that,trueis returned. Otherwise,falseis returned.
operator func ==(StaticVariableInfo)
public operator func ==(that: StaticVariableInfo): Bool
Description: Checks whether the static member variable information is equal to given static member variable information.
Parameters:
- that: StaticVariableInfo: other static member variable information that is compared for equality
Returns:
- Bool: If the static member variable information is equal to
that,trueis returned. Otherwise,falseis returned.
class StructTypeInfo
public class StructTypeInfo <: TypeInfo
Description: Describes type information of a struct type.
Parent Type:
prop constructors
public prop constructors: Collection<ConstructorInfo>
Description: Obtains information about all public constructors of struct corresponding to StructTypeInfo and returns the corresponding collection.
Note:
- If the
structtype does not have any public constructor, an empty collection is returned.- The collection does not guarantee a constant traversal sequence.
Type: Collection<ConstructorInfo>
prop instanceVariables
public prop instanceVariables: Collection<InstanceVariableInfo>
Description: Obtains information about all public instance variables of struct corresponding to StructTypeInfo and returns the corresponding collection.
Note:
- If the
structtype does not have any public instance variable, an empty collection is returned.- The collection does not guarantee a constant traversal sequence.
Type: Collection<InstanceVariableInfo>
prop staticVariables
public prop staticVariables: Collection<StaticVariableInfo>
Description: Obtains information about all public static member variables of struct corresponding to StructTypeInfo and returns the corresponding collection.
Note:
- If the
structtype does not have any public static member variable, an empty collection is returned.- The collection does not guarantee a constant traversal sequence.
Type: Collection<StaticVariableInfo>
func construct(Array<Any>)
public func construct(args: Array<Any>): Any
Description: Searches for and calls the matched constructor based on an actual parameter list in the struct type corresponding to StructTypeInfo, passes the actual parameter list, and returns the call result.
Parameters:
Returns:
- Any: instance of the
structtype
Throws:
- MisMatchException: If
argsfails to match any public constructor of thestructtype, this exception is thrown. - InvocationTargetException: Any exception thrown inside the called constructor is encapsulated as InvocationTargetException and thrown.
Note:
Since the
constructfunction essentially calls theapplyfunction, currently, it cannot be used because a constructor defined in thestructtype cannot call theapplyfunction.
func getConstructor(Array<TypeInfo>)
public func getConstructor(parameterTypes: Array<TypeInfo>): ConstructorInfo
Description: Attempts to obtain information about a public constructor that matches a given formal parameter type information list from the struct type corresponding to StructTypeInfo.
Parameters:
Returns:
- ConstructorInfo: If a match is found, information about the public constructor is returned.
Throws:
- InfoNotFoundException: If no matched public constructor is found, this exception is thrown.
func getInstanceVariable(String)
public func getInstanceVariable(name: String): InstanceVariableInfo
Description: Attempts to obtain information about a matched instance variable in the struct type corresponding to StructTypeInfo based on a given variable name.
Parameters:
- name: String: variable name
Returns:
- InstanceVariableInfo: If a match is found, information about the instance variable is returned.
Throws:
- InfoNotFoundException: If no matched public instance variable is found, this exception is thrown.
func getStaticVariable(String)
public func getStaticVariable(name: String): StaticVariableInfo
Description: Attempts to obtain information about a matched static member variable in the struct type corresponding to StructTypeInfo based on a given variable name.
Parameters:
- name: String: variable name
Returns:
- StaticVariableInfo: If a match is found, information about the static member variable is returned.
Throws:
- InfoNotFoundException: If no matched public static member variable is found, this exception is thrown.
class TypeInfo
sealed abstract class TypeInfo <: Equatable<TypeInfo> & Hashable & ToString
Description: TypeInfo provides universal operation APIs for all data types. Developers can perform reflection operations without converting a data type to a more specific one, such as ClassTypeInfo.
Subtypes of TypeInfo include PrimitiveTypeInfo, StructTypeInfo, ClassTypeInfo, and InterfaceTypeInfo, which correspond to the basic, struct, class, and interface data types, respectively.
Note
The qualified name of a type is
(module_name/)?(default|package_name)(.package_name)*.(type_name).
Parent Type:
prop annotations
public prop annotations: Collection<Annotation>
Description: Obtains all annotations applied to the types corresponding to TypeInfo and returns the corresponding collection.
Note:
- If no annotation is applied to the types corresponding to the type information, an empty collection is returned.
- The collection does not guarantee a constant traversal sequence.
Type: Collection<Annotation>
prop instanceFunctions
public prop instanceFunctions: Collection<InstanceFunctionInfo>
Description: Obtains information about all public instance functions of the type corresponding to TypeInfo and returns the corresponding collection.
Note:
- If the type corresponding to TypeInfo does not have any public instance function, an empty collection is returned.
- The collection does not guarantee a constant traversal sequence.
- If the type corresponding to the type information is
structorclass, the collection contains information about non-abstract instance functions inherited from anotherinterfacetype.
Type: Collection<InstanceFunctionInfo>
prop instanceProperties
public prop instanceProperties: Collection<InstancePropertyInfo>
Description: Obtains information about all public instance properties of the type corresponding to TypeInfo and returns the corresponding collection.
Note:
- If the type corresponding to TypeInfo does not have any public instance property, an empty collection is returned.
- The collection does not guarantee a constant traversal sequence.
- If the type corresponding to the type information is
structorclass, the collection contains property information of non-abstract instances inherited from anotherinterfacetype.
Type: Collection<InstancePropertyInfo>
prop modifiers
public prop modifiers: Collection<ModifierInfo>
Description: Obtains information about all modifiers of the type corresponding to TypeInfo and returns the corresponding collection.
Note:
- If the type is not modified by any modifiers, an empty collection is returned.
- The collection does not guarantee a constant traversal sequence.
- By default, the
interfacetype has theopensemantics. Therefore, the returned collection always contains theopenmodifier.- Since the reflection function can only work on types modified by the
publicaccess control modifier, all access control modifiers are ignored.
Type: Collection<ModifierInfo>
prop name
public prop name: String
Description: Obtains the name of the type corresponding to TypeInfo.
Note:
- The name does not contain any module name prefix or package name prefix.
- The type information of a type alias is the type information of the actual type. Therefore, the function does not return the name of the type alias but the name of the actual type. For example, the name of the type information of the type alias Byte is UInt8 instead of Byte.
Type: String
prop qualifiedName
public prop qualifiedName: String
Description: Obtains the qualified name of the type corresponding to TypeInfo.
Note:
- The qualified name contains the module name prefix and package name prefix.
- In particular, the qualified names of Cangjie built-in data types and all types under the
corepackage of thestdmodule contain no module name prefix or package name prefix.- All types defined in the context of the default module name and package name have no module name prefix, but have a package name prefix
default, for example,default.MyType.
Type: String
prop staticFunctions
public prop staticFunctions: Collection<StaticFunctionInfo>
Description: Obtains information about all public static member functions of the type corresponding to TypeInfo and returns the corresponding collection.
Note:
- If the type corresponding to TypeInfo does not have any public static member function, an empty collection is returned.
- The collection does not guarantee a constant traversal sequence.
- If the type corresponding to the type information is
struct,class, orinterface, the collection contains information about non-abstract static member functions inherited from anotherinterfacetype.
Type: Collection<StaticFunctionInfo>
prop staticProperties
public prop staticProperties: Collection<StaticPropertyInfo>
Description: Obtains information about all public static member properties of the type corresponding to TypeInfo and returns the corresponding collection.
Note:
- If the type corresponding to TypeInfo does not have any public static member property, an empty collection is returned.
- The collection does not guarantee a constant traversal sequence.
- If the type corresponding to the type information is
struct,class, orinterface, the collection contains information about non-abstract static member properties inherited from anotherinterfacetype.
Type: Collection<StaticPropertyInfo>
prop superInterfaces
public prop superInterfaces: Collection<InterfaceTypeInfo>
Description: Obtains information about all interface types that are directly implemented by the type corresponding to TypeInfo and returns the corresponding collection.
Note:
Type: Collection<InterfaceTypeInfo>
static func get(String)
public static func get(qualifiedName: String): TypeInfo
Description: Obtains TypeInfo of the type corresponding to the qualified name of a given type.
Note:
- The type information of a generic type that is not instantiated cannot be obtained.
- Currently, the qualified name
qualifiedNameof a type does not support qualified names ofNothing, function, tuple, andenumtypes, as well asstructtype with generics.
Parameters:
- qualifiedName: String: qualified name of the type
Returns:
- TypeInfo: type information of the type corresponding to the qualified name
qualifiedNameof the type
Throws:
- InfoNotFoundException: If the type information of the type that matches the qualified name
qualifiedNameof the given type cannot be obtained, this exception is thrown.
static func of(Any)
public static func of(a: Any): TypeInfo
Description: Obtains the type information corresponding to the runtime type of a given instance of any type.
A runtime type is a type determined through dynamic binding when a program is running. A runtime type is bound to an instance object. In scenarios such as inheritance, the runtime type may be inconsistent with the static type.
Note:
Currently, instance
adoes not support instances whose runtime type is function, tuple,enum, orstructwith generics.
Parameters:
- a: Any: instance
Returns:
- TypeInfo: type information corresponding to the runtime type of instance
a
Throws:
- InfoNotFoundException: If the type information corresponding to the runtime type of instance
acannot be obtained, this exception is thrown.
static func of(Object)
public static func of(a: Object): ClassTypeInfo
Description: Obtains the class type information corresponding to the runtime type of a given instance of class type.
Parameters:
- a: Object: instance of
classtype
Returns:
- ClassTypeInfo:
classtype information corresponding to the runtime type of instanceaofclasstype
Throws:
- InfoNotFoundException: If the
classtype information corresponding to the runtime type of instanceacannot be obtained, this exception is thrown.
static func of<T>()
public static func of<T>(): TypeInfo
Description: Obtains type information corresponding to a given type.
Notes:
Returns:
- TypeInfo: type information corresponding to the
Ttype
Throws:
- InfoNotFoundException: If the type information corresponding to the T type cannot be obtained, this exception is thrown.
func findAnnotation<T>() where T <: Annotation
public func findAnnotation<T>(): Option<T> where T <: Annotation
Description: Attempts to obtain the annotation that is applied to the types corresponding to TypeInfo and has a given qualified name.
Returns:
- Option<T>: If a match is found, the annotation is returned. Otherwise,
Noneis returned.
func getInstanceFunction(String, Array<TypeInfo>)
public func getInstanceFunction(name: String, parameterTypes: Array<TypeInfo>): InstanceFunctionInfo
Description: Attempts to obtain information about a matched instance function in a type based on a given function name and a type information list corresponding to the formal parameter type list of the function.
Parameters:
- name: String: function name
- parameterTypes: Array<TypeInfo>: type information list corresponding to the formal parameter type list of the function
Returns:
- InstanceFunctionInfo: If a match is found, information about the instance function is returned.
Throws:
- InfoNotFoundException: If no matched public instance function is found, this exception is thrown.
func getInstanceProperty(String)
public func getInstanceProperty(name: String): InstancePropertyInfo
Description: Attempts to obtain information about the instance property that matches a given property name in the type.
Parameters:
- name: String: property name
Returns:
- InstancePropertyInfo: If a match is found, information about the instance property is returned.
Throws:
- InfoNotFoundException: If no matched public instance property is found, this exception is thrown.
func getStaticFunction(String, Array<TypeInfo>)
public func getStaticFunction(name: String, parameterTypes: Array<TypeInfo>): StaticFunctionInfo
Description: Attempts to obtain information about a matched static member function in the type based on a given function name and a type information list corresponding to the formal parameter type list of the function.
Parameters:
- name: String: function name
- parameterTypes: Array<TypeInfo>: type information list corresponding to the formal parameter type list of the function
Returns:
- StaticFunctionInfo: If a match is found, information about the static member function is returned.
Throws:
- InfoNotFoundException: If no matched public static member function is found, this exception is thrown.
func getStaticProperty(String)
public func getStaticProperty(name: String): StaticPropertyInfo
Description: Attempts to obtain information about the static member property that matches a given property name in the type.
Parameters:
- name: String: property name
Returns:
- StaticPropertyInfo: If a match is found, information about the static member property is returned.
Throws:
- InfoNotFoundException: If no matched public static member property is found, this exception is thrown.
func hashCode()
public func hashCode(): Int64
Description: Obtains the hash value of the type information.
Note:
The internal implementation is the hash value of the qualified name string of the type information.
Returns:
- Int64: hash value of the type information
func isSubtypeOf(TypeInfo)
public func isSubtypeOf(supertype: TypeInfo): Bool
Description: Checks whether the type of the current TypeInfo instance is a subtype of the type represented by the TypeInfo instance specified in the parameter.
Note:
Currently, none of
structtypes can obtain theinterfacetype implemented by them. Therefore,falseis always returned when determining whether astructis a subtype of aninterface.
Parameters:
- supertype: TypeInfo: type information of the target type
Returns:
- Bool: If the type corresponding to TypeInfo is a subtype of the type corresponding to
supertype,trueis returned. Otherwise,falseis returned.
func toString()
public func toString(): String
Description: Obtains the type information in string format.
Note:
The internal implementation is the qualified name string of the type information.
Returns:
- String: type information in string format
operator func !=(TypeInfo)
public operator func !=(that: TypeInfo): Bool
Description: Checks whether the type information is not equal to given type information.
Parameters:
- that: TypeInfo: other type information that is compared for equality
Returns:
- Bool: If the qualified name of the type information is not equal to
that,trueis returned. Otherwise,falseis returned.
operator func ==(TypeInfo)
public operator func ==(that: TypeInfo): Bool
Description: Checks whether the type information is equal to given type information.
Parameters:
- that: TypeInfo: other type information that is compared for equality
Returns:
- Bool: If the qualified name of the type information is equal to
that,trueis returned. Otherwise,falseis returned.
Enumeration
enum ModifierInfo
public enum ModifierInfo <: Equatable<ModifierInfo> & Hashable & ToString {
| Open
| Override
| Redef
| Abstract
| Sealed
| Mut
| Static
}
Modifier information
Note:
Since the type information obtained by the developer through the reflection functionality comes from public types, these types inherently have
publicaccess control semantics. Therefore, the modifier information does not include any modifiers related to access control.
Parent Type:
Abstract
Abstract
Description: Specifies the abstract modifier.
Mut
Mut
Description: Specifies the mut modifier.
Open
Open
Description: Specifies the open modifier.
Override
Override
Description: Specifies the override modifier.
Redef
Redef
Description: Specifies the redef modifier.
Sealed
Sealed
Description: Specifies the sealed modifier.
Static
Static
Description: Specifies the static modifier.
func hashCode()
public func hashCode(): Int64
Description: Obtains the hash value of the modifier information.
Returns:
- Int64: hash value of the modifier information
Note:
The internal implementation is the hash value of the modifier keyword string.
func toString()
public func toString(): String
Description: Obtains the modifier information in the string format.
Returns:
- String: modifier information in the string format
Note:
The modifier information in the string format is the identifier of the modifier keyword.
operator func ==(ModifierInfo)
public operator func ==(that: ModifierInfo): Bool
Description: Checks whether the modifier information is equal to the given modifier information.
Parameters:
- that: ModifierInfo: information about another modifier under equality comparison
Returns:
- Bool: If the modifier information is equal to
that,trueis returned. Otherwise,falseis returned.
Note:
The semantics of equality of modifier information is equivalent to the semantics of equality of
enumtype instances.
operator func !=(ModifierInfo)
public operator func !=(that: ModifierInfo): Bool
Description: Checks whether the modifier information is not equal to the given modifier information.
Note:
The semantics of equality of modifier information is equivalent to the semantics of equality of
enumtype instances.
Parameters:
- that: ModifierInfo: information about another modifier whose equality is compared
Returns:
- Bool: If the modifier information is not equal to
that,trueis returned. Otherwise,falseis returned.
Exception
class IllegalSetException
public class IllegalSetException <: ReflectException {
public init()
public init(message: String)
}
Description: Specifies an exception thrown upon an attempt to modify an immutable type.
Parent Type:
init()
public init()
Description: Creates an IllegalSetException instance.
init(String)
public init(message: String)
Description: Creates an IllegalSetException instance based on the exception information.
Parameters:
- message: String: exception information
class IllegalTypeException
public class IllegalTypeException <: ReflectException {
public init()
public init(message: String)
}
Description: Indicates a type mismatch exception.
Parent Type:
init()
public init()
Description: Creates an IllegalTypeException instance.
init(String)
public init(message: String)
Description: Creates an IllegalTypeException instance based on the exception information.
Parameters:
- message: String: exception information
class InfoNotFoundException
public class InfoNotFoundException <: ReflectException {
public init()
public init(message: String)
}
Description: Indicates that the corresponding information cannot be found.
Parent Type:
init()
public init()
Description: Creates an InfoNotFoundException instance.
init(String)
public init(message: String)
Description: Creates an InfoNotFoundException instance based on the exception information.
Parameters:
- message: String: exception information
class InvocationTargetException
public class InvocationTargetException <: ReflectException {
public init()
public init(message: String)
}
Description: Indicates an exception that wraps a function invocation exception.
Parent Type:
init()
public init()
Description: Creates an InvocationTargetException instance.
init(String)
public init(message: String)
Description: Creates an InvocationTargetException instance based on the exception information.
Parameters:
- message: String: exception information
class MisMatchException
public class MisMatchException <: ReflectException {
public init()
public init(message: String)
}
Description: Indicates that an exception thrown when the corresponding function is called incorrectly.
Parent Type:
init()
public init()
Description: Creates a MisMatchException instance.
init(String)
public init(message: String)
Description: Creates a MisMatchException instance based on the exception information.
Parameters:
- message: String: exception information
class ReflectException
public open class ReflectException <: Exception {
public init()
public init(message: String)
}
Description: Specifies the base exception class for the Reflect package.
Parent Type:
init()
public init()
Description: Creates a ReflectException instance.
init(String)
public init(message: String)
Description: Creates a ReflectException instance based on the exception information.
Parameters:
- message: String: exception information
Usage of Annotation
Obtains the values of annotations on an instance through reflection.
The code is as follows:
import std.reflect.*
main() {
let ti = TypeInfo.of(Test())
let annotation = ti.findAnnotation<A>()
if (let Some(a) <- annotation) {
println(a.name)
}
}
@A["Annotation"]
public class Test {}
@Annotation
public class A {
const A(let name: String) {}
}
The running result is as follows:
Annotation
Usage of Dynamic Loading
Create two directories named myModuleDirectory and myExecutableDirectory under the root directory myProject of the project. Use cjpm to build a Cangjie dynamic library module and an executable file in the two directories. The executable file loads the dynamic library module and then uses reflection to manipulate the global variables in the dynamic library module.
$ mkdir -p myProject && cd myProject
$ mkdir -p myPackage && cd myPackage
# Running this command in the myPackage directory initializes the directory structure of the Cangjie dynamic library module, allowing dynamic compilation of Cangjie functionality within myPackage.
$ cjpm init --type=dynamic --name myPackage
cjpm init success
$ cat << EOF > src/myPackage.cj
package myPackage
public var myPublicGlobalVariable0: Int64 = 2333
public let myPublicGlobalVariable1 = MyPublicType("Initializing myPublicGlobalVariable1 in myPackage")
public class MyPublicType {
public MyPublicType(message: String) {
println(message)
}
public static func myPublicStaticMemeberFunction() {
println("myPackage.MyPublicType.myPublicStaticMemeberFunction is called.")
}
static let myStaticVariable = MyPublicType("Initializing myStaticVariable in myPackage.MyPublicType")
}
EOF
# Use cjpm to build the Cangjie dynamic library module.
$ cjpm build
cjpm build success
$ cd .. && mkdir -p myExecutableDirectory && cd myExecutableDirectory
$ cjpm init
$ cat << EOF > src/main.cj
package myExecutableDirectory
import std.reflect.*
main(): Unit {
// Load the Cangjie dynamic library.
let myModule = ModuleInfo.load("../myPackage/target/release/myPackage/libmyPackage.so")
println(myModule.name)
let myPackage = myModule.getPackageInfo("myPackage")
println(myPackage.name)
TypeInfo.get("myPackage.MyPublicType") |> println
let myPublicGlobalVariable0 = myPackage.getVariable("myPublicGlobalVariable0")
(myPublicGlobalVariable0.getValue() as Int64).getOrThrow() |> println
myPublicGlobalVariable0.setValue(666)
(myPublicGlobalVariable0.getValue() as Int64).getOrThrow() |> println
}
EOF
# Build and run the executable program.
$ cjpm run
Initializing myPublicGlobalVariable1 in myPackage
Initializing myStaticVariable in myPackage.MyPublicType
myPackage
myPackage
myPackage.MyPublicType
2333
666
cjpm run finished
$ tree ..
..
├── myExecutableDirectory
│ ├── cjpm.lock
│ ├── cjpm.toml
│ ├── src
│ │ └── main.cj
│ └── target
│ └── release
│ ├── bin
│ │ ├── main
│ │ ├── myExecutableDirectory.bchir2
│ │ └── myExecutableDirectory.cjo
│ ├── myExecutableDirectory
│ │ └── incremental-cache.json
│ └── myExecutableDirectory-cache.json
└── myPackage
├── cjpm.lock
├── cjpm.toml
├── src
│ └── myPackage.cj
└── target
└── release
├── bin
├── myPackage
│ ├── incremental-cache.json
│ ├── libmyPackage.so
│ ├── myPackage.bchir2
│ └── myPackage.cjo
└── myPackage-cache.json
12 directories, 16 files
Note:
The ModuleInfo.load function determines the package name based on the file name. Therefore, the file name cannot be changed. Otherwise, an exception is thrown indicating that the Cangjie dynamic library module file cannot be found.
Usage of Member Information
import std.reflect.*
public class Rectangular {
public var length = 4
public var width = 5
public func area(): Int64 {
return length * width
}
}
main(): Unit {
let a = Rectangular()
let ty = TypeInfo.of(a)
const zl = 3
let members = ty.instanceVariables.toArray()
println((members[0].getValue(a) as Int64).getOrThrow())
println((members[1].getValue(a) as Int64).getOrThrow())
members[0].setValue(a, zl)
members[1].setValue(a, zl)
println((members[0].getValue(a) as Int64).getOrThrow())
println((members[1].getValue(a) as Int64).getOrThrow())
println(a.area())
let funcs = ty.instanceFunctions.toArray()
if (funcs[0].returnType.name == "Int64"){
println("The area of the square is ${zl**2}")
}
return
}
The running result is as follows:
4
5
3
3
9
The area of the square is 9
Usage of TypeInfo
package Demo
import std.reflect.*
public class Foo {
public let item = 0
public func f() {}
}
main() {
let a = Foo()
let ty: TypeInfo = TypeInfo.of(a)
println(ty.name)
println(ty.qualifiedName)
println(ty.instanceFunctions.size)
}
The running result is as follows:
Foo
Demo.Foo
1
std.regex Package
Function Description
The regex package provides the capability of analyzing and processing text (ASCII character strings only) through regular expressions, and supports functions such as search, segmentation, replacement, and verification.
regex Rule Set
Current regular expressions of Cangjie support the following rules only. Use of unsupported rules will cause unexpected output results.
| Character | Description |
|---|---|
\ | Marks the next character as a special character (File Format Escape, listed in this table), a literal character (Identity Escape, a total of 12 including ^$()*+?.[{\|), or a backreference (backreferences). For example, "n" matches the character "n." \n matches a line feed. The sequence \ matches \, and ( matches (. |
^ | Matches the start position of an input string. If multiLine() in RegexOption is selected, ^ also matches the position following \n or \r. |
$ | Matches the end position of an input string. |
* | Matches the preceding subexpression zero times or multiple times. For example, zo* can match z, zo, and zoo. * is equivalent to {0,}. |
+ | Matches the preceding subexpression once or multiple times. For example, zo+ can match zo and zoo, but cannot match z. + is equivalent to {1,}. |
? | Matches the preceding subexpression zero times or once. For example, do(es)? can match do and does in does. ? is equivalent to {0,1}. |
{n} | n is a non-negative integer, and matches exactly n times. For example, o{2} cannot match o in Bob, but can match two letters o in food. |
{n,} | n is a non-negative integer, and matches at least n times. For example, o{2,} cannot match o in Bob, but can match all letters o in foooood. o{1,} is equivalent to o+, and o{0,} is equivalent to o*. |
{n,m} | m and n are non-negative integers, where n ≤ m. Matches at least n times and at most m times. For example, o{1,3} matches the first three letters o in fooooood. o{0,1} is equivalent to o?. Note that there is no space between the comma and the two numbers. |
? | Non-greedy quantifiers: When this character follows any other repeated modifier (*,+,?, {n}, {n,}, {n,m}), the matching pattern is non-greedy. In the non-greedy pattern, strings are matched as few as possible, while in the default greedy pattern, strings are matched as many as possible. For example, regarding the string oooo, o+? matches a single letter o, while o+ matches all letters o. |
. | Matches any single character except \n. Patterns like (.\|\n) need to be used to match any characters including \n. |
(pattern) | Matches a pattern and obtains the substring for this match. The substring is used for backreference. The match can be obtained from the generated set of matches. \( or \) needs to be used to match the parenthesis string. A quantity suffix is allowed. |
x\|y | Not enclosed in parentheses, it specifies the entire regular expression. For example, z|food matches z or food. (?:z|f)ood matches zood or food. |
[xyz] | Specifies a character set (character class), and matches any character contained. For example, [abc] can match a in plain. Among special characters, only the backslash (\) retains its special meaning and is used as an escape character. Other special characters, such as an asterisk, a plus sign, and brackets, are all used as normal characters. A caret (^) denotes a negative character set if appearing at the beginning of a string, and it is used as a normal character if in the middle of a string. A hyphen (-) denotes a character range if appearing in the middle of a string, and it is used only as a normal character if at the beginning (or end) of a string. A right square bracket can be used as an escape character or as the first character. |
[^xyz] | Specifies a negated character set (negated character classes), and matches any character not listed. For example, [^abc] can match plin in plain. |
[a-z] | Specifies a character range, and matches any character within the specified range. For example, [a-z] can match any lowercase letter from a to z. |
[^a-z] | Specifies a range of negated characters, and matches any character outside the specified range. For example, [^a-z] can match any character not in the range from a to z. |
\b | Matches a word boundary, that is, the position between a word and a space. For example, er\b can match er in never, but cannot match er in verb. |
\B | Matches a non-word boundary. er\B can match er in verb, but cannot match er in never. |
\d | Matches a digit character. It is equivalent to [0-9]. |
\D | Matches a non-digit character. It is equivalent to [^0-9]. |
\f | Matches a form feed. It is equivalent to \x0c. |
\n | Matches a line feed. It is equivalent to \x0a. |
\r | Matches a carriage return character. It is equivalent to \x0d. |
\s | Matches any whitespace character, including a space, a tab character, and a form feed. It is equivalent to [\f\n\r\t\v]. |
\S | Matches any non-whitespace character. It is equivalent to [^\f\n\r\t\v]. |
\t | Matches a tab character. It is equivalent to \x09. |
\v | Matches \n\v\f\r\x85. |
\w | Matches any word character including the underscore. It is equivalent to [A-Za-z0-9_]. |
\W | Matches any non-word character. It is equivalent to [^A-Za-z0-9_]. |
\xnm | Specifies a hexadecimal escape character sequence, and matches characters represented by two hexadecimal digits nm. For example, \x41 matches A. ASCII codes can be used in regular expressions. |
\num | Backreferences a substring. The substring matches the (num)th capture group subexpression enclosed in brackets in the regular expression. num is a decimal positive integer starting from 1, and the upper limit of capture groups in Regex is 63. For example, (.)\1 matches two consecutive identical characters. |
(?:pattern) | Matches a pattern but does not obtain the matched substring (shy groups). In other words, it is a non-capturing match and the matched substring is not stored for backreference. This is helpful when the OR character (\|) is used to combine parts of a pattern. |
(?=pattern) | Specifies a positive lookahead assertion. Strings are searched and matched at the beginning of any string matching the pattern. This is a non-capturing match. In other words, the match does not need to be captured for future use. For example, Windows(?=95\|98\|NT\|2000) can match Windows in Windows2000, but cannot match Windows in Windows3.1. An assertion does not consume characters. Specifically, after a match occurs, the next search starts immediately following the last match, instead of starting from the asserted character. |
(?!pattern) | Specifies a negative lookahead assertion. Strings are searched and matched at the beginning of any string that does not match the pattern. This is a non-capturing match. In other words, the match does not need to be captured for future use. For example, Windows(?!95\|98\|NT\|2000) can match Windows in Windows3.1, but cannot match Windows in Windows2000. An assertion does not consume characters. Specifically, after a match occurs, the next search starts immediately following the last match, instead of starting from the asserted character. |
(?<=pattern) | Specifies a positive lookbehind assertion. It is similar to the positive lookahead assertion but in an opposite direction. For example, (?<=95\|98\|NT\|2000)Windows can match Windows in 2000Windows, but cannot match Windows in 3.1Windows. |
(?<!pattern) | Specifies a negative lookbehind assertion. It is similar to the negative lookahead assertion but in an opposite direction. For example, (?<!95\|98\|NT\|2000)Windows can match Windows in 3.1Windows, but cannot match Windows in 2000Windows. |
(?i) | Specifies, using a rule, that some rules are case-insensitive. Currently, Regex supports global case-insensitivity only. If this option is specified, global case-insensitivity applies. |
(?-i) | Specifies, using a rule, that some rules are case-sensitive. Currently, Regex is case-sensitive by default. This option is treated as a compilation compatibility issue rather than a sensitivity issue. |
+ | Specifies a separate plus sign rather than an escaped \+. |
* | Specifies a separate asterisk rather than an escaped \*. |
- | Specifies a separate minus sign, rather than an escaped \-. |
] | Specifies a separate right square bracket rather than an escaped \]. |
} | Specifies a separate right curly bracket rather than an escaped \}. |
[[:alpha:]] | Specifies any uppercase or lowercase letter. |
[[:^alpha:]] | Specifies any character except uppercase and lowercase letters. |
[[:lower:]] | Specifies any lowercase letter. |
[[:^lower:]] | Specifies any character except lowercase letters. |
[[:upper:]] | Specifies any uppercase letter. |
[[:^upper:]] | Specifies any character except uppercase letters. |
[[:digit:]] | Specifies any single digit from 0 to 9. |
[[:^digit:]] | Specifies any character except a single digit from 0 to 9. |
[[:xdigit:]] | Specifies hexadecimal letters and digits. |
[[:^xdigit:]] | Specifies any character except hexadecimal letters and digits. |
[[:alnum:]] | Specifies any digit or letter. |
[[:^alnum:]] | Specifies any character except digits or letters. |
[[:space:]] | Specifies any whitespace character, including a "space" and a "tab key". |
[[:^space:]] | Specifies any character except whitespace characters. |
[[:punct:]] | Specifies any punctuation mark. |
[[:^punct:]] | Specifies any character except punctuation marks. |
Cangjie also has other special rules:
-
Unquantifiable characters before
?,+, and*are ignored. Exception:*is treated as a common character for strings beginning with(*,|*, or*. -
When
*?is matching a string formed by all characters before*?, the character cannot be matched. -
The maximum number of capture groups in a regular expression is 63, and the maximum length of a compiled rule is 65535.
-
The ((pattern1){m1,n1}pattern2){m2,n2} scenario is not supported currently. That is:
- Group definition 1 is modified by {m1,n1}
- Group definition 1 is wrapped by group definition 2
- Group definition 2 is modified by {m2,n2}
API List
Class
| Name | Description |
|---|---|
| Matcher | Specifies a regular expression matcher, used to scan an input sequence for matching. |
| MatchData | Stores regular expression matching results, and provides functions for querying the regular expression matching results. |
| Regex | Specifies the compilation type and input sequence. |
| RegexOption | Specifies the regular expression matching pattern. |
Struct
| Struct Name | Description |
|---|---|
| Position | Stores position information, indicating a range with a closed starting point and an open endpoint. |
Exception Class
| Name | Description |
|---|---|
| RegexException | Provides regex-related exception processing. |
Class
class MatchData
public class MatchData {}
Description: Stores regular expression matching results and provides functions for querying the regular expression matching results.
func groupNumber()
public func groupNumber(): Int64
Description: Obtains the number of capture groups.
Returns:
- Int64: number of capture groups
func matchPosition()
public func matchPosition(): Position
Description: Obtains the indexes of the start position and end position of the substring matched last time in the input string.
Returns:
- Position: position of the match result
func matchPosition(Int64)
public func matchPosition(group: Int64): Position
Description: Obtains, based on the given index, the position of the substring matched last time by the capture group in the input string.
Parameters:
- group: Int64: specified group
Returns:
- Position: position of the capture group
Throws:
- IndexOutOfBoundsException: If group is less than 0 or greater than groupNumber, this exception is thrown.
- RegexException: If group is not 0 and there is no capture group, this exception is thrown.
func matchStr()
public func matchStr(): String
Description: Obtains the substring matched last time. The result is the same as that of calling matchStr(0).
Returns:
- String: matched substring
Throws:
- IndexOutOfBoundsException: If the length of the matched string array is less than 1, this exception is thrown.
func matchStr(Int64)
public func matchStr(group: Int64): String
Description: Obtains, based on the given index, the substring matched last time by the capture group.
The index of a capture group starts from 1. If the index is 0, the match result of the entire regular expression is obtained.
Parameters:
- group: Int64: specified group
Returns:
- String: matched substring
Throws:
- IndexOutOfBoundsException: If group is less than 0 or greater than groupNumber, this exception is thrown.
- RegexException: If group is not 0 and there is no capture group, this exception is thrown.
class Matcher
public class Matcher {
public init(re: Regex, input: String)
}
Description: Specifies a regular expression matcher, used to scan an input sequence for matching.
Notes:
- The maximum length of the string to be matched cannot exceed 231-1.
- The maximum length of the string to be replaced using replaceAll cannot exceed 230-2.
init(Regex, String)
public init(re: Regex, input: String)
Description: Creates a Matcher instance using the input regular expression and input sequence.
Parameters:
Throws:
- RegexException: This exception is thrown upon initialization failure.
- IllegalArgumentException: If input contains a null character or its length is greater than 231-1, this exception is thrown.
func allCount()
public func allCount(): Int64
Description: Obtains the total number of match results of a regular expression.
By default, it is the result of a thorough match. After setRegion is used, only the specified range is searched.
Returns:
- Int64: total number of match results
func find()
public func find(): Option<MatchData>
Description: Searches for the first matched subsequence from the current string offset position.
When the find function is called once, the current offset position is the position of the first character following the last matched subsequence. When the find function is called for another time, matching starts from the current position.
Returns:
- Option<MatchData>: If there is a match result, Option<MatchData> is returned. If there is no match result, Option<MatchData>.None is returned.
Throws:
- RegexException: If resetting the matcher fails, this exception is thrown.
func find(Int64)
public func find(index: Int64): Option<MatchData>
Description: Resets the index position of the matcher, matches the input sequence from the position corresponding to the index, and returns the matched subsequence.
Returns:
- Option<MatchData>: If there is a match result, Option<MatchData> is returned. If there is no match result, Option<MatchData>.None is returned.
Throws:
- IndexOutOfBoundsException: If index is less than 0, or greater than or equal to the size of the input sequence, this exception is thrown.
- RegexException: If resetting the matcher fails, this exception is thrown.
func findAll()
public func findAll(): Option<Array<MatchData>>
Description: Matches the entire input sequence and finds all matched subsequences.
Returns:
- Option < Array<MatchData>>: If there is a match result, Option<Array<MatchData>> is returned. If there is no match result, Option<Array<MatchData>>.None is returned.
Throws:
- RegexException: If memory allocation for resetting the matcher fails or applying for memory fails, this exception is thrown.
func fullMatch()
public func fullMatch(): Option<MatchData>
Description: Matches the entire input sequence.
Returns:
- Option<MatchData>: If all matches are successful, Option<MatchData> is returned; otherwise, Option<MatchData>.None is returned.
func getString()
public func getString(): String
Description: Obtains a matched sequence.
Returns:
- String: matched sequence
func matchStart()
public func matchStart(): Option<MatchData>
Description: Matches the header of the input sequence.
Returns:
- Option<MatchData>: If the match is successful, Option<MatchData> is returned; otherwise, Option<MatchData>.None is returned.
Throws:
- RegexException: If resetting the matcher fails, this exception is thrown.
func region()
public func region(): Position
Description: Returns region settings of the matcher.
Returns:
- Position: region settings of the matcher
func replace(String)
public func replace(replacement: String): String
Description: From the current string offset position, replaces the first matched subsequence with the target string, and sets the current index position to the next position of the matched subsequence.
Parameters:
- replacement: String: string to be replaced
Returns:
- String: new string
Throws:
- RegexException: If resetting the matcher fails, this exception is thrown.
- IllegalArgumentException: If the length of replacement is greater than 230-2 or replacement contains a null character, this exception is thrown.
func replace(String, Int64)
public func replace(replacement: String, index: Int64): String
Description: Performs regular expression matching from the index position of the input sequence and replaces the first matched subsequence with the target string.
Parameters:
Returns:
- String: new string
Throws:
- IndexOutOfBoundsException: If index is less than 0, or greater than or equal to the size of the input sequence, this exception is thrown.
- RegexException: If resetting the matcher fails, this exception is thrown.
- IllegalArgumentException: If the length of replacement is greater than 230-2 or replacement contains a null character, this exception is thrown.
func replaceAll(String)
public func replaceAll(replacement: String): String
Description: Replaces all subsequences in the input sequence, which match the regular expression, with the target string.
Parameters:
- replacement: String: string to be replaced
Returns:
- String: new string
Throws:
- RegexException: This exception is thrown if resetting the matcher fails, applying for memory at the C side fails, or GC occurs during string replacement.
- IllegalArgumentException: If the length of replacement is greater than 230-2 or replacement contains a null character, this exception is thrown.
func replaceAll(String, Int64)
public func replaceAll(replacement: String, limit: Int64): String
Description: Replaces the first limit subsequences in the input sequence, which match the regular expression, with the specified string.
Parameters:
- limit: Int64: number of replacements If the value of limit is 0, the original sequence is returned. If the value of limit is a negative number, the sequence is replaced as many times as possible.
- replacement: String: string to be replaced
Returns:
- String: new string
Throws:
- RegexException: This exception is thrown if resetting the matcher fails, applying for memory at the C side fails, or GC occurs during string replacement.
- IllegalArgumentException: If the length of replacement is greater than 230-2 or replacement contains a null character, this exception is thrown.
func resetRegion()
public func resetRegion(): Matcher
Description: Resets the start and end positions of the matcher.
Returns:
- Matcher: matcher
Throws:
- RegexException: If resetting the matcher fails, this exception is thrown.
func resetString(String)
public func resetString(input: String): Matcher
Description: Resets the matching sequence and the matcher.
Parameters:
- input: String: new matching sequence
Returns:
- Matcher: matcher
Throws:
- RegexException: If resetting the matcher fails, this exception is thrown.
- IllegalArgumentException: If the length of input is greater than 231-1 or input contains a null character, this exception is thrown.
func setRegion(Int64, Int64)
public func setRegion(beginIndex: Int64, endIndex: Int64): Matcher
Description: Sets the position of a searchable region of the matcher. The specific position is determined by begin and end.
Parameters:
Returns:
- Matcher: matcher
Throws:
- IndexOutOfBoundsException: If beginIndex is less than 0 or greater than the size of the input sequence, this exception is thrown. If endIndex is less than 0 or greater than the size of the input sequence, this exception is thrown. If beginIndex is greater than endIndex, this exception is thrown.
func split()
public func split(): Array<String>
Description: Splits a given input sequence into subsequences as many as possible based on the regular expression.
Returns:
func split(Int64)
public func split(limit: Int64): Array<String>
Description: Splits a given input sequence into subsequences as many as possible (limit subsequences at most) based on the regular expression.
Parameters:
- limit: Int64: maximum number of substrings after splitting
Returns:
- Array<String>: If limit is greater than 0, a maximum of limit substrings are returned. If limit is less than or equal to 0, the maximum number of substrings that can be obtained after splitting is returned.
Throws:
- RegexException: If resetting the matcher fails, this exception is thrown.
class Regex
public class Regex {
public init(s: String)
public init(s: String, option: RegexOption)
}
Description: Specifies the compilation type and input sequence.
For details about regular expression matching rules, see the regex rule set.
init(String)
public init(s: String)
Description: Creates a Regex instance, with the matching pattern being normal pattern.
Parameters:
- s: String: regular expression
Throws:
- RegexException: This exception is thrown upon initialization failure.
- IllegalArgumentException: If s contains a null character, this exception is thrown.
init(String, RegexOption)
public init(s: String, option: RegexOption)
Description: Creates a Regex instance using a specified pattern.
Parameters:
- s: String: regular expression
- option: RegexOption: regular expression matching pattern
Throws:
- RegexException: This exception is thrown upon initialization failure.
- IllegalArgumentException: If s contains a null character, this exception is thrown.
func matcher(String)
public func matcher(input: String): Matcher
Description: Creates a matcher.
Parameters:
- input: String: string to be matched, with the maximum length of 231-1
Returns:
- Matcher: created matcher
Throws:
- RegexException: This exception is thrown upon initialization failure.
- IllegalArgumentException: If input contains a null character, this exception is thrown.
func matches(String)
public func matches(input: String): Option<MatchData>
Description: Creates a matcher and perform exact match between input and the regular expression.
Parameters:
- input: String: string to be matched, with the maximum length of 231-1
Returns:
- Option<MatchData>: If the match is successful, Option<MatchData> is returned; otherwise, Option<MatchData>.None is returned.
Throws:
- RegexException: This exception is thrown upon initialization failure.
- IllegalArgumentException: If input contains a null character, this exception is thrown.
func string()
public func string(): String
Description: Obtains the input sequence of a regular expression.
Returns:
- String: input sequence
class RegexOption
public class RegexOption <: ToString {
public init()
}
Description: Specifies the regular expression matching pattern.
The default regular expression matching algorithm is NFA, and the maximum number of matches is 1000000.
Parent Type:
init()
public init()
Description: Creates a RegexOption instance, with the matching pattern being normal pattern (NORMAL).
func ignoreCase()
public func ignoreCase(): RegexOption
Description: Modify RegexOption by changing the matching pattern to case-insensitive (IGNORECASE).
Returns:
- RegexOption: new RegexOption
func multiLine()
public func multiLine(): RegexOption
Description: Modify RegexOption by changing the matching pattern to the multi-line text pattern (MULTILINE).
Returns:
- RegexOption: new RegexOption
func toString()
public func toString(): String
Description: Obtains the regular expression matching pattern represented by RegexOption.
Returns:
- String: regular expression matching pattern
Struct
struct Position
public struct Position
Description: Stores position information, indicating a range with a closed starting point and an open endpoint.
prop end
public prop end: Int64
Description: Specifies the endpoint of a range.
Type: Int64
prop start
public prop start: Int64
Description: Specifies the starting point of a range.
Type: Int64
Exception
class RegexException
public class RegexException <: Exception {
public init()
public init(message: String)
}
Description: Processes exceptions of a regular expression.
Parent Type:
init()
public init()
Description: Creates a RegexException instance.
init(String)
public init(message: String)
Description: Creates a RegexException instance based on the exception information.
Parameters:
- message: String: exception prompt
regex Example
RegexOption Obtaining the Current Regular Expression Matching Pattern
import std.regex.*
main(): Unit {
var a = RegexOption()
println(a.toString())
a = RegexOption().ignoreCase()
println(a.toString())
a = RegexOption().multiLine()
println(a.toString())
a = RegexOption().multiLine().ignoreCase()
println(a.toString())
}
Running result:
NORMAL,NFA
IGNORECASE,NFA
MULTILINE,NFA
MULTILINE,IGNORECASE,NFA
Regex Matching Case-sensitivity
import std.regex.*
main(): Unit {
let r1 = Regex("ab")
let r2 = Regex("ab", RegexOption().ignoreCase())
match (r1.matches("aB")) {
case Some(r) => println(r.matchStr())
case None => println("None")
}
match (r2.matches("aB")) {
case Some(r) => println(r.matchStr())
case None => println("None")
}
}
Running result:
None
aB
MatchOption Multi-line Matching
import std.regex.*
main(): Unit {
let rule = ##"^(\w+)\s(\d+)*$"##
let pattern: String = """
Joe 164
Sam 208
Allison 211
Gwen 171
"""
let r1 = Regex(rule, RegexOption().multiLine())
var arr = r1.matcher(pattern).findAll() ?? Array<MatchData>()
for (md in arr) {
println(md.matchStr())
}
}
Running result:
Joe 164
Sam 208
Allison 211
Gwen 171
Use of Matcher and MatchData
import std.regex.*
main(): Unit {
let r = Regex(#"a\wa"#).matcher("1aba12ada555")
for (_ in 0..2) {
let matchData = r.find()
match (matchData) {
case Some(md) =>
println(md.matchStr())
let pos = md.matchPosition()
println("[${pos.start}, ${pos.end})")
case None => println("None")
}
}
}
Running result:
aba
[1, 4)
ada
[6, 9)
resetString/fullMatch/matchStart Function in Matcher
import std.regex.*
main(): Unit {
let r = Regex("\\d+")
let m = r.matcher("13588123456")
let matchData1 = m.fullMatch()
m.resetString("13588abc")
let matchData2 = m.matchStart()
m.resetString("abc13588123abc")
let matchData3 = m.matchStart()
match (matchData1) {
case Some(md) => println(md.matchStr())
case None => println("None")
}
match (matchData2) {
case Some(md) => println(md.matchStr())
case None => println("None")
}
match (matchData3) {
case Some(md) => println(md.matchStr())
case None => println("None")
}
}
Running result:
13588123456
13588
None
replace/replaceAll Function in Matcher
import std.regex.*
main(): Unit {
let r = Regex("\\d").matcher("a1b1c2d3f4")
println(r.replace("X")) //replace a digit once with X
println(r.replace("X", 2)) //replace once from index 4
println(r.replaceAll("X")) //replace all digit with X
println(r.replaceAll("X", 2)) //replace all at most 2 times
println(r.replaceAll("X", -1)) //replace all digit with X
}
Running result:
aXb1c2d3f4
a1bXc2d3f4
aXbXcXdXfX
aXbXc2d3f4
aXbXcXdXfX
Matcher Obtaining the Total Number of Matches
import std.regex.*
main(): Unit {
var matcher = Regex("a+b").matcher("1ab2aab3aaab4aaaab")
println(matcher.allCount())
}
Running result:
4
groupNumber Function in MatchData
import std.regex.*
main(): Unit {
var r = Regex("(a+c)(a?b)()(()?c+((e|s([a-h]*))))")
var m = r.matcher("aacbcsdedd")
var matchData = m.find()
match (matchData) {
case Some(s) =>
println("groupNum : ${s.groupNumber()}")
if (s.groupNumber() > 0) {
for (i in 1..=s.groupNumber()) {
println("group[${i}] : ${s.matchStr(i)}")
var pos = s.matchPosition(i)
println("position : [${pos.start}, ${pos.end})")
}
}
case None => ()
}
}
Running result:
groupNum : 8
group[1] : aac
position : [0, 3)
group[2] : b
position : [3, 4)
group[3] :
position : [4, 4)
group[4] : csdedd
position : [4, 10)
group[5] :
position : [10, 10)
group[6] : sdedd
position : [5, 10)
group[7] : sdedd
position : [5, 10)
group[8] : dedd
position : [6, 10)
std.runtime Package
Function Description
The runtime package is used to interact with the runtime environment of a program. It provides a series of functions and variables for controlling, managing, and monitoring the execution of the program.
Cangjie uses an automatic garbage collection system for memory management. The runtime package provides functions such as manually triggering garbage collection, setting garbage collection thresholds, and obtaining memory statistics for controlling and monitoring garbage collection.
API List
Function
| Name | Description |
|---|---|
| GC(Bool) | Performs garbage collection (GC). |
| SetGCThreshold(UInt64) | Modifies the memory threshold for triggering GC. When the size of a Cangjie heap exceeds the threshold measured in KB, GC is triggered. |
Struct
| Name | Description |
|---|---|
| MemoryInfo | Provides APIs for obtaining heap memory statistics. |
| ThreadInfo | Provides APIs for obtaining statistics of Cangjie threads. |
Function
func GC(Bool)
public func GC(heavy!: Bool = false): Unit
Description: Executes GC.
Parameters:
- heavy!: Bool: GC execution progress. If the value is true, the execution is slow and more memory is collected. The default value is false.
func SetGCThreshold(UInt64)
public func SetGCThreshold(value: UInt64): Unit
Description: Modifies the memory threshold for triggering GC. When the size of a Cangjie heap exceeds the threshold measured in KB, GC is triggered.
Parameters:
Example: Sets the GC memory threshold to 2 MB.
import std.runtime.*
main() {
SetGCThreshold(2048)
}
Struct
struct MemoryInfo
public struct MemoryInfo
Description: Provides APIs for obtaining heap memory statistics.
static prop allocatedHeapSize
public static prop allocatedHeapSize: Int64
Description: Obtains the occupied size of the Cangjie heap, measured in bytes.
Type: Int64
static prop heapPhysicalMemory
public static prop heapPhysicalMemory: Int64
Description: Obtains the size of the physical memory occupied by the Cangjie heap on the Linux platform, measured in bytes. Obtains the size of the physical memory occupied by the Cangjie process on the Windows and macOS platforms, measured in bytes.
Type: Int64
static prop maxHeapSize
public static prop maxHeapSize: Int64
Description: Obtains the maximum usable size of the Cangjie heap, measured in bytes.
Example:
import std.runtime.*
main() {
println(MemoryInfo.maxHeapSize)
}
Running result (subject to the actual environment):
268435456
Type: Int64
struct ThreadInfo
public struct ThreadInfo
Description: Provides APIs for obtaining statistics of Cangjie threads.
static prop blockingThreadCount
public static prop blockingThreadCount: Int64
Description: Obtains the number of blocked Cangjie threads.
Type: Int64
static prop nativeThreadCount
public static prop nativeThreadCount: Int64
Description: Obtains the number of physical threads.
Type: Int64
static prop threadCount
public static prop threadCount: Int64
Description: Obtains the number of current Cangjie threads.
Type: Int64
std.socket Package
Function Description
The socket package is used for network communication, and provides functions such as starting a Socket server, connecting to a Socket server, sending data, and receiving data.
Three Socket types of UDP, TCP, and UDS are supported. You can select a type as required.
User Datagram Protocol (UDP) is a connectionless transmission protocol. It does not provide reliability or flow control, but features low delay and low network overhead. UDP is mainly used in applications with high real time requirements, such as live video streaming and online gaming.
Transmission Control Protocol (TCP) is a connection-oriented and reliable transmission protocol. As one of commonly used transmission protocols on Internet, it provides functions such as reliable data transmission, flow control, congestion control, error detection, and flow management.
Unix Domain Socket (UDS) is a mechanism used for communication between processes on one computer. Unlike network sockets, the UDS does not require network protocol stacks or network devices. Therefore, it features faster communication, lower latency and higher throughput.
The class inheritance relationship of Socket provided by the library is as follows:
Hierarchy
Resource
├StreamingSocket
│ ├TcpSocket
│ └UnixSocket
│
├DatagramSocket
│ ├UdpSocket
│ └UnixDatagramSocket
│
└ServerSocket
├TcpServerSocket
└UnixServerSocket
API List
Constant & Variable
| Name | Description |
|---|---|
| IPV4_ALL_ROUTER | Specifies the IPv4 multicast address. |
| IPV4_ALL_SYSTEM | Specifies the IPv4 multicast address. |
| IPV4_BROADCAST | Specifies the IPv4 broadcast address. |
| IPV4_LOCAL_HOST | Specifies the local IPv4 address. |
| IPV4_ZERO | Specifies the universal IPv4 address. |
| IPV6_INTERFACE_LOCAL_ALL_NODES | Specifies the IPv6 multicast addresses of all nodes within the node-local scope. |
| IPV6_LINK_LOCAL_ALL_NODES | Specifies the IPv6 multicast addresses of all nodes within the link-local scope. |
| IPV6_LINK_LOCAL_ALL_ROUTERS | Specifies the IPv6 multicast addresses of all routers within the link-local scope. |
| IPV6_LOOPBACK | Specifies the loopback address (local address). |
| IPV6_ZERO | Specifies the universal IPv6 address. |
Interface
| Name | Description |
|---|---|
| DatagramSocket | Specifies a socket for receiving and reading packets. |
| ServerSocket | Provides APIs required by Socket of the server. |
| StreamingSocket | Specifies Socket running in duplex stream mode, which is readable and writable. |
Class
| Name | Description |
|---|---|
| IPMask | Specifies the IP mask, IP address, and routing address. |
| RawSocket | Provides basic functions of a socket. |
| SocketAddress | Specifies the socket address with a specific type, address, and port. |
| SocketAddressWithMask | Provides SocketAddress with a mask. |
| TcpServerSocket | Specifies the server that monitors TCP connections. |
| TcpSocket | Specifies the client that requests a TCP connection. |
| UdpSocket | Provides UDP packet communication. |
| UnixDatagramSocket | Provides the packet-based host communication capability. |
| UnixServerSocket | Provides a duplex stream-based server for host communication. |
| UnixSocket | Provides a duplex stream-based client for host communication. |
Enumeration
| Name | Description |
|---|---|
| SocketAddressKind | Specifies the Internet communication protocol type. |
| SocketNet | Specifies the transport layer protocol type. |
Struct
| Name | Description |
|---|---|
| OptionLevel | Provides common socket option levels. |
| OptionName | Provides common socket options. |
| ProtocolType | Provides common socket protocols, and allows the socket protocols to be constructed by specifying the value of Int32. |
| RawAddress | Creates and obtains the communication address of RawSocket. |
| SocketDomain | Provides common socket communication domains, and allows the socket communication domains to be constructed by specifying the value of Int32. |
| SocketKeepAliveConfig | Configures the TCP KeepAlive attribute. |
| SocketOptions | Stores some constants for setting socket options for subsequent calling. |
| SocketType | Provides common socket types and allows the socket types to be constructed by specifying the value of Int32. |
Exception Class
| Name | Description |
|---|---|
| SocketException | Provides socket-related exception processing. |
| SocketTimeoutException | Provides exception processing related to the character format. |
Constant & Variable
let IPV4_ALL_ROUTER
public let IPV4_ALL_ROUTER: Array<UInt8>
Description: Specifies the reserved IPv4 multicast address.
It is used to send routing information to all routers on all local networks.
let IPV4_ALL_SYSTEM
public let IPV4_ALL_SYSTEM: Array<UInt8>
Description: Specifies the IPv4 multicast address.
It is used to send multicast packets to all hosts on a local area network.
let IPV4_BROADCAST
public let IPV4_BROADCAST: Array<UInt8>
Description: Specifies the IPv4 broadcast address.
let IPV4_LOCAL_HOST
public let IPV4_LOCAL_HOST: Array<UInt8>
Description: Specifies the local IPv4 address.
let IPV4_ZERO
public let IPV4_ZERO: Array<UInt8>
Description: Specifies the universal IPv4 address.
let IPV6_INTERFACE_LOCAL_ALL_NODES
public let IPV6_INTERFACE_LOCAL_ALL_NODES: Array<UInt8>
Description: Specifies the IPv6 multicast addresses of all nodes within the node-local scope.
let IPV6_LINK_LOCAL_ALL_NODES
public let IPV6_LINK_LOCAL_ALL_NODES: Array<UInt8>
Description: Specifies the IPv6 multicast addresses of all nodes within the link-local scope.
let IPV6_LINK_LOCAL_ALL_ROUTERS
public let IPV6_LINK_LOCAL_ALL_ROUTERS: Array<UInt8>
Description: Specifies the IPv6 multicast addresses of all routers within the link-local scope.
let IPV6_LOOPBACK
public let IPV6_LOOPBACK: Array<UInt8>
Description: Specifies the IPv6 loopback address (local address).
let IPV6_ZERO
public let IPV6_ZERO: Array<UInt8>
Description: Specifies the universal IPv6 address.
Interface
interface DatagramSocket
public interface DatagramSocket <: Resource & ToString {
prop localAddress: SocketAddress
prop remoteAddress: ?SocketAddress
mut prop receiveTimeout: ?Duration
mut prop sendTimeout: ?Duration
func receiveFrom(buffer: Array<Byte>): (SocketAddress, Int64)
func sendTo(address: SocketAddress, payload: Array<Byte>): Unit
}
Description: DatagramSocket is a socket for receiving and reading packets.
A packet usually has a limited size and may be empty. Different packet socket types have different maximum packet sizes. For example, the UDP socket can process a maximum of 64 KB packet at a time. Packet transmission is not reliable, and the transmission sequence is not guaranteed. The size of a packet is determined by the transmit end. For example, if a 10-byte packet and a 15-byte packet are sent from one end, the peer end receives the packets of the same sizes: 10 bytes and 15 bytes.
Parent Type:
prop localAddress
prop localAddress: SocketAddress
Description: Reads the local address bound or to be bound with Socket.
Type: SocketAddress
Throws:
- SocketException: This exception is thrown when
Socketis closed or no local address is available (the local address is not configured and the socket is not connected).
prop receiveTimeout
mut prop receiveTimeout: ?Duration
Description: Sets and reads the timeout interval of receiveFrom. If there is no timeout interval, None is used.
If the interval is too small, the minimum clock cycle is used. If the interval is too large, the maximum timeout interval (263–1 ns) is used. The default value is None.
Type: ?Duration
Throws:
- IllegalArgumentException: If the timeout interval is less than 0, this exception is thrown.
prop remoteAddress
prop remoteAddress: ?SocketAddress
Description: Reads the remote address connected to Socket. If Socket is not connected, None is returned.
Type: ?SocketAddress
Throws:
- SocketException: When
Socketis closed, this exception is thrown.
prop sendTimeout
mut prop sendTimeout: ?Duration
Description: Sets and reads the timeout interval of sendTo. By default, it is set to None.
If the interval is too small, the minimum clock cycle is used. If the interval is too large, the maximum timeout interval (263–1 ns) is used. The default value is None.
Type: ?Duration
Throws:
- IllegalArgumentException: If the timeout interval is less than 0, this exception is thrown.
func receiveFrom(Array<Byte>)
func receiveFrom(buffer: Array<Byte>): (SocketAddress, Int64)
Description: Waits in a blocked state for receiving packets in buffer.
Parameters:
- buffer: Array<Byte>: Buffer space for storing the content of packets.
buffershould have a proper size. Otherwise, the packet to be received may be truncated, and the size of the packet is greater than the value ofbuffer.
Returns:
- (SocketAddress, Int64): packet sending address and size of the received packet (which may be 0 or greater than the value of
buffer)
Throws:
- SocketException: When the local buffer is too small to read packets, this exception is thrown.
- SocketTimeoutException: When a timeout occurs in reading, this exception is thrown.
func sendTo(SocketAddress, Array<Byte>)
func sendTo(address: SocketAddress, payload: Array<Byte>): Unit
Description: Sends packets to a specified remote address. When the peer end does not have sufficient buffer, this operation may be blocked and packets may be discarded.
Parameters:
- address: SocketAddress: remote receiving address
- payload: Array<Byte>: packet content to be sent
interface ServerSocket
public interface ServerSocket <: Resource & ToString {
prop localAddress: SocketAddress
func accept(): StreamingSocket
func accept(timeout!: ?Duration): StreamingSocket
func bind(): Unit
}
Description: Provides APIs required by Socket of the server.
Parent Type:
prop localAddress
prop localAddress: SocketAddress
Description: Reads the local address bound or to be bound with Socket.
Type: SocketAddress
Throws:
- SocketException: When
Socketis closed, this exception is thrown.
func accept()
func accept(): StreamingSocket
Description: Receives a connection request from a client socket and waits in a blocked state for the connection request.
Returns:
- StreamingSocket: client socket that is successfully connected
func accept(?Duration)
func accept(timeout!: ?Duration): StreamingSocket
Description: Receives a connection request from a client socket and waits for the connection request in blocking mode.
Parameters:
- timeout!: ?Duration: timeout interval for waiting for a connection
Returns:
- StreamingSocket: client socket that is successfully connected
Throws:
- SocketTimeoutException: When a timeout occurs in waiting for a connection request, this exception is thrown.
- IllegalArgumentException: If the timeout interval is less than 0, this exception is thrown.
func bind()
func bind(): Unit
Description: Binds a socket.
If the reuse attribute is not adopted, the close socket is needed when the local port, address, or file path is occupied, or the last connection to the bound socket fails. The accept() operation can be performed after multiple retries.
Throws:
- SocketException: If binding fails due to a system error, this exception is thrown.
interface StreamingSocket
public interface StreamingSocket <: IOStream & Resource & ToString {
prop localAddress: SocketAddress
prop remoteAddress: SocketAddress
mut prop readTimeout: ?Duration
mut prop writeTimeout: ?Duration
}
Description: Specifies Socket running in duplex stream mode, which is readable and writable.
StreamingSocket can be bound (bind) and connected (connect). You can set the remote and local addresses for the binding and connection through attribute setting. StreamingSocket can transmit byte streams in sequenced packets. A buffer space is used to store read and written byte streams. By default, when no data arrives, the read interface (read()) waits in a blocked state until arrival of subsequent data or a timeout. The write operation (write()) writes data in the buffer and sends the data later. If the buffer space is insufficient or the write speed is faster than the forwarding speed, the write operation waits in a blocked state for spare buffer space or a timeout. Characters are always read and written in order, but the packet policy and size during transmission may not be the same as those during packet delivery. For example, if one end sends a 10-byte packet and then a 15-byte packet, the peer end may receive the 10-byte packet and the 15-byte packet respectively, or may receive a 25-byte packet at a time. When an abnormal packet is received, the packet length of –1 is returned.
Parent Type:
prop localAddress
prop localAddress: SocketAddress
Description: Reads the local address bound or to be bound with Socket.
Type: SocketAddress
Throws:
- SocketException: This exception is thrown when
Socketis closed or no local address is available (the local address is not configured and the socket is not connected).
prop readTimeout
mut prop readTimeout: ?Duration
Description: Sets and reads the read timeout interval.
If the interval is too small, the minimum clock cycle is used. If the interval is too large, the maximum timeout interval (263–1 ns) is used. The default value is None.
Type: ?Duration
Throws:
- IllegalArgumentException: If the timeout interval is less than 0, this exception is thrown.
prop remoteAddress
prop remoteAddress: SocketAddress
Description: Reads the remote address bound or to be bound with Socket.
Type: SocketAddress
Throws:
- SocketException: When
Socketis closed, this exception is thrown.
prop writeTimeout
mut prop writeTimeout: ?Duration
Description: Sets and reads the write timeout interval.
If the interval is too small, the minimum clock cycle is used. If the interval is too large, the maximum timeout interval (263–1 ns) is used. The default value is None.
Type: ?Duration
Throws:
- IllegalArgumentException: If the timeout interval is less than 0, this exception is thrown.
Class
class IPMask
public class IPMask <: ToString {
public init(buf: Array<UInt8>)
public init(ones: Int64, bits: Int64)
public init(a: UInt8, b: UInt8, c: UInt8, d: UInt8)
}
Description: Specifies an IP mask used to operate the IP address and route address.
Parent Type:
init(Array<UInt8>)
public init(buf: Array<UInt8>)
Description: Initializes a mask value.
Parameters:
Throws:
- IllegalArgumentException: If the value of
bufexceeds the threshold, which does not meet IPv4 or IPv6 requirements, this exception is thrown.
init(Int64, Int64)
public init(ones: Int64, bits: Int64)
Description: Initializes a mask value.
Parameters:
Throws:
- IllegalArgumentException: If the value of
bitsexceeds the threshold, which does not meet IPv4 or IPv6 requirements, this exception is thrown.
init(UInt8, UInt8, UInt8, UInt8)
public init(a: UInt8, b: UInt8, c: UInt8, d: UInt8)
Description: Initializes a mask value. The parameter values are the four bytes a.b.c.d of IPv4, respectively.
Parameters:
- a: UInt8: most significant byte
- b: UInt8: second most significant byte
- c: UInt8: second least significant byte
- d: UInt8: least significant byte
func size()
public func size(): (Int64, Int64)
Description: Obtains the number of 1s at the most significant bits and obtains the total number of bits.
Returns:
- (Int64, Int64): number of 1s at the most significant bits and total number of
bits. If any of the most significant bits of the mask is not 1,(0, 0)is returned.
func toString()
public func toString(): String
Description: Converts an IP mask to a string.
Returns:
- String: string after conversion
class RawSocket
public class RawSocket {
public init(domain: SocketDomain, `type`: SocketType, protocol: ProtocolType)
}
Description: RawSocket provides basic functions of a socket.
This class can be used to access a socket combining specific communication domain, type, and protocol. The socket packet provides support for common network protocols including TCP and UDP. Therefore, this class is applicable to network programming using other protocols.
Note:
- Currently, verified functions of RawSocket include TCP, UDP, UDS, and ICMP sockets. For other classes, unexpected usage problems may occur.
- In addition, due to the API openness, using
connectfollowed bylistenis allowed. In some scenarios, unexpected problems may occur. It is recommended that developers comply with normal calling logic to prevent problems.
prop localAddr
public prop localAddr: RawAddress
Description: Obtains the local address of the current RawSocket instance.
Type: RawAddress
Throws:
- SocketException: If the current RawSocket instance has been closed or the local address cannot be obtained, this exception is thrown.
prop readTimeout
public mut prop readTimeout: ?Duration
Description: Obtains or sets the read timeout of the current RawSocket instance.
Type: ?Duration
Throws:
- SocketException: If the current RawSocket instance has been closed, this exception is thrown.
- IllegalArgumentException: If the set read timeout is negative, this exception is thrown.
prop remoteAddr
public prop remoteAddr: RawAddress
Description: Obtains the peer address of the current RawSocket instance.
Type: RawAddress
Throws:
- SocketException: If the current RawSocket instance has been closed or the peer address cannot be obtained, this exception is thrown.
prop writeTimeout
public mut prop writeTimeout: ?Duration
Description: Obtains or sets the write timeout of the current RawSocket instance.
Type: ?Duration
Throws:
- SocketException: If the current RawSocket instance has been closed, this exception is thrown.
- IllegalArgumentException: If the set write timeout is negative, this exception is thrown.
init(SocketDomain, SocketType, ProtocolType)
public init(domain: SocketDomain, `type`: SocketType, protocol: ProtocolType)
Description: Creates a socket combining specific communication domain, type, and protocol.
Parameters:
- domain: SocketDomain: communication domain
- `type`: SocketType: socket type
- protocol: ProtocolType: protocol type
Throws:
- SocketException: If the socket combining the specific communication domain, type, and protocol cannot be created, this exception is thrown.
func accept(?Duration)
public func accept(timeout!: ?Duration = None): RawSocket
Description: Receives the first connection request in the suspended connection queue when the current RawSocket instance is listening, and returns a RawSocket for communication.
Parameters:
- timeout!: ?Duration: maximum duration for waiting for the connection request. The default value
Noneindicates always waiting.
Returns:
Throws:
- SocketException: If the current RawSocket instance has been closed or receiving fails, this exception is thrown.
- SocketTimeoutException: If waiting times out, this exception is thrown.
func bind(RawAddress)
public func bind(addr: RawAddress): Unit
Description: Binds the current RawSocket instance to a specified socket address.
Parameters:
- addr: RawAddress: socket address
Throws:
- SocketException: If the current RawSocket instance has been closed or binding fails, this exception is thrown.
func close()
public func close(): Unit
Description: Closes the current RawSocket instance.
func connect(RawAddress, ?Duration)
public func connect(addr: RawAddress, timeout!: ?Duration = None): Unit
Description: Sends a connection request to a destination address.
Parameters:
- addr: RawAddress: destination address to which the connection request is sent
- timeout!: ?Duration: maximum duration for receiving the connection request. The default value
Noneindicates always waiting.
Throws:
- SocketException: If the current RawSocket instance has been closed or receiving fails, this exception is thrown.
- SocketTimeoutException: If waiting times out, this exception is thrown.
func getSocketOption(Int32, Int32, CPointer<Byte>, CPointer<Int32>)
public unsafe func getSocketOption(level: Int32, option: Int32, value: CPointer<Byte>, len: CPointer<Int32>): Unit
Description: Obtains the value of a socket option.
Parameters:
- level: Int32: socket option level
- option: Int32: socket option name
- value: CPointer<Byte>: socket option value
- len: CPointer<Int32>: socket option value length
Throws:
- SocketException: If the current RawSocket instance has been closed or the socket option fails to be obtained, this exception is thrown.
func listen(Int32)
public func listen(backlog: Int32): Unit
Description: Listens to the address bound to the current RawSocket instance.
Parameters:
- backlog: Int32: maximum length of the waiting queue
Throws:
- SocketException: If the current RawSocket instance has been closed or listening fails, this exception is thrown.
func receive(Array<Byte>, Int32)
public func receive(buffer: Array<Byte>, flags: Int32): Int64
Description: Receives data from the peer end in a connection.
Parameters:
- buffer: Array<Byte>: array for storing received data
- flags: Int32: flag specifying a function behavior
Returns:
- Int64: data length
Throws:
- SocketException: If the current RawSocket instance has been closed or data fails to be received, this exception is thrown.
- SocketTimeoutException: If the specified read timeout is exceeded, this exception is thrown.
func receiveFrom(Array<Byte>, Int32)
public func receiveFrom(buffer: Array<Byte>, flags: Int32): (RawAddress, Int64)
Description: Receives data from another RawSocket instance.
Parameters:
- buffer: Array<Byte>: array for storing received data
- flags: Int32: flag specifying a function behavior
Returns:
- (RawAddress, Int64): data source address and data length
Throws:
- SocketException: If the current RawSocket instance has been closed or data fails to be received, this exception is thrown.
- SocketTimeoutException: If the specified read timeout is exceeded, this exception is thrown.
func send(Array<Byte>, Int32)
public func send(buffer: Array<Byte>, flags: Int32): Unit
Description: Sends data to the peer end in a connection.
Parameters:
Throws:
- SocketException: If the current RawSocket instance has been closed or data fails to be sent, this exception is thrown.
- SocketTimeoutException: If the specified write timeout is exceeded, this exception is thrown.
func sendTo(RawAddress, Array<Byte>, Int32)
public func sendTo(addr: RawAddress, buffer: Array<Byte>, flags: Int32): Unit
Description: Sends data to a destination address. If the type of RawSocket is DATAGRAM, a data packet to be sent can contain a maximum of 65,507 bytes.
Parameters:
- addr: RawAddress: destination address to which data is sent
- buffer: Array<Byte>: data
- flags: Int32: flag specifying a function behavior
Throws:
- SocketException: If the current RawSocket instance has been closed or data fails to be sent, this exception is thrown.
- SocketTimeoutException: If the specified write timeout is exceeded, this exception is thrown.
- SocketException: On macOS, if
sendTois called afterconnectis called, this exception is thrown.
func setSocketOption(Int32, Int32, CPointer<Byte>, Int32)
public unsafe func setSocketOption(level: Int32, option: Int32, value: CPointer<Byte>, len: Int32): Unit
Description: Sets a socket option.
Parameters:
- level: Int32: socket option level
- option: Int32: socket option name
- value: CPointer<Byte>: socket option value
- len: Int32: socket option value length
Throws:
- SocketException: If the current RawSocket instance has been closed or the socket option fails to be set, this exception is thrown.
class SocketAddress
public open class SocketAddress <: ToString & Hashable & Equatable<SocketAddress> {
public init(kind: SocketAddressKind, address: Array<UInt8>, port: UInt16)
public init(hostAddress: String, port: UInt16)
public init(unixPath!: String)
}
Description: Socket address with specific type, address, and port
Parent Type:
prop address
public prop address: Array<UInt8>
Description: Obtains an address.
prop defaultMask
public prop defaultMask: Option<IPMask>
Description: Obtains the default mask.
prop hostAddress
public prop hostAddress: String
Description: Obtains a host address.
Type: String
prop hostName
public prop hostName: Option<String>
Description: Obtains a name and returns None if the name does not exist.
prop kind
public prop kind: SocketAddressKind
Description: Obtains an address type.
Type: SocketAddressKind
prop port
public prop port: UInt16
Description: Obtains a port.
Type: UInt16
prop zone
public prop zone: Option<String>
Description: Obtains the IPv6 address family.
init(SocketAddressKind, Array<UInt8>, UInt16)
public init(kind: SocketAddressKind, address: Array<UInt8>, port: UInt16)
Description: Creates a SocketAddress instance based on the input socket address type, IP address, and port number.
Parameters:
- kind: SocketAddressKind: socket address type
- address: Array<UInt8>: IP address
- port: UInt16: port number
Throws:
- SocketException: If the address length does not meet address type requirements, this exception is thrown.
init(String)
public init(unixPath!: String)
Description: Creates a SocketAddress instance based on the input file address.
Parameters:
- unixPath!: String: file address
Throws:
- SocketException: If the address cannot be resolved into the (../../../crypto/x509/x509_package_api/x509_package_type.md#type-ip) format or does not meet address type requirements, this exception is thrown.
init(String, UInt16)
public init(hostAddress: String, port: UInt16)
Description: Creates a SocketAddress instance based on the input IP address and port number.
Parameters:
Throws:
- SocketException: If the address cannot be resolved into the (../../../crypto/x509/x509_package_api/x509_package_type.md#type-ip) format or does not meet address type requirements, this exception is thrown.
static func resolve(String, UInt64)
public static func resolve(domain: String, port: UInt16): ?SocketAddress
Description: Resolves a domain and port, and constructs a SocketAddress instance.
When an IP address is input, the DNS capability is not included. When a domain name address is input, the IP address is obtained through getaddrinfo resolution. An IPv4 address is preferentially resolved, and only the first IP address obtained is returned.
Parameters:
Returns:
- ?SocketAddress: If the domain and port are resolved successfully, the SocketAddress instance is returned. Otherwise,
Noneis returned.
func hashCode()
public open func hashCode(): Int64
Description: Obtains the hashcode value.
Returns:
- Int64:
hashcodevalue
func kapString()
public func kapString(): String
Description: Obtains an IP protocol, address, and port string.
Returns:
Throws:
- SocketException: If the address size does not match IPv4 or IPv6, this exception is thrown.
func mask(IPMask)
public func mask(mask: IPMask): SocketAddressWithMask
Description: Uses the mask to process an address.
Parameters:
- mask: IPMask: mask
Returns:
- SocketAddressWithMask: address after processing
Throws:
- SocketException: If the mask length does not comply with the address length, this exception is thrown.
- IllegalArgumentException: If the buffer space does not meet IPv4 or IPv6 requirements, this exception is thrown.
func setHostName(String)
public func setHostName(name: String): Unit
Description: Sets a host name.
func toString()
public open func toString(): String
Description: Obtains an address object string.
Format: "127.0.0.1:2048", "[::]:2048", "[212c:3742::ffff:5863:6f00]:2048", and the like
Throws:
- SocketException: If the address is invalid, this exception is thrown.
operator func !=(SocketAddress)
public operator func != (that: SocketAddress): Bool
Description: Checks whether two SocketAddress instances are not equal.
Parameters:
- that: SocketAddress: SocketAddress input
Returns:
- Bool: If the two SocketAddress instances are not equal,
trueis returned. Otherwise,falseis returned.
operator func ==(SocketAddress)
public operator func ==(that: SocketAddress): Bool
Description: Checks whether two SocketAddress instances are equal.
Parameters:
- that: SocketAddress: SocketAddress input
Returns:
- Bool: If the two SocketAddress instances are equal,
trueis returned. Otherwise,falseis returned.
class SocketAddressWithMask
public class SocketAddressWithMask <: SocketAddress {
public init(kind: SocketAddressKind, address: Array<UInt8>, port: UInt16, mask: IPMask)
public init(hostAddress: String, port: UInt16, mask: IPMask)
public init(socketAddr: SocketAddress, mask: IPMask)
}
Description: Provides SocketAddress together with a mask.
Parent Type:
prop ipMask
public mut prop ipMask: IPMask
Description: Sets or obtains an IP mask.
Type: IPMask
init(SocketAddress, IPMask)
public init(socketAddr: SocketAddress, mask: IPMask)
Description: Creates a SocketAddressWithMask instance.
Parameters:
- socketAddr: SocketAddress: address
- mask: IPMask: mask
Throws:
- SocketException: If the parameter
socketAddris invalid, this exception is thrown.
init(SocketAddressKind, Array<UInt8>, UInt16, IPMask)
public init(kind: SocketAddressKind, address: Array<UInt8>, port: UInt16, mask: IPMask)
Description: Creates a SocketAddressWithMask instance.
Parameters:
- kind: SocketAddressKind: SocketAddress type
- address: Array<UInt8>: address of the type specified by
kind - port: UInt16: port
- mask: IPMask: mask
Throws:
- SocketException: If the address specified by the parameter
addressdoes not meet address type requirements of the parameterkind, this exception is thrown.
init(String, UInt16, IPMask)
public init(hostAddress: String, port: UInt16, mask: IPMask)
Description: Creates a SocketAddressWithMask instance.
Parameters:
Throws:
- SocketException: If the parameter
hostAddresscannot be resolved into a valid IP address, this exception is thrown.
func clone()
public func clone(): SocketAddressWithMask
Description: Uses the bound mask to process an address and copies a SocketAddressWithMask instance.
Throws:
- SocketException: If the mask length does not comply with the address length, this exception is thrown.
- IllegalArgumentException: If the buffer length is insufficient, this exception is thrown.
func hashCode()
public override func hashCode(): Int64
Description: Obtains the hashcode value of SocketAddressWithMask.
Returns:
- Int64:
hashcodevalue
func toString()
public override func toString(): String
Description: Converts SocketAddressWithMask into a string.
Returns:
- String: string after conversion
class TcpServerSocket
public class TcpServerSocket <: ServerSocket {
public init(bindAt!: SocketAddress)
public init(bindAt!: UInt16)
}
Description: Specifies a server that listens for TCP connections.
After a socket is created, a property value can be configured through prop and the setSocketOptionXX function.
To start listening, bind() must be called to bind the socket to a local port. The accept() function accepts the TCP connection, and the Cangjie thread is blocked until receiving a connection. If a connection already exists in the queue, a response is returned immediately.
The socket can be explicitly closed through close.
Parent Type:
prop backlogSize
public mut prop backlogSize: Int64
Description: Sets and reads the size of backlog.
If the property is called after bind is called, an exception is thrown.
Whether a variable takes effect depends on system behaviors.
Type: Int64
Throws:
- SocketException: If the property is called after
bindis called, this exception is thrown.
prop bindToDevice
public mut prop bindToDevice: ?String
Description: Sets and reads a bound NIC.
Type: ?String
prop localAddress
public override prop localAddress: SocketAddress
Description: Reads the local address of Socket that is to be or has been bound.
Type: SocketAddress
Throws:
- SocketException: If
Sockethas been closed, this exception is thrown.
prop receiveBufferSize
public mut prop receiveBufferSize: Int64
Description: Sets and reads the SO_RCVBUF property.
Type: Int64
Throws:
- IllegalArgumentException: If the value of
sizeis less than or equal to 0, this exception is thrown. - SocketException: If
Sockethas been closed, this exception is thrown.
prop reuseAddress
public mut prop reuseAddress: Bool
Description: Sets and reads the SO_REUSEADDR property. The default value is true.
Behaviors after the property takes effect depend on the system. Before usage, refer to description documents about the SO_REUSEADDR/SOCK_REUSEADDR property in different systems.
Type: Bool
prop reusePort
public mut prop reusePort: Bool
Description: Sets and reads the SO_REUSEPORT property.
This property can be modified only before binding. On Windows, the SO_REUSEADDR property cannot be used because it does not exist, and an exception is thrown.
Behaviors when the default property is used and after configuration takes effect depend on the system. Before usage, refer to description documents about the SO_REUSEPORT property in different systems.
If both SO_REUSEADDR/SO_REUSEPORT are enabled, unpredictable system errors occur. Exercise caution during configuration.
Type: Bool
Throws:
- SocketException: On Windows, this property is not supported, and this exception is thrown.
prop sendBufferSize
public mut prop sendBufferSize: Int64
Description: Sets and reads the SO_SNDBUF property.
Type: Int64
Throws:
- IllegalArgumentException: If the value of
sizeis less than or equal to 0, this exception is thrown. - SocketException: If
Sockethas been closed, this exception is thrown.
init(SocketAddress)
public init(bindAt!: SocketAddress)
Description: Creates a TcpServerSocket instance, which cannot be connected by clients before binding is complete.
Parameters:
- bindAt!: SocketAddress: local address to be bound. If the port number is set to 0, a random idle local address is bound.
init(UInt16)
public init(bindAt!: UInt16)
Description: Creates a TcpServerSocket instance, which cannot be connected by clients before binding is complete.
Parameters:
- bindAt!: UInt16: specifies a local port to be bound. The value 0 indicates that a random idle local port is bound.
func accept()
public override func accept(): TcpSocket
Description: Listens for or accepts client connections. After the function is called, the Cangjie thread is blocked until receiving a connection.
Returns:
- TcpSocket: client socket
Throws:
- SocketException: If listening fails due to a system error, this exception is thrown.
func accept(?Duration)
public override func accept(timeout!: ?Duration): TcpSocket
Description: Listens for or accepts client connections.
Parameters:
- timeout!: ?Duration: timeout
Returns:
- TcpSocket: client socket
Throws:
- SocketTimeoutException: If the connection times out, this exception is thrown.
- SocketException: If listening fails due to a system error, this exception is thrown.
- IllegalArgumentException: If the timeout is less than 0, this exception is thrown.
func bind()
public override func bind(): Unit
Description: If a local port fails to be bound, the socket needs to be closed using close. Retrying for many times is not supported.
Throws:
- SocketException: If binding fails due to a system error, this exception is thrown.
func close()
public override func close(): Unit
Description: Closes a socket. This function can be called more than once.
func getSocketOption(Int32, Int32, CPointer<Unit>, CPointer<UIntNative>)
public func getSocketOption(
level: Int32,
option: Int32,
value: CPointer<Unit>,
valueLength: CPointer<UIntNative>
): Unit
Description: Obtains a specified socket parameter.
Parameters:
- level: Int32: level, for example,
SOL_SOCKET - option: Int32: parameter, for example,
SO_KEEPALIVE - value: CPointer<Unit>: parameter value
- valueLength: CPointer<UIntNative>: parameter value length
Throws:
- SocketException: If the
getsockoptfunction fails to be called, this exception is thrown.
func getSocketOptionBool(Int32, Int32)
public func getSocketOptionBool(
level: Int32,
option: Int32
): Bool
Description: Obtains a specified socket parameter. It is forcibly converted from IntNative. 0 is converted to false, and a non-zero value is converted to true.
Parameters:
Returns:
- Bool: specified socket parameter. It is forcibly converted from IntNative.
0is converted tofalse, and a non-zero value is converted totrue.
Throws:
- SocketException: If the
getsockoptfunction fails to be called or the parameter value exceeds the threshold of IntNative, this exception is thrown.
func getSocketOptionIntNative(Int32, Int32)
public func getSocketOptionIntNative(
level: Int32,
option: Int32
): IntNative
Description: Obtains a specified socket parameter.
Parameters:
Returns:
- IntNative: value of the socket parameter obtained
Throws:
- SocketException: If the
getsockoptfunction fails to be called or the parameter value exceeds the threshold of IntNative, this exception is thrown.
func isClosed()
public override func isClosed(): Bool
Description: Checks whether a socket has been closed.
Returns:
- Bool: If the socket has been closed,
trueis returned. Otherwise,falseis returned.
func setSocketOption(Int32, Int32, CPointer<Unit>, UIntNative)
public func setSocketOption(
level: Int32,
option: Int32,
value: CPointer<Unit>,
valueLength: UIntNative
): Unit
Description: Sets a specified socket parameter.
Parameters:
- level: Int32: level, for example,
SOL_SOCKET - option: Int32: parameter, for example,
SO_KEEPALIVE - value: CPointer<Unit>: parameter value
- valueLength: UIntNative: parameter value length
Throws:
- SocketException: If the
setsockoptfunction fails to be called, this exception is thrown.
func setSocketOptionBool(Int32, Int32, Bool)
public func setSocketOptionBool(
level: Int32,
option: Int32,
value: Bool
): Unit
Description: Sets a specified socket parameter.
Parameters:
- level: Int32: level, for example,
SOL_SOCKET - option: Int32: parameter, for example,
SO_KEEPALIVE - value: Bool: parameter value
Throws:
- SocketException: If the
setsockoptfunction fails to be called, this exception is thrown.
func setSocketOptionIntNative(Int32, Int32, IntNative)
public func setSocketOptionIntNative(
level: Int32,
option: Int32,
value: IntNative
): Unit
Description: Sets a specified socket parameter.
Parameters:
- level: Int32: level, for example,
SOL_SOCKET - option: Int32: parameter, for example,
SO_KEEPALIVE - value: IntNative: parameter value
Throws:
- SocketException: If the
setsockoptfunction fails to be called, this exception is thrown.
func toString()
public override func toString(): String
Description: Returns status information about the current TcpServerSocket.
Returns:
- String: string containing status information about the current TcpServerSocket
class TcpSocket
public class TcpSocket <: StreamingSocket & Equatable<TcpSocket> & Hashable {
public init(address: String, port: UInt16)
public init(address: SocketAddress)
public init(address: SocketAddress, localAddress!: ?SocketAddress)
}
Description: Serves as a client requesting a TCP connection.
After an instance object is created, a connection can be created using the connect function and explicitly closed using close.
This class is inherited from StreamingSocket. For more information, see StreamingSocket.
Parent Type:
prop bindToDevice
public mut prop bindToDevice: ?String
Description: Sets and reads a bound NIC.
Type: ?String
prop keepAlive
public mut prop keepAlive: ?SocketKeepAliveConfig
Description: Sets and reads the keepalive property. None indicates that keepalive is disabled.
If there is no user setting, the system uses the default configuration. Setting this configuration may be delayed or ignored by the system, which depends on the processing capability of the system.
Type: ?SocketKeepAliveConfig
prop linger
public mut prop linger: ?Duration
Description: Sets and reads the SO_LINGER property. The default value depends on the system. None indicates that this option is disabled.
Note:
- If
SO_LINGERis set toSome(v), when the socket is closed, waiting lasts forv(time) before the connection is closed if there are still byte streams in waiting status. If these byte streams are still not sent after the period, the connection is terminated by an exception (closed through RST packets).- If
SO_LINGERis set toNone, when the socket is closed, the connection is closed immediately. If there is no character waiting to be sent, FIN-ACK is used to close the connection. If there are still characters waiting to be sent, RST is used to close the connection.
Type: ?Duration
Throws:
- IllegalArgumentException: If the timeout is less than 0, this exception is thrown.
prop localAddress
public override prop localAddress: SocketAddress
Description: Reads the local address of Socket that is to be or has been bound.
Type: SocketAddress
Throws:
- SocketException: If
Sockethas been closed or no local address is available (no local address is configured and the socket is not connected), this exception is thrown.
prop noDelay
public mut prop noDelay: Bool
Description: Sets and reads the TCP_NODELAY property. The default value is true.
This option disables the Nagel algorithm, and all written bytes are forwarded without delay. When the property is set to false, the Nagel algorithm introduces a delay time before packet sending.
Type: Bool
prop quickAcknowledge
public mut prop quickAcknowledge: Bool
Description: Sets and reads the TCP_QUICKACK property. The default value is false.
This option is similar to noDelay but affects only TCP ACK and the first response. It is not supported on Windows or macOS.
Type: Bool
prop readTimeout
public override mut prop readTimeout: ?Duration
Description: Sets and reads the read operation timeout.
If the value is too small, the minimum clock cycle is used. If the value is too large, the maximum timeout (263 – 1 nanoseconds) is used. The default value is None.
Type: ?Duration
Throws:
- IllegalArgumentException: If the timeout is less than 0, this exception is thrown.
prop receiveBufferSize
public mut prop receiveBufferSize: Int64
Description: Sets and reads the SO_RCVBUF property, and provides a method to specify the size for buffering received packets. Whether the option takes effect depends on the system.
Type: Int64
Throws:
- IllegalArgumentException: If the value of
sizeis less than or equal to 0, this exception is thrown. - SocketException: If
Sockethas been closed, this exception is thrown.
prop remoteAddress
public override prop remoteAddress: SocketAddress
Description: Reads the remote address to which Socket has been or is to be connected.
Type: SocketAddress
Throws:
- SocketException: If
Sockethas been closed, this exception is thrown.
prop sendBufferSize
public mut prop sendBufferSize: Int64
Description: Sets and reads the SO_SNDBUF property, and provides a method to specify the size for buffering packets to be sent. Whether the option takes effect depends on the system.
Type: Int64
Throws:
- IllegalArgumentException: If the value of
sizeis less than or equal to 0, this exception is thrown. - SocketException: If
Sockethas been closed, this exception is thrown.
prop writeTimeout
public override mut prop writeTimeout: ?Duration
Description: Sets and reads the write operation timeout.
If the value is too small, the minimum clock cycle is used. If the value is too large, the maximum timeout (263 – 1 nanoseconds) is used. The default value is None.
Type: ?Duration
Throws:
- IllegalArgumentException: If the timeout is less than 0, this exception is thrown.
init(SocketAddress)
public init(address: SocketAddress)
Description: Creates a socket that is not connected.
Parameters:
- address: SocketAddress: address to be connected to
Throws:
- SocketException: On Windows, if the
addressparameter is invalid, or the address is an all-zero address, this exception is thrown.
init(SocketAddress, ?SocketAddress)
public init(address: SocketAddress, localAddress!: ?SocketAddress)
Description: Creates a socket that is not connected and binds it to a specified local address. If None of local addresses are available, an address is randomly selected for the binding.
If localAddress is not None, SO_REUSEADDR is set to true by default. Otherwise, the error "address already in use" may occur. To change this configuration, call setSocketOptionBool(SocketOptions.SOL_SOCKET, SocketOptions.SO_REUSEADDR, false). In addition, the local and remote addresses must be IPv4 addresses.
Parameters:
- address: SocketAddress: address to be connected to
- localAddress!: ?SocketAddress: local address bound
Throws:
- SocketException: On Windows, if the
addressparameter is invalid, or the address is an all-zero address, this exception is thrown.
init(String, UInt16)
public init(address: String, port: UInt16)
Description: Creates a socket that is not connected.
Parameters:
- address: String: address to be connected to
- port: [UInt16](../../core/core_package_api/core_package_intrinsics.md#uint16: port to be connected to
Throws:
- SocketException: On Windows, if the
addressparameter is invalid, or the address is an all-zero address, this exception is thrown.
func close()
public func close(): Unit
Description: Closes a socket. All operations except close/isClosed are not allowed to be called again. This function can be called more than once.
func connect(?Duration)
public func connect(timeout!: ?Duration = None): Unit
Description: Connects to a remote socket, with the local address automatically bound. Therefore, no additional binding operation is required.
Parameters:
- timeout!: ?Duration: connection timeout.
Noneindicates no timeout and no connection retry. If the server rejects the connection, connection failure is returned. In addition, this operation includes the binding operation. Therefore, repeatedly calling thebindfunction is not required.
Throws:
- IllegalArgumentException: If the remote address is invalid, the connection timeout is less than 0, or the timeout is less than 0, this exception is thrown.
- SocketException: If the connection cannot be established due to a system issue (for example, socket closed, no access permission, or system error), this exception is thrown. The connection may be successful after the function is called again.
- SocketTimeoutException: If the connection times out, this exception is thrown.
func getSocketOption(Int32, Int32, CPointer<Unit>, CPointer<UIntNative>)
public func getSocketOption(
level: Int32,
option: Int32,
value: CPointer<Unit>,
valueLength: CPointer<UIntNative>
): Unit
Description: Reads a specified socket parameter.
Parameters:
- level: Int32: level, for example,
SOL_SOCKET - option: Int32: parameter, for example,
SO_KEEPALIVE - value: CPointer<Unit>: parameter value
- valueLength: CPointer<UIntNative>: parameter value length
Throws:
- SocketException: If the
getsockoptfunction fails to be called, this exception is thrown.
func getSocketOptionBool(Int32, Int32)
public func getSocketOptionBool(
level: Int32,
option: Int32
): Bool
Description: Reads a specified socket parameter. It is forcibly converted from IntNative. 0 is converted to false, and a non-zero value is converted to true.
Parameters:
Returns:
- Bool: parameter value read
Throws:
- SocketException: If the
getsockoptfunction fails to be called or the parameter value exceeds the threshold of IntNative, this exception is thrown.
func getSocketOptionIntNative(Int32, Int32)
public func getSocketOptionIntNative(
level: Int32,
option: Int32
): IntNative
Description: Reads a specified socket parameter.
Parameters:
Returns:
- IntNative: parameter value
Throws:
- SocketException: If the
getsockoptfunction fails to be called or the parameter value exceeds the threshold of IntNative, this exception is thrown.
func hashCode()
public override func hashCode(): Int64
Description: Obtains the hash value of the current TcpSocket instance.
Returns:
func isClosed()
public func isClosed(): Bool
Description: Checks whether a socket has been explicitly closed by calling close.
Returns:
- Bool: whether the socket has been explicitly closed by calling
close. If yes,trueis returned. Otherwise,falseis returned.
func read(Array<Byte>)
public override func read(buffer: Array<Byte>): Int64
Description: Reads packets. Timeout is determined by readTimeout. For details, see readTimeout.
Note:
- Due to the differences among underlying APIs of the system, if the connection is closed by the peer end, behaviors of the
readandwritefunctions are also different.- On Windows, after the peer end closes the connection, if
writeis called at the local end, content in the buffer is cleared. In this case, ifreadis called, a connection close exception is thrown.- On Linux or macOS, after the peer end closes the connection, if
readis called afterwriteis called, content in the buffer is still read.
Parameters:
Returns:
- Int64: length of the read data
Throws:
- SocketException: If the size of
bufferis 0 or a read operation fails due to a system error, this exception is thrown.
func setSocketOption(Int32, Int32, CPointer<Unit>, UIntNative)
public func setSocketOption(
level: Int32,
option: Int32,
value: CPointer<Unit>,
valueLength: UIntNative
): Unit
Description: Sets a specified socket parameter.
Parameters:
- level: Int32: level, for example,
SOL_SOCKET - option: Int32: parameter, for example,
SO_KEEPALIVE - value: CPointer<Unit>: parameter value
- valueLength: UIntNative: parameter value length
Throws:
- SocketException: If the
setsockoptfunction fails to be called, this exception is thrown.
func setSocketOptionBool(Int32, Int32, Bool)
public func setSocketOptionBool(
level: Int32,
option: Int32,
value: Bool
): Unit
Description: Sets a specified socket parameter.
Parameters:
- level: Int32: level, for example,
SOL_SOCKET - option: Int32: parameter, for example,
SO_KEEPALIVE - value: Bool: parameter value
Throws:
- SocketException: If the
setsockoptfunction fails to be called, this exception is thrown.
func setSocketOptionIntNative(Int32, Int32, IntNative)
public func setSocketOptionIntNative(
level: Int32,
option: Int32,
value: IntNative
): Unit
Description: Sets a specified socket parameter.
Parameters:
- level: Int32: level, for example,
SOL_SOCKET - option: Int32: parameter, for example,
SO_KEEPALIVE - value: IntNative: parameter value
Throws:
- SocketException: If the
setsockoptfunction fails to be called, this exception is thrown.
func toString()
public override func toString(): String
Description: Returns status information about the current TcpSocket.
Returns:
func write(Array<Byte>)
public override func write(payload: Array<Byte>): Unit
Description: Writes packets. Timeout is determined by writeTimeout. For details, see writeTimeout.
Parameters:
Throws:
- SocketException: If the size of
bufferis 0 or a write operation fails due to a system error, this exception is thrown.
operator func !=(TcpSocket)
public override operator func !=(other: TcpSocket): Bool
Description: Checks whether two TcpSocket instances are not equal.
Parameters:
Returns:
operator func ==(TcpSocket)
public override operator func ==(other: TcpSocket): Bool
Description: Checks whether two TcpSocket instances are equal.
Parameters:
Returns:
class UdpSocket
public class UdpSocket <: DatagramSocket {
public init(bindAt!: SocketAddress)
public init(bindAt!: UInt16)
}
Description: Provides UDP packet communication.
After a UDPSocket instance is created, bind() needs to be called for binding. Packets can be received without connection to the remote end. In addition, connection can be established for UDPSocket through the connect()/disconnect() function.
Packets to be transmitted cannot exceed 64 KB, which is required by the UDP protocol.
UDPSocket needs to be explicitly closed using close(). For more information, see DatagramSocket.
Parent Type:
prop localAddress
public override prop localAddress: SocketAddress
Description: Reads the local address of Socket that is to be or has been bound.
Type: SocketAddress
Throws:
- SocketException: If
Sockethas been closed or no local address is available (no local address is configured and the socket is not connected), this exception is thrown.
prop receiveBufferSize
public mut prop receiveBufferSize: Int64
Description: Sets and reads the SO_RCVBUF property.
Type: Int64
Throws:
- IllegalArgumentException: If the value of
sizeis less than or equal to 0, this exception is thrown. - SocketException: If
Sockethas been closed, this exception is thrown.
prop receiveTimeout
public override mut prop receiveTimeout: ?Duration
Description: Sets and reads the receive/receiveFrom operation timeout.
If the value is too small, the minimum clock cycle is used. If the value is too large, the maximum timeout (263 – 1 nanoseconds) is used. The default value is None.
Type: ?Duration
Throws:
- IllegalArgumentException: If the timeout is less than 0, this exception is thrown.
prop remoteAddress
public override prop remoteAddress: ?SocketAddress
Description: Reads the remote address connected to Socket. If Socket is not connected, None is returned.
Type: ?SocketAddress
Throws:
- SocketException: If
Sockethas been closed, this exception is thrown.
prop reuseAddress
public mut prop reuseAddress: Bool
Description: Sets and reads the SO_REUSEADDR property.
Behaviors when the default property is used and after it takes effect depend on the system. Before usage, refer to description documents about the SO_REUSEADDR/SOCK_REUSEADDR property in different systems.
Type: Bool
prop reusePort
public mut prop reusePort: Bool
Description: Sets and reads the SO_REUSEPORT property.
On Windows, SO_REUSEADDR can be used but the SO_REUSEPORT property is excluded. Therefore, an exception is thrown.
Behaviors when the default property is used and after configuration takes effect depend on the system. Before usage, refer to description documents about the SO_REUSEPORT property in different systems.
Type: Bool
Throws:
- SocketException: On Windows, this property is not supported, and this exception is thrown.
prop sendBufferSize
public mut prop sendBufferSize: Int64
Description: Sets and reads the SO_SNDBUF property.
Type: Int64
Throws:
- IllegalArgumentException: If the value of
sizeis less than or equal to 0, this exception is thrown. - SocketException: If
Sockethas been closed, this exception is thrown.
prop sendTimeout
public override mut prop sendTimeout: ?Duration
Description: Sets and reads the send/sendTo operation timeout.
If the value is too small, the minimum clock cycle is used. If the value is too large, the maximum timeout (263 – 1 nanoseconds) is used. The default value is None.
Type: ?Duration
init(SocketAddress)
public init(bindAt!: SocketAddress)
Description: Creates an unbound UDPSocket instance.
Parameters:
- bindAt!: SocketAddress: address and port to be bound
Throws:
- IllegalArgumentException: If the timeout is less than 0, this exception is thrown.
init(UInt64)
public init(bindAt!: UInt16)
Description: Creates an unbound UDPSocket instance.
Parameters:
- bindAt!: UInt16: port to be bound
func bind()
public func bind(): Unit
Description: If a local port fails to be bound, the socket needs to be closed using close. Retrying for many times is not supported.
Throws:
- SocketException: If binding fails due to a system error, this exception is thrown.
func close()
public override func close(): Unit
Description: Closes a socket. All operations except close/isClosed are not allowed to be called again. This function can be called more than once.
func connect(SocketAddress)
public func connect(remote: SocketAddress): Unit
Description: Connects to a specified remote address. The configuration can be canceled using disconnect.
Only packets from the remote address are received. This operation must be performed after bind is called. After this operation is performed, the port starts to receive ICMP packets. If abnormal packets are received, send/sendTo may fail to be executed.
Parameters:
- remote: SocketAddress: remote address
Throws:
- IllegalArgumentException: If the remote address is invalid, this exception is thrown.
- SocketException: On Windows, if the port is not bound, the connection cannot be established due to a system error, or the remote address is an all-zero address, this exception is thrown.
func disconnect()
public func disconnect(): Unit
Description: Stops a connection, which cancels the configuration that only packets from a specified peer end are received. This function can be called before connect more than once.
func getSocketOption(Int32, Int32, CPointer<Unit>, CPointer<UIntNative>)
public func getSocketOption(
level: Int32,
option: Int32,
value: CPointer<Unit>,
valueLength: CPointer<UIntNative>
): Unit
Description: Obtains a specified socket parameter.
Parameters:
- level: Int32: level, for example,
SOL_SOCKET - option: Int32: parameter, for example,
SO_KEEPALIVE - value: CPointer<Unit>: parameter value
- valueLength: CPointer<UIntNative>: parameter value length
Throws:
- SocketException: If the
getsockoptfunction fails to be called, this exception is thrown.
func getSocketOptionBool(Int32, Int32)
public func getSocketOptionBool(
level: Int32,
option: Int32
): Bool
Description: Obtains a specified socket parameter. It is forcibly converted from IntNative. 0 is converted to false, and a non-zero value is converted to true.
Parameters:
Returns:
- Bool: specified socket parameter. It is forcibly converted from IntNative.
0is converted tofalse, and a non-zero value is converted totrue.
Throws:
- SocketException: If the
getsockoptfunction fails to be called or the parameter value exceeds the threshold of IntNative, this exception is thrown.
func getSocketOptionIntNative(Int32, Int32)
public func getSocketOptionIntNative(
level: Int32,
option: Int32
): IntNative
Description: Obtains a specified socket parameter.
Parameters:
Returns:
- IntNative: value of the specified socket parameter
Throws:
- SocketException: If the
getsockoptfunction fails to be called or the parameter value exceeds the threshold of IntNative, this exception is thrown.
func isClosed()
public override func isClosed(): Bool
Description: Checks whether a socket has been explicitly closed by calling close.
Returns:
- Bool: If the socket has been explicitly closed using
close,trueis returned. Otherwise,falseis returned.
func receive(Array<Byte>)
public func receive(buffer: Array<Byte>): Int64
Description: Receives packets from an address connected to using connect.
Parameters:
Returns:
- [Int64](../../core/core_package_api/core_package_intrinsics.md#int64: size of the received packets
func receiveFrom(Array<Byte>)
public override func receiveFrom(buffer: Array<Byte>): (SocketAddress, Int64)
Description: Receives packets.
Parameters:
Returns:
- (SocketAddress, Int64): address from which the received packets are sent, and size of the received packets, which may be 0 or greater than the size of
buffer
Throws:
- SocketException: If the local buffer is too small to read packets, this exception is thrown.
- SocketTimeoutException: If the read operation times out, this exception is thrown.
func send(Array<Byte>)
public func send(payload: Array<Byte>): Unit
Description: Sends packets to the address connected to using connect.
Parameters:
Throws:
- SocketException: If the size of
payloadexceeds the system limit, the system fails to send the packets because, for example,connectis called, and receives abnormal ICMP packets, this exception is thrown.
func sendTo(SocketAddress, Array<Byte>)
public override func sendTo(recipient: SocketAddress, payload: Array<Byte>): Unit
Description: Sends packets. Insufficient buffer addresses may cause blocking.
Parameters:
- recipient: SocketAddress: peer address to which the packets are sent
- payload: Array<Byte>: content of the sent packets
Throws:
- SocketException: If the size of
payloadexceeds the system limit, the system fails to send the packets because (For example, whenconnectis called and abnormal ICMP packets are received, the sending fails), the remote address is an all-zero address, orsendTois called afterconnectis called, this exception is thrown.
func setSocketOption(Int32, Int32, CPointer<Unit>, UIntNative)
public func setSocketOption(
level: Int32,
option: Int32,
value: CPointer<Unit>,
valueLength: UIntNative
): Unit
Description: Sets a specified socket parameter.
Parameters:
- level: Int32: level, for example,
SOL_SOCKET - option: Int32: parameter, for example,
SO_KEEPALIVE - value: CPointer<Unit>: parameter value
- valueLength: UIntNative: parameter value length
Throws:
- SocketException: If the
setsockoptfunction fails to be called, this exception is thrown.
func setSocketOptionBool(Int32, Int32, Bool)
public func setSocketOptionBool(
level: Int32,
option: Int32,
value: Bool
): Unit
Description: Sets a specified socket parameter.
Parameters:
- level: Int32: level, for example,
SOL_SOCKET - option: Int32: parameter, for example,
SO_KEEPALIVE - value: Bool: parameter value
Throws:
- SocketException: If the
setsockoptfunction fails to be called, this exception is thrown.
func setSocketOptionIntNative(Int32, Int32, IntNative)
public func setSocketOptionIntNative(
level: Int32,
option: Int32,
value: IntNative
): Unit
Description: Sets a specified socket parameter.
Parameters:
- level: Int32: level, for example,
SOL_SOCKET - option: Int32: parameter, for example,
SO_KEEPALIVE - value: IntNative: parameter value
Throws:
- SocketException: If the
setsockoptfunction fails to be called, this exception is thrown.
func toString()
public override func toString(): String
Description: Returns status information about the current UdpSocket.
Returns:
class UnixDatagramSocket
public class UnixDatagramSocket <: DatagramSocket {
public init(bindAt!: SocketAddress)
public init(bindAt!: String)
}
Description: Provides the host communication capability based on data packets.
After the UnixDatagramSocket instance is created, the bind() function should be explicitly called for binding. For Unix data packets, the socket does not require a connection or many handshakes with the remote end. However, users can also use the connect/disconnect function to connect to or disconnect from the remote end.
Different from UDP, UDS has no restriction on the data packet size. However, there are operating system and API implementation restrictions.
Socket resources need to be explicitly reclaimed using the close function. For more information, see DatagramSocket.
Note:
- This class is not supported on Windows.
Parent Type:
prop localAddress
public override prop localAddress: SocketAddress
Description: Reads the local address of socket that is to be or has been bound.
Type: SocketAddress
Throws:
- SocketException: If
sockethas been closed, this exception is thrown.
prop receiveBufferSize
public mut prop receiveBufferSize: Int64
Description: Sets and reads the SO_RCVBUF property, and provides a method to specify the size for buffering packets to be sent. Whether the option takes effect depends on the system.
Type: Int64
Throws:
- IllegalArgumentException: If the value of
sizeis less than or equal to 0, this exception is thrown. - SocketException: If
Sockethas been closed, this exception is thrown.
prop receiveTimeout
public override mut prop receiveTimeout: ?Duration
Description: Sets and reads the receive/receiveFrom operation timeout.
If the value is too small, the minimum clock cycle is used. If the value is too large, the maximum timeout (263 – 1 nanoseconds) is used. The default value is None.
Type: ?Duration
Throws:
- IllegalArgumentException: If the timeout is less than 0, this exception is thrown.
prop remoteAddress
public override prop remoteAddress: ?SocketAddress
Description: Reads the remote address connected to Socket. If Socket is not connected, None is returned.
Type: ?SocketAddress
Throws:
- SocketException: If
Sockethas been closed, this exception is thrown.
prop sendBufferSize
public mut prop sendBufferSize: Int64
Description: Sets and reads the SO_SNDBUF property, and provides a method to specify the size for buffering packets to be sent. Whether the option takes effect depends on the system.
Type: Int64
Throws:
- IllegalArgumentException: If the value of
sizeis less than or equal to 0, this exception is thrown. - SocketException: If
Sockethas been closed, this exception is thrown.
prop sendTimeout
public override mut prop sendTimeout: ?Duration
Description: Sets and reads the send/sendTo operation timeout.
If the value is too small, the minimum clock cycle is used. If the value is too large, the maximum timeout (263 – 1 nanoseconds) is used. The default value is None.
Type: ?Duration
Throws:
- IllegalArgumentException: If the timeout is less than 0, this exception is thrown.
init(SocketAddress)
public init(bindAt!: SocketAddress)
Description: Creates a UnixDatagramSocket instance that is not connected.
isSock() can be used to check whether the file type exists, and the unlink() function can be used to delete the file type.
Parameters:
- bindAt!: SocketAddress: socket address to be connected to. The address does not exist and will be created upon binding using
bind.
Throws:
- SocketException: If the path is empty or already exists, this exception is thrown.
init(String)
public init(bindAt!: String)
Description: Creates a UnixDatagramSocket instance that is not connected.
isSock() can be used to check whether the file type exists, and the unlink() function can be used to delete the file type.
Parameters:
- bindAt!: String: file address. The file address does not exist and will be created upon binding using
bind.
Throws:
- SocketException: If the path is empty or already exists, this exception is thrown.
func bind()
public func bind(): Unit
Description: Binds a Unix datagram socket and creates a listening queue.
This function automatically creates a socket file in the local address. If the file already exists, the binding fails. isSock can be used to check whether the file type exists, and the unlink() function can be used to delete the file type. Upon failure, the socket needs to be closed using close. Repeated retries are not supported.
Throws:
- SocketException: If the file address already exists or the file fails to be created, this exception is thrown.
func close()
public override func close(): Unit
Description: Closes a socket. All operations except close/isClosed are not allowed to be called again. This function can be called more than once.
func connect(SocketAddress)
public func connect(remote: SocketAddress): Unit
Description: Connects to a specified remote address. The configuration can be canceled using disconnect.
Only packets from the remote address are received. bind is executed by default without the need of being called. After this operation is performed, the port starts to receive ICMP packets. If abnormal packets are received, send/sendTo may fail to be executed.
Parameters:
- remote: SocketAddress: remote socket address
Throws:
- SocketException: If the address is not bound, this exception is thrown.
func connect(String)
public func connect(remotePath: String): Unit
Description: Connects to a specified remote address. The configuration can be canceled using disconnect.
Only packets from the remote address are received. This function must be called after bind. After this operation is performed, the port starts to receive ICMP packets. If abnormal packets are received, send/sendTo may fail to be executed.
Parameters:
- remotePath: String: remote file address
Throws:
- SocketException: If the address is not bound, this exception is thrown.
func disconnect()
public func disconnect(): Unit
Description: Stops a connection, which cancels the configuration that only packets from a specified peer end are received. This function can be called before connect more than once.
Throws:
- SocketException: If binding is not complete, this exception is thrown.
func getSocketOption(Int32, Int32, CPointer<Unit>, CPointer<UIntNative>)
public func getSocketOption(
level: Int32,
option: Int32,
value: CPointer<Unit>,
valueLength: CPointer<UIntNative>
): Unit
Description: Obtains a specified socket parameter.
Parameters:
- level: Int32: level, for example,
SOL_SOCKET - option: Int32: parameter, for example,
SO_KEEPALIVE - value: CPointer<Unit>: parameter value
- valueLength: CPointer<UIntNative>: parameter value length
Throws:
- SocketException: If the
getsockoptfunction fails to be called, this exception is thrown.
func getSocketOptionIntNative(Int32, Int32)
public func getSocketOptionIntNative(
level: Int32,
option: Int32
): IntNative
Description: Obtains a specified socket parameter.
Parameters:
Returns:
- IntNative: The value of the specified socket parameter is returned.
Throws:
- SocketException: If the
getsockoptfunction fails to be called or the parameter value exceeds the threshold of IntNative, this exception is thrown.
func isClosed()
public override func isClosed(): Bool
Description: Checks whether a socket has been explicitly closed by calling close.
Returns:
- Bool: Information that whether the socket has been explicitly closed by calling
closeis returned. If yes,trueis returned. Otherwise,falseis returned.
func receive(Array<Byte>)
public func receive(buffer: Array<Byte>): Int64
Description: Receives packets from an address connected to using connect.
Parameters:
Returns:
- [Int64](../../core/core_package_api/core_package_intrinsics.md#int64: size of the received packets
func receiveFrom(Array<Byte>)
public override func receiveFrom(buffer: Array<Byte>): (SocketAddress, Int64)
Description: Receives packets.
Parameters:
Returns:
- (SocketAddress, Int64): address from which the received packets are sent, and size of the received packets, which may be 0 or greater than the size of
buffer
Throws:
- SocketException: If the local buffer is too small to read packets, this exception is thrown.
- SocketTimeoutException: If the read operation times out, this exception is thrown.
func send(Array<Byte>)
public func send(payload: Array<Byte>): Unit
Description: Sends packets to the address connected to using connect.
Parameters:
Throws:
- SocketException: If the size of
payloadexceeds the system limit, or the system fails to send the packets because, for example,connectis called, and receives abnormal ICMP packets, the sending fails.
func sendTo(SocketAddress, Array<Byte>)
public override func sendTo(recipient: SocketAddress, payload: Array<Byte>): Unit
Description: Sends packets. Insufficient buffer addresses may cause blocking.
Parameters:
- recipient: SocketAddress: address of the peer end to which the packets are sent
- payload: Array<Byte>: content of the sent packets
Throws:
- SocketException: If the size of
payloadexceeds the system limit, the system fails to send the packets because (For example,connectis called, and receives abnormal ICMP packets, the sending fails), orsendTois called afterconnectis called, this exception is thrown.
func setSocketOption(Int32, Int32, CPointer<Unit>, UIntNative)
public func setSocketOption(
level: Int32,
option: Int32,
value: CPointer<Unit>,
valueLength: UIntNative
): Unit
Description: Sets a specified socket parameter.
Parameters:
- level: Int32: level, for example,
SOL_SOCKET - option: Int32: parameter, for example,
SO_KEEPALIVE - value: CPointer<Unit>: parameter value
- valueLength: UIntNative: parameter value length
Throws:
- SocketException: If the
setsockoptfunction fails to be called, this exception is thrown.
func setSocketOptionBool(Int32, Int32, Bool)
public func setSocketOptionBool(
level: Int32,
option: Int32,
value: Bool
): Unit
Description: Sets a specified socket parameter.
Parameters:
- level: Int32: level, for example,
SOL_SOCKET - option: Int32: parameter, for example,
SO_KEEPALIVE - value: Bool: parameter value
Throws:
- SocketException: If the
setsockoptfunction fails to be called, this exception is thrown.
func setSocketOptionIntNative(Int32, Int32, IntNative)
public func setSocketOptionIntNative(
level: Int32,
option: Int32,
value: IntNative
): Unit
Description: Sets a specified socket parameter.
Parameters:
- level: Int32: level, for example,
SOL_SOCKET - option: Int32: parameter, for example,
SO_KEEPALIVE - value: IntNative: parameter value
Throws:
- SocketException: If the
setsockoptfunction fails to be called, this exception is thrown.
func getSocketOptionBool(Int32, Int32)
public func getSocketOptionBool(
level: Int32,
option: Int32
): Bool
Description: Obtains a specified socket parameter. It is forcibly converted from IntNative. 0 is converted to false, and a non-zero value is converted to true.
Parameters:
Returns:
- Bool: The value of the specified socket parameter is returned. It is forcibly converted from IntNative.
0is converted tofalse, and a non-zero value is converted totrue.
Throws:
- SocketException: If the
getsockoptfunction fails to be called, this exception is thrown.
func toString()
public override func toString(): String
Description: Returns status information about the current UDS.
Returns:
- String: string containing status information about the current
UDS
class UnixServerSocket
public class UnixServerSocket <: ServerSocket
Description: Provides a host communication server based on the duplex stream.
UnixServerSocket listens for connection requests. After creation, a property value can be configured through prop and the setSocketOptionXX function. The bind() function needs to be called for binding a local address to start listening for connections. A connection can be accepted through the accept() function.
Note:
- This class is not supported on Windows.
Parent Type:
prop backlogSize
public mut prop backlogSize: Int64
Description: Sets and reads the size of backlog. If the property is called after bind is called, an exception is thrown.
Whether a variable takes effect depends on system behaviors.
Type: Int64
Throws:
- SocketException: If the property is called after
bindis called, this exception is thrown.
prop localAddress
public override prop localAddress: SocketAddress
Description: Reads the local address of Socket that is to be or has been bound.
Type: SocketAddress
Throws:
- SocketException: If
Sockethas been closed, this exception is thrown.
prop receiveBufferSize
public mut prop receiveBufferSize: Int64
Description: Sets and reads the SO_RCVBUF property.
Type: Int64
Throws:
- IllegalArgumentException: If the value of
sizeis less than or equal to 0, this exception is thrown. - SocketException: If
Sockethas been closed, this exception is thrown.
prop sendBufferSize
public mut prop sendBufferSize: Int64
Description: Sets and reads the SO_SNDBUF property.
Type: Int64
Throws:
- IllegalArgumentException: If the value of
sizeis less than or equal to 0, this exception is thrown. - SocketException: If
Sockethas been closed, this exception is thrown.
init(SocketAddress)
public init(bindAt!: SocketAddress)
Description: Creates a UnixServerSocket instance that is not connected.
Parameters:
- bindAt!: SocketAddress: socket address to be connected to
init(String)
public init(bindAt!: String)
Description: Creates a UnixServerSocket instance that is not connected.
isSock can be used to check whether the file type exists, and the unlink() function can be used to delete the file type.
Parameters:
- bindAt!: String: file address
func accept()
public override func accept(): UnixSocket
Description: Waits to accept a connection from a client or reads a connection from the queue.
Returns:
- UnixSocket: socket of the client to be connected to
func accept(?Duration)
public override func accept(timeout!: ?Duration): UnixSocket
Description: Waits to accept a connection from a client or reads a connection from the queue.
Parameters:
- timeout!: ?Duration: timeout
Returns:
- UnixSocket: socket of the client to be connected to
Throws:
- SocketTimeoutException: If the connection times out, this exception is thrown.
- IllegalArgumentException: If the timeout is less than 0, this exception is thrown.
func bind()
public override func bind(): Unit
Description: Binds a Unix domain socket and creates a listening queue.
This function automatically creates a socket file in the local address. If the file already exists, the binding fails. The isSock function can be used to check whether the file type exists, and the unlink() function can be used to delete the file type. Upon failure, the socket needs to be closed using close. Repeated retries are not supported.
Throws:
- SocketException: If binding fails due to a system error, this exception is thrown.
func close()
public override func close(): Unit
Description: Closes a socket. All operations on the socket except close/isClosed are not allowed to be called again. This function can be called more than once.
func getSocketOption(Int32, Int32, CPointer<Unit>, CPointer<UIntNative>)
public func getSocketOption(
level: Int32,
option: Int32,
value: CPointer<Unit>,
valueLength: CPointer<UIntNative>
): Unit
Description: Obtains a specified socket parameter.
Parameters:
- level: Int32: level, for example,
SOL_SOCKET - option: Int32: parameter, for example,
SO_KEEPALIVE - value: CPointer<Unit>: parameter value
- valueLength: CPointer<UIntNative>: parameter value length
Throws:
- SocketException: If the
getsockoptfunction fails to be called, this exception is thrown.
func getSocketOptionBool(Int32, Int32)
public func getSocketOptionBool(
level: Int32,
option: Int32
): Bool
Description: Obtains a specified socket parameter. It is forcibly converted from IntNative. 0 is converted to false, and a non-zero value is converted to true.
Parameters:
Returns:
- Bool: The specified socket parameter is returned. It is forcibly converted from IntNative.
0is converted tofalse, and a non-zero value is converted totrue.
Throws:
- SocketException: If the
getsockoptfunction fails to be called or the parameter value exceeds the threshold of IntNative, this exception is thrown.
func getSocketOptionIntNative(Int32, Int32)
public func getSocketOptionIntNative(
level: Int32,
option: Int32
): IntNative
Description: Obtains a socket parameter whose return value is an integer.
Parameters:
Returns:
- IntNative: value of the specified socket parameter
Throws:
- SocketException: If the
getsockoptfunction fails to be called or the parameter value exceeds the threshold of IntNative, this exception is thrown.
func isClosed()
public override func isClosed(): Bool
Description: Checks whether a socket has been explicitly closed by calling close.
func setSocketOption(Int32, Int32, CPointer<Unit>, UIntNative)
public func setSocketOption(
level: Int32,
option: Int32,
value: CPointer<Unit>,
valueLength: UIntNative
): Unit
Description: Sets a socket parameter whose return value is an integer.
Parameters:
- level: Int32: level, for example,
SOL_SOCKET - option: Int32: parameter, for example,
SO_KEEPALIVE - value: CPointer<Unit>: parameter value
- valueLength: UIntNative: parameter value length
Throws:
- SocketException: If the
setsockoptfunction fails to be called, this exception is thrown.
func setSocketOptionBool(Int32, Int32, Bool)
public func setSocketOptionBool(
level: Int32,
option: Int32,
value: Bool
): Unit
Description: Sets a specified socket parameter.
Parameters:
- level: Int32: level, for example,
SOL_SOCKET - option: Int32: parameter, for example,
SO_KEEPALIVE - value: Bool: parameter value
Throws:
- SocketException: If the
setsockoptfunction fails to be called, this exception is thrown.
func setSocketOptionIntNative(Int32, Int32, IntNative)
public func setSocketOptionIntNative(
level: Int32,
option: Int32,
value: IntNative
): Unit
Description: Sets a specified socket parameter.
Parameters:
- level: Int32: level, for example,
SOL_SOCKET - option: Int32: parameter, for example,
SO_KEEPALIVE - value: IntNative: parameter value
Throws:
- SocketException: If the
setsockoptfunction fails to be called, this exception is thrown.
func toString()
public override func toString(): String
Description: Returns status information about the current UnixServerSocket.
Returns:
- String: string containing status information about the current UnixServerSocket
class UnixSocket
public class UnixSocket <: StreamingSocket {
public init(address: SocketAddress)
public init(path: String)
}
Description: Provides a host communication client based on the duplex stream.
After the UnixSocket instance is created, the connect() function needs to be called to create a connection, and close() needs to be explicitly called to reclaim resources when the connection is no more required. For more information, see StreamingSocket.
Note:
- This class is not supported on Windows.
Parent Type:
prop localAddress
public override prop localAddress: SocketAddress
Description: Reads the local address of Socket that is to be or has been bound.
Type: SocketAddress
Throws:
- SocketException: If
Sockethas been closed or no local address is available (no local address is configured and the socket is not connected), this exception is thrown.
prop readTimeout
public override mut prop readTimeout: ?Duration
Description: Sets and reads the read operation timeout.
If the value is too small, the minimum clock cycle is used. If the value is too large, None is used. The default value is None.
Type: ?Duration
Throws:
- IllegalArgumentException: If the timeout is less than 0, this exception is thrown.
prop receiveBufferSize
public mut prop receiveBufferSize: Int64
Description: Sets and reads the SO_RCVBUF property.
Type: Int64
Throws:
- IllegalArgumentException: If the value of
sizeis less than or equal to 0, this exception is thrown. - SocketException: If
Sockethas been closed, this exception is thrown.
prop remoteAddress
public override prop remoteAddress: SocketAddress
Description: Reads the remote address to which Socket has been or is to be connected.
Type: SocketAddress
Throws:
- SocketException: If
Sockethas been closed, this exception is thrown.
prop sendBufferSize
public mut prop sendBufferSize: Int64
Description: Sets and reads the SO_SNDBUF property.
Type: Int64
Throws:
- IllegalArgumentException: If the value of
sizeis less than or equal to 0, this exception is thrown. - SocketException: If
Sockethas been closed, this exception is thrown.
prop writeTimeout
public override mut prop writeTimeout: ?Duration
Description: Sets and reads the write operation timeout.
If the value is too small, the minimum clock cycle is used. If the value is too large, the maximum timeout (263 – 1 nanoseconds) is used. The default value is None.
Type: ?Duration
Throws:
- IllegalArgumentException: If the timeout is less than 0, this exception is thrown.
init(SocketAddress)
public init(address: SocketAddress)
Description: Creates a UnixSocket instance that is not connected.
Parameters:
- address: SocketAddress: socket address to be connected to
init(String)
public init(path: String)
Description: Creates a UnixSocket instance that is not connected.
isSock can be used to check whether the file type exists, and the unlink() function can be used to delete the file type.
Parameters:
- path: String: file address
func close()
public func close(): Unit
Description: Closes a socket. All operations except close/isClosed are not allowed to be called again. This function can be called more than once.
func connect(?Duration)
public func connect(timeout!: ?Duration = None): Unit
Description: Establishes a connection with the peer end. If the peer end rejects the connection, the connection fails and a local address is automatically bound. Therefore, no additional binding operation is required.
Parameters:
- timeout!: ?Duration: timeout.
Noneindicates no timeout. Different from TCP, when Unix is used, if the queue is full, an error is returned immediately without retrying blocked waiting when the function is called.
Throws:
- IllegalArgumentException: If the remote address is invalid, or the timeout is less than 0, this exception is thrown.
- SocketException: If the connection cannot be established due to a system error, this exception is thrown.
- SocketTimeoutException: If the connection times out, this exception is thrown.
func getSocketOption(Int32, Int32, CPointer<Unit>, CPointer<UIntNative>)
public func getSocketOption(
level: Int32,
option: Int32,
value: CPointer<Unit>,
valueLength: CPointer<UIntNative>
): Unit
Description: Obtains a specified socket parameter.
Parameters:
- level: Int32: level, for example,
SOL_SOCKET - option: Int32: parameter, for example,
SO_KEEPALIVE - value: CPointer<Unit>: parameter value
- valueLength: CPointer<UIntNative>: parameter value length
Throws:
- SocketException: If the
getsockoptfunction fails to be called, this exception is thrown.
func getSocketOptionBool(Int32, Int32)
public func getSocketOptionBool(
level: Int32,
option: Int32
): Bool
Description: Obtains a specified socket parameter. It is forcibly converted from IntNative. 0 is converted to false, and a non-zero value is converted to true.
Parameters:
Returns:
- Bool: The value of the specified socket parameter is returned. It is forcibly converted from IntNative.
0is converted tofalse, and a non-zero value is converted totrue.
Throws:
- SocketException: If the
getsockoptfunction fails to be called or the parameter value exceeds the threshold of IntNative, this exception is thrown.
func getSocketOptionIntNative(Int32, Int32)
public func getSocketOptionIntNative(
level: Int32,
option: Int32
): IntNative
Description: Obtains a specified socket parameter.
Parameters:
Returns:
- IntNative: value of the specified socket parameter
Throws:
- SocketException: If the
getsockoptfunction fails to be called or the parameter value exceeds the threshold of IntNative, this exception is thrown.
func isClosed()
public func isClosed(): Bool
Description: Checks whether a socket has been explicitly closed by calling close.
Returns:
- Bool: Information that whether the socket has been explicitly closed by calling
closeis returned. If yes,trueis returned. Otherwise,falseis returned.
func read(Array<Byte>)
public override func read(buffer: Array<Byte>): Int64
Description: Reads packets. Timeout is determined by readTimeout. For details, see readTimeout.
Parameters:
Returns:
- Int64: length of the read data
Throws:
- SocketException: If the size of
bufferis 0 or a read operation fails due to a system error, this exception is thrown.
func setSocketOption(Int32, Int32, CPointer<Unit>, UIntNative)
public func setSocketOption(
level: Int32,
option: Int32,
value: CPointer<Unit>,
valueLength: UIntNative
): Unit
Description: Sets a specified socket parameter.
Parameters:
- level: Int32: level, for example,
SOL_SOCKET - option: Int32: parameter, for example,
SO_KEEPALIVE - value: CPointer<Unit>: parameter value
- valueLength: UIntNative: parameter value length
Throws:
- SocketException: If the
setsockoptfunction fails to be called, this exception is thrown.
func setSocketOptionBool(Int32, Int32, Bool)
public func setSocketOptionBool(
level: Int32,
option: Int32,
value: Bool
): Unit
Description: Sets a specified socket parameter.
Parameters:
- level: Int32: level, for example,
SOL_SOCKET - option: Int32: parameter, for example,
SO_KEEPALIVE - value: Bool: parameter value
Throws:
- SocketException: If the
setsockoptfunction fails to be called, this exception is thrown.
func setSocketOptionIntNative(Int32, Int32, IntNative)
public func setSocketOptionIntNative(
level: Int32,
option: Int32,
value: IntNative
): Unit
Description: Sets a specified socket parameter.
Parameters:
- level: Int32: level, for example,
SOL_SOCKET - option: Int32: parameter, for example,
SO_KEEPALIVE - value: IntNative: parameter value
Throws:
- SocketException: If the
setsockoptfunction fails to be called, this exception is thrown.
func toString()
public override func toString(): String
Description: Returns status information about the current UnixSocket.
Returns:
- String: string containing status information about the current UnixSocket
func write(Array<Byte>)
public override func write(buffer: Array<Byte>): Unit
Description: Reads and writes data. Timeout is determined by writeTimeout. For details, see writeTimeout.
Parameters:
Throws:
- SocketException: If the size of
bufferis 0 or a write operation fails due to a system error, this exception is thrown.
Enumeration
enum SocketAddressKind
public enum SocketAddressKind <: ToString & Equatable<SocketAddressKind> {
| IPv4
| IPv6
| Unix
}
Description: Specifies the Internet communication protocol type.
Parent Type:
IPv4
IPv4
Description: Indicates the IPv4 protocol.
IPv6
IPv6
Description: Indicates the IPv6 protocol.
Unix
Unix
Description: Indicates the Unix protocol.
func toString()
public func toString(): String
Description: Converts an enumerated value into a string.
Returns:
- String: string obtained through conversion
operator func !=(SocketAddressKind)
public operator func !=(that: SocketAddressKind): Bool
Description: Checks whether two SocketAddressKind instances are not equal.
Parameters:
- that: SocketAddressKind: input SocketAddressKind
Returns:
- Bool: If they are not equal,
trueis returned; otherwise,falseis returned.
operator func ==(SocketAddressKind)
public operator func ==(that: SocketAddressKind): Bool
Description: Checks whether two SocketAddressKind instances are equal.
Parameters:
- that: SocketAddressKind: input SocketAddressKind
Returns:
- Bool: If they are equal,
trueis returned; otherwise,falseis returned.
enum SocketNet
public enum SocketNet <: ToString & Equatable<SocketNet> {
| TCP
| UDP
| UNIX
}
Description: Specifies the transport layer protocol type.
Parent Type:
TCP
TCP
Description: Indicates the TCP protocol.
UDP
UDP
Description: Indicates the UDP protocol.
UNIX
UNIX
Description: Indicates the UNIX protocol.
func toString()
public func toString(): String
Description: Converts an enumerated value into a string.
Returns:
- String: string obtained through conversion
operator func !=(SocketNet)
public operator func !=(that: SocketNet): Bool
Description: Checks whether two SocketNet instances are not equal.
Parameters:
Returns:
- Bool: If they are not equal,
trueis returned; otherwise,falseis returned.
operator func ==(SocketNet)
public operator func ==(that: SocketNet): Bool
Description: Checks whether two SocketNet instances are equal.
Parameters:
Returns:
- Bool: If they are equal,
trueis returned; otherwise,falseis returned.
Struct
struct OptionLevel
public struct OptionLevel {
public static const ICMP: Int32
public static const IP: Int32
public static const RAW: Int32
public static const SOCKET: Int32
public static const TCP: Int32
public static const UDP: Int32
}
Description: Provides common socket option levels.
static const ICMP
public static const ICMP: Int32
Description: Controls the socket option level of the ICMP protocol behavior.
Type: Int32
static const IP
public static const IP: Int32
Description: Controls the socket option level of the IP protocol behavior.
Type: Int32
static const RAW
public static const RAW: Int32
Description: Controls the socket option level of the RAW protocol behavior.
Type: Int32
static const SOCKET
public static const SOCKET: Int32
Description: Controls the socket option level of basic socket behavior.
Type: Int32
static const TCP
public static const TCP: Int32
Description: Controls the socket option level of the TCP protocol behavior.
Type: Int32
static const UDP
public static const UDP: Int32
Description: Controls the socket option level of the UDP protocol behavior.
Type: Int32
struct OptionName
public struct OptionName {
public static const IP_HDRINCL: Int32
public static const IP_TOS: Int32
public static const IP_TTL: Int32
public static const SO_ACCEPTCONN: Int32
public static const SO_BROADCAST: Int32
public static const SO_DEBUG: Int32
public static const SO_DONTROUTE: Int32
public static const SO_ERROR: Int32
public static const SO_KEEPALIVE: Int32
public static const SO_LINGER: Int32
public static const SO_OOBINLINE: Int32
public static const SO_RCVBUF: Int32
public static const SO_RCVTIMEO: Int32
public static const SO_REUSEADDR: Int32
public static const SO_SNDBUF: Int32
public static const SO_SNDTIMEO: Int32
public static const TCP_KEEPCNT: Int32
public static const TCP_KEEPIDLE: Int32
public static const TCP_KEEPINTVL: Int32
public static const TCP_NODELAY: Int32
}
Description: Provides common socket options.
static const IP_HDRINCL
public static const IP_HDRINCL: Int32
Description: Specifies the socket option used to check whether the IP header is a socket option provided by an application when a packet is being sent.
Type: Int32
static const IP_TOS
public static const IP_TOS: Int32
Description: Indicates the socket option used to specify the service type and priority of a packet.
Type: Int32
static const IP_TTL
public static const IP_TTL: Int32
Description: Specifies the socket option used to limit the maximum number of hops for transmitting IP packets on the network.
Type: Int32
static const SO_ACCEPTCONN
public static const SO_ACCEPTCONN: Int32
Description: Specifies the socket option used to query whether a socket is in the listening state.
Type: Int32
static const SO_BROADCAST
public static const SO_BROADCAST: Int32
Description: Specifies the socket option used to set whether a socket permits sending broadcast messages.
Type: Int32
static const SO_DEBUG
public static const SO_DEBUG: Int32
Description: Specifies the socket option used to enable or disable the debug mode.
Type: Int32
static const SO_DONTROUTE
public static const SO_DONTROUTE: Int32
Description: Specifies the socket option used to avoid routing socket packets during socket connection.
Type: Int32
static const SO_ERROR
public static const SO_ERROR: Int32
Description: Specifies the socket option used to obtain and clear the error state of a socket.
Type: Int32
static const SO_KEEPALIVE
public static const SO_KEEPALIVE: Int32
Description: Specifies the socket option used to check whether the TCP connection is still active.
Type: Int32
static const SO_LINGER
public static const SO_LINGER: Int32
Description: Specifies the socket option used to set the behavior of closing a socket.
Type: Int32
static const SO_OOBINLINE
public static const SO_OOBINLINE: Int32
Description: Specifies the socket option used to control the mode of receiving out-of-band data.
Type: Int32
static const SO_RCVBUF
public static const SO_RCVBUF: Int32
Description: Specifies the socket option used to set the size of the receive buffer of the socket.
Type: Int32
static const SO_RCVTIMEO
public static const SO_RCVTIMEO: Int32
Description: Specifies the socket option used to set the timeout interval for the socket to receive data.
Type: Int32
static const SO_REUSEADDR
public static const SO_REUSEADDR: Int32
Description: Specifies the socket option used to release the bound port immediately after the socket is closed so that other sockets can be immediately bound to the port.
Type: Int32
static const SO_SNDBUF
public static const SO_SNDBUF: Int32
Description: Specifies the socket option used to set the size of the send buffer of the socket.
Type: Int32
static const SO_SNDTIMEO
public static const SO_SNDTIMEO: Int32
Description: Specifies the socket option used to set the timeout interval for the socket to send data.
Type: Int32
static const TCP_KEEPCNT
public static const TCP_KEEPCNT: Int32
Description: Specifies the socket option used to control the number of keepalive probe packets sent over a TCP connection.
Type: Int32
static const TCP_KEEPIDLE
public static const TCP_KEEPIDLE: Int32
Description: Specifies the socket option used to set the maximum number of times a TCP connection is maintained when no acknowledgment is received from the peer end.
Type: Int32
static const TCP_KEEPINTVL
public static const TCP_KEEPINTVL: Int32
Description: Specifies the socket option used to set the interval for sending probe packets when the TCP connection is maintained.
Type: Int32
static const TCP_NODELAY
public static const TCP_NODELAY: Int32
Description: Specifies the socket option used to control the delay behavior of the TCP protocol.
Type: Int32
struct ProtocolType
public struct ProtocolType <: Equatable<ProtocolType> & ToString & Hashable {
public static let ICMP: ProtocolType
public static let IPV4: ProtocolType
public static let IPV6: ProtocolType
public static let RAW: ProtocolType
public static let TCP: ProtocolType
public static let UDP: ProtocolType
public static let Unspecified: ProtocolType
public init(protocol: Int32)
}
Description: Provides common socket protocols, and allows the socket protocols to be constructed by specifying the value of Int32.
Parent Type:
static let ICMP
public static let ICMP: ProtocolType
Description: Sets the protocol type to ICMP.
Type: ProtocolType
static let IPV4
public static let IPV4: ProtocolType
Description: Sets the protocol type to IPV4.
Type: ProtocolType
static let IPV6
public static let IPV6: ProtocolType
Description: Sets the protocol type to IPV6.
Type: ProtocolType
static let RAW
public static let RAW: ProtocolType
Description: Sets the protocol type to RAW.
Type: ProtocolType
static let TCP
public static let TCP: ProtocolType
Description: Sets the protocol type to TCP.
Type: ProtocolType
static let UDP
public static let UDP: ProtocolType
Description: Sets the protocol type to UDP.
Type: ProtocolType
static let Unspecified
public static let Unspecified: ProtocolType
Description: Leaves the protocol type unspecified.
Type: ProtocolType
init(Int32)
public init(protocol: Int32)
Description: Creates a protocol by specifying the socket protocol value.
Parameters:
- protocol: Int32: socket protocol value
func hashCode()
public func hashCode(): Int64
Description: Returns the hash value of the current ProtocolType instance.
Returns:
- Int64: hash value of the current ProtocolType instance
func toString()
public func toString(): String
Description: Returns the string representation of the current ProtocolType instance.
Returns:
- [String](../../core/core_package_api/core_package_structs.md#struct-string): string representation of the current ProtocolType instance
operator func !=(ProtocolType)
public operator func !=(r: ProtocolType): Bool
Description: Checks whether two ProtocolType instances are not equal.
Parameters:
- r: ProtocolType: ProtocolType instances for comparison
Returns:
- Bool: If the Int32 values represented by the two instances are not equal,
trueis returned. Otherwise,falseis returned.
operator func ==(ProtocolType)
public operator func ==(r: ProtocolType): Bool
Description: Checks whether two ProtocolType instances are equal.
Parameters:
- r: ProtocolType: ProtocolType instances for comparison
Returns:
- Bool: If the Int32 values represented by the two instances are equal,
trueis returned. Otherwise,falseis returned.
struct RawAddress
public struct RawAddress {
public init(addr: Array<Byte>)
}
Description: Creates and obtains the communication address of RawSocket.
prop addr
public prop addr: Array<Byte>
Description: Obtains the address.
init(Array<Byte>)
public init(addr: Array<Byte>)
Description: Creates an address based on a byte array.
Parameters:
struct SocketDomain
public struct SocketDomain <: Equatable<SocketDomain> & ToString & Hashable {
public static let IPV4: SocketDomain
public static let IPV6: SocketDomain
public static let NETLINK: SocketDomain
public static let PACKET: SocketDomain
public static let UNIX: SocketDomain
public init(domain: Int32)
}
Description: Provides common socket communication domains, and allows the socket communication domains to be constructed by specifying the value of Int32.
Parent Type:
static let IPV4
public static let IPV4: SocketDomain
Description: Specifies the IPV4 communication domain.
Type: SocketDomain
static let IPV6
public static let IPV6: SocketDomain
Description: Specifies the IPV6 communication domain.
Type: SocketDomain
static let NETLINK
public static let NETLINK: SocketDomain
Description: Specifies the communication between the kernel space process and the userspace process.
Note:
- The Windows platform does not provide this constant.
Type: SocketDomain
static let PACKET
public static let PACKET: SocketDomain
Description: Provides userspace applications with direct access to network packets.
Note:
- The Windows platform does not provide this constant.
Type: SocketDomain
static let UNIX
public static let UNIX: SocketDomain
Description: Supports local communication.
Type: SocketDomain
init(Int32)
public init(domain: Int32)
Description: Creates a socket communication domain based on the specified communication domain value.
Parameters:
- domain: Int32: communication domain value
func hashCode()
public func hashCode(): Int64
Description: Returns the hash value of the current SocketDomain instance.
Returns:
- Int64: hash value of the current SocketDomain instance
func toString()
public func toString(): String
Description: Returns the string representation of the current SocketDomain instance.
Returns:
- [String](../../core/core_package_api/core_package_structs.md#struct-string): string representation of the current SocketDomain instance
operator func !=(SocketDomain)
public operator func !=(r: SocketDomain): Bool
Description: Compares whether two SocketDomain instances are not equal.
Parameters:
- r: SocketDomain: SocketDomain instances for comparison
Returns:
- Bool: If the Int32 values represented by the two instances are not equal,
trueis returned. Otherwise,falseis returned.
operator func ==(SocketDomain)
public operator func ==(r: SocketDomain): Bool
Description: Compares whether two SocketDomain instances are equal.
Parameters:
- r: SocketDomain: SocketDomain instances for comparison
Returns:
- Bool: If the Int32 values represented by the two instances are equal,
trueis returned. Otherwise,falseis returned.
struct SocketKeepAliveConfig
public struct SocketKeepAliveConfig <: ToString & Equatable<SocketKeepAliveConfig> {
public let count: UInt32
public let idle: Duration
public let interval: Duration
public init(idle!: Duration = Duration.second * 45, interval!: Duration = Duration.second * 5, count!: UInt32 = 5)
}
Description: Configures the TCP KeepAlive attribute.
Parent Type:
let count
public let count: UInt32
Description: Queries the number of packets indicating whether the connection is invalid.
Type: UInt32
let idle
public let idle: Duration
Description: Specifies the duration in which a connection is allowed to be idle. If the duration exceeds a threshold, the connection is terminated.
Type: Duration
let interval
public let interval: Duration
Description: Specifies the interval for sending keepalive packets.
Type: Duration
init(Duration, Duration, UInt32)
public init(idle!: Duration = Duration.second * 45, interval!: Duration = Duration.second * 5, count!: UInt32 = 5)
Description: Initializes the SocketKeepAliveConfig instance object.
Parameters:
- idle!: Duration: duration allowed to be idle. The default value is 45 seconds.
- interval!: Duration: interval for sending keepalive packets. The default value is 45 seconds.
- count!: UInt32: number of packets indicating whether a connection is invalid. The default value is 5.
Throws:
- IllegalArgumentException: When the idle state is configured or the interval is less than 0, this exception is thrown.
func toString()
public override func toString(): String
Description: Converts the TCP KeepAlive attribute into a string.
Returns:
- String: string obtained through conversion
operator func !=(SocketKeepAliveConfig)
public override operator func !=(other: SocketKeepAliveConfig): Bool
Description: Checks whether two SocketKeepAliveConfig instances are not equal.
Parameters:
- other: SocketKeepAliveConfig: SocketKeepAliveConfig instances for comparison
Returns:
- Bool: If they are not equal,
trueis returned. Otherwise,falseis returned.
operator func ==(SocketKeepAliveConfig)
public override operator func ==(other: SocketKeepAliveConfig): Bool
Description: Checks whether two SocketKeepAliveConfig instances are equal.
Parameters:
- other: SocketKeepAliveConfig: SocketKeepAliveConfig instances for comparison
Returns:
- Bool: If they are equal,
trueis returned. Otherwise,falseis returned.
struct SocketOptions
public struct SocketOptions {
public static const IPPROTO_TCP
public static const IPPROTO_UDP
public static const SOL_SOCKET
public static const SO_BINDTODEVICE
public static const SO_KEEPALIVE
public static const SO_LINGER
public static const SO_RCVBUF
public static const SO_REUSEADDR
public static const SO_REUSEPORT
public static const SO_SNDBUF
public static const TCP_NODELAY
public static const TCP_QUICKACK
}
Description: SocketOptions stores some constants for setting socket options for subsequent calling.
const IPPROTO_TCP
public static const IPPROTO_TCP: Int32 = IPPROTO_TCP
Description: Specifies the constant used to set level of a socket option to IPPROTO_TCP.
Type: Int32
const IPPROTO_UDP
public static const IPPROTO_UDP: Int32 = IPPROTO_UDP
Description: Specifies the constant used to set level of a socket option to IPPROTO_UDP.
Type: Int32
const SOL_SOCKET
public static const SOL_SOCKET: Int32 = SOL_SOCKET
Description: Specifies the constant used to set level of a socket option to SOL_SOCKET.
Type: Int32
const SO_BINDTODEVICE
public static const SO_BINDTODEVICE: Int32 = SOCK_BINDTODEVICE
Description: Specifies the constant used to set optname of a socket option to SO_BINDTODEVICE.
Type: Int32
const SO_KEEPALIVE
public static const SO_KEEPALIVE: Int32 = SOCK_KEEPALIVE
Description: Specifies the constant used to set optname of a socket option to SO_KEEPALIVE.
Type: Int32
const SO_LINGER
public static const SO_LINGER: Int32 = SOCK_LINGER
Description: Specifies the constant used to set optname of a socket option to SO_LINGER.
Type: Int32
const SO_RCVBUF
public static const SO_RCVBUF: Int32 = SOCK_RCVBUF
Description: Specifies the constant used to set optname of a socket option to SO_RCVBUF.
Type: Int32
const SO_REUSEADDR
public static const SO_REUSEADDR: Int32 = SOCK_REUSEADDR
Description: Specifies the constant used to set optname of a socket option to SO_REUSEADDR.
Type: Int32
const SO_REUSEPORT
public static const SO_REUSEPORT: Int32 = SOCK_REUSEPORT
Description: Specifies the constant used to set optname of a socket option to SO_REUSEPORT.
Type: Int32
const SO_SNDBUF
public static const SO_SNDBUF: Int32 = SOCK_SNDBUF
Description: Specifies the constant used to set optname of a socket option to SO_SNDBUF.
Type: Int32
const TCP_NODELAY
public static const TCP_NODELAY: Int32 = SOCK_TCP_NODELAY
Description: Specifies the constant used to set optname of a socket option to TCP_NODELAY.
Type: Int32
const TCP_QUICKACK
public static const TCP_QUICKACK: Int32 = SOCK_TCP_QUICKACK
Description: Specifies the constant used to set optname of a socket option to TCP_QUICKACK.
Type: Int32
struct SocketType
public struct SocketType <: Equatable<SocketType> & ToString & Hashable {
public static let DATAGRAM: SocketType
public static let RAW: SocketType
public static let SEQPACKET: SocketType
public static let STREAM: SocketType
public init(`type`: Int32)
}
Description: Provides common socket types and allows the socket types to be constructed by specifying the value of Int32.
Parent Type:
static let DATAGRAM
public static let DATAGRAM: SocketType
Description: Specifies the packet socket type.
Type: SocketType
static let RAW
public static let RAW: SocketType
Description: Specifies the raw socket type.
Type: SocketType
static let SEQPACKET
public static let SEQPACKET: SocketType
Description: Specifies the sequenced packet socket type.
Type: SocketType
static let STREAM
public static let STREAM: SocketType
Description: Specifies the stream socket type.
Type: SocketType
init(Int32)
public init(`type`: Int32)
Description: Creates a socket type by specifying the socket type value.
Parameters:
- `type`: Int32: socket type value
func hashCode()
public func hashCode(): Int64
Description: Returns the hash value of the current SocketType instance.
Returns:
- Int64: hash value of the current SocketType instance
func toString()
public func toString(): String
Description: Returns the string representation of the current SocketType instance.
Returns:
- String: string representation of the current SocketType instance
operator func !=(SocketType)
public operator func !=(r: SocketType): Bool
Description: Checks whether two SocketType instances are not equal.
Parameters:
- r: SocketType: SocketType instances for comparison
Returns:
- Bool: If the Int32 values represented by the two instances are not equal,
trueis returned. Otherwise,falseis returned.
operator func ==(SocketType)
public operator func ==(r: SocketType): Bool
Description: Checks whether two SocketType instances are equal.
Parameters:
- r: SocketType: SocketType instances for comparison
Returns:
- Bool: If the Int32 values represented by the two instances are equal,
trueis returned. Otherwise,falseis returned.
Exception Class
class SocketException
public class SocketException <: Exception {
public init()
public init(message: String)
}
Description: Provides socket-related exception processing.
Parent Type:
init()
public init()
Description: Creates a SocketException instance.
init(String)
public init(message: String)
Description: Creates a SocketException instance based on the exception information.
Parameters:
- message: String: exception prompt
class SocketTimeoutException
public class SocketTimeoutException <: Exception {
public init()
public init(message: String)
}
Description: Provides exception processing related to socket operation timeout.
Parent Type:
init()
public init()
Description: Creates a SocketTimeoutException instance.
init(String)
public init(message: String)
Description: Creates a SocketTimeoutException instance based on the exception information.
Parameters:
- message: String: exception prompt
Usage Cases of Attribute Configuration
Configuring Attributes
import std.socket.*
import std.time.*
import std.sync.*
main (){
try (tcpSocket = TcpSocket("127.0.0.1", 80)) {
tcpSocket.readTimeout = Duration.second
tcpSocket.noDelay = false
tcpSocket.linger = Duration.minute
tcpSocket.keepAlive = SocketKeepAliveConfig(
interval: Duration.second * 7,
count: 15
)
}
}
Adding Custom Attributes
import std.socket.*
extend TcpSocket {
public mut prop customNoDelay: Int64 {
get() {
Int64(getSocketOptionIntNative(SocketOptions.IPPROTO_TCP, SocketOptions.TCP_NODELAY))
}
set(value) {
setSocketOptionIntNative(SocketOptions.IPPROTO_TCP, SocketOptions.TCP_NODELAY, IntNative(value))
}
}
}
main() {
let socket = TcpSocket("127.0.0.1", 0)
socket.customNoDelay = 1
println(socket.customNoDelay)
}
Running result:
1
TCP Usage Example
import std.socket.*
import std.time.*
import std.sync.*
let SERVER_PORT: UInt16 = 33333
func runTcpServer() {
try (serverSocket = TcpServerSocket(bindAt: SERVER_PORT)) {
serverSocket.bind()
try (client = serverSocket.accept()) {
let buf = Array<Byte>(10, item: 0)
let count = client.read(buf)
// Server read 3 bytes: [1, 2, 3, 0, 0, 0, 0, 0, 0, 0]
println("Server read ${count} bytes: ${buf}")
}
}
}
main(): Int64 {
spawn {
runTcpServer()
}
sleep(Duration.millisecond * 500)
try (socket = TcpSocket("127.0.0.1", SERVER_PORT)) {
socket.connect()
socket.write(Array<Byte>([1, 2, 3]))
}
return 0
}
Running result:
Server read 3 bytes: [1, 2, 3, 0, 0, 0, 0, 0, 0, 0]
UDP Usage Example
import std.socket.*
import std.time.*
import std.sync.*
let SERVER_PORT: UInt16 = 33333
func runUpdServer() {
try (serverSocket = UdpSocket(bindAt: SERVER_PORT)) {
serverSocket.bind()
let buf = Array<Byte>(3, item: 0)
let (clientAddr, count) = serverSocket.receiveFrom(buf)
let sender = clientAddr.hostAddress
// Server receive 3 bytes: [1, 2, 3] from 127.0.0.1
println("Server receive ${count} bytes: ${buf} from ${sender}")
}
}
main(): Int64 {
spawn {
runUpdServer()
}
sleep(Duration.second)
try (udpSocket = UdpSocket(bindAt: 0)) { // random port
udpSocket.sendTimeout = Duration.second * 2
udpSocket.bind()
udpSocket.sendTo(
SocketAddress("127.0.0.1", SERVER_PORT),
Array<Byte>([1, 2, 3])
)
}
return 0
}
Running result:
Server receive 3 bytes: [1, 2, 3] from 127.0.0.1
UNIX Usage Example
import std.socket.*
import std.time.*
import std.sync.*
let SOCKET_PATH = "/tmp/tmpsock"
func runUnixServer() {
try (serverSocket = UnixServerSocket(bindAt: SOCKET_PATH)) {
serverSocket.bind()
try (client = serverSocket.accept()) {
client.write("hello".toArray())
}
}
}
main(): Int64 {
spawn {
runUnixServer()
}
sleep(Duration.second)
try (socket = UnixSocket(SOCKET_PATH)) {
socket.connect()
let buf = Array<Byte>(10, item: 0)
socket.read(buf)
println(String.fromUtf8(buf)) // hello
}
return 0
}
Running result:
hello
UnixDatagram Usage Example
import std.socket.*
import std.time.*
import std.sync.*
import std.fs.*
import std.os.*
import std.random.*
func createTempFile(): String {
let tempDir: Path = tempDir().info.path
let index: String = Random().nextUInt64().toString()
return tempDir.join("tmp${index}").toString()
}
func runUnixDatagramServer(serverPath: String, clientPath: String) {
try (serverSocket = UnixDatagramSocket(bindAt: serverPath)) {
serverSocket.bind()
let buf = Array<Byte>(3, item: 0)
let (clientAddr, read) = serverSocket.receiveFrom(buf)
if (read == 3 && buf == Array<Byte>([1, 2, 3])) {
println("server received")
}
if (clientAddr.toString() == clientPath) {
println("client address correct")
}
}
}
main(): Int64 {
let clientPath = createTempFile()
let serverPath = createTempFile()
spawn {
runUnixDatagramServer(serverPath, clientPath)
}
sleep(Duration.second)
try (unixSocket = UnixDatagramSocket(bindAt: clientPath)) {
unixSocket.sendTimeout = Duration.second * 2
unixSocket.bind()
unixSocket.connect(serverPath)
unixSocket.send(Array<Byte>([1, 2, 3]))
sleep(Duration.second)
}
return 0
}
Running result:
server received
client address correct
std.sort Package
Function Description
The sort package provides sorting functions of the array type.
Based on the sorting mode, this package provides two sets of implementation: stable sorting and unstable sorting. During stable sorting, the sequence of equal elements remains unchanged before and after sorting. On the contrary, during unstable sorting, it is not ensured that the sequence of equal elements is consistent before and after sorting.
This package provides a group of generic sorting functions for sorting arrays with type T elements. Sorting requires elements to be comparable. Therefore, this group of functions is further classified into two categories: 1. The Comparable<T> interface needs to be implemented by T. 2. The T related compare function is transferred to a function as a parameter.
In addition, this package provides auxiliary interfaces SortByExtension and SortExtension, which can be used to implement sorting-related functions of other types.
API List
Function
| Name | Description |
|---|---|
| stableSort<T>(Array<T>) where T <: Comparable<T> | Stably sorts arrays in ascending order. |
| stableSort<T>(Array<T>, (T, T) -> Ordering) | Stably sorts arrays in ascending order. |
| unstableSort<T>(Array<T>) where T <: Comparable<T> | Unstably sorts arrays in ascending order. |
| unstableSort<T>(Array<T>, (T, T) -> Ordering) | Unstably sorts arrays in ascending order. |
Interface
| Name | Description |
|---|---|
| SortByExtension | Serves as an auxiliary interface related to sorting. This interface is empty internally. |
| SortExtension | Serves as an auxiliary interface related to sorting. This interface is empty internally. |
Function
func stableSort<T>(Array<T>) where T <: Comparable<T>
public func stableSort<T>(data: Array<T>): Unit where T <: Comparable<T>
Description: Stably sorts an array in ascending order.
Parameters:
- data: Array<T>: array to be sorted
func stableSort<T>(Array<T>, (T, T) -> Ordering)
public func stableSort<T>(data: Array<T>, comparator: (T, T) -> Ordering): Unit
Description: Sorts an array stably.
You can input a custom compare function comparator. If the return of comparator is Ordering.GT, t1 follows t2 after the sorting. If the return of comparator is Ordering.LT, t1 precedes t2 after the sorting. If the return of comparator is Ordering.EQ, the sequences of t1 and t2 remain unchanged after the sorting.
Parameters:
- data: Array<T>: array to be sorted
- comparator: (T, T) ->Ordering: compare function input by the user
func unstableSort<T>(Array<T>) where T <: Comparable<T>
public func unstableSort<T>(data: Array<T>): Unit where T <: Comparable<T>
Description: Unstably sort an array in ascending order.
Parameters:
- data: Array<T>: array to be sorted
func unstableSort<T>(Array<T>, (T, T) -> Ordering)
public func unstableSort<T>(data: Array<T>, comparator: (T, T) -> Ordering): Unit
Description: Sorts an array unstably.
You can input a custom compare function comparator. If the return of comparator is Ordering.GT, t1 follows t2 after the sorting. If the return of comparator is Ordering.LT, t1 precedes t2 after the sorting. If the return of comparator is Ordering.EQ, the sequences of t1 and t2 remain unchanged after the sorting.
Parameters:
- data: Array<T>: array to be sorted
- comparator: (T, T) ->Ordering: compare function input by the user
Interface
interface SortByExtension
public interface SortByExtension
Description: Serves as an auxiliary interface related to sorting. This interface is empty internally.
extend<T> Array<T> <: SortByExtension
extend<T> Array<T> <: SortByExtension
Description: This extension is used to implement the sortBy function of Array.
Parent Type:
func sortBy(Bool, (T, T) -> Ordering)
public func sortBy(stable!: Bool = false, comparator!: (T, T) -> Ordering): Unit
Description: Performs custom sorting of arrays based on the input compare function and the Ordering type in the return.
Parameters:
- stable!: Bool: whether to use stable sorting
- comparator!: (T, T) ->Ordering: compare function input by the user. For example, comparator: (t1: T, t2: T) -> Ordering. If the return of
comparatoris Ordering.GT,t1followst2after the sorting. If the return ofcomparatoris Ordering.LT,t1precedest2after the sorting. If the return ofcomparatoris Ordering.EQ and stable sorting is used, the sequences oft1andt2remain unchanged after the sorting. If the return ofcomparatoris Ordering.EQ and unstable sorting is used, the sequences oft1andt2are uncertain.
interface SortExtension
public interface SortExtension
Description: Serves as an auxiliary interface related to sorting. This interface is empty internally.
extend<T> Array<T> <: SortExtension where T <: Comparable<T>
extend<T> Array<T> <: SortExtension where T <: Comparable<T>
Description: This extension is used to implement the sort/sortDescending function of Array.
Parent Type:
func sort(Bool)
public func sort(stable!: Bool = false): Unit
Description: Sorts Array in ascending order.
Parameters:
- stable!: Bool: whether to use stable sorting
func sortDescending(Bool)
public func sortDescending(stable!: Bool = false): Unit
Description: Sorts Array in descending order.
Parameters:
- stable!: Bool: whether to use stable sorting
Sorting Arrays
Creates an unordered array, sorts the array in ascending order, and uses isAse to determine whether the array is sorted in ascending order.
Code:
import std.sort.*
import std.random.*
main(): Unit {
let r: Random = Random()
let arr: Array<Int64> = Array<Int64>(70000, { _ => r.nextInt64() })
arr.sortBy(stable: true){ rht: Int64, lht: Int64 =>
if (rht < lht) {
return Ordering.LT
}
if (rht > lht) {
return Ordering.GT
}
return Ordering.EQ
}
println(isAse(arr))
}
func isAse(t: Array<Int64>) {
var item: Int64 = t[0]
for (i in 1..t.size) {
if (item > t[i]) {
return false
}
item = t[i]
}
return true
}
Running result:
true
std.sync Package
Function Description
The sync package provides concurrent programming capabilities.
As more computers begin to use multi-core processors, concurrent programming becomes more important to give full play to the advantages of multi-core processors.
Different programming languages implement threads in different ways. In some programming languages, threads are created by calling an operating system (OS) API. In this case, each language thread corresponds to an OS thread, which is generally referred to as a 1:1 thread model. Some other programming languages provide a special thread implementation, which allows multiple language threads to be switched and executed in contexts of different quantities of OS threads. This implementation is also referred to as an M:N thread model. Specifically, M language threads are scheduled and executed on N OS threads, where M and N may not be equal.
The Cangjie programming language is intended to provide a user-friendly, efficient, and unified concurrent programming interface so that you do not need to care about the differences between concepts such as OS threads and user-mode threads. In addition, details of the underlying implementation are concealed. Therefore, we provide only the concept of Cangjie thread. The Cangjie thread is implemented using the M:N thread model. Therefore, it is essentially a user-mode lightweight thread that supports preemption and occupies less memory resources than the OS thread.
To execute a section of code concurrently, you only need to create one Cangjie thread.
To create a new Cangjie thread, you can use the keyword spawn and pass a lambda expression without formal parameters. The lambda expression is the code expected to be executed in the new thread.
Example:
Create a Cangjie thread using the keyword spawn:
import std.sync.sleep
import std.time.Duration
main () {
spawn {
// Executed in the new thread
println("Thread: ${Thread.currentThread.id}")
}
// Executed in the main thread
println("Thread: ${Thread.currentThread.id}")
sleep(Duration.second)
0
}
The sync package provides different types of atomic operations, reentrant mutex and APIs thereof, and uses thread synchronization mechanism of shared variables and timers.
Atomic operations include operations of the integer type, Bool type, and reference type.
The integer types include Int8, Int16, Int32, Int64, UInt8, UInt16, UInt32, and UInt64.
Atomic operations of the integer type include basic operations such as read (load) and write (store), swap (swap/compareAndSwap), and arithmetic operation (fetchAdd/fetchSub). Note the following:
-
The returns of the swap operation and arithmetic operation are values not modified.
-
compareAndSwapis used to check whether the value of the current atomic variable is equal to the specified value. If they are equal, the value is replaced with another value. If they are not equal, the value is not replaced.
Atomic operations of the Bool type and reference type provide only read, write, and swap operations. Note the following:
The atomic operations of the reference type are valid only for the reference type.
ReentrantMutex has many drawbacks in application. For example, you may forget to unlock, or when the mutex is held, an exception of being unable to automatically release the lock, is thrown. Therefore, the Cangjie programming language provides the keyword synchronized for solving similar problems in combination with reentrantMutex.
A reentrant mutex instance is added after synchronized to protect the subsequent modified code block. In this way, only one thread can execute the protected code at any time.
- Before entering a code block modified by
synchronized, a thread automatically acquires a lock corresponding to theReentrantMutexinstance. If failing to acquire the lock, the current thread is blocked. - Before exiting the code block modified by
synchronized(including use of control transfer expressions such asbreak,continue,return, andthrowin the code block), a thread automatically releases the lock of theReentrantMutexinstance.
Example:
Before entering the synchronized code block, the thread of each for loop automatically acquires a lock corresponding to the mtx instance. Before exiting the code block, the thread releases the lock corresponding to the mtx instance.
import std.sync.{ReentrantMutex, sleep}
import std.time.Duration
main () {
let mtx = ReentrantMutex()
let cnt = Box<Int64>(0)
for (_ in 0..10) {
spawn {
synchronized(mtx) {
cnt.value ++
println("count: ${cnt.value}")
}
}
}
sleep(Duration.second)
0
}
API List
Constant & Variable
| Name | Description |
|---|---|
| DefaultMemoryOrder | Specifies the default memory order. For details, see MemoryOrder. |
Function
| Name | Description |
|---|---|
| sleep(Duration) | Hibernates the current thread. |
Interface
| Name | Description |
|---|---|
| IReentrantMutex | Provides the reentrant mutex interface. |
Class
| Name | Description |
|---|---|
| AtomicBool | Provides functions related to atomic operations of the Bool type. |
| AtomicInt16 | Provides functions related to atomic operations of the Int16 type. |
| AtomicInt32 | Provides functions related to atomic operations of the Int32 type. |
| AtomicInt64 | Provides functions related to atomic operations of the Int64 type. |
| AtomicInt8 | Provides functions related to atomic operations of the Int8 type. |
| AtomicOptionReference | Provides functions related to atomic operations of the reference type. |
| AtomicReference | Provides functions related to atomic operations of the reference type. |
| AtomicUInt16 | Provides functions related to atomic operations of the UInt16 type. |
| AtomicUInt32 | Provides functions related to atomic operations of the UInt32 type. |
| AtomicUInt64 | Provides functions related to atomic operations of the UInt64 type. |
| AtomicUInt8 | Provides functions related to atomic operations of the UInt8 type. |
| Barrier | Coordinates multiple threads to stop at a point of a program. |
| Monitor | Blocks a thread and waits for a signal from another thread to resume. |
| MultiConditionMonitor | Binds multiple condition variables to a mutex. |
| ReentrantMutex | Provides functionality related to the reentrant lock. |
| ReentrantReadMutex | Provides the read lock type in the reentrant read/write lock. |
| ReentrantReadWriteMutex | Provides functionality related to the reentrant read/write lock. |
| ReentrantWriteMutex | Provides the write lock type in the reentrant read/write lock. |
| Semaphore | Provides semaphore-related functionality. |
| SyncCounter | Provides the countdown counter functionality. |
| Timer | Provides the timer functionality. |
Enumeration
| Type | Description |
|---|---|
| MemoryOrder | Enumerates memory order types. |
| ReadWriteMutexMode | Enumerates the read/write lock fairness modes. |
| CatchupStyle | Enumerates the catch-up policies used by a repetitive task timer. |
Struct
| Name | Description |
|---|---|
| ConditionID | Specifies the condition variable of a mutex. For details, see MultiConditionMonitor. |
Exception Class
| Name | Description |
|---|---|
| IllegalSynchronizationStateException | Indicates an invalid synchronization state. |
Constant & Variable
let DefaultMemoryOrder
public let DefaultMemoryOrder: MemoryOrder = MemoryOrder.SeqCst
Description: Specifies the default memory order. For details, see MemoryOrder.
Type: MemoryOrder
Function
func sleep(Duration)
public func sleep(dur: Duration): Unit
Description: Hibernates the current thread.
If the value of dur is less than or equal to Duration.Zero, execution of the current thread is suspended.
Parameters:
- dur: Duration: sleep duration of a thread
Interface
interface IReentrantMutex
public interface IReentrantMutex
Description: Provides an interface for implementing reentrant mutex.
Note:
When implementing this interface, you must ensure that the underlying mutex supports nested locks. Otherwise, a deadlock occurs during nesting.
func lock()
func lock(): Unit
Description: Locks a mutex.
If a mutex is locked, the current thread is blocked.
func tryLock()
func tryLock(): Bool
Description: Tries to lock a mutex.
Returns:
- Bool: If a mutex is already locked, false is returned. Otherwise, the mutex is locked and true is returned.
func unlock()
func unlock(): Unit
Description: Unlocks a mutex.
If a mutex is repeatedly locked for N times, this function needs to be called for N times to unlock the mutex. Once the mutex is completely unlocked, if other threads are blocked on the mutex, one of the threads is awakened.
Throws:
- IllegalSynchronizationStateException: If the current thread does not hold the mutex, this exception is thrown.
Class
class AtomicBool
public class AtomicBool
Description: Provides functions related to atomic operations of the Bool class.
init(Bool)
public init(val: Bool)
Description: Constructs an instance of the atomic type AtomicBool that encapsulates the Bool data type. The initial value of the internal data for the instance is the value of the input parameter val.
Parameters:
- val: Bool: initial value of the atomic type
func compareAndSwap(Bool, Bool)
public func compareAndSwap(old: Bool, new: Bool): Bool
Description: Performs a Compare and Swap (CAS) operation using default memory ordering.
The value of the atomic type and the value specified by the old parameter are compared for equality. If they are equal, the value specified by the new parameter is written and true is returned. Otherwise, no value is written and false is returned.
Parameters:
- old: Bool: value to be compared with the atomic type instance
- new: Bool: value to be written to the atomic type when the two values are equal
Returns:
- Bool: If the swap is successful after comparison,
trueis returned. Otherwise,falseis returned.
func compareAndSwap(Bool, Bool, MemoryOrder, MemoryOrder)
public func compareAndSwap(old: Bool, new: Bool, successOrder!: MemoryOrder, failureOrder!: MemoryOrder): Bool
Description: Performs a CAS operation using the memory ordering specified by successOrder used upon success and the memory ordering specified by failureOrder used upon failure.
The value of the atomic type and the value specified by the old parameter are compared for equality. If they are equal, the value specified by the new parameter is written and true is returned. Otherwise, no value is written and false is returned.
Parameters:
- old: Bool: value to be compared with the atomic type instance
- new: Bool: value to be written to the atomic type when the two values are equal
- successOrder!: MemoryOrder: When the CAS operation is successful, the memory ordering required for the read > modify > write operation is executed.
- failureOrder!: MemoryOrder: When the CAS operation fails, the memory ordering required for the read operation is executed.
Returns:
- Bool: If the swap is successful after comparison,
trueis returned. Otherwise,falseis returned.
func load()
public func load(): Bool
Description: Reads the value of an atomic type using the default memory ordering.
Returns:
- Bool: value of the atomic type
func load(MemoryOrder)
public func load(memoryOrder!: MemoryOrder): Bool
Description: Reads the value of an atomic type using the memory ordering specified by the memoryOrder parameter.
Parameters:
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Bool: value of the atomic type
func store(Bool)
public func store(val: Bool): Unit
Description: Writes the value specified by the val parameter to an atomic type using the default memory ordering.
Parameters:
- val: Bool: value to be written to an atomic type
func store(Bool, MemoryOrder)
public func store(val: Bool, memoryOrder!: MemoryOrder): Unit
Description: Writes the value specified by the val parameter to an atomic type using the memory ordering specified by the memoryOrder parameter.
Parameters:
- val: Bool: value to be written to an atomic type
- memoryOrder!: MemoryOrder: memory ordering of the current operation
func swap(Bool)
public func swap(val: Bool): Bool
Description: Performs a swap operation using the default memory ordering to write the value specified by the val parameter to an atomic type, and returns the value before the writing.
Parameters:
- val: Bool: value to be written to an atomic type
Returns:
- Bool: value before writing
func swap(Bool, MemoryOrder)
public func swap(val: Bool, memoryOrder!: MemoryOrder): Bool
Description: Performs a swap operation using the memory ordering specified by the memoryOrder parameter to write the value specified by the val parameter to an atomic type, and returns the value before writing.
Parameters:
- val: Bool: value to be written to an atomic type
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Bool: value before writing
class AtomicInt16
public class AtomicInt16
Description: Provides functions related to atomic operations of the Int16 class.
init(Int16)
public init(val: Int16)
Description: Constructs an instance of the atomic type AtomicInt16 that encapsulates the data type Int16. The initial value of the internal data for the instance is the value of the input parameter val.
Parameters:
- val: Int16: initial value of the atomic type
func compareAndSwap(Int16, Int16)
public func compareAndSwap(old: Int16, new: Int16): Bool
Description: Performs a CAS operation using the default memory ordering.
The value of the atomic type and the value specified by the old parameter are compared for equality. If they are equal, the value specified by the new parameter is written and true is returned. Otherwise, no value is written and false is returned.
Parameters:
- old: Int16: value to be compared with the atomic type instance
- new: Int16: value to be written to the atomic type when the two values are equal
Returns:
- Bool: If the swap is successful after comparison,
trueis returned. Otherwise,falseis returned.
func compareAndSwap(Int16, Int16, MemoryOrder, MemoryOrder)
public func compareAndSwap(old: Int16, new: Int16, successOrder!: MemoryOrder, failureOrder!: MemoryOrder): Bool
Description: Performs a CAS operation using the memory ordering specified by successOrder used upon success and the memory ordering specified by failureOrder used upon failure.
The value of the atomic type and the value specified by the old parameter are compared for equality. If they are equal, the value specified by the new parameter is written and true is returned. Otherwise, no value is written and false is returned.
Parameters:
- old: Int16: value to be compared with the atomic type instance
- new: Int16: value to be written to the atomic type when the two values are equal
- successOrder!: MemoryOrder: When the CAS operation is successful, the memory ordering required for the read > modify > write operation is executed.
- failureOrder!: MemoryOrder: When the CAS operation fails, the memory ordering required for the read operation is executed.
Returns:
- Bool: If the swap is successful after comparison,
trueis returned. Otherwise,falseis returned.
func fetchAdd(Int16)
public func fetchAdd(val: Int16): Int16
Description: Adds the value of an atomic type to the val parameter using the default memory ordering, writes the result to the atomic type instance, and returns the value before the addition.
Parameters:
- val: Int16: value to be added to the atomic type instance
Returns:
- Int16: value before the addition
func fetchAdd(Int16, MemoryOrder)
public func fetchAdd(val: Int16, memoryOrder!: MemoryOrder): Int16
Description: Adds the value of an atomic type to the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the atomic type instance, and returns the value before the addition.
Parameters:
- val: Int16: value to be added to the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Int16: value before the addition
func fetchAnd(Int16)
public func fetchAnd(val: Int16): Int16
Description: Performs an AND operation on the value of the current atomic type instance and the val parameter using the default memory ordering, writes the result to the current atomic type instance, and returns the value before the AND operation.
Parameters:
- val: Int16: value to be ANDed with the atomic type instance
Returns:
- Int16: value before the AND operation
func fetchAnd(Int16, MemoryOrder)
public func fetchAnd(val: Int16, memoryOrder!: MemoryOrder): Int16
Description: Performs an AND operation on the value of the current atomic type instance and the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the current atomic type instance, and returns the value before the AND operation.
Parameters:
- val: Int16: value to be ANDed with the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Int16: value before the AND operation
func fetchOr(Int16)
public func fetchOr(val: Int16): Int16
Description: Performs an OR operation on the value of the current atomic type instance and the val parameter using the default memory ordering, writes the result to the current atomic type instance, and returns the value before the OR operation.
Parameters:
- val: Int16: value to be ORed with the atomic type instance
Returns:
- Int16: value before the OR operation
func fetchOr(Int16, MemoryOrder)
public func fetchOr(val: Int16, memoryOrder!: MemoryOrder): Int16
Description: Performs an OR operation on the value of the current atomic type instance and the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the current atomic type instance, and returns the value before the OR operation.
Parameters:
- val: Int16: value to be ORed with the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Int16: value before the OR operation
func fetchSub(Int16)
public func fetchSub(val: Int16): Int16
Description: Uses the value of an atomic type as the minuend and the val parameter as the subtrahend to perform subtraction using the default memory ordering, writes the result to the current atomic type instance, and returns the value before the subtraction.
Parameters:
- val: Int16: value to be subtracted from the atomic type instance
Returns:
- Int16: value before the subtraction
func fetchSub(Int16, MemoryOrder)
public func fetchSub(val: Int16, memoryOrder!: MemoryOrder): Int16
Description: Uses the value of an atomic type as the minuend and the val parameter as the subtrahend to perform subtraction using the memory ordering specified by the memoryOrder parameter, writes the result to the current atomic type instance, and returns the value before the subtraction.
Parameters:
- val: Int16: value to be subtracted from the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Int16: value before the subtraction
func fetchXor(Int16)
public func fetchXor(val: Int16): Int16
Description: Performs an XOR operation on the value of the current atomic type instance and the val parameter using the default memory ordering, writes the result to the current atomic type instance, and returns the value before the XOR operation.
Parameters:
- val: Int16: value to be XORed with the atomic type instance
Returns:
- Int16: value before the XOR operation
func fetchXor(Int16, MemoryOrder)
public func fetchXor(val: Int16, memoryOrder!: MemoryOrder): Int16
Description: Performs an XOR operation on the value of the current atomic type instance and the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the current atomic type instance, and returns the value before the XOR operation.
Parameters:
- val: Int16: value to be XORed with the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Int16: value before the XOR operation
func load()
public func load(): Int16
Description: Reads the value of an atomic type using the default memory ordering.
Returns:
- Int16: value of the atomic type
func load(MemoryOrder)
public func load(memoryOrder!: MemoryOrder): Int16
Description: Reads the value of an atomic type with the memory ordering specified by the memoryOrder parameter.
Parameters:
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Int16: value of the atomic type
func store(Int16)
public func store(val: Int16): Unit
Description: Writes the value specified by the val parameter to an atomic type using the default memory ordering.
Parameters:
- val: Int16: value to be written to an atomic type
func store(Int16, MemoryOrder)
public func store(val: Int16, memoryOrder!: MemoryOrder): Unit
Description: Writes the value specified by the val parameter to an atomic type using the memory ordering specified by the memoryOrder parameter.
Parameters:
- val: Int16: value to be written to an atomic type
- memoryOrder!: MemoryOrder: memory ordering of the current operation
func swap(Int16)
public func swap(val: Int16): Int16
Description: Performs a swap operation to write the value specified by the val parameter to an atomic type using the default memory ordering, and returns the value before the writing.
Parameters:
- val: Int16: value to be written to an atomic type
Returns:
- Int16: value before writing
func swap(Int16, MemoryOrder)
public func swap(val: Int16, memoryOrder!: MemoryOrder): Int16
Description: Performs a swap operation to write the value specified by the val parameter to an atomic type using the memory ordering specified by the memoryOrder parameter, and returns the value before the writing.
Parameters:
- val: Int16: value to be written to an atomic type
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Int16: value before writing
class AtomicInt32
public class AtomicInt32
Description: Provides functions related to atomic operations of the Int32 class.
init(Int32)
public init(val: Int32)
Description: Constructs an instance of the atomic type AtomicInt32 that encapsulates the data type Int32. The initial value of the internal data for the instance is the value of the input parameter val.
Parameters:
- val: Int32: initial value of the atomic type
func compareAndSwap(Int32, Int32)
public func compareAndSwap(old: Int32, new: Int32): Bool
Description: Performs a CAS operation using the default memory ordering.
The value of the atomic type and the value specified by the old parameter are compared for equality. If they are equal, the value specified by the new parameter is written and true is returned. Otherwise, no value is written and false is returned.
Parameters:
- old: Int32: value to be compared with the atomic type instance
- new: Int32: value to be written to the atomic type when the two values are equal
Returns:
- Bool: If the swap is successful after comparison,
trueis returned. Otherwise,falseis returned.
func compareAndSwap(Int32, Int32, MemoryOrDer, MemoryOrder)
public func compareAndSwap(old: Int32, new: Int32, successOrder!: MemoryOrder, failureOrder!: MemoryOrder): Bool
Description: Performs a CAS operation using the memory ordering specified by successOrder used upon success and the memory ordering specified by failureOrder used upon failure.
The value of the atomic type and the value specified by the old parameter are compared for equality. If they are equal, the value specified by the new parameter is written and true is returned. Otherwise, no value is written and false is returned.
Parameters:
- old: Int32: value to be compared with the atomic type instance
- new: Int32: value to be written to the atomic type when the two values are equal
- successOrder!: MemoryOrder: When the CAS operation is successful, the memory ordering required for the read > modify > write operation is executed.
- failureOrder!: MemoryOrder: When the CAS operation fails, the memory ordering required for the read operation is executed.
Returns:
- Bool: If the swap is successful after comparison,
trueis returned. Otherwise,falseis returned.
func fetchAdd(Int32)
public func fetchAdd(val: Int32): Int32
Description: Adds the value of an atomic type to the val parameter using the default memory ordering, writes the result to the atomic type instance, and returns the value before the addition.
Parameters:
- val: Int32: value to be added to the atomic type instance
Returns:
- Int32: value before the addition
func fetchAdd(Int32, MemoryOrder)
public func fetchAdd(val: Int32, memoryOrder!: MemoryOrder): Int32
Description: Adds the value of an atomic type to the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the atomic type instance, and returns the value before the addition.
Parameters:
- val: Int32: value to be added to the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Int32: value before the addition
func fetchAnd(Int32)
public func fetchAnd(val: Int32): Int32
Description: Performs an AND operation on the value of the current atomic type instance and the val parameter using the default memory ordering, writes the result to the current atomic type instance, and returns the value before the AND operation.
Parameters:
- val: Int32: value to be ANDed with the atomic type instance
Returns:
- Int32: value before the AND operation
func fetchAnd(Int32, MemoryOrder)
public func fetchAnd(val: Int32, memoryOrder!: MemoryOrder): Int32
Description: Performs an AND operation on the value of the current atomic type instance and the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the current atomic type instance, and returns the value before the AND operation.
Parameters:
- val: Int32: value to be ANDed with the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Int32: value before the AND operation
func fetchOr(Int32)
public func fetchOr(val: Int32): Int32
Description: Performs an OR operation on the value of the current atomic type instance and the val parameter using the default memory ordering, writes the result to the current atomic type instance, and returns the value before the OR operation.
Parameters:
- val: Int32: value to be ORed with the atomic type instance
Returns:
- Int32: value before the OR operation
func fetchOr(Int32, MemoryOrder)
public func fetchOr(val: Int32, memoryOrder!: MemoryOrder): Int32
Description: Performs an OR operation on the value of the current atomic type instance and the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the current atomic type instance, and returns the value before the OR operation.
Parameters:
- val: Int32: value to be ORed with the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Int32: value before the OR operation
func fetchSub(Int32)
public func fetchSub(val: Int32): Int32
Description: Uses the value of an atomic type as the minuend and the val parameter as the subtrahend to perform subtraction using the default memory ordering, writes the result to the current atomic type instance, and returns the value before the subtraction.
Parameters:
- val: Int32: value to be subtracted from the atomic type instance
Returns:
- Int32: value before the subtraction
func fetchSub(Int32, MemoryOrder)
public func fetchSub(val: Int32, memoryOrder!: MemoryOrder): Int32
Description: Uses the value of an atomic type as the minuend and the val parameter as the subtrahend to perform subtraction using the memory ordering specified by the memoryOrder parameter, writes the result to the current atomic type instance, and returns the value before the subtraction.
Parameters:
- val: Int32: value to be subtracted from the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Int32: value before the subtraction
func fetchXor(Int32)
public func fetchXor(val: Int32): Int32
Description: Performs an XOR operation on the value of the current atomic type instance and the val parameter using the default memory ordering, writes the result to the current atomic type instance, and returns the value before the XOR operation.
Parameters:
- val: Int32: value to be XORed with the atomic type instance
Returns:
- Int32: value before the XOR operation
func fetchXor(Int32, MemoryOrder)
public func fetchXor(val: Int32, memoryOrder!: MemoryOrder): Int32
Description: Performs an XOR operation on the value of the current atomic type instance and the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the current atomic type instance, and returns the value before the XOR operation.
Parameters:
- val: Int32: value to be XORed with the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Int32: value before the XOR operation
func load()
public func load(): Int32
Description: Reads the value of an atomic type using the default memory ordering.
Returns:
- Int32: value of the atomic type
func load(MemoryOrder)
public func load(memoryOrder!: MemoryOrder): Int32
Description: Reads the value of an atomic type with the memory ordering specified by the memoryOrder parameter.
Parameters:
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Int32: value of the atomic type
func store(Int32)
public func store(val: Int32): Unit
Description: Writes the value specified by the val parameter to an atomic type using the default memory ordering.
Parameters:
- val: Int32: value to be written to an atomic type
func store(Int32, MemoryOrder)
public func store(val: Int32, memoryOrder!: MemoryOrder): Unit
Description: Writes the value specified by the val parameter to an atomic type using the memory ordering specified by the memoryOrder parameter.
Parameters:
- val: Int32: value to be written to an atomic type
- memoryOrder!: MemoryOrder: memory ordering of the current operation
func swap(Int32)
public func swap(val: Int32): Int32
Description: Performs a swap operation to write the value specified by the val parameter to an atomic type using the default memory ordering, and returns the value before the writing.
Parameters:
- val: Int32: value to be written to an atomic type
Returns:
- Int32: value before writing
func swap(Int32, MemoryOrder)
public func swap(val: Int32, memoryOrder!: MemoryOrder): Int32
Description: Performs a swap operation to write the value specified by the val parameter to an atomic type using the memory ordering specified by the memoryOrder parameter, and returns the value before the writing.
Parameters:
- val: Int32: value to be written to an atomic type
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Int32: value before writing
class AtomicInt64
public class AtomicInt64
Description: Provides functions related to atomic operations of the Int64 class.
init(Int64)
public init(val: Int64)
Description: Constructs an instance of the atomic type AtomicInt64 that encapsulates the data type Int64. The initial value of the internal data for the instance is the value of the input parameter val.
Parameters:
- val: Int64: initial value of the atomic type
func compareAndSwap(Int64, Int64)
public func compareAndSwap(old: Int64, new: Int64): Bool
Description: Performs a CAS operation using the default memory ordering.
The value of the atomic type and the value specified by the old parameter are compared for equality. If they are equal, the value specified by the new parameter is written and true is returned. Otherwise, no value is written and false is returned.
Parameters:
- old: Int64: value to be compared with the atomic type instance
- new: Int64: value to be written to the atomic type when the two values are equal
Returns:
- Bool: If the swap is successful after comparison,
trueis returned. Otherwise,falseis returned.
func compareAndSwap(Int64, Int64, MemoryOrder, MemoryOrder)
public func compareAndSwap(old: Int64, new: Int64, successOrder!: MemoryOrder, failureOrder!: MemoryOrder): Bool
Description: Performs a CAS operation using the memory ordering specified by successOrder used upon success and the memory ordering specified by failureOrder used upon failure.
The value of the atomic type and the value specified by the old parameter are compared for equality. If they are equal, the value specified by the new parameter is written and true is returned. Otherwise, no value is written and false is returned.
Parameters:
- old: Int64: value to be compared with the atomic type instance
- new: Int64: value to be written to the atomic type when the two values are equal
- successOrder!: MemoryOrder: When the CAS operation is successful, the memory ordering required for the read > modify > write operation is executed.
- failureOrder!: MemoryOrder: When the CAS operation fails, the memory ordering required for the read operation is executed.
Returns:
- Bool: If the swap is successful after comparison,
trueis returned. Otherwise,falseis returned.
func fetchAdd(Int64)
public func fetchAdd(val: Int64): Int64
Description: Adds the value of an atomic type to the val parameter using the default memory ordering, writes the result to the atomic type instance, and returns the value before the addition.
Parameters:
- val: Int64: value to be added to the atomic type instance
Returns:
- Int64: value before the addition
func fetchAdd(Int64, MemoryOrder)
public func fetchAdd(val: Int64, memoryOrder!: MemoryOrder): Int64
Description: Adds the value of an atomic type to the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the atomic type instance, and returns the value before the addition.
Parameters:
- val: Int64: value to be added to the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Int64: value before the addition
func fetchAnd(Int64)
public func fetchAnd(val: Int64): Int64
Description: Performs an AND operation on the value of the current atomic type instance and the val parameter using the default memory ordering, writes the result to the current atomic type instance, and returns the value before the AND operation.
Parameters:
- val: Int64: value to be ANDed with the atomic type instance
Returns:
- Int64: value before the AND operation
func fetchAnd(Int64, MemoryOrder)
public func fetchAnd(val: Int64, memoryOrder!: MemoryOrder): Int64
Description: Performs an AND operation on the value of the current atomic type instance and the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the current atomic type instance, and returns the value before the AND operation.
Parameters:
- val: Int64: value to be ANDed with the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Int64: value before the AND operation
func fetchOr(Int64)
public func fetchOr(val: Int64): Int64
Description: Performs an OR operation on the value of the current atomic type instance and the val parameter using the default memory ordering, writes the result to the current atomic type instance, and returns the value before the OR operation.
Parameters:
- val: Int64: value to be ORed with the atomic type instance
Returns:
- Int64: value before the OR operation
func fetchOr(Int64, MemoryOrder)
public func fetchOr(val: Int64, memoryOrder!: MemoryOrder): Int64
Description: Performs an OR operation on the value of the current atomic type instance and the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the current atomic type instance, and returns the value before the OR operation.
Parameters:
- val: Int64: value to be ORed with the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Int64: value before the OR operation
func fetchSub(Int64)
public func fetchSub(val: Int64): Int64
Description: Uses the value of an atomic type as the minuend and the val parameter as the subtrahend to perform subtraction using the default memory ordering, writes the result to the current atomic type instance, and returns the value before the subtraction.
Parameters:
- val: Int64: value to be subtracted from the atomic type instance
Returns:
- Int64: value before the subtraction
func fetchSub(Int64, MemoryOrder)
public func fetchSub(val: Int64, memoryOrder!: MemoryOrder): Int64
Description: Uses the value of an atomic type as the minuend and the val parameter as the subtrahend to perform subtraction using the memory ordering specified by the memoryOrder parameter, writes the result to the current atomic type instance, and returns the value before the subtraction.
Parameters:
- val: Int64: value to be subtracted from the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Int64: value before the subtraction
func fetchXor(Int64)
public func fetchXor(val: Int64): Int64
Description: Performs an XOR operation on the value of the current atomic type instance and the val parameter using the default memory ordering, writes the result to the current atomic type instance, and returns the value before the XOR operation.
Parameters:
- val: Int64: value to be XORed with the atomic type instance
Returns:
- Int64: value before the XOR operation
func fetchXor(Int64, MemoryOrder)
public func fetchXor(val: Int64, memoryOrder!: MemoryOrder): Int64
Description: Performs an XOR operation on the value of the current atomic type instance and the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the current atomic type instance, and returns the value before the XOR operation.
Parameters:
- val: Int64: value to be XORed with the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Int64: value before the XOR operation
func load()
public func load(): Int64
Description: Reads the value of an atomic type using the default memory ordering.
Returns:
- Int64: value of the atomic type
func load(MemoryOrder)
public func load(memoryOrder!: MemoryOrder): Int64
Description: Reads the value of an atomic type with the memory ordering specified by the memoryOrder parameter.
Parameters:
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Int64: value of the atomic type
func store(Int64)
public func store(val: Int64): Unit
Description: Writes the value specified by the val parameter to an atomic type using the default memory ordering.
Parameters:
- val: Int64: value to be written to an atomic type
func store(Int64, MemoryOrder)
public func store(val: Int64, memoryOrder!: MemoryOrder): Unit
Description: Writes the value specified by the val parameter to an atomic type using the memory ordering specified by the memoryOrder parameter.
Parameters:
- val: Int64: value to be written to an atomic type
- memoryOrder!: MemoryOrder: memory ordering of the current operation
func swap(Int64)
public func swap(val: Int64): Int64
Description: Performs a swap operation to write the value specified by the val parameter to an atomic type using the default memory ordering, and returns the value before the writing.
Parameters:
- val: Int64: value to be written to an atomic type
Returns:
- Int64: value before writing
func swap(Int64, MemoryOrder)
public func swap(val: Int64, memoryOrder!: MemoryOrder): Int64
Description: Performs a swap operation to write the value specified by the val parameter to an atomic type using the memory ordering specified by the memoryOrder parameter, and returns the value before the writing.
Parameters:
- val: Int64: value to be written to an atomic type
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Int64: value before writing
class AtomicInt8
public class AtomicInt8
Description: Provides functions related to atomic operations of the Int8 class.
init(Int8)
public init(val: Int8)
Description: Constructs an instance of the atomic type AtomicInt8 that encapsulates the data type Int8. The initial value of the internal data for the instance is the value of the input parameter val.
Parameters:
- val: Int8: initial value of the atomic type
func compareAndSwap(Int8, Int8)
public func compareAndSwap(old: Int8, new: Int8): Bool
Description: Performs a CAS operation using the default memory ordering.
The value of the atomic type and the value specified by the old parameter are compared for equality. If they are equal, the value specified by the new parameter is written and true is returned. Otherwise, no value is written and false is returned.
Parameters:
- old: Int8: value to be compared with the atomic type instance
- new: Int8: value to be written to the atomic type when the two values are equal
Returns:
- Bool: If the swap is successful after comparison,
trueis returned. Otherwise,falseis returned.
func compareAndSwap(Int8, Int8, MemoryOrder, MemoryOrder)
public func compareAndSwap(old: Int8, new: Int8, successOrder!: MemoryOrder, failureOrder!: MemoryOrder): Bool
Description: Performs a CAS operation using the memory ordering specified by successOrder used upon success and the memory ordering specified by failureOrder used upon failure.
The value of the atomic type and the value specified by the old parameter are compared for equality. If they are equal, the value specified by the new parameter is written and true is returned. Otherwise, no value is written and false is returned.
Parameters:
- old: Int8: value to be compared with the atomic type instance
- new: Int8: value to be written to the atomic type when the two values are equal
- successOrder!: MemoryOrder: When the CAS operation is successful, the memory ordering required for the read > modify > write operation is executed.
- failureOrder!: MemoryOrder: When the CAS operation fails, the memory ordering required for the read operation is executed.
Returns:
- Bool: If the swap is successful after comparison,
trueis returned. Otherwise,falseis returned.
func fetchAdd(Int8)
public func fetchAdd(val: Int8): Int8
Description: Adds the value of an atomic type to the val parameter using the default memory ordering, writes the result to the atomic type instance, and returns the value before the addition.
Parameters:
- val: Int8: value to be added to the atomic type instance
Returns:
- Int8: value before the addition
func fetchAdd(Int8, MemoryOrder)
public func fetchAdd(val: Int8, memoryOrder!: MemoryOrder): Int8
Description: Adds the value of an atomic type to the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the atomic type instance, and returns the value before the addition.
Parameters:
- val: Int8: value to be added to the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Int8: value before the addition
func fetchAnd(Int8)
public func fetchAnd(val: Int8): Int8
Description: Performs an AND operation on the value of the current atomic type instance and the val parameter using the default memory ordering, writes the result to the current atomic type instance, and returns the value before the AND operation.
Parameters:
- val: Int8: value to be ANDed with the atomic type instance
Returns:
- Int8: value before the AND operation
func fetchAnd(Int8, MemoryOrder)
public func fetchAnd(val: Int8, memoryOrder!: MemoryOrder): Int8
Description: Performs an AND operation on the value of the current atomic type instance and the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the current atomic type instance, and returns the value before the AND operation.
Parameters:
- val: Int8: value to be ANDed with the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Int8: value before the AND operation
func fetchOr(Int8)
public func fetchOr(val: Int8): Int8
Description: Performs an OR operation on the value of the current atomic type instance and the val parameter using the default memory ordering, writes the result to the atomic type instance, and returns the value before the OR operation.
Parameters:
- val: Int8: value to be ORed with the atomic type instance
Returns:
- Int8: value before the OR operation
func fetchOr(Int8, MemoryOrder)
public func fetchOr(val: Int8, memoryOrder!: MemoryOrder): Int8
Description: Performs an OR operation on the value of the atomic type instance and the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the atomic type instance, and returns the value before the OR operation.
Parameters:
- val: Int8: value to be ORed with the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Int8: value before the OR operation
func fetchSub(Int8)
public func fetchSub(val: Int8): Int8
Description: Uses the value of an atomic type as the minuend and the val parameter as the subtrahend to perform subtraction using the default memory ordering, writes the result to the current atomic type instance, and returns the value before the subtraction.
Parameters:
- val: Int8: value to be subtracted from the atomic type instance
Returns:
- Int8: value before the subtraction
func fetchSub(Int8, MemoryOrder)
public func fetchSub(val: Int8, memoryOrder!: MemoryOrder): Int8
Description: Uses the value of an atomic type as the minuend and the val parameter as the subtrahend to perform subtraction using the memory ordering specified by the memoryOrder parameter, writes the result to the current atomic type instance, and returns the value before the subtraction.
Parameters:
- val: Int8: value to be subtracted from the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Int8: value before the subtraction
func fetchXor(Int8)
public func fetchXor(val: Int8): Int8
Description: Performs an XOR operation on the value of the current atomic type instance and the val parameter using the default memory ordering, writes the result to the current atomic type instance, and returns the value before the XOR operation.
Parameters:
- val: Int8: value to be XORed with the atomic type instance
Returns:
- Int8: value before the XOR operation
func fetchXor(Int8, MemoryOrder)
public func fetchXor(val: Int8, memoryOrder!: MemoryOrder): Int8
Description: Performs an XOR operation on the value of the current atomic type instance and the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the current atomic type instance, and returns the value before the XOR operation.
Parameters:
- val: Int8: value to be XORed with the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Int8: value before the XOR operation
func load()
public func load(): Int8
Description: Reads the value of an atomic type using the default memory ordering.
Returns:
- Int8: value of the atomic type
func load(MemoryOrder)
public func load(memoryOrder!: MemoryOrder): Int8
Description: Reads the value of an atomic type using the memory ordering specified by the memoryOrder parameter.
Parameters:
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Int8: value of the atomic type
func store(Int8)
public func store(val: Int8): Unit
Description: Writes the value specified by the val parameter to an atomic type using the default memory ordering.
Parameters:
- val: Int8: value to be written to an atomic type
func store(Int8, MemoryOrder)
public func store(val: Int8, memoryOrder!: MemoryOrder): Unit
Description: Writes the value specified by the val parameter to an atomic type using the memory ordering specified by the memoryOrder parameter.
Parameters:
- val: Int8: value to be written to an atomic type
- memoryOrder!: MemoryOrder: memory ordering of the current operation
func swap(Int8)
public func swap(val: Int8): Int8
Description: Performs a swap operation to write the value specified by the val parameter to an atomic type using the default memory ordering, and returns the value before the writing.
Parameters:
- val: Int8: value to be written to an atomic type
Returns:
- Int8: value before writing
func swap(Int8, MemoryOrder)
public func swap(val: Int8, memoryOrder!: MemoryOrder): Int8
Description: Performs a swap operation to write the value specified by the val parameter to an atomic type using the memory ordering specified by the memoryOrder parameter, and returns the value before the writing.
Parameters:
- val: Int8: value to be written to an atomic type
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Int8: value before writing
class AtomicOptionReference
public class AtomicOptionReference<T> where T <: Object
Description: Provides functions related to atomic operations of a reference class.
The reference class must be a subclass of Object.
init()
public init()
Description: Constructs an empty AtomicOptionReference instance.
init(Option<T>)
public init(val: Option<T>)
Description: Constructs an instance of the atomic type AtomicOptionReference that encapsulates the data type Option<T>. The initial value of the internal data for the instance is the value of the input parameter val.
Parameters:
- val: Option<T>: initial value of the atomic type
func compareAndSwap(Option<T>, Option<T>)
public func compareAndSwap(old: Option<T>, new: Option<T>): Bool
Description: Performs a CAS operation using the default memory ordering.
The value of the atomic type and the value specified by the old parameter are compared for equality. If they are equal, the value specified by the new parameter is written and true is returned. Otherwise, no value is written and false is returned.
Parameters:
- old: Option<T>: value to be compared with the atomic type instance
- new: Option<T>: value to be written to the atomic type when the two values are equal
Returns:
- Bool: If the swap is successful after comparison,
trueis returned. Otherwise,falseis returned.
func compareAndSwap(Option<T>, Option<T>, MemoryOrder, MemoryOrder)
public func compareAndSwap(old: Option<T>, new: Option<T>, successOrder!: MemoryOrder, failureOrder!: MemoryOrder): Bool
Description: Performs a CAS operation using the memory ordering specified by successOrder used upon success and the memory ordering specified by failureOrder used upon failure.
The value of the atomic type and the value specified by the old parameter are compared for equality. If they are equal, the value specified by the new parameter is written and true is returned. Otherwise, no value is written and false is returned.
Parameters:
- old: Option<T>: value to be compared with the atomic type instance
- new: Option<T>: value to be written to the atomic type when the two values are equal
- successOrder!: MemoryOrder: When the CAS operation is successful, the memory ordering required for the read > modify > write operation is executed.
- failureOrder!: MemoryOrder: When the CAS operation fails, the memory ordering required for the read operation is executed.
Returns:
- Bool: If the swap is successful after comparison,
trueis returned. Otherwise,falseis returned.
func load()
public func load(): Option<T>
Description: Reads the value of an atomic type using the default memory ordering.
Returns:
- Option<T>: value of the atomic type
func load(MemoryOrder)
public func load(memoryOrder!: MemoryOrder): Option<T>
Description: Reads the value of an atomic type using the memory ordering specified by the memoryOrder parameter.
Parameters:
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Option<T>: value of the atomic type
func store(Option<T>)
public func store(val: Option<T>): Unit
Description: Writes the value specified by the val parameter to an atomic type using the default memory ordering.
Parameters:
- val: Option<T>: value to be written to an atomic type
func store(Option<T>, MemoryOrder)
public func store(val: Option<T>, memoryOrder!: MemoryOrder): Unit
Description: Writes the value specified by the val parameter to an atomic type using the memory ordering specified by the memoryOrder parameter.
Parameters:
- val: Option<T>: value to be written to an atomic type
- memoryOrder!: MemoryOrder: memory ordering of the current operation
func swap(Option<T>)
public func swap(val: Option<T>): Option<T>
Description: Performs a swap operation to write the value specified by the val parameter to an atomic type using the default memory ordering, and returns the value before the writing.
Parameters:
- val: Option<T>: value to be written to an atomic type
Returns:
- Option<T>: value before writing
func swap(Option<T>, MemoryOrder)
public func swap(val: Option<T>, memoryOrder!: MemoryOrder): Option<T>
Description: Performs a swap operation to write the value specified by the val parameter to an atomic type using the memory ordering specified by the memoryOrder parameter, and returns the value before the writing.
Parameters:
- val: Option<T>: value to be written to an atomic type
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- Option<T>: value before writing
class AtomicReference
public class AtomicReference<T> where T <: Object
Description: Provides functions related to atomic operations of a reference class.
The reference class must be a subclass of Object.
init(T)
public init(val: T)
Description: Constructs an instance of the atomic type AtomicReference that encapsulates the data type T. The initial value of the internal data for the instance is the value of the input parameter val.
Parameters:
- val: T: initial value of the atomic type
func compareAndSwap(T, T)
public func compareAndSwap(old: T, new: T): Bool
Description: Performs a CAS operation using the default memory ordering.
The value of the atomic type and the value specified by the old parameter are compared for equality. If they are equal, the value specified by the new parameter is written and true is returned. Otherwise, no value is written and false is returned.
Parameters:
- old: T: value to be compared with the atomic type instance
- new: T: value to be written to the atomic type when the two values are equal
Returns:
- Bool: If the swap is successful after comparison,
trueis returned. Otherwise,falseis returned.
func compareAndSwap(T, T, MemoryOrder, MemoryOrder)
public func compareAndSwap(old: T, new: T, successOrder!: MemoryOrder, failureOrder!: MemoryOrder): Bool
Description: Performs a CAS operation using the memory ordering specified by successOrder used upon success and the memory ordering specified by failureOrder used upon failure.
The value of the atomic type and the value specified by the old parameter are compared for equality. If they are equal, the value specified by the new parameter is written and true is returned. Otherwise, no value is written and false is returned.
Parameters:
- old: T: value to be compared with the atomic type instance
- new: T: value to be written to the atomic type when the two values are equal
- successOrder!: MemoryOrder: When the CAS operation is successful, the memory ordering required for the read > modify > write operation is executed.
- failureOrder!: MemoryOrder: When the CAS operation fails, the memory ordering required for the read operation is executed.
Returns:
- Bool: If the swap is successful after comparison,
trueis returned. Otherwise,falseis returned.
func load()
public func load(): T
Description: Reads the value of an atomic type using the default memory ordering.
Returns:
- T: value of the atomic type
func load(MemoryOrder)
public func load(memoryOrder!: MemoryOrder): T
Description: Reads the value of an atomic type using the memory ordering specified by the memoryOrder parameter.
Parameters:
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- T: value of the atomic type
func store(T)
public func store(val: T): Unit
Description: Writes the value specified by the val parameter to an atomic type using the default memory ordering.
Parameters:
- val: T: value to be written to an atomic type
func store(T, MemoryOrder)
public func store(val: T, memoryOrder!: MemoryOrder): Unit
Description: Writes the value specified by the val parameter to an atomic type using the memory ordering specified by the memoryOrder parameter.
Parameters:
- val: T: value to be written to an atomic type
- memoryOrder!: MemoryOrder: memory ordering of the current operation
func swap(T)
public func swap(val: T): T
Description: Performs a swap operation to write the value specified by the val parameter to an atomic type using the default memory ordering, and returns the value before the writing.
Parameters:
- val: T: value to be written to an atomic type
Returns:
- T: value before writing
func swap(T, MemoryOrder)
public func swap(val: T, memoryOrder!: MemoryOrder): T
Description: Performs a swap operation to write the value specified by the val parameter to an atomic type using the memory ordering specified by the memoryOrder parameter, and returns the value before the writing.
Parameters:
- val: T: value to be written to an atomic type
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- T: value before writing
class AtomicUInt16
public class AtomicUInt16
Description: Provides functions related to atomic operations of the UInt16 class.
init(UInt16)
public init(val: UInt16)
Description: Constructs an instance of the atomic type AtomicUInt16 that encapsulates the data type UInt16. The initial value of the internal data for the instance is the value of the input parameter val.
Parameters:
- val: UInt16: initial value of the atomic type
func compareAndSwap(UInt16, UInt16)
public func compareAndSwap(old: UInt16, new: UInt16): Bool
Description: Performs a CAS operation using the default memory ordering.
The value of the atomic type and the value specified by the old parameter are compared for equality. If they are equal, the value specified by the new parameter is written and true is returned. Otherwise, no value is written and false is returned.
Parameters:
- old: UInt16: value to be compared with the atomic type instance
- new: UInt16: value to be written to the atomic type when the two values are equal
Returns:
- Bool: If the swap is successful after comparison,
trueis returned. Otherwise,falseis returned.
func compareAndSwap(UInt16, UInt16, MemoryOrder, MemoryOrder)
public func compareAndSwap(old: UInt16, new: UInt16, successOrder!: MemoryOrder, failureOrder!: MemoryOrder): Bool
Description: Performs a CAS operation using the memory ordering specified by successOrder used upon success and the memory ordering specified by failureOrder used upon failure.
The value of the atomic type and the value specified by the old parameter are compared for equality. If they are equal, the value specified by the new parameter is written and true is returned. Otherwise, no value is written and false is returned.
Parameters:
- old: UInt16: value to be compared with the atomic type instance
- new: UInt16: value to be written to the atomic type when the two values are equal
- successOrder!: MemoryOrder: When the CAS operation is successful, the memory ordering required for the read > modify > write operation is executed.
- failureOrder!: MemoryOrder: When the CAS operation fails, the memory ordering required for the read operation is executed.
Returns:
- Bool: If the swap is successful after comparison,
trueis returned. Otherwise,falseis returned.
func fetchAdd(UInt16)
public func fetchAdd(val: UInt16): UInt16
Description: Adds the value of an atomic type to the val parameter using the default memory ordering, writes the result to the atomic type instance, and returns the value before the addition.
Parameters:
- val: UInt16: value to be added to the atomic type instance
Returns:
- UInt16: value before the addition
func fetchAdd(UInt16, MemoryOrder)
public func fetchAdd(val: UInt16, memoryOrder!: MemoryOrder): UInt16
Description: Adds the value of an atomic type to the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the atomic type instance, and returns the value before the addition.
Parameters:
- val: UInt16: value to be added to the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- UInt16: value before the addition
func fetchAnd(UInt16)
public func fetchAnd(val: UInt16): UInt16
Description: Performs an AND operation on the value of the current atomic type instance and the val parameter using the default memory ordering, writes the result to the current atomic type instance, and returns the value before the AND operation.
Parameters:
- val: UInt16: value to be ANDed with the atomic type instance
Returns:
- UInt16: value before the AND operation
func fetchAnd(UInt16, MemoryOrder)
public func fetchAnd(val: UInt16, memoryOrder!: MemoryOrder): UInt16
Description: Performs an AND operation on the value of the current atomic type instance and the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the current atomic type instance, and returns the value before the AND operation.
Parameters:
- val: UInt16: value to be ANDed with the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- UInt16: value before the AND operation
func fetchOr(UInt16)
public func fetchOr(val: UInt16): UInt16
Description: Performs an OR operation on the value of the current atomic type instance and the val parameter using the default memory ordering, writes the result to the current atomic type instance, and returns the value before the OR operation.
Parameters:
- val: UInt16: value to be ORed with the atomic type instance
Returns:
- UInt16: value before the OR operation
func fetchOr(UInt16, MemoryOrder)
public func fetchOr(val: UInt16, memoryOrder!: MemoryOrder): UInt16
Description: Performs an OR operation on the value of the current atomic type instance and the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the current atomic type instance, and returns the value before the OR operation.
Parameters:
- val: UInt16: value to be ORed with the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- UInt16: value before the OR operation
func fetchSub(UInt16)
public func fetchSub(val: UInt16): UInt16
Description: Uses the value of an atomic type as the minuend and the val parameter as the subtrahend to perform subtraction using the default memory ordering, writes the result to the current atomic type instance, and returns the value before the subtraction.
Parameters:
- val: UInt16: value to be subtracted from the atomic type instance
Returns:
- UInt16: value before the subtraction
func fetchSub(UInt16, MemoryOrder)
public func fetchSub(val: UInt16, memoryOrder!: MemoryOrder): UInt16
Description: Uses the value of an atomic type as the minuend and the val parameter as the subtrahend to perform subtraction using the memory ordering specified by the memoryOrder parameter, writes the result to the current atomic type instance, and returns the value before the subtraction.
Parameters:
- val: UInt16: value to be subtracted from the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- UInt16: value before the subtraction
func fetchXor(UInt16)
public func fetchXor(val: UInt16): UInt16
Description: Performs an XOR operation on the value of the current atomic type instance and the val parameter using the default memory ordering, writes the result to the current atomic type instance, and returns the value before the XOR operation.
Parameters:
- val: UInt16: value to be XORed with the atomic type instance
Returns:
- UInt16: value before the XOR operation
func fetchXor(UInt16, MemoryOrder)
public func fetchXor(val: UInt16, memoryOrder!: MemoryOrder): UInt16
Description: Performs an XOR operation on the value of the current atomic type instance and the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the current atomic type instance, and returns the value before the XOR operation.
Parameters:
- val: UInt16: value to be XORed with the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- UInt16: value before the XOR operation
func load()
public func load(): UInt16
Description: Reads the value of an atomic type using the default memory ordering.
Returns:
- UInt16: value of the atomic type
func load(MemoryOrder)
public func load(memoryOrder!: MemoryOrder): UInt16
Description: Reads the value of an atomic type using the memory ordering specified by the memoryOrder parameter.
Parameters:
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- UInt16: value of the atomic type
func store(UInt16)
public func store(val: UInt16): Unit
Description: Writes the value specified by the val parameter to an atomic type using the default memory ordering.
Parameters:
- val: UInt16: value to be written to an atomic type
func store(UInt16, MemoryOrder)
public func store(val: UInt16, memoryOrder!: MemoryOrder): Unit
Description: Writes the value specified by the val parameter to an atomic type using the memory ordering specified by the memoryOrder parameter.
Parameters:
- val: UInt16: value to be written to an atomic type
- memoryOrder!: MemoryOrder: memory ordering of the current operation
func swap(UInt16)
public func swap(val: UInt16): UInt16
Description: Performs a swap operation to write the value specified by the val parameter to an atomic type using the default memory ordering, and returns the value before the writing.
Parameters:
- val: UInt16: value to be written to an atomic type
Returns:
- UInt16: value before writing
func swap(UInt16, MemoryOrder)
public func swap(val: UInt16, memoryOrder!: MemoryOrder): UInt16
Description: Performs a swap operation to write the value specified by the val parameter to an atomic type using the memory ordering specified by the memoryOrder parameter, and returns the value before the writing.
Parameters:
- val: UInt16: value to be written to an atomic type
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- UInt16: value before writing
class AtomicUInt32
public class AtomicUInt32
Description: Provides functions related to atomic operations of the UInt32 class.
init(UInt32)
public init(val: UInt32)
Description: Constructs an instance of the atomic type AtomicUInt32 that encapsulates the data type UInt32. The initial value of the internal data for the instance is the value of the input parameter val.
Parameters:
- val: UInt32: initial value of the atomic type
func compareAndSwap(UInt32, UInt32)
public func compareAndSwap(old: UInt32, new: UInt32): Bool
Description: Performs a CAS operation using the default memory ordering.
The value of the atomic type and the value specified by the old parameter are compared for equality. If they are equal, the value specified by the new parameter is written and true is returned. Otherwise, no value is written and false is returned.
Parameters:
- old: UInt32: value to be compared with the atomic type instance
- new: UInt32: value to be written to the atomic type when the two values are equal
Returns:
- Bool: If the swap is successful after comparison,
trueis returned. Otherwise,falseis returned.
func compareAndSwap(UInt32, UInt32, MemoryOrder, MemoryOrder)
public func compareAndSwap(old: UInt32, new: UInt32, successOrder!: MemoryOrder, failureOrder!: MemoryOrder): Bool
Description: Performs a CAS operation using the memory ordering specified by successOrder used upon success and the memory ordering specified by failureOrder used upon failure.
The value of the atomic type and the value specified by the old parameter are compared for equality. If they are equal, the value specified by the new parameter is written and true is returned. Otherwise, no value is written and false is returned.
Parameters:
- old: UInt32: value to be compared with the atomic type instance
- new: UInt32: value to be written to the atomic type when the two values are equal
- successOrder!: MemoryOrder: When the CAS operation is successful, the memory ordering required for the read > modify > write operation is executed.
- failureOrder!: MemoryOrder: When the CAS operation fails, the memory ordering required for the read operation is executed.
Returns:
- Bool: If the swap is successful after comparison,
trueis returned. Otherwise,falseis returned.
func fetchAdd(UInt32)
public func fetchAdd(val: UInt32): UInt32
Description: Adds the value of an atomic type to the val parameter using the default memory ordering, writes the result to the atomic type instance, and returns the value before the addition.
Parameters:
- val: UInt32: value to be added to the atomic type instance
Returns:
- UInt32: value before the addition
func fetchAdd(UInt32, MemoryOrder)
public func fetchAdd(val: UInt32, memoryOrder!: MemoryOrder): UInt32
Description: Adds the value of an atomic type to the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the atomic type instance, and returns the value before the addition.
Parameters:
- val: UInt32: value to be added to the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- UInt32: value before the addition
func fetchAnd(UInt32)
public func fetchAnd(val: UInt32): UInt32
Description: Performs an AND operation on the value of the current atomic type instance and the val parameter using the default memory ordering, writes the result to the current atomic type instance, and returns the value before the AND operation.
Parameters:
- val: UInt32: value to be ANDed with the atomic type instance
Returns:
- UInt32: value before the AND operation
func fetchAnd(UInt32, MemoryOrder)
public func fetchAnd(val: UInt32, memoryOrder!: MemoryOrder): UInt32
Description: Performs an AND operation on the value of the current atomic type instance and the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the current atomic type instance, and returns the value before the AND operation.
Parameters:
- val: UInt32: value to be ANDed with the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- UInt32: value before the AND operation
func fetchOr(UInt32)
public func fetchOr(val: UInt32): UInt32
Description: Performs an OR operation on the value of the current atomic type instance and the val parameter with the default memory ordering, writes the result to the current atomic type instance, and returns the value before the OR operation.
Parameters:
- val: UInt32: value to be ORed with the atomic type instance
Returns:
- UInt32: value before the OR operation
func fetchOr(UInt32, MemoryOrder)
public func fetchOr(val: UInt32, memoryOrder!: MemoryOrder): UInt32
Description: Performs an OR operation on the value of the current atomic type instance and the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the current atomic type instance, and returns the value before the OR operation.
Parameters:
- val: UInt32: value to be ORed with the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- UInt32: value before the OR operation
func fetchSub(UInt32)
public func fetchSub(val: UInt32): UInt32
Description: Uses the value of an atomic type as the minuend and the val parameter as the subtrahend to perform subtraction using the default memory ordering, writes the result to the current atomic type instance, and returns the value before the subtraction.
Parameters:
- val: UInt32: value to be subtracted from the atomic type instance
Returns:
- UInt32: value before the subtraction
func fetchSub(UInt32, MemoryOrder)
public func fetchSub(val: UInt32, memoryOrder!: MemoryOrder): UInt32
Description: Uses the value of an atomic type as the minuend and the val parameter as the subtrahend to perform subtraction using the memory ordering specified by the memoryOrder parameter, writes the result to the current atomic type instance, and returns the value before the subtraction.
Parameters:
- val: UInt32: value to be subtracted from the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- UInt32: value before the subtraction
func fetchXor(UInt32)
public func fetchXor(val: UInt32): UInt32
Description: Performs an XOR operation on the value of the current atomic type instance and the val parameter using the default memory ordering, writes the result to the current atomic type instance, and returns the value before the XOR operation.
Parameters:
- val: UInt32: value to be XORed with the atomic type instance
Returns:
- UInt32: value before the XOR operation
func fetchXor(UInt32, MemoryOrder)
public func fetchXor(val: UInt32, memoryOrder!: MemoryOrder): UInt32
Description: Performs an XOR operation on the value of the current atomic type instance and the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the current atomic type instance, and returns the value before the XOR operation.
Parameters:
- val: UInt32: value to be XORed with the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- UInt32: value before the XOR operation
func load()
public func load(): UInt32
Description: Reads the value of an atomic type using the default memory ordering.
Returns:
- UInt32: value of the atomic type
func load(MemoryOrder)
public func load(memoryOrder!: MemoryOrder): UInt32
Description: Reads the value of an atomic type using the memory ordering specified by the memoryOrder parameter.
Parameters:
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- UInt32: value of the atomic type
func store(UInt32)
public func store(val: UInt32): Unit
Description: Writes the value specified by the val parameter to an atomic type using the default memory ordering.
Parameters:
- val: UInt32: value to be written to an atomic type
func store(UInt32, MemoryOrder)
public func store(val: UInt32, memoryOrder!: MemoryOrder): Unit
Description: Writes the value specified by the val parameter to an atomic type using the memory ordering specified by the memoryOrder parameter.
Parameters:
- val: UInt32: value to be written to an atomic type
- memoryOrder!: MemoryOrder: memory ordering of the current operation
func swap(UInt32)
public func swap(val: UInt32): UInt32
Description: Performs a swap operation using the default memory ordering to write the value specified by the val parameter to an atomic type, and returns the value before the writing.
Parameters:
- val: UInt32: value to be written to an atomic type
Returns:
- UInt32: value before writing
func swap(UInt32, MemoryOrder)
public func swap(val: UInt32, memoryOrder!: MemoryOrder): UInt32
Description: Performs a swap operation to write the value specified by the val parameter to an atomic type using the memory ordering specified by the memoryOrder parameter, and returns the value before the writing.
Parameters:
- val: UInt32: value to be written to an atomic type
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- UInt32: value before writing
class AtomicUInt64
public class AtomicUInt64
Description: Provides functions related to atomic operations of the UInt64 class.
init(UInt64)
public init(val: UInt64)
Description: Constructs an instance of the atomic type AtomicUInt64 that encapsulates the data type UInt64. The initial value of the internal data for the instance is the value of the input parameter val.
Parameters:
- val: UInt64: initial value of the atomic type
func compareAndSwap(UInt64, UInt64)
public func compareAndSwap(old: UInt64, new: UInt64): Bool
Description: Performs a CAS operation using the default memory ordering.
The value of the atomic type and the value specified by the old parameter are compared for equality. If they are equal, the value specified by the new parameter is written and true is returned. Otherwise, no value is written and false is returned.
Parameters:
- old: UInt64: value to be compared with the atomic type instance
- new: UInt64: value to be written to the atomic type when the two values are equal
Returns:
- Bool: If the swap is successful after comparison,
trueis returned. Otherwise,falseis returned.
func compareAndSwap(UInt64, UInt64, MemoryOrder, MemoryOrder)
public func compareAndSwap(old: UInt64, new: UInt64, successOrder!: MemoryOrder, failureOrder!: MemoryOrder): Bool
Description: Performs a CAS operation using the memory ordering specified by successOrder used upon success and the memory ordering specified by failureOrder used upon failure.
The value of the atomic type and the value specified by the old parameter are compared for equality. If they are equal, the value specified by the new parameter is written and true is returned. Otherwise, no value is written and false is returned.
Parameters:
- old: UInt64: value to be compared with the atomic type instance
- new: UInt64: value to be written to the atomic type when the two values are equal
- successOrder!: MemoryOrder: When the CAS operation is successful, the memory ordering required for the read > modify > write operation is executed.
- failureOrder!: MemoryOrder: When the CAS operation fails, the memory ordering required for the read operation is executed.
Returns:
- Bool: If the swap is successful after comparison,
trueis returned. Otherwise,falseis returned.
func fetchAdd(UInt64)
public func fetchAdd(val: UInt64): UInt64
Description: Adds the value of an atomic type to the val parameter using the default memory ordering, writes the result to the atomic type instance, and returns the value before the addition.
Parameters:
- val: UInt64: value to be added to the atomic type instance
Returns:
- UInt64: value before the addition
func fetchAdd(UInt64, MemoryOrder)
public func fetchAdd(val: UInt64, memoryOrder!: MemoryOrder): UInt64
Description: Adds the value of an atomic type to the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the atomic type instance, and returns the value before the addition.
Parameters:
- val: UInt64: value to be added to the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- UInt64: value before the addition
func fetchAnd(UInt64)
public func fetchAnd(val: UInt64): UInt64
Description: Performs an AND operation on the value of the current atomic type instance and the val parameter using the default memory ordering, writes the result to the current atomic type instance, and returns the value before the AND operation.
Parameters:
- val: UInt64: value to be ANDed with the atomic type instance
Returns:
- UInt64: value before the AND operation
func fetchAnd(UInt64, MemoryOrder)
public func fetchAnd(val: UInt64, memoryOrder!: MemoryOrder): UInt64
Description: Performs an AND operation on the value of the current atomic type instance and the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the current atomic type instance, and returns the value before the AND operation.
Parameters:
- val: UInt64: value to be ANDed with the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- UInt64: value before the AND operation
func fetchOr(UInt64)
public func fetchOr(val: UInt64): UInt64
Description: Performs an OR operation on the value of the current atomic type instance and the val parameter using the default memory ordering, writes the result to the current atomic type instance, and returns the value before the OR operation.
Parameters:
- val: UInt64: value to be ORed with the atomic type instance
Returns:
- UInt64: value before the OR operation
func fetchOr(UInt64, MemoryOrder)
public func fetchOr(val: UInt64, memoryOrder!: MemoryOrder): UInt64
Description: Performs an OR operation on the value of the current atomic type instance and the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the current atomic type instance, and returns the value before the OR operation.
Parameters:
- val: UInt64: value to be ORed with the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- UInt64: value before the OR operation
func fetchSub(UInt64)
public func fetchSub(val: UInt64): UInt64
Description: Uses the value of an atomic type as the minuend and the val parameter as the subtrahend to perform subtraction using the default memory ordering, writes the result to the current atomic type instance, and returns the value before the subtraction.
Parameters:
- val: UInt64: value to be subtracted from the atomic type instance
Returns:
- UInt64: value before the subtraction
func fetchSub(UInt64, MemoryOrder)
public func fetchSub(val: UInt64, memoryOrder!: MemoryOrder): UInt64
Description: Uses the value of an atomic type as the minuend and the val parameter as the subtrahend to perform subtraction using the memory ordering specified by the memoryOrder parameter, writes the result to the current atomic type instance, and returns the value before the subtraction.
Parameters:
- val: UInt64: value to be subtracted from the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- UInt64: value before the subtraction
func fetchXor(UInt64)
public func fetchXor(val: UInt64): UInt64
Description: Performs an XOR operation on the value of the current atomic type instance and the val parameter using the default memory ordering, writes the result to the current atomic type instance, and returns the value before the XOR operation.
Parameters:
- val: UInt64: value to be XORed with the atomic type instance
Returns:
- UInt64: value before the XOR operation
func fetchXor(UInt64, MemoryOrder)
public func fetchXor(val: UInt64, memoryOrder!: MemoryOrder): UInt64
Description: Performs an XOR operation on the value of the current atomic type instance and the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the current atomic type instance, and returns the value before the XOR operation.
Parameters:
- val: UInt64: value to be XORed with the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- UInt64: value before the XOR operation
func load()
public func load(): UInt64
Description: Reads the value of an atomic type using the default memory ordering.
Returns:
- UInt64: value of the atomic type
func load(MemoryOrder)
public func load(memoryOrder!: MemoryOrder): UInt64
Description: Reads the value of an atomic type using the memory ordering specified by the memoryOrder parameter.
Parameters:
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- UInt64: value of the atomic type
func store(UInt64)
public func store(val: UInt64): Unit
Description: Writes the value specified by the val parameter to an atomic type using the default memory ordering.
Parameters:
- val: UInt64: value to be written to an atomic type
func store(UInt64, MemoryOrder)
public func store(val: UInt64, memoryOrder!: MemoryOrder): Unit
Description: Writes the value specified by the val parameter to an atomic type using the memory ordering specified by the memoryOrder parameter.
Parameters:
- val: UInt64: value to be written to an atomic type
- memoryOrder!: MemoryOrder: memory ordering of the current operation
func swap(UInt64)
public func swap(val: UInt64): UInt64
Description: Performs a swap operation to write the value specified by the val parameter to an atomic type using the default memory ordering, and returns the value before the writing.
Parameters:
- val: UInt64: value to be written to an atomic type
Returns:
- UInt64: value before writing
func swap(UInt64, MemoryOrder)
public func swap(val: UInt64, memoryOrder!: MemoryOrder): UInt64
Description: Performs a swap operation to write the value specified by the val parameter to an atomic type using the memory ordering specified by the memoryOrder parameter, and returns the value before the writing.
Parameters:
- val: UInt64: value to be written to an atomic type
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- UInt64: value before writing
class AtomicUInt8
public class AtomicUInt8
Description: Provides functions related to atomic operations of the UInt8 class.
init(UInt8)
public init(val: UInt8)
Description: Constructs an instance of the atomic type AtomicUInt8 that encapsulates the data type UInt8. The initial value of the internal data for the instance is the value of the input parameter val.
Parameters:
- val: UInt8: initial value of the atomic type
func compareAndSwap(UInt8, UInt8)
public func compareAndSwap(old: UInt8, new: UInt8): Bool
Description: Performs a CAS operation using the default memory ordering.
The value of the atomic type and the value specified by the old parameter are compared for equality. If they are equal, the value specified by the new parameter is written and true is returned. Otherwise, no value is written and false is returned.
Parameters:
- old: UInt8: value to be compared with the atomic type instance
- new: UInt8: value to be written to the atomic type when the two values are equal
Returns:
- Bool: If the swap is successful after comparison,
trueis returned. Otherwise,falseis returned.
func compareAndSwap(UInt8, UInt8, MemoryOrder, MemoryOrder)
public func compareAndSwap(old: UInt8, new: UInt8, successOrder!: MemoryOrder, failureOrder!: MemoryOrder): Bool
Description: Performs a CAS operation using the memory ordering specified by successOrder used upon success and the memory ordering specified by failureOrder used upon failure.
The value of the atomic type and the value specified by the old parameter are compared for equality. If they are equal, the value specified by the new parameter is written and true is returned. Otherwise, no value is written and false is returned.
Parameters:
- old: UInt8: value to be compared with the atomic type instance
- new: UInt8: value to be written to the atomic type when the two values are equal
- successOrder!: MemoryOrder: When the CAS operation is successful, the memory ordering required for the read > modify > write operation is executed.
- failureOrder!: MemoryOrder: When the CAS operation fails, the memory ordering required for the read operation is executed.
Returns:
- Bool: If the swap is successful after comparison,
trueis returned. Otherwise,falseis returned.
func fetchAdd(UInt8)
public func fetchAdd(val: UInt8): UInt8
Description: Adds the value of an atomic type to the val parameter using the default memory ordering, writes the result to the atomic type instance, and returns the value before the addition.
Parameters:
- val: UInt8: value to be added to the atomic type instance
Returns:
- UInt8: value before the addition
func fetchAdd(UInt8, MemoryOrder)
public func fetchAdd(val: UInt8, memoryOrder!: MemoryOrder): UInt8
Description: Adds the value of an atomic type to the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the atomic type instance, and returns the value before the addition.
Parameters:
- val: UInt8: value to be added to the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- UInt8: value before the addition
func fetchAnd(UInt8)
public func fetchAnd(val: UInt8): UInt8
Description: Performs an AND operation on the value of the current atomic type instance and the val parameter using the default memory ordering, writes the result to the current atomic type instance, and returns the value before the AND operation.
Parameters:
- val: UInt8: value to be ANDed with the atomic type instance
Returns:
- UInt8: value before the AND operation
func fetchAnd(UInt8, MemoryOrder)
public func fetchAnd(val: UInt8, memoryOrder!: MemoryOrder): UInt8
Description: Performs an AND operation on the value of the current atomic type instance and the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the current atomic type instance, and returns the value before the AND operation.
Parameters:
- val: UInt8: value to be ANDed with the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- UInt8: value before the AND operation
func fetchOr(UInt8)
public func fetchOr(val: UInt8): UInt8
Description: Performs an OR operation on the value of the current atomic type instance and the val parameter using the default memory ordering, writes the result to the current atomic type instance, and returns the value before the OR operation.
Parameters:
- val: UInt8: value to be ORed with the atomic type instance
Returns:
- UInt8: value before the OR operation
func fetchOr(UInt8, MemoryOrder)
public func fetchOr(val: UInt8, memoryOrder!: MemoryOrder): UInt8
Description: Performs an OR operation on the value of the current atomic type instance and the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the current atomic type instance, and returns the value before the OR operation.
Parameters:
- val: UInt8: value to be ORed with the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- UInt8: value before the OR operation
func fetchSub(UInt8)
public func fetchSub(val: UInt8): UInt8
Description: Uses the value of an atomic type as the minuend and the val parameter as the subtrahend to perform subtraction using the default memory ordering, writes the result to the current atomic type instance, and returns the value before the subtraction.
Parameters:
- val: UInt8: value to be subtracted from the atomic type instance
Returns:
- UInt8: value before the subtraction
func fetchSub(UInt8, MemoryOrder)
public func fetchSub(val: UInt8, memoryOrder!: MemoryOrder): UInt8
Description: Uses the value of an atomic type as the minuend and the val parameter as the subtrahend to perform subtraction using the memory ordering specified by the memoryOrder parameter, writes the result to the current atomic type instance, and returns the value before the subtraction.
Parameters:
- val: UInt8: value to be subtracted from the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- UInt8: value before the subtraction
func fetchXor(UInt8)
public func fetchXor(val: UInt8): UInt8
Description: Performs an XOR operation on the value of the current atomic type instance and the val parameter using the default memory ordering, writes the result to the current atomic type instance, and returns the value before the XOR operation.
Parameters:
- val: UInt8: value to be XORed with the atomic type instance
Returns:
- UInt8: value before the XOR operation
func fetchXor(UInt8, MemoryOrder)
public func fetchXor(val: UInt8, memoryOrder!: MemoryOrder): UInt8
Description: Performs an XOR operation on the value of the current atomic type instance and the val parameter using the memory ordering specified by the memoryOrder parameter, writes the result to the current atomic type instance, and returns the value before the XOR operation.
Parameters:
- val: UInt8: value to be XORed with the atomic type instance
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- UInt8: value before the XOR operation
func load()
public func load(): UInt8
Description: Reads the value of an atomic type using the default memory ordering.
Returns:
- UInt8: value of the atomic type
func load(MemoryOrder)
public func load(memoryOrder!: MemoryOrder): UInt8
Description: Reads the value of an atomic type using the memory ordering specified by the memoryOrder parameter.
Parameters:
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- UInt8: value of the atomic type
func store(UInt8)
public func store(val: UInt8): Unit
Description: Writes the value specified by the val parameter to an atomic type using the default memory ordering.
Parameters:
- val: UInt8: value to be written to an atomic type
func store(UInt8, MemoryOrder)
public func store(val: UInt8, memoryOrder!: MemoryOrder): Unit
Description: Writes the value specified by the val parameter to an atomic type using the memory ordering specified by the memoryOrder parameter.
Parameters:
- val: UInt8: value to be written to an atomic type
- memoryOrder!: MemoryOrder: memory ordering of the current operation
func swap(UInt8)
public func swap(val: UInt8): UInt8
Description: Performs a swap operation to write the value specified by the val parameter to an atomic type using the default memory ordering, and returns the value before the writing.
Parameters:
- val: UInt8: value to be written to an atomic type
Returns:
- UInt8: value before writing
func swap(UInt8, MemoryOrder)
public func swap(val: UInt8, memoryOrder!: MemoryOrder): UInt8
Description: Performs a swap operation to write the value specified by the val parameter to an atomic type using the memory ordering specified by the memoryOrder parameter, and returns the value before the writing.
Parameters:
- val: UInt8: value to be written to an atomic type
- memoryOrder!: MemoryOrder: memory ordering of the current operation
Returns:
- UInt8: value before writing
class Barrier
public class Barrier
Description: Provides the function of coordinating the execution of multiple threads to a program point.
Threads reaching the program point enter the blocked status until all threads reach the program point to continue the execution.
init(Int64)
public init(count: Int64)
Description: Creates a Barrier object.
Parameters:
- count: Int64: number of threads to be coordinated.
Throws:
- IllegalArgumentException: When the value of the count parameter is negative, this exception is thrown.
func wait(Duration)
public func wait(timeout!: Duration = Duration.Max): Unit
Description: Instructs a thread to enter the Barrier waiting point.
If the number of times (the number of threads entering the waiting point) the Barrier object calls the wait method equals the initial value, all waiting threads are woken up. If the number of times the wait method is called is less than the initial value, the current thread enters the blocked status until it is woken up or the waiting time exceeds timeout. If the number of times the wait method is called is greater than the initial value, the thread continues running.
Parameters:
- timeout!: Duration: maximum waiting duration in blocked status; default value: Duration.Max
class Monitor
public class Monitor <: ReentrantMutex
Description: Provides the function of blocking a thread and waiting for a signal from another thread to resume execution.
This is a mechanism that uses shared variables to synchronize threads. Specifically, if some threads are suspended when waiting for certain condition satisfaction of the shared variables, other threads change the shared variables for the condition to be met. Then, the suspended threads are woken up to continue running.
Parent Type:
init()
public init()
Description: Creates a Monitor object instance using the default constructor.
func notify()
public func notify(): Unit
Function: Wakes up a thread waiting on the Montior.
Throws:
- IllegalSynchronizationStateException: If the current thread does not hold the mutex, this exception is thrown.
func notifyAll()
public func notifyAll(): Unit
Description: Wakes up all threads waiting on the Montior.
Throws:
- IllegalSynchronizationStateException: If the current thread does not hold the mutex, this exception is thrown.
func wait(Duration)
public func wait(timeout!: Duration = Duration.Max): Bool
Description: Instructs the current thread to be suspended until the corresponding notify function is called or the suspension duration exceeds timeout.
Parameters:
- timeout!: Duration: suspension duration; default value: Duration.Max
Returns:
- Bool: If Monitor is woken up by another thread,
trueis returned. If timeout occurs,falseis returned.
Throws:
- IllegalArgumentException: If
timeoutis less than or equal to Duration.Zero, this exception is thrown. - IllegalSynchronizationStateException: If the current thread does not hold the mutex, this exception is thrown.
class MultiConditionMonitor
public class MultiConditionMonitor <: ReentrantMutex
Description: Provides the function of binding multiple condition variables to the same mutex.
Note:
- This class should be used only when the Monitor class cannot implement advanced concurrency algorithms.
- During initialization, there is no condition variable related to MultiConditionMonitor.
- Each time
newConditionis called, a new waiting queue is created and associated with the current object, and an instance of the ConditionID type is returned as the unique identifier.
Parent Type:
init()
public init()
Description: Creates a MultiConditionMonitor object instance using the default constructor.
func newCondition()
public func newCondition(): ConditionID
Description: Creates ConditionID related to Monitor, which may be used to implement the concurrency primitive of "single mutex for multiple waiting queues".
Returns:
- ConditionID: new ConditionID
Throws:
- IllegalSynchronizationStateException: If the current thread does not hold the mutex, this exception is thrown.
func notify(ConditionID)
public func notify(condID: ConditionID): Unit
Description: Wakes up a thread (if any) waiting for the specified condition variable.
Parameters:
- condID: ConditionID: condition variable
Throws:
- IllegalSynchronizationStateException: If the current thread does not hold the mutex or
condIDis not created by the MultiConditionMonitor instance using thenewConditionfunction, this exception is thrown.
func notifyAll(ConditionID)
public func notifyAll(condID: ConditionID): Unit
Description: Wakes up all threads (if any) waiting for the specified condition variable.
Parameters:
- condID: ConditionID: condition variable
Throws:
- IllegalSynchronizationStateException: If the current thread does not hold the mutex or
condIDis not created by the MultiConditionMonitor instance using thenewConditionfunction, this exception is thrown.
func wait(ConditionID, Duration)
public func wait(condID: ConditionID, timeout!: Duration = Duration.Max): Bool
Description: Instructs the current thread to be suspended until the corresponding notify function is called.
Parameters:
- condID: ConditionID: condition variable
- timeout!: Duration: suspension duration; default value: Duration.Max
Returns:
- Bool: If the condition variable specified by Monitor is woken up by another thread,
trueis returned. If timeout occurs,falseis returned.
Throws:
- IllegalSynchronizationStateException: If the current thread does not hold the mutex, the suspension duration exceeds
timeout, orcondIDis not created by the MultiConditionMonitor instance using thenewConditionfunction, this exception is thrown. - IllegalArgumentException: If
timeoutis less than or equal to Duration.Zero, this exception is thrown.
class ReentrantMutex
public open class ReentrantMutex <: IReentrantMutex
Description: Provides functions related to reentrant mutexes.
The function of a reentrant mutex is to protect the critical section so that only one thread can execute the code in the critical section at any time. When a thread attempts to obtain a mutex that has been held by another thread, the thread is blocked and is not woken up until the mutex is released. The word reentrant indicates that a thread can obtain a mutex again after obtaining it.
Note:
- ReentrantMutex provides built-in mutexes. Developers must ensure that no classes inherit it?
- Before shared data is accessed, a mutex must be obtained.
- After the shared data is processed, the mutex must be unlocked for other threads to obtain.
Parent Type:
init()
public init()
Description: Creates a reentrant mutex.
Throws:
- IllegalSynchronizationStateException: When a system error occurs, this exception is thrown.
func lock()
public open func lock(): Unit
Description: Locks a mutex. If the mutex has been locked, the blocked status is entered.
func tryLock()
public open func tryLock(): Bool
Description: Attempts to lock a mutex.
Returns:
- Bool: If the mutex has been locked,
falseis returned. Otherwise, the mutex is locked andtrueis returned.
func unlock
public open func unlock(): Unit
Description: Unlocks a mutex.
If the mutex is locked for N times, this function needs to be called for N times to completely unlock the mutex. Once the mutex is completely unlocked, one of other threads blocked and waiting for the mutex is woken up.
Throws:
- IllegalSynchronizationStateException: If the current thread does not hold the mutex, this exception is thrown.
class ReentrantReadMutex
public class ReentrantReadMutex <: ReentrantMutex
Description: Specifies the read lock class in reentrant read-write locks.
Parent Type:
func lock()
public func lock(): Unit
Description: Obtains a read lock.
Note:
- In fair mode, if no other thread holds or is waiting for the write lock, or the current thread has held the read lock, the current thread holds the read lock immediately. Otherwise, the current thread enters the waiting status.
- In unfair mode, if no other thread holds or is waiting for the write lock, the current thread holds the read lock immediately. If another thread holds the write lock, the current thread enters the waiting status. Otherwise, whether the thread can hold the read lock immediately is not guaranteed.
- Multiple threads can hold the read lock concurrently, and one thread can hold the read lock repeatedly. A thread holding the write lock, can still hold the read lock.
func tryLock()
public func tryLock(): Bool
Description: Attempts to obtain a read lock. This method does not follow the fair mode when used to obtain a read lock.
Returns:
- Bool: If the read lock is successfully obtained,
trueis returned. If the read lock is not obtained,falseis returned.
func unlock()
public func unlock(): Unit
Description: Releases a read lock. If a thread holds the read lock repeatedly, the read lock is released only when the number of release operations is equal to that of obtain operations. After the read lock is released, one of the threads waiting for the write lock is woken up.
Throws:
- IllegalSynchronizationStateException: If the current thread does not hold the read lock, this exception is thrown.
class ReentrantReadWriteMutex
public class ReentrantReadWriteMutex
Description: Provides functions related to reentrant read-write locks.
Difference between a read-write lock and a common mutex: A read-write lock carries two mutexes, a read lock and a write lock, and allows multiple threads to hold the read lock concurrently.
Special properties of a read-write lock:
- Mutual exclusivity of writing: Only one thread can hold the write lock. When a thread holds the write lock, another thread is blocked when attempting to obtain a lock (read lock or write lock).
- Read concurrency: Multiple threads are allowed to hold the read lock concurrently. When a thread holds the read lock, other threads can still obtain the read lock. However, other threads are blocked when attempting to obtain the write lock.
- Reentrance: A thread can obtain a lock repeatedly.
- A thread holding the write lock can still obtain the write lock or read lock. A lock is completely released only when the lock release and obtain operations are in a one-to-one correspondence.
- A thread holding the read lock can obtain the read lock again. A lock is completely released only when the lock release and obtain operations are in a one-to-one correspondence. Note: Obtaining the write lock when the read lock is held is not allowed and triggers an exception.
- Lock degradation: After holding the write lock > holding the read lock > releasing the write lock, a thread holds the read lock instead of the write lock.
- Read/write fairness: A read-write lock supports fair and unfair modes.
- In unfair mode, the sequence of obtaining locks by threads is not guaranteed for a read-write lock.
- In fair mode, when a thread obtains the read lock (the current thread does not hold the read lock), if the write lock has been obtained or any thread is waiting for the write lock, the current thread cannot obtain the read lock and enters the waiting status.
- In fair mode, when the write lock is released, all read threads are woken up preferentially. When the read lock is released, a thread waiting for the write lock is woken up preferentially. The sequence of waking up multiple threads waiting for the write lock is not guaranteed.
prop readMutex
public prop readMutex: ReentrantReadMutex
Description: Obtains a read lock.
Type: ReentrantReadMutex
prop writeMutex
public prop writeMutex: ReentrantWriteMutex
Description: Obtains a write lock.
Type: ReentrantWriteMutex
init(ReadWriteMutexMode)
public init(mode!: ReadWriteMutexMode = ReadWriteMutexMode.Unfair)
Description: Constructs a read-write lock.
Parameters:
- mode!: ReadWriteMutexMode: read-write lock mode; default value:
Unfair, indicating that a read-write lock in unfair mode is to be constructed
class ReentrantWriteMutex
public class ReentrantWriteMutex <: ReentrantMutex
Description: Specifies the write lock class in reentrant read-write locks.
Parent Type:
func lock()
public func lock(): Unit
Description: Obtains a write lock. Only one thread is allowed to hold the write lock at the same time, and a thread can hold the write lock repeatedly. If another thread holds the write lock or read lock, the current thread enters the waiting status.
Throws:
- IllegalSynchronizationStateException: If the current thread has held the read lock, this exception is thrown.
func tryLock()
public func tryLock(): Bool
Description: Attempts to obtain a write lock. This method does not follow the fair mode when used to obtain a read lock.
Returns:
- Bool: If the write lock is successfully obtained,
trueis returned. If the read lock is not obtained,falseis returned.
func unlock()
public func unlock(): Unit
Description: Releases a write lock.
Note:
- If a thread holds the read lock repeatedly, the read lock is released only when the number of release operations is equal to that of obtain operations. After the read lock is released, one of the threads waiting for the write lock is woken up.
- In fair mode, if the write lock is released, threads waiting for the read lock are woken up preferentially. If no thread is waiting for the read lock, one of threads waiting for the write lock is woken up.
- In unfair mode, if the write lock is released, whether a thread waiting for the write lock or a thread waiting for the read lock is preferentially woken up is determined by specific implementation.
Throws:
- IllegalSynchronizationStateException: If the current thread does not hold the write lock, this exception is thrown.
class Semaphore
public class Semaphore
Description: Provides functions related to semaphores.
A Semaphore can be considered as a Monitor carrying a counter and is often used to control the number of threads concurrently accessing shared resources.
prop count
public prop count: Int64
Description: Returns the value of the current internal counter.
Type: Int64
init(Int64)
public init(count: Int64)
Description: Creates a Semaphore object and initializes the value of the internal counter.
Parameters:
Throws:
- IllegalArgumentException: When the value of the count parameter is negative, this exception is thrown.
func acquire(Int64)
public func acquire(amount!: Int64 = 1): Unit
Description: Obtains a specified value from the Semaphore object.
If the current counter is less than the required value, the current thread is blocked and is not woken up until the value that meets the requirement is obtained.
Parameters:
- amount!: Int64: value to be obtained from the internal counter of the object; default value: 1
Throws:
- IllegalArgumentException: When the value of the
amountparameter is negative or greater than the initial value, this exception is thrown.
func release(Int64)
public func release(amount!: Int64 = 1): Unit
Description: Releases a specified value to the Semaphore object.
If the internal counter can meet the requirements of the thread that is currently blocked at the Semaphore object after the released values are accumulated, the thread is woken up. The value of the internal counter is not greater than the initial value. That is, if the value of the internal counter is greater than the initial value after the accumulation, the value is set to the initial value. All operations before release is called occur before operations after acquire/tryAcquire is called.
Parameters:
- amount!: Int64: value to be released to the internal counter of the object; default value: 1
Returns:
- Unit: If the value of the current counter is less than the required value, the obtaining fails and
falseis returned. If the obtaining is successful,trueis returned.
Throws:
- IllegalArgumentException: When the value of the
amountparameter is negative or greater than the initial value, this exception is thrown.
func tryAcquire(Int64)
public func tryAcquire(amount!: Int64 = 1): Bool
Description: Attempts to obtain a specified value from the Semaphore object.
This method does not block threads. If multiple threads concurrently perform the obtain operation, the obtaining sequence is not guaranteed.
Parameters:
- amount!: Int64: value to be obtained from the internal counter of the object; default value: 1
Returns:
- Bool: If the value of the current counter is less than the required value, the obtaining fails and
falseis returned. If the obtaining is successful,trueis returned.
Throws:
- IllegalArgumentException: When the value of the
amountparameter is negative or greater than the initial value, this exception is thrown.
class SyncCounter
public class SyncCounter
Description: Provides countdown counter functions.
Threads can wait for the value of the counter to become zero.
prop count
public prop count: Int64
Description: Obtains the current value of the counter.
Type: Int64
init(Int64)
public init(count: Int64)
Description: Creates a countdown counter.
Parameters:
Throws:
- IllegalArgumentException: When the value of the count parameter is negative, this exception is thrown.
func dec()
public func dec(): Unit
Description: Decreases the value of the counter by one.
If the value of the counter becomes zero, all waiting threads are woken up. If the value of the counter is already zero, the value remains unchanged.
func waitUntilZero(Duration)
public func waitUntilZero(timeout!: Duration = Duration.Max): Unit
Description: Instructs the current thread to wait until the value of the counter becomes zero or the waiting duration exceeds timeout.
Parameters:
- timeout!: Duration: maximum waiting duration in blocked status; default value: Duration.Max
class Timer
public class Timer <: Equatable<Timer> & Hashable
Description: Provides timer functions.
This class is used to execute a specified task once or multiple times at a specified time point or after a specified interval.
Note:
- Timer implicitly includes the
spawnoperation. That is, each Timer creates a thread to execute its associated task.- Each Timer can be bound to one task only during initialization. After the initialization is complete, the associated task cannot be reset.
- The lifecycle of Timer ends only after the associated task is executed or the
cancelinterface is used to cancel Timer. Then, Timer can be reclaimed by GC. In other words, before the task associated with Timer is executed or Timer is canceled, Timer instance is not reclaimed by GC. This ensures that the associated task can be properly executed.- When the system is busy, the triggering time of the task may be affected. Timer does not guarantee on-time task triggering, but ensures that the triggering time of the task is earlier than or the same as the current time.
- Timer does not proactively capture exceptions thrown from the associated task. If any exception of the task is not captured, Timer becomes invalid.
- Timer includes one-off task timers and repetitive task timers based on the usage method. When a one-off task timer is used, the task is executed only once. When a repetitive task timer is used, the task is executed periodically as specified until the
cancelinterface is used to cancel the task or the end condition specified upon creation of Timer is met.
Parent Type:
static func after(Duration, ()->?Duration)
public static func after(delay: Duration, task: () -> Option<Duration>): Timer
Description: Initializes a Timer. The number of times the associated task is scheduled for execution depends on the return value. If the time when the timer is triggered for the first time is earlier than the current time, the associated task is scheduled for execution immediately. If the return value of the associated task is Option.None, Timer becomes invalid and the associated task stops being scheduled. If the return value of the associated task is Option.Some(v) and v is greater than Duration.Zero, the minimum interval before the next running is set to v. Otherwise, the associated task is scheduled for execution again immediately.
Parameters:
- delay: Duration: interval between the current time and the time when the associated task is scheduled for execution for the first time
- task: () ->Option<Duration>: task to be scheduled for execution by Timer
Returns:
static func once(Duration, ()->Unit)
public static func once(delay: Duration, task: ()->Unit): Timer
Description: Sets and starts a one-off scheduled task, and returns the Timer object instance that controls the task.
Parameters:
- delay: interval between the current time and the time when the task is executed; value range: [Duration.Min, Duration.Max]. If the value is less than or equal to Duration.Zero, the task is executed immediately.
- task: task to be executed as scheduled
Returns: Timer object instance
Example:
import std.sync.{Timer, sleep}
import std.time.{Duration, MonoTime}
main() {
let start = MonoTime.now()
Timer.once(Duration.second, {=>
println("Tick at: ${MonoTime.now() - start}")
})
sleep(Duration.second * 2)
0
}
Running result:
Tick at: 1s2ms74us551ns
static func repeat(Duration, Duration, ()->Unit, CatchupStyle)
public static func repeat(delay: Duration, interval: Duration, task: ()->Unit, style!: CatchupStyle = Burst): Timer
Description: Sets and starts a one-off repetitive task, and returns the Timer object instance that controls the task.
Parameters:
- delay: interval between the current time and the time when the task is executed; value range: [Duration.Min, Duration.Max]. If the value is less than or equal to Duration.Zero, the task is executed immediately.
- interval: interval between two task executions; value range: (Duration.Zero, Duration.Max]
- task: task to be executed as scheduled
- style: catch-up policy; default value: Burst. If the execution duration of a task is too long, the execution times of subsequent tasks may be delayed. Different catch-up policies apply to different scenarios. For details, see CatchupStyle description.
Returns: Timer object instance
Throws:
- IllegalArgumentException: If
intervalis less than or equal to Duration.Zero, this exception is thrown.
Example:
import std.sync.{Timer, sleep}
import std.time.{Duration, MonoTime}
main() {
let start = MonoTime.now()
let timer = Timer.repeat(Duration.second, Duration.second, {=>
println("Tick at: ${MonoTime.now() - start}")
})
sleep(Duration.second * 5)
timer.cancel()
0
}
Running result:
Tick at: 1s2ms72us188ns
Tick at: 2s4ms185us160ns
Tick at: 3s6ms275us464ns
Tick at: 4s8ms18us399ns
Tick at: 5s9ms621us394ns
static func repeatDuring(Duration, Duration, Duration, ()->Unit, CatchupStyle)
public static func repeatDuring(period: Duration, delay: Duration, interval: Duration, task: () -> Unit, style!: CatchupStyle = Burst): Timer
Description: Sets and starts a repetitive scheduled task, specifies the maximum duration of the repetition period, and returns the Timer object instance that controls the task.
Parameters:
- period: maximum duration of the repetition period, for which timing starts after delay; value range: (Duration.Zero, Duration.Max]
- delay: interval between the current time and the time when the task is executed; value range: [Duration.Min, Duration.Max]. If the value is less than or equal to Duration.Zero, the task is executed immediately.
- interval: interval between two task executions; value range: (Duration.Zero, Duration.Max]
- task: task to be executed as scheduled
- style: catch-up policy; default value: Burst. If the execution duration of a task is too long, the execution times of subsequent tasks may be delayed. Different catch-up policies apply to different scenarios. For details, see CatchupStyle description.
Returns: Timer object instance
Throws:
- IllegalArgumentException: If the value of period is less than or equal to that of Duration.Zero or the value of interval is less than or equal to that of Duration.Zero, this exception is thrown.
Example:
import std.sync.{Timer, sleep}
import std.time.{Duration, MonoTime}
main() {
let start = MonoTime.now()
Timer.repeatDuring(Duration.second * 5, Duration.second, Duration.second, {=>
println("Tick at: ${MonoTime.now() - start}")
})
sleep(Duration.second * 7)
0
}
Running result:
Tick at: 1s2ms372us626ns
Tick at: 2s4ms714us879ns
Tick at: 3s6ms769us623ns
Tick at: 4s8ms780us235ns
Tick at: 5s660us104ns
Tick at: 6s3ms257us508ns
static func repeatTimes(Int64, Duration, Duration, ()->Unit, CatchupStyle)
public static func repeatTimes(count: Int64, delay: Duration, interval: Duration, task: () -> Unit, style!: CatchupStyle = Burst): Timer
Description: Sets and starts a repetitive scheduled task, specifies the maximum number of execution times of the task, and returns the Timer object instance that controls the task.
Parameters:
- count: maximum number of execution times of the task; value range: (0, Int64.Max]
- delay: interval between the current time and the time when the task is executed; value range: [Duration.Min, Duration.Max]. If the value is less than or equal to Duration.Zero, the task is executed immediately.
- interval: interval between two task executions; value range: (Duration.Zero, Duration.Max]
- task: task to be executed as scheduled
- style: catch-up policy; default value: Burst. If the execution duration of a task is too long, the execution times of subsequent tasks may be delayed. Different catch-up policies apply to different scenarios. For details, see CatchupStyle description.
Returns: Timer object instance
Throws:
- IllegalArgumentException: If the value of count is less than or equal to 0 or the value of interval is less than or equal to that of Duration.Zero, this exception is thrown.
Example:
import std.sync.{Timer, sleep}
import std.time.{Duration, MonoTime}
main() {
let start = MonoTime.now()
Timer.repeatTimes(3, Duration.second, Duration.second, {=>
println("Tick at: ${MonoTime.now() - start}")
})
sleep(Duration.second * 4)
0
}
Running result:
Tick at: 1s2ms855us251ns
Tick at: 2s5ms390us18ns
Tick at: 3s7ms935us552ns
func cancel()
public func cancel(): Unit
Description: Cancels a Timer, after which the associated task is no longer scheduled for execution.
An associated task being executed is not interrupted when this function is called. This function does not block the current thread. Calling this function for multiple times is equivalent to calling this function only once.
func hashCode()
public func hashCode(): Int64
Description: Obtains the hash value of a Timer object.
Returns: hash value of the Timer object
operator func !=(Timer)
public operator func !=(rhs: Timer): Bool
Description: Checks whether the current Timer and Timer specified by the input parameter rhs are not the same instance.
Returns:
operator func ==(Timer)
public operator func ==(rhs: Timer): Bool
Description: Checks whether the current Timer and Timer specified by the input parameter rhs are the same instance.
Returns:
Enumeration
enum CatchupStyle
public enum CatchupStyle {
| Delay
| Burst
| Skip
}
Description: Enumerates the catch-up policies used by a repetitive task timer.
If the execution time of a task is too long, subsequent tasks may be delayed. Different catch-up policies are applicable to different scenarios.
- The
Delaypolicy is applicable to the scenario where the start time of a task is not concerned and the execution interval between two tasks is fixed. - The
Burstpolicy is applicable to the scenario where scheduled tasks need to be executed in sequence. - The
Skippolicy is applicable to the scenario where scheduled tasks do not need to be executed in sequence and intermediate tasks can be ignored.
Example:
In this example, Timer is created. Within the duration of Timer, three tasks will be executed. One task is executed one second after the creation, and the remaining tasks are executed at an interval of one second. Delay is the catch-up policy.
import std.sync.{Timer, sleep, CatchupStyle}
import std.time.{Duration, MonoTime}
main() {
let start = MonoTime.now()
Timer.repeatTimes(3, Duration.second, Duration.second, {=>
println("Tick at: ${MonoTime.now() - start}")
}, style: Delay)
sleep(Duration.second * 4)
0
}
Burst
Burst
Description: When this policy is used, tasks are started at a fixed interval. If the execution time of a task is longer than the preset task starting interval, other tasks missing the point of time are executed in sequence until catch-up.
Delay
Delay
Description: When this policy is used, the interval between the end time of the current task and the start time of the next task is fixed. That is, start time of the next task = end time of the current task + preset task starting interval.
Skip
Skip
Description: When this policy is used, tasks are started at a fixed interval. If the execution time of a task is longer than the preset task starting interval, the following missed points of time are skipped for fast catch-up.
enum MemoryOrder
public enum MemoryOrder {
| SeqCst
}
Description: Enumerates memory order types.
The memory order refers to the sequence of memory read (load) and write (store) operations. For performance optimization, the compiler or the CPU may reorder instructions. The memory order enumeration is used to indicate a sorting policy.
SeqCst
SeqCst
Description: Indicates a consistent sequence. That is, instruction reordering is disabled to ensure that all atomic operations prior to the atomic operation are completed before the atomic operations subsequent to the atomic operation.
enum ReadWriteMutexMode
public enum ReadWriteMutexMode {
| Unfair
| Fair
}
Description: Enumerates the read/write lock fairness modes.
The lock fairness refers to whether a lock is acquired in sequence according to a waiting order when multiple threads are waiting for the same lock.
Fair
Fair
Description: Indicates the fair mode of read/write lock. When a lock is released, the longest-waiting thread acquires the lock first.
Unfair
Unfair
Description: Indicates the unfair mode of read/write lock. When a lock is released, any waiting thread may acquire the lock.
Struct
struct ConditionID
public struct ConditionID
Description: Specifies the condition variable of a mutex. For details, see MultiConditionMonitor.
Exception Class
class IllegalSynchronizationStateException
public class IllegalSynchronizationStateException <: Exception
Description: Indicates an invalid synchronization state.
Parent Type:
init()
public init()
Description: Creates an IllegalSynchronizationStateException instance.
init(String)
public init(message: String)
Description: Creates an IllegalSynchronizationStateException instance whose information is specified by the parameter message.
Parameters:
- message: String: predefined message
Usage of Atomic, Monitor, and Timer
Usage of Atomic
In a multi-threaded program, atomic operations are performed for counting.
import std.sync.*
import std.time.*
import std.collection.*
let count = AtomicInt64(0)
main(): Int64 {
let list = ArrayList<Future<Int64>>()
/* Creates 1000 threads */
for (_ in 0..1000) {
let fut = spawn {
sleep(Duration.millisecond) /* Sleeps for 1 millisecond */
count.fetchAdd(1)
}
list.append(fut)
}
/* Waits for completion of all threads */
for (f in list) {
f.get()
}
var val = count.load()
println("count = ${val}")
return 0
}
Output:
count = 1000
Usage of Monitor
Example:
In different threads, Monitor is used to suspend and awaken threads.
import std.sync.*
import std.time.{Duration, DurationExtension}
var mon = Monitor()
var flag: Bool = true
main(): Int64 {
let fut = spawn {
mon.lock()
while (flag) {
println("New thread: before wait")
mon.wait()
println("New thread: after wait")
}
mon.unlock()
}
/* Sleep for 10 milliseconds so that the new thread can be executed */
sleep(10 * Duration.millisecond)
mon.lock()
println("Main thread: set flag")
flag = false
mon.unlock()
println("Main thread: notify")
mon.lock()
mon.notifyAll()
mon.unlock()
/* Wait for completion of the new thread */
fut.get()
return 0
}
Output:
New thread: before wait
Main thread: set flag
Main thread: notify
New thread: after wait
Usage of Timer
Example:
Timer is used to create one-off and repetitive tasks.
import std.sync.*
import std.time.{Duration, DurationExtension}
main(): Int64 {
let count = AtomicInt8(0)
Timer.once(50 * Duration.millisecond) { =>
println("run only once")
count.fetchAdd(1)
}
let timer = Timer.repeat(100 * Duration.millisecond, 200 * Duration.millisecond, { =>
println("run repetitively")
count.fetchAdd(10)
})
sleep(Duration.second)
timer.cancel()
sleep(500 * Duration.millisecond)
println("count = ${count.load()}")
0
}
Output:
run only once
run repetitively
run repetitively
run repetitively
run repetitively
run repetitively
count = 51
std.time Package
Function Description
The time package provides time-related types, including date and time, time interval, monotonic time, and time zone, and provides functionality of calculation and comparison.
Time String Formats
Parsing time from a string has the following requirements:
-
The string must contain the information about the specific year, month, and day, for example, year (y) + month (M) and day (d), or year (y) and day of the year (D).
-
If information about the hour, minute, and second is not contained, the default value 0 is used. If information about the time zone is not contained, the default value of TimeZone.Local is used.
-
It is not allowed to assign a value twice to the formats represented by the same letter. For example, the year (y) format cannot be assigned a value twice. The O and Z formats cannot be used together to indicate the time zone.
-
The format of some other letters is used as auxiliary information for verification. For example, when "2023-04-24-Mon" is parsed using the "yyyy-MM-dd-www" format, the correctness of "Mon" is verified.
Meanings of Letters
| Letter | Meaning |
|---|---|
| a | Daytime |
| y | Year |
| Y | Week-based year |
| M | Month |
| d | Day |
| D | Number of days in a year |
| w | Number of days in weeks |
| W | ISO 8601-compliant week date |
| h | Hour in 12-hour clock format |
| H | Hour in 24-hour clock format |
| m | Minutes |
| s | Seconds |
| S | Part less than one second |
| z | Time zone name and time zone ID |
| Z | Zero hour offset |
| O | Time zone offset |
| G | Calendar era |
The following describes the rules of mapping of these letters.
Rules
Daytime
The valid number is 1, indicating morning or afternoon. The value is permanently AM or PM.
Year
| Number of Letters | Parsing | Output |
|---|---|---|
| 1, 3, or 4 | A year in four digits, for example, 2023 and 0001. | A year in at least four digits, for example, 2023, 0001, and 99999. Zeros are added if there are less than four digits. |
| 2 | A year in two digits, for example, 23 and 69. If xx is greater than or equal to 69, the year is parsed as 19xx; otherwise, the year is parsed as 20xx. The same rule applies to negative numbers. | A year in two or more digits, for example, 23 and 69. The output of [1969, 1999] is [69, 99], and the output of [2000, 2068] is [00, 68]. The same rule applies to negative numbers. In other cases, the output contains at least four digits. Zeros are added if there are less than four digits. |
| 5–9 | A year in the corresponding number of digits. | A year in the corresponding number of digits. Zeros are added if the number of digits is less than the expected. |
Month
| Number of Letters | Parsing | Output |
|---|---|---|
| 1 | One to two digits, for example, 1, 01, and 11. | One to two digits, for example, 1 and 11. |
| 2 | Two digits, for example, 01 and 11. | Two digits, for example, 01 and 11. |
| 3 | An abbreviation of month, for example, Jan and Dec. | An abbreviation of month, for example, Jan and Dec. |
| 4 | A full name of month, for example, January and December. | A full name of month, for example, January and December. |
Numeric Value
The representing range of data of different number types varies according to actual values.
| Number of Letters | Parsing | Output |
|---|---|---|
| 1 | One to two digits, for example, 1, 01, and 11. | One to two digits, for example, 1 and 11. |
| 2 | Two digits, for example, 01 and 11. | Two digits, for example, 01 and 11. |
Fractional Second
| Number of Letters | Parsing | Output |
|---|---|---|
| 1 | Three digits, for example, 001 and 123 as milliseconds. | Three digits, for example, 001 and 123 as milliseconds. |
| 2 | Six digits, for example, 000001 and 123456 as microseconds. | Six digits, for example, 000001 and 123456 as microseconds. |
| 3 | Nine digits, for example, 000000001 and 123456789 as nanoseconds. | Nine digits, for example, 000000001 and 123456789 as nanoseconds. |
Time Zone Offset
| Number of Letters | Parsing | Output |
|---|---|---|
| 1 | Formats such as +08 and -08. | Formats such as +08 and -08. If not in full hours, the offset is truncated. |
| 2 | Formats such as +08:00 and -08:59. | Format such as +08:00 and -08:59. If not in full minutes, the offset is truncated. |
| 3 | Formats such as +08:00:00 and -08:59:59. | Formats such as +08:00:00 and -08:59:59. |
| 4 | Formats such as +08:00:00 and -08:59:59. | Formats such as case2 and case3. If the offset is 0, Z is output. |
Time zone name and time zone ID
| Number of Letters | Parsing | Output |
|---|---|---|
| 1, 2, or 3 | Formats such as CST and GMT. | Formats such as CST and GMT. |
| 4 | Time zone ID, in the format such as Asia/Shanghai. | Time zone ID, in the format such as Asia/Shanghai. |
Zero hour offset
| Number of Letters | Parsing | Output |
|---|---|---|
| 1 | Formats such as GMT+0 and GMT+10. | Formats such as GMT+0 and GMT+10. |
| 2 | Formats such as GMT+00:00 and GMT+10:00. | Formats such as GMT+00:00 and GMT+10:00. |
| 3 | Formats such as GMT+00:00:00 and GMT+10:00:00. | Formats such as GMT+00:00:00 and GMT+10:00:00. |
| 4 | Format with the number of 2 or 3. | Format with the number of 2 or 3. |
Number of Days in a Year
| Number of Letters | Parsing | Output |
|---|---|---|
| 1 | One to three digits, for example, 1, 01, and 001. | One to three digits, for example, 1, 12, and 123. |
| 2 | Two to three digits, for example, 01 and 001. | Two to three digits, for example, 001, 012, and 123. |
Number of Days in Weeks
| Number of Letters | Parsing | Output |
|---|---|---|
| 1 | One digit, for example, 0 and 6. 0 indicates Sunday, and the others indicate Monday to Saturday. | One digit, for example, 0 and 6. 0 indicates Sunday, and the others indicate Monday to Saturday. |
| 2 | Two digits, for example, 00 and 06. 00 indicates Sunday, and the others indicate Monday to Saturday. | Two digits, for example, 00 and 06. 00 indicates Sunday, and the others indicate Monday to Saturday. |
| 3 | An abbreviation of week, for example, Sun and Sat. | An abbreviation of week, for example, Sun and Sat. |
| 4 | A full name of week, for example, Sunday and Saturday. | A full name of week, for example, Sunday and Saturday. |
Calendar Era
| Number of Letters | Parsing | Output |
|---|---|---|
| 1 | A. | A. |
| 2 | AD. | AD. |
| 3 | Anno Domini. | Anno Domini. |
API List
Interface
| Name | Description |
|---|---|
| DurationExtension | Returns a multiplication with the new Duration instance as the product when extending the Duration instance as a right operand. |
Class
| Name | Description |
|---|---|
| DateTimeFormat | Provides time formats for parsing and generating DateTime. |
| TimeZone | Indicates the time zone. It records the time offsets of a region relative to the zero time zone at different times. It provides functionality such as loading a time zone from the system and customizing a time zone. |
Enumeration
| Name | Description |
|---|---|
| DayOfWeek | Indicates a day of a week. It provides functionality of Int64 type conversion, equality judgment, and obtaining the string representation of enumerated values. |
| Month | Indicates a month, that is, a month in a year. It provides functionality of Int64 type conversion and calculation, equality judgment, and obtaining the string representation of enumerated values. |
Struct
| Name | Description |
|---|---|
| DateTime | Indicates a date-time, which is a time type describing a point of time. It provides functionality such as time zone-based date-time reading, calculation, comparison, and conversion, as well as serialization and deserialization. |
| Duration | Indicates a time interval, which is a time type describing a period of time. It provides common static instances and functionality such as calculation and comparison. |
| MonoTime | Indicates monotonic time, which is a time type used to measure the elapsed time. Similar to an ever-running stopwatch, it provides functionality such as obtaining current time, calculation, and comparison. |
Exception Class
| Name | Description |
|---|---|
| InvalidDataException | Indicates an exception that occurs during time zone loading. |
| TimeParseException | Indicates an exception that occurs during time string parsing. |
Interface
interface DurationExtension
public interface DurationExtension {
operator func *(r: Duration): Duration
}
Description: Returns a multiplication with the new Duration instance as the product when extending the Duration instance as a right operand.
operator func *(Duration)
operator func *(r: Duration): Duration
Description: Implements a multiplication of a T instance (T is a type for implementing the DurationExtension interface) and a Duration instance, that is, T * Duration.
Parameters:
- r: Duration: right operand of the multiplication
Returns:
- Duration: product of the
Tinstance multiplied byr
Throws:
- ArithmeticException: If the result of the multiplication exceeds the range specified by Duration, this exception is thrown.
extend Float64 <: DurationExtension
extend Float64 <: DurationExtension
Description: Extends the multiplication with a Float64 instance as the left operand and a Duration instance as the right operand.
Parent Type:
operator func *(Duration)
public operator func *(r: Duration): Duration
Description: Implements a multiplication of a Float64 instance and a Duration instance, that is, Float64 * Duration.
Parameters:
Returns:
Throws:
- ArithmeticException: If the result of the multiplication exceeds the range specified by Duration, this exception is thrown.
extend Int64 <: DurationExtension
extend Int64 <: DurationExtension
Description: Extends the multiplication with an Int64 instance as the left operand and a Duration instance as the right operand.
Parent Type:
operator func *(Duration)
public operator func *(r: Duration): Duration
Description: Implements a multiplication of an Int64 instance and a Duration instance, that is, Int64 * Duration.
For example, if 2 * Duration.second is returned, it indicates a Duration instance with the time interval of two seconds.
Parameters:
- r: Duration: right operand of the multiplication
Returns:
Throws:
- ArithmeticException: If the result of the multiplication exceeds the range specified by Duration, this exception is thrown.
Class
class DateTimeFormat
public class DateTimeFormat {
public static prop RFC1123: DateTimeFormat
public static prop RFC3339: DateTimeFormat
public prop format: String
}
Description: Provides time formats for parsing and generating DateTime.
static prop RFC1123
public static prop RFC1123: DateTimeFormat
Description: Provides the RFC1123 time format. The time string format is www, dd MMM yyyy HH:mm:ss z.
Type: DateTimeFormat
static prop RFC3339
public static prop RFC3339: DateTimeFormat
Description: Provides the RFC3339 time format. The time string format is yyyy-MM-ddTHH:mm:ssOOOO.
Type: DateTimeFormat
prop format: String
public prop format: String
Description: Specifies the string format of the DateTimeFormat instance.
Type: String
static func of(String)
public static func of(format: String): DateTimeFormat
Description: Creates a specific DateTimeFormat instance based on a string.
For details about the string formats, see Time String Formats.
Parameters:
- format: String: string format
Returns:
- DateTimeFormat: time format
Throws:
- IllegalArgumentException: If the input parameter format does not meet the requirement on the number of letters in Time String Formats, this exception is thrown.
class TimeZone
public class TimeZone <: ToString & Equatable<TimeZone> {
public init(id: String, offset: Duration)
}
Description: Indicates the time zone. It records the time offsets of a region relative to the zero time zone at different times. It provides functionality such as loading a time zone from the system and customizing a time zone.
Parent Type:
static let Local
public static let Local: TimeZone
Description: Obtains the local time zone.
Local obtains a time zone ID from the system environment variable TZ and loads the time zone from the system time zone file based on the time zone ID. The behavior is the same as that of the load function.
The value of the environment variable TZ is in a standard time zone ID format, for example, Asia/Shanghai. All operating systems adopt the same time zone ID format.
If the environment variable TZ is not set or is empty, the rules for loading the local time zone are as follows:
- In the Linux or Unix like system, the system path /etc/localtime is loaded. The time zone name is the same as the name of the relative path to which /etc/localtime points, for example, Asia/Shanghai.
- If the loading fails or the system is Windows, the time zone whose ID is UTC&offset is returned, for example, UTC+08:00 corresponding to Asia/Shanghai.
Type: TimeZone
static let UTC
public static let UTC: TimeZone
Description: Obtains the UTC time zone.
Type: TimeZone
prop id
public prop id: String
Description: Obtains the time zone ID associated with the current TimeZone instance.
Type: String
init(String, Duration)
public init(id: String, offset: Duration)
Description: Constructs a custom TimeZone instance using the specified time zone ID and offset.
Parameters:
- id: String: time zone ID A slash (/) is used as the delimiter, for example, Asia/Shanghai. All operating systems adopt the same rule.
- offset: Duration: offset relative to the UTC time zone, accurate to seconds. The offset is positive for time zones east of UTC and negative for time zones west of UTC. The value range is (-25 * Duration.hour, 26 * Duration.hour).
Throws:
- IllegalArgumentException: This exception is thrown if the input
idis a null string oroffsetexceeds the valid range.
static func load(String)
public static func load(id: String): TimeZone
Description: Loads the time zone specified by the parameter id from the system.
- In Linux, macOS, and HarmonyOS systems, if the environment variable CJ_TZPATH exists, the time zone file is loaded from the path specified by the environment variable. If there are multiple values for the environment variable separated by colons (:), the time zone files are searched based on the order of paths, and the time zone file first found is loaded. Otherwise, the time zone is loaded from the system time zone file at /usr/share/zoneinfo for Linux and macOS and /system/etc/zoneinfo for HarmonyOS.
- In Windows, you need to download and compile a Time Zone File, and set the environment variable CJ_TZPATH to point to the zoneinfo directory. If there are multiple values for the environment variable separated by semicolons (;), the time zone files are searched based on the order of paths, and the time zone file first found is loaded. Otherwise, an exception occurs.
Parameters:
- id: String: time zone ID
Returns:
- TimeZone: time zone
Throws:
- IllegalArgumentException: This exception is thrown if the parameter
idis empty, its length exceeds 4096 bytes, or the parameter does not comply with the standard time zone ID format. - InvalidDataException: This exception is thrown if loading the time zone file fails (for example, the file cannot be found or parsing the file fails).
static func loadFromPaths(String, Array<String>)
public static func loadFromPaths(id: String, tzpaths: Array<String>): TimeZone
Description: Loads the time zone specified by the parameter id from the time zone file directory specified by the parameter tzpaths.
During time zone loading, the time zone is loaded from the path of the first time zone file that is successfully read. The time zone file format must comply with the Time Zone Information Format.
Parameters:
Returns:
- TimeZone: time zone to be loaded
Throws:
- IllegalArgumentException: This exception is thrown if the parameter
idis empty, its length exceeds 4096 bytes, or the parameter does not comply with the standard time zone ID format. - InvalidDataException: This exception is thrown if loading the time zone file fails (for example, the file cannot be found or parsing the file fails).
static func loadFromTZData(String, Array<UInt8>)
public static func loadFromTZData(id: String, data: Array<UInt8>): TimeZone
Description: Constructs a custom TimeZone instance using the specified time zone ID and time zone data. id can be any valid string, and data must comply with the IANA time zone file format. If the loading is successful, the TimeZone instance is created. Otherwise, an exception is thrown.
Parameters:
- id: String: time zone ID
- data: Array<UInt8>: data complying with the Time Zone Information Format
Returns:
- TimeZone: time zone to be loaded
Throws:
- IllegalArgumentException: If
idis empty, this exception is thrown. - InvalidDataException: If
dataparsing fails, this exception is thrown.
func toString()
public func toString(): String
Description: Obtains the string representation of the time zone ID in the current TimeZone instance.
Returns:
- String: string representation of the time zone ID
operator func !=(TimeZone)
public operator func !=(r: TimeZone): Bool
Description: Checks whether the reference of the current TimeZone instance is not equal to the reference of r.
Parameters:
Returns:
- Bool:
trueorfalse. If the reference of the current TimeZone instance is not equal to the reference ofr,trueis returned; otherwise,falseis returned.
operator func ==(TimeZone)
public operator func ==(r: TimeZone): Bool
Description: Checks whether the reference of the current TimeZone instance is equal to the reference of r.
Parameters:
Returns:
- Bool:
trueorfalse. If the reference of the current TimeZone instance is equal to the reference ofr,trueis returned. Otherwise,falseis returned.
Enumeration
enum DayOfWeek
public enum DayOfWeek <: ToString {
| Sunday
| Monday
| Tuesday
| Wednesday
| Thursday
| Friday
| Saturday
}
Description: Indicates a day of a week. It provides functionality of Int64 type conversion, equality judgment, and obtaining the string representation of enumerated values.
Parent Type:
Friday
Friday
Description: Constructs a DayOfWeek instance indicating Friday.
Monday
Monday
Description: Constructs a DayOfWeek instance indicating Monday.
Saturday
Saturday
Description: Constructs a DayOfWeek instance indicating Saturday.
Sunday
Sunday
Description: Constructs a DayOfWeek instance indicating Sunday.
Thursday
Thursday
Description: Constructs a DayOfWeek instance indicating Thursday.
Tuesday
Tuesday
Description: Constructs a DayOfWeek instance indicating Tuesday.
Wednesday
Wednesday
Description: Constructs a DayOfWeek instance indicating Wednesday.
static func of(Int64)
public static func of(dayOfWeek: Int64): DayOfWeek
Description: Obtains the DayOfWeek instance corresponding to the parameter dayOfWeek.
Parameters:
- dayOfWeek: Int64: integer representation of a day of a week. The valid range is [0, 6]. 0 indicates Sunday, and 1 to 6 indicate Monday to Saturday respectively.
Returns:
Throws:
- IllegalArgumentException: If the parameter
dayOfWeekis not within the range of [0, 6], this exception is thrown.
func toString()
public func toString(): String
Description: Returns the string representation of the current DayOfWeek instance. For example, "Monday" indicates Monday.
Returns:
func value()
public func value(): Int64
Description: Obtains the integer representation of the current DayOfWeek instance. Sunday is represented by 0, and Monday to Saturday are represented by 1 to 6 respectively.
Returns:
operator func !=(DayOfWeek)
public operator func !=(r: DayOfWeek): Bool
Description: Checks whether the current DayOfWeek and r indicate different days of a week.
Parameters:
Returns:
- Bool:
trueorfalse. If the current DayOfWeek instance is not equal tor,trueis returned; otherwise,falseis returned.
operator func ==(DayOfWeek)
public operator func ==(r: DayOfWeek): Bool
Description: Checks whether the current DayOfWeek and r indicate the same day of a week.
Parameters:
Returns:
- Bool:
trueorfalse. If the current DayOfWeek instance is equal tor,trueis returned; otherwise,falseis returned.
enum Month
public enum Month <: ToString {
| January
| February
| March
| April
| May
| June
| July
| August
| September
| October
| November
| December
}
Description: Indicates a month, that is, a month in a year. It provides functionality of Int64 type conversion and calculation, equality judgment, and obtaining the string representation of enumerated values.
Parent Type:
April
April
Description: Constructs a Month instance indicating April.
August
August
Description: Constructs a Month instance indicating August.
December
December
Description: Constructs a Month instance indicating December.
February
February
Description: Constructs a Month instance indicating February.
January
January
Description: Constructs a Month instance indicating January.
July
July
Description: Constructs a Month instance indicating July.
June
June
Description: Constructs a Month instance indicating June.
March
March
Description: Constructs a Month instance indicating March.
May
May
Description: Constructs a Month instance indicating May.
November
November
Description: Constructs a Month instance indicating November.
October
October
Description: Constructs a Month instance indicating October.
September
September
Description: Constructs a Month instance indicating September.
static func of(Int64)
public static func of(mon: Int64): Month
Description: Obtains the Month instance corresponding to the parameter mon.
Parameters:
- mon: Int64: integer representation of a month. The valid range is [1, 12], indicating the 12 months in a year.
Returns:
Throws:
- IllegalArgumentException: If the parameter
monis not within the range of [1, 12], this exception is thrown.
func toString()
public func toString(): String
Description: Returns the string representation of the current Month instance. For example, "January" indicates January.
Returns:
func value()
public func value(): Int64
Description: Obtains the integer representation of the current Month instance. January to December are represented by 1 to 12 respectively.
Returns:
operator func !=(Month)
public operator func !=(r: Month): Bool
Description: Checks whether the current Month instance and r indicate different months.
Parameters:
Returns:
operator func +(Int64)
public operator func +(n: Int64): Month
Description: Calculates the calendar month that is n months later than the current calendar month (n is a positive number). If n is a negative number, it indicates a month earlier than the current month.
Parameters:
- n: Int64: number of months
Returns:
- Month: month that is
nmonths later
operator func -(Int64)
public operator func -(n: Int64): Month
Description: Calculates the calendar month that is n months earlier than the current calendar month (n is a positive number). If n is a negative number, it indicates a month later than the current month.
Parameters:
- n: Int64: number of months
Returns:
- Month: month that is
nmonths earlier
operator func ==(Month)
public operator func ==(r: Month): Bool
Description: Checks whether the current Month instance and r indicate the same month.
Parameters:
Returns:
- Bool:
trueorfalse. If the current Month instance is equal tor,trueis returned; otherwise,falseis returned.
Struct
struct DateTime
public struct DateTime <: ToString & Hashable & Comparable<DateTime>
Description: Indicates a date-time, which is a time type describing a point of time. It provides functionality such as time zone-based date-time reading, calculation, comparison, and conversion, as well as serialization and deserialization.
-
DateTime is an immutable type that contains date, time, and time zone information. It represents a time range of [-999,999,999-01-01T00:00:00.000000000, 999,999,999-12-31T23:59:59.999999999], which is applicable to any valid time zone.
-
The following lists the system call functions used by the now and nowUTC functions in DateTime to obtain the current time.
System System Call Function Clock Type Linux clock_gettime CLOCK_REALTIME Windows clock_gettime CLOCK_REALTIME macOS clock_gettime CLOCK_REALTIME
Parent Type:
static prop UnixEpoch
public static prop UnixEpoch: DateTime
Description: Obtains the Unix epoch, that is, the DateTime instance that indicates 1970-01-01 00:00:00 in the zero time zone.
Type: DateTime
prop dayOfMonth
public prop dayOfMonth: Int64
Description: Obtains the day of the current month in the DateTime instance.
Type: Int64
prop dayOfWeek
public prop dayOfWeek: DayOfWeek
Description: Obtains the day of the current week in the DateTime instance.
Type: DayOfWeek
prop dayOfYear
public prop dayOfYear: Int64
Description: Obtains the day of the current year in the DateTime instance.
Type: Int64
prop hour
public prop hour: Int64
Description: Obtains the hour information in the DateTime instance.
Type: Int64
prop isoWeek
public prop isoWeek: (Int64, Int64)
Description: Obtains the ISO 8601-compliant year and the number of weeks in the year in the DateTime instance.
prop minute
public prop minute: Int64
Description: Obtains the minute information in the DateTime instance.
Type: Int64
prop month
public prop month: Month
Description: Obtains the month in the DateTime instance.
Type: Month
prop monthValue
public prop monthValue: Int64
Description: Obtains the month represented by a number in the DateTime instance.
Type: Int64
prop nanosecond
public prop nanosecond: Int64
Description: Obtains the nanosecond information in the DateTime instance.
Type: Int64
prop second
public prop second: Int64
Description: Obtains the second information in the DateTime instance.
Type: Int64
prop year
public prop year: Int64
Description: Obtains the year in the DateTime instance.
Type: Int64
prop zone
public prop zone: TimeZone
Description: Obtains the time zone associated with the DateTime instance.
Type: TimeZone
prop zoneId
public prop zoneId: String
Description: Obtains the time zone ID in the TimeZone instance associated with the DateTime instance.
Type: String
prop zoneOffset
public prop zoneOffset: Duration
Description: Obtains the time offset in the TimeZone instance associated with the DateTime instance.
Type: Duration
static func fromUnixTimeStamp(Duration)
public static func fromUnixTimeStamp(d: Duration): DateTime
Description: Obtains the date-time after the time interval specified by the parameter d since UnixEpoch.
Parameters:
- d: Duration: time interval
Returns:
Throws:
- ArithmeticException: If the result exceeds the date-time range, this exception is thrown.
static func now(TimeZone)
public static func now(timeZone!: TimeZone = TimeZone.Local): DateTime
Description: Obtains the current time of the time zone specified by the parameter timeZone. The current time obtained using this method is affected by the system time. If timing is not affected by the system time, MonoTime.now() can be used instead.
Parameters:
- timeZone!: TimeZone: time zone, which is the local time zone by default.
Returns:
- DateTime: current time of the specified time zone
static func nowUTC()
public static func nowUTC(): DateTime
Description: Obtains the current time of the UTC time zone. The current time obtained using this method is affected by the system time. If timing is not affected by the system time, MonoTime.now() can be used instead.
Returns:
- DateTime: current time of the UTC time zone
static func of(Int64, Int64, Int64, Int64, Int64, Int64, Int64, TimeZone)
public static func of(
year!: Int64,
month!: Int64,
dayOfMonth!: Int64,
hour!: Int64 = 0,
minute!: Int64 = 0,
second!: Int64 = 0,
nanosecond!: Int64 = 0,
timeZone!: TimeZone = TimeZone.Local
): DateTime
Description: Constructs a DateTime instance based on the year, month, day, hour, minute, second, nanosecond, and time zone specified by parameters.
Parameters:
- year!: Int64: year, in the value range of [-999,999,999, 999,999,999]
- month!: Int64: month, in the value range of [1, 12]
- dayOfMonth!: Int64: day, in the value range of [1, 31]. The maximum value depends on month, which can be 28, 29, 30, or 31.
- hour!: Int64: hour, in the value range of [0, 23]
- minute!: Int64: minute, in the value range of [0, 59]
- second!: Int64: second, in the value range of [0, 59]
- nanosecond!: Int64: nanosecond, in the value range of [0, 999,999,999]
- timeZone!: TimeZone: time zone
Returns:
Throws:
- IllegalArgumentException: If the parameter value exceeds the specified range, this exception is thrown.
static func of(Int64, Month, Int64, Int64, Int64, Int64, Int64, TimeZone)
public static func of(
year!: Int64,
month!: Month,
dayOfMonth!: Int64,
hour!: Int64 = 0,
minute!: Int64 = 0,
second!: Int64 = 0,
nanosecond!: Int64 = 0,
timeZone!: TimeZone = TimeZone.Local
): DateTime
Description: Constructs a DateTime instance based on the year, month, day, hour, minute, second, nanosecond, and time zone specified by parameters.
Parameters:
- year!: Int64: year, in the value range of [-999,999,999, 999,999,999]
- month!: Month: month of the Month type
- dayOfMonth!: Int64: day, in the value range of [1, 31]. The maximum value depends on month, which can be 28, 29, 30, or 31.
- hour!: Int64: hour, in the value range of [0, 23]
- minute!: Int64: minute, in the value range of [0, 59]
- second!: Int64: second, in the value range of [0, 59]
- nanosecond!: Int64: nanosecond, in the value range of [0, 999,999,999]
- timeZone!: TimeZone: time zone
Returns:
Throws:
- IllegalArgumentException: If the parameter value exceeds the specified range, this exception is thrown.
static func ofEpoch(Int64, Int64)
public static func ofEpoch(second!: Int64, nanosecond!: Int64): DateTime
Description: Constructs a DateTime instance based on the input parameters second and nanosecond. The input parameter second indicates the second part of the Unix time, and nanosecond indicates the nanosecond part of the Unix time. The Unix time counts from UnixEpoch. The value range of nanosecond cannot exceed [0, 999,999,999]. Otherwise, an exception is thrown.
Parameters:
- second!: Int64: second part of the Unix time
- nanosecond!: Int64: nanosecond part of the Unix time. The value range is [0, 999,999,999].
Returns:
Throws:
- IllegalArgumentException: If the value of
nanosecondexceeds the specified range, this exception is thrown. - ArithmeticException: If the result exceeds the date-time range, this exception is thrown.
static func ofUTC(Int64, Int64, Int64, Int64, Int64, Int64, Int64)
public static func ofUTC(
year!: Int64,
month!: Int64,
dayOfMonth!: Int64,
hour!: Int64 = 0,
minute!: Int64 = 0,
second!: Int64 = 0,
nanosecond!: Int64 = 0
): DateTime
Description: Constructs a DateTime instance of the UTC time zone based on the year, month, day, hour, minute, second, nanosecond, and time zone specified by parameters.
Parameters:
- year!: Int64: year, in the value range of [-999,999,999, 999,999,999]
- month!: Int64: month, in the value range of [1, 12]
- dayOfMonth!: Int64: day, in the value range of [1, 31]. The maximum value depends on month, which can be 28, 29, 30, or 31.
- hour!: Int64: hour, in the value range of [0, 23]
- minute!: Int64: minute, in the value range of [0, 59]
- second!: Int64: second, in the value range of [0, 59]
- nanosecond!: Int64: nanosecond, in the value range of [0, 999,999,999]
Returns:
Throws:
- IllegalArgumentException: If the parameter value exceeds the specified range, this exception is thrown.
static func ofUTC(Int64, Month, Int64, Int64, Int64, Int64, Int64)
public static func ofUTC(
year!: Int64,
month!: Month,
dayOfMonth!: Int64,
hour!: Int64 = 0,
minute!: Int64 = 0,
second!: Int64 = 0,
nanosecond!: Int64 = 0
): DateTime
Description: Constructs a DateTime instance of the UTC time zone based on the year, month, day, hour, minute, second, nanosecond, and time zone specified by parameters.
Parameters:
- year!: Int64: year, in the value range of [-999,999,999, 999,999,999]
- month!: Month: month of the Month type
- dayOfMonth!: Int64: day, in the value range of [1, 31]. The maximum value depends on month, which can be 28, 29, 30, or 31.
- hour!: Int64: hour, in the value range of [0, 23]
- minute!: Int64: minute, in the value range of [0, 59]
- second!: Int64: second, in the value range of [0, 59]
- nanosecond!: Int64: nanosecond, in the value range of [0, 999,999,999]
Returns:
Throws:
- IllegalArgumentException: If the parameter value exceeds the specified range, this exception is thrown.
static func parse(String)
public static func parse(str: String): DateTime
Description: Parses the parameter str to acquire a time. If the parsing is successful, the DateTime instance is returned.
Parameters:
- str: String: time string, in the format of
date-timeinRFC3339. It may contain fractional seconds, for example, "2023-04-10T08:00:00[.123456]+08:00" (content in[]is optional).
Returns:
Throws:
- TimeParseException: If the parsing fails, this exception is thrown.
static func parse(String, String)
public static func parse(str: String, format: String): DateTime
Description: Parses the string str based on the time format specified by format to acquire a time. If the parsing is successful, the DateTime instance is returned. For details about the parsing specifications, see "Parsing time from a string."
Parameters:
- str: String: time string, for example, 2023/04/10 08:00:00 +08:00
- format: String: time string format, for example, yyyy/MM/dd HH:mm:ss OOOO For details about the formats, see Time String Formats.
Returns:
- DateTime: DateTime instance parsed from the parameter
strbased on time format specified by the parameterformat
Throws:
- TimeParseException: This exception is thrown if the parsing fails or the same
formathas multiple values. - IllegalArgumentException: If
formatis incorrect, this exception is thrown.
static func parse(String, DateTimeFormat)
public static func parse(str: String, format: DateTimeFormat): DateTime
Description: Parses the string str based on the time format specified by format to acquire a time. If the parsing is successful, the DateTime instance is returned. For details about the parsing specifications, see "Parsing time from a string."
Parameters:
- str: String: time string, for example, 2023/04/10 08:00:00 +08:00
- format: DateTimeFormat: time format, for example, a time format corresponding to yyyy/MM/dd HH:mm:ss OOOO For details about the formats, see Time String Formats.
Returns:
- DateTime: DateTime instance parsed from the parameter
strbased on time format specified by the parameterformat
Throws:
- TimeParseException: This exception is thrown if the parsing fails or the same
formathas multiple values. - IllegalArgumentException: If
formatis incorrect, this exception is thrown.
func addDays(Int64)
public func addDays(n: Int64): DateTime
Description: Obtains the time n days after the DateTime instance, and returns a new DateTime instance.
Parameters:
Returns:
Throws:
- ArithmeticException: If the date-time
ndays after the DateTime instance exceeds a range, this exception is thrown.
func addHours(Int64)
public func addHours(n: Int64): DateTime
Description: Obtains the time n hours after the DateTime instance, and returns a new DateTime instance.
Parameters:
Returns:
Throws:
- ArithmeticException: If the date-time
nhours after the DateTime instance exceeds a range, this exception is thrown.
func addMinutes(Int64)
public func addMinutes(n: Int64): DateTime
Description: Obtains the time n minutes after the DateTime instance, and returns a new DateTime instance.
Parameters:
Returns:
Throws:
- ArithmeticException: If the date-time
nminutes after the DateTime instance exceeds a range, this exception is thrown.
func addMonths(Int64)
public func addMonths(n: Int64): DateTime
Description: Obtains the time n months after the DateTime instance, and returns a new DateTime instance.
Note:
The interval between months is not fixed. If dt is set to March 30, 2020,
dt.addMonths(1)does not return an invalid date March 31, 2020. To ensure that a valid date is returned, the last day of the current month is used, and April 30, 2020 is returned.
Parameters:
Returns:
Throws:
- ArithmeticException: If the date-time
nmonths after the DateTime instance exceeds a range, this exception is thrown.
func addNanoseconds(Int64)
public func addNanoseconds(n: Int64): DateTime
Description: Obtains the time n nanoseconds after the DateTime instance, and returns a new DateTime instance.
Parameters:
Returns:
Throws:
- ArithmeticException: If the date-time
nnanoseconds after the DateTime instance exceeds a range, this exception is thrown.
func addSeconds(Int64)
public func addSeconds(n: Int64): DateTime
Description: Obtains the time n seconds after the DateTime instance, and returns a new DateTime instance.
Parameters:
Returns:
Throws:
- ArithmeticException: If the date-time
nseconds after the DateTime instance exceeds a range, this exception is thrown.
func addWeeks(Int64)
public func addWeeks(n: Int64): DateTime
Description: Obtains the time n weeks after the DateTime instance, and returns a new DateTime instance.
Parameters:
Returns:
Throws:
Description: Obtains the time n weeks later, and returns a new DateTime instance.
func addYears(Int64)
public func addYears(n: Int64): DateTime
Description: Obtains the time n years after the DateTime instance, and returns a new DateTime instance.
Note:
The interval between years is not fixed. If dt is set to February 29, 2020,
dt.addYears(1)does not return an invalid date February 29, 2021. To ensure that a valid date is returned, the last day of the current month is used, and February 28, 2021 is returned.
Parameters:
Returns:
Throws:
- ArithmeticException: If the date-time
nyears after the DateTime instance exceeds a range, this exception is thrown.
func compare(DateTime)
public func compare(rhs: DateTime): Ordering
Description: Compares the value of a DateTime instance with that of the parameter rhs. If the value of the instance is greater, Ordering.GT is returned. If they are equal, Ordering.EQ is returned. If the value of the instance is smaller, Ordering.LT is returned.
Parameters:
Returns:
func hashCode()
public func hashCode(): Int64
Description: Obtains the hash value of a DateTime instance.
Returns:
- Int64: hash value
func inLocal()
public func inLocal(): DateTime
Description: Obtains the time of the DateTime instance in the local time zone.
Returns:
Throws:
- ArithmeticException: If the date-time specified by the DateTime instance exceeds a range, this exception is thrown.
func inTimeZone(TimeZone)
public func inTimeZone(timeZone: TimeZone): DateTime
Description: Obtains the time of the DateTime instance in the time zone specified by the parameter timeZone.
Parameters:
- timeZone: TimeZone: target time zone
Returns:
Throws:
- ArithmeticException: If the date-time specified by the DateTime instance exceeds a range, this exception is thrown.
func inUTC()
public func inUTC(): DateTime
Description: Obtains the time of the DateTime instance in the UTC time zone.
Returns:
Throws:
- ArithmeticException: If the date-time specified by the DateTime instance exceeds a range, this exception is thrown.
func toString()
public func toString(): String
Description: Returns a string indicating a DateTime instance. The string adopts the format of date-time in RFC3339. If the time contains nanosecond information (not zero), fractional seconds are returned.
Returns:
func toString(String)
public func toString(format: String): String
Description: Returns a string indicating a DateTime instance. The format is specified by the parameter format. For details about the formats, see Time String Formats.
Parameters:
- format: String: format of the returned string. The format can be yyyy/MM/dd HH:mm:ss OOOO.
Returns:
Throws:
- IllegalArgumentException: If
formatis incorrect, this exception is thrown.
func toString(DateTimeFormat)
public func toString(format: DateTimeFormat): String
Description: Returns a string indicating a DateTime instance. The format is specified by the parameter format. For details about the formats, see Time String Formats.
Parameters:
- format: DateTimeFormat: time format. The format can be yyyy/MM/dd HH:mm:ss OOOO.
Returns:
Throws:
- IllegalArgumentException: If
formatis incorrect, this exception is thrown.
func toUnixTimeStamp()
public func toUnixTimeStamp(): Duration
Description: Obtains the time interval between the current instance and UnixEpoch.
Returns:
operator func !=(DateTime)
public operator func !=(r: DateTime): Bool
Description: Checks whether the current DateTime instance is not equal to r.
If two DateTime instances are not equal, they point to different UTC time.
Parameters:
Returns:
- Bool:
trueorfalse. If the current DateTime instance is not equal tor,trueis returned; otherwise,falseis returned.
operator func +(Duration)
public operator func +(r: Duration): DateTime
Description: Implements an addition of the DateTime instance and the Duration instance, that is, DateTime + Duration.
Parameters:
- r: Duration: right operand of the addition
Returns:
Throws:
- ArithmeticException: If the result exceeds the date-time range, this exception is thrown.
operator func -(DateTime)
public operator func -(r: DateTime): Duration
Description: Implements a subtraction between DateTime types, that is, DateTime - DateTime.
Parameters:
- r: DateTime: right operand of the subtraction
Returns:
operator func -(Duration)
public operator func -(r: Duration): DateTime
Description: Implements a subtraction between the DateTime type and the Duration type, that is, DateTime - Duration.
Parameters:
- r: Duration: right operand of the subtraction
Returns:
Throws:
- ArithmeticException: If the result exceeds the date-time range, this exception is thrown.
operator func <(DateTime)
public operator func <(r: DateTime): Bool
Description: Checks whether the current DateTime instance is earlier than r (the DateTime instance pointing to an earlier UTC time is smaller).
Parameters:
Returns:
- Bool:
trueorfalse. If the current DateTime instance is earlier thanr,trueis returned; otherwise,falseis returned.
operator func <=(DateTime)
public operator func <=(r: DateTime): Bool
Description: Checks whether the current DateTime instance is earlier than or equal to r (the DateTime instance pointing to an earlier UTC time is smaller).
Parameters:
Returns:
- Bool:
trueorfalse. If the current DateTime instance is earlier than or equal tor,trueis returned; otherwise,falseis returned.
operator func ==(DateTime)
public operator func ==(r: DateTime): Bool
Description: Checks whether the current DateTime instance is equal to r.
If two DateTime instances are equal, they point to the same UTC time.
Parameters:
Returns:
- Bool:
trueorfalse. If the current DateTime instance is equal tor,trueis returned; otherwise,falseis returned.
operator func >(DateTime)
public operator func >(r: DateTime): Bool
Description: Checks whether the current DateTime instance is later than r (the DateTime instance pointing to a later UTC time is greater).
Parameters:
Returns:
- Bool:
trueorfalse. If the current DateTime instance is later thanr,trueis returned; otherwise,falseis returned.
operator func >=(DateTime)
public operator func >=(r: DateTime): Bool
Description: Checks whether the current DateTime instance is later than or equal to r (the DateTime instance pointing to a later UTC time is greater).
Parameters:
Returns:
- Bool:
trueorfalse. If the current DateTime instance is later than or equal tor,trueis returned; otherwise,falseis returned.
struct Duration
public struct Duration <: ToString & Hashable & Comparable<Duration>
Description: Indicates a time interval, which is a time type describing a period of time. It provides common static instances and functionality such as calculation and comparison.
Notes:
- Duration specifies a range from Duration.Min to Duration.Max, numerically, [-263, 263) in seconds. It is accurate to nanoseconds.
- Duration in each unit of time is represented by an integer. If the actual value is not an integer, the value is rounded up to the smaller absolute value. For example, if the
toHoursmethod is called on the Duration instance indicating1 hour 30 minutes 46 seconds, 1 instead of 1.5 or 2 is returned.
Parent Type:
static prop Max
public static prop Max: Duration
Description: Specifies the Duration instance of the maximum time interval.
Type: Duration
static prop Min
public static prop Min: Duration
Description: Specifies the Duration instance of the minimum time interval.
Type: Duration
static prop Zero
public static prop Zero: Duration
Description: Specifies the Duration instance of a 0-nanosecond time interval.
Type: Duration
static prop day
public static prop day: Duration
Description: Specifies the Duration instance of a 1-day time interval.
Type: Duration
static prop hour
public static prop hour: Duration
Description: Specifies the Duration instance of a 1-hour time interval.
Type: Duration
static prop microsecond
public static prop microsecond: Duration
Description: Specifies the Duration instance of a 1-microsecond time interval.
Type: Duration
static prop millisecond
public static prop millisecond: Duration
Description: Specifies the Duration instance of a 1-millisecond time interval.
Type: Duration
static prop minute
public static prop minute: Duration
Description: Specifies the Duration instance of a 1-minute time interval.
Type: Duration
static prop nanosecond
public static prop nanosecond: Duration
Description: Specifies the Duration instance of a 1-nanosecond time interval.
Type: Duration
static prop second
public static prop second: Duration
Description: Specifies the Duration instance of a 1-second time interval.
Type: Duration
static func since(DateTime)
public static func since(t: DateTime): Duration
Description: Calculates the time interval counted from t to the current time.
Parameters:
Returns:
static func until(DateTime)
public static func until(t: DateTime): Duration
Description: Calculates the time interval counted from the current time to t.
Parameters:
Returns:
func abs()
public func abs(): Duration
Description: Returns a new Duration instance. Its value is the absolute value of the current Duration instance.
Returns:
Throws:
- ArithmeticException: If the current Duration instance is equal to Duration.Min, this exception is thrown because the absolute value exceeds the range of Duration.
func compare(Duration)
public func compare(rhs: Duration): Ordering
Description: Compares the current Duration instance with another Duration instance. If the current Duration instance is greater, Ordering.GT is returned. If they are equal, Ordering.EQ is returned. If the current Duration instance is smaller, Ordering.LT is returned.
Parameters:
Returns:
func hashCode()
public func hashCode(): Int64
Description: Obtains the hash value of the current Duration instance.
Returns:
func toDays()
public func toDays(): Int64
Description: Obtains the integer value of the current Duration instance, in units of days.
Returns:
func toHours()
public func toHours(): Int64
Description: Obtains the integer value of the current Duration instance, in units of hours.
Returns:
func toMicroseconds()
public func toMicroseconds(): Int64
Description: Obtains the integer value of the current Duration instance, in units of microseconds.
Returns:
Throws:
- ArithmeticException: If the value of the Duration instance in units of microseconds exceeds the range specified by Int64, this exception is thrown.
func toMilliseconds()
public func toMilliseconds(): Int64
Description: Obtains the integer value of the current Duration instance, in units of milliseconds.
Returns:
Throws:
- ArithmeticException: If the value of the Duration instance in units of milliseconds exceeds the range specified by Int64, this exception is thrown.
func toMinutes()
public func toMinutes(): Int64
Description: Obtains the integer value of the current Duration instance, in units of minutes.
Returns:
func toNanoseconds()
public func toNanoseconds(): Int64
Description: Obtains the integer value of the current Duration instance, in units of nanoseconds. The value is rounded up to the smaller absolute value.
Returns:
Throws:
- ArithmeticException: If the value of the Duration instance in units of nanoseconds exceeds the range specified by Int64, this exception is thrown.
func toSeconds()
public func toSeconds(): Int64
Description: Obtains the integer value of the current Duration instance, in units of seconds.
Returns:
func toString()
public func toString(): String
Description: Obtains the string representation of the current Duration instance. For example, "1d2h3m4s5ms6us7ns" indicates 1 day, 2 hours, 3 minutes, 4 seconds, 5 milliseconds, 6 microseconds, and 7 nanoseconds. A unit of time followed by 0 is omitted. Particularly, 0s is returned if all units of time are followed by 0.
Returns:
operator func !=(Duration)
public operator func !=(r: Duration): Bool
Description: Checks whether the current Duration instance is not equal to r.
Parameters:
Returns:
- Bool:
trueorfalse. If the current Duration instance is not equal tor,trueis returned; otherwise,falseis returned.
operator func *(Float64)
public operator func *(r: Float64): Duration
Description: Implements a multiplication of a Duration instance and a Float64 instance, that is, Duration * Float64.
Parameters:
- r: Float64: right operand of the multiplication
Returns:
Throws:
- ArithmeticException: If the result of the multiplication exceeds the range specified by Duration, this exception is thrown.
operator func *(Int64)
public operator func *(r: Int64): Duration
Description: Implements a multiplication of a Duration instance and an Int64 instance, that is, Duration * Int64.
Parameters:
- r: Int64: right operand of the multiplication
Returns:
Throws:
- ArithmeticException: If the result of the multiplication exceeds the range specified by Duration, this exception is thrown.
operator func +(Duration)
public operator func +(r: Duration): Duration
Description: Implements an addition of Duration instances, that is, Duration + Duration.
Parameters:
- r: Duration: right operand of the addition
Returns:
Throws:
- ArithmeticException: If the result of the addition exceeds the range specified by Duration, this exception is thrown.
operator func -(Duration)
public operator func -(r: Duration): Duration
Description: Implements a subtraction between Duration types, that is, Duration - Duration.
Parameters:
- r: Duration: right operand of the subtraction
Returns:
Throws:
- ArithmeticException: If the result of the subtraction exceeds the range specified by Duration, this exception is thrown.
operator func /(Duration)
public operator func /(r: Duration): Float64
Description: Implements a division between Duration instances, that is, Duration / Duration.
Parameters:
- r: Duration: divisor
Returns:
Throws:
- IllegalArgumentException: If
ris equal to Duration.Zero, this exception is thrown.
operator func /(Float64)
public operator func /(r: Float64): Duration
Description: Implements a division between a Duration instance and a Float64 instance, that is, Duration/Float64.
Parameters:
- r: Float64: divisor
Returns:
Throws:
- IllegalArgumentException: If
ris 0, this exception is thrown. - ArithmeticException: If the result of the division exceeds the range specified by Duration, this exception is thrown.
operator func /(Int64)
public operator func /(r: Int64): Duration
Description: Implements a division between a Duration instance and an Int64 instance, that is, Duration/Int64.
Parameters:
- r: Int64: divisor
Returns:
Throws:
- IllegalArgumentException: If
ris 0, this exception is thrown. - ArithmeticException: If the result of the division exceeds the range specified by Duration, this exception is thrown.
operator func <(Duration)
public operator func <(r: Duration): Bool
Description: Checks whether the current Duration instance is less than r.
Parameters:
Returns:
- Bool:
trueorfalse. If the current Duration instance is less thanr,trueis returned; otherwise,falseis returned.
operator func <=(Duration)
public operator func <=(r: Duration): Bool
Description: Checks whether the current Duration instance is less than or equal to r.
Parameters:
Returns:
- Bool:
trueorfalse. If the current Duration instance is less than or equal tor,trueis returned; otherwise,falseis returned.
operator func ==(Duration)
public operator func ==(r: Duration): Bool
Description: Checks whether the current Duration instance is equal to r.
Parameters:
Returns:
- Bool:
trueorfalse. If the current Duration instance is equal tor,trueis returned; otherwise,falseis returned.
operator func >(Duration)
public operator func >(r: Duration): Bool
Description: Checks whether the current Duration instance is greater than r.
Parameters:
Returns:
- Bool:
trueorfalse. If the current Duration instance is greater thanr,trueis returned; otherwise,falseis returned.
operator func >=(Duration)
public operator func >=(r: Duration): Bool
Description: Checks whether the current Duration instance is greater than or equal to r.
Parameters:
Returns:
- Bool:
trueorfalse. If the current Duration instance is greater than or equal tor,trueis returned; otherwise,falseis returned.
struct MonoTime
public struct MonoTime <: Hashable & Comparable<MonoTime>
Description: Indicates monotonic time, which is a time type used to measure the elapsed time. Similar to an ever-running stopwatch, it provides functionality such as obtaining current time, calculation, and comparison.
-
MonoTime specifies a range from Duration.Zero to Duration.Max, numerically, [0, 263) in seconds. It is accurate to nanoseconds. MonoTime created using the now method is always later than MonoTime created earlier using this method. It is usually used for performance tests and time-prioritized task queues.
-
The following lists the system call functions used by the now function in MonoTime to obtain the current time.
System System Call Function Clock Type Linux clock_gettime CLOCK_MONOTONIC Windows clock_gettime CLOCK_MONOTONIC macOS clock_gettime CLOCK_MONOTONIC
Parent Type:
static func now()
public static func now(): MonoTime
Description: Obtains MonoTime corresponding to the current time.
Returns:
func compare(MonoTime)
public func compare(rhs: MonoTime): Ordering
Description: Compares the value of a MonoTime instance with that of the parameter rhs. If the value of the instance is greater, Ordering.GT is returned. If they are equal, Ordering.EQ is returned. If the value of the instance is smaller, Ordering.LT is returned.
Parameters:
Returns:
func hashCode()
public func hashCode(): Int64
Description: Obtains the hash value of the current MonoTime instance.
Returns:
- Int64: hash value
operator func !=(MonoTime)
public operator func !=(r: MonoTime): Bool
Description: Checks whether the current MonoTime instance is not equal to r.
Parameters:
- r: MonoTime: monotonic time
Returns:
- Bool:
trueorfalse. If the current MonoTime instance is not equal tor,trueis returned; otherwise,falseis returned.
operator func +(Duration)
public operator func +(r: Duration): MonoTime
Description: Implements an addition of the MonoTime instance and the Duration instance, that is, MonoTime + Duration.
Parameters:
- r: Duration: time interval
Returns:
- MonoTime: monotonic time after the time interval specified by the parameter
r
Throws:
- ArithmeticException: If the result exceeds the monotonic time range, this exception is thrown.
operator func -(Duration)
public operator func -(r: Duration): MonoTime
Description: Implements a subtraction between the MonoTime instance and the Duration instance, that is, MonoTime - Duration.
Parameters:
- r: Duration: time interval
Returns:
- MonoTime: monotonic time before the time interval specified by the parameter
r
Throws:
- ArithmeticException: If the result exceeds the monotonic time range, this exception is thrown.
operator func -(MonoTime)
public operator func -(r: MonoTime): Duration
Description: Implements a subtraction between MonoTime instances, that is, MonoTime - MonoTime.
Parameters:
- r: MonoTime: monotonic time
Returns:
- Duration: time elapsed from the current instance to
r
operator func <(MonoTime)
public operator func <(r: MonoTime): Bool
Description: Checks whether the current MonoTime instance is earlier than r.
Parameters:
- r: MonoTime: monotonic time
Returns:
- Bool:
trueorfalse. If the current MonoTime instance is earlier thanr,trueis returned; otherwise,falseis returned.
operator func <=(MonoTime)
public operator func <=(r: MonoTime): Bool
Description: Checks whether the current MonoTime instance is earlier than or equal to r.
Parameters:
- r: MonoTime: monotonic time
Returns:
- Bool:
trueorfalse. If the current MonoTime instance is earlier than or equal tor,trueis returned; otherwise,falseis returned.
operator func ==(MonoTime)
public operator func ==(r: MonoTime): Bool
Description: Checks whether the current MonoTime instance is equal to r.
Parameters:
- r: MonoTime: monotonic time
Returns:
- Bool:
trueorfalse. If the current MonoTime instance is equal tor,trueis returned; otherwise,falseis returned.
operator func >(MonoTime)
public operator func >(r: MonoTime): Bool
Description: Checks whether the current MonoTime instance is later than r.
Parameters:
- r: MonoTime: monotonic time
Returns:
- Bool:
trueorfalse. If the current MonoTime instance is later thanr,trueis returned; otherwise,falseis returned.
operator func >=(MonoTime)
public operator func >=(r: MonoTime): Bool
Description: Checks whether the current MonoTime instance is later than or equal to r.
Parameters:
- r: MonoTime: monotonic time
Returns:
- Bool:
trueorfalse. If the current MonoTime instance is later than or equal tor,trueis returned; otherwise,falseis returned.
Exception Class
class InvalidDataException
public class InvalidDataException <: Exception {
public init()
public init(message: String)
}
Description: Indicates an exception that occurs during time zone loading.
Parent Type:
init()
public init()
Description: Constructs an InvalidDataException instance.
init(String)
public init(message: String)
Description: Constructs an InvalidDataException instance based on the exception information specified by the parameter message.
Parameters:
- message: String: predefined message
class TimeParseException
public class TimeParseException <: Exception {
public init()
public init(message: String)
}
Description: Indicates an exception that occurs during time string parsing.
Parent Type:
init()
public init()
Description: Constructs a TimeParseException instance.
init(String)
public init(message: String)
Description: Constructs a TimeParseException instance based on the exception information specified by the parameter message.
Parameters:
- message: String: predefined message
DateTime Comparison
In this example, China Standard Time (CST, time zone ID: Asia/Shanghai) is compared with American Eastern Daylight Time (EDT, time zone ID: America/New_York).
Notes:
In this example, the TimeZone.load function is used to load the time zone information. Different dependencies exist in loading time zone information on different platforms. Setting needs to be performed as required.
import std.time.*
main() {
let tzSH = TimeZone.load("Asia/Shanghai")
let tzNY = TimeZone.load("America/New_York")
// 2024-05-25T00:00:00Z
let shanghai1 = DateTime.of(year: 2024, month: May, dayOfMonth: 25, hour: 8, timeZone: tzSH)
let new_york1 = DateTime.of(year: 2024, month: May, dayOfMonth: 24, hour: 20, timeZone: tzNY)
// 2024-05-25T01:00:00Z
let shanghai2 = DateTime.of(year: 2024, month: May, dayOfMonth: 25, hour: 9, timeZone: tzSH)
let new_york2 = DateTime.of(year: 2024, month: May, dayOfMonth: 24, hour: 21, timeZone: tzNY)
println(shanghai1 == new_york1)
println(shanghai1 != new_york2)
println(shanghai1 <= new_york2)
println(shanghai1 < new_york2)
println(shanghai2 >= new_york1)
println(shanghai2 > new_york1)
}
Running result:
true
true
true
true
true
true
Conversion Between DateTime and String
This example demonstrates how to format time by formatting the string pattern and parse time from the formatted string.
Notes:
In this example, the TimeZone.load function is used to load the time zone information. Different dependencies exist in loading time zone information on different platforms. Setting needs to be performed as required.
import std.time.*
main() {
let pattern = "yyyy/MM/dd HH:mm:ssSSS OO"
let datetime = DateTime.of(
year: 2024,
month: May,
dayOfMonth: 22,
hour: 12,
minute: 34,
second: 56,
nanosecond: 789000000,
timeZone: TimeZone.load("Asia/Shanghai")
)
let str = datetime.toString(pattern)
println(str)
println(DateTime.parse(str, pattern))
}
Running result:
2024/05/22 12:34:56789000000 +08:00
2024-05-22T12:34:56.789+08:00
Obtaining the Date-Time Information
This example demonstrates how to obtain the information about year, month, and day of date-time.
Notes:
In this example, the TimeZone.load function is used to load the time zone information. Different dependencies exist in loading time zone information on different platforms. Setting needs to be performed as required.
import std.time.*
main() {
let datetime = DateTime.of(
year: 2024,
month: May,
dayOfMonth: 22,
hour: 12,
minute: 34,
second: 56,
nanosecond: 789000000,
timeZone: TimeZone.load("Asia/Shanghai")
)
let yr = datetime.year
let mon = datetime.month
let day = datetime.dayOfMonth
let hr = datetime.hour
let min = datetime.minute
let sec = datetime.second
let ns = datetime.nanosecond
let zoneId = datetime.zoneId
let offset = datetime.zoneOffset
let dayOfWeek = datetime.dayOfWeek
let dayOfYear = datetime.dayOfYear
let (isoYear, isoWeek) = datetime.isoWeek
println("datetime is ${yr}, ${mon}, ${day}, ${hr}, ${min}, ${sec}, ${ns}, ${zoneId}, ${offset}")
println("datetime.toString() = ${datetime}")
println("${dayOfWeek}, ${dayOfYear}th day, ${isoWeek}th week of ${isoYear}")
}
Running result:
datetime is 2024, May, 22, 12, 34, 56, 789000000, Asia/Shanghai, 8h
datetime.toString() = 2024-05-22T12:34:56.789+08:00
Wednesday, 143th day, 21th week of 2024
Local Time of a Time in Different Time Zones
This example demonstrates how to convert a CST time into a UTC time and an EDT time.
Notes:
In this example, the TimeZone.load function is used to load the time zone information. Different dependencies exist in loading time zone information on different platforms. Setting needs to be performed as required.
import std.time.*
main() {
let datetime = DateTime.of(year: 2024, month: May, dayOfMonth: 22, hour: 12, timeZone: TimeZone.load("Asia/Shanghai"))
println("CST: ${datetime}")
println("UTC: ${datetime.inUTC()}")
println("EDT: ${datetime.inTimeZone(TimeZone.load("America/New_York"))}")
}
Running result:
CST: 2024-05-22T12:00:00+08:00
UTC: 2024-05-22T04:00:00Z
EDT: 2024-05-22T00:00:00-04:00
Using MonoTime for Timing
This example demonstrates how to count time using the MonoTime type.
import std.time.*
const count = 10000
main() {
let start = MonoTime.now()
for (_ in 0..count) {
DateTime.now()
}
let end = MonoTime.now()
let result = end - start
println("total cost: ${result.toNanoseconds()}ns")
}
Running result (subject to the actual result):
total cost: 951159ns
std.unicode Package
Function Description
The unicode package provides the capability of processing characters based on the unicode encoding standard.
Unicode is a character encoding standard that provides a unified encoding scheme for all languages and symbols to exchange and process text in a computer system.
The Unicode encoding standard uses a unique code point to represent each character and defines several attributes for each character, such as the category (letter, digit, and punctuation), script (Latin letter, Greek letter, and Chinese character), case mapping (uppercase or lowercase mapping), and voice change symbol (whether there is a voice change symbol, such as an accent symbol).
This package provides UnicodeExtension interface types for extending Unicode related character operations for other types. In addition, several extension methods are implemented for the Rune and String types, including character type determination and character case conversion.
API List
Interface
| Name | Description |
|---|---|
| UnicodeExtension | Specifies a Unicode character set extension interface, which is used to extend Unicode character set operations for other types. |
Interface
interface UnicodeExtension
public interface UnicodeExtension
Description: Specifies a Unicode character set extension interface, which is used to extend Unicode character set operations for other types.
It can be used to add a series of extended functions related to Unicode character sets for the Rune and String types, including character type determination, character case conversion, and whitespace character deletion.
extend Rune <: UnicodeExtension
extend Rune <: UnicodeExtension
Parent Type:
func isLetter()
public func isLetter(): Bool
Description: Checks whether a character is a Unicode alphabetic character.
Returns:
- Bool: If the character is a
Unicodealphabetic character,trueis returned; otherwise,falseis returned.
Example:
import std.unicode.*
main(): Unit {
println(r'a'.isLetter())
println(r'1'.isLetter())
}
Running result:
true
false
func isLowerCase()
public func isLowerCase(): Bool
Description: Checks whether the character is in Unicode lowercase.
Returns:
- Bool: If the character is a
Unicodelowercase character,trueis returned; otherwise,falseis returned.
Example:
import std.unicode.*
main(): Unit {
println(r'a'.isLowerCase())
println(r'A'.isLowerCase())
}
Running result:
true
false
func isNumber()
public func isNumber(): Bool
Description: Checks whether the character is a Unicode numeric character.
Returns:
- Bool: If the character is a
Unicodenumeric character,trueis returned; otherwise,falseis returned.
Example:
import std.unicode.*
main(): Unit {
println(r'a'.isNumber())
println(r'1'.isNumber())
}
Running result:
false
true
func isTitleCase()
public func isTitleCase(): Bool
Description: Determines whether a character is a Unicode title character.
Title characters in Unicode refer to a special letter form, which is used to indicate the capitalization of the first letter of each word in a title in some languages. These letters are represented by special characters, for example, U+01C5 (Dž) and U+01F1 (DZ). These characters are usually used in some Eastern European languages, such as Croatian and Serbian.
Title characters include: 0x01C5, 0x01C8, 0x01CB, 0x01F2, 0x1F88 - 0x1F8F, 0x1F98 - 0x1F9F, 0x1F98 - 0x1F9F, 0x1FA8 - 0x1FAF, 0x1FBC, 0x1FCC, and 0x1FFC.
Returns:
- Bool: If the character is a
Unicodetitle uppercase character,trueis returned; otherwise,falseis returned.
Example:
import std.unicode.*
main(): Unit {
println(r'Dž'.isTitleCase())
}
Running result:
true
func isUpperCase()
public func isUpperCase(): Bool
Description: Determines whether a character is a Unicode uppercase character.
Returns:
- Bool: If the character is a
Unicodeuppercase character,trueis returned; otherwise,falseis returned.
Example:
import std.unicode.*
main(): Unit {
println(r'a'.isUpperCase())
println(r'A'.isUpperCase())
}
Running result:
false
true
func isWhiteSpace()
public func isWhiteSpace(): Bool
Description: Checks whether a character is a Unicode whitespace character.
Whitespace characters include 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x0020, 0x0085, 0x00A0, 0X1680, 0X2000, 0X2001, 0X2002, 0X2003, 0X2004, 0X2005, 0X2006, 0X2007, 0X2008, 0X2009, 0X200A, 0X2028, 0X2029, 0X202F, 0X205F, and 0X3000.
Returns:
- Bool: If the character is a
Unicodewhitespace character,trueis returned; otherwise,falseis returned.
Example:
import std.unicode.*
main(): Unit {
println(r' '.isWhiteSpace())
}
Running result:
true
func toLowerCase()
public func toLowerCase(): Rune
Description: Obtains the Unicode lowercase character corresponding to the character.
Returns:
- Rune: lowercase character corresponding to the current character
Example:
import std.unicode.*
main(): Unit {
println(r'A'.toLowerCase())
}
Running result:
a
func toTitleCase()
public func toTitleCase(): Rune
Description: Obtains the Unicode title uppercase character corresponding to the character.
Returns:
- Rune: title uppercase character corresponding to the current character
Example:
import std.unicode.*
main(): Unit {
println(r'a'.toTitleCase())
}
Running result:
A
func toUpperCase()
public func toUpperCase(): Rune
Description: Obtains the Unicode uppercase letter corresponding to a character.
Returns:
- Rune: lowercase character corresponding to the current character
Example:
import std.unicode.*
main(): Unit {
println(r'a'.toUpperCase())
}
Running result:
A
extend String <: UnicodeExtension
extend String <: UnicodeExtension
Parent Type:
func isBlank()
public func isBlank(): Bool
Description: Checks whether the current string is empty or contains only null characters in the Unicode character set.
Whitespace characters include 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x0020, 0x0085, 0x00A0, 0X1680, 0X2000, 0X2001, 0X2002, 0X2003, 0X2004, 0X2005, 0X2006, 0X2007, 0X2008, 0X2009, 0X200A, 0X2028, 0X2029, 0X202F, 0X205F, and 0X3000.
Returns:
- Bool: If the string is null or contains only null characters,
trueis returned; otherwise,falseis returned.
Example:
import std.unicode.*
main(): Unit {
println(" \t\n\r".isBlank())
}
Running result:
true
func toLower()
public func toLower(): String
Description: Converts uppercase characters in all Unicode character sets of the current string to lowercase characters.
Returns:
- String: all-lowercase string after conversion
Throws:
- IllegalArgumentException: If the string contains an invalid UTF-8 code, this exception is thrown.
Example:
import std.unicode.*
main(): Unit {
println("AbcDEF".toLower())
}
Running result:
abcdef
func toTitle()
public func toTitle(): String
Description: Converts the title uppercase characters in the Unicode character set of the current string to title uppercase characters.
Returns:
- String: title capitalized string after conversion
Throws:
- IllegalArgumentException: If the string contains an invalid UTF-8 code, this exception is thrown.
Example:
import std.unicode.*
main(): Unit {
println("AbcDEF".toTitle())
}
Running result:
ABCDEF
func toUpper()
public func toUpper(): String
Description: Converts lowercase characters in all Unicode character sets of the current string to uppercase characters.
Returns:
- String: all-uppercase string after conversion
Throws:
- IllegalArgumentException: If the string contains an invalid UTF-8 code, this exception is thrown.
Example:
import std.unicode.*
main(): Unit {
println("AbcDEF".toUpper())
}
Running result:
ABCDEF
func trim()
public func trim(): String
Description: Removes the substring consisting of null characters at the beginning and end of the original string. For the definition of null characters, see the extended function isWhiteSpace of the Rune type.
Returns:
- String: Character string after the null characters at the beginning and the end are removed.
Throws:
- IllegalArgumentException: If no valid UTF-8 encoding exists in the string, this exception is thrown.
Example:
import std.unicode.*
main(): Unit {
println("\nx \t ".trim())
}
Running result:
x
func trimLeft()
public func trimLeft(): String
Description: Removes the substring consisting of null characters at the beginning of the original string. For the definition of null characters, see the extended function isWhiteSpace of the Rune type.
Returns:
- String: Character string after the null character at the beginning is removed.
Throws:
- IllegalArgumentException: If no valid UTF-8 encoding exists in the string, this exception is thrown.
Example:
import std.unicode.*
main(): Unit {
println(" x ".trimLeft())
}
Running result:
x
func trimRight()
public func trimRight(): String
Description: Removes the substring consisting of null characters at the end of the original string. For the definition of null characters, see the extended function isWhiteSpace of the Rune type.
Returns:
- String: Character string after the null character at the end is removed.
Throws:
- IllegalArgumentException: If no valid UTF-8 encoding exists in the string, this exception is thrown.
Example:
import std.unicode.*
main(): Unit {
println(" x ".trimRight())
}
Running result:
x
std.unittest Package
Function Description
The Unittest library is used to compile unit test code for the Cangjie project. It provides basic functions including code writing, running, and debugging, and some advanced functions for experienced users. The Cangjie unit test supports the CJC compiler (single-package compilation mode) and CJPM package manager (multi-package mode).
You can write the first unit test program following the Quick Start Guide. The document describes some basic concepts and usage and provides sample code. It also describes some advanced features, such as parameterized tests.
The following APIs are re-exported from other packages. You may import unittest alone.
APIs re-exported from the unittest.common package:
Interface
| Interface | Description |
|---|---|
| DataProvider | Specifies a component of DataStrategy, which is used to provide test data. T specifies the data type provided by the provider. |
| DataShrinker | Specifies a component of DataStrategy, which is used to reduce data during testing. T specifies the type of data processed by the shrinker. |
| DataStrategy | Specifies a strategy that provides data for parameterized tests. T specifies the data type that the strategy operates on. |
Class
| Class | Description |
|---|---|
| Configuration | Specifies an object for storing the unittest configuration data generated by the @Configure macro. Configuration is a class similar to HashMap, but its key is not of a key or value type but of a String type and its value is of any given type. |
| ConfigurationKey | Specifies a key value of a configuration item. Provides the equality comparison and hashCode methods. |
APIs re-exported from the unittest.prop_test package
Function
| Function | Description |
|---|---|
| random<T>() | Generates random data of type T. T must implement the Arbitrary<T> interface. The returned value of this function is a parameter source for parameterized tests. |
Interface
| Interface | Description |
|---|---|
| Arbitrary | Generates a random value of type T. |
| Shrink | Shrinks a T-type value to multiple "smaller" values. |
API List
Function
| Name | Description |
|---|---|
| assertCaughtUnexpectedE(String,String,String) | Records information and throws an exception if a caught exception does not meet the expectation. |
| assertEqual<T>(String, String, T, T): Unit where T <: Equatable<T> | Checks whether the expected and actual values are equal. Throws an exception if they are not. |
| csv<T>(String, Rune, Rune, Rune, Option<Rune>, Option<Array<String>>, Array<UInt64>, Array<UInt64>, Bool) | Reads the data value of type T from a CSV file, where T must be serializable. The returned value is a parameter source of the parameterized tests. |
| defaultConfiguration() | Generates default configuration information. |
| entryMain(TestPackage) | Specifies an entry function for the framework to execute test cases, for use by cjc --test. |
| expectCaughtUnexpectedE(String,String,String) | Records information without throwing any exception if a caught exception does not meet the expectation. |
| expectEqual<T>(String, String, T, T): Unit where T <: Equatable<T> | Checks whether the expected and actual values are equal. Records the comparison result without throwing any exception. |
| fail(String) | Makes the case fail and throws an exception. |
| failExpect(String) | Makes the case fail and records the information without throwing any exception. |
| json<T>(String) | Reads the data value of type T from a JSON file. T must be serializable. The returned value of this function is a parameter source of the parameterized test. |
| tsv<T>(String, Rune, Rune, Option<Rune>, Option<Array<String>>, Array<UInt64>, Array<UInt64>, Bool) | Reads the data value of type T from the TSV file. T must be serializable. The returned value of this function is a parameter source of the parameterized test. |
Interface
| Name | Description |
|---|---|
| BenchInputProvider | Specifies an interface used to handle performance testing. It requires executing specific code before each invocation of the performance test. When the input for the performance test changes, the input data must be regenerated from scratch each time. |
| BenchmarkConfig | Specifies an empty interface that differentiates certain Configuration functions as performance-related configurations. |
| BenchmarkInputMarker | Detects BenchInputProvider<T> when T is not known. |
| Generator | Generates a value of type T. |
| Measurement | Specifies an interface for collecting and analyzing various data during performance testing. The specific instance used by the performance test framework is specified by the measurement parameter of the @Configure macro. |
| TestClass | Provides the method for creating a TestSuite. |
Class
| Name | Description |
|---|---|
| Benchmark | Provides methods for creating and running individual performance test cases. |
| BenchReport | Provides capabilities for handling performance test case execution result reports. |
| CartesianProductProcessor | Specifies the Cartesian product processor. |
| ConsoleReporter | Prints the unit test case results or performance test case results to the console. |
| CsvReporter | Prints the performance test case results to a CSV file. |
| CsvRawReporter | Prints the performance test case results, which contain only a batch of raw measurement data, to a CSV file. |
| CsvStrategy | Indicates serialization implementation by DataStrategy on the CSV data format. |
| DataStrategyProcessor | Specifies a base class for all DataStrategy components. Instances of this class are created by the @Strategy macro or member function. |
| FlatMapProcessor | Specifies a processor for handling parameter data with FlatMap. |
| FlatMapStrategyProcessor | Specifies a processor for handling parameter data with FlatMap. |
| InputParameter | Specifies an input parameter object type. |
| JsonStrategy | Indicates serialization implementation by DataStrategy on the JSON data format. |
| LazyCyclicNode | Specifies an internal lazy iterator used to advance type erasure one after another in a loop. |
| MapProcessor | Processor for handling parameter data with Map. |
| PowerAssertDiagramBuilder | Specifies a builder of the PowerAssert output result. |
| RandomDataProvider | Indicates DataProvider implementation generated using random data. |
| RandomDataShrinker | Indicates DataShrinker implementation generated using random data. |
| RandomDataStrategy | Indicates DataStrategy implementation generated using random data. |
| RawStatsReporter | Specifiesa reporter for raw performance test data. It is used only within the framework. |
| Report | Specifies a base class for printing test case result reports. |
| SerializableProvider | Indicates DataProvider implementation for obtaining serialized data. |
| SimpleProcessor | Specifies a simple data strategy processor. Implementation of DataStrategyProcessor. |
| TestGroup | Provides methods for building and running test groups. |
| TestGroupBuilder | Provides methods for configuring test groups. |
| TestPackage | Specifies the test case package object. |
| TestReport | Provides the unit test result report. |
| TestSuite | Provides methods for building and executing test suites. |
| TestSuiteBuilder | Provides methods for configuring test suites. |
| UnitTestCase | Provides methods for creating and executing unit test cases. |
| XmlReporter | Prints the unit test case result data to an XML file. |
Enumeration
| Name | Description |
|---|---|
| ExplicitGcType | Specifies explicitGC configuration parameters for the @Configure macro. Indicates three GC execution methods. |
| TimeUnit | Specifies a time unit that can be used in the TimeNow class constructor. |
Struct
| Name | Description |
|---|---|
| BatchInputProvider | Specifies an input provider that generates the input for the entire benchmark batch in the buffer before execution. |
| BatchSizeOneInputProvider | Specifies a benchmark input provider that generates input before each benchmark execution. |
| GenerateEachInputProvider | Specifies a benchmark input provider that generates input before each benchmark execution. |
| ImmutableInputProvider | Specifies the simplest input provider that merely copies data for each benchmark call. It is applicable to the scenario where the benchmark test does not change the input. This is the default provider used within the framework. |
| TimeNow | Indicates implementation of Measurement, used to measure the time taken to execute a function. |
Exception Class
| Name | Description |
|---|---|
| AssertException | Specifies an exception thrown when an @Expect / @Assert check fails. |
| AssertIntermediateException | Specifies an exception thrown when a @PowerAssert check fails. |
| UnittestCliOptionsFormatException | Specifies an exception thrown when there is a format error in the console options. |
| UnittestException | Specifies a general exception for the framework. |
Function
func assertCaughtUnexpectedE(String,String,String)
public func assertCaughtUnexpectedE(
message: String,
expectedExceptions: String,
caughtException: String
): Nothing
Description: Records information and throws an exception if a caught exception does not meet the expectation.
Parameters:
- message: String: message displayed when the caught exception does not meet the expectation
- expectedExceptions: String: expected exception to be caught
- caughtException: String: exception that is actually caught
func assertEqual<T>(String, String, T, T): Unit where T <: Equatable<T>
public func assertEqual<T>(leftStr: String, rightStr: String, expected: T, actual: T): Unit where T <: Equatable<T>
Description: Checks whether the expected and actual values are equal. Throws an exception if they are not.
Parameters:
- leftStr: String: string of the expected expression
- rightStr: String: string of the actual expression
- expected: T: expected value
- actual: T: actual value
func csv<T>(String, Rune, Rune, Rune, Option<Rune>, Option<Array<String>>, Array<UInt64>, Array<UInt64>, Bool) where T <: Serializable<T>
public func csv<T>(
fileName: String,
delimiter!: Rune = ',',
quoteChar!: Rune = '"',
escapeChar!: Rune = '"',
commentChar!: Option<Rune> = None,
header!: Option<Array<String>> = None,
skipRows!: Array<UInt64> = [],
skipColumns!: Array<UInt64> = [],
skipEmptyLines!: Bool = false
): CsvStrategy<T> where T <: Serializable<T>
Description: Reads the data value of type T from a CSV file, where T must be serializable. The returned value is a parameter source for parameterized tests.
Parameters:
- fileName: String: Specifies the file path of the CSV file. It can be a relative path and has no restrictions on the file name extension.
- delimiter!: Rune: symbol used as the delimiter between elements in a row. The default value is comma (
,). - quoteChar!: Rune: symbol used to enclose elements. The default value is double quotes (
"). - escapeChar!: Rune: symbol that escapes the enclosed element. The default value is
"(double quotes). - commentChar!: Option<Rune>: comment symbol for skipping a line. It must be at the leftmost position of a row. The default value is
None(without comment symbol). - header!: Option<Array<String>>: Provides a way to override the first row.
- When the header is specified, the first row of the file is used as a data row, and the specified header is used.
- When the header is specified and the first row is skipped through
skipRows, the first row is ignored and the specified header is used. - When the header is not specified (that is,
None), the first row of the file is used as the header. This is the default value.
- skipRows!: Array<UInt64>: Specifies which rows to skip, with row numbers starting from 0. The default value is an empty array
[]. - skipColumns!: Array<UInt64>: Specifies which columns to skip, with column numbers starting from 0. If data columns are skipped and a custom header is provided, the header matches with the actual remaining columns. The default value is empty
[]. - skipEmptyLines!: Bool: Specifies whether to skip empty lines. The default value is
false.
Returns:
- an object of type CsvStrategy<T>, where T is serializable, and the data is read from the CSV file.
func defaultConfiguration()
public func defaultConfiguration(): Configuration
Description: Generates default configuration information.
Returns:
- Configuration: configuration information
func entryMain(TestPackage)
public func entryMain(testPackage: TestPackage): Int64
Description: Specifies an entry function for the framework to execute test cases, for use by cjc --test.
Parameters:
- testPackage: TestPackage: test package object
Returns:
- Int64: execution result
func expectCaughtUnexpectedE(String,String,String)
public func expectCaughtUnexpectedE(
message: String,
expectedExceptions: String,
caughtException: String
): Unit
Description: Records information without throwing any exception if a caught exception does not meet the expectation.
Parameters:
- message: String: message displayed when the caught exception does not meet the expectation
- expectedExceptions: String: expected exception to be caught
- caughtException: String: exception that is actually caught
func expectEqual<T>(String, String, T, T): Unit where T <: Equatable<T>
public func expectEqual<T>(leftStr: String, rightStr: String, expected: T, actual: T): Unit where T <: Equatable<T>
Description: Checks whether the expected and actual values are equal. Records the comparison result without throwing any exception.
Parameters:
- leftStr: String: string of the expected expression
- rightStr: String: string of the actual expression
- expected: T: expected value
- actual: T: actual value
func fail(String)
public func fail(message: String): Nothing
Description: Makes the case fail and throws an exception.
Parameters:
- message: String: failure information
func failExpect(String)
public func failExpect(message: String): Unit
Description: Makes the case fail and records information without throwing any exception.
Parameters:
- message: String: failure information
func json<T>(String) where T <: Serializable<T>
public func json<T>(fileName: String): JsonStrategy<T> where T <: Serializable<T>
Description: Reads the data value of type T from a JSON file, where T must be serializable. The returned value is a parameter source for parameterized tests.
Parameters:
- fileName: String: file path of the JSON file. It can be a relative path.
Returns:
- JsonStrategy<T>, where T is serializable, and the data is read from the JSON file.
Example:
@Test[user in json("users.json")]
func test_user_age(user: User): Unit {
@Expect(user.age, 100)
}
The following is an example json file:
[
{
"age": 100
},
{
"age": 100
}
]
Create a class that is used to test function parameters. This class implements the Serializable interface.
class User <: Serializable<User> {
User(let age: Int64) {}
public func serialize(): DataModel {
DataModelStruct()
.add(Field("age", DataModelInt(age)))
}
public static func deserialize(dm: DataModel): User {
if (let Some(dms) <- dm as DataModelStruct) {
if (let Some(age) <- dms.get("age") as DataModelInt) {
return User(age.getValue())
}
}
throw Exception("Can't deserialize user.")
}
}
Any type that implements Serializable can be used as a parameter type, including the default type.
@Test[user in json("numbers.json")]
func test(value: Int64)
@Test[user in json("names.json")]
func test(name: String)
func tsv<T>(String, Rune, Rune, Option<Rune>, Option<Array<String>>, Array<UInt64>, Array<UInt64>, Bool) where T <: Serializable<T>
public func tsv<T>(
fileName: String,
quoteChar!: Rune = '"',
escapeChar!: Rune = '"',
commentChar!: Option<Rune> = None,
header!: Option<Array<String>> = None,
skipRows!: Array<UInt64> = [],
skipColumns!: Array<UInt64> = [],
skipEmptyLines!: Bool = false
): CsvStrategy<T> where T <: Serializable<T>
Description: Reads the data value of type T from a TSV file, where T must be serializable. The returned value is a parameter source for parameterized tests.
Parameters:
- fileName: String: file path of the TSV file. It can be a relative path, and has no restrictions on the file name extension.
- quoteChar!: Rune: symbol used to enclose elements. The default value is double quotes (
"). - escapeChar!: Rune: symbol used to escape enclosed elements. The default value is double quotes (
"). - commentChar!: Option<Rune>: comment symbol used to skip a row. It must be at the very beginning of a row. The default value is
None(no comment symbol). - header!: Option<Array<String>>: Provides a way to override the first row.
- When the header is specified, the first row of the file is used as a data row, and the specified header is used.
- When the header is specified and the first row is skipped through
skipRows, the first row is ignored and the specified header is used. - When the header is not specified (that is,
None), the first row (the actual data remaining) of the file is used as the header. This is the default value.
- skipRows!: Array<UInt64>: Specifies which rows to skip, with row numbers starting from 0. The default value is an empty array
[]. - skipColumns!: Array<UInt64>: Specifies which columns to skip, with column numbers starting from 0. If data columns are skipped and a custom header is provided, the header matches with the actual remaining data columns. The default value is empty
[]. - skipEmptyLines!: Bool: Specifies whether to skip empty lines. The default value is
false.
Returns:
- CsvStrategy<T>, where T is serializable, and the data is read from the TSV file.
Example:
In unit testing, you can conduct parameterized tests by passing the CSV/TSV file path.
The data in each row of the CSV file is represented as a Serializable<T> object. The member names correspond to the column headers, and the member values are the values in the corresponding columns of the DataModelString type.
For example, consider a testdata.csv file with the following content:
username,age
Alex Great,21
Donald Sweet,28
There are several ways to serialize this data:
-
Represent the data as HashMap<String, String>.
An example is as follows:
import std.collection.HashMap import std.unittest.* import std.unittest.testmacro.* @Test[user in csv("testdata.csv")] func testUser(user: HashMap<String, String>) { @Assert(user["username"] == "Alex Great" || user["username"] == "Donald Sweet") @Assert(user["age"] == "21" || user["age"] == "28") } -
Represent the data as Serializable<T> data. Data of the String type can be deserialized into a DataModelStruct object.
An example is as follows:
import serialization.serialization.*
import std.convert.*
import std.unittest.*
import std.unittest.testmacro.*
public class User <: Serializable<User> {
public User(let name: String, let age: UInt32) {}
public func serialize(): DataModel {
let dms = DataModelStruct()
dms.add(Field("username", DataModelString(name)))
dms.add(Field("age", DataModelString(age.toString())))
return dms
}
static public func deserialize(dm: DataModel): User {
var data: DataModelStruct = match (dm) {
case dms: DataModelStruct => dms
case _ => throw DataModelException("this data is not DataModelStruct")
}
let name = String.deserialize(data.get("username"))
let age = String.deserialize(data.get("age"))
return User(name, UInt32.parse(age))
}
}
@Test[user in csv("testdata.csv")]
func testUser(user: User) {
@Assert(user.name == "Alex Great" || user.name == "Donald Sweet")
@Assert(user.age == 21 || user.age == 28)
}
Interface
interface BenchInputProvider
public interface BenchInputProvider<T> <: BenchmarkInputMarker {
mut func get(idx: Int64): T
mut func reset(max: Int64)
}
Description: Specifies the interface used to handle performance testing. handle performance testing. It requires executing specific code before each invocation of the performance test. When the input for the performance test changes, the input data must be regenerated from scratch each time. To use this function, your DataStrategy implementation should return the implementer of this interface. The recommended method is to use the @Strategy macro.
Parent Type:
mut func get(Int64)
mut func get(idx: Int64): T
Description: Obtains elements. Its execution time is included in the benchmark measurement and then excluded from the result as part of the framework overhead.
Parameters:
- idx: Int64: element index
Returns:
- T: element value
mut func reset(Int64)
mut func reset(max: Int64)
Description: Calls this function before the benchmark measurement. After this function is called, subsequent get(i) calls must successfully obtain the value of i in [0, max).
Parameters:
- max: Int64: maximum value
interface BenchmarkConfig
public interface BenchmarkConfig{}
Description: Specifies an empty interface. It differentiates certain Configuration functions as performance-related configurations.
interface BenchmarkInputMarker
public interface BenchmarkInputMarker
Description: Detects BenchInputProvider<T> when T is not known.
interface Generator<T>
public interface Generator<T> {
func next(): T
}
Description: Generates a value of type T.
func next()
func next(): T
Description: Obtains the generated value of type T.
Returns:
- T: generated value of type T
interface Measurement
public interface Measurement {
func measure(f: () -> Unit): Float64
func measureIntermediate(): Float64 { 0.0 }
func toString(f: Float64): String
}
Description: Collects and analyzes various data during performance testing. The specific instance used by the performance test framework is specified by the measurement parameter of the @Configure macro.
func measure(() -> Unit)
func measure(f: () -> Unit): Float64
Description: Returns the data measuring the f execution duration for statistical analysis.
Parameters:
- f: () -> Unit: a lambda function whose execution duration should be measured
Returns:
- Float64: measured data
func measureIntermediate()
func measureIntermediate(): Float64
Description: Measures the running time for statistical analysis.
Returns:
- Float64: measured data
func toString(Float64)
func toString(f: Float64): String
Description: Converts the floating-point representation of the measurement data into a string to be used in the performance test output.
Parameters:
- f: Float64: floating-point representation of the measurement data
Returns:
- String: string converted according to the format rule
interface Reporter
sealed interface Reporter <TReport, TReturn>
Description: Specifies a basic interface of a reporter.
interface TestClass
public interface TestClass {
func asTestSuite(): TestSuite
}
Description: Provides a method for creating a TestSuite.
func asTestSuite()
func asTestSuite(): TestSuite
Description: Provides a method for creating a TestSuite.
Returns:
- TestSuite: test suite object
Class
class Benchmark
public class Benchmark {}
Description: Provides methods for creating and running individual performance test cases.
prop name
public prop name: String
Description: Obtains the name of a test case.
Type: String
func run()
public func run(): BenchReport
Description: Runs the performance test case.
Returns:
- BenchReport: running result report
static func create(String, Configuration, () -> Unit)
public static func create(name: String, configuration!: Configuration = Configuration(), body!: () -> Unit): Benchmark
Description: Creates a performance test case object.
Parameters:
- name: String: case name
- configuration!: Configuration: test case configuration information
- body!: () -> Unit: test case executor
Returns:
- Benchmark: performance test case object
static func createParameterized<T>(String, DataStrategy<T>, Configuration, (T) -> Unit)
public static func createParameterized<T>(name: String, strategy: DataStrategy<T>, configuration!: Configuration = Configuration(), body!: (T) -> Unit): Benchmark
Description: Creates a parameterized performance test case object.
Parameters:
- name: String: case name
- strategy: DataStrategy: parameter data strategy
- configuration!: Configuration: test case configuration information
- body!: () -> Unit: test case executor
Returns:
- Benchmark: performance test case object
static func createParameterized<T>(String, DataStrategyProcessor<T>, Configuration, (T) -> Unit)
public static func createParameterized<T>(name: String, strategy: DataStrategyProcessor<T>, configuration!: Configuration = Configuration(), body!: (T) -> Unit): Benchmark
Description: Creates a parameterized performance test case object.
Parameters:
- name: String: case name
- strategy: DataStrategyProcessor: parameter data processor
- configuration!: Configuration: test case configuration information
- body!: () -> Unit: test case executor
Returns:
- Benchmark: performance test case object
class BenchReport
public class BenchReport <: Report {}
Description: Provides capabilities for handling performance test case execution result reports.
Parent Type:
func reportTo<T>(Reporter<BenchReport, T>)
public func reportTo<T>(reporter: Reporter<BenchReport, T>): T
Description: Prints the performance test case result report.
Parameters:
- reporter: Reporter<BenchReport, T> : performance test case result report
Returns:
- T: the result printed. Generally the value is of the Unit type.
class CartesianProductProcessor
public class CartesianProductProcessor<T0,T1> <: DataStrategyProcessor<(T0,T1)> {}
Description: Specifies a Cartesian product processor.
Parent Type:
- DataStrategyProcessor<(T0, T1)>
init(DataStrategyProcessor<T0>, DataStrategyProcessor<T1>)
public CartesianProductProcessor(let left: DataStrategyProcessor<T0>, let right: DataStrategyProcessor<T1>)
Description: Specifies a constructor.
Parameters:
- left: DataStrategyProcessor<T0>: data strategy processor
- right: DataStrategyProcessor<T1>: data strategy processor
class ConsoleReporter
public class ConsoleReporter <: Reporter<TestReport, Unit> & Reporter<BenchReport, Unit>{
public ConsoleReporter(let colored!: Bool = true)
}
Description: Prints the unit test case results or performance test case results to the console.
Parent Type:
init(Bool)
public ConsoleReporter(let colored!: Bool = true)
Description: Specifies a constructor.
Parameters:
- colored!: Bool: Specifies whether colored printing is used. By default, colored printing is used.
class CsvReporter
public class CsvReporter <: Reporter<BenchReport, Unit> {
public CsvReporter(let directory: Directory)
}
Description: Prints the performance test case results to a CSV file.
Parent Type:
init(Directory)
public CsvReporter(let directory: Directory)
Description: Specifies a constructor.
Parameters:
- directory: Directory: directory where the printed file is generated
class CsvRawReporter
public class CsvRawReporter <: Reporter<BenchReport, Unit> {
public CsvRawReporter(let directory: Directory)
}
Description: Prints the performance test case results, which contain only a batch of raw measurement data, to a CSV file.
Parent Type:
init(Directory)
public CsvRawReporter(let directory: Directory)
Description: Specifies a constructor.
Parameters:
- directory: Directory: directory where the printed file is generated
class CsvStrategy
public class CsvStrategy<T> <: DataStrategy<T> where T <: Serializable<T> {}
Description: Indicates serialization implementation by DataStrategy on the CSV data format.
Parent Type:
- DataStrategy<T>
func provider(Configuration)
public override func provider(configuration: Configuration): SerializableProvider<T>
Description: Generates a serialized data iterator.
Parameters:
- configuration: Configuration: data configuration information
Returns:
- SerializableProvider<T> : serialized iterator object
class DataStrategyProcessor
abstract sealed class DataStrategyProcessor<T> {}
Description: Specifies a base class for all DataStrategy components. Instances of this class are created by the @Strategy macro or member function.
prop isInfinite
protected prop isInfinite: Bool
Description: Checks whether the strategy is infinite.
Type: Bool
func intoBenchmark(String, Configuration, (T, Int64, Int64) -> Float64)
public func intoBenchmark(
caseName!: String,
configuration!: Configuration,
doRun!: (T, Int64, Int64) -> Float64
): Benchmark
Description: Specifies an auxiliary function used by the code generated by the macro. It is used to create performance test cases that use the strategy.
Parameters:
- caseName!: String: test case name
- configuration!: Configuration: configuration information
- doRun!: (T, Int64, Int64) -> Float64: performance test case executor
Returns:
- Benchmark: performance test case object
func intoUnitTestCase(String, Configuration, (T) -> Unit)
public func intoUnitTestCase(
caseName!: String,
configuration!: Configuration,
doRun!: (T) -> Unit
): UnitTestCase
Description: Specifies an auxiliary function used by the code generated by the macro. It is used to create test cases that use the strategy.
Parameters:
- caseName!: String: test case name
- configuration!: Configuration: configuration information
- doRun!: (T) -> Unit: performance test case executor
Returns:
- UnitTestCase: test case object
func lastItemInfo()
protected func lastItemInfo(): Array<InputParameter>
Description: Obtains the information about the last handled item.
Returns:
- Array<InputParameter>: information about the last handled item
func lastItem(Configuration)
protected func lastItem(configuration: Configuration): T
Description: Obtains the last handled item.
Parameters:
- configuration : Configuration: configuration information of the handling strategy
Returns:
- T: last handled item
func provide(Configuration)
protected func provide(configuration: Configuration): Iterable<T>
Description: Generates a data iterator based on the configuration information and data strategy.
Parameters:
- configuration : Configuration: configuration information of the handling strategy
Returns:
- Iterable<T>: data iterators
func shrinkLastItem(Configuration, LazyCyclicNode)
protected func shrinkLastItem(configuration: Configuration, engine: LazyCyclicNode): Iterable<T>
Description: Shrinks the last item.
Parameters:
- configuration:Configuration: configuration information
- engine : LazyCyclicNode: lazy node
Returns:
- Iterable<T>: data iterator after shrinking
static func start(DataStrategy<T>, String)
public static func start(s: DataStrategy<T>, name: String): SimpleProcessor<T>
Description: Specifies a start point for the composition and mapping of DataStrategy.
Parameters:
- s: DataStrategy<T>: data strategy
- name: String: case name
Returns:
- SimpleProcessor<T>: test case processor
static func start<U>(() -> DataStrategy<U>, String)
public static func start<U>(f: () -> DataStrategy<U>, name: String): DataStrategyProcessor<U> where U <: BenchInputProvider < T >
Description: Specifies a start point for the composition and mapping of DataStrategy.
Parameters:
- s: () -> DataStrategy<U>: closure generating the data strategy
- name: String: case name
Returns:
- DataStrategyProcessor<T>: data strategy processor
static func start(() -> DataStrategy<T>, String, Int64)
public static func start(f: () -> DataStrategy<T>, name: String, x!: Int64 = 0): SimpleProcessor<T>
Description: Specifies a start point for the composition and mapping of DataStrategy.
Parameters:
- s: () -> DataStrategy<T>: closure generating the data strategy
- name: String: case name
- x!: Int64: parameter added to reconstruct different return values
Returns:
- SimpleProcessor<T>: test case processor
static func start(() -> DataStrategyProcessor<T>, String)
public static func start(f: () -> DataStrategyProcessor<T>, name: String): DataStrategyProcessor<T>
Description: Specifies a start point for the composition and mapping of DataStrategy.
Parameters:
- s: () -> DataStrategyProcessor<T>: closure generating the data strategy processor
- name: String: case name
Returns:
- DataStrategyProcessor<T>: data strategy processor
static func start<U>(() -> DataStrategyProcessor<U>, String, Int64)
public static func start<U>(f: () -> DataStrategyProcessor<U>, name: String, x!: Int64 = 0):
DataStrategyProcessor<U> where U <: BenchInputProvider<T>
Description: Specifies a start point for the composition and mapping of DataStrategy.
Parameters:
- s: () -> DataStrategyProcessor<U> : closure generating the data strategy processor
- name: String: case name
- x!: Int64: parameter added to reconstruct different return values
Returns:
- DataStrategyProcessor<U> where U <: BenchInputProvider<T>: data strategy processor
extend <T> DataStrategyProcessor<T>
extend <T> DataStrategyProcessor<T> {}
func map<R>((T) -> R)
public func map<R>(f: (T) -> R): MapProcessor<T, R>
Description: Simply applies f to each item of the original data strategy. Shrink also occurs on the original input before mapping.
Parameters:
- f: (T) -> R: processing logic function to be applied
Returns:
- MapProcessor<T, R>: processor with
fapplied
func mapWithConfig<R>((T, Configuration) -> R)
public func mapWithConfig<R>(f: (T, Configuration) -> R): MapProcessor<T, R>
Description: Allows access to the current Configuration and applies f to each item of the original data strategy. Shrink also occurs on the original input before mapping.
Parameters:
- f: (T, Configuration) -> R: processing logic function to be applied
Returns:
- MapProcessor<T, R>: processor with
fapplied
func flatMap<R>((T) -> DataProvider<R>)
public func flatMap<R>(f: (T) -> DataProvider<R>): FlatMapProcessor<T, R>
Description: Simply applies f to each item of the original data strategy, and then flattens the result. Shrink also occurs on the original input before flatMap is applied.
Parameters:
- f: (T) -> DataProvider<R>: processing logic function to be applied
Returns:
- FlatMapProcessor<T, R> : processor with
fapplied
func flatMapStrategy((T) -> DataStrategy<R>)
public func flatMapStrategy<R>(f: (T) -> DataStrategy<R>): FlatMapStrategyProcessor<T, R>
Description: Simply applies f to each item of the original data strategy, and then flattens the result. Shrink is completed through the returned strategy rather than the original input.
Parameters:
- f: (T) -> DataStrategy<R>: processing logic function to be applied
Returns:
- FlatMapStrategyProcessor<T, R>: processor with
fapplied
func product(DataStrategyProcessor<R>)
public func product<R>(p: DataStrategyProcessor<R>): CartesianProductProcessor<T, R>
Description: Indicates a data strategy created by the Cartesian product combiner that contains all possible permutations of elements in the original strategy. For an infinite strategy, it iterates over all finite sub-strategies before advancing the infinite sub-policies. Shrink occurs independently and uniformly on each element of the original strategy.
Parameters:
- p: DataStrategyProcessor<R>: data strategy processor
Returns:
- CartesianProductProcessor<T, R>: Cartesian product processor
class FlatMapProcessor
public class FlatMapProcessor<T,R> <: DataStrategyProcessor<R> {}
Description: Specifies a processor applying FlatMap on parameter data.
Parent Type:
class FlatMapStrategyProcessor
public class FlatMapStrategyProcessor<T,R> <: DataStrategyProcessor<R> {}
Description: Specifies a processor applying FlatMap on parameter data.
Parent Type:
class InputParameter
public class InputParameter {}
Description: Specifies an input parameter object type.
class JsonStrategy
public class JsonStrategy<T> <: DataStrategy<T> where T <: Serializable<T> {}
Description: Indicates serialization implementation by DataStrategy on the JSON data format.
Parent Type:
- DataStrategy<T>
func provider(Configuration)
public override func provider(configuration: Configuration): SerializableProvider<T>
Description: Generates a serialized data iterator.
Parameters:
- configuration: Configuration: data configuration information
Returns:
- SerializableProvider<T>: serialized iterator object
class LazyCyclicNode
public open class LazyCyclicNode {}
Description: Specifies an internal lazy iterator used to advance type erasure one after another in a loop.
func advance()
protected open func advance(): ?Unit
Description: Advances by one value.
Returns:
- ?Unit: If advancement cannot be made, None is returned; otherwise, Unit is returned.
func recover()
protected open func recover(): Unit
Description: Restores or moves back by one value.
class MapProcessor
public class MapProcessor<T,R> <: DataStrategyProcessor<R> {}
Description: Specifies a processor for handling parameter data with Map.
Parent Type:
class PowerAssertDiagramBuilder
public class PowerAssertDiagramBuilder {
public init(expression: String, initialPosition: Int64)
}
Description: Specifies a constructor of the PowerAssert output result.
init(String, Int64)
public init(expression: String, initialPosition: Int64)
Description: Specifies a constructor.
Parameters:
func r<T>(T, String, Int64)
public func r<T>(value: T, exprAsText: String, position: Int64): T
Description: Records comparison data.
Parameters:
- value: T: data being recorded
- exprAsText: String: expression string
- position: Int64: position information
Returns:
- T: data being recorded
func r(String, String, Int64)
public func r(value: String, exprAsText: String, position: Int64): String
Description: Records comparison data.
Parameters:
- value: String: data being recorded
- exprAsText: String: expression string
- position: Int64: position information
Returns:
- String: recorded data
func h(Exception, String, Int64)
public func h(exception: Exception, exprAsText: String, position: Int64): Nothing
Description: Handles exceptions.
Parameters:
- exception: Exception: exception to be handled
- exprAsText: String: expression string
- position: Int64: position information
func w(Bool)
public func w(passed: Bool): Unit
Description: Returns a success result if the test case is passed; throws an exception and prints the comparison result if it fails.
Parameters:
- passed: Bool: whether the test case is passed
class RandomDataProvider
public class RandomDataProvider<T> <: DataProvider<T> where T <: Arbitrary<T> {
public RandomDataProvider(private let configuration: Configuration)
}
Description: Implements the DataProvider interface generated by random data.
Parent Type:
- DataProvider<T>
init(Configuration)
public RandomDataProvider(private let configuration: Configuration)
Description: Constructs an object for the random data provider.
Parameters:
- configuration: Configuration: configuration object, which must contain a random generator named
random, of type random.Random.
Throws:
- IllegalArgumentException: When the configuration does not contain a random instance, this exception is thrown.
prop isInfinite
public override prop isInfinite: Bool
Description: Specifies whether infinite data is generated.
Type: Bool
func provide()
public override func provide(): Iterable<T>
Description: Provides randomly generated data.
Returns:
- Iterable<T>: infinite iterator created from arbitrary instances of T
class RandomDataShrinker
public class RandomDataShrinker<T> <: DataShrinker<T> {}
Description: Indicates DataShrinker implementation generated using random data.
Parent Type:
- DataShrinker<T>
func shrinker(T)
public override func shrink(value: T): Iterable<T>
Description: Obtains the shrinker for the value.
Parameters:
- value: T: parameter value
Returns:
- Iterable<T>: If the parameter implements the Shrink interface, an iterator of the shrunk values is returned. If not, an empty array is returned.
class RandomDataStrategy
public class RandomDataStrategy<T> <: DataStrategy<T> where T <: Arbitrary<T>{}
Description: Indicates DataStrategy implementation generated using random data.
Parent Type:
- DataStrategy<T>
func provider(Configuration)
public override func provider(configuration: Configuration): RandomDataProvider<T>
Description: Obtains the provider of random data.
Parameters:
- configuration: Configuration: parameter configuration information
Returns:
- RandomDataProvider: random data provider
func shrinker(Configuration)
public override func shrinker(_: Configuration): RandomDataShrinker<T>
Description: Obtains the shrinker for random data.
Parameters:
- _: Configuration: parameter configuration information
Returns:
- RandomDataShrinker: random data shrinker
class Report
sealed abstract class Report {}
Description: Specifies a base class for printing test case result reports.
prop errorCount
public prop errorCount: Int64
Description: Obtains the number of test cases with errors.
Type: Int64
prop caseCount
public prop caseCount: Int64
Description: Obtains the number of test cases.
Type: Int64
prop passedCount
public prop passedCount: Int64
Description: Obtains the number of passed test cases.
Type: Int64
prop failedCount
public prop failedCount: Int64
Description: Obtains the number of failed test cases.
Type: Int64
prop skippedCount
public prop skippedCount: Int64
Description: Obtains the number of skipped test cases.
Type: Int64
class RawStatsReporter
public class RawStatsReporter <: Reporter<BenchReport, HashMap<String, (Float64, Float64)>> {
public RawStatsReporter()
}
Description: Reports raw performance test data. It is used only in the framework.
Parent Type:
init()
public RawStatsReporter()
Description: Specifies a constructor.
class SerializableProvider
public class SerializableProvider<T> <: DataProvider<T> where T <: Serializable<T> {}
Description: Implements the DataProvider interface for obtaining serialized data.
Parent Type:
- DataProvider<T>
prop isInfinite
public prop isInfinite: Bool
Description: Specifies whether infinite data is generated.
func provide()
public override func provide(): Iterable<T>
Description: Obtains the data iterator.
Returns:
- Iterable<T>: data iterator
class SimpleProcessor
public class SimpleProcessor<T> <: DataStrategyProcessor<T> {}
Description: Indicates simple data strategy processor implementation of DataStrategyProcessor.
Parent Type:
init(() -> DataStrategy<T>, String)
public SimpleProcessor(let buildDelegate:() -> DataStrategy<T>, let name: String)
Description: Specifies a constructor.
Parameters:
- buildDelegate : () -> DataStrategy<T>: closure generating the data strategy
- name: String: processor name
class TestGroup
public class TestGroup {}
Description: Provides methods for building and running test groups.
prop name
public prop name: String
Description: Obtains the name of a test group.
Type: String
func runBenchmarks()
public func runBenchmarks(): BenchReport
Description: Runs all performance test cases.
Returns:
- BenchReport: performance test case report
func runBenchmarks(Configuration)
public func runBenchmarks(Configuration): BenchReport
Description: Executes all performance test cases with running configurations.
Parameters:
- configuration: Configuration: running configuration
Returns:
- BenchReport: performance test case report
func runTests()
public func runTests(): TestReport
Description: Executes all unit test cases.
Returns:
- TestReport: unit test case report
func runTests(Configuration)
public func runTests(configuration: Configuration): TestReport
Description: Executes all unit test cases with running configurations.
Parameters:
- configuration: Configuration: running configuration
Returns:
- TestReport: unit test case report
static func builder(String)
public static func builder(name: String): TestGroupBuilder
Description: Creates a test group builder.
Parameters:
- name: String: test group name
Returns:
- TestGroupBuilder: test group builder
static func builder(TestGroup)
public static func builder(group: TestGroup): TestGroupBuilder
Description: Creates a test group builder.
Parameters:
- group: TestGroup: test group
Returns:
- TestGroupBuilder: test group builder
class TestGroupBuilder
public class TestGroupBuilder {}
Description: Provides methods for configuring test groups.
func add(Benchmark)
public func add(benchmark: Benchmark): TestGroupBuilder
Description: Adds performance test cases for the test group.
Parameters:
- benchmark: Benchmark: performance test case
Returns:
- TestGroupBuilder: test group builder
func add(TestSuite)
public func add(suite: TestSuite): TestGroupBuilder
Description: Adds a unit test suite for a test group.
Parameters:
- suite: TestSuite: unit test suite
Returns:
- TestGroupBuilder: test group builder
func add(UnitTestCase)
public func add(test: UnitTestCase): TestGroupBuilder
Description: Adds unit test cases for the test group.
Parameters:
- test: UnitTestCase: unit test case
Returns:
- TestGroupBuilder: test group builder
func build()
public func build(): TestGroup
Description: Builds test group objects after the configuration is complete.
Returns:
- TestGroup: test group
func configure(Configuration)
public func configure(configuration: Configuration): TestGroupBuilder
Description: Configures the configuration information for the test group.
Parameters:
- configuration: Configuration: configuration information
Returns:
- TestGroupBuilder: test group builder
func setName(String)
public func setName(name: String): TestGroupBuilder
Description: Sets a name for the test group.
Parameters:
- name: String: name
Returns:
- TestGroupBuilder: test group builder
class TestPackage
public class TestPackage {
public TestPackage(let name: String)
}
Description: Specifies a test case package object.
init(String)
public TestPackage(let name: String)
Description: Specifies a constructor.
Parameters:
- name: String: test case package name
func registerCase(() -> UnitTestCase)
public func registerCase(testCase: () -> UnitTestCase): Unit
Description: Registers unit test cases.
Parameters:
- testCase: () -> UnitTestCase : closure generating unit test cases
func registerSuite(() -> TestSuite)
public func registerSuite(suite: () -> TestSuite): Unit
Description: Registers a test suite.
Parameters:
- suite: () -> TestSuite: closure generating the test suite
func registerBench(() -> Benchmark)
public func registerBench(bench: () -> Benchmark): Unit
Description: Registers performance test cases.
Parameters:
- bench: () -> Benchmark: closure generating performance test cases
class TestReport
public class TestReport <: Report {}
Description: Reports the unit test result.
Parent Type:
func reportTo<T>(Reporter<TestReport, T>)
public func reportTo<T>(reporter: Reporter<TestReport, T>): T
Description: Prints the unit test execution report.
Parameters:
- reporter : Reporter<TestReport, T>: printer for unit test reports
Returns:
- T: Unit
class TestSuite
public class TestSuite {}
Description: Provides methods for building and executing test suites.
prop name
public prop name: String
Description: Obtains the name of a test suite.
Type: String
func runBenchmarks()
public func runBenchmarks(): BenchReport
Description: Runs all performance test cases.
Returns:
- BenchReport: performance test result
func runBenchmarks(Configuration)
public func runBenchmarks(configuration: Configuration): BenchReport
Description: Runs all performance test cases with configuration information.
Parameters:
- configuration : Configuration: running configuration information.
Returns:
- BenchReport: running results of the performance test cases
func runTests()
public func runTests(): TestReport
Description: Runs the test suite.
Returns:
- TestReport: running result of the test suite
func runTests(Configuration)
public func runTests(configuration: Configuration): TestReport
Description: Runs the test suite with configuration information.
Parameters:
- configuration : Configuration: running configuration information.
Returns:
- TestReport: running result of the test suite
static func builder(String)
public static func builder(name: String): TestSuiteBuilder
Description: Creates a test suite builder.
Parameters:
- name: String: test suite name
Returns:
- TestSuiteBuilder: test suite builder
static func builder(TestSuite)
public static func builder(suite: TestSuite): TestSuiteBuilder
Description: Creates a test suite builder.
Parameters:
- suite: TestSuite: test suite
Returns:
- TestSuiteBuilder: test suite builder
class TestSuiteBuilder
public class TestSuiteBuilder {}
Description: Provides methods for configuring test suites.
add(Benchmark)
public func add(benchmark: Benchmark): TestSuiteBuilder
Description: Adds performance cases to a test suite.
Parameters:
- benchmark: Benchmark: performance test case
Returns:
- TestGroupBuilder: test group builder
add(UnitTestCase)
public func add(test: UnitTestCase): TestSuiteBuilder
Description: Adds unit test cases to a test suite.
Parameters:
- test: UnitTestCase: unit test case
Returns:
- TestGroupBuilder: test group builder
afterAll(() -> Unit)
public func afterAll(body: () -> Unit): TestSuiteBuilder
Description: Adds to a test suite a lifecycle management closure to be executed after all test cases have been completed.
Parameters:
- body: () -> Unit: executor
Returns:
- TestGroupBuilder: test group builder
afterEach(() -> Unit)
public func afterEach(body: () -> Unit): TestSuiteBuilder
Description: Adds to a test suite a lifecycle management closure to be executed after each test case has been completed.
Parameters:
- body: () -> Unit: executor
Returns:
- TestGroupBuilder: test group builder
afterEach((String) -> Unit)
public func afterEach(body: (String) -> Unit): TestSuiteBuilder
Description: Adds to a test suite a lifecycle management closure to be executed after each test case has been completed.
Parameters:
- body: (String) -> Unit: executor
Returns:
- TestGroupBuilder: test group builder
beforeAll(() -> Unit)
public func beforeAll(body: () -> Unit): TestSuiteBuilder
Description: Adds to a test suite a lifecycle management closure to be executed before the execution of all test cases.
Parameters:
- body: () -> Unit: executor
Returns:
- TestGroupBuilder: test group builder
beforeEach(() -> Unit)
public func beforeEach(body: () -> Unit): TestSuiteBuilder
Description: Adds to a test suite a lifecycle management closure to be executed before the execution of each test case.
Parameters:
- body: () -> Unit: executor
Returns:
- TestGroupBuilder: test group builder
beforeEach((String) -> Unit)
public func beforeEach(body: (String) -> Unit): TestSuiteBuilder
Description: Adds to a test suite a lifecycle management closure to be executed before the execution of each test case.
Parameters:
- body: (String) -> Unit: executor
Returns:
- TestGroupBuilder: test group builder
build()
public func build(): TestSuite
Description: Constructs a test suite after the configuration is complete.
Returns:
- TestSuite: test suite
configure(Configuration)
public func configure(configuration: Configuration): TestSuiteBuilder
Description: Adds configuration information to a test suite.
Parameters:
- configuration: Configuration: test configuration information
Returns:
- TestGroupBuilder: test group builder
setName(String)
public func setName(name: String): TestSuiteBuilder
Description: Sets a name for the test suite.
Parameters:
- name: String: test suite name
Returns:
- TestGroupBuilder: test group builder
class UnitTestCase
public class UnitTestCase {}
Description: Provides methods for creating and executing unit test cases.
prop name
public prop name: String
Description: Obtains the name of a unit test.
Type: String
func run()
public func run(): TestReport
Description: Runs unit test cases.
Returns:
- TestReport: unit test execution result report
static func create(String, Configuration, () -> Unit)
public static func create(name: String, configuration!: Configuration = Configuration(), body!: () -> Unit): UnitTestCase
Description: Creates a unit test case.
Parameters:
- name: String: test case name
- configuration!: Configuration: test case configuration information
- body!: () -> Unit: test case executor
Returns:
- UnitTestCase: unit test case object
static func createParameterized<T>(String, DataStrategy<T>, Configuration, (T) -> Unit)
public static func createParameterized<T>(name: String, strategy: DataStrategy<T>, configuration!: Configuration = Configuration(), body!: (T) -> Unit): UnitTestCase
Description: Creates a parameterized unit test case.
Parameters:
- name: String: test case name
- strategy: DataStrategy: parameter data strategy
- configuration!: Configuration: test case configuration information
- body!: () -> Unit: test case executor
Returns:
- UnitTestCase: unit test case object
static func createParameterized<T>(String, DataStrategyProcessor<T>, Configuration, (T) -> Unit)
public static func createParameterized<T>(name: String, strategy: DataStrategyProcessor<T>, configuration!: Configuration = Configuration(), body!: (T) -> Unit): UnitTestCase
Description: Creates a parameterized unit test case.
Parameters:
- name: String: test case name
- strategy: DataStrategyProcessor: parameter data processor
- configuration!: Configuration: test case configuration information
- body!: () -> Unit: test case executor
Returns:
- UnitTestCase: unit test case object
class XmlReporter
public class XmlReporter <: Reporter<TestReport, Unit> {
public XmlReporter(let directory: Directory)
}
Description: Prints unit test case results to an XML file.
Parent Type:
init(Path)
public XmlReporter(let directory: Directory)
Description: Specifies a constructor.
Parameters:
- directory: Directory: directory where the printed file is generated
Enumeration
enum ExplicitGcType
public enum ExplicitGcType <: ToString {
Disabled |
Heavy |
Light
}
Description: Specifies explicitGC configuration parameters for the @Configure macro. Indicates three GC execution methods.
Parent Type:
Disabled
Disabled
Description: Indicates that GC is not explicitly called by the framework.
Heavy
Heavy
Description: Indicates that std.runtime.GC(heavy: true) is explicitly called by the framework during the execution of performance tests.
Light
Light
Description: Indicates that std.runtime.GC(heavy: false) is explicitly called by the framework during the execution of the benchmark function. This is the default setting.
func toString()
public override func toString(): String
Description: Returns a string representing the three GC execution methods.
Returns:
enum TimeUnit
public enum TimeUnit {
| Micros
| Millis
| Nanos
| Seconds
}
Description: Specifies the time unit that can be used in the TimeNow constructor.
Micros
Micros
Description: Specifies the unit microsecond.
Millis
Millis
Description: Specifies the unit millisecond.
Nanos
Nanos
Description: Specifies the unit nanosecond.
Seconds
Seconds
Description: Specifies the unit second.
Structure
struct BatchInputProvider
public struct BatchInputProvider<T> <: BenchInputProvider<T> {
public BatchInputProvider(let builder: () -> T)
}
Description: Specifies an input provider that generates the input for the entire benchmark batch in the buffer before execution.
Parent Type:
init(() -> T)
public BatchInputProvider(let builder: () -> T)
Description: Specifies a default constructor.
Parameters:
- builder: () -> T: closure used to generate the benchmark input
mut func get(Int64)
public mut func get(idx: Int64): T
Description: Obtains elements. Its execution time is included in the benchmark measurement and then excluded from the result as part of the framework overhead.
Parameters:
- idx: Int64: element index
Returns:
- T: element value
mut func reset(Int64)
public mut func reset(max: Int64)
Description: Calls this function before the benchmark measurement. After this function is called, subsequent get(i) calls must successfully obtain the value of i in [0, max).
Parameters:
- max: Int64: maximum value
struct BatchSizeOneInputProvider
public struct BatchSizeOneInputProvider<T> <: BenchInputProvider<T>{
public BatchSizeOneInputProvider(let builder: () -> T)
}
Description: Specifies a benchmark input provider that generates input before each benchmark execution. It differs from GenerateEachInputProvider in that it allows measurement when the batch size is 1. Each benchmark test call is independent, so the input generation is never included in the measurement. This structure should be used if the quality of the result provided by GenerateEachInputProvider is poor. This may happen when the time required to generate the input is much longer than the actual benchmark, or if the execution time of the input generation is highly unstable.
Parent Type:
init(() -> T)
public BatchSizeOneInputProvider(let builder: () -> T)
Description: Specifies a default constructor.
Parameters:
- builder: () -> T: lambda used to generate the benchmark test input
mut func get(Int64)
public mut func get(idx: Int64): T
Description: Obtains elements. Its execution time is included in the benchmark measurement and then excluded from the result as part of the framework overhead.
Parameters:
- idx: Int64: element index
Returns:
- T: element value
mut func reset(Int64)
public mut func reset(max: Int64)
Description: Calls this function before the benchmark measurement. After this function is called, subsequent get(i) calls must successfully obtain the value of i in [0, max).
Parameters:
- max: Int64: maximum value
struct GenerateEachInputProvider
public struct GenerateEachInputProvider<T> <: BenchInputProvider<T>{
public GenerateEachInputProvider(let builder: () -> T)
}
Description: Benchmark input provider that generates input before each benchmark execution. The generation time is included in the benchmark measurement and then excluded from the final result as part of the framework overhead.
Parent Type:
init(() -> T)
public GenerateEachInputProvider(let builder: () -> T)
Description: Specifies a default constructor.
Parameters:
- builder: () -> T: closure used to generate the benchmark input
mut func get(Int64)
public mut func get(idx: Int64): T
Description: Obtains elements. Its execution time is included in the benchmark measurement and then excluded from the result as part of the framework overhead.
Parameters:
- idx: Int64: element index
Returns:
- T: element value
mut func reset(Int64)
public mut func reset(max: Int64)
Description: Calls this function before the benchmark measurement. After this function is called, subsequent get(i) calls must successfully obtain the value of i in [0, max).
Parameters:
- max: Int64: maximum value
struct ImmutableInputProvider
public struct ImmutableInputProvider<T> <: BenchInputProvider<T> {
public ImmutableInputProvider(let data: T)
}
Description: Specifies the simplest input provider that simply copies data for each invocation of the benchmark. It is applicable to the scenario where the benchmark test does not change the input. This is the default provider used within the framework.
Parent Type:
init(T)
public ImmutableInputProvider(let data: T)
Description: Specifies a default constructor.
Parameters:
- data: T: input of the benchmark test
mut func get(Int64)
public mut func get(idx: Int64): T
Description: Obtains elements. Its execution time is included in the benchmark measurement and then excluded from the result as part of the framework overhead.
Parameters:
- idx: Int64: element index
Returns:
- T: element value
static func createOrExisting(T, Int64)
public static func createOrExisting(arg: T, x!:Int64=0): ImmutableInputProvider<T>
Description: Creates or obtains an ImmutableInputProvider object.
Parameters:
- arg: T: parameter to be copied by the provider
- x!: Int64: parameter added for overloading
Returns:
- ImmutableInputProvider<T>: input provider
static func createOrExisting<U>(U): U where U <: BenchInputProvider<T>
public static func createOrExisting<U>(arg: U): U where U <: BenchInputProvider<T>
Description: Creates or obtains a BenchInputProvider subtype object.
Parameters:
- arg: T: parameter to be copied by the provider
Returns:
- U where U <: BenchInputProvider<T>: input provider
struct TimeNow
public struct TimeNow <: Measurement {
public init()
public init(unit: ?TimeUnit)
}
Description: Implementation of Measurement, used to measure the time taken to execute a function.
Parent Type:
init()
public init()
Description: Automatically selects the default constructor for the output format.
init(?TimeUnit)
public init(unit: ?TimeUnit)
Description: Specifies the time unit to be used when the result is printed.
Parameters:
- unit: ?TimeUnit : specified time unit
func measure(() -> Unit)
public func measure(f: () -> Unit): Float64
Description: Measures the execution duration of f for statistical analysis.
Parameters:
- f: () -> Unit: executor whose execution time is calculated
Returns:
- Float64: calculated data, which is used for statistical analysis
func measureIntermediate()
public func measureIntermediate(): Float64
Description: Obtains the current time for statistical analysis.
Returns:
- Float64: calculated data, which is used for statistical analysis
func toString(Float64)
public func toString(duration: Float64): String
Description: Prints the provided time value according to the time unit.
Parameters:
- duration: Float64: time to be printed
Returns:
- String: time value formatted as a string in the specified unit
Exception
class AssertException
public class AssertException <: Exception {
public init()
public init(message: String)
}
Description: Specifies an exception thrown when an @Expect / @Assert check fails.
Parent Type:
init()
public init(message: String)
Description: Specifies a constructor.
init(String)
public init(message: String)
Description: Specifies a constructor.
Parameters:
- message: String: specified exception information
class AssertIntermediateException
public class AssertIntermediateException <: Exception {
public let expression: String
public let originalException: Exception
public let position: Int64
}
Description: Specifies an exception thrown when a @PowerAssert check fails.
Parent Type:
let expression
public let expression: String
Description: Specifies the expression to be checked.
Type: String
let originalException
public let originalException: Exception
Description: Specifies the original type information.
Type: Exception
let position
public let position: Int64
Description: Specifies the position information.
Type: Int64
func getOriginalStackTrace
public func getOriginalStackTrace(): String
Description: Obtains the original stack information.
Returns:
- String: stack information
class UnittestCliOptionsFormatException
public class UnittestCliOptionsFormatException <: UnittestException
Description: Specifies an exception thrown when there is a format error in console options.
Parent Type:
class UnittestException
public open class UnittestException <: Exception
Description: Specifies a general exception for the framework.
Parent Type:
Getting Started with Unittest
First, compile a simple Cangjie function:
package example
func add(left: Int64, right: Int64) {
return left + right
}
Save this function in an add.cj file and then write the test code for the function.
package example
@Test
func addTest() {
@Expect(add(2, 3), 5)
}
The test includes the following components:
@Testmacro, applied to theaddTestfunction, indicating that it is a test function.@Expectmacro, used as an assertion to check whether the two input parameters are equal. In this example, the two parameters are the resultadd(2, 3)and expected value5of theaddfunction.
Save the test function in an add_test.cj file and run it with the code function in add.cj.
cjc add.cj add_test.cj --test -o add_test
./add_test
Normally, you would get output similar to the following:
-------------------------------------------------------------------------------------------------
TP: default, time elapsed: 59363 ns, Result:
TCS: TestCase_addTest, time elapsed: 32231 ns, RESULT:
[ PASSED ] CASE: addTest (28473 ns)
Summary: TOTAL: 1
PASSED: 1, SKIPPED: 0, ERROR: 0
FAILED: 0
--------------------------------------------------------------------------------------------------
At this point, we have completed the test setup and execution. Now, let's take a closer look at the cjc command used to build the test.
code file to be tested
↓
cjc add.cj add_test.cj --test -o add_test
↑ ↑
| --test indicates that a binary file is generated in test mode
test file
Note that running the cjc compiler directly is not recommended for complex projects. For large-scale projects, the cjpm package manager is recommended. Take testing a cjpm project as an example.
First, create a simple cjpm project that contains a package named example. The file structure of the project is as follows (with files from the cjc example):
- src
|
+- example
|
+- add.cj
+- add_test.cj
The original files indicate that they belong to the example package. Therefore, you only need to run the following command to initialize the cjpm project:
cjpm init example example
The cjpm package manager has built-in support for running unit tests. Therefore, you can simply run:
cjpm test
This command runs all tests in packages of the project and generates output similar to the following:
--------------------------------------------------------------------------------------------------
TP: example/example, time elapsed: 60989 ns, Result:
TCS: TestCase_addTest, time elapsed: 32804 ns, RESULT:
[ PASSED ] CASE: addTest (29195 ns)
Summary: TOTAL: 1
PASSED: 1, SKIPPED: 0, ERROR: 0
FAILED: 0
--------------------------------------------------------------------------------------------------
Note that you do not need to specify --test or any other special options. By default, cjpm uses filenames in the project to determine whether the files should be compiled in test mode or normal mode. In the example package, add_test.cj is the test file, with the filename ending with _test.cj. In normal builds, binary files or libraries do not include these test files.
The unit test framework APIs are already available in the unittest package of the std module, and the macros are in the unittest.testmacro package of the std module. Therefore, you do not need to explicitly import the them to the test files.
For more information about the basic concepts of the unittest framework, see Basic Concepts and Usage of Unittest.
Basic Concepts and Usage of Unittest
Test and Test Case
Tests are entities marked with the @Test macro and are executed during the testing process. There are two types of tests in the Cangjie unittest framework: test class and test function. Test functions are simpler. Each function contains the full code for test running. Test classes are suitable for scenarios where deeper test structures are needed or where the test life cycle behavior needs to be covered.
Each test class consists of several test cases, each marked with the @TestCase macro. Each test case is a function within the test class. The same test from the previous section can be rewritten as a test class like this:
func add(a:Int64, b:Int64) {
a + b
}
@Test
class AddTests {
@TestCase
func addTest() {
@Expect(add(2, 3), 5)
}
@TestCase
func addZero() {
@Expect(add(2, 0), 2)
}
}
A test function contains a single test case. In this case, the @TestCase macro is not required.
Running this new test class in cjpm test would generate the following output:
--------------------------------------------------------------------------------------------------
TP: example/example, time elapsed: 67369 ns, Result:
TCS: AddTests, time elapsed: 31828 ns, RESULT:
[ PASSED ] CASE: addTest (25650 ns)
[ PASSED ] CASE: addZero (4312 ns)
Summary: TOTAL: 2
PASSED: 2, SKIPPED: 0, ERROR: 0
FAILED: 0
--------------------------------------------------------------------------------------------------
cjpm test success
Assertion
Assertions are individual condition checks executed within the body of a test case function to determine whether the code is functioning properly. There are two types of assertions: @Expect and @Assert. Here is an example of a failed test to illustrate their difference:
func add(a:Int64, b:Int64) {
a + b
}
@Test
func testAddIncorrect() {
@Expect(add(3, 3), 5)
}
Running this test will fail and generate the following output (only relevant parts displayed):
TCS: TestCase_testAddIncorrect, time elapsed: 4236 ns, RESULT:
[ FAILED ] CASE: testAddIncorrect (3491 ns)
Expect Failed: `(add ( 3 , 3 ) == 5)`
left: 6
right: 5
In this case, replacing @Expect with @Assert would not change much. Add a check item and run the test again:
func add(a:Int64, b:Int64) {
a + b
}
@Test
func testAddIncorrect() {
@Expect(add(3, 3), 5)
@Expect(add(5, 3), 9)
}
Running this test will fail and generate the following output (only relevant parts displayed):
TCS: TestCase_testAddIncorrect, time elapsed: 5058 ns, RESULT:
[ FAILED ] CASE: testAddIncorrect (4212 ns)
Expect Failed: `(add ( 3 , 3 ) == 5)`
left: 6
right: 5
Expect Failed: `(add ( 5 , 3 ) == 9)`
left: 8
right: 9
Both checks are reported in the output. However, if @Expect is replaced with @Assert:
func add(a:Int64, b:Int64) {
a + b
}
@Test
func testAddIncorrectAssert() {
@Assert(add(3, 3), 5)
@Assert(add(5, 3), 9)
}
The output will be:
TCS: TestCase_testAddIncorrectAssert, time elapsed: 31653 ns, RESULT:
[ FAILED ] CASE: testAddIncorrectAssert (30893 ns)
Assert Failed: `(add ( 3 , 3 ) == 5)`
left: 6
right: 5
Here, only the first @Assert check fails, and no further tests are executed. This is because the @Assert macro follows a fail-fast mechanism. Once the first assertion fails, the entire test case fails, and subsequent assertions are not checked.
This is important in large tests with many assertions, especially in loops. It allows users to be notified of the first failure without waiting for all to fail.
Choosing between @Assert and @Expect depends on the complexity of the test scenario and whether the fail-fast mechanism is required.
Below are the usage forms for using the two assertion macros provided by unittest:
- Equality assertions:
@Assert(a, b)or@Expect(a, b)checks whether the values ofaandbare equal. Ifais of typeA, andbis of typeB,Amust implement Equatable<B>. - Boolean assertions:
@Assert(c)or@Expect(c)takes aBoolparameterc, checking whether it istrueorfalse.
The second form @Assert(c) can be considered shorthand for @Assert(c, true).
Failure Assertion
Failure assertions cause the test case to fail. @Fail triggers a fail-fast mechanism. Execution of this assertion fails the test case immediately, skipping all subsequent assertions. @FailExpect causes the test case to fail, but subsequent assertions will still be checked. The parameter of these macros is a string that describes the cause of failure. The return type of @Fail is Nothing, and the return type of @FailExpect is Unit.
An example is as follows:
@Test
func validate_even_number_generator() {
let even = generateRandomEven()
if (even % 2 == 1) {
@Fail("Not even number was generated: ${even}")
}
}
The following error information is output:
[ FAILED ] CASE: validate_even_number_generator (54313 ns)
Assert Failed: `(Not even number was generated: 111)`
Expected Exception Assertion
If the expected exception type is not thrown at the assertion poi, the test case fails. @AssertThrows stops further checks, whereas @ExpectThrows continues checking. The parameters of these macros include a list of expected exception types, separated by |.If no input parameter is provided, the base class Exception is expected. The input parameter is an expression or a code block expected to throw the exception.
An example is as follows:
// No.1
@AssertThrows(throw Exception())
// Semantically equivalent to No.1
@AssertThrows[Exception](throw Exception())
@AssertThrows[IllegalStateException | NoneValueException](random.seed = 42u64)
@ExpectThrows[OutOfMemoryError](foo())
@ExpectThrows({
foo()
boo()
})
@ExpectThrows[OutOfMemoryError]({
for (i in list) {
foo(i)
}
})
Returned Type of @AssertThrows
If no more than one exception is specified, the returned type matches the expected exception type.
let e: NoneValueException = @AssertThrows[NoneValueException](foo())
If more than one exception is specified, the return type is the least common supertype of the expected exception types.
// A <: C
// B <: C
let e: C = @AssertThrows[A | B](foo())
Returned Type of @ExpectThrows
@ExpectThrows continues execution after a failure. If the number of specified exceptions does not exceed one, the returned type is Option<T>, where T is the expected exception type.
let e: ?NoneValueException = @ExpectThrows[NoneValueException](foo())
If more than one exception is specified, the return type is ?Exception:
let e: ?Exception = @ExpectThrows[NoneValueException | IllegalMemoryException](foo())
Test Life Cycle
Test cases sometimes share setup or cleanup code. The test framework supports four life cycle steps, each being set with corresponding macros. Life cycle steps can be specified only for @Test test classes, not for @Test top-level functions.
| Macro | Life cycle |
|---|---|
| @BeforeAll | Runs before all test cases. |
| @BeforeEach | Runs once before each test case. |
| @AfterEach | Runs once after each test case. |
| @AfterAll | Runs after all test cases are completed. |
These macros must be applied to members or static functions of a @Test test class. The @BeforeAll and @AfterAll functions cannot declare any parameters. The @BeforeEach and @AfterEach functions can declare one String type parameter (or none at all).
@Test
class FooTest {
@BeforeAll
func setup() {
// Code to run before the test is executed
}
}
Each macro can be applied to multiple functions within a single test class, and multiple life cycle macros can be configured on a single function. However, life cycle macros cannot be applied to functions marked with @TestCase or similar macros.
If multiple functions are marked as the same life cycle step, they can be executed in the order they are declared in the code (from top to bottom).
The test framework ensures that:
- Steps marked as Before all are executed at least once before all test cases.
- For each test case
TCin the test class: (1) Steps marked as Before each are executed once beforeTC. (2)TCis executed. (3) Steps marked as After each are executed once afterTC. - Runs the step marked with After all after all test cases in the test class.
Note:
If no test case is run, the above steps do not apply.
In the simple scenarios, steps marked as Before all and After all are executed only once. However, there are exceptions:
- For a type-parameterized test, the steps marked as before/after all will run once for each combination of type parameters.
- If multiple test cases are executed in parallel in different processes, the steps marked as before/after all are executed once in each process.
@BeforeEach and @AfterEach can access test cases being created or removed by specifying a String type parameter in the corresponding function.
@Test
class Foo {
@BeforeEach
func prepareData(testCaseName: String) {
// The name of the test case function is passed as a parameter.
// In this example, the name would be "bar".
}
@AfterEach
func cleanup() {
// Can be used without specifying a parameter.
}
@TestCase
func bar() {}
}
When configuring the life cycle for a parameterized test or parameterized performance test, note that the steps marked as before each or after each are executed only once for all parameters before or after the test case or benchmark. That is, from the perspective of the life cycle, a test body that is executed multiple times with different parameters is considered as a single test case.
If each parameter of the parameterized test requires separate setup or cleanup, the corresponding code needs to be placed in the test case body itself. Additionally, the parameters themselves can be accessed.
Test Configuration
Additional configuration may be required for other more advanced features in the unit test framework. There are three ways to configure tests:
- Using the
@Configuremacro - Using command line arguments directly during test execution or with the
cjpm testcommand - Using a
cjpmconfiguration file
Running Configuration
Usage
Run the test executable compiled by cjc, adding parameter options:
./test --bench --filter MyTest.*Test,-stringTest
--bench
By default, only the functions marked with @TestCase are executed. Only @Bench macro-qualified cases are executed when --bench is used.
--filter
To filter out a subset of tests by test class and test case, you can use --filter=test class name.test case name. For example:
--filter=*: Matches all test classes.--filter=*.*: Matches all test cases of all test classes (same result as *).--filter=*.*Test,*.*case*: Matches all test cases ending with Test or containing case in their name in all test classes.--filter=MyTest*.*Test,*.*case*,-*.*myTest: Matches all test cases ending with Test or containing case in their name in test classes starting with MyTest, but excludes test cases containing myTest.
In addition, --filter is supported whether with = or without =.
--timeout-each=timeout
Using the --timeout-each=timeout options is equivalent to applying @Timeout[timeout] to all test classes. If @Timeout[timeout] is already specified in the code, the option value will be overridden by the timeout specified in the code. That is, the timeout configuration specified in the option has a lower priority than that set in the code.
The timeout value must comply with the following syntax: number ('millis' | 's' | 'm' | 'h') For example: 10s, and 9millis etc.
- millis: millisecond
- s: second
- m: minute
- h: hour
--parallel
The --parallel option allows the test framework to run different test classes in parallel across multiple separate processes. Test classes should be independent of each other and not rely on shared mutable state. Static initialization of the program may occur multiple times. This option cannot be used together with --bench. This is because performance test cases are sensitive to underlying resources, so whether test cases are executed in parallel can affect the result of performance test cases.
--parallel=<BOOL>:<BOOL>can betrueorfalse. If it istrue, test classes can run in parallel, and the number of parallel processes is controlled by the number of CPU cores on the running system. In addition,--parallelmay be used without=true.--parallel=nCores: Specifies that the number of parallel test processes must be equal to the number of available CPU cores.--parallel=NUMBER: Specifies the number of parallel test processes. The value must be a positive integer.--parallel=NUMBERnCores: Specifies the number of parallel test processes as a multiple of the number of available CPU cores. The value must be a positive number (floating point number or integer).
--option=value
Any options provided in the --option=value format that are not listed above are processed and converted to configuration parameters according to the following rules (similar to how the @Configure macro processes parameters) and applied in sequence:
option and value are custom key-value pairs for runtime configuration options. The option can consist of any English characters connected by hyphens (-) and converted to the lower camel case format when transforming into a @Configure parameter. The rules for value formatting are as follows:
Note: The validity of option and value is not currently checked, and the priority of these options is lower than that of parameters set in the code using @Configure.
- If the
=valuepart is omitted, the option is treated asBoolvaluetrue. For example,--no-colorgenerates the configuration entrynoColor = true. - If the
valueis strictlytrueorfalse, the option is treated as aBoolvalue having the corresponding meaning:--no-color=falsegenerates the configuration entrynoColor = false. - If the
valueis a valid decimal integer, the option is treated as anInt64value. For example,--random-seed=42generates the configuration entryrandomSeed = 42. - If the
valueis a valid decimal fraction, the option is treated as aFloat64value. For example,--angle=42.0generates the configuration entryangle = 42. - If the
valueis string literal enclosed in quotes ("), the option is treated as aString, and the value is generated by decoding the string between the quotes (") with escape symbols like\n,\t, and\"handled as the corresponding characters. For example, the--mode="ABC \"2\""option generates a configuration entrymode = "ABC \"2\"". - In all other cases, the
valueis treated as aString, with the value taken exactly as provided in the option. For example,--mode=ABC23[1,2,3]generates a configuration entrymode = "ABC23[1,2,3]".
--report-path=path
This option specifies the directory where the test report is generated after execution. By default, no report is generated if the option is not explicitly specified.
--report-format=value
This option specifies the format of the report generated after the test execution.
Currently, unit testing supports only the default XML format.
For benchmark tests, the following formats are supported:
csv: The CSV report contains statistical data.csv-raw: The CSV-raw report contains only the raw batch measurements.
The default format for benchmark tests is:
csv
Parameterized Test
Getting Started with Parameterized Test
The Cangjie unittest framework supports parameterized tests in the data DSL format. The framework automatically inserts input parameters to the test.
The following is a complex code example that sorts an array using a function.
package example
func sort(array: Array<Int64>): Unit {
for (i in 0..array.size) {
var minIndex = i
for (j in i..array.size) {
if (array[j] < array[minIndex]) {
minIndex = j
}
}
(array[i], array[minIndex]) = (array[minIndex], array[i])
}
}
This function is not the optimal and most efficient sorting implementation, but it serves the purpose. Let's test it.
package example
@Test
func testSort() {
let arr = [45, 5, -1, 0, 1, 2]
sort(arr)
@Expect(arr, [-1, 0, 1, 2, 5, 45])
}
The test results show that the function works with a single input. Now test whether the sorting function still works if the array contains only equal elements.
@Test
func testAllEqual() {
let arr = [0, 0, 0, 0]
let expected = [0, 0, 0, 0]
sort(arr)
@Expect(expected, arr)
}
The test results show that the function works, but it is still unclear whether it works for arrays of all sizes. Next, test parameterized arrays of different sizes.
@Test[size in [0, 1, 50, 100, 1000]]
func testAllEqual(size: Int64) {
let arr = Array(size, item: 0)
let expected = Array(size, item: 0)
sort(arr)
@Expect(expected, arr)
}
Now, the parameterized test is complete. This is the simplest form of parameterized testing, called value-driven testing, where the values are listed directly in the code. Multiple parameters are allowed in a parameterized test. We can specify not only the size of the sorting function but also the elements to be tested.
@Test[
size in [0, 1, 50, 100, 1000],
item in (-1..20)
]
func testAllEqual(size: Int64, item: Int64) {
let arr = Array(size, item: item)
let expected = Array(size, item: item)
sort(arr)
@Expect(expected, arr)
}
Note that the value range of item is -1..20, which is not an array. So, how will the results look when this test is run? The values of size and item will be combined to form test cases and results will be returned. Therefore, be cautious not to configure too many parameters for a function; otherwise, the number of combinations may grow too large, making the tests slow. In the preceding example, the size parameter has five values and item has 21 values, resulting in a total of 21 x 5=105 combinations.
Note that value-driven testing is not limited to integer or built-in types. It can be used with any Cangjie types. Consider the following test:
@Test[
array in [
[],
[1, 2, 3],
[1, 2, 3, 4, 5],
[5, 4, 3, 2, 1],
[-1, 0],
[-20]
]
]
func testDifferentArrays(array: Array<Int64>) {
// Test whether the array is sorted.
for (i in 0..(array.size - 1)) {
@Expect(array[i] <= array[i + 1])
}
}
Here, the test data is provided directly as parameters.
Testing code with arrays can be too bulky. In some cases, it may be easier to randomly generate data for such a generic function. The following shows a more advanced form of parameterized testing: random testing. You can create a random test by replacing the value-driven arrays or ranges with the unittest.random<T>() function:
@Test[
array in random()
]
func testRandomArrays(array: Array<Int64>) {
// Test whether the array is sorted.
for (i in 0..(array.size - 1)) {
@Expect(array[i] <= array[i + 1])
}
}
This test essentially generates a large number of completely random values (200 by default) and uses them to test the code. The values are not entirely random but tend to include boundary values, such as zero, maximum and minimum values of specific types, and empty sets.
Note: It is recommended that random testing and manually written tests be used together, as practices show that they complement each other.
To better describe random testing, put the sorting function aside and write the following test code:
@Test[
array in random()
]
func testNonsense(array: Array<Int64>) {
if (array.size < 2) { return }
@Expect(array[0] <= array[1] + 500)
}
Running this test generates output similar to the following:
[ FAILED ] CASE: testNonsense (1159229 ns)
REASON: After 4 generation steps and 200 reduction steps:
array = [0, -453923686263, 0]
with randomSeed = 1702373121372171563
Expect Failed: `(array [ 0 ] <= array [ 1 ] + 500 == true)`
left: false
right: true
The result shows that the test with the array [0, -453923686263, 0] fails. Run the test again:
[ FAILED ] CASE: testNonsense (1904718 ns)
REASON: After 5 generation steps and 200 reduction steps:
array = [0, -1196768422]
with randomSeed = 1702373320782980551
Expect Failed: `(array [ 0 ] <= array [ 1 ] + 500 == true)`
left: false
right: true
The test fails again, but the values are different. Why does this happen? Because random tests are inherently random, new random values are generated each time. It may be easy to test functions with various data, but for some tests, this means that the test may pass sometimes and fail at others, making it difficult to share test results. Random testing is a powerful tool but comes with these drawbacks which we need to be clear of when using it.
How do we show results to other developers when the test results differ each time? The answer is simple—it is in the output of running the test:
with randomSeed = 1702373320782980551
A random seed is provided above, which can be used as a configuration in the test. Modify the test as follows:
@Test[
array in random()
]
@Configure[randomSeed: 1702373320782980551]
func testNonsense(array: Array<Int64>) {
if (array.size < 2) { return }
@Expect(array[0] <= array[1] + 500)
}
The output will now be:
[ FAILED ] CASE: testNonsense (1910109 ns)
REASON: After 5 generation steps and 200 reduction steps:
array = [0, -1196768422]
with randomSeed = 1702373320782980551
Expect Failed: `(array [ 0 ] <= array [ 1 ] + 500 == true)`
left: false
right: true
Note that the values generated, the steps used to generate the values, and the random seed used in this run are the same as those in the previous run. This mechanism makes random tests reproducible, allowing them to be shared in a test suite with other developers. You can also just extract data from random tests (in this example, the array values [0, -1196768422]) and write new tests using those values.
Take a quick look at the output from the failed test.
REASON: After 5 generation steps and 200 reduction steps:
array = [0, -1196768422]
with randomSeed = 1702373320782980551
The output contains the following important information:
- Number of generation steps before the test fail: This is the number of iterations running before the test fails.
- Number of reduction steps : Random tests have a mechanism for reducing test data, which makes it easier to work with and improves the readability by minimizing the data set.
- Actual data that causes the test failure: All parameters are list in order (in this case,, only one parameter
array) along with the values that actually cause the test failure. The parameters must implement the ToString interface. Otherwise, only placeholders are printed. - The random seed: Used to reproduce the random test.
Some tests are tricky and require adjustments in the random generation steps. You can control this with the following two configuration parameters: generationSteps and reductionSteps. A significant advantage of random testing is that it can run for a long time if enough steps are set, testing millions of values.
However, to avoid excessively long tests, the maximum values for both generationSteps and reductionSteps are 200 by default. These two configuration parameters allow you to set the maximum number of steps that the framework runs. For example, for a small test like the one mentioned earlier, setting a large value for the parameters may not make much sense. Previous runs have shown that the test typically fails in fewer than 10 steps.
Type-Parameterized Test
Although the current sorting implementation is designed specially for integer arrays, it could, in essence, sort any type. You can modify the sort function to make it generic, allowing it to sort arrays of any type. Note that elements must be comparable in order to be sorted.
package example
func sort<T>(array: Array<T>): Unit where T <: Comparable<T> {
for (i in 0..array.size) {
var minIndex = i
for (j in i..array.size) {
if (array[j] < array[minIndex]) {
minIndex = j
}
}
(array[i], array[minIndex]) = (array[minIndex], array[i])
}
}
All tests continue to run normally, showing that the sorting function is widely applicable. But does it really work for types other than integers?
To check this, write a new test based on the testDifferentArrays function in the previous example and use it to test other types (such as strings):
@Test[
array in [
[],
["1","2","3"],
["1","2","3","4","5"],
["5","4","3","2","1"]
]
]
func testDifferentArraysString(array: Array<String>) {
// Test whether the array is sorted.
let sorted = array.clone()
sort(sorted)
for (i in 0..(sorted.size - 1)) {
@Expect(sorted[i] <= sorted[i + 1])
}
}
The test result shows that it works correctly. Note that the subjects and assertions of the two tests are the same. Imagine how convenient it would be if the test for a generic function could also be generic.
Revisit the previous random testing example:
@Test[array in random()]
func testRandomArrays(array: Array<Int64>) {
let sorted = array.clone()
sort(sorted)
for (i in 0..(sorted.size - 1)) {
@Expect(sorted[i] <= sorted[i + 1])
}
}
The test is widely applicable. The element type is not limited to Int64, but can be any type T. For example, the elements:
- Are comparable: They need to implement Comparable<T>.
- Support random instance generation: They need to implement Arbitrary<T>.
Now, rewrite this test as a generic function:
@Test[array in random()]
func testRandomArrays<T>(array: Array<T>) where T <: Comparable<T> & Arbitrary<T> {
let sorted = array.clone()
sort(sorted)
for (i in 0..(sorted.size - 1)) {
@Expect(sorted[i] <= sorted[i + 1])
}
}
After compiling and running, we encounter an issue:
An exception has occurred:
MacroException: Generic function testRandomArrays requires a @Types macro to set up generic arguments
Naturally, to run the test, we need to provide types for testing. We can set the types using the @Types macro, allowing the test to run with Int64, Float64, and String.
@Test[array in random()]
@Types[T in <Int64, Float64, String>]
func testRandomArrays<T>(array: Array<T>) where T <: Comparable<T> & Arbitrary<T> {
let sorted = array.clone()
sort(sorted)
for (i in 0..(sorted.size - 1)) {
@Expect(sorted[i] <= sorted[i + 1])
}
}
Now, when you run the test, it compiles and generates the following output:
TCS: TestCase_testRandomArrays, time elapsed: 2491737752 ns, RESULT:
[ PASSED ] CASE: testRandomArrays<Int64> (208846446 ns)
[ PASSED ] CASE: testRandomArrays<Float64> (172845910 ns)
[ PASSED ] CASE: testRandomArrays<String> (2110037787 ns)
As you can see, each type test runs separately, as the behavior may vary greatly between types. The @Types macro can be used for any parameterized test cases, including test functions and test classes.
Reusing, Combining, and Mapping Parameter Strategies
Take HashSet as an example. Start by testing the contains function.
@Test[data in random()]
func testHashSetContains(data: Array<Int64>) {
let hashSet = HashSet(len)
hashSet.putAll(data)
for (element in data){
@Assert(hashSet.contains(element))
}
}
This works well. Now try testing the remove function.
@Test[data in random()]
func testHashSetRemove(data: Array<Int64>) {
let hashSet = HashSet(len)
hashSet.putAll(data)
for (element in data){
@Assert(hashSet.remove(element))
}
}
At first glance, it seems like the code should work fine. However, you will soon notice that it does not work correctly because the randomly generated array may contain duplicate items, which will cause the second call to remove to fail. What we need is to generate arrays without duplicates.
var counter = 0
@OverflowWrapping
func generateUniqArray(len: Int64, start: Int64){
let rng = Random(start)
let step = Int64.Max / len
counter = 0
Array(len, { _ =>
counter += rng.nextInt64()%step
counter
} )
}
@Test[len in random(), start in random()]
func testHashSetRemove(len: Int64, start: Int64) {
let data = generateUniqArray(len,start)
let hashSet = HashSet(len)
hashSet.putAll(data)
for (element in data){
@Assert(hashSet.remove(element))
}
}
However, even though the data generation has been moved to a separate function, there is still a considerable amount of duplication if it is expected to be reused across different tests. In addition, the distinction between preparation code and test code is unclear. To solve this issue, the test framework provides a convenient API in the form of the @Strategy macro, allowing existing strategies to be combined and mapped.
var counter = 0
@Strategy[len in random(), start in random()]
@OverflowWrapping
func generateUniqArray(len: Int64, start: Int64): Array<Int64>{
let rng = Random(start)
let step = Int64.Max / len
counter = 0
Array(len, { _ =>
counter += rng.nextInt64()%step
counter
} )
}
Now, you can use the strategy for this input:
@Test[data in generateUniqArray]
func testHashSetRemove(data: Array<Int64>) {
let hashSet = HashSet()
hashSet.putAll(data)
for (element in data){
@Assert(hashSet.remove(element))
}
}
@Test[data in generateUniqArray]
func testHashSetToArray(data: Array<Int64>) {
let hashSet = HashSet()
hashSet.putAll(data)
let result = hashSet.toArray()
result.sort()
data.sort()
@Assert(result == data)
}
Dynamic Test
Getting Started with Dynamic Test
The Cangjie testing framework supports dynamic tests. It allows constructing test cases when test data is unknown at the compilation time. Key use cases include:
- Creating test suites based on external data.
- Creating test suites based on parameters or configuration files.
By comparing with ordinary test cases, you can see how dynamic test cases are constructed using @TestBuilder.
The following is a simple test suite that is constructed using @Test/@TestCase:
@Test
class A {
@TestCase
func f() { @Assert(false) }
@TestCase[x in [1, 2]]
func g(x: Int) {
@Assert( x >= 1 )
}
}
Using @TestBuilder, you can create a dynamic test suite with the same logic as the preceding test suite.
@TestBuilder
public func buildCustomTestSuite(): TestSuite {
let suiteBuilder = TestSuite.builder("A")
let caseConfiguration = Configuration()
suiteBuilder.add(
UnitTestCase.create("f", configuration: caseConfiguration) { @Assert(false) })
suiteBuilder.add(
UnitTestCase.createParameterized("g", [1, 2]) { value => @Assert( value >= 1 ) })
suiteBuilder.build()
}
TestSuite creates a TestSuiteBuilder object, which supports adding test cases. Test cases are constructed using static functions in the UnitTestCase class. This class supports constructing simple test cases or parameterized test cases. Once the TestSuiteBuilder is fully configured, it finally generates a TestSuite object, which is the return value of the function marked with @TestBuilder.
After the preceding code is compiled using --test and executed, the output matches that of the test suite constructed with @Test/@TestCase.
--------------------------------------------------------------------------------------------------
TP: default, time elapsed: 121592 ns, RESULT:
TCS: A, time elapsed: 121592 ns, RESULT:
[ PASSED ] CASE: g (13969 ns)
[ FAILED ] CASE: f (91641 ns)
Assert Failed: `(false == true)`
left: false
right: true
Summary: TOTAL: 2
PASSED: 1, SKIPPED: 0, ERROR: 0
FAILED: 1, listed below:
TCS: A, CASE: f
--------------------------------------------------------------------------------------------------
@TestBuilder is subject to the following constraints:
- It can only be applied to top-level functions that are not
foreign. - The return type must be explicitly specified and must be of the
TestSuitetype. - It can be combined with the
@Configure,@Timeout, and@Parallelmacros but cannot be combined with other macros from the unittest.testmacro package.
std.unittest.mock Package
Function Description
The unittest.mock package provides a mock framework for Cangjie unit tests and provides APIs for creating and configuring mock objects. These mock objects have the same APIs as the real objects. The mock test technology supports testing code in isolation. Test cases are encoded using mock objects to eliminate external dependencies.
The mock framework has the following features:
- Creation of mock and spy objects: Production code does not need to be modified during tests.
- Simple configuration API: The behavior of mock/spy objects can be configured.
- Unit test framework: Other features of the unit test framework are seamlessly integrated. The error output is readable.
- Automatic verification of configuration behavior: In most cases, extra verification code is not needed.
- Verification API: This API is used to test complex interactions within the system.
The application scenarios are as follows:
- simplifying test settings and code;
- testing abnormal scenarios;
- replacing costly dependencies with lightweight mock objects to improve test performance; and
- verifying and testing complex scenarios, for example, sequence or number of calls.
You can compile the first mock test program by referring to Getting Started with the Mock Framework. In addition, Basic Concepts and Usage of Mock are described together with example code. Advanced use of APIs (stub) is further illustrated.
API List
Function
| Name | Description |
|---|---|
| mock<T>() | Creates a mock object of type T. By default, all member functions, attributes, or operator overloading functions of this object do not have any specific implementation. |
| mock<T>(Array<StubMode>) | Creates a mock object of type T. A parameter specifies the stub mode. |
| spy<T>(T) | Creates a spy object of type T (an extension of mock object). The members of the object have a skeleton object implemented by default. This object wraps the input object. In addition, the member functions, attributes, or operator overloading functions are implemented as calls to the corresponding member functions, attributes, or operator overloading functions of the input instance object. |
API
| Name | Description |
|---|---|
| ValueListener<T> | Provides multiple member functions to support "listening" on the parameters input in the stub signature. |
Class
| Name | Description |
|---|---|
| ActionSelector | Provides methods for specifying an operation API for member functions and permitting chain calls. |
| AnyMatcher | Specifies an arbitrary parameter matcher, that is, the stub signature permits any parameter. |
| ArgumentMatcher | Specifies an abstract class of the parameter matcher. This class and its subclasses can be used as the input parameter types of the stub signature. |
| CardinalitySelector | Provides the API for defining the number of executions of the latest behavior of a stub signature. |
| ConfigureMock | Configures mock object. |
| Continuation | Provides the API for continuing to define the behavior of a stub signature. |
| GetterActionSelector | Provides methods for specifying an operation API for the Getter function and permitting chain calls. |
| Matchers | Provides the static function for generating a matcher. The matcher object can be generated only by this static function. Matchers can be used in the stub chain. |
| MethodActionSelector | Provides methods for specifying an operation API for member functions and permitting chain calls. |
| MockFramework | Provides functions for preparing and recycling the framework required for use case execution. |
| NoneMatcher | Specifies the matcher with the parameter value of None. |
| OrderedVerifier | Specifies the class that is used to collect verification statements and can dynamically input verification behavior in the ordered function. |
| SetterActionSelector | Provides methods for specifying an operation API for the Setter function and permitting chain calls. |
| SyntheticField | Specifies a synthetic field. |
| TypedMatcher | Specifies a parameter type matcher. |
| UnorderedVerifier | Specifies the class that is used to collect verification statements and can dynamically input verification behavior in the unordered function. |
| Verify | Provides a series of static methods to support the definition of verification actions such as that, ordered, and unorder. |
| VerifyStatement | Specifies a single verification statement (that is, the foregoing verification statement) for the stub signature within the verification scope, and provides the number of executions of the stub signature specified by a member function. |
Enumeration
| Name | Description |
|---|---|
| Exhaustiveness | Specifies the verification mode of the unordered function. Two modes are available. |
| MockSessionKind | Specifies the type of a stub that can be used in MockSession. |
| StubMode | Controls the stub mode. |
Function
func mock<T>()
public func mock<T>(): T
Description: Creates a mock object of the T type. By default, all member functions, attributes, or operator overloading functions of this object do not have any specific implementation. @On can be called to specify the behavior of member functions, attributes, or operator overloading functions of this object.
Returns:
- T:
mock objectof the T type
func mock<T>(Array<StubMode>)
public func mock<T>(modes: Array<StubMode>): T
Description: Creates a mock object of the T type. A parameter specifies the stub mode.
Parameters:
- modes: Array<StubMode>: stub mode. Multiple modes may be available.
Returns:
- T:
mock objectof the T type
func spy<T>(T)
public func spy<T>(objectToSpyOn: T): T
Description: Creates a spy object of the T type (an extension of mock object). The members of the object have a "skeleton" object implemented by default. This object wraps the input object. In addition, the member functions, attributes, or operator overloading functions are implemented as calls to the corresponding member functions, attributes, or operator overloading functions of the input instance object. @On can be called to reload the behavior of member functions, attributes, or operator overloading functions of this object.
Parameters:
- objectToSpyOn: T: input instance object. By default, an implementation of this object is used.
Returns:
- T:
spy objectof the T type
Interface
interface ValueListener<T>
public interface ValueListener<T> {
func lastValue(): Option<T>
func allValues(): Array<T>
func addCallback(callback: (T) -> Unit): Unit
static func new(): ValueListener<T>
static func onEach(callback: (T) -> Unit): ValueListener<T>
}
Description: Provides multiple member functions to support "listening" on the parameters input in the stub signature. That is, a specified operation is performed on the parameter input in the stub signature in each call. The closure function in addCallback() or onEach indicates the content of the operation on the parameter. Generally, this function is used in combination with the parameter matcher generation function argThat or capture. The value listener and the parameter capturer are input in the stub signature as a type of parameter matcher. The parameter value is checked when the parameter value range of the stub signature is defined.
For example:
struct Animal {
Animal(
let name: String,
let info: String
) {}
}
abstract class AnimalUi {
func showAnimal(animal: Animal): Unit
}
let animals = [Animal("Smokey", "Cat, age: 5"), Animal("Daisy", "Dog, age: 9")]
@Test func testAnimal(): Unit {
let ui = mock<AnimalUi>()
// Define a value listener. Each value is checked, and an exception is thrown if a value does not meet the conditions.
let listener = ValueListener<Animal>.onEach { animal =>
if (animal.name == "Smokey") {
@Assert(animal.info.contains("Cat"))
}
}
// Define the stub behavior of a stub signature. The parameter matcher is a parameter capturer capable of executing the preceding value listener.
@On(ui.showAnimal(capture(listener))).returns(())
for (animal in animals) {
// Capture the input animal object, and execute the inspection behavior defined in the value listener.
ui.showAnimal(animal)
}
}
func addCallback((T) -> Unit)
func addCallback(callback: (T) -> Unit): Unit
Description: Adds a closure function to the current value listener object. This function processes the input parameter values.
Parameters:
- callback: (T) ->Unit: closure function for processing parameter values
func allValues()
func allValues(): Array<T>
Description: Returns all values processed by the current value listener object.
Returns:
- Array<T>: Returns the list of all values processed by the value listener object.
func lastValue()
func lastValue(): Option<T>
Description: Returns the last value processed by the current value listener object.
Returns:
- Option<T>: last value processed by the value listener object. If the value does not exist, None is returned.
func new()
static func new(): ValueListener<T>
Description: Creates a new value listener object not containing any closure method for processing parameters.
Returns:
- ValueListener<T>: value listener object
func onEach((T) -> Unit)
static func onEach(callback: (T) -> Unit): ValueListener<T>
Description: Creates a new value listener object containing one closure method for processing parameters.
Parameters:
- callback: (T) ->Unit: closure function for processing parameter values
Returns:
- ValueListener<T>: value listener object
Class
class ActionSelector
public sealed abstract class ActionSelector {}
Description: Provides methods for specifying an operation API for member functions and permitting chain calls. The input parameter is the @On macro call expression of the call expression of a member function of mock object or spy object. The instance of ActionSelector is returned. That is, APIs in this class or its subclasses may insert stub code for member functions.
func fails()
func fails(): Unit
Description: Specifies that a test fails when a stub signature is called. The AssertionException is thrown when execution reaches the stub signature.
class AnyMatcher
public class AnyMatcher <: ArgumentMatcher {}
Description: Specifies an arbitrary parameter matcher, that is, the stub signature accepts any parameter.
Parent Type:
func matchesAny(Any)
public func matchesAny(_: Any)
Description: Matches any value of any type.
Parameters:
- _: Any: input parameter to be checked It is any value of any type.
Returns:
- Bool:
true
extend AnyMatcher
extend AnyMatcher {}
Description: Extends AnyMatcher.
func value<T>()
public func value<T>(): T
Description: Specifies the return value of the parameter matcher to be called by the framework.
Returns:
- T: value that matches the actual input parameter type
class ArgumentMatcher
public abstract class ArgumentMatcher {}
Description: Specifies an abstract class of the parameter matcher. This class and its subclasses can be used as the input parameter types of the stub signature.
func withDescription(String)
public func withDescription(description: String): ArgumentMatcher
Description: Configures the descriptive information of exceptions thrown by the parameter matcher.
Parameters:
- description: String: descriptive information
Returns:
- ArgumentMatcher: parameter matcher
func forParameter(String)
public func forParameter(name: String): ArgumentMatcher
Description: Configures the name of the matched parameter.
Parameters:
- name: String: name of the matched parameter
Returns:
- ArgumentMatcher: parameter matcher
func matchesAny(Any)
public func matchesAny(arg: Any)
Description: Matches any value of any type.
Parameters:
- arg: Any: input parameter to be checked It is any value of any type.
Returns:
- Bool: match result
class CardinalitySelector
public class CardinalitySelector<A> where A <: ActionSelector {}
Description: Provides the API for specifying the number of executions of the latest behavior of a stub signature. For example, @On(foo.bar()).returns("Predefined value").atLeastOnce() . For ease of expression, the latest behavior of the stub signature is referred to as the "stub behavior" below. This API provides the following verification capabilities:
- If the number of times the stub signature is called exceeds a specified value, ExpectationFailedException is thrown immediately.
- If the number of times the stub signature is called is less than expected, the framework throws ExceptionFailedException after the test case is executed.
func anyTimes()
func anyTimes(): Unit
Description: Specifies that the stub behavior can be executed for any number of times. This function does not verify the number of times the stub signature is called.
func atLeastOnce()
func atLeastOnce(): Unit
Description: Specifies that the stub behavior is executed at least once. If it is verified that the stub behavior is not executed, an exception is thrown.
Throws:
- ExceptionFailedException: If it is verified that the stub behavior is not executed, this exception is thrown.
func atLeastTimes(Int64)
func atLeastTimes(minTimesExpected: Int64): Unit
Description: Specifies that the stub behavior is executed for at least a specified number of times. If it is verified that the actual number of executions is less than the specified minimum number, an exception is thrown.
Parameters:
- minTimesExpected: Int64: expected minimum number of times the stub behavior is executed
Throws:
- ExceptionFailedException: If it is verified that the number of times the stub behavior is executed is less than the specified number of times, this exception is thrown.
func once()
func once(): Continuation<R>
Description: Specifies that the stub behavior is executed only once. If it is verified that the stub signature is executed more than once, this exception is thrown.
Returns:
- Continuation<R>: The object instance can call the method to continue to generate the ActionSelector object.
Throws:
- ExceptionFailedException: If it is verified that the stub behavior is executed more than once, this exception is thrown.
func times(Int64)
func times(expectedTimes: Int64): Continuation<R>
Description: Specifies that the stub behavior is executed for a specified number of times. If it is verified that the stub behavior is not executed for the specified number of times, an exception is thrown.
Parameters:
- expectedTimes: Int64: expected number of times the stub behavior is executed
Returns:
- Continuation<R>: The object instance can call the method to continue to generate the ActionSelector object.
Throws:
- ExceptionFailedException: If it is verified that the stub behavior is not executed for the specified number of times, this exception is thrown.
func times(Int64, Int64)
func times(min!: Int64, max!: Int64): Unit
Description: Specifies a range for the number of times the stub behavior is executed. If it is verified that the number of executions exceeds the specified range, an exception is thrown.
Parameters:
- min!: Int64: expected minimum number of times the stub behavior is executed
- max!: Int64: expected maximum number of times that the stub behavior is executed
Throws:
- ExceptionFailedException: If it is verified that the number of times the stub behavior is executed is out of the specified range, this exception is thrown.
class ConfigureMock
public class ConfigureMock {}
Description: Configures mock object.
static func stubGetter<TObj, TRet>(() -> TRet,TObj,String,String,String,Int64)
public static func stubGetter<TObj, TRet>(
stubCall: () -> TRet,
objectReference: TObj,
objectName: String,
fieldOrPropertyName: String,
callDescription: String,
lineNumber: Int64
): GetterActionSelector<TRet>
Description: Creates an operator object to which stub code is inserted using the attribute-specific Getter method.
Parameters:
- stubCall: () -> TRet: call expression corresponding to the stub signature
- objectReference: TObj: reference to the stubbed object
- objectName: String: name of the stubbed object
- fieldOrPropertyName: String: name of the stubbed field or property
- callDescription: String: string representation of the call expression corresponding to the stub signature
- lineNumber: Int64: line number of the corresponding call expression
Returns:
- GetterActionSelector<TRet>: operator object to which stub code is inserted using the attribute-specific Getter method
static func stubMethod<TObj, TRet>(() -> TRet,Array<ArgumentMatcher>,TObj,String,String,String,Int64)
public static func stubMethod<TObj, TRet>(
stubCall: () -> TRet,
matchers: Array<ArgumentMatcher>,
objectReference: TObj,
objectName: String,
methodName: String,
callDescription: String,
lineNumber: Int64
): MethodActionSelector<TRet>
Description: Creates an operator object to which stub code is inserted using a common member method.
Parameters:
- stubCall: () -> TRet: call expression corresponding to the stub signature
- matchers: Array<ArgumentMatcher>: parameter matcher corresponding to the input parameter
- objectReference: TObj: reference to the stubbed object
- objectName: String: name of the stubbed object
- methodName: String: name of the stubbed method
- callDescription: String: string representation of the call expression corresponding to the stub signature
- lineNumber: Int64: line number of the corresponding call expression
Returns:
- MethodActionSelector<TRet>: operator object to which stub code is inserted using the common member method
static func stubSetter<TObj, TRet>(() -> Unit, () -> TArg,ArgumentMatcher,TObj,String,String,String,Int64)
public static func stubSetter<TObj, TArg>(
stubCall: () -> Unit,
_: () -> TArg,
matcher: ArgumentMatcher,
objectReference: TObj,
objectName: String,
fieldOrPropertyName: String,
callDescription: String,
lineNumber: Int64
): SetterActionSelector<TArg>
Description: Creates an operator object to which stub code is inserted using the attribute-specific Setter method.
Parameters:
- stubCall: () -> Unit: call expression corresponding to the stub signature
- _: () -> TArg: type for capturing attributes or fields
- matcher: ArgumentMatcher: input parameter matcher
- objectReference: TObj: reference to the stubbed object
- objectName: String: name of the stubbed object
- fieldOrPropertyName: String: name of the stubbed property or field
- callDescription: String: string representation of the call expression corresponding to the stub signature
- lineNumber: Int64: line number of the corresponding call expression
Returns:
- MethodActionSelector<TRet>: operator object to which stub code is inserted using the common member method
class Continuation
public class Continuation<A> where A <: ActionSelector {}
Description: Provides the API for continuing to define the behavior of a stub signature. The method provided by this class has the following capabilities:
- The stub signature is allowed to execute an extra operation when the previous operation is satisfied. The
Continuationinstance is meaningful only when followed by a behavior definition. - If the previous operation is not satisfied, the MockFrameworkException is thrown. The exact position where this exception is thrown is not guaranteed.
func then()
func then(): A
Description: When the previous operation in the chain is completed, the subclass object of ActionSelector is returned.
Returns:
- A: subclass object instance of ActionSelector
Throws:
- MockFrameworkException: If the previous operation is not satisfied, this exception is thrown.
class GetterActionSelector
public class GetterActionSelector<TRet> <: ActionSelector {}
Description: Provides methods for specifying an operation API for the Getter function and permitting chain calls. The input parameter is the @On macro call expression of the call expression of a member function of mock object or spy object. The instance of ActionSelector is returned. That is, APIs in this class or its subclasses may insert stub code for member functions.
Parent Type:
func getsField(SyntheticField<TRet>)
public func getsField(field: SyntheticField<TRet>): CardinalitySelector<GetterActionSelector<TRet>>
Description: Reads a synthetic field.
Parameters:
- field: SyntheticField<TRet>: synthetic field, used to process variable attributes
Returns:
- CardinalitySelector<GetterActionSelector<TRet>>: operator for an expected number of executions
func getsOriginal()
public func getsOriginal(): CardinalitySelector<GetterActionSelector<TRet>>
Description: Reads original attributes or obtains the field values from the original instance.
Returns:
- CardinalitySelector<GetterActionSelector<TRet>>: operator for an expected number of executions
func returns(TRet)
public func returns(value: TRet): CardinalitySelector<GetterActionSelector<TRet>>
Description: Specifies the return value.
Parameters:
- value: TRet: specified return value
Returns:
- CardinalitySelector<GetterActionSelector<TRet>>: operator for an expected number of executions
func returns(() -> TRet)
public func returns(valueFactory: () -> TRet): CardinalitySelector<GetterActionSelector<TRet>>
Description: Specifies the return value.
Parameters:
- valueFactory: () -> TRet: generator of specified return values
Returns:
- CardinalitySelector<GetterActionSelector<TRet>>: operator for an expected number of executions
func returnsConsecutively(Array<TRet>)
public func returnsConsecutively(values: Array<TRet>)
Description: Specifies multiple return values.
Parameters:
- values: Array<TRet>: specified multiple return values
Returns:
- CardinalitySelector<GetterActionSelector<TRet>>: operator for an expected number of executions
func returnsConsecutively(ArrayList<TRet>)
public func returnsConsecutively(values: ArrayList<TRet>)
Description: Specifies multiple return values.
Parameters:
- values: ArrayList<TRet>: specified multiple return values
Returns:
- CardinalitySelector<GetterActionSelector<TRet>>: operator for an expected number of executions
func throws(Exception)
public func throws(exception: Exception): CardinalitySelector<GetterActionSelector<TRet>>
Description: Specifies the exception to be thrown.
Parameters:
- exception: Exception: specified exception to be thrown
Returns:
- CardinalitySelector<GetterActionSelector<TRet>>: operator for an expected number of executions
func throws(() -> Exception)
public func throws(exceptionFactory: () -> Exception): CardinalitySelector<GetterActionSelector<TRet>>
Description: Specifies the exception to be thrown.
Parameters:
- exceptionFactory: () -> Exception: generator of the specified exceptions to be thrown
Returns:
- CardinalitySelector<GetterActionSelector<TRet>>: operator for an expected number of executions
extend<TRet> MethodActionSelector<TRet> where TRet <: Unit
extend<TRet> MethodActionSelector<TRet> where TRet <: Unit {}
Description: Extends MethodActionSelector.
func returns()
public func returns(): CardinalitySelector<MethodActionSelector<TRet>>
Description: Specifies that the stub function does nothing.
Returns:
- CardinalitySelector<GetterActionSelector<TRet>>: operator for an expected number of executions
class Matchers
public class Matchers {}
Description: Provides the static function for generating a matcher. The matcher object can be generated only by this static function. Matchers can be used in the stub chain.
For example, @On(foo.bar(ofType<Int64>())).returns(1)
The parameter matcher can be used for input parameters of the @On macro call expression to control the parameters expected to be passed in a stub signature. Parameter matchers are most commonly used in the following cases.
-
Specify different behaviors for different parameters. For example:
// If the input parameter of bar is 5, a value is returned. @On(foo.bar(eq(5))).returns(...) // If the input parameter of bar is 6, an exception is thrown. @On(foo.bar(eq(6))).throws(...) -
Ensure that only specified parameters are passed to specified stub signatures.
let foo = mock<Foo>() // The input parameter of bar can only be a positive number. Otherwise, UnhandledCallException is thrown. @On(foo.bar(argThat<Int64> { arg => arg > 0 })).returns(...)Notes:
The preceding examples apply only to
mock object.spy objecthas different behavior.let foo = spy(Foo()) // If the input parameter of bar is not a positive number, a member function of the Foo() object is called. @On(foo.bar(argThat<Int64> { arg => arg <= 0 })).fails()
static func any()
public static func any(): AnyMatcher
Description: Allows any value to be used as a parameter.
Returns:
- AnyMatcher: parameter matcher that accepts any value
static func argThat<T>(ValueListener<T>, (T) -> Bool)
public static func argThat<T>(listener: ValueListener<T>, predicate: (T) -> Bool): TypedMatcher<T>
Description: Filters input parameter values using the input predicate closure function and allows the value listener to process the eligible input parameter values.
Parameters:
- listener: ValueListener<T>: value listener
- predicate: (T) ->Bool: filter. This function can be used to define the matching conditions for filtering parameter values.
Returns:
- TypedMatcher<T>: type matcher with a value listener and filter
static func argThat<T>((T) -> Bool)
public static func argThat<T>(predicate: (T) -> Bool): TypedMatcher<T>
Description: Filters input values based on the filter closure.
Parameters:
- predicate: (T) ->Bool: filter
Returns:
- TypedMatcher<T>: instance of parameter filter type matcher
static func argThatNot<T>((T) -> Bool)
public static func argThatNot<T>(predicate: (T) -> Bool): TypedMatcher<T>
Description: Filters input values based on the filter closure.
Parameters:
- predicate: (T) ->Bool: filter
Returns:
- TypedMatcher<T>: instance of parameter filter type matcher
static func capture<T>(ValueListener<T>)
public static func capture<T>(listener: ValueListener<T>): TypedMatcher<T>
Allows the value listener to process input parameter values of type T. When a captured type parameter is not specified, the type parameter value of the value listener is used.
Parameters:
- listener: ValueListener<T>: value listener
Returns:
- TypedMatcher<T>: type matcher with a value listener
Note: The value listener cannot be used within the parameter range of @Called.
static func default<T>(T)
public static func default<T>(target: T): TypedMatcher<T>
Description: Matches values based on the structural (higher priority) or referential equality. If the input parameter is of neither the Equatable<T> type nor the reference type, an exception is thrown during running (no check is performed during compilation).
Parameters:
- target: T: object that must be matched based on structural or referential equality
Returns:
- TypedMatcher<T>: default type matcher
Throws:
- MockFrameworkException: If the parameter target is of neither the Equatable<T> type nor the reference type, this exception is thrown.
static func eq<T>(T)
public static func eq<T>(target: T): TypedMatcher<T> where T <: Equatable<T>
Description: Filters input values based on the structural equality with a given value.
Parameters:
- target: T: object to be matched
Returns:
- TypedMatcher<T>: parameter matcher equal to the given value structurally
static func ofType<T>()
public static func ofType<T>(): TypedMatcher<T>
Description: Filters input values by type.
Returns:
- TypedMatcher<T>: type matcher of the specific type
static func same<T>(T) where T <: Object
public static func same<T>(target: T): TypedMatcher<T> where T <: Object
Description: Filters input values based on referential equality with the provided object.
Parameters:
- target: T: object to be matched
Returns:
- TypedMatcher<T>: parameter matcher for the parameter referentially equal to the given object
extend Matchers
extend Matchers {}
Description: Extends Matchers.
static func none()
public static func none(): NoneMatcher
Description: Filters the input parameter with the value of None.
Returns:
- NoneMatcher:
Nonevalue matcher
class MethodActionSelector
public class MethodActionSelector<TRet> <: ActionSelector {}
Description: Provides methods for specifying an operation API for member functions and permitting chain calls. The input parameter is the @On macro call expression of the call expression of a member function of mock object or spy object. The instance of ActionSelector<R> is returned, where R specifies the return value type of a function member being configured. That is, an API in this class can insert stub code for a member function.
Parent Type:
func callsOriginal()
func callsOriginal(): CardinalitySelector<R>
Description: Specifies the behavior of executing original code logic by a stub signature.
Returns:
- CardinalitySelector<R>: CardinalitySelector<R> object instance specifying that the stub signature executes the original code logic
func returns(() -> R)
func returns(valueFactory: () -> R): CardinalitySelector<R>
Description: Specifies the behavior of returning a specified value by a stub signature. The value is generated by the input closure.
Parameters:
- valueFactory: () ->R: closure function (generator) that generates the expected return value
Returns:
- CardinalitySelector<R>: CardinalitySelector<R> object instance specifying that the stub signature returns the specified value
func returns(R)
func returns(value: R): CardinalitySelector<R>
Description: Specifies the behavior of returning a specified value by a stub signature.
Parameters:
- value: R: expected return value of the stub signature
Returns:
- CardinalitySelector<R>: CardinalitySelector<R> object instance specifying that the stub signature returns the specified value
func returnsConsecutively(Array<R>)
func returnsConsecutively(values: Array<R>): Continuation<R>
Description: Specifies the behavior of returning specified values by a stub signature according to a list. The stub signature will be called multiple times, and the number of times is the same as the number of values in the array.
Parameters:
- values: Array<R>: list of return values of the stub signature
Returns:
- Continuation<R>: Continuation<R> object instance specifying that the stub signature returns the specified values in sequence
Throws:
- IllegalArgumentException: If the parameter list is empty, this exception is thrown.
func returnsConsecutively(ArrayList<R>)
func returnsConsecutively(values: ArrayList<R>): Continuation<R>
Description: Specifies the behavior of returning specified values by a stub signature according to a list. The stub signature will be called consecutively for multiple times. The number of times is the same as the number of values listed in the array.
Parameters:
- values: ArrayList<R>: list of return values of the stub signature
Returns:
- Continuation<R>: Continuation<R> object instance specifying that the stub signature returns the specified values in sequence
Throws:
- IllegalArgumentException: If the parameter list is empty, this exception is thrown.
func throws(() -> Exception)
func throws(exceptionFactory: () -> Exception): CardinalitySelector<R>
Description: Specifies the behavior of throwing an exception by a stub signature. This exception is generated by the parameter closure function.
Notes:
Throws versus fails
A throw is intended to test the behavior of throwing an exception by a stub signature. For example, check whether the system can be recovered when some services are unavailable.
A fail means that calling the stub signature will cause test failure. That is, if the system behaves correctly, the stub signature should never be called.
Parameters:
- exceptionFactory: () ->Exception: closure function (generator) that constructs the expected exception object thrown by the stub signature
Returns:
- CardinalitySelector<R>: CardinalitySelector<R> object instance specifying that the stub signature throws the exception
func throws(Exception)
func throws(exception: Exception): CardinalitySelector<R>
Description: Specifies the behavior of throwing an exception by a stub signature.
Parameters:
- exception: Exception: expected exception object thrown by the stub signature
Returns:
- CardinalitySelector<R>: CardinalitySelector<R> object instance specifying that the stub signature throws the exception
class MockFramework
public class MockFramework {}
Description: Provides functions for preparing and recycling the framework required for use case execution.
static func openSession
public static func openSession(name: String, sessionKind: MockSessionKind): Unit
Description: Opens a new session. Sessions form a stack-like structure. The sessions are opened and closed in reverse sequences. mock object created during a given session can only be accessed within the session or any one of its internal sessions. Each session retains its own call log. Therefore, for any verification of a call within a session opened most recently, expectations can be verified only at the end of the session.
Parameters:
- name: String: name of the session
- sessionKind: MockSessionKind: permitted stub type
static func closeSession
public static func closeSession(): Unit
Description: Opens a new session. Sessions form a stack-like structure. The sessions are opened and closed in reverse sequences. mock object created during a given session can only be accessed within the session or any one of its internal sessions. Each session retains its own call log. Therefore, for any verification of a call within a session opened most recently, expectations can be verified only at the end of the session.
Throws:
- MockFrameworkException: If a configuration error is detected, this exception is thrown.
- ExpectationFailedException: If the expectation is not satisfied, this exception is thrown.
class NoneMatcher
public class NoneMatcher <: ArgumentMatcher {}
Description: Specifies the matcher with the parameter value of None.
Parent Type:
func matchesAny
public override func matchesAny(arg: Any): Bool
Description: Matches any input value. If the value is None, true is returned.
Parameters:
- arg: Any: input parameter value to be matched
Returns:
- Bool: If the input is None,
trueis returned; otherwise,falseis returned.
extend NoneMatcher
extend NoneMatcher {}
Description: Extends NoneMatcher.
func value<T>()
public func value<T>(): Option<T>
Description: Specifies the return value of the parameter matcher to be called by the framework.
Returns:
- Option<T>: value that matches the type of the actual input parameter value
class OrderedVerifier
public class OrderedVerifier {}
Description: Specifies the class that is used to collect verification statements and can dynamically input verification behavior in the ordered function.
func checkThat(VerifyStatement)
public func checkThat(statement: VerifyStatement): OrderedVerifier
Description: Adds a verification statement.
Parameters:
- statement: VerifyStatement: verification statement to be added
Returns:
- OrderedVerifier: object itself
class SetterActionSelector
public class SetterActionSelector<TRet> <: ActionSelector {}
Description: Provides methods for specifying an operation API for the Setter function and permitting chain calls. The input parameter is the @On macro call expression of the call expression of a member function of mock object or spy object. The instance of ActionSelector is returned. That is, APIs in this class or its subclasses may insert stub code for member functions.
Parent Type:
func doesNothing()
public func doesNothing(): CardinalitySelector<SetterActionSelector<TArg>>
Description: Specifies that no action is performed on the attribute or field.
Returns:
- CardinalitySelector<GetterActionSelector<TRet>>: operator for an expected number of executions
func setsOriginal()
public func setsOriginal(): CardinalitySelector<SetterActionSelector<TArg>>
Description: Sets original attributes or obtains the field values from the original instance.
Returns:
- CardinalitySelector<GetterActionSelector<TRet>>: operator for an expected number of executions
func setsField(SyntheticField<TRet>)
public func setsField(field: SyntheticField<TArg>): CardinalitySelector<SetterActionSelector<TArg>>
Description: Sets a synthetic field.
Parameters:
- field: SyntheticField<TRet>: synthetic field, used to process variable attributes
Returns:
- CardinalitySelector<GetterActionSelector<TRet>>: operator for an expected number of executions
func throws(Exception)
public func throws(exception: Exception): CardinalitySelector<GetterActionSelector<TRet>>
Description: Specifies the exception to be thrown.
Parameters:
- exception: Exception: specified exception to be thrown
Returns:
- CardinalitySelector<GetterActionSelector<TRet>>: operator for an expected number of executions
func throws(() -> Exception)
public func throws(exceptionFactory: () -> Exception): CardinalitySelector<GetterActionSelector<TRet>>
Description: Specifies the exception to be thrown.
Parameters:
- exceptionFactory: () -> Exception: generator of the specified exceptions to be thrown
Returns:
- CardinalitySelector<GetterActionSelector<TRet>>: operator for an expected number of executions
class SyntheticField
public class SyntheticField<T> {}
Description: Specifies a synthetic field. It is used to process variable attributes and fields.
static func create(T)
public static func create(initialValue!: T): SyntheticField<T>
Description: Creates a synthetic field.
Parameters:
- initialValue!: T: Initial value
Returns:
- SyntheticField<T>: synthetic field
class TypedMatcher
public abstract class TypedMatcher<T> <: ArgumentMatcher {}
Description: Specifies a parameter type matcher.
Parent Type:
func matches(T)
public func matches(arg: T): Bool
Description: Check whether the input parameter type matches the expectation.
Parameters:
- arg: T: input parameter to be checked
Returns:
- Bool: If the type matches,
trueis returned; otherwise,falseis returned.
func matchesAny(Any)
public func matchesAny(arg: Any): Bool
Description: Check whether the input parameter type matches the expectation.
Parameters:
- arg: Any: input parameter to be checked
Returns:
- Bool: If the type matches,
trueis returned; otherwise,falseis returned.
extend<T> TypedMatcher<T>
extend<T> TypedMatcher<T> {}
Description: Extends TypedMatcher.
func value<T>()
public func value<T>(): T
Description: Specifies the return value of the argument matcher to be called by the framework.
Returns:
- T: value that matches the type of the actual input parameter value
class UnorderedVerifier
public class UnorderedVerifier{
public func checkThat(statement: VerifyStatement):UnorderedVerifier
}
Description: Specifies the class that is used to collect verification statements and can dynamically input verification behavior in the unordered function.
func checkThat(VerifyStatement)
public func checkThat(statement: VerifyStatement):UnorderedVerifier
Description: Adds a verification statement.
Parameters:
- statement: VerifyStatement: verification statement to be added
Returns:
- UnorderedVerifier: object itself
class Verify
public class Verify {}
Description: Verify provides a series of static methods to support the definition of verification actions such as that, ordered, and unorder.
One verification action can contain multiple verification statements generated by @Called for describing the actions to be verified.
Generally, the scope of verification is restricted to function bodies in a test case. However, Verify provides the clearInvocationLog function for clearing the execution records to narrow down the scope of verification.
Behavior verification refers to checking whether an operation of the "stub signature" is performed in a defined manner. If the actual execution is inconsistent with the definition, an exception is thrown.
Verification applies to the following behavior:
- whether the specified stub signature is executed;
- whether the specified stub signature is executed for the specified number of times;
- whether the input parameters meet the requirements during execution of the specified "stub signature"; and
- whether the sequence of calling multiple specified "stub signatures" meets the requirements.
Behavior verification is implemented in the following two steps:
- specifying a verification action by calling a static method of Verify; and
- specifying a to-be-verified action of the "stub signature" by using the
@Calledmacro call expression. To simplify the expression, it is referred to as a verification statement below.
For example:
let foo = mock<Foo>()
// Define the "stub behavior" of the "stub signature".
@On(foo.bar().returns(1))
// Actual execution of the "stub signature" in the use case
foo.bar()
// Verify the execution of the "stub signature". foo.bar() is executed at least once.
Verify.that(@Called(foo.bar()))
It should be noted that CardinalitySelector<R> provides APIs for verifying some behavior. Therefore, you can select different behavior verification manners.
static func clearInvocationLog()
public static func clearInvocationLog(): Unit
Description: Clears the execution records of a preorder to narrow down the verification scope.
static func noInteractions(Array<Object>)
public static func noInteractions(mocks: Array<Object>): Unit
Description: If no action is performed on the object within the verification scope, the verification is successful.
Parameters:
Throws:
- VerificationFailedException: If the verification fails, this exception is thrown.
static func ordered((OrderedVerifier) -> Unit)
public static func ordered( collectStatements: (OrderedVerifier) -> Unit): Unit
Description: Checks whether a verification statement is executed or whether the number of executions matches the definition, and verifies the execution sequence. By default, a verification statement is executed once.
Verification statements in the input list must be disjoint. In other words, an exception is thrown when a single call behavior can match multiple verification statements. Verification statements dynamically increase depending on the closures in the input parameters.
The verification mode is exhaustive, namely, full match. In this mode, all executions within the verification scope must be specified in the verification actions.
Parameters:
- collectStatements: (OrderedVerifier) ->Unit: closure supporting dynamic increase of verification statements
Throws:
- VerificationFailedException: If the verification fails, this exception is thrown.
static func ordered(Array<VerifyStatement>)
public static func ordered(statements: Array<VerifyStatement>): Unit
Description: Checks whether a verification statement is executed or whether the number of executions matches the definition, and verifies the execution sequence. By default, a verification statement is executed once.
Verification statements in the input list are not allowed to intersect. In other words, an exception is thrown when a single call behavior can match multiple verification statements. The verification mode is exhaustive, namely, full match. In this mode, all executions within the verification scope must be specified for verification.
For example:
for (i in 0..4) {
foo.bar(i % 2)
}
Verify.ordered(
@Called(foo.bar(0)),
@Called(foo.bar(1)),
@Called(foo.bar(0)),
@Called(foo.bar(1)),
)
// An exception is thrown. The foo.bar() expression is executed four times within the verification scope, but only two executions are verified.
Verify.ordered(
@Called(foo.bar(0)),
@Called(foo.bar(_)),
)
Parameters:
- statements: Array<VerifyStatement>: verification statement to be verified
Throws:
- VerificationFailedException: If the verification fails, this exception is thrown.
static func that(VerifyStatement)
public static func that(statement: VerifyStatement): Unit
Description: Checks whether a single input verification statement is correctly executed.
Parameters:
- statement: VerifyStatement: verification statement to be verified
Throws:
- VerificationFailedException: If the verification fails, this exception is thrown.
static func unordered((UnorderedVerifier) -> Unit)
public static func unordered(collectStatements: (UnorderedVerifier) -> Unit): Unit
Description: Checks whether a verification statement is executed or whether the number of executions matches the definition, without verifying the execution sequence. By default, a verification statement is executed at least once.
Verification statements in the input list are not allowed to intersect. In other words, an exception is thrown when a single call behavior can match multiple verification statements. The verification mode is exhaustive, namely, full match. In this mode, all executions within the verification scope must be specified for verification. Verification statements dynamically increase depending on the closures in the input parameters. For example:
let totalTimes = getTimes()
for (i in 0..totalTimes) {
foo.bar(i % 2)
}
// Content of a verification statement can be determined by the value of totalTimes due to use of closures.
Verify.unordered { v =>
for (j in 0..totalTimes) {
v.checkThat(@Called(foo.bar(eq(j % 2))))
}
}
Parameters:
- collectStatements: (UnorderedVerifier) ->Unit: closure supporting dynamic increase of verification statements
Throws:
- VerificationFailedException: If the verification fails, this exception is thrown.
static func unordered(Array<VerifyStatement>)
public static func unordered(statements: Array<VerifyStatement>): Unit
Description: Checks whether a verification statement is executed or whether the number of executions matches the definition, without verifying the execution sequence. By default, a verification statement is executed at least once.
Verification statements in the input list are not allowed to intersect. In other words, an exception is thrown when a single call behavior can match multiple verification statements. The verification mode is exhaustive, namely, full match. In this mode, all executions within the verification scope must be specified for verification.
For example:
let foo = mock<Foo>()
for (i in 0..4) {
foo.bar(i % 2)
}
// Verify that bar() is executed at least once when the input parameter is 0 or 1.
Verify.unordered(
@Called(foo.bar(0)),
@Called(foo.bar(1))
)
// An exception is thrown during the verification because `foo.bar(_)` contains `foo.bar(1)`.
Verify.unordered(
@Called(foo.bar(_)).times(2),
@Called(foo.bar(1)).times(2)
)
// Verification can be performed as follows:
// Verify that the call expression with the input parameter of 1 is executed twice.
Verify.that(@Called(foo.bar(1)).times(2))
// Verify that the call expression with any input parameter is executed twice.
Verify.that(@Called(foo.bar(_)).times(2)) // called four times in total
Parameters:
- statements: Array<VerifyStatement>: multiple verification statements to be verified.
[]can be omitted for variable-length parameters.
Throws:
- VerificationFailedException: If the verification fails, this exception is thrown.
static func unordered(Exhaustiveness, (UnorderedVerifier) -> Unit)
public static func unordered(exhaustive: Exhaustiveness, collectStatements: (UnorderedVerifier) -> Unit): Unit
Description: Checks whether a verification statement is executed or whether the number of executions matches the definition, without verifying the execution sequence. By default, a verification statement is executed at least once.
Verification statements in the input list are not allowed to intersect. In other words, an exception is thrown when a single call behavior can match multiple verification statements. Verification statements dynamically increase depending on the closures in the input parameters.
Parameters:
- collectStatements: (UnorderedVerifier) ->Unit: closure supporting dynamic increase of verification statements
- exhaustive: Exhaustiveness: verification mode
Throws:
- VerificationFailedException: If the verification fails, this exception is thrown.
static func unordered(Exhaustiveness, Array<VerifyStatement>)
public static func unordered(exhaustive: Exhaustiveness, statements: Array<VerifyStatement>): Unit
Description: Checks whether a verification statement is executed or whether the number of executions matches the definition, without verifying the execution sequence. By default, a verification statement is executed at least once.
Verification statements in the input list are not allowed to intersect. In other words, an exception is thrown when a single call behavior can match multiple verification statements.
Parameters:
- statements: Array<VerifyStatement>: multiple verification statements to be verified.
[]can be omitted for variable-length parameters. - exhaustive: Exhaustiveness: verification mode
Throws:
- VerificationFailedException: If the verification fails, this exception is thrown.
class VerifyStatement
public class VerifyStatement {}
Description: Specifies a single verification statement (that is, the foregoing verification statement) for the stub signature within the verification scope, and provides the number of executions of the stub signature specified by a member function.
Objects of this type can be created only using @Called the macro call expression.
It is useless to call multiple member functions consecutively regarding one object, and an exception will be thrown in that case. That is, the number of executions can be specified only once.
When no member function is called to specify the number of executions, the default number of executions is defined based on the verification action type of the statement. For example, the verification statement in Verify.ordered() is executed once by default.
func atLeastOnce()
public func atLeastOnce(): VerifyStatement
Description: Specifies that the verification statement verifies that the stub signature is executed at least once within the verification scope.
Returns:
- VerifyStatement: object itself
Throws:
- MockFrameworkException: If the number of executions is specified for the object or the object has been passed in the verification action, this exception is thrown.
func atLeastTimes(Int64)
public func atLeastTimes(minTimesExpected: Int64): VerifyStatement
Description: Specifies that the verification statement verifies that the stub signature is executed for at least the specified number of times within the verification scope.
Parameters:
- minTimesExpected: Int64: expected minimum number of executions to be verified
Returns:
- VerifyStatement: object itself
Throws:
- MockFrameworkException: If the number of executions is specified for the object or the object has been passed in the verification action, this exception is thrown.
func once()
public func once(): VerifyStatement
Description: Specifies that the verification statement verifies that the stub signature is executed only once within the verification scope.
Returns:
- VerifyStatement: object itself
Throws:
- MockFrameworkException: If the number of executions is specified for the object or the object has been passed in the verification action, this exception is thrown.
func times(Int64)
public func times(expectedTimes: Int64): VerifyStatement
Description: Specifies that the verification statement verifies that the stub signature is executed for the specified number of times within the verification scope.
Parameters:
- expectedTimes: Int64: expected number of executions to be verified
Returns:
- VerifyStatement: object itself
Throws:
- MockFrameworkException: If the number of executions is specified for the object or the object has been passed in the verification action, this exception is thrown.
func times(Int64, Int64)
public func times(min!: Int64, max!: Int64): VerifyStatement
Description: Specifies that the verification statement verifies that the number of times the stub signature is executed within the verification scope falls in the specified range .
Parameters:
- min!: Int64: expected minimum number of executions to be verified
- max!: Int64: expected maximum number of executions to be verified
Returns:
- VerifyStatement: object itself
Throws:
- MockFrameworkException: If the number of executions is specified for the object or the object has been passed in the verification action, this exception is thrown.
Enumeration
enum Exhaustiveness
public enum Exhaustiveness {
Exhaustive | Partial
}
Description: Specifies the verification mode of the unordered function. Two modes are available. In Exhaustive mode, all stub signatures within the verification scope must be defined in the verification action. In Partial mode, the execution behavior of a stub signature that is not defined in the verification action within the verification scope can be ignored.
For example:
for (i in 0..6) {
foo.bar(i % 3)
}
// An exception is thrown for this verification action. This is because foo.bar() is executed six times within the verification scope, but the verification action specifies only four executions.
Verify.unordered(
@Called(foo.bar(1)).times(2),
@Called(foo.bar(2)).times(2)
)
// This verification action may be successful. After the Partial mode is specified, two executions not defined in the verification action are ignored.
Verify.unordered(Partial,
@Called(foo.bar(1)).times(2),
@Called(foo.bar(2)).times(2)
)
Exhaustive
Exhaustive
Description: Specifies that each call of a stub signature within the verification scope must be defined in the verification action.
Partial
Partial
Description: Permits calls of stub signatures that are not defined in the validation action within the validation scope.
enum MockSessionKind
public enum MockSessionKind {
| Forbidden
| Stateless
| Verifiable
}
Description: Specifies the type of Stub that can be used in MockSession. Only the expectation of the stub created in Session of Verifiable can be verified.
Forbidden
Description: Forbids the use of stubs.
Stateless
Description: Permits stateless stubs only. Essentially stateful operations are not permitted, for example, returnsConsequively and cardinality specifier (an expression that specifies the expected number of executions).
Verifiable
Description: Permits any stub.
enum StubMode
public enum StubMode {
| ReturnsDefaults
| SyntheticFields
}
Description: Controls the stub mode.
ReturnsDefaults
Description: Indicates that Mock object returns default values for the basic type, so as to simplify the configuration procedure of mock object. These default values are usually void or 0. The following basic types are supported: Unit, numeric type (such as Int64), Option type, Bool, String, Array, ArrayList, HashSet, and HashMap.
SyntheticFields
Description: Indicates that Mock object considers its variable attributes and fields as variable fields. This is similar to the use of SyntheticField, but simpler. Reading an uninitialized field will cause an error.
Exception Class
class ExpectationFailedException
public open class ExpectationFailedException <: PrettyException {}
Description: Specifies that one or more expectations set during mock configuration are violated during test execution.
Parent Type:
class MockFrameworkException
public class MockFrameworkException <: PrettyException {}
Description: Provides framework exception information. This exception is thrown when an API in use does not meet the framework requirements.
Parent Type:
class MockFrameworkInternalError
public class MockFrameworkInternalError <: PrettyException {}
Description: Specifies framework exception information. This exception should not be expected to be thrown.
Parent Type:
class PrettyException
public abstract class PrettyException <: Exception & PrettyPrintable {}
Description: Specifies the exception types of PrettyPrintable. Exception information can be printed properly.
Parent Type:
func pprint
public func pprint(to: PrettyPrinter): PrettyPrinter
Description: Provides exception information for color printing and indentation format printing.
Parameters:
- to: PrettyPrinter: printer to which colors and indentation formats are added
Returns:
- PrettyPrinter: printer to which colors and indentation formats are added
class UnhandledCallException
public class UnhandledCallException <: PrettyException {}
Description: Specifies that the call is not processed by provided stubs.
Parent Type:
class UnnecessaryStubbingException
public class UnnecessaryStubbingException <: PrettyException {}
Description: Indicates that code under test never triggers a stub.
Parent Type:
class UnstubbedInvocationException
public class UnstubbedInvocationException <: PrettyException {}
Description: Specifies that a stub matching the call is not provided.
Parent Type:
class VerificationFailedException
public class VerificationFailedException <: PrettyException {}
Description: Specifies the exception thrown by the framework when the verification fails.
Parent Type:
Getting Started with the Mock Framework
Use of the Mock Framework
The mock framework itself is part of the unit tests in the Cangjie standard library. Before using the mock framework, you need to import unittest.mock.* and unittest.mock.mockmacro.* to the test file.
To use the CJPM tool, you only need to run the cjpm test command. Then, the mock framework is started automatically.
For direct use of CJC, see Compilation Using CJC.
Example
Commonly used mock test cases are as follows:
- calling the mock constructor to create a mock/spy object;
- calling the configuration API to set the mock behavior;
- replacing test code dependencies with mock objects; and
- (optional) calling the verification API to verify the interaction between the test code and a mock/spy object.
The following simple API is used as an example:
public interface Repository {
func requestData(id: UInt64, timeoutMs: Int): String
}
public class Controller {
public Controller(
private let repo: Repository
) {}
public func findData(id: UInt64): ?String {
try {
return repo.requestData(id, 100)
}
catch (e: TimeoutException) {
return None
}
}
}
public class TimeoutException <: Exception {}
If the implementation of Repository is not satisfying, the mock framework can test Controller without creating dependencies. For example, the repository is implemented in another package due to existence of complex dependencies, or the test is too slow.
Testing the findData method:
//Import the mock framework package.
import std.unittest.mock.*
import std.unittest.mock.mockmacro.*
@Test
class ControllerTest {
let testId: UInt64 = 100
let testResponse = "foo"
@TestCase
func testFindSuccessfully() {
//Only mocks, rather than a real repository, need to be created.
let repository = mock<Repository>()
//Use the @On macro to configure the testData behavior.
@On(repository.requestData(testId, _)).returns(testResponse)
//Create a real Controller test for testing an actual implementation.
let controller = Controller(repository)
//Run test code.
let result = controller.findData(testId)
//Run an assertion on the result.
@Assert(result == Some(testResponse))
}
@TestCase
func testTimeout() {
let repository = mock<Repository>()
//Set getData to throw an exception.
@On(repository.requestData(testId, _)).throws(TimeoutException())
let controller = Controller(repository)
//When an underlying implementation throws an exception, the behavior is tested.
let result = controller.findData(testId)
//Run an assertion on the result.
@Assert(result == None)
}
}
Basic Concepts and Usage of Mock
Creating a Mock Object
The mock constructor can create mock and spy objects by calling and functions mock<T> and spy<T>, where T represents the mocked class or interface.
public func mock<T>(): T
public func spy<T>(objectToSpyOn: T): T
As a skeleton object, mock does not perform any operation on members by default. As a special mock object, spy is used to wrap the current instance of a class or interface. By default, calls to members of a spy object are entrusted to an underlying object. In other aspects, the spy object is similar to the mock object.
Only classes (including the final class and sealed class) and interfaces can be mocked.
For details, see Use of Mock and Spy Objects.
Configuration API
As the core of the framework, the configuration API can define the behavior of members of a mock/spy object (or redefine spy objects). The @On macro call provides access to the configuration API.
@On(storage.getComments(testId)).returns(testComments)
In this example, if the mock object storage receives a call to the getComments method and the parameter testId is specified, testComment is returned.
The preceding behavior is called stubbing. Stubs need to be first defined within the principal part of a test case, where a stub simulates a component that is not implemented or cannot be executed in the test environment.
Only instance members (including the final member) of classes and interfaces can be stubbed. The following entities cannot be stubbed:
- static members;
- extended members; and
- top-level functions, including external functions.
A complete stub declaration consists of the following parts:
- stub signature described in the
@Onmacro call; - operation used to describe the stub behavior;
- (optional) cardinality specifier (an expression specifying the expected number of executions) used to set expectations; and
- (optional) continuation (an expression supporting chain calls).
The mock framework intercepts calls matching the stub signature and performs the operation specified in the stub declaration. Only members of the spy and mock objects can be intercepted.
Stub Signature
A stub signature defines a set of conditions that match a specified subset of calls, including the following parts:
- reference to a mock/spy object, which must be a single identifier;
- member call; and
- call of parameters in specified formats. For details, see Parameter Matcher.
A signature can match the following entities:
- methods;
- attribute getter;
- attribute setter;
- field read operation; and
- field write operation.
As long as a mock/spy object calls a member and all parameters (if any) match the corresponding parameter matchers, the stub signature matches a call.
The signature structure of a method stub is <mock object name>.<method name>(<argument matcher>*).
@On(foo.method(0, 1)) // Call a method with the parameter of 0 and 1
@On(foo.method(param1: 0, param2: 1)) // Call a method with named parameters
When a stub signature matches an attribute getter/setter or a field read/write operation, <mock object name>.<property or field name> or <mock object name>.<property or field name> = <argument matcher> is used.
@On(foo.prop) //Attribute getter
@On(foo.prop = 3) //Attribute setter with the parameter of 3
To stub an operator function, the recipient of the operator must be a single reference to the mock/spy object, and the parameter of the operator must be a parameter matcher.
@On(foo + 3) // 'operator func +', with the parameter of 3
@On(foo[0]) // 'operator func []', with the parameter of 0
Parameter Matcher
Each stub signature must contain the parameter matchers for all parameters. A single parameter matcher defines a condition for accepting a subset of all possible parameter values. Each matcher is defined by calling a static method of the Matchers class. For example, Matchers.any() is a valid matcher that permits any parameter. For convenience, a syntactic sugar without the Matcher. prefix is provided.
The predefined matchers include:
| Matcher | Description | Syntactic sugar |
|---|---|---|
| any() | Any parameter | Symbol _ |
eq(value: Equatable) | Parameters with the same value structure (structural equality, meaning that objects have the same value but possibly different memory) | A single identifier and literal constants are allowed. |
same(reference: Object) | Parameters with the same reference (referential equality, meaning that objects have equal reference and same memory) | A single identifier is allowed. |
ofType<T>() | Values of the T type | - |
argThat(predicate: (T) -> Bool) | Values of the T type obtained by predicate | - |
| none() | None value of the option type | - |
If a single identifier is used as the parameter matcher, the parameters with the same structure are preferred.
If a method has a default parameter and the parameter is not explicitly specified, the any() matcher is used.
Example:
let p = mock<Printer>() //Assume that print adopts a single parameter of the ToString type.
@On(p.print(_)) //The special character "_" can be used to replace any().
@On(p.print(eq("foo"))) //Match the foo parameter only.
@On(p.print("foo")) //The explicit matcher can be omitted for constant strings.
let predefined = "foo" //A single identifier, instead of a parameter matcher, can be passed.
@On(p.print(predefined)) //For the same type, structural equality is used for matching.
@On(p.print(ofType<Bar>())) //Only parameters of the Bar type are matched.
//For more complex matchers, the following mode is recommended.
let hasQuestionMark = { arg: String => arg.contains("?") }
@On(p.print(argThat(hasQuestionMark))) //Only strings with a question mark are matched.
Selecting function overloading properly depends on the type inference mechanism of Cangjie. ofType can be used to solve compilation problems related to type inference.
Note: When used as a parameter matcher, a function call is considered a call to the matcher.
@On(foo.bar(calculateArgument())) //Incorrect. calculateArgument() is not a matcher.
let expectedArgument = calculateArgument()
@On(foo.bar(expectedArgument)) //Correct as long as expectedArgument is equivalent and/or of the reference type.
Operation API
The mock framework provides APIs for specifying stub operations. After a stub is triggered, a stub member executes the specified operation. If the call matches the signature specified by the @On macro call, the stub is triggered.
Each stub function must specify an operation. The ActionSelector subtype returned by the @On macro call defines available operations. The list of operations depends on the entity to be stubbed.
Universal (Operations)
Specifies the operations applicable to all stubs.
throws(exception: Exception):exceptionis thrown.throws(exceptionFactory: () -> Exception):exceptionFactoryis called to construct an exception thrown when a stub is triggered.fails(): If a stub is triggered, the test fails.
throwsis used to test the system behavior when a stub member throws an exception.failsis used to test whether a stub member is not called.
@On(service.request()).throws(TimeoutException())
Method and Attribute/Field Getter
R indicates the return type of a member.
returns(): No operation is performed and()is returned. This return type is available only whenRisUnit.returns(value: R):valueis returned.returns(valueFactory: () -> R):valueFactoryis called to construct an exception thrown when a stub is triggered.returnsConsecutively(values: Array<R>),returnsConsecutively(values: ArrayList<R>): When a stub is triggered, the next element invaluesis returned.
@On(foo.bar()).returns(2) //0 is returned.
@On(foo.bar()).returnsConsecutively(1, 2, 3) //1, 2, and 3 are returned consecutively.
Attribute/Field Setter
doesNothing(): Calls are ignored and no operation is performed. It is similar toreturns()the function that returns Unit. For more details, see Here.
Spy Operation
For spy objects, other operations can be used to entrust monitoring instances.
callsOriginal(): Calls an original method.getsOriginal(): Calls an original attribute getter or obtains the field value from an original instance.setsOriginal(): Calls an original attribute setter or sets the field value in an original instance.
Expectation
When a stub is defined, an expectation is implicitly or explicitly attached to the stub. A stub can define the desired cardinality. An instance of CardinalitySelector is returned after an operation (except fails and returnsConcesecutively). Expectations can be customized for this instance by using a cardinality specifier.
CardinalitySelector defines the following functions:
once()atLeastOnce()anyTimes()times(expectedTimes: Int64)times(min!: Int64, max!: Int64)atLeastTimes(minTimesExpected: Int64)
The anyTimes specifier is used to improve expectations, that is, if a stub is never triggered, the test will not fail. Other specifiers imply the upper and lower limits on the number of times a specified stub is called in the test code. If a stub is triggered more than expected, the test fails immediately. The lower limit is checked after the test code is executed.
Example:
// example_test.cj
@Test
func tooFewInvocations() {
let foo = mock<Foo>()
@On(foo.bar()).returns().times(2)
foo.bar()
}
Output:
Expectation failed
Too few invocations for stub foo.bar() declared at example_test.cj:9.
Required: exactly 2 times
Actual: 1
Invocations handled by this stub occured at:
example_test.cj:6
If no expectation is customized, the mock framework adopts the default expectation.
| Operation | Default Expected Cardinality | Custom Cardinality Allowed or Not |
|---|---|---|
| fails | Cannot be called. | No |
| returns | atLeastOnce | Yes |
| returnsConsecutively | times(values.size) | No |
| throws | atLeastOnce | Yes |
| doesNothing | atLeastOnce | Yes |
| (calls/gets/sets)Original | atLeastOnce | Yes |
Stub Chain
For the returnsConsecutively operation, the once and times(n) cardinality specifiers return a continuation instance. As the name implies, continuation means that continued use of a chain is allowed. Specifically, an operation is executed immediately after the previous operation is completed.
The continuation itself only provides the then() function that returns a new ActionSelector. Same rules apply to all operations on the chain. If then() is called, a new operation must be specified.
The total number of expectations is the sum of expectations of all chains. If a complex chain is specified in a test, all parts of the chain are triggered.
@On(foo.bar()).returnsConsecutively(1, 2, 3, 4)
//Same as below.
@On(foo.bar()).returnsConsecutively(1, 2).then().returnsConsecutively(3, 4)
//A stub is specified and must be called for NUM_OF_RETRIES times in total.
@On(service.request()).throws(TimeoutException()).times(NUM_OF_RETRIES - 1). //Request timeout occurs for several times.
then().returns(response).once() //Sending the request stops after the first successful response is received.
Use of Spy and Mock Objects
Spy objects and mock objects are similar in configuration, except that the spy objects monitor current instances.
The main difference is as follows: When a member call does not trigger any stub, the spy object calls the original implementation of the underlying instance, and the mock object throws a runtime error (the test fails).
Mock objects do not need to create real dependencies to test APIs, but configure the behavior required for a specific test scenario.
Spy objects allow you to rewrite the observable behavior of real instances. Only the calls referenced by spy objects are intercepted. Creating a spy object does not affect the reference of the original spy instance. Calling a method of the spy itself is not intercepted.
let serviceSpy = spy(service)
//Simulation timeout. Continue to use a real implementation.
@On(serviceSpy.request()).throws(TimeoutException()).once().then().callsOriginal()
//Test code must use 'serviceSpy' reference.
Mock dependency
Interfaces can always be mocked. When a class is mocked from another package, the class itself and its superclass must be compiled in a specified way. That is, only the interfaces in precompiled libraries (for example, stdlib), rather than classes, can be mocked.
Compilation Using CJC
For CJC, mocks are controlled by the --mock flag. To mock the class p in a specified package, add the --mock=on flag to CJC for calling.
This flag must also be added when a package dependent on
pis compiled.
An extra flag is not needed for using a mock object (cjc--test) in tests.
Compilation Using CJPM
CJPM automatically detects the use of mocks and generates correct CJC calls to ensure that classes can be mocked from any package compiled using source code.
In addition, the CJPM configuration file can be used to control the packages to support mocks.
Guide to Stubs
Mock objects, spy objects, and stubs can be used in various manners. This document introduces different modes and cases so that you can compile maintainable and simple test cases for the mock framework.
Operating Principles of Stubs
Stubs are declared by calling the @On macro within a test case. The declaration is valid before the execution of a specified test case is completed. Test cases can share a stub.
The mock framework processes member calls of a mock or spy object in the following sequence:
- Searches for stubs of a specified member. The stub declared later precedes the stub declared earlier. The stub declared within the principal part of a test case precedes the shared stub.
- Apply the parameter matchers of each stub. If all parameters are successfully matched, the operation defined by the stub is performed.
- If no stub is found or no stub matches actual parameters, the default behavior applies. For a mock object, an error indicating an unstubbed call is reported. For a spy object, an original member of the monitoring instance is called.
Regardless whether multiple stubs are defined for a single member, each stub has its own expectations. A test can be passed when these expectations are satisfied.
@On(foo.bar(1)).returns(1)
@On(foo.bar(2)).returns(2)
foo.bar(2)
//The first stub has been defined but is never used. The test fails.
Redefining a Stub
To change the behavior of a stub in a test, you can redefine the stub.
@On(service.request()).returns(testData)
//Use a service.
@On(service.request()).throws(Exception())
//Test the consequence of a service failure.
Defining Multiple Stubs for a Member
Multiple stubs can define different behavior by using different parameters.
Example:
@On(storage.get(_)).returns(None) // 1
@On(storage.get(TEST_ID)).returns(Some(TEST_DATA)) // 2
In this example, storage returns None for all parameters except TEST_ID. If get is never called using the parameter TEST_ID, the test fails because stub 2 is not used. If get is called always using the parameter TEST_ID, the test fails because stub 1 is not used. These restrictions help ensure pure test code, and developers learn about when a stub becomes unused. If a use case does not require this function, the cardinality specifier anyTimes() is used to improve these expectations.
//Implementation is changed frequently, but the test is expected to proceed.
//anyTimes is used to improve the expectations irrelevant to the test.
@On(storage.get(_)).returns(None).anyTimes()
@On(storage.get(TEST_ID)).returns(Some(TEST_DATA)) // It is a must to call the content under test.
Given that the stub priority becomes higher from the bottom up, the following uses are all incorrect.
@On(storage.get(TEST_ID)).returns(Some(TEST_DATA)) // Incorrect. This stub will never be triggered.
@On(storage.get(_)).returns(None) // A higher stub is always hidden.
Expectations can also be used to check the called parameters.
let renderer = spy(Renderer())
@On(renderer.render(_)).fails()
let isVisible = { c: Component => c.isVisible }
@On(renderer.render(argThat(isVisible))).callsOriginal() // Only visible components are permitted.
Sharing Mock Objects and Stubs
When a large number of mock objects are required for testing, multiple test cases can share mock objects and/or stubs. A mock or spy object can be created anywhere. However, if a mock object is leaked from one test case to another by mistake, sequential dependency problems or unstable tests may be caused. Therefore, such operation is not recommended, and the mock framework also detects this type of problems. To share mock or spy objects between test cases of one test class, the objects can be placed in instance variables of the class.
A stub declaration implies expectations, making it more difficult to process shared stubs. Expectations cannot be shared between test cases. A stub can be declared in only two positions:
- principal part of test case (regardless of the
@Testfunction or@TestCasein the@Testclass): check expectations; and beforeAllIn the@Testclass: share stubs between test cases. Such a stub cannot declare an expectation, and the expectation is not checked. Cardinality specifiers are not allowed. Only stateless operations such asreturns(value),throws(exception),fails(), andcallsOriginal()are allowed. These stubs can be considered to have implicitanyTimes()cardinality.
If test cases have the same expectations, you can extract and call functions (non-test case member functions in the test class) in the principal part of the test cases.
Using beforeAll:
@Test
class TestFoo {
let foo = mock<Foo>()
//The unit test framework calls the content below before executing test cases.
public func beforeAll(): Unit {
//Default behavior is shared among all test cases.
//This stub does not need to be used in each test case.
@On(foo.bar(_)).returns("default")
}
@TestCase
func testZero() {
@On(foo.bar(0)).returns("zero") //This stub needs to be used in this test case.
foo.bar(0) //"zero" is returned.
foo.bar(1) //"default" is returned.
}
@TestCase
func testOne() {
@On(foo.bar(0)).returns("one")
foo.bar(0) //"one" is returned.
}
}
Using the function:
@Test
class TestFoo {
let foo = mock<Foo>()
func setupDefaultStubs() {
@On(foo.bar(_)).returns("default")
}
@TestCase
func testZero() {
setupDefaultStubs()
@On(foo.bar(0)).returns("zero")
foo.bar(0) //"zero" is returned.
foo.bar(1) //"default" is returned.
}
@TestCase
func testOne() {
setupDefaultStubs()
@On(foo.bar(0)).returns("zero")
foo.bar(0) //"zero" is returned.
//Expectation fails. The stub has declared the expectation but never uses it.
}
}
Do not declare stubs in constructors of the test class. When to call a constructor of the test class cannot be guaranteed.
Capturing Parameters
The mock framework uses the captor(ValueListener) parameter matcher to capture parameters for checking actual parameters passed to a stub member. Once a stub is triggered, ValueListener intercepts corresponding parameters, and checks parameters and/or adds verification parameters.
On each call, the ValueListener.onEach static function can also be used to verify a condition. After lambda is accepted, lambda is called when the stub is triggered. lambda is used to receive the value of a parameter.
let renderer = spy(TextRenderer())
let markUpRenderer = MarkupRenderer(renderer)
// Create a validator.
let validator = ValueListener.onEach { str: String =>
@Assert(str == "must be bold")
}
// Use the "capture" parameter matcher to bind parameters to the validator.
@On(renderer.renderBold(capture(validator))).callsOriginal() // If this function has never been called, the test fails.
markUpRenderer.render("text inside tag <b>must be bold</b>")
In addition, ValueListener also provides allValues() and lastValue() functions for checking parameters in the following mode:
//Create a capturer.
let captor = ValueListener<String>.new()
//Use the "capture" parameter matcher to bind parameters to the validator.
@On(renderer.renderBold(capture(captor))).callsOriginal()
markUpRenderer.render("text inside tag <b>must be bold</b>")
let argumentValues = captor.allValues()
@Assert(argumentValues.size == 1 && argumentValues[0] == "must be bold")
The argThat matcher is an overloaded function that combines parameter filtering and capturing. argThat(listener, filter) accepts ValueListener instances and filter predicates. listener collects only the parameters that have passed the filter check.
let filter = { arg: String => arg.contains("bold") }
let captor = ValueListener<String>.new()
// Failed unless parameters are intercepted. However, the stub is declared below.
@On(renderer.renderBold(_)).fails()
// Collect only the strings containing "bold".
@On(renderer.renderBold(argThat(captor, filter))).callsOriginal()
markUpRenderer.render("text inside tag <b>must be bold</b>")
// The "captor" object can be used to check all filtered parameters.
@Assert(captor.lastValue() == "must be bold")
The parameter capturer can be used with mock and spy objects. However, such parameter matchers are not allowed in the @Called macro.
Customizing and Using a Parameter Matcher
To prevent reuse of a parameter matcher, you can customize parameter matchers.
The following example shows how to share a matcher between test cases:
@On(foo.bar(oddNumbers())).returns("Odd")
@On(foo.bar(evenNumbers())).returns("Even")
foo.bar(0) // "Even"
foo.bar(1) // "Odd"
Since each matcher is just a static function of the Matchers class, extensions can be used to customize parameter matchers. New parameter matchers need to call existing instances.
extend Matchers {
static func evenNumbers(): TypedMatcher<Int> {
argThat { arg: Int => arg % 2 == 0}
}
static func oddNumbers(): TypedMatcher<Int> {
argThat { arg: Int => arg % 2 == 1}
}
}
A function parameter matcher may contain parameters.
extend Matchers {
//Accept Int parameters only.
static func isDivisibleBy(n: Int): TypedMatcher<Int> {
argThat { arg: Int => arg % n == 0}
}
}
Most matcher functions specify the return type TypedMatcher<T>. Such a matcher accepts only the T type. When a parameter matcher is used in a stub declaration, values of the T type must be valid parameters for a stubbed function or attribute setter. In other words, the T type should be a parameter subtype or the same as the actual type of parameters.
Setting Attributes and Fields
Fields and attributes are stubbed using the same method. You can configure the return values through same operations.
A setter is similar to a function that returns Unit. The special operation doesNothing() can be used for setters.
The common mode of stubbing variable attributes is as follows:
@On(foo.prop).returns("value") //Configure a getter.
@On(foo.prop = _).doesNothing() //Ignore the call of a setter.
In rare cases, the behavior of a variable attribute is expected to be the same as that of a field. To create a synthetic field (a field generated by the framework), use the static function SyntheticField.create. The storage of synthetic fields is managed by the mock framework. It is applicable to the scenario of mocking interfaces or abstract classes that contain variable attributes and fields.
Fields are bound to specified calls by executing getsField and setsField stub operations. Through these operations, an expectation can be configured as any other operation.
interface Foo {
mut prop bar: String
}
@Test
func test() {
let foo = mock<Foo>()
let syntheticField = SyntheticField.create(initialValue: "initial")
@On(foo.bar).getsField(syntheticField) // Reading attributes is to read a synthetic field.
@On(foo.bar = _).setsField(syntheticField) // Write a new value for the attribute.
//The 'bar' attribute is represented as a field.
}
If multiple test cases share the
SyntheticFieldobject, the value of this field is reset toinitialValuebefore each test case to prevent sharing a variable state between tests.
Stub Mode
Usually, an exception is thrown when some calls do not match any stub. However, in some common situations, the mock object can be configured to add default behavior. In this way, when no stub is matched, the default behavior is executed. This is implemented by enabling the stub mode. Two modes are available: ReturnsDefaults and SyntheticFields. These modes are represented by the enumeration type StubMode. During creation of a mock object, these modes can be passed to the mock function so that the stub mode is enabled for specified mock objects.
public func mock<T>(modes: Array<StubMode>): T
The stub mode can be used to reduce code for configuring mock objects, and it can be combined with explicit stubs flexibly. An explicit stub always precedes its default behavior. Note that using the stub mode does not impose any expectations on the members of a mock object. When a use case is intended to check whether only specified members of a mock object are called, the stub mode should be used with caution. The behavior of the object under test may change in an unexpected manner, but the test may still be passed.
ReturnsDefaults Mode
In this mode, if the return type of a member is listed in the following table, the member can be called without explicit stub configuration.
let foo = mock<Foo>(ReturnsDefaults)
@Assert(foo.isPretty(), false)
The default values returned by this type of members are also shown in the following table.
| Type | Default Value |
|---|---|
| Bool | false |
| numbers | 0 |
| String | empty string |
| Option | None |
| ArrayList, HashSet, Array | new empty collection |
| HashMap | new empty map |
The ReturnsDefaults mode takes effect only for the following members:
- member functions whose return values are of a supported type (as shown in the table above); and
- attribute readers and fields of a supported type (as shown in the table above).
SyntheticFields Mode
The SyntheticFields mode can simplify the configuration actions of SyntheticField. For details, see Setting Attributes and Fields. SyntheticFields implicitly creates synthetic fields of the corresponding type for all attributes and fields by using the mock framework. However, these fields can be read only after being assigned values. This mode is effective only for variable attributes and fields.
let foo = mock<Foo>(SyntheticFields)
// can simply assign a value to a mutable property
foo.bar = "Hello"
@Assert(foo.bar, "Hello")
Values assigned to attributes and fields are visible only in the corresponding test cases. When both SyntheticFields and ReturnsDefaultsare enabled, the assigned value precedes the default value. However, the default value can be used as long as the field or attribute is not assigned a value.
let foo = mock<Foo>(ReturnsDefaults, SyntheticFields)
@Assert(foo.bar, "")
foo.bar = "Hello"
@Assert(foo.bar, "Hello")
Verification API of Mock Framework
The verification API is part of the mock framework and provides the following functionality:
- verifying whether certain calls are executed;
- verifying the number of specific calls;
- verifying whether specified parameters are used for calling; and
- verifying whether calls follow a specified order.
Verification runs assertions by examining the call log built during the execution of a test. The call log contains all calls that make the mock and spy objects accessible in the test. Only calls to mock or spy objects can be verified.
The Verify class provides access to the verification API. The @Called macro is used to construct assertions about code.
The @Called macro call constructs a verification statement, that is, checks a single assertion of the code against the call log. The Verify class is a collection of static methods. Methods such as that, ordered, and unordered can be called to construct verification blocks.
Example
let foo = mock<Foo>()
//Configure foo.
@On(foo.bar()).returns()
foo.bar()
Verify.that(@Called(foo.bar())) //Verify that bar is called at least once.
Verification Statements and @CalledMacro
Verification statements are represented by the VerifyStatement class. The VerifyStatement instance is created by the @Called macro.
Similar to the @On macro, the @Called macro call accepts stub signatures, and complies with the rules of parameter matchers.
Example:
@Called(foo.bar(1, _)) //Match the verification statement called by the bar method, where the first parameter is '1'.
@Called(foo.baz) //Match the verification statement called by the baz attribute getter.
The API provided by the VerifyStatement class is similar to the cardinality specifier available during stub configuration.
Cardinality functions are as follows:
once()atLeastOnce()times(expectedTimes: Int64)times(min!: Int64, max!: Int64)atLeastTimes(minTimesExpected: Int64)never()
Calling these functions returns the same VerifyStatement instance. Cardinality cannot be reset for one statement and must be set before the statement is passed to the verification block generator function. If cardinality is not explicitly set, the default cardinality is used.
Verify.that(@Called(foo.bar()).atLeastOnce())
Verify.that(@Called(foo.bar()).once())
Verification Block
A verification block usually contains one or more verification statements, and checking the statements the check block will construct more complex assertions.
A call to a verification block is verified immediately, but subsequent calls are not verified. Verification blocks do not change the state of the call log. Each call in the log can be checked by any number of blocks. Each block is checked independently. No dependency exists between blocks. The order of calling verification blocks is insignificant unless some calls occur between blocks or the call log is manually cleared.
A verification statement itself does not perform any type of verification but must be passed to a verification block for verification.
A single verification block only checks the calls to mock or spy objects mentioned by verification statements within the block, and calls to other objects are ignored.
The Verify class contains several static methods for constructing verification blocks. Ordered verification blocks are used to check the exact order of calls. Unordered verification blocks verify only the number of calls.
Ordered
To check the call sequence of one or more objects, the ordered verification block generator is used.
The static function ordered receives an array of verification statements.
for (i in 0..4) {
foo.bar(i % 2)
}
Verify.ordered(
@Called(foo.bar(0)),
@Called(foo.bar(1)),
@Called(foo.bar(0)),
@Called(foo.bar(1))
)
The call sequence of multiple objects can be checked.
for (i in 0..4) {
if (i % 2 == 0) {
fooEven.bar(i)
}
else {
forOdd.bar(i)
}
}
Verify.ordered(
@Called(fooEven.bar(0)),
@Called(fooOdd.bar(1)),
@Called(fooEven.bar(2)),
@Called(fooOdd.bar(3)),
)
The default cardinality specifier for ordered verification is once(). Other cardinality specifiers can be used if necessary.
for (i in 0..4) {
foo1.bar(i)
}
for (i in 0..4) {
foo2.bar(i)
}
Verify.ordered(
@Called(foo1.bar(_).times(4)),
@Called(foo2.bar(_).times(4))
)
For ordered verification, all calls to mock or spy objects (mentioned in the block) must be listed. Any unlisted call will cause a validation failure.
foo.bar(0)
foo.bar(10)
foo.bar(1000)
Verify.ordered(
@Called(foo.bar(0)),
@Called(foo.bar(10))
)
Output:
Verification failed
No statement is matched for the call below:
foo.bar(...) at example_test.cj:6
Unordered
Unordered verification checks only the number of times its verification statement is called.
For unordered verification, the cardinality atLeastOnce() is used unless explicitly specified, that is, the statement called at least once is checked.
for (i in 0..4) {
foo.bar(i % 2)
}
//Verifies whether the bar with the parameter of 0 and 1 is called at least once.
Verify.unordered(
@Called(foo.bar(0)),
@Called(foo.bar(1))
)
//Verifies whether the bar with the parameter of 0 and 1 is called twice.
Verify.unordered(
@Called(foo.bar(0)).times(2),
@Called(foo.bar(1)).times(2)
)
//Verifies whether the bar is called four times in total.
Verify.unordered(
@Called(foo.bar(_)).times(4)
)
Unordered verification falls into Partial and Exhaustive verifications.
Exhaustive verification is used by default. All calls to the mock or spy object mentioned in the verification statement must be listed. For Partial verification, only part of calls are listed.
for (i in 0..4) {
foo.bar(i)
}
//Failed. Two calls to foo.bar() are not listed in the block.
Verify.unordered(
@Called(foo.bar(0)).once(),
@Called(foo.bar(1)).once()
)
//Unrelated calls are ignored.
Verify.unordered(Partial,
@Called(foo.bar(0)).once(),
@Called(foo.bar(1)).once()
)
Dynamic Construction of Verification Blocks
The ordered and unordered functions are overloaded functions supporting lambda. The checkThat(statement: VerifyStatement) function can be used to dynamically add statements.
Example:
let totalTimes = 40
for (i in 0..totalTimes) {
foo.bar(i % 2)
}
Verify.ordered { v =>
for (j in 0..totalTimes) {
v.checkThat(@Called(foo.bar(eq(j % 2))))
}
}
Other APIs
The Verify class further provides the following tools:
- that(statement: VerifyStatement) is the alias of Verify.unordered(Paritial, statement), which is used to check a single statement. It is unnecessary to list all calls to the corresponding mock or spy object.
- noInteractions(mocks: Array
clearInvocationLog()resets the log to the empty state. This affects all subsequent verification blocks, but does not affect stub expectations.
Example:
foo.bar()
Verify.that(@Called(foo.bar())) // OK
Verify.noInteractions(foo) // Failed. The call to foo.bar() is recorded in the log.
Verify.clearInvocationLog() // Clear the log.
Verify.noInteractions(foo) // Clear all interactions with foo from the log.
Verify.that(@Called(foo.bar())) // Failed.
Verify APIs
public static func that(statement: VerifyStatement): Unit
public static func unordered(
exhaustive: Exhaustiveness,
collectStatements: (UnorderedVerifier) -> Unit
): Unit
public static func unordered(
collectStatements: (UnorderedVerifier) -> Unit
): Unit
public static func unordered(statements: Array<VerifyStatement>): Unit
public static func unordered(
exhaustive: Exhaustiveness,
statements: Array<VerifyStatement>
): Unit
public static func ordered(
collectStatements: (OrderedVerifier) -> Unit
): Unit
public static func ordered(statements: Array<VerifyStatement>): Unit
public static func clearInvocationLog(): Unit
public static func noInteractions(mocks: Array<Object>): Unit
Verification Errors
If a verification fails, VerificationFailedException is thrown and the mock framework generates a report. Do not capture such exception.
The failure types are as follows:
- Excessively few or many calls: The number of calls does not match the statement in the block.
- Statement mismatch: A statement in the block does not match the number of calls recorded in the log.
- Call mismatch: The log contains a call that does not match the statement in the block.
- Unexpected call: An ordered verification block requires other calls.
- Useless interaction: noInteractions detects an unexpected call.
Another failure type is disjoint statements. Therefore, a failure may not be caused by an error in test code. This failure type is reported when multiple statements match a call. This error may be caused if a statement with a disjoint parameter matcher is used in a single verification block. Fuzzy match is not allowed between statements and calls.
Examples and Patterns
Usually, the verification API is used to verify the interaction between test code (including functions, classes, and entire packages) and external objects. Details are as follows:
- creating spy objects;
- passing these spy objects to the test code; and
- verifying the interaction between code and the spy objects.
Verifying the Number of Calls
func testDataCaching() {
// Creates required spy or mock objects.
let uncachedRepo = spy(Repository())
let invalidationTracker = mock<InvalidationTracker>()
@On(invalidationTracker.getTimestamp()).returns(0)
// Prepares test data.
let cachedRepo = CachedRepistory(uncachedRepo, invalidationTracker)
// Runs test code.
for (i in 0..10) {
cachedRepo.get(TEST_ID)
}
// According to verification results, only the basic repo is queried once, and other calls to uncached repos do not exist.
Verify.unordered(Exhaustive,
@Called(uncachedRepo.get(TEST_ID)).once()
)
// Clears the log.
Verify.clearInvocationLog()
// Sets other behavior.
@On(invalidationTracker.getTimestamp()).returns(1)
for (i in 0..10) {
cachedRepo.get(TEST_ID)
}
// Only one call is executed since the last clearing.
Verify.unordered(Exhaustive,
@Called(uncachedRepo.get(TEST_ID)).once()
)
}
Verifying Calls with Specified Parameters
func testDrawingTriangle() {
// Creates required spy or mock objects.
let canvas = spy(Canvas())
// Runs test code.
canvas.draw(Triangle())
// Tests that a triangle consists of three lines and three points.
// Uses “that” block.
Verify.that(
@Called(canvas.draw(ofType<Dot>())).times(3)
)
Verify.that(
@Called(canvas.draw(ofType<Line>())).times(3)
)
//Uses part of the unordered verification block instead.
Verify.unordered(Partial, // The actual sequence of drawing lines and points is unknown.
@Called(canvas.draw(ofType<Dot>())).times(3),
@Called(canvas.draw(ofType<Line>())).times(3)
)
// During use of an enumeration block, all calls must be enumerated.
Verify.unordered(Exhaustive,
@Called(canvas.draw(ofType<Triangle>())).once(),
@Called(canvas.draw(ofType<Dot>())).times(3),
@Called(canvas.draw(ofType<Line>())).times(3)
)
// Verifies that the draw function with an input parameter of the Square type is never called.
Verify.that(
@Called(canvas.draw(ofType<Square>)).never()
)
// To distinguish parameters by using more complex conditions,
// use the pattern below:
let isDot = { f: Figure =>
f is Dot //This is a more complex logic.
}
Verify.that(
@Called(canvas.draw(argThat(isDot))).times(3)
)
// Note: It must be specified that statements in one block matches only one call.
// In the counterexample below, some calls match two statements.
Verify.unordered(
@Called(canvas.draw(_)).times(7),
@Called(canvas.draw(ofType<Dot>())).times(3)
)
}
Verifying the Call Sequence
func testBuildFlight() {
let plane = spy(Plane())
FlightBuilder(plane).planFlight(Shenzhen, Shanghai, Beijing).execute()
Verify.ordered(
@Called(plane.takeOffAt(Shenzhen)),
@Called(plane.landAt(Shanghai)),
@Called(plane.takeOffAt(Shanghai)),
@Called(plane.landAt(Beijing))
)
}
Expectation and Verification API
When configuring a stub, you can set expectations and verification API to cover some assertions in the test code. In this case, you have to select a method that can better reflect the test intention.
Generally, it is recommended that you avoid repeating the configuration steps in the verification block.
let foo = mock<Foo>()
@On(foo.bar(_)).returns() //If this stub is never used, the test fails.
foo.bar(1)
foo.bar(2)
Verify.that(
//Unnecessary. Automatic verification is used.
@Called(foo.bar(_)).atLeastOnce()
)
//The number of calls and specific parameters can be examined instead.
Verify.unordered(
@Called(foo.bar(1)).once(),
@Called(foo.bar(2)).once()
)
The example above can be rewritten using an expectation:
let foo = mock<Foo>()
@On(foo.bar(1)).returns().once() //It is expected to be called once. The parameter is '1'.
@On(foo.bar(2)).returns().once() //It is expected to be called once. The parameter is '2'.
foo.bar(1)
foo.bar(2)
//If no stub is triggered, the test fails.
std.unittest.mock.mockmacro Package
Function Description
unittest.mock.mockmacro provides macros required by the mock framework.
API List
Macro
| Name | Description |
|---|---|
| Called | Creates a verification statement. |
| On | Uses the configuration API to define the behavior of members of a mock/spy object (or redefine a spy object). |
Macro
@Called Macro
Description: Creates a verification statement.
@On Macro
Description: Uses the configuration API to define the behavior of members of a mock/spy object (or redefine a spy object).
std.unittest.testmacro Package
Function Description
unittest.testmacro provides macros for the unit test framework.
API List
Macro
| Name | Description |
|---|---|
| AfterAll | Declares that the function in a test class is a test life cycle function. The function modified by this macro runs once after all test cases are completed. |
| AfterEach | Declares that the function in a test class is a test life cycle function. The function modified by this macro runs once after each test case is completed. |
| Assert | Declares an assertion. This macro is used in test functions. If the assertion fails, the test case stops. |
| AssertThrows | Declares an expected exception assertion. This macro is used in test functions. If the assertion fails, the test case stops. |
| BeforeAll | Declares that the function in a test class is a test life cycle function. The function modified by this macro runs once before all test cases are completed. |
| BeforeEach | Declares that the function in a test class is a test life cycle function. The function modified by this macro runs once before each test case is completed. |
| Bench | Labels a function to be executed for multiple times and calculates the scheduled execution time of the function. |
| Configure | Provides configuration parameters for test classes or test functions. It can be placed on a test class or test function. |
| Expect | Declares an Expect assertion. This macro is used in test functions. If the assertion fails, the test case stops. |
| ExpectThrows | Declares an expected exception assertion. This macro is used in test functions. If the assertion fails, the test case still proceeds. |
| Fail | Declares an expected failure assertion. This macro is used in test functions. If the assertion fails, the test case stops. |
| FailExpect | Declares an expected failure assertion. This macro is used in test functions. If the assertion fails, the test case still proceeds. |
| Parallel | Modifies test classes. Test cases in the test class modified by @Parallel can be executed in parallel. |
| PowerAssert | Checks whether a passed expression is true and displays a detailed chart containing the intermediate values and exceptions of the passed expression. |
| Skip | Modifies a function that has been modified by @TestCase/@Bench so that the test case is skipped. |
| Strategy | Combines, maps, and reuses various data policies. |
| Test | Applies to top-level functions or classes so that they are converted into unit test classes. |
| TestBuilder | Declares a dynamic test suite. |
| TestCase | Labels functions in a unit test class so that these functions become test cases of the unit test. |
| Timeout | Indicates that a test should be stopped after a specified period of time. It helps test complex algorithms that may run for a long time or enter an infinite loop. |
| Types | Provides type parameters for test classes or test functions. It can be placed on a test class or test function. |
Macro
@AfterAll Macro
Description: Declares that the function in a test class is a test life cycle function. The function modified by this macro runs once after all test cases are completed.
@AfterEach Macro
Description: Declares that the function in a test class is a test life cycle function. The function modified by this macro runs once after each test case is completed.
@Assert Macro
Description: @Assert declares an assertion. This macro is used inside test functions. If the assertion fails, the test case stops.
@Assert(leftExpr, rightExpr): Compares whether the values ofleftExprandrightExprare equal.@Assert(condition: Bool): Compares whetherconditionistrue, that is, whether@Assert(condition: Bool)is equivalent to@Assert(condition: Bool, true).
@AssertThrows Macro
Description: Declares an expected exception assertion. This macro is used inside test functions. If the assertion fails, the test case stops.
@BeforeAll Macro
Description: Declares that the function in a test class is a test life cycle function. The function modified by this macro runs once before all test cases are completed.
@BeforeEach Macro
Description: Declares that the function in a test class is a test life cycle function. The function modified by this macro runs once before each test case is completed.
@Bench Macro
Description: Labels a function to be executed for multiple times and calculates the scheduled execution time of the function.
This type of function is executed in batches and the execution time of a batch is measured. Such measurement is repeated multiple times to obtain a statistical distribution of results and various statistical parameters of the distribution are calculated. Currently, the following parameters are supported:
- Median
- Absolute value of the 99% confidence interval for the median used for error estimation
- Relative value of the 99% confidence interval for the median
- Average value
The following shows an example of combining the parameterized DSL with @Bench. For detailed syntax and rules, see @TestCase Macro.
func sortArray<T>(arr: Array<T>): Unit
where T <: Comparable<T> {
if (arr.size < 2) { return }
var minIndex = 0
for (i in 1..arr.size) {
if (arr[i] < arr[minIndex]) {
minIndex = i
}
}
(arr[0], arr[minIndex]) = (arr[minIndex], arr[0])
sortArray(arr[1..])
}
@Test
@Configure[baseline: "test1"]
class ArrayBenchmarks{
@Bench
func test1(): Unit
{
let arr = Array(10) { i: Int64 => i }
sortArray(arr)
}
@Bench[x in 10..20]
func test2(x:Int64): Unit
{
let arr = Array(x) { i: Int64 => i.toString() }
sortArray(arr)
}
}
As shown in the output below, the Args column is added so that test data with different parameters is listed. Each parameter value is used as a performance test case and the test result is output accordingly. In the case of multiple parameters, all combinations are enumerated.
--------------------------------------------------------------------------------------------------
TP: default, time elapsed: 68610430659 ns, Result:
TCS: ArrayBenchmarks, time elapsed: 68610230100 ns, RESULT:
| Case | Args | Median | Err | Err% | Mean |
|:-------|:-------|---------:|----------:|-------:|---------:|
| test1 | - | 4.274 us | ±2.916 ns | ±0.1% | 4.507 us |
| | | | | | |
| test2 | 10 | 6.622 us | ±5.900 ns | ±0.1% | 6.670 us |
| test2 | 11 | 7.863 us | ±5.966 ns | ±0.1% | 8.184 us |
| test2 | 12 | 9.087 us | ±10.74 ns | ±0.1% | 9.918 us |
| test2 | 13 | 10.34 us | ±6.363 ns | ±0.1% | 10.28 us |
| test2 | 14 | 11.63 us | ±9.219 ns | ±0.1% | 11.67 us |
| test2 | 15 | 13.05 us | ±7.520 ns | ±0.1% | 13.24 us |
| test2 | 16 | 14.66 us | ±11.59 ns | ±0.1% | 15.53 us |
| test2 | 17 | 16.21 us | ±8.972 ns | ±0.1% | 16.35 us |
| test2 | 18 | 17.73 us | ±6.288 ns | ±0.0% | 17.88 us |
| test2 | 19 | 19.47 us | ±5.819 ns | ±0.0% | 19.49 us |
Summary: TOTAL: 11
PASSED: 11, SKIPPED: 0, ERROR: 0
FAILED: 0
--------------------------------------------------------------------------------------------------
@Configure Macro
Description: Provides configuration parameters for test classes or test functions. It can be placed on a test class or test function.
The syntax rule is @Configure[parameter1: <value1>,parameter2: <value2>], where parameter1 is a Cangjie identifier and value is any valid Cangjie expression. value may be a constant or any Cangjie expression that is valid within the scope of a declaration labeled with @Configure. If multiple parameters are of different types, they can have the same name. If multiple parameters with the same name and type are specified, the latest parameter is used.
Currently, the following configuration parameters are supported:
randomSeed: Int64 type, used to set the initial random seed for all functions that adopts random generation.generationSteps: Int64 type, used to specify the maximum number of steps for value generation in parameterized test algorithms.reductionSteps: Int64 type, used to specify the maximum number of steps for value reduction in parameterized test algorithms.
The following parameters are generally used for Benchmark test functions modified by @Bench:
explicitGC: ExplicitGcType type, used to specify how to call GC during Benchmark function testing. The default value is ExplicitGcType.Light.baseline: String type. The parameter value is the name of the Benchmark function, which is used as the baseline for comparing the execution results of the Benchmark function. The result value is added to the output as an additional column, which contains the comparison result.batchSize: Int64 or Range<Int64> type, used to configure the batch size for the Benchmark function. The default value is calculated by the framework during warm-up.minBatches: Int64 type, used to specify the number of batches to be executed during Benchmark function testing. The default value is10.minDuration: Duration type, used to specify the time for repeatedly executing the Benchmark function to obtain better results. The default value is Duration.second * 5.warmup: Duration or Int64 type, used to specify the time or number of times for repeatedly executing the Benchmark function before the result is collected. The default value is Duration.second. If the value is0, no warm-up is involved. In this case, the number of executions is calculated by multiplyingbatchSizebyminBatches. IfbatchSizeis not specified, an exception is thrown.measurement: Measurement type, used to describe the information to be collected for the performance test. The default value is TimeNow(). Internally, DateTime.now() is used for measurement.
You can specify other configuration parameters in the @Configure macro, which may be used in the future. If a test class uses the @Configure macro to specify the configuration, all test functions in the class inherit the configuration parameter. If test functions in this class are also labeled with the @Configure macro, the configuration parameter combines the subclasses and functions, where function-level macros precede.
@Expect Macro
Description: @Expect declares an Expect assertion. This macro is used inside test functions. If the assertion fails, the test case stops.
@Expect(leftExpr, rightExpr): Compares whether the value ofleftExprandrightExprare equal.@Expect(condition: Bool): Compares whetherconditionistrue, that is,@Expect(condition: Bool)is equivalent to@Expect(condition: Bool, true).
@ExpectThrows Macro
Description: Declares an expected exception assertion. This macro is used inside test functions. If the assertion fails, the test case still proceeds.
@Fail Macro
Description: Declares an expected failure assertion. This macro is used inside test functions. If the assertion fails, the test case stops.
@FailExpect Macro
Description: Declares an expected failure assertion. This macro is used inside test functions. If the assertion fails, the test case still proceeds.
@Parallel Macro
Description: Modifies a test class so that test cases in that test class can be executed in parallel. Such configuration takes effect only in --parallel running mode.
- All related test cases should be independent of each other and not rely on any mutable shared state.
beforeAll()andafterAll()should be reentrant so that they can be executed multiple times in different processes.- Test cases to be executed in paralle should be time consuming themselves. Otherwise, the multiple
beforeAll()andafterAll()executions introduced by parallelization may exceed the benefits of parallelization. - This macro cannot be used together with
@Bench. Performance test cases are sensitive to underlying resources, and whether test cases are executed in parallel affects the results of performance test cases. Therefore, concurrent use of this macro and@Benchis not allowed.
@PowerAssert Macro
Description: @PowerAssert(condition: Bool) checks whether a passed expression is true and displays a detailed chart containing the intermediate values and exceptions of the passed expression.
The detailed information is as follows:
REASON: `foo(10, y: test + s) == foo(s.size, y: s) + bar(a)` has been evaluated to false
Assert Failed: `(foo(10, y: test + s) == foo(s.size, y: s) + bar(a))`
| | |_|| | |_| | |_|| | |_||
| | "123" | "123" | "123" | 1 |
| |__________|| | |______| | |______|
| "test123" | | 3 | 33 |
|______________________| |_________________| |
0 | 1 |
|__________________________|
34
--------------------------------------------------------------------------------------------------
Note that not all AST nodes are supported currently. The following nodes are supported:
- Any binary expression
- Arithmetic expression, for example,
a + b == p % b - Boolean expression, for example,
a || b == a && b - Bit expression, for example,
a | b == a ^ b
- Arithmetic expression, for example,
- Member access, for example,
a.b.c == foo.bar - Bracket expression, for example,
(foo) == ((bar)) - Call expression, for example,
foo(bar()) == Zoo() - Reference expression, for example,
x == y - Assignment expression, for example,
a = foo, which is actually always Unit (represented by()). Note that the left value of an assignment expression cannot be printed. - Unary expression, for example,
!myBool isexpression, for example,myExpr is Fooasexpression, for example,myExpr as Foo
If other nodes are passed, their values are not printed in the chart. The returned Tokens are initial expressions, but are wrapped into some internal wrappers. These wrappers allow intermediate values and exceptions to be further printed.
@Skip Macro
Description: @Skip modifies a function that has been modified by @TestCase/@bench so that the test case is skipped.
The syntax rule is @Skip[expr].
- Currently,
exprcan betrueonly. If the expression istrue, the test is skipped. Otherwise,falseis returned. - By default,
expristrue, that is,@Skip[true]==@Skip.
@Strategy Macro
Description: The @Strategy macro can be used to create a new DataStrategy from a function. It is a shortcut API for combining, mapping, and reusing policies.
The functions labeled with @Strategy must meet the following conditions:
- The return type must be explicitly specified.
- The parameter must correspond to the DSL specified in the macro parameter.
- The functions can be used inside and outside of the class labeled with
@Test.
Implementation description: The result of the macro expansion is a DataStrategyProcessor variable with a function name. This variable can be used wherever DataStrategy is allowed.
@Test Macro
Description: @Test applies to top-level functions or classes so that they are converted into unit test classes.
For a top-level function, a class with a single test case is added to the function for use by the framework. In addition, the function can still be called as a common function.
The classes labeled with @Test must meet the following conditions:
- A parameterless constructor is contained.
- The class is not inherited from other classes.
Implementation description: The
@Testmacro introduces a new base class for any class labeled with it:unittest.TestCases. All public and protected members ofunittest.TestCases(see API overview below) will become available in the class or function labeled with@Test, including two fields: 1.ctxof theTestContextinstance 2.name, indicating the name of a class Users of the unit test framework should not modify these fields; otherwise, errors may be caused.
@TestBuilder Macro
Description: Declares a dynamic test suite.
@TestCase Macro
Description: @TestCase labels functions in a unit test class, and then these functions become test cases of the unit test.
The functions labeled with @TestCase must meet the following conditions:
- This class must be labeled with
@Test. - The return type of this function must be Unit.
@Test
class Tests {
@TestCase
func fooTest(): Unit {...}
}
A test case may have parameters. In this situation, developers must specify the values of these parameters using the parameterized test DSL:
@Test[x in source1, y in source2, z in source3]
func test(x: Int64, y: String, z: Float64): Unit {}
This DSL can be applied to @Test, @Strategy, @Bench, and @TestCase macros, where @Test is only for top-level functions. If both @Bench and @TestCase exist in a test function, only @Bench can contain a DSL. According to the DSL syntax, identifiers (x, y, and z in the example above) previous to in must directly correspond to parameters of the function, and the parameter sources (source1, source2, and source3 in the example above) are any valid Cangjie expressions. This type of expressions must implement the DataStrategy<T> or DataStrategyProcessor<T> interface. Details are provided below. The element type of the parameter sources (this type serves as the generic parameter T provided for the DataStrategy<T> interface) must be the same as the type of the corresponding function parameter.
The following parameter source types are supported:
- Array:
x in [1,2,3,4] - Ranges:
x in 0..14 - Randomly generated value:
x in random() - Value read from a JSON file:
x in json("filename.json") - Value read from a CSV file:
x in csv("filename.csv") - Function modified by
@Strategy:x in nameOfStrategyAnnotatedFunction - Result of combining data policies using DataStrategyProcessor
Advanced users can introduce custom parameter source types by defining types and implementing the DataStrategy<T> interface.
By default, the random functions generated using random() support the following types:
- Unit
- Bool
- All built-in integer types (including signed and unsigned)
- All built-in float types
- Ordering
- Array types of all supported types
- Option types of all supported types
If other types need to support
random(), you can extend Arbitrary for these type. If a parameter has multiple values,beforeEach/afterEachis executed only once instead of being executed on each value. If initialization and deinitialization need to be performed for each value, it must be specified in the principal part of the test case. For performance test schemes,@Strategyshould be used for code that needs to be excluded from the benchmark. No special API is provided for such case because code depends on specific parameter values in most cases.
@Timeout Macro
Description: @Timeout indicates that a test should be stopped after a specified period of time. It helps test complex algorithms that may run for a long time or enter an infinite loop.
The syntax rule is @Timeout[expr].
The type of expr must be std.time.Duration. It provides a timeout period for each corresponding test case when modifying a test class.
@Types Macro
Description: The @Types macro provides type parameters for test classes or test functions. It can be placed on a test class or test function.
The syntax rule is @Types[Id1 in <Type1, Type2, Type3>, Id2 in <Type4, Type5> ...], where Id1, Id2, ... are valid type parameter identifiers, and Type1, Type2, Type3, ... are valid Cangjie types.
The @Types macro has the following restrictions:
- It must be used together with the
@Test,@TestCase, or@Benchmacro. - One declaration has only one
@Typesmacro modifier. - The declaration must be a generic class or function that has the same type parameters as those listed in the
@Typesmacro. - The types in the type list cannot depend on each other. For example,
@Types[A in <Int64, String>, B in <List<A>>]cannot be compiled correctly. However, types provided for a test class can be used by test functions within the class. For example:
@Test
@Types[T in <...>]
class TestClass<T> {
@TestCase
@Types[U in <Array<T>>]
func testfunc<U>() {}
}
This mechanism can be used with other functionalities of the test framework, for example, @Configure.
std.unittest.common Package
Function Description
unittest.common provides the types and common methods required for printing in the unit test framework.
API List
Function
| Name | Description |
|---|---|
| toStringOrPlaceholder<T>(T) | Converts a parameter that implements ToString to a string. |
Interface
| Name | Description |
|---|---|
| DataProvider | Specifies a component of DataStrategy, which is used to provide test data. T specifies the data type provided by the provider. |
| DataShrinker | Specifies a component of DataStrategy, which is used to shrink data during testing. T specifies the type of data handled by the shrinker. |
| DataStrategy | Provides the data strategy for parameterized tests. T specifies the data type operated on by the strategy. |
| PrettyPrintable | Provides stronger capabilities of handling colors and indentation formats during printing for types that implement this interface. |
Class
| Name | Description |
|---|---|
| Configuration | Specifies an object for storing the unittest configuration data generated by the @Configure macro. It is a class similar to HashMap, but its keys are not of a key or value type, but of a String type and its values can be of any given type. |
| ConfigurationKey | Specifies a key value object of a configuration item. Provides the equality comparison and hashCode methods. |
| PrettyPrinter | Specifies a printer with color, alignment, and indentation controls. |
| PrettyText | Specifies a constructor-like class for storing the printed output. |
Enumeration
| Name | Description |
|---|---|
| Color | Specifies the color. |
Function
func toStringOrPlaceholder<T>(T)
public func toStringOrPlaceholder<T>(value: T)
Description: Converts the parameters that implement ToString into strings. ToString does not support conversion to the default string.
Returns:
- String: string representation of a parameter
Interface
interface DataProvider
public interface DataProvider<T> {
func provide(): Iterable<T>
func positions(): Array<Int64>
prop isInfinite: Bool
}
Description: Specifies a component of DataStrategy, which is used to provide test data. T specifies the data type provided by the provider.
prop isInfinite
prop isInfinite: Bool
Description: Checks whether infinity is not supported.
Type: Bool
func provide()
func provide(): Iterable<T>
Description: Obtains the data iterator.
Returns:
- Iterable<T>: data iterator
func positions()
func positions(): Array<Int64>
Description: Obtains the location information.
Returns:
- Array<Int64>: location information
extend<T> Array<T> <: DataProvider<T>
extend<T> Array<T> <: DataProvider<T>
Description: Implements the DataProvider<T> interface for Array. It makes the following configuration form available:
@Test[x in [1,2,3]]
func test(x: Int64) {}
Parent Type:
- DataProvider<T>
extend<T> Range<T> <: DataProvider<T>
extend<T> Range<T> <: DataProvider<T>
Description: Implements the DataProvider<T> interface for Range. It makes the following configuration form available:
@Test[x in (0..5)]
func test(x: Int64) {}
Parent Type:
- DataProvider<T>
interface DataShrinker<T>
public interface DataShrinker<T> {
func shrink(value: T): Iterable<T>
}
Description: Specifies a component of DataStrategy, which is used to shrink data during the test. T specifies the type of data handled by the shrinker.
func shrink(T)
func shrink(value: T): Iterable<T>
Description: Obtains the value of the T type and generates a set of smaller values. What is considered "smaller" data depends on the data type.
Parameters:
- value: T: shrunk value
Returns:
- Iterable<T>: Set of smaller values. If the data cannot be shrunk, an empty set is returned.
interface DataStrategy
public interface DataStrategy<T> {
func provider(configuration: Configuration): DataProvider<T>
func shrinker(configuration: Configuration): DataShrinker<T>
}
Description: Provides the data strategy for parameterized tests. T specifies the data type operated on by the strategy.
func provider(Configuration)
func provider(configuration: Configuration): DataProvider<T>
Description: Obtains the test data component.
Parameters:
- configuration: Configuration: configuration information
Returns:
- DataProvider<T>: component object that provides test data
func shrinker(Configuration)
open func shrinker(configuration: Configuration): DataShrinker<T>
Description: Obtains the component for shrinking test data.
Parameters:
- configuration: Configuration: configuration information
Returns:
- DataShrinker<T>: component object for shrinking test data
extend<T> Array<T> <: DataStrategy<T>
extend<T> Array<T> <: DataStrategy<T>
Description: Implements the DataStrategy<T> interface for Array. It makes the following configuration form available:
@Test[x in [1,2,3]]
func test(x: Int64) {}
Parent Type:
- DataStrategy<T>
extend<T> Range<T> <: DataStrategy<T>
extend<T> Range<T> <: DataStrategy<T>
Description: Implements the DataStrategy<T> interface for Range. It makes the following configuration form available:
@Test[x in (0..5)]
func test(x: Int64) {}
Parent Type:
- DataStrategy<T>
interface PrettyPrintable
public interface PrettyPrintable {
func pprint(to: PrettyPrinter): PrettyPrinter
}
Description: Provides stronger capabilities of handling colors and indentation formats during printing for types that implement this interface.
func pprint(PrettyPrinter)
func pprint(to: PrettyPrinter): PrettyPrinter
Description: Prints the type value to the specified printer.
Parameters:
- to: PrettyPrinter: printer
Returns:
- PrettyPrinter: printer
extend<T> Array<T> <: PrettyPrintable where T <: PrettyPrintable
extend<T> Array<T> <: PrettyPrintable where T <: PrettyPrintable {
}
Description: Extends the PrettyPrintable interface for the Array type.
Parent Type:
func pprint(PrettyPrinter)
public func pprint(to: PrettyPrinter): PrettyPrinter
Description: Prints Array<T> to the specified printer.
Parameters:
- to: PrettyPrinter: printer
Returns:
- PrettyPrinter: printer
extend<T> ArrayList<T> <: PrettyPrintable where T <: PrettyPrintable
extend<T> ArrayList<T> <: PrettyPrintable where T <: PrettyPrintable {
}
Description: Extends the PrettyPrintable interface for the ArrayList type.
Parent Type:
func pprint(PrettyPrinter)
public func pprint(to: PrettyPrinter): PrettyPrinter
Description: Prints ArrayList<T> to the specified printer.
Parameters:
- to: PrettyPrinter: printer
Returns:
- PrettyPrinter: printer
Class
class Configuration
public class Configuration <: ToString {
public init()
}
Description: Specifies an object for storing the unittest configuration data generated by the @Configure macro. Configuration is a class similar to HashMap, but its keys are not of a key or value type, but of a String type and its values can be of any given type.
Parent Type:
init()
public init()
Description: Constructs an empty instance.
func clone()
public func clone(): Configuration
Description: Clones an object.
Returns:
- Configuration: object cloned
func get<T>(String)
public func get<T>(key: String): ?T
Description: Obtains the value of a key.
T is a generic parameter used for searching for the value of a corresponding type in an object.
Parameters:
- key: String: key name
Returns:
- ?T: If the type is not found, None is returned, and if the type and name are found, Some<T>(v) is returned.
func remove<T>(String)
public func remove<T>(key: String): ?T
Description: Deletes the value of the corresponding key name and type.
Parameters:
- key: String: key name
Returns:
- ?T: If the value exists, the value is returned. If the value does not exist, None is returned.
func set<T>(String, T)
public func set<T>(key: String, value: T)
Description: Sets a value for the key name and type.
Parameters:
- key: String: key name
- value: T: key value
func toString()
public func toString(): String
Description: Characterized object of the object. When the internal object does not implement the ToString interface, '<not printable>' is output.
Returns:
- String: character string
static func merge(Configuration, Configuration)
public static func merge(parent: Configuration, child: Configuration): Configuration
Description: Merges the child configuration to the parent configuration. If a child key value with the same name exists, the child key value overwrites the parent key value.
Parameters:
- parent:Configuration: configuration to be merged
- child:Configuration: configuration to be merged
Returns:
- Configuration: merged configuration
extend Configuration <: BenchmarkConfig
extend Configuration <: BenchmarkConfig {}
Description: Extends the BenchmarkConfig interface for Configuration.
Parent Type:
func batchSize(Int64)
public func batchSize(b: Int64)
Description: Configures the number of execution times of a batch during a performance test.
Parameters:
- b: Int64: number of execution times
func batchSize(Range<Int64>)
public func batchSize(x: Range<Int64>)
Description: Configures the execution times range of a batch during a performance test.
Parameters:
- b: Range<Int64>: range of execution times
func explicitGC(ExplicitGcType)
public func explicitGC(x: ExplicitGcType)
Description: Configures the GC execution mode for a performance test.
Parameters:
- x: ExplicitGcType: GC execution mode
func minBatches(Int64)
public func minBatches(x: Int64)
Description: Specifies the minimum number of batches for a performance test.
Parameters:
- x: Int64: minimum number of batches
func minDuration(Duration)
public func minDuration(x: Duration)
Description: Configures the minimum execution duration of a performance test.
Parameters:
- x: Duration: minimum execution duration
func warmup(Int64)
public func warmup(x: Int64)
Description: Configures the warm-up seconds for a performance test.
Parameters:
- x: Int64: number of warm-up seconds
func warmup(Duration)
public func warmup(x: Duration)
Description: Configures the warm-up duration for a performance test.
Parameters:
- x: Duration: warm-up duration
class ConfigurationKey
abstract sealed class ConfigurationKey <: Equatable<ConfigurationKey> & Hashable {
public override operator func !=(that: ConfigurationKey)
}
Description: Specifies a key value object of a configuration item. Provides the equality comparison and hashCode methods.
Parent Type:
func equals(ConfigurationKey)
protected func equals(that: ConfigurationKey): Bool
Description: Checks whether the values are equal.
Parameters:
- that: ConfigurationKey: object to be compared with
Returns:
- Bool: whether they are equal
func hashCode
public override func hashCode(): Int64
Description: Obtains the hashCode value.
Returns:
- Int64: hashCode value
operator func ==(ConfigurationKey)
public override operator func ==(that: ConfigurationKey)
Description: Compares for equality.
Parameters:
- that: ConfigurationKey: data to be compared with
Returns:
- Bool: whether they are equal
public override operator func !=(that: ConfigurationKey)
public override operator func !=(that: ConfigurationKey)
Description: Compares for inequality.
Parameters:
- that: ConfigurationKey: data to be compared with
Returns:
- Bool: whether they are not equal
class PrettyPrinter
public abstract class PrettyPrinter {
public PrettyPrinter(let indentationSize!: UInt64 = 4, let startingIndent!: UInt64 = 0)
}
Description: Specifies a printer with color, alignment, and indentation controls.
init(UInt64,UInt64)
public PrettyPrinter(let indentationSize!: UInt64 = 4, let startingIndent!: UInt64 = 0)
Description: Specifies a constructor.
Parameters:
- indentationSize!: UInt64: number of indented spaces
- startingIndent!: UInt64: number of indents at the beginning
prop isTopLevel
public prop isTopLevel: Bool
Description: Checks whether the indentation is at the top layer of the printed content.
Type: Bool
func append(String)
public func append(text: String): PrettyPrinter
Description: Adds a string to the printer. Multi-line strings are not supported, and they cannot be indented.
Parameters:
- text: String: character string to be added
Returns:
- PrettyPrinter: printer
func append<PP>(PP)where PP <: PrettyPrintable
public func append<PP>(value: PP): PrettyPrinter where PP <: PrettyPrintable
Description: Adds an object that implements PrettyPrintable to the printer.
Parameters:
- value: PP: object that implements PrettyPrintable
Returns:
- PrettyPrinter: printer
func appendCentered(String, UInt64)
public func appendCentered(text: String, space: UInt64): PrettyPrinter
Description: Adds a string to the printer, center-aligned to the specified number of characters. If the string is shorter than the specified width, it is padded with spaces. Multi-line strings are not supported, and they cannot be indented.
Parameters:
Returns:
- PrettyPrinter: printer
func appendLeftAligned(String, UInt64)
public func appendLeftAligned(text: String, space: UInt64): PrettyPrinter
Description: Adds a string to the printer. Left-aligned to the specified number of characters. If the string is shorter than the specified width, it is padded with spaces. Multi-line strings are not supported, and they cannot be indented.
Parameters:
Returns:
- PrettyPrinter: printer
func appendLine(String): PrettyPrinter
public func appendLine(text: String): PrettyPrinter
Description: Adds a string to the printer, followed by a newline character.
Parameters:
- text: String: character string to be added
Returns:
- PrettyPrinter: printer
func appendLine<PP>(PP) where PP <: PrettyPrintable
public func appendLine<PP>(value: PP): PrettyPrinter where PP <: PrettyPrintable
Description: Adds an object that implements PrettyPrintable to the printer, followed by a newline character.
Parameters:
- value: PP: object that implements PrettyPrintable
Returns:
- PrettyPrinter: printer
func appendRightAligned(String, UInt64)
public func appendRightAligned(text: String, space: UInt64): PrettyPrinter
Description: Adds a string to the printer. Right-aligned to the specified number of characters. Multi-line strings are not supported, and they cannot be indented.
Parameters:
Returns:
- PrettyPrinter: printer
func colored(Color, body: () -> Unit)
public func colored(color: Color, body: () -> Unit): PrettyPrinter
Description: Specifies a color for the character string added to the printer within the closure. A common usage is as follows:
pp.colored(RED) {
pp.appendLine("1")
pp.appendLine("2")
pp.appendLine("3")
}
In this case, the character strings "1", "2", and "3" are printed in red.
Parameters:
- color: Color: color specified for printing
- body: () -> Unit: closure for adding a string
Returns:
- PrettyPrinter: printer
func colored(Color, String)
public func colored(color: Color, text: String): PrettyPrinter
Description: Specifies a color for the string added to the printer.
Parameters:
Returns:
- PrettyPrinter: printer
func customOffset(UInt64, body: () -> Unit)
public func customOffset(symbols: UInt64, body: () -> Unit): PrettyPrinter
Description: Specifies the number of extra indents for the string added to the printer within the closure. A common usage is as follows:
pp.customOffset(5) {
pp.appendLine("1")
pp.appendLine("2")
pp.appendLine("3")
}
In this case, the character strings "1", "2", and "3" are indented by five extra characters.
Parameters:
- symbols: UInt64: specified number of indents
- body: () -> Unit: closure for adding a string
Returns:
- PrettyPrinter: printer
func indent(body: () -> Unit)
public func indent(body: () -> Unit): PrettyPrinter
Description: Specifies an extra indent for the string added to the printer within the closure. A common usage is as follows:
pp.indent {
pp.appendLine("1")
pp.appendLine("2")
pp.appendLine("3")
}
In this case, the character strings "1", "2", and "3" are indented once.
Parameters:
- body: () -> Unit: closure for adding a string
Returns:
- PrettyPrinter: printer
func indent(UInt64, body: () -> Unit)
public func indent(indents: UInt64, body: () -> Unit): PrettyPrinter
Description: Specifies the number of extra indents for the string added to the printer within the closure. A common usage is as follows:
pp.indent(2) {
pp.appendLine("1")
pp.appendLine("2")
pp.appendLine("3")
}
In this case, the character strings "1", "2", and "3" are indented twice.
Parameters:
- indents: UInt64: specified number of extra indents
- body: () -> Unit: closure for adding a string
Returns:
- PrettyPrinter: printer
func newLine()
public func newLine(): PrettyPrinter
Description: Adds a line.
Returns:
- PrettyPrinter: printer
func put(String)
protected func put(s: String): Unit
Description: Prints a string.
Parameters:
- s: String: string to be printed
func putNewLine()
protected open func putNewLine(): Unit
Description: Prints a new line.
func setColor(Color)
protected func setColor(color: Color): Unit
Description: Sets the color.
Parameters:
- color: Color: the specified color
class PrettyText
public class PrettyText <: PrettyPrinter & PrettyPrintable & ToString {
public init()
public init(string: String)
}
Description: Specifies a constructor-like class for storing the printed output. It is used to store and transfer these values. It implements PrettyPrinter and PrettyPrintable.
Parent Type:
init()
public init()
Description: Specifies a default constructor, which is used to generate an empty object.
init(String)
public init(string: String)
Description: Specifies a constructor, which is used to generate a text constructor starting with the input parameter.
Parameters:
- string: String: string to be placed at the beginning of the text to be printed
func isEmpty()
public func isEmpty(): Bool
Description: Returns whether the current constructor is empty, that is, whether no value is transferred to the constructor.
Returns:
- Bool: If no value is passed in,
trueis returned; otherwise,falseis returned.
func pprint(PrettyPrinter)
public func pprint(to: PrettyPrinter): PrettyPrinter
Description: Prints information to the printer.
Parameters:
- to: PrettyPrinter: printer
Returns:
- PrettyPrinter: printer
func toString()
public func toString(): String
Description: Prints text to a string.
Returns:
- String: string to which the text is to be printed
static func of<PP>(PP) where PP <: PrettyPrintable
public static func of<PP>(pp: PP) where PP <: PrettyPrintable
Description: Creates PrettyText from PrettyPrintable by printing.
Parameters:
- pp: PP: type that implements PrettyPrintable
Returns:
- PrettyText: the printed text object
Enumeration
enum Color
public enum Color <: Equatable<Color> {
| RED
| GREEN
| YELLOW
| BLUE
| CYAN
| MAGENTA
| GRAY
| DEFAULT_COLOR;
}
Description: Specifies the color.
Parent Type:
RED
RED
Description: Specifies the color red.
GREEN
GREEN
Description: Specifies the color green.
YELLOW
YELLOW
Description: Specifies the color yellow.
BLUE
BLUE
Description: Specifies the color blue.
CYAN
CYAN
Description: Specifies the color cyan.
MAGENTA
MAGENTA
Description: Specifies the color magenta.
GRAY
GRAY
Description: Specifies the color gray.
DEFAULT_COLOR
DEFAULT_COLOR
Description: Specifies the default color.
operator func ==(Color)
public operator func ==(that: Color): Bool
Description: Checks whether the color values are equal.
Parameters:
- that: Color: color to be compared with
Returns:
- Bool: If they are equal,
trueis returned; otherwise,falseis returned.
operator func !=(Color)
public operator func !=(that: Color): Bool
Description: Checks whether the color values are not equal.
Parameters:
- that: Color: color to be compared with
Returns:
- Bool: If they are not equal,
trueis returned; otherwise,falseis returned.
std.unittest.diff Package
Function Description
unittest.diff provides APIs for printing difference comparison information in the unit test framework.
API List
Interface
| Name | Description |
|---|---|
| AssertPrintable | Provides the method for printing the check result of @Assert/@Expect. |
Interface
interface AssertPrintable
public interface AssertPrintable<T> {
prop hasNestedDiff: Bool
func pprintForAssertion(
pp: PrettyPrinter, that: T, thisPrefix: String, thatPrefix: String, level: Int64
): PrettyPrinter
}
Description: Provides the method for printing the check result of @Assert/@Expect.
prop hasNestedDiff
prop hasNestedDiff: Bool
Description: Checks whether there are nested diff levels.
Type: Bool
func pprintForAssertion(PrettyPrinter, T, String, String, Int64)
func pprintForAssertion(
pp: PrettyPrinter, that: T, thisPrefix: String, thatPrefix: String, level: Int64
): PrettyPrinter
Description: Prints the check result of @Assert/@Expect.
Parameters:
- pp: PrettyPrinter: printer
- that: T: information to be printed
- thisPrefix: String: prefix of the expected content
- thatPrefix: String: prefix of the actual content
- level: Int64: nesting level
Returns:
- PrettyPrinter: printer
std.unittest.prop_test Package
Function Description
unittest.prop_test provides the unit test framework with the types and methods required for parameterized tests.
API List
Function
| Name | Description |
|---|---|
| emptyIterable<T>() | Creates an empty iterator. |
| random<T>() | Generates random data of the T type. T must implement the Arbitrary<T> interface. The return value of this function is a parameter source for parameterized tests. |
Interface
| Name | Description |
|---|---|
| Arbitrary | Generates random values of the T type. |
| IndexAccess | Serves as the utility interface for accessing tuple elements through indexes. |
| RandomSource | Provides the capability of randomly generating basic data required by Arbitrary. |
| Shrink | Reduces a T-type value to multiple smaller values. |
Class
| Name | Description |
|---|---|
| Generators | Provides auxiliary functions for helping developers compile their own generators. |
| LazySeq | Specifies the sequence of T-type values for delay calculation. It is used to calculate and memorize values during iteration. |
| ShrinkHelpers | Provides a method for implementing the reduce iterator for tuples. |
Struct
| Name | Description |
|---|---|
| Function0Wrapper | Wraps a closure into a struct. |
| TupleWrapper2 | Wraps a closure into a struct. The closure contains two parameters. |
| TupleWrapper3 | Wraps a closure into a struct. The closure contains three parameters. |
| TupleWrapper4 | Wraps a closure into a struct. The closure contains four parameters. |
| TupleWrapper5 | Wraps a closure into a struct. The closure contains five parameters. |
Function
func emptyIterable<T>()
public func emptyIterable<T>(): Iterable<T>
Description: Creates an empty iterator.
Returns:
- Iterator<T>: empty iterator
func random<T>() where T <: Arbitrary<T>
public func random<T>(): RandomDataStrategy<T> where T <: Arbitrary<T>
Description: Generates random data of the T type. T must implement the Arbitrary<T> interface. The return value of this function is a parameter source for parameterized tests.
Returns:
- Arbitrary<T>: instance of the RandomDataStrategy interface generated using random data
Interface
interface Arbitrary
public interface Arbitrary<T> {
static func arbitrary(random: RandomSource): Generator<T>
}
Description: Generates random values of the T type.
static func arbitrary(RandomSource)
static func arbitrary(random: RandomSource): Generator<T>
Description: Obtains the generator for generating random values of the T type.
Parameters:
- random: RandomSource: random number
Returns:
- Generator<T>: generator for generating random values of the T type
extend Bool <: Arbitrary<Bool>
extend Bool <: Arbitrary<Bool>
Description: Implements the Arbitrary<T> interface for the Bool type.
Parent Type:
static func arbitrary(RandomSource)
static func arbitrary(random: RandomSource): Generator<Bool>
Description: Obtains the generator for generating random values of the T type.
Parameters:
- random: RandomSource: random number
Returns:
- Generator<Bool>: generator for generating random values of the Bool type
extend Float16 <: Arbitrary<Float16>
extend Float16 <: Arbitrary<Float16>
Description: Implements the Arbitrary<T> interface for the Float16 type.
Parent Type:
static func arbitrary(RandomSource)
static func arbitrary(random: RandomSource): Generator<Float16>
Description: Obtains the generator for generating random values of the T type.
Parameters:
- random: RandomSource: random number
Returns:
- Generator<Float16>: generator for generating random values of the Float16 type
extend Float32 <: Arbitrary<Float32>
extend Float32 <: Arbitrary<Float32>
Description: Implements the Arbitrary<T> interface for the Float32 type.
Parent Type:
static func arbitrary(RandomSource)
static func arbitrary(random: RandomSource): Generator<Float32>
Description: Obtains the generator for generating random values of the T type.
Parameters:
- random: RandomSource: random number
Returns:
- Generator<Float32>: generator for generating random values of the Float32 type
extend Float64 <: Arbitrary<Float64>
extend Float64 <: Arbitrary<Float64>
Description: Implements the Arbitrary<T> interface for the Float64 type.
Parent Type:
static func arbitrary(RandomSource)
static func arbitrary(random: RandomSource): Generator<Float64>
Description: Obtains the generator for generating random values of the T type.
Parameters:
- random: RandomSource: random number
Returns:
- Generator<Float64>: generator for generating random values of the Float64 type
extend Int16 <: Arbitrary<Int16>
extend Int16 <: Arbitrary<Int16>
Description: Implements the Arbitrary<T> interface for the Int16 type.
Parent Type:
static func arbitrary(RandomSource)
static func arbitrary(random: RandomSource): Generator<Int16>
Description: Obtains the generator for generating random values of the T type.
Parameters:
- random: RandomSource: random number
Returns:
- Generator<Int16>: generator for generating random values of the Int16 type
extend Int32 <: Arbitrary<Int32>
extend Int32 <: Arbitrary<Int32>
Description: Implements the Arbitrary<T> interface for the Int32 type.
Parent Type:
static func arbitrary(RandomSource)
static func arbitrary(random: RandomSource): Generator<Int32>
Description: Obtains the generator for generating random values of the T type.
Parameters:
- random: RandomSource: random number
Returns:
- Generator<Int32>: generator for generating random values of the Int32 type
extend Int64 <: Arbitrary<Int64>
extend Int64 <: Arbitrary<Int64>
Description: Implements the Arbitrary<T> interface for the Int64 type.
Parent Type:
static func arbitrary(RandomSource)
static func arbitrary(random: RandomSource): Generator<Int64>
Description: Obtains the generator for generating random values of the Int64 type.
Parameters:
- random: RandomSource: random number
Returns:
- Generator<Int64>: generator for generating random values of the Int64 type
extend Int8 <: Arbitrary<Int8>
extend Int8 <: Arbitrary<Int8>
Description: Implements the Arbitrary<T> interface for the Int8 type.
Parent Type:
static func arbitrary(RandomSource)
static func arbitrary(random: RandomSource): Generator<Int8>
Description: Obtains the generator for generating random values of the Int8 type.
Parameters:
- random: RandomSource: random number
Returns:
- Generator<Int8>: generator for generating random values of the Int8 type
extend IntNative <: Arbitrary<IntNative>
extend IntNative <: Arbitrary<IntNative>
Description: Implements the Arbitrary<T> interface for the IntNative type.
Parent Type:
static func arbitrary(RandomSource)
static func arbitrary(random: RandomSource): Generator<IntNative>
Description: Obtains the generator for generating random values of the IntNative type.
Parameters:
- random: RandomSource: random number
Returns:
- Generator<IntNative>: generator for generating random values of the IntNative type
extend Ordering <: Arbitrary<Ordering>
extend Ordering <: Arbitrary<Ordering>
Description: Implements the Arbitrary<T> interface for the Ordering type.
Parent Type:
static func arbitrary(RandomSource)
static func arbitrary(random: RandomSource): Generator<Ordering>
Description: Obtains the generator for generating random values of the Ordering type.
Parameters:
- random: RandomSource: random number
Returns:
- Generator<Ordering>: generator for generating random values of the Ordering type
extend Rune <: Arbitrary<Rune>
extend Rune <: Arbitrary<Rune>
Description: Implements the Arbitrary<T> interface for the Rune type.
Parent Type:
static func arbitrary(RandomSource)
static func arbitrary(random: RandomSource): Generator<Rune>
Description: Obtains the generator for generating random values of the Rune type.
Parameters:
- random: RandomSource: random number
Returns:
- Generator<Rune>: generator for generating random values of the Rune type
extend String <: Arbitrary<String>
extend String <: Arbitrary<String>
Description: Implements the Arbitrary<T> interface for the String type.
Parent Type:
static func arbitrary(RandomSource)
static func arbitrary(random: RandomSource): Generator<String>
Description: Obtains the generator for generating random values of the String type.
Parameters:
- random: RandomSource: random number
Returns:
- Generator<String>: generator for generating random values of the String type
extend UInt16 <: Arbitrary<UInt16>
extend UInt16 <: Arbitrary<UInt16>
Description: Implements the Arbitrary<T> interface for the UInt16 type.
Parent Type:
static func arbitrary(RandomSource)
static func arbitrary(random: RandomSource): Generator<UInt16>
Description: Obtains the generator for generating random values of the UInt16 type.
Parameters:
- random: RandomSource: random number
Returns:
- Generator<UInt16>: generator for generating random values of the UInt16 type
extend UInt32 <: Arbitrary<UInt32>
extend UInt32 <: Arbitrary<UInt32>
Description: Implements the Arbitrary<T> interface for the UInt32 type.
Parent Type:
static func arbitrary(RandomSource)
static func arbitrary(random: RandomSource): Generator<UInt32>
Description: Obtains the generator for generating random values of the UInt32 type.
Parameters:
- random: RandomSource: random number
Returns:
- Generator<UInt32>: generator for generating random values of the UInt32 type
extend UInt64 <: Arbitrary<UInt64>
extend UInt64 <: Arbitrary<UInt64>
Description: Implements the Arbitrary<T> interface for the UInt64 type.
Parent Type:
static func arbitrary(RandomSource)
static func arbitrary(random: RandomSource): Generator<UInt64>
Description: Obtains the generator for generating random values of the UInt64 type.
Parameters:
- random: RandomSource: random number
Returns:
- Generator<UInt64>: generator for generating random values of the UInt64 type
extend UInt8 <: Arbitrary<UInt8>
extend UInt8 <: Arbitrary<UInt8>
Description: Implements the Arbitrary<T> interface for the UInt8 type.
Parent Type:
static func arbitrary(RandomSource)
static func arbitrary(random: RandomSource): Generator<UInt8>
Description: Obtains the generator for generating random values of the UInt8 type.
Parameters:
- random: RandomSource: random number
Returns:
- Generator<UInt8>: generator for generating random values of the UInt8 type
extend UIntNative <: Arbitrary<UIntNative>
extend UIntNative <: Arbitrary<UIntNative>
Description: Implements the Arbitrary<T> interface for the UIntNative type.
Parent Type:
static func arbitrary(RandomSource)
static func arbitrary(random: RandomSource): Generator<UIntNative>
Description: Obtains the generator for generating random values of the UIntNative type.
Parameters:
- random: RandomSource: random number
Returns:
- Generator<UIntNative>: generator for generating random values of the UIntNative type
extend Unit <: Arbitrary<Unit>
extend Unit <: Arbitrary<Unit>
Description: Implements the Arbitrary<T> interface for the Unit type.
Parent Type:
static func arbitrary(RandomSource)
static func arbitrary(random: RandomSource): Generator<Unit>
Description: Obtains the generator for generating random values of the Unit type.
Parameters:
- random: RandomSource: random number
Returns:
- Generator<Unit>: generator for generating random values of the Unit type
extend<T> Array<T> <: Arbitrary<Array<T>> where T <: Arbitrary<T>
extend<T> Array<T> <: Arbitrary<Array<T>> where T <: Arbitrary<T>
Description: Implements the Arbitrary<Array<T>> interface for the Array<T> type, where T needs to implement the Arbitrary<T> interface.
Parent Type:
static func arbitrary(RandomSource)
static func arbitrary(random: RandomSource): Generator<Array<T>>
Description: Obtains the generator for generating random values of the Array<T> type.
Parameters:
- random: RandomSource: random number
Returns:
- Generator<Array<T>>: generator for generating random values of the Array<T> type
extend<T> Option<T> <: Arbitrary<Option<T>> where T <: Arbitrary<T>
extend<T> option<T> <: Arbitrary<Option<T>> where T <: Arbitrary<T>
Description: Implements the Arbitrary<Option<T>> interface for the Option<T> type, where T needs to implement the Arbitrary<T> interface.
Parent Type:
static func arbitrary(RandomSource)
static func arbitrary(random: RandomSource): Generator<option<T>>
Description: Obtains the generator for generating random values of the option<T> type.
Parameters:
- random: RandomSource: random number
Returns:
- Generator<option<T>>: generator for generating random values of the option<T> type
extend<T> ArrayList<T> <: Arbitrary<ArrayList<T>> where T <: Arbitrary<T>
extend<T> ArrayList<T> <: Arbitrary<ArrayList<T>> where T <: Arbitrary<T>
Description: Implements the Arbitrary interface for the ArrayList<T> type, where T needs to implement the Arbitrary<T> interface.
Parent Type:
static func arbitrary(RandomSource)
static func arbitrary(random: RandomSource): Generator<ArrayList<T>>
Description: Obtains the generator for generating random values of the ArrayList<T> type.
Parameters:
- random: RandomSource: random number
Returns:
- Generator<ArrayList<T>>: generator for generating random values of the ArrayList<T> type
extend<T> HashSet<T> <: Arbitrary<HashSet<T>> where T <: Arbitrary<T>
extend<T> HashSet<T> <: Arbitrary<HashSet<T>> where T <: Arbitrary<T>
Description: Implements the Arbitrary interface for the HashSet<T> type, where T needs to implement the Arbitrary<T> interface.
Parent Type:
static func arbitrary(RandomSource)
static func arbitrary(random: RandomSource): Generator<HashSet<T>>
Description: Obtains the generator for generating random values of the HashSet<T> type.
Parameters:
- random: RandomSource: random number
Returns:
- Generator<HashSet<T>>: generator for generating random values of the HashSet<T> type
extend<K, V> HashMap<K, V> <: Arbitrary<HashMap<K, V>> where K <: Arbitrary<K>, V <: Arbitrary<V>
extend<K, V> HashMap<K, V> <: Arbitrary<HashMap<K, V>> where K <: Arbitrary<K>, V <: Arbitrary<V>
Description: Implements the Arbitrary interface for the HashMap<T> type, where T needs to implement the Arbitrary<T> interface.
Parent Type:
static func arbitrary(RandomSource)
static func arbitrary(random: RandomSource): Generator<HashMap<K, V>>
Description: Obtains the generator for generating random values of the HashMap<K, V> type.
Parameters:
- random: RandomSource: random number
Returns:
- Generator<HashMap<K, V>>: generator for generating random values of the HashMap<K, V> type
interface IndexAccess
public interface IndexAccess {
func getElementAsAny(index: Int64): ?Any
}
Description: Serves as the utility interface for accessing tuple elements through indexes.
func getElementAsAny(Int64)
func getElementAsAny(index: Int64): ?Any
Description: Accesses tuple elements through indexes.
Parameters:
- index: Int64: index
Returns:
- ?Any: element value. If it is not obtained,
Noneis returned.
interface RandomSource
public interface RandomSource {
func nextBool(): Bool
func nextInt8(): Int8
func nextInt16(): Int16
func nextInt32(): Int32
func nextInt64(): Int64
func nextInt8(max: Int8): Int8
func nextInt16(max: Int16): Int16
func nextInt32(max: Int32): Int32
func nextInt64(max: Int64): Int64
func nextUInt8(): UInt8
func nextUInt16(): UInt16
func nextUInt32(): UInt32
func nextUInt64(): UInt64
func nextUInt8(max: UInt8): UInt8
func nextUInt16(max: UInt16): UInt16
func nextUInt32(max: UInt32): UInt32
func nextUInt64(max: UInt64): UInt64
func nextFloat16(): Float16
func nextFloat32(): Float32
func nextFloat64(): Float64
func nextGaussianFloat64(mean!: Float64, sigma!: Float64): Float64
func nextIntNative(): IntNative
func nextUIntNative(): UIntNative
func suggestUInt8(): UInt8
func suggestUInt16(): UInt16
func suggestUInt32(): UInt32
func suggestUInt64(): UInt64
func suggestUIntNative(): UIntNative
func suggestInt8(): Int8
func suggestInt16(): Int16
func suggestInt32(): Int32
func suggestInt64(): Int64
func suggestIntNative(): IntNative
func suggestFloat16(): Float16
func suggestFloat32(): Float32
func suggestFloat64(): Float64
func suggestBool(): Bool
func suggestRune(): Rune
}
Description: Provides the capability of randomly generating basic data required by Arbitrary.
func nextBool()
public open func nextBool(): Bool
Description: Obtains a pseudo-random value of the Boolean type.
Returns:
func nextFloat16()
public open func nextFloat16(): Float16
Description: Obtains a pseudo-random number of the Float16 type. The range is [0.0,1.0).
Returns:
func nextFloat32()
public open func nextFloat32(): Float32
Description: Obtains a pseudo-random number of the Float32 type. The range is [0.0,1.0).
Returns:
func nextFloat64()
public open func nextFloat64(): Float64
Description: Obtains a pseudo-random number of the Float64 type. The range is [0.0,1.0).
Returns:
func nextGaussianFloat64(Float64, Float64)
public func nextGaussianFloat64(mean!: Float64 = 0.0, sigma!: Float64 = 1.0): Float64
Description: Obtains a random number of the Float64 type complying with a Gaussian distribution where the mean and standard deviation are specified.
By default, a random number of the Float64 type is obtained, complying with a Gaussian distribution where the mean is 0.0 and the standard deviation is 1.0. The mean is an expected value and can be interpreted as a location parameter, which determines the location of the distribution. The standard deviation can be interpreted as a scale parameter, which determines the amplitude of the distribution. This function calls the function nextGaussianFloat64Implement to obtain a return value. Therefore, when a subclass inherits Random and overwrites the function nextGaussianFloat64Implement, the return value of the overwritten function is returned when this function of the subclass is called.
Parameters:
- mean!: Float64: mean, with the default value of 0.0
- sigma!: Float64: standard deviation, with the default value of 1.0
Returns:
func nextInt16()
public open func nextInt16(): Int16
Description: Obtains a pseudo-random number of the Int16 type.
Returns:
func nextInt16(Int16)
public open func nextInt16(upper: Int16): Int16
Description: Obtains a pseudo-random number of the Int16 type with the range of [0,upper).
Parameters:
- upper: Int16: upper bound of the generated pseudo-random number (not including
upper). The value range is (0,Int16.Max].
Returns:
Throws:
- IllegalArgumentException: If the value of
upperis less than or equal to 0, this exception is thrown.
func nextInt32()
public open func nextInt32(): Int32
Description: Obtains a pseudo-random number of the Int32 type.
Returns:
func nextInt32(Int32)
public open func nextInt32(upper: Int32): Int32
Description: Obtains a pseudo-random number of the Int32 type with the range of [0,upper).
Parameters:
- upper: Int32: upper bound of the generated pseudo-random number (not including
upper). The value range is (0,Int32.Max].
Returns:
Throws:
- IllegalArgumentException: If the value of
upperis less than or equal to 0, this exception is thrown.
func nextInt64()
public open func nextInt64(): Int64
Description: Obtains a pseudo-random number of the Int64 type.
Returns:
func nextInt64(Int64)
public open func nextInt64(upper: Int64): Int64
Description: Obtains a pseudo-random number of the Int64 type with the range of [0,upper).
Parameters:
- upper: Int64: upper bound of the generated pseudo-random number (not including
upper). The value range is (0,Int64.Max].
Returns:
Throws:
- IllegalArgumentException: If the value of
upperis less than or equal to 0, this exception is thrown.
func nextInt8()
public open func nextInt8(): Int8
Description: Obtains a pseudo-random number of the Int8 type.
Returns:
func nextInt8(Int8): Int8
public open func nextInt8(upper: Int8): Int8
Description: Obtains a pseudo-random number of the Int8 type with the range of [0,upper).
Parameters:
- upper: Int8: upper bound of the generated pseudo-random number (not including
upper). The value range is (0,Int8.Max].
Returns:
Throws:
- IllegalArgumentException: If the value of
upperis less than or equal to 0, this exception is thrown.
func nextIntNative():IntNative
public func nextIntNative(): IntNative
Description: Obtains a pseudo-random number of the IntNative type.
Returns:
func nextUInt16()
public open func nextUInt16(): UInt16
Description: Obtains a pseudo-random number of the UInt16 type.
Returns:
func nextUInt16(UInt16)
public open func nextUInt16(upper: UInt16): UInt16
Description: Obtains a pseudo-random number of the UInt16 type with the range of [0,upper).
Parameters:
- upper: UInt16: upper bound of the generated pseudo-random number (not including
upper). The value range is (0,UInt16.Max].
Returns:
Throws:
- IllegalArgumentException: If the value of
upperis 0, this exception is thrown.
func nextUInt32()
public open func nextUInt32(): UInt32
Description: Obtains a pseudo-random number of the UInt32 type.
Returns:
func nextUInt32(UInt32)
public open func nextUInt32(upper: UInt32): UInt32
Description: Obtains a pseudo-random number of the UInt32 type with the range of [0,upper).
Parameters:
- upper: UInt32: upper bound of the generated pseudo-random number (not including
upper). The value range is (0,UInt32.Max].
Returns:
Throws:
- IllegalArgumentException: If the value of
upperis 0, this exception is thrown.
func nextUInt64()
public open func nextUInt64(): UInt64
Description: Obtains a pseudo-random number of the UInt64 type.
Returns:
func nextUInt64(UInt64)
public open func nextUInt64(upper: UInt64): UInt64
Description: Obtains a pseudo-random number of the UInt64 type with the range of [0,upper).
Parameters:
- upper: UInt64: upper bound of the generated pseudo-random number (not including
upper). The value range is (0,UInt64.Max].
Returns:
Throws:
- IllegalArgumentException: If the value of
upperis 0, this exception is thrown.
func nextUInt8()
public open func nextUInt8(): UInt8
Description: Obtains a pseudo-random number of the UInt8 type.
Returns:
func nextUInt8(UInt8)
public open func nextUInt8(upper: UInt8): UInt8
Description: Obtains a pseudo-random number of the UInt8 type with the range of [0,upper).
Parameters:
- upper: UInt8: upper bound of the generated pseudo-random number (not including
upper). The value range is (0,UInt8.Max].
Returns:
Throws:
- IllegalArgumentException: If the value of
upperis 0, this exception is thrown.
func nextUIntNative():UIntNative
public func nextUIntNative(): UIntNative
Description: Obtains a pseudo-random number of the UIntNative type.
Returns:
- UIntNative: pseudo-random number of the UIntNative type
func suggestBool()
public open func suggestBool(): Bool
Description: Obtains a pseudo-random value of the Boolean type.
Returns:
func suggestRune()
public open func suggestRune(): Rune
Description: Obtains a pseudo-random value of the Rune type.
Returns:
func suggestFloat16()
public open func suggestFloat16(): Float16
Description: Obtains a pseudo-random number of the Float16 type. The range is [0.0,1.0).
Returns:
func suggestFloat32()
public open func suggestFloat32(): Float32
Description: Obtains a pseudo-random number of the Float32 type. The range is [0.0,1.0).
Returns:
func suggestFloat64()
public open func suggestFloat64(): Float64
Description: Obtains a pseudo-random number of the Float64 type. The range is [0.0,1.0).
Returns:
func suggestInt16()
public open func suggestInt16(): Int16
Description: Obtains a pseudo-random number of the Int16 type.
Returns:
func suggestInt32()
public open func suggestInt32(): Int32
Description: Obtains a pseudo-random number of the Int32 type.
Returns:
func suggestInt64()
public open func suggestInt64(): Int64
Description: Obtains a pseudo-random number of the Int64 type.
Returns:
func suggestInt8()
public open func suggestInt8(): Int8
Description: Obtains a pseudo-random number of the Int8 type.
Returns:
func suggestIntNative():IntNative
public func suggestIntNative(): IntNative
Description: Obtains a pseudo-random number of the IntNative type.
Returns:
func suggestUInt16()
public open func suggestUInt16(): UInt16
Description: Obtains a pseudo-random number of the UInt16 type.
Returns:
func suggestUInt32()
public open func suggestUInt32(): UInt32
Description: Obtains a pseudo-random number of the UInt32 type.
Returns:
func suggestUInt64()
public open func suggestUInt64(): UInt64
Description: Obtains a pseudo-random number of the UInt64 type.
Returns:
func suggestUInt8()
public open func suggestUInt8(): UInt8
Description: Obtains a pseudo-random number of the UInt8 type.
Returns:
func suggestUIntNative():UIntNative
public func suggestUIntNative(): UIntNative
Description: Obtains a pseudo-random number of the UIntNative type.
Returns:
- UIntNative: pseudo-random number of the UIntNative type
interface Shrink<T>
public interface Shrink<T> {
func shrink(): Iterable<T>
}
Description: Reduces a T-type value to multiple smaller values.
func shrink()
func shrink(): Iterable<T>
Description: Reduces a value to a set of possible smaller values.
Returns:
- Iterable<T>: iterator for a set of possible smaller values
extend Bool <: Shrink<Bool>
extend Bool <: Shrink<Bool>
Description: Implements the Shrink<T> interface for the Bool type.
Parent Type:
func shrink()
func shrink(): Iterable<Bool>
Description: Reduces a value to a set of possible smaller values.
Returns:
- Iterable<Bool>: iterator for a set of possible smaller values
extend Int16 <: Shrink<Int16>
extend Int16 <: Shrink<Int16>
Description: Implements the Shrink<T> interface for the Int16 type.
Parent Type:
func shrink()
func shrink(): Iterable<Int16>
Description: Reduces a value to a set of possible smaller values.
Returns:
- Iterable<Int16>: iterator for a set of possible smaller values
extend Int32 <: Shrink<Int32>
extend Int32 <: Shrink<Int32>
Description: Implements the Shrink<T> interface for the Int32 type.
Parent Type:
func shrink()
func shrink(): Iterable<Int32>
Description: Reduces a value to a set of possible smaller values.
Returns:
- Iterable<Int32>: iterator for a set of possible smaller values
extend Int64 <: Shrink<Int64>
extend Int64 <: Shrink<Int64>
Description: Implements the Shrink<T> interface for the Int64 type.
Parent Type:
func shrink()
func shrink(): Iterable<Int64>
Description: Reduces a value to a set of possible smaller values.
Returns:
- Iterable<Int64>: iterator for a set of possible smaller values
extend Int8 <: Shrink<Int8>
extend Int8 <: Shrink<Int8>
Description: Implements the Shrink<T> interface for the Int8 type.
Parent Type:
func shrink()
func shrink(): Iterable<Int8>
Description: Reduces a value to a set of possible smaller values.
Returns:
- Iterable<Int8>: iterator for a set of possible smaller values
extend IntNative <: Shrink<IntNative>
extend IntNative <: Shrink<IntNative>
Description: Implements the Shrink<T> interface for the IntNative type.
Parent Type:
func shrink()
func shrink(): Iterable<IntNative>
Description: Reduces a value to a set of possible smaller values.
Returns:
- Iterable<IntNative>: iterator for a set of possible smaller values
extend Rune <: Shrink<Rune>
extend Rune <: Shrink<Rune>
Description: Implements the Shrink<T> interface for the Rune type.
Parent Type:
func shrink()
func shrink(): Iterable<Rune>
Description: Reduces a value to a set of possible smaller values.
Returns:
- Iterable<Rune>: iterator for a set of possible smaller values
extend String <: Shrink<String>
extend String <: Shrink<String>
Description: Implements the Shrink<T> interface for the String type.
Parent Type:
func shrink()
func shrink(): Iterable<String>
Description: Reduces a value to a set of possible smaller values.
Returns:
- Iterable<String>: iterator for a set of possible smaller values
extend UInt16 <: Shrink<UInt16>
extend UInt16 <: Shrink<UInt16>
Description: Implements the Shrink<T> interface for the UInt16 type.
Parent Type:
func shrink()
func shrink(): Iterable<UInt16>
Description: Reduces a value to a set of possible smaller values.
Returns:
- Iterable<UInt16>: iterator for a set of possible smaller values
extend UInt32 <: Shrink<UInt32>
extend UInt32 <: Shrink<UInt32>
Description: Implements the Shrink<T> interface for the UInt32 type.
Parent Type:
func shrink()
func shrink(): Iterable<UInt32>
Description: Reduces a value to a set of possible smaller values.
Returns:
- Iterable<UInt32>: iterator for a set of possible smaller values
extend UInt64 <: Shrink<UInt64>
extend UInt64 <: Shrink<UInt64>
Description: Implements the Shrink<T> interface for the UInt64 type.
Parent Type:
func shrink()
func shrink(): Iterable<UInt64>
Description: Reduces a value to a set of possible smaller values.
Returns:
- Iterable<UInt64>: iterator for a set of possible smaller values
extend UInt8 <: Shrink<UInt8>
extend UInt8 <: Shrink<UInt8>
Description: Implements the Shrink<T> interface for the UInt8 type.
Parent Type:
func shrink()
func shrink(): Iterable<UInt8>
Description: Reduces a value to a set of possible smaller values.
Returns:
- Iterable<UInt8>: iterator for a set of possible smaller values
extend UIntNative <: Shrink<UIntNative>
extend UIntNative <: Shrink<UIntNative>
Description: Implements the Shrink<T> interface for the UIntNative type.
Parent Type:
func shrink()
func shrink(): Iterable<UIntNative>
Description: Reduces a value to a set of possible smaller values.
Returns:
- Iterable<UIntNative>: iterator for a set of possible smaller values
extend Unit <: Shrink<Unit>
extend Unit <: Shrink<Unit>
Description: Implements the Shrink<T> interface for the Unit type.
Parent Type:
func shrink()
func shrink(): Iterable<Unit>
Description: Reduces a value to a set of possible smaller values.
Returns:
- Iterable<Unit>: iterator for a set of possible smaller values
extend<T> Array<T> <: Shrink<Array<T>> where T <: Shrink<T>
extend<T> Array<T> <: Shrink<Array<T>> where T <: Shrink<T>
Description: Implements the Shrink<Array<T>> interface for the Array<T> type, where T needs to implement the Shrink<T> interface.
Parent Type:
func shrink()
func shrink(): Iterable<Array<T>>
Description: Reduces a value to a set of possible smaller values.
Returns:
- Iterable<Array<T>>: iterator for a set of possible smaller values
extend<T> Option<T> <: Shrink<Option<T>> where T <: Shrink<T>
extend<T> Option<T> <: Shrink<Option<T>> where T <: Shrink<T>
Description: Implements the Shrink<Option<T>> interface for the Option<T> type, where T needs to implement the Shrink<T> interface.
Parent Type:
func shrink()
func shrink(): Iterable<Option<T>>
Description: Reduces a value to a set of possible smaller values.
Returns:
- Iterable<Option<T>>: iterator for a set of possible smaller values
Class
class Generators
public class Generators {}
Description: Provides auxiliary functions for helping developers compile their own generators.
static func generate<T>(() -> T)
public static func generate<T>(body: () -> T): Generator<T>
Description: Generates a value generator by repeatedly calling functions.
Parameters:
- body: () -> T: generator closure that is called
Returns:
- Generator<T>: generator
static func iterable<T>(RandomSource, Array<T>)
public static func iterable<T>(random: RandomSource, collection: Array<T>): Generator<T>
Description: Generates a value generator through random selection from an array.
Parameters:
- random: RandomSource: random number
- collection: Array<T>: array to which the selected number belongs
Returns:
- Generator<T>: generator
static func lookup<T>(RandomSource) where T <: Arbitrary<T>
public static func lookup<T>(random: RandomSource): Generator<T> where T <: Arbitrary<T>
Description: Specifies the generator provided by the Arbitrary instance of T.
Parameters:
- random: RandomSource: random number
Returns:
- Generator<T>: generator
static func mapped<T, R>(RandomSource,(T) -> R) where T <: Arbitrary<T>
public static func mapped<T, R>(random: RandomSource, body: (T) -> R): Generator<R> where T <: Arbitrary<T>
Description: Obtains the generator provided by the Arbitrary instance of T, and uses the function body to generate a value of the R type.
Parameters:
- random: RandomSource: random number
- body: (T) -> R: value of the R type
Returns:
- Generator<T>: generator
static func mapped<T1, T2, R>(RandomSource, (T1, T2) -> R) where T1 <: Arbitrary<T1>, T2 <: Arbitrary<T2>
public static func mapped<T1, T2, R>(random: RandomSource, body: (T1, T2) -> R): Generator<R> where T1 <: Arbitrary<T1>, T2 <: Arbitrary<T2>
Description: Obtains the generator provided by the Arbitrary instance of T1 and T2, and uses the function body to generate a value of the R type.
Parameters:
- random: RandomSource: random number
- body: (T1, T2) -> R: value of the R type
Returns:
- Generator<T>: generator
static func mapped<T1, T2, T3, R>(RandomSource, (T1, T2, T3) -> R) where T1 <: Arbitrary<T1>, T2 <: Arbitrary<T2>, T3 <: Arbitrary<T3>
public static func mapped<T1, T2, T3, R>(random: RandomSource, body: (T1, T2, T3) -> R): Generator<R>
where T1 <: Arbitrary<T1>, T2 <: Arbitrary<T2>, T3 <: Arbitrary<T3>
Description: Obtains the generator provided by the Arbitrary instance of T1, T2 and T3, and uses the function body to generate a value of the R type.
Parameters:
- random: RandomSource: random number
- body: (T1, T2, T3) -> R: value of the R type
Returns:
- Generator<T>: generator
static func mapped<T1, T2, T3, T4, R>(RandomSource, (T1, T2, T3, T4) -> R) where T1 <: Arbitrary<T1>, T2 <: Arbitrary<T2>, T3 <: Arbitrary<T3>, T4 <: Arbitrary<T4>
public static func mapped<T1, T2, T3, T4, R>(random: RandomSource, body: (T1, T2, T3, T4) -> R): Generator<R>
where T1 <: Arbitrary<T1>, T2 <: Arbitrary<T2>, T3 <: Arbitrary<T3>, T4 <: Arbitrary<T4>
Description: Obtains the generator provided by the Arbitrary instance of T1, T2, T3, and T4, and uses the function body to generate a value of the R type.
Parameters:
- random: RandomSource: random number
- body: (T1, T2, T3, T4) -> R: value of the R type
Returns:
- Generator<T>: generator
static func pick<T>(RandomSource, Array<Generator<T>>)
public static func pick<T>(random: RandomSource, variants: Array<Generator<T>>): Generator<T>
Description: Generates a value generator through random selection from a generator array.
Parameters:
- random: RandomSource: random number
- variants: Array<Generator<T>>: generator array
Returns:
- Generator<T>: generator
static func single<T>(T)
public static func single<T>(value: T): Generator<T>
Description: The generator always returns the same value.
Parameters:
- value: T: value returned by the generator
Returns:
- Generator<T>: generator
static func weighted<T>(RandomSource, Array<(UInt64, Generator<T>)>)
public static func weighted<T>(random: RandomSource, variants: Array<(UInt64, Generator<T>)>): Generator<T>
Description: Generates a value generator through random selection from paired arrays (weight and generator).
Parameters:
- random: RandomSource: random number
- variants: Array<(UInt64, Generator<T>)>: array (weight and generator)
Returns:
- Generator<T>: generator
class LazySeq
public class LazySeq<T> <: Iterable<T> {
public init()
public init(element: T)
}
Description: Specifies the sequence of T-type values for delay calculation. It is used to calculate and memorize values during iteration. This is completely immutable, and a new sequence is generated during each operation.
Parent Type:
- Iterable<T>
init()
public init()
Description: Specifies a constructor.
init(T)
public init(element: T)
Description: Specifies a constructor.
Parameters:
- element: T: initial element
func append(T)
public func append(element: T): LazySeq<T>
Description: Adds an element.
Parameters:
- element: T: added element
Returns:
- LazySeq<T>: sequence with the element added
func concat(LazySeq<T>)
public func concat(other: LazySeq<T>): LazySeq<T>
Description: Adds a sequence to the sequence. The complexity is O(1).
Parameters:
- other: LazySeq<T>: added sequence
Returns:
- LazySeq<T>: sequence with the element added
func iterator()
public func iterator(): Iterator<T>
Description: Specifies an iterator that implements sequences.
Returns:
- Iterator<T>: sequence iterator
func map<U>((T) -> U)
public func map<U>(body: (T) -> U): [LazySeq](#class-lazyseq)<U>
Description: Executes a closure on each element in a sequence.
Parameters:
- body: (T) -> U: closure executed on each element
Returns:
- LazySeq<U>: processed sequence
func mixWith(LazySeq<T>)
public func mixWith(other: LazySeq<T>): LazySeq<T>
Description: Inserts a new sequence into the original sequence, for example, {1,2,3,4}.mixWith({5,6,7}) -> {1,5,2,6,3,7,4}.
Parameters:
- other: LazySeq<T>: sequence to be inserted
Returns:
- LazySeq<U>: processed sequence
func prepend(T)
public func prepend(element: T): LazySeq<T>
Description: Inserts a new sequence at the beginning of the original sequence.
Parameters:
- other: LazySeq<T>: sequence to be inserted
Returns:
- LazySeq<U>: processed sequence
static func mix(LazySeq<T>,LazySeq<T>)
public static func mix(l1: LazySeq<T>, l2: LazySeq<T>)
Description: Mixes two sequences into one, for example, mix({1,2,3,4}, {5,6,7}) -> {1,5,2,6,3,7,4}.
Parameters:
Returns:
- LazySeq<U>: processed sequence
static func mix(LazySeq<T>,LazySeq<T>,LazySeq<T>)
public static func mix(l1: LazySeq<T>, l2: LazySeq<T>, l3: LazySeq<T>)
Description: Mixes three sequences into one.
Parameters:
- l1: LazySeq<T>: sequence to be mixed
- l2: LazySeq<T>: sequence to be mixed
- l3: LazySeq<T>: sequence to be mixed
Returns:
- LazySeq<U>: processed sequence
static func mix(LazySeq<T>,LazySeq<T>,LazySeq<T>,LazySeq<T>)
public static func mix(l1: LazySeq<T>, l2: LazySeq<T>, l3: LazySeq<T>, l4: LazySeq<T>)
Description: Mixes four sequences into one.
Parameters:
- l1: LazySeq<T>: sequence to be mixed
- l2: LazySeq<T>: sequence to be mixed
- l3: LazySeq<T>: sequence to be mixed
- l4: LazySeq<T>: sequence to be mixed
Returns:
- LazySeq<U>: processed sequence
static func mix(LazySeq<T>,LazySeq<T>,LazySeq<T>,LazySeq<T>,LazySeq<T>)
public static func mix(l1: LazySeq<T>, l2: LazySeq<T>, l3: LazySeq<T>, l4: LazySeq<T>, l5: LazySeq<T>)
Description: Mixes five sequences into one.
Parameters:
- l1: LazySeq<T>: sequence to be mixed
- l2: LazySeq<T>: sequence to be mixed
- l3: LazySeq<T>: sequence to be mixed
- l4: LazySeq<T>: sequence to be mixed
- l5: LazySeq<T>: sequence to be mixed
Returns:
- LazySeq<U>: processed sequence
static func of(Iterable<T>)
public static func of(iterable: Iterable<T>)
Description: Constructs a sequence from an iterator.
Parameters:
- iterable: Iterable<T>: iterator to be processed
Returns:
- LazySeq<U>: processed sequence
static func of(Array<T>)
public static func of(array: Array<T>)
Description: Constructs a sequence from an array.
Parameters:
- array: Array<T>: array to be processed
Returns:
- LazySeq<U>: processed sequence
class ShrinkHelpers
public class ShrinkHelpers {}
Description: Provides a method for implementing the reduce iterator for tuples.
static func shrinkTuple<T0, T1>((T0, T1),Iterable<T0>,Iterable<T1>)
public static func shrinkTuple<T0, T1>(
tuple: (T0, T1),
t0: Iterable<T0>,
t1: Iterable<T1>
): Iterable<(T0, T1)>
Description: Implements the reduce iterator for tuples.
Parameters:
- tuple: (T0, T1): reduced tuple
- t0: Iterable<T0>: reduce iterator for the first tuple member
- t1: Iterable<T1>: reduce iterator for the second tuple member
Returns:
- Iterable<(T0, T1)>: reduce iterator for tuples
static func shrinkTuple<T0, T1, T2>((T0, T1, T2),Iterable<T0>,Iterable<T1>,Iterable<T2>)
public static func shrinkTuple<T0, T1, T2>(
tuple: (T0, T1, T2),
t0: Iterable<T0>,
t1: Iterable<T1>,
t2: Iterable<T2>
): Iterable<(T0, T1, T2)>
Description: Implements the reduce iterator for tuples.
Parameters:
-
tuple: (T0, T1, T2): reduced tuple
-
t0: Iterable<T0>: reduce iterator for the first tuple member
-
t1: Iterable<T1>: reduce iterator for the second tuple member
-
t2: Iterable<T2>: reduce iterator for the third tuple member
Returns:
- Iterable<(T0, T1, T2)>: reduce iterator for tuples
static func shrinkTuple<T0, T1, T2, T3>((T0, T1, T2, T3),Iterable<T0>,Iterable<T1>,Iterable<T2>,Iterable<T3>)
public static func shrinkTuple<T0, T1, T2, T3>(
tuple: (T0, T1, T2, T3),
t0: Iterable<T0>,
t1: Iterable<T1>,
t2: Iterable<T2>,
t3: Iterable<T3>
): Iterable<(T0, T1, T2, T3)>
Description: Implements the reduce iterator for tuples.
Parameters:
-
tuple: (T0, T1, T2, T3): reduced tuple
-
t0: Iterable<T0>: reduce iterator for the first tuple member
-
t1: Iterable<T1>: reduce iterator for the second tuple member
-
t2: Iterable<T2>: reduce iterator for the third tuple member
-
t3: Iterable<T3>: reduce iterator for the fourth tuple member
Returns:
- Iterable<(T0, T1, T2, T3)>: reduce iterator for tuples
static func shrinkTuple<T0, T1, T2, T3, T4>((T0, T1, T2, T3, T4),Iterable<T0>,Iterable<T1>,Iterable<T2>,Iterable<T3>,Iterable<T4>)
public static func shrinkTuple<T0, T1, T2, T3, T4>(
tuple: (T0, T1, T2, T3, T4),
t0: Iterable<T0>,
t1: Iterable<T1>,
t2: Iterable<T2>,
t3: Iterable<T3>,
t4: Iterable<T4>
): Iterable<(T0, T1, T2, T3, T4)>
Description: Implements the reduce iterator for tuples.
Parameters:
- tuple: (T0, T1, T2, T3, T4): reduced tuple
- t0: Iterable<T0>: reduce iterator for the first tuple member
- t1: Iterable<T1>: reduce iterator for the second tuple member
- t2: Iterable<T2>: reduce iterator for the third tuple member
- t3: Iterable<T3>: reduce iterator for the fourth tuple member
- t4: Iterable<T4>: reduce iterator for the fifth tuple member
Returns:
- Iterable<(T0, T1, T2, T3, T4)>: reduce iterator for tuples
Struct
struct Function0Wrapper<R>
public struct Function0Wrapper<R> {
public Function0Wrapper(public let function: () -> R)
}
Description: Wraps a closure into a struct.
init(() -> R)
public Function0Wrapper(public let function: () -> R)
Description: Specifies a constructor.
Parameters:
- function: () -> R: wrapped closure
operator func()()
public operator func () (): R
Description: Specifies a call operator function. It is the call operator function that converts a closure into a struct.
Returns:
- R: same as the return value of the closure
extend<R> Function0Wrapper<R> <: Arbitrary<Function0Wrapper<R>> where R <: Arbitrary<R>
extend<R> Function0Wrapper<R> <: Arbitrary<Function0Wrapper\<R>> where R <: Arbitrary<R>
Description: Extends Arbitrary implementation for Function0Wrapper.
Parent Type:
static func arbitrary(RandomSource)
public static func arbitrary(random: RandomSource): Generator<Function0Wrapper<R>>
Description: Obtains the generator for generating random values of the Function0Wrapper<R> type.
struct TupleWrapper2<T0, T1>
public struct TupleWrapper2<T0, T1> {
public TupleWrapper2(public let tuple: (T0, T1))
}
Description: Wraps a closure into a struct. The closure contains two parameters.
init((T0, T1))
public TupleWrapper2(public let tuple: (T0, T1))
Description: Specifies a constructor.
Parameters:
- tuple: (T0, T1): two input parameters of the closure
func apply<R>(f: (T0, T1) -> R)
public func apply<R>(f: (T0, T1) -> R): R
Description: Executes a closure function.
Parameters:
- f: (T0, T1) -> R: closure to be executed
Returns:
- R: closure execution result
extend<T0, T1> TupleWrapper2<T0, T1> <: ToString
extend<T0, T1> TupleWrapper2<T0, T1> <: ToString
Description: Extends ToString implementation for TupleWrapper2.
Parent Type:
func toString()
public func toString()
Description: Specifies the string representation of TupleWrapper2.
extend<T0, T1> TupleWrapper2<T0, T1> <: Equatable<TupleWrapper2<T0, T1>>
extend<T0, T1> TupleWrapper2<T0, T1> <: Equatable<TupleWrapper2<T0, T1>>
Description: Extends Equatable implementation for TupleWrapper2.
Parent Type:
- Equatable<TupleWrapper2<T0, T1>>
operator func ==(TupleWrapper2<T0, T1>)
public operator func ==(other: TupleWrapper2<T0, T1>)
Description: Compares two binary tuples.
Parameters:
- other: TupleWrapper2<T0, T1>: binary tuples to be compared
Returns:
- Bool: If they are equal,
trueis returned; otherwise,falseis returned.
operator func !=(TupleWrapper2<T0, T1>)
public operator func !=(other: TupleWrapper2<T0, T1>)
Description: Compares two binary tuples.
Parameters:
- other: TupleWrapper2<T0, T1>: binary tuples to be compared
Returns:
- Bool: If they are not equal,
trueis returned; otherwise,falseis returned.
extend<T0, T1> TupleWrapper2<T0, T1> <: IndexAccess
extend<T0, T1> TupleWrapper2<T0, T1> <: IndexAccess
Description: Extends IndexAccess implementation for TupleWrapper2.
Parent Type:
func getElementAsAny(Int64)
public func getElementAsAny(index: Int64): ?Any
Description: Obtains the value in a tuple based on the index.
Parameters:
- index: Int64: index
Returns:
- ?Any: value obtained from the tuple. If the index is invalid,
Noneis returned.
extend<T0, T1> TupleWrapper2<T0, T1> <: Arbitrary<TupleWrapper2<T0, T1>> where T0 <: Arbitrary<T0>,T1 <: Arbitrary<T1>
extend<T0, T1> TupleWrapper2<T0, T1> <: Arbitrary<TupleWrapper2<T0, T1>> where T0 <: Arbitrary<T0>,T1 <: Arbitrary<T1>
Description: Extends Arbitrary implementation for TupleWrapper2.
Parent Type:
- Arbitrary<TupleWrapper2<T0, T1>>
static func arbitrary(RandomSource)
public static func arbitrary(random: RandomSource): Generator<TupleWrapper2<T0, T1>>
Description: Obtains the generator for generating random values of the TupleWrapper2<T0, T1> type.
struct TupleWrapper3<T0, T1, T2>
public struct TupleWrapper3<T0, T1, T2> {
public TupleWrapper3(public let tuple: (T0, T1,T2))
}
Description: Wraps a closure into a struct. The closure contains two parameters.
init((T0, T1,T2))
public TupleWrapper3(public let tuple: (T0, T1,T2))
Description: Specifies a constructor.
Parameters:
- tuple: (T0, T1, T2): two input parameters of the closure
func apply<R>(f: (T0, T1,T2) -> R)
public func apply<R>(f: (T0, T1,T2) -> R): R
Description: Executes a closure function.
Parameters:
- f: (T0, T1,T2) -> R: closure to be executed
Returns:
- R: closure execution result
extend<T0, T1, T2> TupleWrapper3<T0, T1, T2> <: ToString
extend<T0, T1, T2> TupleWrapper3<T0, T1, T2> <: ToString
Description: Extends ToString implementation for TupleWrapper3.
Parent Type:
func toString()
public func toString()
Description: Specifies the string representation of TupleWrapper3.
extend<T0, T1, T2> TupleWrapper3<T0, T1, T2> <: Equatable<TupleWrapper3<T0, T1, T2>>
extend<T0, T1, T2> TupleWrapper3<T0, T1, T2> <: Equatable<TupleWrapper3<T0, T1, T2>>
Description: Extends Equatable implementation for TupleWrapper3.
Parent Type:
- Equatable<TupleWrapper3<T0, T1, T2>>
operator func ==(TupleWrapper3<T0, T1, T2>)
public operator func ==(other: TupleWrapper3<T0, T1, T2>)
Description: Compares two tuples.
Parameters:
- other: TupleWrapper3<T0, T1, T2>: tuples to be compared
Returns:
- Bool: If they are equal,
trueis returned; otherwise,falseis returned.
operator func !=(TupleWrapper3<T0, T1, T2>)
public operator func !=(other: TupleWrapper3<T0, T1, T2>)
Description: Compares two tuples.
Parameters:
- other: TupleWrapper3<T0, T1, T2>: tuples to be compared
Returns:
- Bool: If they are not equal,
trueis returned; otherwise,falseis returned.
extend<T0, T1, T2> TupleWrapper3<T0, T1, T2> <: IndexAccess
extend<T0, T1, T2> TupleWrapper3<T0, T1, T2> <: IndexAccess
Description: Extends IndexAccess implementation for TupleWrapper3.
Parent Type:
func getElementAsAny(Int64)
public func getElementAsAny(index: Int64): ?Any
Description: Obtains the value in a tuple based on the index.
Parameters:
- index: Int64: index
Returns:
- ?Any: value obtained from the tuple. If the index is invalid,
Noneis returned.
extend<T0, T1, T2> TupleWrapper3<T0, T1, T2> <: Arbitrary<TupleWrapper3<T0, T1, T2>> where T0 <: Arbitrary<T0>,T1 <: Arbitrary<T1>,T2 <: Arbitrary<T2>
extend<T0, T1, T2> TupleWrapper3<T0, T1, T2> <: Arbitrary<TupleWrapper3<T0, T1, T2>> where T0 <: Arbitrary<T0>,T1 <: Arbitrary<T1>,T2 <: Arbitrary<T2>
Description: Extends Arbitrary implementation for TupleWrapper3.
Parent Type:
- Arbitrary<TupleWrapper3<T0, T1, T2>>
static func arbitrary(RandomSource)
public static func arbitrary(random: RandomSource): Generator<TupleWrapper3<T0, T1, T2>>
Description: Obtains the generator for generating random values of the TupleWrapper3<T0, T1, T2> type.
struct TupleWrapper4<T0, T1, T2, T3>
public struct TupleWrapper4<T0, T1, T2, T3> {
public TupleWrapper4(public let tuple: (T0, T1, T2, T3))
}
Description: Wraps a closure into a struct. The closure contains two parameters.
init((T0, T1, T2, T3))
public TupleWrapper4(public let tuple: (T0, T1, T2, T3))
Description: Specifies a constructor.
Parameters:
- tuple: (T0, T1, T2, T3): four input parameters of the closure
func apply<R>(f: (T0, T1, T2, T3) -> R)
public func apply<R>(f: (T0, T1, T2, T3) -> R): R
Description: Executes a closure function.
Parameters:
- f: (T0, T1, T2, T3) -> R: closure to be executed
Returns:
- R: closure execution result
extend<T0, T1, T2, T3> TupleWrapper4<T0, T1, T2, T3> <: ToString
extend<T0, T1, T2, T3> TupleWrapper4<T0, T1, T2, T3> <: ToString
Description: Extends ToString implementation for TupleWrapper4.
Parent Type:
func toString()
public func toString()
Description: Specifies the string representation of TupleWrapper4.
extend<T0, T1, T2, T3> TupleWrapper4<T0, T1, T2, T3> <: Equatable<TupleWrapper4<T0, T1, T2, T3>>
extend<T0, T1, T2> TupleWrapper3<T0, T1, T2> <: Equatable<TupleWrapper3<T0, T1, T2>>
Description: Extends Equatable implementation for TupleWrapper4.
Parent Type:
- Equatable<TupleWrapper3<T0, T1, T2>>
operator func ==(TupleWrapper4<T0, T1, T2, T3>)
public operator func ==(other: TupleWrapper4<T0, T1, T2, T3>)
Description: Compares two tuples.
Parameters:
- other: TupleWrapper4<T0, T1, T2, T3>: tuples to be compared
Returns:
- Bool: If they are equal,
trueis returned; otherwise,falseis returned.
operator func !=(TupleWrapper4<T0, T1, T2, T3>)
public operator func !=(other: TupleWrapper4<T0, T1, T2, T3>)
Description: Compares two tuples.
Parameters:
- other: TupleWrapper4<T0, T1, T2, T3>: tuples to be compared
Returns:
- Bool: If they are not equal,
trueis returned; otherwise,falseis returned.
extend<T0, T1, T2, T3> TupleWrapper4<T0, T1, T2, T3> <: IndexAccess
extend<T0, T1, T2, T3> TupleWrapper4<T0, T1, T2, T3> <: IndexAccess
Description: Extends IndexAccess implementation for TupleWrapper4.
Parent Type:
func getElementAsAny(Int64)
public func getElementAsAny(index: Int64): ?Any
Description: Obtains the value in a tuple based on the index.
Parameters:
- index: Int64: index
Returns:
- ?Any: value obtained from the tuple. If the index is invalid,
Noneis returned.
extend<T0, T1, T2, T3> TupleWrapper4<T0, T1, T2, T3><: Arbitrary<TupleWrapper4<T0, T1, T2, T3>> where where T0 <: Arbitrary<T0>,T1 <: Arbitrary<T1>,T2 <: Arbitrary<T2>,T3 <: Arbitrary<T3>
extend<T0, T1, T2, T3> TupleWrapper4<T0, T1, T2, T3><: Arbitrary<TupleWrapper4<T0, T1, T2, T3>> where where T0 <: Arbitrary<T0>,T1 <: Arbitrary<T1>,T2 <: Arbitrary<T2>,T3 <: Arbitrary<T3>
Description: Extends Arbitrary implementation for TupleWrapper4.
Parent Type:
- Arbitrary<TupleWrapper4<T0, T1, T2, T3>>
static func arbitrary(RandomSource)
public static func arbitrary(random: RandomSource): Generator<TupleWrapper2<T0, T1, T2, T3>>
Description: Obtains the generator for generating random values of the TupleWrapper4<T0, T1, T2, T3> type.
struct TupleWrapper5<T0, T1, T2, T3, T4>
public struct TupleWrapper5<T0, T1, T2, T3, T4> {
public TupleWrapper5(public let tuple: (T0, T1, T2, T3, T4))
}
Description: Wraps a closure into a struct. The closure contains two parameters.
init((T0, T1, T2, T3, T4))
public TupleWrapper5(public let tuple: (T0, T1, T2, T3, T4))
Description: Specifies a constructor.
Parameters:
- tuple: (T0, T1, T2, T3, T4): five input parameters of the closure
func apply<R>(f: (T0, T1, T2, T3, T4) -> R)
public func apply<R>(f: (T0, T1, T2, T3, T4) -> R): R
Description: Executes a closure function.
Parameters:
- f: (T0, T1, T2, T3, T4) -> R: closure to be executed
Returns:
- R: closure execution result
extend<T0, T1, T2, T3, T4> TupleWrapper5<T0, T1, T2, T3, T4> <: ToString
extend<T0, T1, T2, T3, T4> TupleWrapper5<T0, T1, T2, T3, T4> <: ToString
Description: Extends ToString implementation for TupleWrapper5.
Parent Type:
func toString()
public func toString()
Description: Specifies the string representation of TupleWrapper5.
extend<T0, T1, T2, T3, T4> TupleWrapper5<T0, T1, T2, T3, T4> <: Equatable<TupleWrapper5<T0, T1, T2, T3, T4>>
extend<T0, T1, T2> TupleWrapper3<T0, T1, T2> <: Equatable<TupleWrapper3<T0, T1, T2>>
Description: Extends Equatable implementation for TupleWrapper5.
Parent Type:
- Equatable<TupleWrapper3<T0, T1, T2>>
operator func ==(TupleWrapper5<T0, T1, T2, T3, T4>)
public operator func ==(other: TupleWrapper5<T0, T1, T2, T3, T4>)
Description: Compares two binary tuples.
Parameters:
- other: TupleWrapper5<T0, T1, T2, T3>: tuples to be compared
Returns:
- Bool: If they are equal,
trueis returned; otherwise,falseis returned.
operator func !=(TupleWrapper5<T0, T1, T2, T3, T4>)
public operator func !=(other: TupleWrapper2<T0, T1, T2, T3, T4>)
Description: Compares two tuples.
Parameters:
- other: TupleWrapper5<T0, T1, T2, T3, T4>: tuples to be compared
Returns:
- Bool: If they are not equal,
trueis returned; otherwise,falseis returned.
extend<T0, T1, T2, T3, T4> TupleWrapper5<T0, T1, T2, T3, T4> <: IndexAccess
extend<T0, T1, T2, T3, T4> TupleWrapper5<T0, T1, T2, T3, T4> <: IndexAccess
Description: Extends IndexAccess implementation for TupleWrapper5.
Parent Type:
func getElementAsAny(Int64)
public func getElementAsAny(index: Int64): ?Any
Description: Obtains the value in a tuple based on the index.
Parameters:
- index: Int64: index
Returns:
- ?Any: value obtained from the tuple. If the index is invalid,
Noneis returned.
extend<T0, T1, T2, T3, T4> TupleWrapper5<T0, T1, T2, T3, T4> <: Arbitrary<TupleWrapper2<T0, T1, T2, T3, T4>> where T0 <: Arbitrary<T0>,T1 <: Arbitrary<T1>,T2 <: Arbitrary<T2>,T3 <: Arbitrary<T3>,T4 <: Arbitrary<T4>
extend<T0, T1, T2, T3, T4> TupleWrapper5<T0, T1, T2, T3, T4> <: Arbitrary<TupleWrapper2<T0, T1, T2, T3, T4>> where T0 <: Arbitrary<T0>,T1 <: Arbitrary<T1>,T2 <: Arbitrary<T2>,T3 <: Arbitrary<T3>,T4 <: Arbitrary<T4>
Description: Extends Arbitrary implementation for TupleWrapper5.
Parent Type:
- Arbitrary<TupleWrapper2<T0, T1, T2, T3, T4>>
static func arbitrary(RandomSource)
public static func arbitrary(random: RandomSource): Generator<TupleWrapper5<T0, T1, T2, T3, T4>>
Description: Obtains the generator for generating random values of the TupleWrapper5<T0, T1, T2, T3, T4> type.
compress Module
Note:
The import compress command cannot be used to directly import the compressed module. Otherwise, the error message "error: can not find package'compress'" is displayed during compilation. You are advised to import the compress subpackage to use the compress module.
compress Function Description
The compress module provides compression and decompression functions.
Compression means that data is represented by using fewer bits, so that the data is stored and transmitted more efficiently. In practice, compression is widely used in file compression, web page compression, database backup, and the like.
The implementation of the compression function depends on the compression algorithm. Mainstream compression algorithms include deflate, lz77, and lzw. These algorithms can remove redundant information from data or replace redundant information with more compact representations to implement data compression. Currently, this module uses the Huawei-developed deflate algorithm.
Based on the deflate compression algorithm, a header and a tail are added to the compressed data, and the compressed data can be encapsulated in different formats, such as deflate-raw (without encapsulation), gzip, zip, and png. The zip format is applicable to compression and packing of multiple files, and the gzip format supports only one compressed file. Currently, this module supports the deflate-raw and gzip data formats and does not support the file packing function.
In addition, this module supports the setting of compression levels. A higher compression level corresponds to a higher compression ratio and a slower compression speed. Conversely, a lower compression level corresponds to a lower compression ratio and a faster compression speed.
In particular, zlib is a library for implementing the compression function. The zlib package of this module implements the deflate algorithm and supports the deflate-raw and gzip compression formats.
Package List of the compress Module
The compress module provides the following package:
| Name | Description |
|---|---|
| zlib | The zlib package provides the compression and decompression capabilities. |
compress.zlib Package
Function Description
A zlib compression and decompression library is provided.
This package uses the Huawei deflate algorithm, supports the deflate-raw and gzip data formats, and provides three compression levels: fast, default, and high compression ratio where the compression speed and ratio are in descending and ascending orders, respectively.
This package provides the streaming compression and decompression functions. That is, it can read data from the input stream, compress or decompress the data, and writ the data to the byte array, or it can read data from the byte array, compress or decompress the data, and write the data to the output stream.
Note:
This package does not support file packing.
API List
Class
| Name | Description |
|---|---|
| CompressInputStream | Compresses an input stream. |
| CompressOutputStream | Compresses an output stream. |
| DecompressInputStream | Decompresses an input stream. |
| DecompressOutputStream | Decompresses an output stream. |
Enumeration
| Name | Description |
|---|---|
| CompressLevel | Specifies the compression level |
| WrapType | Specifies the compressed data format |
Exception Class
| Name | Description |
|---|---|
| ZlibException | Specifies the exception class of the zlib package |
Class
class CompressInputStream
public class CompressInputStream <: InputStream {
public init(inputStream: InputStream, wrap!: WrapType = DeflateFormat, compressLevel!: CompressLevel = DefaultCompression, bufLen!: Int64 = 512)
}
Description: Compresses an input stream.
A CompressInputStream instance can be bound to any input stream of the InputStream type, and data in the input stream is compressed and output to a byte array.
Parent Type:
init(InputStream, WrapType, CompressLevel, Int64)
public init(inputStream: InputStream, wrap!: WrapType = DeflateFormat, compressLevel!: CompressLevel = DefaultCompression, bufLen!: Int64 = 512)
Description: Constructs an input stream to be compressed.
An input stream must be bound. The compressed data format, compression level, and internal buffer size (data volume to be read from the input stream for compression each time) can be set.
Parameters:
- inputStream: InputStream: input stream to be compressed
- wrap!: WrapType: compressed data format; default value: DeflateFormat
- compressLevel!: CompressLevel: compression level; default value: DefaultCompression
- bufLen!: Int64: size of the input stream buffer; value range: (0, Int64.Max]; default value: 512 bytes
Throws:
- ZlibException: When
bufLenis less than or equal to 0, memory allocation for the input stream fails, or initialization for the compression resources fails, and this exception is thrown.
func close()
public func close(): Unit
Description: Closes a compression input stream.
After the current CompressInputStream instance is used, this function must be called to release the memory resources occupied by the instance to prevent memory leakage. Before calling this function, ensure that 0 has been returned from the read function. Otherwise, the bound InputStream may not be completely compressed.
Throws:
- ZlibException: If compression resources fail to be released, this exception is thrown.
func read(Array<Byte>)
public func read(outBuf: Array<Byte>): Int64
Description: Reads data from a bound input stream, compresses the data, and stores the compressed data in a specified byte array.
Parameters:
Returns:
- Int64: If the compression is successful, the number of bytes after compression is returned. If the data in the bound input stream is completely compressed or the compression input stream is closed, 0 is returned.
Throws:
- ZlibException: If
outBufis empty or data compression fails, this exception is thrown.
class CompressOutputStream
public class CompressOutputStream <: OutputStream {
public init(outputStream: OutputStream, wrap!: WrapType = DeflateFormat, compressLevel!: CompressLevel = DefaultCompression, bufLen!: Int64 = 512)
}
Description: Compresses and writes data to an output stream.
A CompressOutputStream instance can be bound to any output stream of the OutputStream type, and data in a specified byte array is read, compressed, and then output to the bound output stream.
Parent Type:
init(OutputStream, WrapType, CompressLevel, Int64)
public init(outputStream: OutputStream, wrap!: WrapType = DeflateFormat, compressLevel!: CompressLevel = DefaultCompression, bufLen!: Int64 = 512)
Description: Constructs a compression output stream. An output stream must be bound, and the compressed data type, compression level, and internal buffer size (volume of compressed data to be written to the output stream each time) can be set.
Parameters:
- outputStream: OutputStream: bound output stream, to which compressed data is written
- wrap!: WrapType: compressed data format; default value: DeflateFormat
- compressLevel!: CompressLevel: compression level; default value: DefaultCompression
- bufLen!: Int64: size of the output stream buffer; value range: (0, Int64.Max]; default value: 512 bytes
Throws:
- ZlibException: When
bufLenis less than or equal to 0, memory allocation for the output stream fails, or initialization for the compression resources fails, and this exception is thrown.
func close()
public func close(): Unit
Description: Closes the current compression output stream instance.
When an instance is closed, the remaining compressed data (including the data in the buffer and the compressed tail information) is written to the output stream and the memory resources occupied by the instance are released. After the current compression output stream instance is used, this function must be called to release the memory resources occupied by the instance to prevent memory leakage. Before the close function is called, the data written to the bound output stream is not a complete segment of compressed data. The remaining compressed data is written to the bound output stream only after the close function is called.
Throws:
- ZlibException: If the current compression output stream has been closed or the compression resources fail to be released, this exception is thrown.
func flush()
public func flush(): Unit
Description: Refreshes a compression output stream, specifically, reads the compressed data in the internal buffer, writes the data to the bound output stream, and then refreshes the bound output stream.
Throws:
- ZlibException: If the current compression output stream has been closed, this exception is thrown.
func write(Array<Byte>)
public func write(inBuf: Array<Byte>): Unit
Description: Compresses data in a specified byte array and writes the data to an output stream. When all data is compressed and written to the output stream, the function returns a result.
Parameters:
Throws:
- ZlibException: If the current compression output stream has been closed or the resources fail to be compressed, this exception is thrown.
class DecompressInputStream
public class DecompressInputStream <: InputStream {
public init(inputStream: InputStream, wrap!: WrapType = DeflateFormat, bufLen!: Int64 = 512)
}
Description: Decompresses an input stream.
A DecompressInputStream instance can be bound to any input stream of the InputStream type, and data in the stream is read, decompressed, and then output to a specified byte array.
Parent Type:
init(InputStream, WrapType, Int64)
public init(inputStream: InputStream, wrap!: WrapType = DeflateFormat, bufLen!: Int64 = 512)
Description: Constructs a decompression input stream.
An input stream must be bound. The decompressed data format and internal buffer size (data volume to be read from the input stream for decompression each time) can be set.
Parameters:
- inputStream: InputStream: input stream to be compressed
- wrap!: WrapType: format of the data to be decompressed; default value: DeflateFormat
- bufLen!: Int64: size of the input stream buffer; value range: (0, Int64.Max]; default value: 512 bytes
Throws:
- ZlibException: When
bufLenis less than or equal to 0, memory allocation for the input stream fails, or initialization for the resources to be decompressed fails, and this exception is thrown.
func close()
public func close(): Unit
Description: Closes a decompression input stream.
After the current DecompressInputStream instance is used, this function must be called to release the memory resources occupied by the instance to prevent memory leakage. Before calling this function, ensure that 0 has been returned from the read function. Otherwise, the bound InputStream may not be completely decompressed.
Throws:
- ZlibException: If resources to be decompressed fail to be released, this exception is thrown.
func read(Array<Byte>)
public func read(outBuf: Array<Byte>): Int64
Description: Reads data from a bound input stream, decompresses the data, and stores the decompressed data in a specified byte array.
Parameters:
Returns:
- Int64: If the decompression is successful, the number of bytes after decompression is returned. If the data in the bound input stream is completely decompressed or the decompression input stream is closed, 0 is returned.
Throws:
- ZlibException: If
outBufis empty or data decompression fails, this exception is thrown.
class DecompressOutputStream
public class DecompressOutputStream <: OutputStream {
public init(outputStream: OutputStream, wrap!: WrapType = DeflateFormat, bufLen!: Int64 = 512)
}
Description: Decompresses and writes data to an output stream.
A DecompressOutputStream instance can be bound to a specified output stream of the OutputStream type, and data in a specified byte array is read, decompressed, and then output to the bound output stream.
Parent Type:
init(OutputStream, WrapType, Int64)
public init(outputStream: OutputStream, wrap!: WrapType = DeflateFormat, bufLen!: Int64 = 512)
Description: Constructs a decompression output stream.
An output stream must be bound. The compressed data type, compression level, and internal buffer size can be set. (After decompression, data is stored in the internal buffer. After the buffer is full, data is written to the output stream.)
Parameters:
- outputStream: OutputStream: bound output stream, to which decompressed data is written
- wrap!: WrapType: format of the data to be decompressed; default value: DeflateFormat
- bufLen!: Int64: size of the output stream buffer; value range: (0, Int64.Max]; default value: 512 bytes
Throws:
- ZlibException: When
bufLenis less than or equal to 0, memory allocation for the output stream fails, or initialization for the resources to be decompressed fails, and this exception is thrown.
func close()
public func close(): Unit
Description: Closes the current decompression output stream instance.
When this instance is closed, the remaining decompressed data is written to the output stream and the memory resources occupied by the instance are released. After the current compression output stream instance is used, this function must be called to release the memory resources occupied by the instance to prevent memory leakage. If the compressed data processed by the write function is incomplete, an exception is thrown due to incomplete decompressed data when the close function is called.
Throws:
- ZlibException: If the current compression output stream has been closed, the data to be decompressed transferred through the write function is incomplete, or the compression resources fail to be released, this exception is thrown.
func flush()
public func flush(): Unit
Description: Refreshes a decompression output stream, specifically, writes the decompressed data in the internal buffer to the bound output stream, and then refreshes the bound output stream.
Throws:
- ZlibException: If the current decompression output stream has been closed, this exception is thrown.
func write(Array<Byte>)
public func write(inBuf: Array<Byte>): Unit
Description: Decompresses data in a specified byte array and writes the data to an output stream. When all data is decompressed and written to the output stream, the function returns a result.
Parameters:
Throws:
- ZlibException: If the current decompression output stream has been closed or the data fails to be decompressed, this exception is thrown.
Enumeration
enum CompressLevel
public enum CompressLevel {
| BestCompression
| BestSpeed
| DefaultCompression
}
Description: Indicates the compression level.
The compression ratio and speed are determined by the compression level. Currently, three compression levels are supported. The compression ratios are BestSpeed, DefaultCompression, and BestCompression, which are in ascending order of compression ratio and descending order of compression speed.
BestCompression
BestCompression
Description: Constructs an enumeration instance of the compression level with the compression ratio preferred, which indicates the highest compression ratio and a relatively low compression speed.
BestSpeed
BestSpeed
Description: Constructs an enumeration instance of the compression level with the compression speed preferred, which indicates the highest compression speed and a relatively low compression ratio.
DefaultCompression
DefaultCompression
Description: Constructs an enumeration instance of the compression level, which indicates the default compression level.
enum WrapType
public enum WrapType {
| DeflateFormat
| GzipFormat
}
Description: Indicates the compressed data format.
Currently, DeflateFormat and GzipFormat are supported.
DeflateFormat
DeflateFormat
Description: Constructs an enumeration instance of the Deflate compression data format.
GzipFormat
GzipFormat
Description: Constructs an enumeration instance of the Gzip compression data format.
Exception Class
class ZlibException
public class ZlibException <: Exception {
public init(message: String)
}
Description: Indicates the exception class of the zlib package.
Parent Type:
init(String)
public init(message: String)
Description: Creates a ZlibException instance based on exception information:
Parameters:
- message: String: error information
Compression and Decompression of Data in Deflate Format
import compress.zlib.*
import std.fs.*
main() {
var arr: Array<Byte> = Array<Byte>(1024 * 1024, {i => UInt8(i % 256)})
File.writeTo("./zlib1.txt", arr, openOption: Create(false))
if (compressFile("./zlib1.txt", "./zlib_copmressed1.zlib") <= 0) {
println("Failed to compress file!")
}
if (decompressFile("./zlib_copmressed1.zlib", "./zlib_decopmressed1.txt") != arr.size) {
println("Failed to decompress file!")
}
if (compareFile("./zlib1.txt", "./zlib_decopmressed1.txt")) {
println("success")
} else {
println("failed")
}
File.delete("./zlib1.txt")
File.delete("./zlib_copmressed1.zlib")
File.delete("./zlib_decopmressed1.txt")
return 0
}
func compressFile(srcFileName: String, destFileName: String): Int64 {
var count: Int64 = 0
var srcFile: File = File(srcFileName, OpenOption.Open(true, false))
var destFile: File = File(destFileName, OpenOption.Create(false))
var tempBuf: Array<UInt8> = Array<UInt8>(1024, item: 0)
var compressOutputStream: CompressOutputStream = CompressOutputStream(destFile, wrap: DeflateFormat)
while (true) {
var readNum = srcFile.read(tempBuf)
if (readNum > 0) {
compressOutputStream.write(tempBuf.slice(0, readNum).toArray())
count += readNum
} else {
break
}
}
compressOutputStream.flush()
compressOutputStream.close()
srcFile.close()
destFile.close()
return count
}
func decompressFile(srcFileName: String, destFileName: String): Int64 {
var count: Int64 = 0
var srcFile: File = File(srcFileName, OpenOption.Open(true, false))
var destFile: File = File(destFileName, OpenOption.Create(false))
var tempBuf: Array<UInt8> = Array<UInt8>(1024, item: 0)
var decompressInputStream: DecompressInputStream = DecompressInputStream(srcFile, wrap: DeflateFormat)
while (true) {
var readNum = decompressInputStream.read(tempBuf)
if (readNum <= 0) {
break
}
destFile.write(tempBuf.slice(0, readNum).toArray())
count += readNum
}
decompressInputStream.close()
srcFile.close()
destFile.close()
return count
}
func compareFile(fileName1: String, fileName2: String): Bool {
return File.readFrom(fileName1) == File.readFrom(fileName2)
}
Running result:
success
Compression and Decompression of Data in Gzip Format
import compress.zlib.*
import std.fs.*
main() {
var arr: Array<Byte> = Array<Byte>(1024 * 1024, {i => UInt8(i % 256)})
File.writeTo("./zlib.txt", arr, openOption: Create(false))
if (compressFile("./zlib.txt", "./zlib_copmressed.zlib") <= 0) {
println("Failed to compress file!")
}
if (decompressFile("./zlib_copmressed.zlib", "./zlib_decopmressed.txt") != arr.size) {
println("Failed to decompress file!")
}
if (compareFile("./zlib.txt", "./zlib_decopmressed.txt")) {
println("success")
} else {
println("failed")
}
File.delete("./zlib.txt")
File.delete("./zlib_copmressed.zlib")
File.delete("./zlib_decopmressed.txt")
return 0
}
func compressFile(srcFileName: String, destFileName: String): Int64 {
var count: Int64 = 0
var srcFile: File = File(srcFileName, OpenOption.Open(true, false))
var destFile: File = File(destFileName, OpenOption.Create(false))
var tempBuf: Array<UInt8> = Array<UInt8>(1024, item: 0)
var compressOutputStream: CompressOutputStream = CompressOutputStream(destFile, wrap: GzipFormat, bufLen: 10000)
while (true) {
var readNum = srcFile.read(tempBuf)
if (readNum > 0) {
compressOutputStream.write(tempBuf.slice(0, readNum).toArray())
count += readNum
} else {
break
}
}
compressOutputStream.flush()
compressOutputStream.close()
srcFile.close()
destFile.close()
return count
}
func decompressFile(srcFileName: String, destFileName: String): Int64 {
var count: Int64 = 0
var srcFile: File = File(srcFileName, OpenOption.Open(true, false))
var destFile: File = File(destFileName, OpenOption.Create(false))
var tempBuf: Array<UInt8> = Array<UInt8>(1024, item: 0)
var decompressInputStream: DecompressInputStream = DecompressInputStream(srcFile, wrap: GzipFormat, bufLen: 10000)
while (true) {
var readNum = decompressInputStream.read(tempBuf)
if (readNum <= 0) {
break
}
destFile.write(tempBuf.slice(0, readNum).toArray())
count += readNum
}
decompressInputStream.close()
srcFile.close()
destFile.close()
return count
}
func compareFile(fileName1: String, fileName2: String): Bool {
return File.readFrom(fileName1) == File.readFrom(fileName2)
}
Running result:
success
crypto Module
Note:
The crypto module cannot be directly imported using the import crypto command. Otherwise, an error message indicating that the crypto package cannot be found is displayed during compilation (error: can not find package'crypt'). It is recommended that you use the crypto module in the form of an imported crypto subpackage.
crypto Function Description
The crypto module provides security encryption capabilities, including generating secure random numbers, generating message digests, encrypting and signing data, and creating and parsing certificates.
In actual applications, the crypto module is used to encrypt user passwords, protect sensitive data, and generate digital signatures.
Package List of the crypto Module
The crypto module provides the following packages:
| Name | Description |
|---|---|
| crypto | The crypto package provides the secure random number function. |
| digest | The digest package provides common message digest algorithms, including MD5, SHA1, SHA224, SHA256, SHA384, SHA512, HMAC, and SM3. |
| keys | The keys package provides asymmetric encryption and signature algorithms, including RSA and SM2 asymmetric encryption algorithms and the ECDSA signature algorithm. |
| x509 | The x509 package provides digital certificate processing functions, including parsing and serializing x509 certificates, verifying certificates, creating self-signed certificates, and creating and verifying certificate chains. |
crypto.crypto Package
Function Description
The crypto package provides the secure random number function.
This package depends on the crypto dynamic library file of OpenSSL 3. Therefore, related tools must be installed before using this package.
-
For Linux, perform the following operations:
- Install the OpenSSL 3 development tool package using the package management tool of the system if the tool supports the installation, and ensure that the system installation directory contains the libcrypto.so and libcrypto.so.3 dynamic library files. For example, on Ubuntu 22.04, run the sudo apt install libssl-dev command to install the libssl-dev tool package.
- Download and install the OpenSSL 3.x.x source code compilation software package if the preceding method fails, and ensure that the installation directory contains the libcrypto.so and libcrypto.so.3 dynamic library files. Then, use either of the following methods to ensure that the system linker can find these files:
- Install the software in a system directory if OpenSSL has not been installed.
- Set the directory containing these files to the environment variables LD_LIBRARY_PATH and LIBRARY_PATH if the software is installed in a user-defined directory.
-
For Windows, perform the following operations:
- Download and install the OpenSSL 3.x.x source code compilation software package for the x64 architecture, or download and install the OpenSSL 3.x.x software package precompiled by a third party for developers.
- Ensure that the installation directory contains the libcrypto.dll.a (or libcrypto.lib) and libcrypto-3-x64.dll library files.
- Set the directory containing the libcrypto.dll.a (or libcrypto.lib) to the environment variable LIBRARY_PATH, and the directory containing libcrypto-3-x64.dll to the environment variable PATH.
-
For macOS, perform the following operations:
- Run the brew install openssl@3 command to install OpenSSL, and ensure that the system installation directory contains the libcrypto.dylib and libcrypto.3.dylib dynamic library files.
- Download and install the OpenSSL 3.x.x source code compilation software package if the preceding method fails, and ensure that the installation directory contains the libcrypto.dylib and libcrypto.3.dylib dynamic library files. Then, use either of the following methods to ensure that the system linker can find these files:
- Install the software in a system directory if OpenSSL has not been installed.
- Set the directory containing these files to the environment variables DYLD_LIBRARY_PATH and LIBRARY_PATH.
Note:
If OpenSSL 3 is not installed or an earlier version is installed, the program may fail to work with the following exception thrown: SecureRandomException: Can not load openssl library or function xxx.
API List
Class
| Name | Description |
|---|---|
| SecureRandom | Specifies a secure random number. |
| SM4 | Provides SM4 symmetric encryption and decryption. |
Structure
| Name | Description |
|---|---|
| OperationMode | Specifies the working mode of the symmetric encryption and decryption algorithm |
| PaddingMode | Specifies the padding mode of the symmetric encryption and decryption algorithm |
Exception Class
| Name | Description |
|---|---|
| SecureRandomException | Specifies the secure random number exception class. |
Class
class SecureRandom
public class SecureRandom {
public init(priv!: Bool = false)
}
Description: Generates encrypted and secure pseudo-random numbers.
This class is compared with Random, the differences are as follows:
-
Random seed: Random uses the system clock as the default seed. If the timestamps are the same, the random numbers are the same. SecureRandom uses the random seed provided by the operating system or hardware to generate true random numbers.
-
Random number generation: Random uses the Mersenne twister pseudo-random generator. SecureRandom uses random algorithms such as MD5 provided by the OpenSSL library and entropy sources to generate true random numbers. If supported by hardware, hardware random number generators can also be used to generate more secure random numbers.
-
Security: Random cannot be used to encrypt applications or protect private data, but SecureRandom can.
init(Bool)
public init(priv!: Bool = false)
Description: Creates a SecureRandom instance and supports specifying whether to use a more secure encryption pseudo-random generator. The encryption pseudo-random generator can be used in encryption scenarios such as session keys and certificate private keys.
Parameters:
- priv!: Bool: If this parameter is set to true, a secure encryption pseudo-random generator is used.
func nextBool()
public func nextBool(): Bool
Description: Obtains a random Bool instance.
Returns:
Throws:
- SecureRandomException: When the generator cannot generate a random number correctly or fails to generate a random number, this exception is thrown.
func nextBytes(Int32)
public func nextBytes(length: Int32): Array<Byte>
Description: Obtains a random byte array of a specified length.
Parameters:
- length: Int32: length of the random byte array to be generated
Returns:
Throws:
- IllegalArgumentException: If the value of the parameter length is less than or equal to 0, this exception is thrown.
- SecureRandomException: When the generator cannot generate a random number correctly or fails to generate a random number, this exception is thrown.
func nextFloat16()
public func nextFloat16(): Float16
Description: Obtains a random number of the Float16 type in the range [0.0, 1.0).
Returns:
Throws:
- SecureRandomException: When the generator cannot generate a random number correctly or fails to generate a random number, this exception is thrown.
func nextFloat32()
public func nextFloat32(): Float32
Description: Obtains a random number of the Float32 type in the range [0.0, 1.0).
Returns:
Throws:
- SecureRandomException: When the generator cannot generate a random number correctly or fails to generate a random number, this exception is thrown.
func nextFloat64()
public func nextFloat64(): Float64
Description: Obtains a random number of the Float64 type in the range [0.0, 1.0).
Returns:
Throws:
- SecureRandomException: When the generator cannot generate a random number correctly or fails to generate a random number, this exception is thrown.
func nextGaussianFloat16(Float16, Float16)
public func nextGaussianFloat16(mean!: Float16 = 0.0, sigma!: Float16 = 1.0): Float16
Description: Obtains a random number that is of the Float16 type and complies with the Gaussian distribution with the mean value of 0.0 and standard deviation of 1.0. The mean value is the expected value and can be interpreted as the location parameter, which determines the location of the distribution. The standard deviation can be interpreted as the scale parameter, which determines the amplitude of the distribution.
Parameters:
Returns:
Throws:
- SecureRandomException: When the generator cannot generate a random number correctly or fails to generate a random number, this exception is thrown.
func nextGaussianFloat32(Float32, Float32)
public func nextGaussianFloat32(mean!: Float32 = 0.0, sigma!: Float32 = 1.0): Float32
Description: Obtains a random number that is of the Float32 type and complies with the Gaussian distribution with the mean value of 0.0 and standard deviation of 1.0. The mean value is the expected value and can be interpreted as the location parameter, which determines the location of the distribution. The standard deviation can be interpreted as the scale parameter, which determines the amplitude of the distribution.
Parameters:
Returns:
Throws:
- SecureRandomException: When the generator cannot generate a random number correctly or fails to generate a random number, this exception is thrown.
func nextGaussianFloat64(Float64, Float64)
public func nextGaussianFloat64(mean!: Float64 = 0.0, sigma!: Float64 = 1.0): Float64
Description: Obtains a random number that is of the Float64 type and complies with the Gaussian distribution with the mean value of 0.0 and standard deviation of 1.0. The mean value is the expected value and can be interpreted as the location parameter, which determines the location of the distribution. The standard deviation can be interpreted as the scale parameter, which determines the amplitude of the distribution.
Parameters:
Returns:
Throws:
- SecureRandomException: When the generator cannot generate a random number correctly or fails to generate a random number, this exception is thrown.
func nextInt16()
public func nextInt16(): Int16
Description: Obtains a random number of the Int16 type.
Returns:
Throws:
- SecureRandomException: When the generator cannot generate a random number correctly or fails to generate a random number, this exception is thrown.
func nextInt32()
public func nextInt32(): Int32
Description: Obtains a random number of the Int32 type.
Returns:
Throws:
- SecureRandomException: When the generator cannot generate a random number correctly or fails to generate a random number, this exception is thrown.
func nextInt16(Int16)
public func nextInt16(max: Int16): Int16
Description: Obtains a random number of the Int16 type in the range [0, max).
Parameters:
- max: Int16: maximum value of the range
Returns:
Throws:
- IllegalArgumentException: If the value of max is not a positive number, this exception is thrown.
- SecureRandomException: When the generator cannot generate a random number correctly or fails to generate a random number, this exception is thrown.
func nextInt32(Int32)
public func nextInt32(max: Int32): Int32
Description: Obtains a random number of the Int32 type in the range [0, max).
Parameters:
- max: Int32: maximum value of the range
Returns:
Throws:
- IllegalArgumentException: If the value of max is not a positive number, this exception is thrown.
- SecureRandomException: When the generator cannot generate a random number correctly or fails to generate a random number, this exception is thrown.
func nextInt64()
public func nextInt64(): Int64
Description: Obtains a random number of the Int64 type.
Returns:
Throws:
- SecureRandomException: When the generator cannot generate a random number correctly or fails to generate a random number, this exception is thrown.
func nextInt64(Int64)
public func nextInt64(max: Int64): Int64
Description: Obtains a random number of the Int64 type in the range [0, max).
Parameters:
- max: Int64: maximum value of the range
Returns:
Throws:
- IllegalArgumentException: If the value of max is not a positive number, this exception is thrown.
- SecureRandomException: When the generator cannot generate a random number correctly or fails to generate a random number, this exception is thrown.
func nextInt8()
public func nextInt8(): Int8
Description: Obtains a random number of the Int8 type.
Returns:
Throws:
- SecureRandomException: When the generator cannot generate a random number correctly or fails to generate a random number, this exception is thrown.
func nextInt8(Int8)
public func nextInt8(max: Int8): Int8
Description: Obtains a random number of the Int8 type in the range [0, max).
Parameters:
- max: Int8: maximum value of the range
Returns:
Throws:
- IllegalArgumentException: If the value of max is not a positive number, this exception is thrown.
- SecureRandomException: When the generator cannot generate a random number correctly or fails to generate a random number, this exception is thrown.
func nextUInt16()
public func nextUInt16(): UInt16
Description: Obtains a random number of the UInt16 type.
Returns:
Throws:
- SecureRandomException: When the generator cannot generate a random number correctly or fails to generate a random number, this exception is thrown.
func nextUInt16(UInt16)
public func nextUInt16(max: UInt16): UInt16
Description: Obtains a random number of the UInt16 type in the range [0, max).
Parameters:
- max: UInt16: maximum value of the range
Returns:
Throws:
- IllegalArgumentException: If the value of max is 0, this exception is thrown.
- SecureRandomException: When the generator cannot generate a random number correctly or fails to generate a random number, this exception is thrown.
func nextUInt32()
public func nextUInt32(): UInt32
Description: Obtains a random number of the UInt32 type.
Returns:
Throws:
- SecureRandomException: When the generator cannot generate a random number correctly or fails to generate a random number, this exception is thrown.
func nextUInt32(UInt32)
public func nextUInt32(max: UInt32): UInt32
Description: Obtains a random number of the UInt32 type in the range [0, max).
Parameters:
- max: UInt32: maximum value of the range
Returns:
Throws:
- IllegalArgumentException: If the value of max is 0, this exception is thrown.
- SecureRandomException: When the generator cannot generate a random number correctly or fails to generate a random number, this exception is thrown.
func nextUInt64()
public func nextUInt64(): UInt64
Description: Obtains a random number of the UInt64 type.
Returns:
Throws:
- SecureRandomException: When the generator cannot generate a random number correctly or fails to generate a random number, this exception is thrown.
func nextUInt64(UInt64)
public func nextUInt64(max: UInt64): UInt64
Description: Obtains a random number of the UInt64 type in the range [0, max).
Parameters:
- max: UInt64: maximum value of the range
Returns:
Throws:
- IllegalArgumentException: If the value of max is 0, this exception is thrown.
- SecureRandomException: When the generator cannot generate a random number correctly or fails to generate a random number, this exception is thrown.
func nextUInt8()
public func nextUInt8(): UInt8
Description: Obtains a random number of the UInt8 type.
Returns:
Throws:
- SecureRandomException: When the generator cannot generate a random number correctly or fails to generate a random number, this exception is thrown.
func nextUInt8(UInt8)
public func nextUInt8(max: UInt8): UInt8
Description: Obtains a random number of the UInt8 type in the range [0, max).
Parameters:
- max: UInt8: maximum value of the range
Returns:
Throws:
- IllegalArgumentException: If the value of max is 0, this exception is thrown.
- SecureRandomException: When the generator cannot generate a random number correctly or fails to generate a random number, this exception is thrown.
class SM4
public class SM4 <: BlockCipher {
public init(
optMode: OperationMode,
key: Array<Byte>,
iv!: Array<Byte> = Array<Byte>(),
paddingMode!: PaddingMode = PaddingMode.PKCS7Padding,
aad!: Array<Byte> = Array<Byte>(),
tagSize!: Int64 = SM4_GCM_TAG_SIZE
)
}
Description: Provides SM4 symmetric encryption and decryption.
The encryption and decryption working mode supported by the SM4 is defined by OperationMode. Currently, the ECB, CBC, OFB, CFB, CTR, and GCM modes are supported.
Different working modes may correspond to different encryption and decryption implementations, and different security. The encryption and decryption working mode that adapts to the scenario must be selected.
In GCM mode, the recommended length for the IV is 12 bytes. In CBC, OFB, CFB, and CTR modes, the IV length is 16 bytes. In ECB mode, the IV does not need to be set.
paddingMode (padding mode) is defined by PaddingMode. Currently, NoPadding (non-padding) and PKCS7Padding (PKCS7 padding) are supported. PKCS7 padding is used by default.
The setting of paddingMode is valid for ECB and CBC. The block length must be equal to the value of blockSize for ECB and CBC block encryption and decryption. Padding will be performed according to the padding mode. The setting of paddingMode is invalid for the OFB, CFB, CTR, and GCM working modes. Padding is not required in these working modes.
If the NoPadding mode is selected, no padding is performed. In the ECB and CBC working modes, it is necessary to check whether data can be grouped. If data cannot be grouped or the length of the last group of data is less than the value of blockSize, an error is reported.
aad indicates additional data, is used only in the GCM mode, is filled by users, is used for digest calculation, and is left empty by default.
tagSize specifies the digest length and is used only in the GCM mode. Its value ranges from 12 to 16 bytes, with the default value SM4_GCM_TAG_SIZE, which is 16 bytes.
In the GCM mode, the last tagSize bytes of the encryption result represent the digest data.
Note:
The GCM mode requires OpenSSL 3.2 or above.
Parent Type:
init(OperationMode, Array<Byte>, Array<Byte>, PaddingMode, Array<Byte>, Int64)
public init(
optMode: OperationMode,
key: Array<Byte>,
iv!: Array<Byte> = Array<Byte>(),
paddingMode!: PaddingMode = PaddingMode.PKCS7Padding,
aad!: Array<Byte> = Array<Byte>(),
tagSize!: Int64 = SM4_GCM_TAG_SIZE
)
Description: Creates an SM4 instance and supports specifying parameters in different working modes.
Parameters:
- optMode: OperationMode: encryption and decryption working mode
- key: Array<Byte>: key; length: 16 bytes
- iv!: Array<Byte>: initialization vector
- paddingMode!: PaddingMode: set padding mode
- aad!: Array<Byte>: set additional data
- tagSize: Int64: set digest length
Throws:
- CryptoException: This exception is thrown when the instantiation fails due to incorrect parameter settings.
prop aad
public prop aad: Array<Byte>
Description: Obtains additional data
prop blockSize
public prop blockSize: Int64
Description: Obtains the grouping length, in bytes.
Type: Int64
prop keySize
public prop keySize: Int64
Description: Obtains the key length.
Type: Int64
prop key
public prop key: Array<Byte>
Description: Obtains the key.
prop optMode
public prop optMode: OperationMode
Description: Obtains the working mode.
Type: OperationMode
prop paddingMode
public prop paddingMode: PaddingMode
Description: Obtains the padding mode.
Type: PaddingMode
prop iv
public prop iv: Array<Byte>
Description: Obtains the initialization vector.
prop ivSize
public prop ivSize: Int64
Description: Obtains the initialization vector length.
Type: Int64
prop tagSize
public prop tagSize: Int64
Description: Obtains the digest length.
Type: Int64
func encrypt(Array<Byte>)
public func encrypt(input: Array<Byte>): Array<Byte>
Description: Encrypts a segment of data.
Parameters:
Returns:
Throws:
- CryptoException: When encryption fails, this exception is thrown.
func encrypt(InputStream, OutputStream)
public func encrypt(input: InputStream, output: OutputStream)
Description: Encrypts an input stream. If the data is too large to be encrypted at a time, data streams can be encrypted.
Parameters:
- input: InputStream: data input stream to be encrypted
- output: OutputStream: data output stream after decryption
Throws:
- CryptoException: When encryption fails, this exception is thrown.
func decrypt(Array<Byte>)
public func decrypt(input: Array<Byte>): Array<Byte>
Description: Decrypts a segment of data.
Parameters:
Returns:
Throws:
- CryptoException: When decryption fails, this exception is thrown.
func decrypt(InputStream, OutputStream)
public func decrypt(input: InputStream, output: OutputStream)
Description: Decrypts an input stream. If the data is too large to be decrypted at a time, data streams can be decrypted.
Parameters:
- input: InputStream: data input stream to be decrypted
- output: OutputStream: data output stream after decryption
Throws:
- CryptoException: When decryption fails, this exception is thrown.
Struct
struct OperationMode
public struct OperationMode <: ToString & Equatable<OperationMode>
Description: Indicates the working mode of the symmetric encryption and decryption algorithm.
Parent Type:
static let ECB
public static let ECB
Description: Obtains the Electronic CodeBook working mode.
Type: OperationMode
static let CBC
public static let CBC
Description: Obtains the Cipher Block Chaining working mode.
Type: OperationMode
static let OFB
public static let OFB
Description: Obtains the Output FeedBack working mode.
Type: OperationMode
static let CFB
public static let CFB
Description: Obtains the Cipher Feedback working mode.
Type: OperationMode
static let CTR
public static let CTR
Description: Obtains the CounTeR (counter) working mode.
Type: OperationMode
static let GCM
public static let GCM
Description: Obtains the Galois Counter working mode.
Type: OperationMode
let mode
public let mode: String
Description: Obtains the working mode of operation block encryption and decryption. Currently, ECB, CBC, CFB, OFB, CTR, and GCM are supported.
Type: String
func toString()
public override func toString(): String
Description: Obtains a working mode character string.
Returns:
- String: working mode string
func ==(OperationMode)
public operator override func ==(other: OperationMode): Bool
Description: Checks whether the working modes are the same.
Parameters:
- other: OperationMode: working mode
Returns:
- Bool: true: yes; false: no
func !=(OperationMode)
public operator override func !=(other: OperationMode): Bool
Description: Checks whether the working modes are not the same.
Parameters:
- other: OperationMode: working mode
Returns:
- Bool: true: yes; false: no
struct PaddingMode
public struct PaddingMode <: Equatable<PaddingMode>
Description: Indicates the padding mode of the symmetric encryption and decryption algorithm.
Parent Type:
static let NoPadding
public static let NoPadding
Description: Indicates that no padding is performed.
Type: PaddingMode
static let PKCS7Padding
public static let PKCS7Padding
Description: Adopts the PKCS7 protocol for padding.
Type: PaddingMode
let paddingType
public let paddingType: Int64
Description: Obtains the padding mode for block encryption and decryption. Currently, non-padding and PKCS7 padding are supported.
Type: Int64
func ==(PaddingMode)
public operator override func ==(other: PaddingMode): Bool
Description: Checks whether the padding modes are the same.
Parameters:
- other: PaddingMode: padding mode
Returns:
- Bool: true: yes; false: no
func !=(PaddingMode)
public operator override func !=(other: PaddingMode): Bool
Description: Checks whether the working modes are not the same.
Parameters:
- other: PaddingMode: padding mode
Returns:
- Bool: true: yes; false: no
Exception Class
class SecureRandomException
public class SecureRandomException <: Exception {
public init()
public init(message: String)
}
Description: Indicates the exception class for secure random numbers in the crypto package.
Parent Type:
init()
public init()
Description: Creates a SecureRandomException instance. The exception information is empty.
init(String)
public init(message: String)
Description: Creates a SecureRandomException instance according to exception information.
Parameters:
- message: String: error information
SecureRandom Usage
Example: Creating random number objects
Code:
import crypto.crypto.*
main() {
let r = SecureRandom()
for (_ in 0..10) {
let flip = r.nextBool()
println(flip)
}
return 0
}
Running result:
Note
A possible running result is as follows (true and false are random):
false
true
false
false
false
true
true
false
false
true
SM4 Usage
Example: Encrypting and decrypting data using SM4
Code:
import crypto.crypto.*
import encoding.hex.fromHexString
main() {
var plains ="hello cangjie!"
var key = "1234567890123456"
var iv = "1234567890123456"
var sm4 = SM4(OperationMode.CBC, key.toArray(), iv: iv.toArray())
var enRe = sm4.encrypt(plains.toArray())
var dd =sm4.decrypt(enRe)
println(String.fromUtf8(dd))
}
Running result:
hello cangjie!
crypto.digest Package
Function Description
The digest package provides common message digest algorithms, including MD5, SHA1, SHA224, SHA256, SHA384, SHA512, HMAC, and SM3.
This package depends on the crypto dynamic library file of OpenSSL 3. Therefore, related tools must be installed before using this package.
-
For Linux, perform the following operations:
- Install the OpenSSL 3 development tool package using the package management tool of the system if the tool supports the installation, and ensure that the system installation directory contains the libcrypto.so and libcrypto.so.3 dynamic library files. For example, on Ubuntu 22.04, run the sudo apt install libssl-dev command to install the libssl-dev tool package.
- Download and install the OpenSSL 3.x.x source code compilation software package if the preceding method fails, and ensure that the installation directory contains the libcrypto.so and libcrypto.so.3 dynamic library files. Then, use either of the following methods to ensure that the system linker can find these files:
- Install the software in a system directory if OpenSSL has not been installed.
- Set the directory containing these files to the environment variables LD_LIBRARY_PATH and LIBRARY_PATH if the software is installed in a user-defined directory.
-
For Windows, perform the following operations:
- Download and install the OpenSSL 3.x.x source code compilation software package for the x64 architecture, or download and install the OpenSSL 3.x.x software package precompiled by a third party for developers.
- Ensure that the installation directory contains the libcrypto.dll.a (or libcrypto.lib) and libcrypto-3-x64.dll library files.
- Set the directory containing the libcrypto.dll.a (or libcrypto.lib) to the environment variable LIBRARY_PATH, and the directory containing libcrypto-3-x64.dll to the environment variable PATH.
-
For macOS, perform the following operations:
- Run the brew install openssl@3 command to install OpenSSL, and ensure that the system installation directory contains the libcrypto.dylib and libcrypto.3.dylib dynamic library files.
- Download and install the OpenSSL 3.x.x source code compilation software package if the preceding method fails, and ensure that the installation directory contains the libcrypto.dylib and libcrypto.3.dylib dynamic library files. Then, use either of the following methods to ensure that the system linker can find these files:
- Install the software in a system directory if OpenSSL has not been installed.
- Set the directory containing these files to the environment variables DYLD_LIBRARY_PATH and LIBRARY_PATH.
Note
If OpenSSL 3 is not installed or an earlier version is installed, the program may fail to work with the following exception thrown: CryptoException: Can not load openssl library or function xxx.
API List
Class
| Name | Description |
|---|---|
| HMAC | Specifies the HMAC digest algorithm. |
| MD5 | Specifies the MD5 digest algorithm. |
| SHA1 | Specifies the SHA1 digest algorithm. |
| SHA224 | Specifies the SHA224 digest algorithm. |
| SHA256 | Specifies the SHA256 digest algorithm. |
| SHA384 | Specifies the SHA384 digest algorithm. |
| SHA512 | Specifies the SHA512 digest algorithm. |
| SM3 | SM3 digest algorithm. |
Struct
| Name | Description |
|---|---|
| HashType | Specifies the digest algorithm type. |
Exception Class
| Name | Description |
|---|---|
| CryptoException | Specifies the exception class of the crypto package. |
Class
class HMAC
public class HMAC <: Digest {
public init(key: Array<Byte>, digest: () -> Digest)
public init(key: Array<Byte>, algorithm: HashType)
}
Description: Provides implementation functions of the HMAC algorithm. The currently supported digest algorithms include MD5, SHA1, SHA224, SHA256, SHA384, SHA512, and SM3.
Parent Type:
prop blockSize
public prop blockSize: Int64
Description: Obtains the information block length (in bytes) of the hash algorithm selected by HMAC.
Type: Int64
prop size
public prop size: Int64
Description: Obtains the digest information length (in bytes) of the hash algorithm selected by HMAC.
Type: Int64
init(Array<Byte>, () -> Digest)
public init(key: Array<Byte>, digest: () -> Digest)
Description: Indicates a constructor used to create an HMAC object.
Parameters:
- key: Array<Byte>: key. It is recommended that this parameter be greater than or equal to the digest length of the selected hash algorithm.
- digest: () -> Digest: hash algorithm
Throws:
- CryptoException: When the key value is null, this exception is thrown.
init(Array<Byte>, HashType)
public init(key: Array<Byte>, algorithm: HashType)
Description: Indicates a constructor used to create an HMAC object.
Parameters:
- key: Array<Byte>: key. It is recommended that this parameter be greater than or equal to the digest length of the selected hash algorithm.
- algorithm: HashType: hash algorithm.
Throws:
- CryptoException: When the key value is null, this exception is thrown.
func equal(Array<Byte>, Array<Byte>)
public static func equal(mac1: Array<Byte>, mac2: Array<Byte>): Bool
Description: Checks whether two message digests are equal and without disclosing the comparison time. That is, the traditional short-circuit principle is not used for the comparison to prevent timing attacks.
Parameters:
- mac1: Array<Byte>: one information digest sequence
- mac2: Array<Byte>: the other information digest sequence
Returns:
- Bool: whether the information digests are equal; true: yes, false: no
func finish()
public func finish(): Array<Byte>
Description: Returns the generated message digest value. Note that digest calculation cannot be performed after finish is called. If digest calculation needs to be performed again, the context needs to be reset.
Returns:
Throws:
- CryptoException: When finish is called again to perform digest calculation without context reset, this exception is thrown.
func reset()
public func reset(): Unit
Description: Resets an HMAC object to the initial state and clears the HMAC context.
Throws:
- CryptoException: When the resetting fails due to an internal error, this exception is thrown.
func write(Array<Byte>)
public func write(buffer: Array<Byte>): Unit
Description: Updates an HMAC object using a given buffer. An object can be updated more than once before finish is called.
Parameters:
Throws:
- CryptoException: When buffer is empty or finish has been called to generate an information digest, this exception is thrown.
class MD5
public class MD5 <: Digest {
public init()
}
Description: Provides implementation functions of the MD5 algorithm.
Parent Type:
prop blockSize
public prop blockSize: Int64
Description: Obtains the length (in bytes) of an MD5 information block.
Type: Int64
prop size
public prop size: Int64
Description: Obtains the length (in bytes) of an MD5 digest information.
Type: Int64
init()
public init()
Description: Indicates a constructor without parameters used to create an MD5 object.
func finish()
public func finish(): Array<Byte>
Description: Returns the generated MD5 value. Note that the MD5 context changes after finish is called. After finish is called, digest calculation cannot be performed. If digest calculation needs to be performed again, the context needs to be reset.
Returns:
Throws:
- CryptoException: When finish is called again to perform digest calculation without context reset, this exception is thrown.
func reset()
public func reset(): Unit
Description: Resets an MD5 object to the initial state and clears the MD5 context.
func write(Array<Byte>)
public func write(buffer: Array<Byte>): Unit
Description: Updates an MD5 object using a given buffer. An object can be updated more than once before finish is called.
Parameters:
Throws:
- CryptoException: When finish is called again to perform digest calculation without context reset, this exception is thrown.
class SHA1
public class SHA1 <: Digest {
public init()
}
Description: Provides implementation functions of the SHA1 algorithm.
Parent Type:
prop blockSize
public prop blockSize: Int64
Description: Obtains the length (in bytes) of a SHA1 information block.
Type: Int64
prop size
public prop size: Int64
Description: Obtains the length (in bytes) of a SHA1 digest information.
Type: Int64
init()
public init()
Description: Indicates a constructor without parameters used to create a SHA1 object.
func finish()
public func finish(): Array<Byte>
Description: Returns the generated SHA1 value. Note that the SHA1 context changes after finish is called. After finish is called, digest calculation cannot be performed. If digest calculation needs to be performed again, the context needs to be reset.
Returns:
Throws:
- CryptoException: When finish is called again to perform digest calculation without context reset, this exception is thrown.
func reset()
public func reset(): Unit
Description: Resets a SHA1 object to the initial state and clears the SHA1 context.
func write(Array<Byte>)
public func write(buffer: Array<Byte>): Unit
Description: Updates a SHA1 object using a given buffer. An object can be updated more than once before finish is called.
Parameters:
Throws:
- CryptoException: When finish is called again to perform digest calculation without context reset, this exception is thrown.
class SHA224
public class SHA224 <: Digest {
public init()
}
Description: Provides implementation functions of the SHA224 algorithm.
Parent Type:
prop blockSize
public prop blockSize: Int64
Description: Obtains the length (in bytes) of a SHA224 information block.
Type: Int64
prop size
public prop size: Int64
Description: Obtains the length (in bytes) of a SHA224 digest information.
Type: Int64
init()
public init()
Description: Indicates a constructor without parameters used to create a SHA224 object.
func finish()
public func finish(): Array<Byte>
Description: Returns the generated SHA224 value. Note that the SHA224 context changes after finish is called. After finish is called, digest calculation cannot be performed. If digest calculation needs to be performed again, the context needs to be reset.
Returns:
Throws:
- CryptoException: When finish is called again to perform digest calculation without context reset, this exception is thrown.
func reset()
public func reset(): Unit
Description: Resets a SHA224 object to the initial state and clears the SHA224 context.
func write(Array<Byte>)
public func write(buffer: Array<Byte>): Unit
Description: Updates a SHA224 object using a given buffer. An object can be updated more than once before finish is called.
Parameters:
Throws:
- CryptoException: When finish is called again to perform digest calculation without context reset, this exception is thrown.
class SHA256
public class SHA256 <: Digest {
public init()
}
Description: Provides implementation functions of the SHA256 algorithm.
Parent Type:
prop blockSize
public prop blockSize: Int64
Description: Obtains the length (in bytes) of a SHA256 information block.
Type: Int64
prop size
public prop size: Int64
Description: Obtains the length (in bytes) of a SHA256 digest information.
Type: Int64
init()
public init()
Description: Indicates a constructor without parameters used to create a SHA256 object.
func finish()
public func finish(): Array<Byte>
Description: Returns the generated SHA256 value. Note that the SHA256 context changes after finish is called. After finish is called, digest calculation cannot be performed. If digest calculation needs to be performed again, the context needs to be reset.
Returns:
Throws:
- CryptoException: When finish is called again to perform digest calculation without context reset, this exception is thrown.
func reset()
public func reset(): Unit
Description: Resets a SHA256 object to the initial state and clears the SHA256 context.
func write(Array<Byte>)
public func write(buffer: Array<Byte>): Unit
Description: Updates a SHA256 object using a given buffer. An object can be updated more than once before finish is called.
Parameters:
Throws:
- CryptoException: When finish is called again to perform digest calculation without context reset, this exception is thrown.
class SHA384
public class SHA384 <: Digest {
public init()
}
Description: Provides implementation functions of the SHA384 algorithm.
Parent Type:
prop blockSize
public prop blockSize: Int64
Description: Obtains the length (in bytes) of a SHA384 information block.
Type: Int64
prop size
public prop size: Int64
Description: Obtains the length (in bytes) of a SHA384 digest information.
Type: Int64
init()
public init()
Description: Indicates a constructor without parameters used to create a SHA384 object.
func finish()
public func finish(): Array<Byte>
Description: Returns the generated SHA384 value. Note that the SHA384 context changes after finish is called. After finish is called, digest calculation cannot be performed. If digest calculation needs to be performed again, the context needs to be reset.
Returns:
Throws:
- CryptoException: When finish is called again to perform digest calculation without context reset, this exception is thrown.
func reset()
public func reset(): Unit
Description: Resets a SHA384 object to the initial state and clears the SHA384 context.
func write(Array<Byte>)
public func write(buffer: Array<Byte>): Unit
Description: Updates a SHA384 object using a given buffer. An object can be updated more than once before finish is called.
Parameters:
Throws:
- CryptoException: When finish is called again to perform digest calculation without context reset, this exception is thrown.
class SHA512
public class SHA512 <: Digest {
public init()
}
Description: Provides implementation functions of the SHA512 algorithm.
Parent Type:
prop blockSize
public prop blockSize: Int64
Description: Obtains the length (in bytes) of a SHA512 information block.
Type: Int64
prop size
public prop size: Int64
Description: Obtains the length (in bytes) of a SHA512 digest information.
Type: Int64
init()
public init()
Description: Indicates a constructor without parameters used to create a SHA512 object.
func finish()
public func finish(): Array<Byte>
Description: Returns the generated SHA512 value. Note that the SHA512 context changes after finish is called. After finish is called, digest calculation cannot be performed. If digest calculation needs to be performed again, the context needs to be reset.
Returns:
Throws:
- CryptoException: When finish is called again to perform digest calculation without context reset, this exception is thrown.
func reset()
public func reset(): Unit
Description: Resets a SHA512 object to the initial state and clears the SHA512 context.
func write(Array<Byte>)
public func write(buffer: Array<Byte>): Unit
Description: Updates a SHA512 object using a given buffer. An object can be updated more than once before finish is called.
Parameters:
Throws:
- CryptoException: When finish is called again to perform digest calculation without context reset, this exception is thrown.
class SM3
public class SM3 <: Digest {
public init()
}
Description: Provides implementation functions of the SM3 algorithm.
Parent Type:
prop blockSize
public prop blockSize: Int64
Description: Obtains the length (in bytes) of an SM3 information block.
Type: Int64
prop size
public prop size: Int64
Description: Obtains the length (in bytes) of an SM3 digest information.
Type: Int64
init()
public init()
Description: Indicates a constructor without parameters used to create an SM3 object.
func finish()
public func finish(): Array<Byte>
Description: Returns the generated SM3 value. Note that the SM3 context changes after finish is called. After finish is called, digest calculation cannot be performed. If digest calculation needs to be performed again, the context needs to be reset.
Returns:
Throws:
- CryptoException: When finish is called again to perform digest calculation without context reset, this exception is thrown.
func reset()
public func reset(): Unit
Description: Resets an SM3 object to the initial state and clears the SM3 context.
func write(Array<Byte>)
public func write(buffer: Array<Byte>): Unit
Description: Updates an SM3 object using a given buffer. An object can be updated more than once before finish is called.
Parameters:
Throws:
- CryptoException: When finish is called again to perform digest calculation without context reset, this exception is thrown.
Struct
struct HashType
public struct HashType <: ToString & Equatable<HashType>
Description: Indicates a hash algorithm type struct. MD5, SHA1, SHA224, SHA256, SHA384, and SHA512 are common digest algorithms.
Parent Type:
prop MD5
public static prop MD5: HashType
Description: Returns an MD5 type.
Type: HashType
prop SHA1
public static prop SHA1: HashType
Description: Returns a SHA1 type.
Type: HashType
prop SHA224
public static prop SHA224: HashType
Description: Returns a SHA224 type.
Type: HashType
prop SHA256
public static prop SHA256: HashType
Description: Returns a SHA256 type.
Type: HashType
prop SHA384
public static prop SHA384: HashType
Description: Returns a SHA384 type.
Type: HashType
prop SHA512
public static prop SHA512: HashType
Description: Returns a SHA512 type.
Type: HashType
prop SM3
public static prop SM3: HashType
Description: Returns a SM3 type.
Type: HashType
func toString()
public func toString(): String
Description: Obtains the name of a hash algorithm.
Returns:
- String: name of the hash algorithm
operator func ==(HashType)
public operator override func ==(other: HashType): Bool
Description: Checks whether two HashType values references the same instance.
Parameters:
- other: HashType: HashType to be compared
Returns:
- Bool: If they are the same,
trueis returned. Otherwise,falseis returned.
operator func !=(HashType)
public operator override func !=(other: HashType): Bool
Description: Checks whether two HashType values references different instances.
Parameters:
- other: HashType: HashType to be compared
Returns:
- Bool: If they are different,
trueis returned. Otherwise,falseis returned.
Exception Class
class CryptoException
public class CryptoException <: Exception {
public init()
public init(message: String)
}
Description: Specifies exceptions thrown when errors occur in digests and during encryption and decryption.
Parent Type:
init()
public init()
Description: Indicates a constructor without parameters used to construct a CryptoException exception.
init(String)
public init(message: String)
Description: Constructs a CryptoException object based on exception information.
Parameters:
- message: String: exception information
digest Usage
MD5 Algorithm Example
Calling the Common digest Function Provided by the Cangjie Standard Library
import crypto.digest.*
import std.convert.*
import std.crypto.digest.*
import encoding.hex.*
main() {
var str: String = "helloworld"
var md5Instance = MD5()
var md: Array<Byte> = digest(md5Instance, str)
var result: String = toHexString(md)
println(result)
return 0
}
Calling the MD5 Member Function
import crypto.digest.*
import std.convert.*
import std.crypto.digest.*
import encoding.hex.*
main() {
var str: String = "helloworld"
var md5Instance = MD5()
md5Instance.write(str.toArray())
var md: Array<Byte> = md5Instance.finish()
var result: String = toHexString(md)
println(result)
return 0
}
Running result:
fc5e038d38a57032085441e7fe7010b0
SHA1 Algorithm Example
Calling the Common digest Function Provided by the Cangjie Standard Library
import crypto.digest.*
import std.convert.*
import std.crypto.digest.*
import encoding.hex.*
main() {
var str: String = "helloworld"
var sha1Instance = SHA1()
var md: Array<Byte> = digest(sha1Instance, str)
var result: String = toHexString(md)
println(result)
return 0
}
Calling the SHA1 Member Function
import crypto.digest.*
import std.convert.*
import std.crypto.digest.*
import encoding.hex.*
main() {
var str: String = "helloworld"
var sha1Instance = SHA1()
sha1Instance.write(str.toArray())
var md: Array<Byte> = sha1Instance.finish()
var result: String = toHexString(md)
println(result)
return 0
}
Running result:
6adfb183a4a2c94a2f92dab5ade762a47889a5a1
SHA224 Algorithm Example
Calling the Common digest Function Provided by the Cangjie Standard Library
import crypto.digest.*
import std.convert.*
import std.crypto.digest.*
import encoding.hex.*
main() {
var str: String = "helloworld"
var sha224Instance = SHA224()
var md: Array<Byte> = digest(sha224Instance, str)
var result: String = toHexString(md)
println(result)
return 0
}
Calling the SHA224 Member Function
import crypto.digest.*
import std.convert.*
import std.crypto.digest.*
import encoding.hex.*
main() {
var str: String = "helloworld"
var sha224Instance = SHA224()
sha224Instance.write(str.toArray())
var md: Array<Byte> = sha224Instance.finish()
var result: String = toHexString(md)
println(result)
return 0
}
Running result:
b033d770602994efa135c5248af300d81567ad5b59cec4bccbf15bcc
SHA256 Algorithm Example
Calling the Common digest Function Provided by the Cangjie Standard Library
import crypto.digest.*
import std.convert.*
import std.crypto.digest.*
import encoding.hex.*
main() {
var str: String = "helloworld"
var sha256Instance = SHA256()
var md: Array<Byte> = digest(sha256Instance, str)
var result: String = toHexString(md)
println(result)
return 0
}
Calling the SHA256 Member Function
import crypto.digest.*
import std.convert.*
import std.crypto.digest.*
import encoding.hex.*
main() {
var str: String = "helloworld"
var sha256Instance = SHA256()
sha256Instance.write(str.toArray())
var md: Array<Byte> = sha256Instance.finish()
var result: String = toHexString(md)
println(result)
return 0
}
Running result:
936a185caaa266bb9cbe981e9e05cb78cd732b0b3280eb944412bb6f8f8f07af
SHA384 Algorithm Example
Calling the Common digest Function Provided by the Cangjie Standard Library
import crypto.digest.*
import std.convert.*
import std.crypto.digest.*
import encoding.hex.*
main() {
var str: String = "helloworld"
var sha384Instance = SHA384()
var md: Array<Byte> = digest(sha384Instance, str)
var result: String = toHexString(md)
println(result)
return 0
}
Calling the SHA384 Member Function
import crypto.digest.*
import std.convert.*
import std.crypto.digest.*
import encoding.hex.*
main() {
var str: String = "helloworld"
var sha384Instance = SHA384()
sha384Instance.write(str.toArray())
var md: Array<Byte> = sha384Instance.finish()
var result: String = toHexString(md)
println(result)
return 0
}
Running result:
97982a5b1414b9078103a1c008c4e3526c27b41cdbcf80790560a40f2a9bf2ed4427ab1428789915ed4b3dc07c454bd9
SHA512 Algorithm Example
Calling the Common digest Function Provided by the Cangjie Standard Library
import crypto.digest.*
import std.convert.*
import std.crypto.digest.*
import encoding.hex.*
main() {
var str: String = "helloworld"
var sha512Instance = SHA512()
var md: Array<Byte> = digest(sha512Instance, str)
var result: String = toHexString(md)
println(result)
return 0
}
Calling the SHA512 Member Function
import crypto.digest.*
import std.convert.*
import std.crypto.digest.*
import encoding.hex.*
main() {
var str: String = "helloworld"
var sha512Instance = SHA512()
sha512Instance.write(str.toArray())
var md: Array<Byte> = sha512Instance.finish()
var result: String = toHexString(md)
println(result)
return 0
}
Running result:
1594244d52f2d8c12b142bb61f47bc2eaf503d6d9ca8480cae9fcf112f66e4967dc5e8fa98285e36db8af1b8ffa8b84cb15e0fbcf836c3deb803c13f37659a60
HMAC Algorithm Example
Note
Currently, only HMAC-SHA512 is supported.
Calling the Common digest Function Provided by the Cangjie Standard Library
import crypto.digest.*
import encoding.hex.*
import std.crypto.digest.*
main() {
var algorithm: HashType = HashType.SHA512
var key: Array<UInt8> = "cangjie".toArray()
var data: Array<UInt8> = "123456789".toArray()
var hmac= HMAC(key,algorithm)
var md: Array<Byte> = digest(hmac, data)
var result: String = toHexString(md)
println(result)
return 0
}
Running result:
2bafeb53b60a119d38793a886c7744f5027d7eaa3702351e75e4ff9bf255e3ce296bf41f80adda2861e81bd8efc52219df821852d84a17fb625e3965ebf2fdd9
Calling the HMAC-SHA512 Member Function
import crypto.digest.*
import encoding.hex.*
main() {
var algorithm: HashType = HashType.SHA512
var key: Array<UInt8> = "cangjie".toArray()
var data1: Array<UInt8> = "123".toArray()
var data2: Array<UInt8> = "456".toArray()
var data3: Array<UInt8> = "789".toArray()
var data4: Array<UInt8> = "123456789".toArray()
var hmac= HMAC(key,algorithm)
hmac.write(data1)
hmac.write(data2)
hmac.write(data3)
var md1: Array<Byte>= hmac.finish()
var result1: String = toHexString(md1)
println(result1)
hmac.reset()
hmac.write(data4)
var md2: Array<Byte>= hmac.finish()
var result2: String = toHexString(md2)
println(result2)
println(HMAC.equal(md1,md2))
return 0
}
Running result:
2bafeb53b60a119d38793a886c7744f5027d7eaa3702351e75e4ff9bf255e3ce296bf41f80adda2861e81bd8efc52219df821852d84a17fb625e3965ebf2fdd9
2bafeb53b60a119d38793a886c7744f5027d7eaa3702351e75e4ff9bf255e3ce296bf41f80adda2861e81bd8efc52219df821852d84a17fb625e3965ebf2fdd9
true
SM3 Algorithm Example
Calling the Common digest Function Provided by the Cangjie Standard Library
import crypto.digest.*
import std.convert.*
import std.crypto.digest.*
import encoding.hex.*
main() {
var str: String = "helloworld"
var sm3Instance = SM3()
var md: Array<Byte> = digest(sm3Instance, str)
var result: String = toHexString(md)
println(result)
return 0
}
crypto.keys Package
Function Description
The keys package provides asymmetric encryption and signature algorithms, including RSA and SM2 asymmetric encryption algorithms and the ECDSA signature algorithm.
This package depends on the crypto dynamic library file of OpenSSL 3. Therefore, Related tools must be installed before using this package.
-
For Linux, perform the following operations:
- Install the OpenSSL 3 development tool package using the package management tool of the system if the tool supports the installation, and ensure that the system installation directory contains the libcrypto.so and libcrypto.so.3 dynamic library files. For example, on Ubuntu 22.04, run the sudo apt install libssl-dev command to install the libssl-dev tool package.
- Download and install the OpenSSL 3.x.x source code compilation software package if the preceding method fails, and ensure that the installation directory contains the libcrypto.so and libcrypto.so.3 dynamic library files. Then, use either of the following methods to ensure that the system linker can find these files:
- Install the software in a system directory if OpenSSL has not been installed.
- Set the directory containing these files to the environment variables LD_LIBRARY_PATH and LIBRARY_PATH if the software is installed in a user-defined directory.
-
For Windows, perform the following operations:
- Download and install the OpenSSL 3.x.x source code compilation software package for the x64 architecture, or download and install the OpenSSL 3.x.x software package precompiled by a third party for developers.
- Ensure that the installation directory contains the libcrypto.dll.a (or libcrypto.lib) and libcrypto-3-x64.dll library files.
- Set the directory containing the libcrypto.dll.a (or libcrypto.lib) to the environment variable LIBRARY_PATH, and the directory containing libcrypto-3-x64.dll to the environment variable PATH.
-
For macOS, perform the following operations:
- Run the brew install openssl@3 command to install OpenSSL, and ensure that the system installation directory contains the libcrypto.dylib and libcrypto.3.dylib dynamic library files.
- Download and install the OpenSSL 3.x.x source code compilation software package if the preceding method fails, and ensure that the installation directory contains the libcrypto.dylib and libcrypto.3.dylib dynamic library files. Then, use either of the following methods to ensure that the system linker can find these files:
- Install the software in a system directory if OpenSSL has not been installed.
- Set the directory containing these files to the environment variables DYLD_LIBRARY_PATH and LIBRARY_PATH.
Note:
If OpenSSL 3 is not installed or an earlier version is installed, the program may fail to work with the following exception thrown: CryptoException: Can not load openssl library or function xxx.
API List
Class
| Name | Description |
|---|---|
| ECDSAPrivateKey | Specifies the ECDSA private key class. |
| ECDSAPublicKey | Specifies the ECDSA public key class. |
| RSAPrivateKey | Specifies the RSA private key class. |
| RSAPublicKey | Specifies the RSA public key class. |
| SM2PrivateKey | Specifies the SM2 private key class. |
| SM2PublicKey | Specifies the SM2 public key class. |
Enumeration
| Name | Description |
|---|---|
| Curve | The enumeration type Curve is used to select the elliptic curve type when the ECDSA key is generated. |
| PadOption | Specifies the padding mode of the RSA. |
Structure
| Name | Description |
|---|---|
| OAEPOption | Specifies optimal asymmetric encryption padding |
| PSSOption | Specifies a probabilistic signature scheme |
Class
class ECDSAPrivateKey
public class ECDSAPrivateKey <: PrivateKey {
public init(curve: Curve)
}
Description: Indicates the ECDSA private key class which provides the capability of generating ECDSA private keys. ECDSA private keys support sign operations as well as encoding and decoding in PEM and DER formats.
Parent Type:
init()
public init(curve: Curve)
Description: Generates a private key with initialization performed.
Parameters:
- curve: Curve: elliptic curve type
Throws:
- CryptoException: When initialization fails, this exception is thrown.
func decodeDer(DerBlob)
public static func decodeDer(blob: DerBlob): ECDSAPrivateKey
Description: Decodes a private key from the DER format.
Parameters:
- blob: DerBlob: private key object in binary format
Returns:
- ECDSAPrivateKey: decoded ECDSA private key
Throws:
- CryptoException: When decoding fails, this exception is thrown.
func decodeDer(DerBlob, ?String)
public static func decodeDer(blob: DerBlob, password!: ?String): ECDSAPrivateKey
Description: Decodes an encrypted private key from the DER format.
Parameters:
- blob: DerBlob: private key object in binary format
- password!: ?String: password required for decrypting the private key. If the password is None, decryption is not performed.
Returns:
- ECDSAPrivateKey: decoded ECDSA private key
Throws:
- CryptoException: If decoding or decryption fails, or the parameter password is empty, this exception is thrown.
func decodeFromPem(String)
public static func decodeFromPem(text: String): ECDSAPrivateKey
Description: Decodes a private key from the PEM format.
Parameters:
- text: String: private key character stream in PEM format
Returns:
- ECDSAPrivateKey: decoded ECDSA private key
Throws:
- CryptoException: If decoding fails, the character stream does not comply with the PEM format, or the file header does not comply with the private key header standard, this exception is thrown.
func decodeFromPem(String, ?String)
public static func decodeFromPem(text: String, password!: ?String): ECDSAPrivateKey
Description: Decodes a private key from the PEM format.
Parameters:
- text: String: private key character stream in PEM format
- password!: ?String: password required for decrypting the private key. If the password is None, decryption is not performed.
Returns:
- ECDSAPrivateKey: decoded ECDSA private key
Throws:
- CryptoException: If decoding or decryption fails, the parameter password is empty, the character stream does not comply with the PEM format, or the file header does not comply the private key header standard, this exception is thrown.
func encodeToDer()
public override func encodeToDer(): DerBlob
Description: Encodes a private key in DER format.
Returns:
- DerBlob: encoded private key in DER format
Throws:
- CryptoException: When encoding fails, this exception is thrown.
func encodeToDer(?String)
public func encodeToDer(password!: ?String): DerBlob
Description: Encrypts a private key using AES-256-CBC and encodes the private key in DER format.
Parameters:
- password!: ?String: password required for encrypting the private key. If the password is None, encryption is not performed.
Returns:
- DerBlob: encoded private key in DER format
Throws:
- CryptoException: If encoding or encryption fails, or the parameter password is empty, this exception is thrown.
func encodeToPem()
public override func encodeToPem(): PemEntry
Description: Encodes a private key in PEM format.
Returns:
- PemEntry: object of the private key in PEM format
Throws:
- CryptoException: When encoding fails, this exception is thrown.
func sign(Array<Byte>)
public func sign(digest: Array<Byte>): Array<Byte>
Description: Signs the digest result of data.
Parameters:
Returns:
Throws:
- CryptoException: When signing fails, this exception is thrown.
func toString
public override func toString(): String
Description: Outputs the private key type.
Returns:
- String: private key type description
class ECDSAPublicKey
public class ECDSAPublicKey <: PublicKey {
public init(pri: ECDSAPrivateKey)
}
Description: Indicates the ECDSA public key class which provides the capability of generating ECDSA public keys. ECDSA public keys support signature authentication as well as encoding and decoding in PEM and DER formats.
Parent Type:
init(ECDSAPrivateKey)
public init(pri: ECDSAPrivateKey)
Description: Initializes a public key with initialization performed, that is, obtains the corresponding public key from a private key.
Parameters:
- pri: ECDSAPrivateKey: ECDSA private key
Throws:
- CryptoException: When initialization fails, this exception is thrown.
func decodeDer(DerBlob)
public static func decodeDer(blob: DerBlob): ECDSAPublicKey
Description: Decodes a public key from the DER format.
Parameters:
- blob: DerBlob: public key object in binary format
Returns:
- ECDSAPublicKey: decoded ECDSA public key
Throws:
- CryptoException: When encoding fails, this exception is thrown.
func decodeFromPem(String)
public static func decodeFromPem(text: String): ECDSAPublicKey
Description: Decodes a public key from the PEM format.
Parameters:
- text: String: public key character stream in PEM format
Returns:
- ECDSAPublicKey: decoded ECDSA public key
Throws:
- CryptoException: If decoding fails, the character stream does not comply with the PEM format, or the file header does not comply with the public key header standard, this exception is thrown.
func encodeToDer()
public override func encodeToDer(): DerBlob
Description: Encodes a public key in DER format.
Returns:
- DerBlob: encoded public key in DER format
Throws:
- CryptoException: When encoding fails, this exception is thrown.
func encodeToPem()
public override func encodeToPem(): PemEntry
Description: Encodes a public key in PEM format.
Returns:
Throws:
- CryptoException: When encoding fails, this exception is thrown.
func toString
public override func toString(): String
Description: Outputs the public key type.
Returns:
- String: private key type description
func verify(Array<Byte>, Array<Byte>)
public func verify(digest: Array<Byte>, sig: Array<Byte>): Bool
Description: Verifies the signing result.
Parameters:
Returns:
- Bool: If true is returned, the verification is successful. If false is returned, the verification fails.
class RSAPrivateKey
public class RSAPrivateKey <: PrivateKey{
public init(bits: Int32)
public init(bits: Int32, e: BigInt)
}
Description: Indicates the RSA private key class which provides the capability of generating RSA private keys. RSA private keys support sign and decrypt operations as well as encoding and decoding in PEM and DER formats, complying with the PKCS1 standard.
Parent Type:
init(Int32)
public init(bits: Int32)
Description: Generates a private key with initialization performed. The default public key exponent is 65537, which is recommended in the industry. The public key exponent e directly affects the security and encryption efficiency of the RSA algorithm. Generally, a smaller value of e indicates a higher encryption speed but lower security.
Parameters:
- bits: Int32: key length, which must be greater than or equal to 512 bits and less than or equal to 16,384 bits
Throws:
- CryptoException: If the key length does not meet the requirements or the initialization fails, this exception is thrown.
init(Int32, BigInt)
public init(bits: Int32, e: BigInt)
Description: Generates a private key with initialization performed and allowing users to specify the public exponent.
Parameters:
- bits: Int32: key length, which must be greater than 512 bits and less than or equal to 16,384 bits; recommended key length: no less than 3,072 bits
- e: BigInt: public exponent of the public key; value range: odd number in [3, 2^256 – 1].
Throws:
- CryptoException: If the key length or the public exponent of the public key does not meet the requirements, or the initialization fails, this exception is thrown.
func decodeDer(DerBlob)
public static func decodeDer(blob: DerBlob): RSAPrivateKey
Description: Decodes a private key from the DER format.
Parameters:
- blob: DerBlob: private key object in binary format
Returns:
- RSAPrivateKey: decoded RSA private key
Throws:
- CryptoException: When decoding fails, this exception is thrown.
func decodeDer(DerBlob, ?String)
public static func decodeDer(blob: DerBlob, password!: ?String): RSAPrivateKey
Description: Decodes an encrypted private key from the DER format.
Parameters:
- blob: DerBlob: private key object in binary format
- password!: ?String: password required for decrypting the private key. If the password is None, decryption is not performed.
Returns:
- RSAPrivateKey: decoded RSA private key
Throws:
- CryptoException: If decoding or decryption fails, or the parameter password is empty, this exception is thrown.
func decodeFromPem(String)
public static func decodeFromPem(text: String): RSAPrivateKey
Description: Decodes a private key from the PEM format.
Parameters:
- text: String: private key character stream in PEM format
Returns:
- RSAPrivateKey: decoded RSA private key
Throws:
- CryptoException: If decoding or decryption fails, the character stream does not comply with the PEM format, or the file header does not comply with the private key header standard, this exception is thrown.
func decodeFromPem(String, ?String)
public static func decodeFromPem(text: String, password!: ?String): RSAPrivateKey
Description: Decodes a private key from the PEM format.
Parameters:
- text: String: private key character stream in PEM format
- password!: ?String: password required for decrypting the private key. If the password is None, decryption is not performed.
Returns:
- RSAPrivateKey: decoded RSA private key
Throws:
- CryptoException: If decoding or decryption fails, the parameter password is empty, the character stream does not comply with the PEM format, or the file header does not comply the private key header standard, this exception is thrown.
func decrypt(InputStream, OutputStream, PadOption)
public func decrypt(input: InputStream, output: OutputStream, padType!: PadOption): Unit
Description: Performs decryption to obtain the original data.
Parameters:
- input: InputStream: encrypted data
- output: OutputStream: data after decryption
- padType!: PadOption: padding mode. The PKCS1 or OAEP mode can be selected. The PSS mode is not supported. The OAEP mode is recommended in scenarios with high security requirements.
Throws:
- CryptoException: When the padding mode fails to be set or the decryption fails, this exception is thrown.
func encodeToDer()
public override func encodeToDer(): DerBlob
Description: Encodes a private key in DER format.
Returns:
- DerBlob: encoded private key in DER format
Throws:
- CryptoException: When encoding fails, this exception is thrown.
func encodeToDer(?String)
public func encodeToDer(password!: ?String): DerBlob
Description: Encrypts a private key using AES-256-CBC and encodes the private key in DER format.
Parameters:
- password!: ?String: password required for encrypting the private key. If the password is None, encryption is not performed.
Returns:
- DerBlob: encoded private key in DER format
Throws:
- CryptoException: If encoding or encryption fails, or the parameter password is empty, this exception is thrown.
func encodeToPem()
public override func encodeToPem(): PemEntry
Description: Encodes a private key in PEM format.
Returns:
- PemEntry: object of the private key in PEM format
Throws:
- CryptoException: When encoding fails, this exception is thrown.
func sign(Digest, Array<Byte>, PadOption)
public func sign(hash: Digest, digest: Array<Byte>, padType!: PadOption): Array<Byte>
Description: Signs the digest result of data.
Parameters:
- hash: Digest: digest method used to obtain the digest result
- digest: Array<Byte>: digest result of the data
- padType!: PadOption: padding mode. The PKCS1 or PSS mode can be selected. The OAEP mode is not supported. The PSS mode is recommended in scenarios with high security requirements.
Returns:
Throws:
- CryptoException: When the digest method or padding mode fails to be set, or signing fails, this exception is thrown.
func toString()
public override func toString(): String
Description: Outputs the private key type.
Returns:
- String: private key type description
class RSAPublicKey
public class RSAPublicKey <: PublicKey {
public init(pri: RSAPrivateKey)
}
Description: Indicates the RSA public key class which provides the capability of generating RSA public keys. RSA public keys support signature authentication and encryption as well as encoding and decoding in PEM and DER formats.
Parent Type:
init(RSAPrivateKey)
public init(pri: RSAPrivateKey)
Description: Initializes a public key with initialization performed, that is, obtains the corresponding public key from a private key.
Parameters:
- pri: RSAPrivateKey: RSA private key
Throws:
- CryptoException: When initialization fails, this exception is thrown.
func decodeDer(DerBlob)
public static func decodeDer(blob: DerBlob): RSAPublicKey
Description: Decodes a public key from the DER format.
Parameters:
- blob: DerBlob: public key object in binary format
Returns:
- RSAPublicKey: decoded RSA public key
Throws:
- CryptoException: When decoding fails, this exception is thrown.
func decodeFromPem(String)
public static func decodeFromPem(text: String): RSAPublicKey
Description: Decodes a public key from the PEM format.
Parameters:
- text: String: public key character stream in PEM format
Returns:
- RSAPublicKey: decoded RSA public key
Throws:
- CryptoException: If decoding fails, the character stream does not comply with the PEM format, or the file header does not comply with the public key header standard, this exception is thrown.
func encodeToDer()
public override func encodeToDer(): DerBlob
Description: Encodes a public key in DER format.
Returns:
- DerBlob: encoded public key in DER format
Throws:
- CryptoException: When encoding fails, this exception is thrown.
func encodeToPem()
public override func encodeToPem(): PemEntry
Description: Encodes a public key in PEM format.
Returns:
Throws:
- CryptoException: When encoding fails, this exception is thrown.
func encrypt(InputStream, OutputStream, PadOption)
public func encrypt(input: InputStream, output: OutputStream, padType!: PadOption): Unit
Description: Encrypts a segment of data.
Parameters:
- input: InputStream: data to be encrypted
- output: OutputStream: data after encryption
- padType!: PadOption: padding mode. The PKCS1 or OAEP mode can be selected. The PSS mode is not supported. The OAEP mode is recommended in scenarios with high security requirements.
Throws:
- CryptoException: When the padding mode fails to be set or the encryption fails, this exception is thrown.
func toString()
public override func toString(): String
Description: Outputs the public key type.
Returns:
- String: private key type description
func verify(Digest, Array<Byte>, Array<Byte>, PadOption)
public func verify(hash: Digest, digest: Array<Byte>, sig: Array<Byte>, padType!: PadOption): Bool
Description: Verifies the signing result.
Parameters:
- hash: Digest: digest method used to obtain the digest result
- digest: Array<Byte>: digest result of the data
- sig: Array<Byte>: signing result of the data
- padType!: PadOption: padding mode. The PKCS1 or PSS mode can be selected. The OAEP mode is not supported. The PSS mode is recommended in scenarios with high security requirements.
Returns:
- Bool: If true is returned, the verification is successful. If false is returned, the verification fails.
Throws:
- CryptoException: When the padding mode fails to be set or the authentication fails, this exception is thrown.
class SM2PrivateKey
public class SM2PrivateKey <: PrivateKey {
public init()
}
Description: Indicates the SM2 private key class which provides the capability of generating SM2 private keys. SM2 private keys support sign and decrypt operations as well as encoding and decoding in PEM and DER formats, complying with the PKCS1 standard.
Parent Type:
init()
public init()
Description: Generates a private key with initialization performed.
Throws:
- CryptoException: When initialization fails, this exception is thrown.
func decodeDer(DerBlob)
public static func decodeDer(blob: DerBlob): SM2PrivateKey
Description: Decodes a private key from the DER format.
Parameters:
- blob: DerBlob: private key object in binary format
Returns:
- SM2PrivateKey: decoded SM2 private key
Throws:
- CryptoException: When decoding fails, this exception is thrown.
func decodeDer(DerBlob, ?String)
public static func decodeDer(blob: DerBlob, password!: ?String): SM2PrivateKey
Description: Decodes an encrypted private key from the DER format.
Parameters:
- blob: DerBlob: private key object in binary format
- password!: ?String: password required for decrypting the private key. If the password is None, decryption is not performed.
Returns:
- SM2PrivateKey: decoded SM2 private key
Throws:
- CryptoException: If decoding or decryption fails, or the parameter password is empty, this exception is thrown.
func decodeFromPem(String)
public static func decodeFromPem(text: String): SM2PrivateKey
Description: Decodes a private key from the PEM format.
Parameters:
- text: String: private key character stream in PEM format
Returns:
- SM2PrivateKey: decoded SM2 private key
Throws:
- CryptoException: If decoding or decryption fails, the character stream does not comply with the PEM format, or the file header does not comply with the private key header standard, this exception is thrown.
func decodeFromPem(String, ?String)
public static func decodeFromPem(text: String, password!: ?String): SM2PrivateKey
Description: Decodes a private key from the PEM format.
Parameters:
- text: String: private key character stream in PEM format
- password!: ?String: password required for decrypting the private key. If the password is None, decryption is not performed.
Returns:
- SM2PrivateKey: decoded SM2 private key
Throws:
- CryptoException: If decoding or decryption fails, the parameter password is empty, the character stream does not comply with the PEM format, or the file header does not comply the private key header standard, this exception is thrown.
func decrypt(Array<Byte>)
public func decrypt(input: Array<Byte>): Array<Byte>
Description: Performs decryption to obtain the original data.
Parameters:
Returns:
Throws:
- CryptoException: When decryption fails, this exception is thrown.
func encodeToDer()
public func encodeToDer(): DerBlob
Description: Encodes a private key in DER format.
Returns:
- DerBlob: encoded private key in DER format
Throws:
- CryptoException: When encoding fails, this exception is thrown.
func encodeToDer(?String)
public func encodeToDer(password!: ?String): DerBlob
Description: Encrypts a private key using AES-256-CBC and encodes the private key in DER format.
Parameters:
- password!: ?String: password required for encrypting the private key. If the password is None, encryption is not performed.
Returns:
- DerBlob: encoded public key in DER format
Throws:
- CryptoException: If encoding or encryption fails, or the parameter password is empty, this exception is thrown.
func encodeToPem(?String)
public func encodeToPem(password!: ?String): PemEntry
Description: Encodes an encrypted private key in PEM format.
Parameters:
- password!: ?String: password required for encrypting the private key. If the password is None, encryption is not performed.
Returns:
- PemEntry: object of the private key in PEM format
Throws:
- CryptoException: If encoding or encryption fails, or the parameter password is empty, this exception is thrown.
func encodeToPem()
public func encodeToPem(): PemEntry
Description: Encodes a private key in PEM format.
Returns:
- PemEntry: object of the private key in PEM format
Throws:
- CryptoException: When encoding fails, this exception is thrown.
func sign(Array<Byte>)
public func sign(data: Array<Byte>): Array<Byte>
Description: Signs data. SM2 uses the SM3 data digest algorithm.
Parameters:
Returns:
Throws:
- CryptoException: When signing fails, this exception is thrown.
func toString
public override func toString(): String
Description: Outputs the private key type.
Returns:
- String: private key type description
class SM2PublicKey
public class SM2PublicKey <: PublicKey {
public init(pri: SM2PrivateKey)
}
Description: Indicates the SM2 public key class which provides the capability of generating SM2 public keys. SM2 public keys support signature authentication and encryption as well as encoding and decoding in PEM and DER formats.
Parent Type:
init(SM2PrivateKey)
public init(pri: SM2PrivateKey)
Description: Initializes a public key with initialization performed, that is, obtains the corresponding public key from a private key.
Parameters:
- pri: SM2PrivateKey: SM2 private key
Throws:
- CryptoException: When initialization fails, this exception is thrown.
func decodeDer(DerBlob)
public static func decodeDer(blob: DerBlob): SM2PublicKey
Description: Decodes a public key from the DER format.
Parameters:
- blob: DerBlob: public key object in binary format
Returns:
- SM2PublicKey: decoded SM2 public key
Throws:
- CryptoException: When decoding fails, this exception is thrown.
func decodeFromPem(String)
public static func decodeFromPem(text: String): SM2PublicKey
Description: Decodes a public key from the PEM format.
Parameters:
- text: String: public key character stream in PEM format
Returns:
- SM2PublicKey: decoded SM2 public key
Throws:
- CryptoException: If decoding fails, the character stream does not comply with the PEM format, or the file header does not comply with the public key header standard, this exception is thrown.
func encodeToDer()
public func encodeToDer(): DerBlob
Description: Encodes a public key in DER format.
Returns:
- DerBlob: encoded public key in DER format
Throws:
- CryptoException: When encoding fails, this exception is thrown.
func encodeToPem()
public func encodeToPem(): PemEntry
Description: Encodes a public key in PEM format.
Returns:
Throws:
- CryptoException: When encoding fails, this exception is thrown.
func encrypt(Array<Byte>)
public func encrypt(input: Array<Byte>): Array<Byte>
Description: Encrypts a segment of data.
Parameters:
Returns:
Throws:
- CryptoException: When encryption fails, this exception is thrown.
func toString()
public override func toString(): String
Description: Outputs the public key type.
Returns:
- String: private key type description
func verify(Array<Byte>, Array<Byte>)
public func verify(data: Array<Byte>, sig: Array<Byte>): Bool
Description: Verifies the signing result.
Parameters:
Returns:
- Bool: If true is returned, the verification is successful. If false is returned, the verification fails.
Throws:
- CryptoException: When the padding mode fails to be set or the authentication fails, this exception is thrown.
Enumeration
enum Curve
public enum Curve {
| P224 | P256 | P384 | P521 | BP256 | BP320 | BP384 | BP512
}
Description: The enumeration type Curve is used to select the elliptic curve type used for generating ECDSA keys.
The elliptic curve is a mathematical curve, and is usually used for key generation in encryption algorithms. In cryptography, the elliptic curve cryptography algorithm is a public key cryptography algorithm based on elliptic curves. Its basic idea is to use the point set on the elliptic curve to form a computational difficulty to implement the security of public key passwords.
The Curve enumeration type supports eight elliptic curves: NIST P-224, NIST P-256, NIST P-384, NIST P-521, Brainpool P-256, Brainpool P-320, Brainpool P-384, and Brainpool P-512.
-
NIST P-224: Indicates an encryption algorithm based on elliptic curves, which uses a 224-bit prime number as a modulus, has relatively high security, and is applicable to lightweight applications.
-
NIST P-256: Indicates an encryption algorithm based on elliptic curves, which uses a 256-bit prime number as a modulus, has relatively high security, and is applicable to medium-level applications.
-
NIST P-384: Indicates an encryption algorithm based on elliptic curves, which uses a 384-bit prime number as a modulus, has very high security, and is applicable to high-level applications.
-
NIST P-521: Indicates an encryption algorithm based on elliptic curves, which uses a 521-bit prime number as a modulus, has very high security, and is applicable to extremely-high-level applications.
-
Brainpool P-256: Indicates an encryption algorithm based on elliptic curves, which uses a 256-bit prime number as a modulus, has relatively high security, and is faster than NIST P-256.
-
Brainpool P-320: Indicates an encryption algorithm based on elliptic curves, which uses a 320-bit prime number as a modulus, has very high security, and is faster than NIST P-384.
-
Brainpool P-384: Indicates an encryption algorithm based on elliptic curves, which uses a 384-bit prime number as a modulus, has very high security, and is faster than NIST P-384.
-
Brainpool P-512: Indicates an encryption algorithm based on elliptic curves, which uses a 512-bit prime number as a modulus, has very high security, and is faster than NIST P-521.
BP256
BP256
Description: Initializes a Curve instance using the Brainpool P-256 elliptic curve.
BP320
BP320
Description: Initializes a Curve instance using the Brainpool P-320 elliptic curve.
BP384
BP384
Description: Initializes a Curve instance using the Brainpool P-384 elliptic curve.
BP512
BP512
Description: Initializes a Curve instance using the Brainpool P-512 elliptic curve.
P224
P224
Description: Initializes a Curve instance using the NIST P-224 elliptic curve.
P256
P256
Description: Initializes a Curve instance using the NIST P-256 elliptic curve.
P384
P384
Description: Initializes a Curve instance using the NIST P-384 elliptic curve.
P521
P521
Description: Initializes a Curve instance using the NIST P-521 elliptic curve.
enum PadOption
public enum PadOption {
| OAEP(OAEPOption) | PSS(PSSOption) | PKCS1
}
Description: Specifies the padding mode of the RSA.
RSA has the following three common padding modes:
OAEP is the optimal asymmetric encryption padding mode and can be used only for encryption and decryption. PSS is a probabilistic signature scheme mode and can be used only for signing and verification. PKCS1 is a common padding mode used to pad the data length. It can be used for encryption, decryption, signing, and verification. The PKCS1 padding mode of the RSA is defined in PKCS #1 v1.5. Currently, attacks on the PKCS1 padding mode are mature, and attackers can easily decrypt or forge signatures. It is advised to use the more secure PSS or OAEP padding mode in PKCS #1 v2.
OAEP(OAEPOption)
OAEP(OAEPOption)
Description: Initializes a PadOption instance using the optimal asymmetric encryption.
PKCS1
PKCS1
Description: Initializes a PadOption instance using the PKCS #1 public key cryptography standard.
PSS(PSSOption)
PSS(PSSOption)
Description: Initializes a PadOption instance using the probabilistic signature scheme.
Struct
struct OAEPOption
public struct OAEPOption {
public init(hash: Digest, mgfHash: Digest, label!: String = "")
}
Description: Indicates the parameters to be set for the OAEP padding mode.
init(Digest, Digest, String)
public init(hash: Digest, mgfHash: Digest, label!: String = "")
Description: Initializes the OAEP padding parameters.
Parameters:
- hash: Digest: digest method, which is used to digest the label
- mgfHash: Digest: digest method, which is used to set the digest method in the MGF1 function
- label!: String: optional parameter used to distinguish different encryption operations, which is an empty string by default
struct PSSOption
public struct PSSOption {
public init(saltLen: Int32)
}
This struct is a parameter that needs to be set in the PSS padding mode.
init(Int32)
public init(saltLen: Int32)
Description: Initializes the PSS padding parameters.
Parameters:
- saltLen: Int32: random salt length (in bytes). The value must be greater than or equal to 0 and less than or equal to (RSA length – Digest length – 2). If the length is too long, signing fails.
Throws:
- CryptoException: If the length of the random salt is less than 0, this exception is thrown.
keys Usage
RSA Key Example
Generating RSA Public and Private Keys, Encrypting Data Using the OAEP Padding Mode of the Public Key, and Decrypting Data Using the OAEP Padding Mode of the Private Key
import crypto.keys.*
import crypto.digest.*
import std.io.*
import std.crypto.digest.*
main() {
var rsaPri = RSAPrivateKey(2048)
var rsaPub = RSAPublicKey(rsaPri)
var str: String = "hello world, hello cangjie"
var bas1 = ByteArrayStream()
var bas2 = ByteArrayStream()
var bas3 = ByteArrayStream()
bas1.write(str.toArray())
var encOpt = OAEPOption(SHA1(), SHA256())
rsaPub.encrypt(bas1, bas2, padType: OAEP(encOpt))
var encOpt2 = OAEPOption(SHA1(), SHA256())
rsaPri.decrypt(bas2, bas3, padType: OAEP(encOpt2))
var buf = Array<Byte>(str.size, item:0)
bas3.read(buf)
if (str.toArray() == buf){
println("success")
} else {
println("fail")
}
}
Running result:
success
Reading the RSA Public and Private Keys from a File, Using the PKCS1 Padding Mode of the Private Key for Signing, and Using the PKCS1 Padding Mode of the Public Key to Verify the Signature Result
Note: >
- The public and private key files need to be prepared in advance.
import crypto.keys.*
import crypto.digest.*
import std.crypto.digest.*
import std.fs.*
main() {
var pemPri = String.fromUtf8(File("./files/rsaPri.pem", OpenOption.Open(true, false)).readToEnd())
var rsaPri = RSAPrivateKey.decodeFromPem(pemPri)
var pemPub = String.fromUtf8(File("./files/rsaPub.pem", OpenOption.Open(true, false)).readToEnd())
var rsaPub = RSAPublicKey.decodeFromPem(pemPub)
var str: String = "helloworld"
var sha512Instance = SHA512()
var md: Array<Byte> = digest(sha512Instance, str)
var sig = rsaPri.sign(sha512Instance, md, padType: PKCS1)
if (rsaPub.verify(sha512Instance, md, sig, padType: PKCS1)){
println("verify successful")
}
}
Running result:
verify successful
ECDSA Key Example
ECDSA Key Usage Example
Generating ECDSA Public and Private Keys, Using the Private Key for Signing, and Using the Public Key to Verify the Signature Result
import crypto.keys.*
import crypto.digest.*
import std.convert.*
import std.crypto.digest.*
main() {
var ecPri = ECDSAPrivateKey(P224)
var ecPub = ECDSAPublicKey(ecPri)
var str: String = "helloworld"
var sha512Instance = SHA512()
var md: Array<Byte> = digest(sha512Instance, str)
var sig = ecPri.sign(md)
println(sig)
if (ecPub.verify(md, sig)){
println("verify successful")
}
}
Running result:
verify successful
SM2 Key Example
Generating SM2 Public and Private Keys, Using the Private Key for Signing, and Using the Public Key to Verify the Signature Result
main(): Unit {
// Generates public and private keys without parameters.
let sm2PrivateKey = SM2PrivateKey()
let sm2PublicKey = SM2PublicKey(sm2PrivateKey)
// Exports the public and private keys.
let priPem = sm2PrivateKey.encodeToPem()
let file1: File = File("./sm2Pri.pem", OpenOption.CreateOrTruncate(true))
file1.write(priPem.encode().toArray())
file1.close()
let pubPem = sm2PublicKey.encodeToPem()
let file2: File = File("./sm2Pub.pem", OpenOption.CreateOrTruncate(true))
file2.write(pubPem.encode().toArray())
file2.close()
// Encrypts data using the public key and decrypts data using the private key.
let str: String = "helloworld"
let encresult = sm2PublicKey.encrypt(str.toArray())
let decresult = sm2PrivateKey.decrypt(encresult)
println(String.fromUtf8(decresult))
// Performs signing using the private key and verifies the signature using the public key.
let strSig: String = "helloworld"
let sigRe = sm2PrivateKey.sign(strSig.toArray())
let verifyre = sm2PublicKey.verify(strSig.toArray(), sigRe)
println(verifyre)
//Imports the private and public keys.
let pemPri = String.fromUtf8(File("./sm2Pri.pem", OpenOption.Open(true, false)).readToEnd())
let sm2PrivateKeyNew = SM2PrivateKey.decodeFromPem(pemPri)
let pemPub = String.fromUtf8(File("./sm2Pub.pem", OpenOption.Open(true, false)).readToEnd())
let sm2PublicKeyNew = SM2PublicKey.decodeFromPem(pemPub)
}
Running result:
helloworld
true
crypto.x509 Package
Function Description
The x509 package provides digital certificate processing functions, including parsing and serializing X509 certificates, verifying certificates, creating self-signed certificates, and creating and verifying certificate chains.
This package depends on the crypto dynamic library file of OpenSSL 3. Therefore, related tools must be installed before using this package.
-
For Linux, perform the following operations:
- Install the OpenSSL 3 development tool package using the package management tool of the system if the tool supports the installation, and ensure that the system installation directory contains the libcrypto.so and libcrypto.so.3 dynamic library files. For example, on Ubuntu 22.04, run the sudo apt install libssl-dev command to install the libssl-dev tool package.
- Download and install the OpenSSL 3.x.x source code compilation software package if the preceding method fails, and ensure that the installation directory contains the libcrypto.so and libcrypto.so.3 dynamic library files. Then, use either of the following methods to ensure that the system linker can find these files:
- Install the software in a system directory if OpenSSL has not been installed.
- Set the directory containing these files to the environment variables LD_LIBRARY_PATH and LIBRARY_PATH if the software is installed in a user-defined directory.
-
For Windows, perform the following operations:
- Download and install the OpenSSL 3.x.x source code compilation software package for the x64 architecture, or download and install the OpenSSL 3.x.x software package precompiled by a third party for developers.
- Ensure that the installation directory contains the libcrypto.dll.a (or libcrypto.lib) and libcrypto-3-x64.dll library files.
- Set the directory containing the libcrypto.dll.a (or libcrypto.lib) to the environment variable LIBRARY_PATH, and the directory containing libcrypto-3-x64.dll to the environment variable PATH.
-
For macOS, perform the following operations:
- Run the brew install openssl@3 command to install OpenSSL, and ensure that the system installation directory contains the libcrypto.dylib and libcrypto.3.dylib dynamic library files.
- Download and install the OpenSSL 3.x.x source code compilation software package if the preceding method fails, and ensure that the installation directory contains the libcrypto.dylib and libcrypto.3.dylib dynamic library files. Then, use either of the following methods to ensure that the system linker can find these files:
- Install the software in a system directory if OpenSSL has not been installed.
- Set the directory containing these files to the environment variables DYLD_LIBRARY_PATH and LIBRARY_PATH.
Note:
If OpenSSL 3 is not installed or an earlier version is installed, the program may fail to work with the following exception thrown: X509Exception: Can not load openssl library or function xxx.
API List
Type Alias
| Type Alias | Description |
|---|---|
| IP | x509 uses Array<Byte> to record IP addresses. |
Interface
| Name | Description |
|---|---|
| DHParamters | Provides DH key interfaces. |
| Key | Provides key interfaces. |
| PrivateKey | Provides private key interfaces. |
| PublicKey | Provides public key interfaces. |
Class
| Name | Description |
|---|---|
| X509Certificate | The X509 digital certificate is a digital certificate used for encrypted communication. |
| X509CertificateRequest | Specifies a digital certificate signature request. |
| X509Name | Specifies a recognizable name of the certificate entity. |
Enumeration
| Name | Description |
|---|---|
| PublicKeyAlgorithm | Specifies public key information contained in a digital certificate. |
| SignatureAlgorithm | Specifies the certificate signature algorithm. |
Struct
| Name | Description |
|---|---|
| DerBlob | Binary certificate streams can be configured for Crypto. |
| ExtKeyUsage | Specifies the digital certificate extension field. |
| KeyUsage | The digital certificate extension field usually contains the usage description of the public key carried. |
| Pem | Specifies a Pem struct. |
| PemEntry | Specifies the PEM text format. |
| SerialNumber | Specifies the serial number of the digital certificate. |
| Signature | Specifies the signature of the digital certificate. |
| VerifyOption | Specifies a verification option. |
| X509CertificateInfo | Specifies certificate information. |
| X509CertificateRequestInfo | Specifies certificate request information. |
Exception Class
| Name | Description |
|---|---|
| X509Exception | Specifies the exception class of the x509 package. |
Type Alias
type IP
public type IP = Array<Byte>
Description: The x509 package uses Array<Byte> to record IP addresses.
Interface
interface DHParamters
public interface DHParamters <: Key {
override func encodeToPem(): PemEntry
static func decodeDer(blob: DerBlob): DHParamters
static func decodeFromPem(text: String): DHParamters
}
Description: Provides the DH parameter interfaces.
Parent Type:
static func decodeDer(DerBlob)
static func decodeDer(blob: DerBlob): DHParamters
Description: Decodes a DH key parameter from the DER format.
Note:
- The Diffie-Hellman (DH) key exchange protocol ensures that a shared key securely traverses insecure networks.
- DER and PEM are two common encoding formats.
Parameters:
- blob: DerBlob: DH key parameter object in DER format
Returns:
- DHParamters: DH key parameter decoded from the DER format
Throws:
- X509Exception: When the DH key parameter in DER format is incorrect and cannot be parsed, this exception is thrown.
static func decodeFromPem(String)
static func decodeFromPem(text: String): DHParamters
Description: Decodes a DH key parameter from the PEM format.
Note:
PEM certificates are encoded using ASCLL (BASE64).
Parameters:
- text: String: DH key parameter character stream in PEM format
Returns:
- DHParamters: DH key parameter decoded from the PEM format
Throws:
- X509Exception: When the character stream does not comply with the PEM format or the file header does not comply with the DH key parameter header standard "-----BEGIN DH PARAMETERS-----", this exception is thrown.
func encodeToPem()
override func encodeToPem(): PemEntry
Description: Encodes a DH key parameter into the PEM format.
Returns:
- PemEntry: DH key parameter object generated in PEM format
interface Key
public interface Key <: ToString {
func encodeToDer(): DerBlob
func encodeToPem(): PemEntry
static func decodeDer(encoded: DerBlob): Key
static func decodeFromPem(text: String): Key
}
Description: Provides the key interfaces. The public key is used for signature verification or encryption, and the private key is used for signature or decryption. The public key and private key must match and be paired. This interface does not have specific implementation, and is provided for PrivateKey, PublicKey, and users to extend interfaces.
Parent Type:
static func decodeDer(DerBlob)
static func decodeDer(encoded: DerBlob): Key
Description: Decodes a key from the DER format.
Parameters:
- encoded: DerBlob: object in DER format
Returns:
- Key: key decoded from the DER format
Throws:
- X509Exception: When the private key content in DER format is incorrect and cannot be parsed, this exception is thrown.
static func decodeFromPem(String)
static func decodeFromPem(text: String): Key
Description: Decodes a key from the PEM format.
Parameters:
- text: String: character stream in PEM format
Returns:
- Key: key decoded from the PEM format
func encodeToDer()
func encodeToDer(): DerBlob
Description: Encodes a key into the DER format.
Returns:
- DerBlob: key data object generated in DER format
func encodeToPem()
func encodeToPem(): PemEntry
Description: Encodes a key into the PEM format.
Returns:
- PemEntry: key data object generated in PEM format
interface PrivateKey
public interface PrivateKey <: Key {
static func decodeDer(blob: DerBlob): PrivateKey
static func decodeFromPem(text: String): PrivateKey
static func decodeDer(blob: DerBlob, password!: ?String): PrivateKey
static func decodeFromPem(text: String, password!: ?String): PrivateKey
func encodeToDer(password!: ?String): DerBlob
override func encodeToPem(): PemEntry
func encodeToPem(password!: ?String): PemEntry
}
Description: Provides the private key interfaces.
Parent Type:
static func decodeDer(DerBlob)
static func decodeDer(blob: DerBlob): PrivateKey
Description: Decodes a private key from the DER format.
Parameters:
- blob: DerBlob: private key object in DER format
Returns:
- PrivateKey: private key decoded from the DER format
Throws:
- X509Exception: When the private key content in DER format is incorrect and cannot be parsed, this exception is thrown.
static func decodeDer(DerBlob, ?String)
static func decodeDer(blob: DerBlob, password!: ?String): PrivateKey
Description: Decrypts and decodes a private key in DER format into a PrivateKey object. If the password is None, decryption is not performed.
Parameters:
Returns:
- PrivateKey: private key object after decryption and decoding
Throws:
- X509Exception: When decryption or decoding fails or the
passwordis empty, this exception is thrown.
static func decodeFromPem(String)
static func decodeFromPem(text: String): PrivateKey
Description: Decodes a private key from the PEM format.
Parameters:
- text: String: private key character stream in PEM format
Returns:
- PrivateKey: private key decoded from the PEM format
Throws:
- X509Exception: When the character stream does not comply with the PEM format or the file header does not comply with the public key header standard, this exception is thrown.
static func decodeFromPem(String, ?String)
static func decodeFromPem(text: String, password!: ?String): PrivateKey
Description: Decrypts and decodes a private key in PEM format into a PrivateKey object. If the password is None, decryption is not performed.
Parameters:
Returns:
- PrivateKey: private key object after decryption and decoding
Throws:
- X509Exception: When decryption or decoding fails or the
passwordis empty, this exception is thrown.
func encodeToDer(?String)
func encodeToDer(password!: ?String): DerBlob
Description: Encrypts and encodes a private key into the DER format. If the password is None, encryption is not performed.
Parameters:
- password!: ?String: encryption password
Returns:
- DerBlob: encrypted private key in DER format
Throws:
- X509Exception: When encryption fails or the
passwordis empty, this exception is thrown.
func encodeToPem()
override func encodeToPem(): PemEntry
Description: Encodes a private key into the PEM format.
Returns:
- PemEntry: encoded private key in PEM format
Throws:
- X509Exception: When encoding fails, this exception is thrown.
func encodeToPem(?String)
func encodeToPem(password!: ?String): PemEntry
Description: Encrypts and encodes a private key into the PEM format. If the password is None, encryption is not performed.
Parameters:
- password!: ?String: encryption password
Returns:
- PemEntry: encrypted private key in PEM format
Throws:
- X509Exception: When encryption fails or the
passwordis empty, this exception is thrown.
interface PublicKey
public interface PublicKey <: Key {
override func encodeToPem(): PemEntry
static func decodeDer(blob: DerBlob): PublicKey
static func decodeFromPem(text: String): PublicKey
}
Description: Indicates the public key interface.
Parent Type:
static func decodeDer(DerBlob)
static func decodeDer(blob: DerBlob): PublicKey
Description: Decodes a public key from the DER format.
Parameters:
- blob: DerBlob: public key object in DER format
Returns:
- PublicKey: public key decoded from DER format
Throws:
- X509Exception: When the public key content in DER format is incorrect and cannot be parsed, this exception is thrown.
static func decodeFromPem(String)
static func decodeFromPem(text: String): PublicKey
Description: Decodes a public key from the PEM format.
Parameters:
- text: String: public key character stream in PEM format
Returns:
- PublicKey: public key decoded from the PEM format
Throws:
- X509Exception: When the character stream does not comply with the PEM format or the file header does not comply with the public key header standard, this exception is thrown.
func encodeToPem()
override func encodeToPem(): PemEntry
Description: Encodes a public key into the PEM format.
Returns:
- PemEntry: public key data object generated in PEM format
x509 Package
class X509Certificate
public class X509Certificate <: Equatable<X509Certificate> & Hashable & ToString {
public init(
certificateInfo: X509CertificateInfo,
parent!: X509Certificate,
publicKey!: PublicKey,
privateKey!: PrivateKey,
signatureAlgorithm!: ?SignatureAlgorithm = None
)
public func encodeToDer(): DerBlob
public func encodeToPem(): PemEntry
public static func decodeFromDer(der: DerBlob): X509Certificate
public static func decodeFromPem(pem: String): Array<X509Certificate>
public static func systemRootCerts(): Array<X509Certificate>
public prop serialNumber: SerialNumber
public prop signatureAlgorithm: SignatureAlgorithm
public prop signature: Signature
public prop issuer: X509Name
public prop subject: X509Name
public prop notBefore: DateTime
public prop notAfter: DateTime
public prop publicKeyAlgorithm: PublicKeyAlgorithm
public prop publicKey: PublicKey
public prop dnsNames: Array<String>
public prop emailAddresses: Array<String>
public prop IPAddresses: Array<IP>
public prop keyUsage: KeyUsage
public prop extKeyUsage: ExtKeyUsage
public func verify(verifyOption: VerifyOption): Bool
public override func toString(): String
public override operator func ==(other: X509Certificate): Bool
public override operator func !=(other: X509Certificate): Bool
public override func hashCode(): Int64
}
Description: The x509 digital certificate is a digital certificate used for encrypted communication. It is one of the core components of the public key infrastructure (PKI). An x509 digital certificate contains the public key and identity information of an entity. It is used to verify the identity of the entity and ensure communication security.
Parent Type:
prop dnsNames
public prop dnsNames: Array<String>
Description: Parses the domain name in the alternative name of a digital certificate.
prop emailAddresses
public prop emailAddresses: Array<String>
Description: Parses the email address in the alternative name of a digital certificate.
prop extKeyUsage
public prop extKeyUsage: ExtKeyUsage
Description: Parses the usage of the extended key in a digital certificate.
Type: ExtKeyUsage
prop issuer
public prop issuer: X509Name
Description: Parses the issuer information in a digital certificate.
Type: X509Name
prop IPAddresses
public prop IPAddresses: Array<IP>
Description: Parses the IP address in the alternative name of a digital certificate.
prop keyUsage
public prop keyUsage: KeyUsage
Description: Parses the usage of a key in a digital certificate.
Type: KeyUsage
prop notAfter
public prop notAfter: DateTime
Description: Parses the expiration time of a digital certificate.
Type: DateTime
prop notBefore
public prop notBefore: DateTime
Description: Parses the effective time of a digital certificate.
Type: DateTime
prop publicKey
public prop publicKey: PublicKey
Description: Parses the public key of a digital certificate.
Type: PublicKey
prop publicKeyAlgorithm
public prop publicKeyAlgorithm: PublicKeyAlgorithm
Description: Parses the public key algorithm of a digital certificate.
Type: PublicKeyAlgorithm
prop serialNumber
public prop serialNumber: SerialNumber
Description: Parses the sequence number of a digital certificate.
Type: SerialNumber
prop signature
public prop signature: Signature
Description: Parses the signature of a digital certificate.
Type: Signature
prop signatureAlgorithm
public prop signatureAlgorithm: SignatureAlgorithm
Description: Parses the signature algorithm of a digital certificate.
Type: SignatureAlgorithm
prop subject
public prop subject: X509Name
Description: Parses the user information in a digital certificate.
Type: X509Name
init(X509CertificateInfo, X509Certificate, PublicKey, PrivateKey, ?SignatureAlgorithm)
public init(
certificateInfo: X509CertificateInfo,
parent!: X509Certificate,
publicKey!: PublicKey,
privateKey!: PrivateKey,
signatureAlgorithm!: ?SignatureAlgorithm = None
)
Description: Creates a digital certificate object.
Parameters:
- certificateInfo: X509CertificateInfo: digital certificate configuration information
- parent!: X509Certificate: issuer certificate
- publicKey!: PublicKey: applicant public key. Only public keys of RSA, ECDSA, and DSA are supported.
- privateKey!: PrivateKey: issuer private key. Only private keys of RSA, ECDSA, and DSA are supported.
- signatureAlgorithm!: ?SignatureAlgorithm: certificate signature algorithm; default value: None. When the default value is used, the default digest type is SHA256.
Throws:
- X509Exception](./x509_package_exceptions.md#class-x509exception): When the public or private key type is not supported, the private key type does not match the private key type in the certificate signature algorithm, or the digital certificate information fails to be set, this exception is thrown.
static func decodeFromDer(DerBlob)
public static func decodeFromDer(der: DerBlob): X509Certificate
Description: Decodes a digital certificate in DER format.
Parameters:
- der: DerBlob: binary data in DER format
Returns:
- X509Certificate: digital certificate decoded from the DER format
Throws:
- X509Exception: When the data is empty or the data is not in valid digital certificate DER format, this exception is thrown.
static func decodeFromPem(String)
public static func decodeFromPem(pem: String): Array<X509Certificate>
Description: Decodes a digital certificate from the PEM format.
Parameters:
- pem: String: digital certificate character stream in PEM format
Returns:
- Array<X509Certificate>: digital certificate array decoded from the PEM format
Throws:
- X509Exception: When the character stream does not comply with the PEM format or the file header does not comply with the digital certificate header standard, this exception is thrown.
func encodeToDer()
public func encodeToDer(): DerBlob
Description: Encodes a digital certificate into the DER format.
Returns:
- DerBlob: encoded digital certificate in DER format
func encodeToPem()
public func encodeToPem(): PemEntry
Description: Encodes a digital certificate into the PEM format.
Returns:
- PemEntry: encoded digital certificate in PEM format
func hashCode()
public override func hashCode(): Int64
Description: Returns the hash value of a certificate.
Returns:
- Int64: result obtained after hash calculation is performed on a certificate object
static func systemRootCerts()
public static func systemRootCerts(): Array<X509Certificate>
Description: Returns the root certificate of the operating system. Linux, MacOS, and Windows are supported.
Returns:
- Array<X509Certificate>: root certificate chain of the operating system
func toString()
public override func toString(): String
Description: Generates a certificate name string, which contains the user, validity period, and issuer information of the certificate.
Returns:
- String: certificate name string
func verify(VerifyOption)
public func verify(verifyOption: VerifyOption): Bool
Description: Verifies the validity of the current certificate according to the verification option.
Verification priority:
- Preferentially verify the validity period.
- (Optional) Verify the DNS domain name.
- Verifies the validity of the certificate according to the root and intermediate certificates.
Parameters:
- verifyOption: VerifyOption: certificate verification option
Returns:
- Bool: If the certificate is valid, true is returned. Otherwise, false is returned.
Throws:
- X509Exception: When the verification fails, for example, an internal error such as memory allocation exception, this exception is thrown.
operator func !=(X509Certificate)
public override operator func !=(other: X509Certificate): Bool
Description: Checks whether two certificates are different.
Parameters:
- other: X509Certificate: certificate to be compared
Returns:
- Bool: If the certificates are different, true is returned. Otherwise, false is returned.
operator func ==(X509Certificate)
public override operator func ==(other: X509Certificate): Bool
Description: Checks whether two certificates are the same.
Parameters:
- other: X509Certificate: certificate to be compared
Returns:
- Bool: If the certificates are the same, true is returned. Otherwise, false is returned.
class X509CertificateRequest
public class X509CertificateRequest <: Hashable & ToString {
public init(
privateKey: PrivateKey,
certificateRequestInfo!: ?X509CertificateRequestInfo = None,
signatureAlgorithm!: ?SignatureAlgorithm = None
)
public func encodeToDer(): DerBlob
public func encodeToPem(): PemEntry
public static func decodeFromDer(der: DerBlob): X509CertificateRequest
public static func decodeFromPem(pem: String): Array<X509CertificateRequest>
public prop signatureAlgorithm: SignatureAlgorithm
public prop signature: Signature
public prop publicKeyAlgorithm: PublicKeyAlgorithm
public prop publicKey: PublicKey
public prop subject: X509Name
public prop dnsNames: Array<String>
public prop emailAddresses: Array<String>
public prop IPAddresses: Array<IP>
public override func toString(): String
public override func hashCode(): Int64
}
Description: Indicates the digital certificate signature request.
Parent Type:
prop IPAddresses
public prop IPAddresses: Array<IP>
Description: Parses the IP address in the alternative name of a digital certificate signature request.
prop dnsNames
public prop dnsNames: Array<String>
Description: Parses the domain name in the alternative name of a digital certificate signature request.
prop emailAddresses
public prop emailAddresses: Array<String>
Description: Parses the email address in the alternative name of a digital certificate signature request.
prop publicKey
public prop publicKey: PublicKey
Description: Parses the public key in a digital certificate signature request.
Type: PublicKey
prop publicKeyAlgorithm
public prop publicKeyAlgorithm: PublicKeyAlgorithm
Description: Parses the public key algorithm in a digital certificate signature request.
Type: PublicKeyAlgorithm
prop signature
public prop signature: Signature
Description: Parses the signature in a digital certificate signature request.
Type: Signature
prop signatureAlgorithm
public prop signatureAlgorithm: SignatureAlgorithm
Description: Parses the signature algorithm in a digital certificate signature request.
Type: SignatureAlgorithm
prop subject
public prop subject: X509Name
Description: Parses the user information in a digital certificate signature request.
Type: X509Name
init(PrivateKey, ?X509CertificateRequestInfo, ?SignatureAlgorithm)
public init(
privateKey: PrivateKey,
certificateRequestInfo!: ?X509CertificateRequestInfo = None,
signatureAlgorithm!: ?SignatureAlgorithm = None
)
Description: Creates a digital certificate signature request object.
Parameters:
- privateKey!: PrivateKey: private key. Only private keys of RSA, ECDSA, and DSA are supported.
- certificateRequestInfo!: ?X509CertificateRequestInfo: digital certificate signature; default value: None
- signatureAlgorithm!: ?SignatureAlgorithm: certificate signature algorithm; default value: None. When the default value is used, the default digest type is SHA256.
Throws:
- X509Exception: When the private key type is not supported, the private key type does not match the private key type in the certificate signature algorithm, or the digital certificate signature information fails to be set, this exception is thrown.
static func decodeFromDer(DerBlob)
public static func decodeFromDer(der: DerBlob): X509CertificateRequest
Description: Decodes a digital certificate signature request in DER format.
Parameters:
- der: DerBlob: binary data in DER format
Returns:
- X509CertificateRequest: digital certificate signature request decoded from the DER format
Throws:
- X509Exception: When the data is empty or the data is not in valid digital certificate signature request DER format, this exception is thrown.
static func decodeFromPem(String)
public static func decodeFromPem(pem: String): Array<X509CertificateRequest>
Description: Decodes a digital certificate signature request from the PEM format.
Parameters:
- pem: String: digital certificate signature request character stream in PEM format
Returns:
- Array<X509CertificateRequest>: digital certificate signature request array decoded from the PEM format
Throws:
- X509Exception: When the character stream does not comply with the PEM format or the file header does not comply with the digital certificate signature request header standard, this exception is thrown.
func encodeToDer()
public func encodeToDer(): DerBlob
Description: Encodes a digital certificate signature request into the DER format.
Returns:
- DerBlob: encoded digital certificate signature request in DER format
func encodeToPem()
public func encodeToPem(): PemEntry
Description: Encodes a digital certificate signature request into the PEM format.
Returns:
- PemEntry: encoded digital certificate signature request in PEM format
func hashCode()
public override func hashCode(): Int64
Description: Returns the hash value of a certificate signature request.
Returns:
- Int64: result obtained after hash calculation is performed on a certificate signature request object
func toString()
public override func toString(): String
Description: Generates a certificate signature request name string, which contains the user information of the certificate signature request.
Returns:
- String: certificate signature request name string
class X509Name
public class X509Name <: ToString {
public init(
countryName!: ?String = None,
provinceName!: ?String = None,
localityName!: ?String = None,
organizationName!: ?String = None,
organizationalUnitName!: ?String = None,
commonName!: ?String = None,
email!: ?String = None
)
public prop countryName: ?String
public prop provinceName: ?String
public prop localityName: ?String
public prop organizationName: ?String
public prop organizationalUnitName: ?String
public prop commonName: ?String
public prop email: ?String
public override func toString(): String
}
Description: The recognizable name (Distinguished Name) of a certificate entity is an important part of a digital certificate. It ensures the authenticity and credibility of the identity of the certificate holder and is an important basis for digital certificate verification.
X509Name contains the country or region name (Country Name), state or province name (State or Province Name), city name (Locality Name), organization name (Organization Name), organization unit name (Organizational Unit Name), and common name (Common Name) of a certificate entity. Sometimes, an email address is also included.
Parent Type:
prop commonName
public prop commonName: ?String
Description: Returns the common name of a certificate entity.
Type: ?String
prop countryName
public prop countryName: ?String
Description: Returns the country or region name of a certificate entity.
Type: ?String
prop email
public prop email: ?String
Description: Returns the email address of a certificate entity.
Type: ?String
prop localityName
public prop localityName: ?String
Description: Returns the city name of a certificate entity.
Type: ?String
prop organizationName
public prop organizationName: ?String
Description: Returns the organization name of a certificate entity.
Type: ?String
prop organizationalUnitName
public prop organizationalUnitName: ?String
Description: Returns the organization unit name of a certificate entity.
Type: ?String
prop provinceName
public prop provinceName: ?String
Description: Returns the state or province name of a certificate entity.
Type: ?String
init(?String, ?String, ?String, ?String, ?String, ?String, ?String)
public init(
countryName!: ?String = None,
provinceName!: ?String = None,
localityName!: ?String = None,
organizationName!: ?String = None,
organizationalUnitName!: ?String = None,
commonName!: ?String = None,
email!: ?String = None
)
Description: Constructs an X509Name object.
Parameters:
- countryName!: ?String: country or region name; default value: None
- provinceName!: ?String: state or province name; default value: None
- localityName!: ?String: city name; default value: None
- organizationName!: ?String: organization name; default value: None
- organizationalUnitName!: ?String: organization unit name; default value: None
- commonName!: ?String: common name; default value: None
- email!: ?String: email address; default value: None
Throws:
- X509Exception: When the recognizable name of the certificate entity fails to be set, for example, an internal error such as memory allocation exception, this exception is thrown.
func toString()
public override func toString(): String
Description: Generates a certificate entity name string.
Returns:
- String: certificate entity name string. It contains information of the fields in the entity name.
Enumeration
enum PublicKeyAlgorithm
public enum PublicKeyAlgorithm <: Equatable<PublicKeyAlgorithm> & ToString {
RSA | DSA | ECDSA | UnknownPublicKeyAlgorithm
}
Description: Indicates the public key type information contained in a digital certificate. Currently, RSA, DSA, and ECDSA are supported.
Parent Type:
DSA
DSA
Description: Indicates the DSA public key algorithm.
ECDSA
ECDSA
Description: Indicates the ECDSA public key algorithm.
RSA
RSA
Description: Indicates the RSA public key algorithm.
UnknownPublicKeyAlgorithm
UnknownPublicKeyAlgorithm
Description: Indicates an unknown public key algorithm.
func toString()
public override func toString(): String
Description: Generates the public key algorithm name string carried in a certificate.
Returns:
- String: public key algorithm name string carried in the certificate
operator func !=(PublicKeyAlgorithm)
public override operator func !=(other: PublicKeyAlgorithm): Bool
Description: Checks whether two public key algorithms are different.
Parameters:
- other: PublicKeyAlgorithm: public key algorithm to be compared
Returns:
- Bool: If the public key algorithms are different, true is returned. Otherwise, false is returned.
operator func ==(PublicKeyAlgorithm)
public override operator func ==(other: PublicKeyAlgorithm): Bool
Description: Checks whether two public key algorithms are the same.
Parameters:
- other: PublicKeyAlgorithm: public key algorithm to be compared
Returns:
- Bool: If the public key algorithms are the same, true is returned. Otherwise, false is returned.
enum SignatureAlgorithm
public enum SignatureAlgorithm <: Equatable<SignatureAlgorithm> & ToString {
| MD2WithRSA | MD5WithRSA | SHA1WithRSA | SHA256WithRSA | SHA384WithRSA
| SHA512WithRSA | DSAWithSHA1 | DSAWithSHA256 | ECDSAWithSHA1 | ECDSAWithSHA256
| ECDSAWithSHA384 | ECDSAWithSHA512 | UnknownSignatureAlgorithm
}
Description: A certificate signature algorithm (Signature Algorithm) is used to sign digital certificates. It encrypts the public key and other information in a digital certificate to guarantee the integrity and authenticity of the digital certificate.
Currently, the following signature algorithms are supported: MD2WithRSA, MD5WithRSA, SHA1WithRSA, SHA256WithRSA, SHA384WithRSA, SHA512WithRSA, DSAWithSHA1, DSAWithSHA256, ECDSAWithSHA1, ECDSAWithSHA256, ECDSAWithSHA384, and ECDSAWithSHA512.
Parent Type:
DSAWithSHA1
DSAWithSHA1
Description: Indicates the DSAwithSHA1 signature algorithm.
DSAWithSHA256
DSAWithSHA256
Description: Indicates the DSAwithSHA256 signature algorithm.
ECDSAWithSHA1
ECDSAWithSHA1
Description: Indicates the ECDSAwithSHA1 signature algorithm.
ECDSAWithSHA256
ECDSAWithSHA256
Description: Indicates the ECDSAwithSHA256 signature algorithm.
ECDSAWithSHA384
ECDSAWithSHA384
Description: Indicates the ECDSAwithSHA384 signature algorithm.
ECDSAWithSHA512
ECDSAWithSHA512
Description: Indicates the ECDSAwithSHA512 signature algorithm.
MD2WithRSA
MD2WithRSA
Description: Indicates the MD2withRSA signature algorithm.
MD5WithRSA
MD5WithRSA
Description: Indicates the MD5withRSA signature algorithm.
SHA1WithRSA
SHA1WithRSA
Description: Indicates the SHA1withRSA signature algorithm.
SHA256WithRSA
SHA256WithRSA
Description: Indicates the SHA256withRSA signature algorithm.
SHA384WithRSA
SHA384WithRSA
Description: Indicates the SHA384withRSA signature algorithm.
SHA512WithRSA
SHA512WithRSA
Description: Indicates the SHA512withRSA signature algorithm.
UnknownSignatureAlgorithm
UnknownSignatureAlgorithm
Description: Indicates an unknown signature algorithm.
func toString()
public override func toString(): String
Description: Generates a certificate signature algorithm name string.
Returns:
- String: certificate signature algorithm name string
operator func !=
public override operator func !=(other: SignatureAlgorithm): Bool
Description: Checks whether two signature algorithms are different.
Parameters:
- other: SignatureAlgorithm: signature algorithm to be compared
Returns:
- Bool: If the signature algorithms are different, true is returned. Otherwise, false is returned.
operator func ==
public override operator func ==(other: SignatureAlgorithm): Bool
Description: Checks whether two signature algorithms are the same.
Parameters:
- other: SignatureAlgorithm: signature algorithm to be compared
Returns:
- Bool: If the signature algorithms are the same, true is returned. Otherwise, false is returned.
Struct
struct DerBlob
public struct DerBlob <: Equatable<DerBlob> & Hashable {
public init(content: Array<Byte>)
}
Description: Crypto supports the configuration of binary certificate streams. After a user reads binary certificate data and creates a DerBlob object, the object can be parsed into one X509Certificate, X509CertificateRequest, PublicKey, or PrivateKey object.
Parent Type:
prop body
public prop body: Array<Byte>
Description: Obtains the character sequence in the DerBlob object.
prop size
public prop size: Int64
Description: Obtains the size of the character sequence in a DerBlob object.
Type: Int64
init(Array)
public init(content: Array<Byte>)
Description: Constructs a DerBlob object.
Parameters:
func hashCode()
public override func hashCode(): Int64
Description: Returns the hash value of a DerBlob object.
Returns:
operator func !=(DerBlob)
public override operator func !=(other: DerBlob): Bool
Description: Checks whether two DerBlob objects are different.
Parameters:
Returns:
- Bool: If the objects are different, true is returned. Otherwise, false is returned.
operator func ==(DerBlob)
public override operator func ==(other: DerBlob): Bool
Description: Checks whether two DerBlob objects are the same.
Parameters:
Returns:
- Bool: If the objects are the same, true is returned. Otherwise, false is returned.
struct ExtKeyUsage
public struct ExtKeyUsage <: ToString {
public static let AnyKey = 0u16
public static let ServerAuth = 1u16
public static let ClientAuth = 2u16
public static let EmailProtection = 3u16
public static let CodeSigning = 4u16
public static let OCSPSigning = 5u16
public static let TimeStamping = 6u16
public init(keys: Array<UInt16>)
public override func toString(): String
}
Description: A digital certificate extension field usually contains the usage description of the extended key carried. Currently, ServerAuth, ClientAuth, EmailProtection, CodeSigning, OCSPSigning, and TimeStamping.are supported
Parent Type:
static let AnyKey
public static let AnyKey = 0u16
Description: Indicates that a key can be used for any purpose.
Type: UInt16
static let ClientAuth
public static let ClientAuth = 2u16
Description: Indicates that a key is used for SSL client authentication.
Type: UInt16
static let CodeSigning
public static let CodeSigning = 4u16
Description: Indicates that a key is used for code signing
Type: UInt16
static let EmailProtection
public static let EmailProtection = 3u16
Function: used for email encryption, decryption, and signature.
Type: UInt16
static let OCSPSigning
public static let OCSPSigning = 5u16
Description: Indicates that a key is used for OCSP response packet signing.
Type: UInt16
static let ServerAuth
public static let ServerAuth = 1u16
Description: Indicates that a key is used for SSL server authentication.
Type: UInt16
static let TimeStamping
public static let TimeStamping = 6u16
Description: Indicates that a key is used for binding an object digest value to a time.
Type: UInt16
init(Array<UInt16>)
public init(keys: Array<UInt16>)
Description: Constructs extended key usage for a specified purpose. Note that a key can be used for multiple purposes.
Parameters:
func toString()
public override func toString(): String
Description: Generates an extended key usage string.
Returns:
- String: extended key usage string of the certificate
struct KeyUsage
public struct KeyUsage <: ToString {
public static let DigitalSignature = 0x0080u16
public static let NonRepudiation = 0x0040u16
public static let KeyEncipherment = 0x0020u16
public static let DataEncipherment = 0x0010u16
public static let KeyAgreement = 0x0008u16
public static let CertSign = 0x0004u16
public static let CRLSign = 0x0002u16
public static let EncipherOnly = 0x0001u16
public static let DecipherOnly = 0x0100u16
public init(keys: UInt16)
public override func toString(): String
}
Description: A digital certificate extension field usually contains the usage description of the public key carried. Currently, DigitalSignature, NonRepudiation, KeyEncipherment, DataEncipherment, KeyAgreement, CertSign, CRLSign, EncipherOnly, and DecipherOnly are supported.
Parent Type:
static let CRLSign
public static let CRLSign = 0x0002u16
Description: Indicates that the private key can be used to sign a CRL and the public key can be used to verify the CRL signature.
Type: UInt16
static let CertSign
public static let CertSign = 0x0004u16
Description: Indicates that the private key is used to sign a certificate, and the public key is used to verify the certificate signature. This constant is specific to CA certificates.
Type: UInt16
static let DataEncipherment
public static let DataEncipherment = 0x0010u16
Description: Indicates that a public key is used to directly encrypt data.
Type: UInt16
static let DecipherOnly
public static let DecipherOnly = 0x0100u16
Description: Indicates that the public key in a certificate is used only for decryption calculation during key negotiation. This constant is meaningful only when used together with the key Agreement.
Type: UInt16
static let DigitalSignature
public static let DigitalSignature = 0x0080u16
Description: Indicates that the private key can be used for various digital signature operations except issuing certificates, issuing CRLs, and non-repudiation services, and the public key is used to verify the signatures.
Type: UInt16
static let EncipherOnly
public static let EncipherOnly = 0x0001u16
Description: Indicates that the public key in a certificate is used only for encryption calculation during key negotiation. This constant is meaningful only when used together with the key Agreement.
Type: UInt16
static let KeyAgreement
public static let KeyAgreement = 0x0008u16
Description: Indicates that a key is used for key negotiation.
Type: UInt16
static let KeyEncipherment
public static let KeyEncipherment = 0x0020u16
Description: Indicates that a key is used to encrypt other keys.
Type: UInt16
static let NonRepudiation
public static let NonRepudiation = 0x0040u16
Description: Indicates that the private key can be used for signature in non-repudiation services, and the public key is used for signature verification.
Type: UInt16
init(UInt16)
public init(keys: UInt16)
Description: Constructs the usage of an extended key for a specified purpose. Note that a key can be used for multiple purposes.
Parameters:
- keys: UInt16: key usage. It is advised to use the key usage variables provided in this structure to transfer parameters in the bitwise OR mode.
func toString()
public override func toString(): String
Description: Generates a key usage string.
Returns:
- String: certificate key usage string
struct Pem
public struct Pem <: Collection<PemEntry> & ToString {
public Pem(private let items: Array<PemEntry>)
}
Description: The Pem struct is an entry sequence that can contain more than one PemEntry.
Parent Type:
prop size
public override prop size: Int64
Description: Obtains the number of entry sequences.
Type: Int64
Pem(Array<PemEntry>)
public Pem(private let items: Array<PemEntry>)
Description: Constructs a Pem object.
Parameters:
static func decode(String)
public static func decode(text: String): Pem
Description: Decodes PEM text into an entry sequence.
Parameters:
- text: String: PEM string
Returns:
- Pem: PEM entry sequence
func encode()
public func encode(): String
Description: Returns a string in PEM format. The line ending character is generated according to the current operating system.
Returns:
- String: string in PEM format
func isEmpty()
public override func isEmpty(): Bool
Description: Checks whether the entry sequence decoded from the PEM text is empty.
Returns:
- Bool: When the entry sequence decoded from the PEM text is empty, true is returned. Otherwise, false is returned.
func iterator()
public override func iterator(): Iterator<PemEntry>
Description: Generates the iterator of the entry sequence decoded from the PEM text.
Returns:
func toString()
public override func toString(): String
Description: Returns a string which contains the label of each entry sequence.
Returns:
- String: string containing the label of each entry sequence
struct PemEntry
public struct PemEntry <: ToString {
public PemEntry(
public let label: String,
public let headers: Array<(String, String)>,
public let body: ?DerBlob
)
public init(label: String, body: DerBlob)
}
Description: The PEM text format is often used to store certificates and keys. In the PEM encoding structure:
The first line is a UTF-8-encoded string consisting of "-----BEGIN", the label, and "-----". The middle part is the body, which is a printable string encoded using Base64 from binary content. For details about PEM encoding specifications, see RFC 7468. The last line is a UTF-8-encoded string consisting of -----END, the label, and -----. For details, see RFC 1421. In the old PEM encoding standard, an entry header is included between the first line and the body.
To support different user scenarios, the PemEntry and Pem types are provided. PemEntry is used to store a single PEM infrastructure.
Parent Type:
static let LABEL_CERTIFICATE
public static let LABEL_CERTIFICATE = "CERTIFICATE"
Description: Records the entry type as certificate.
Type: String
static let LABEL_CERTIFICATE_REQUEST
public static let LABEL_CERTIFICATE_REQUEST = "CERTIFICATE REQUEST"
Description: Records the entry type as certificate signature request.
Type: String
static let LABEL_DH_PARAMETERS
public static let LABEL_DH_PARAMETERS = "DH PARAMETERS"
Description: Records the entry type as DH key parameter.
Type: String
static let LABEL_EC_PARAMETERS
public static let LABEL_EC_PARAMETERS = "EC PARAMETERS"
Description: Records the entry type as elliptic curve parameter.
Type: String
static let LABEL_EC_PRIVATE_KEY
public static let LABEL_EC_PRIVATE_KEY = "EC PRIVATE KEY"
Description: Records the entry type as elliptic curve private key.
Type: String
static let LABEL_ENCRYPTED_PRIVATE_KEY
public static let LABEL_ENCRYPTED_PRIVATE_KEY = "ENCRYPTED PRIVATE KEY"
Description: Records the entry type as private key encrypted according to the PKCS #8 standard.
Type: String
static let LABEL_PRIVATE_KEY
public static let LABEL_PRIVATE_KEY = "PRIVATE KEY"
Description: Records the entry type as private key not encrypted according to the PKCS #8 standard.
Type: String
static let LABEL_PUBLIC_KEY
public static let LABEL_PUBLIC_KEY = "PUBLIC KEY"
Description: Records the entry type as public key.
Type: String
static let LABEL_RSA_PRIVATE_KEY
public static let LABEL_RSA_PRIVATE_KEY = "RSA PRIVATE KEY"
Description: Records the entry type as RSA private key.
Type: String
static let LABEL_SM2_PRIVATE_KEY
public static let LABEL_SM2_PRIVATE_KEY = "SM2 PRIVATE KEY"
Description: Records the entry type as SM2 private key.
Type: String
static let LABEL_X509_CRL
public static let LABEL_X509_CRL = "X509 CRL"
Description: Records the entry type as certificate revocation list.
Type: String
PemEntry(String, Array<(String, String)>, ?DerBlob)
public PemEntry(
public let label: String,
public let headers: Array<(String, String)>,
public let body: ?DerBlob
)
Description: Constructs a PemEntry object.
Parameters:
body
public let body: ?DerBlob
Description: Obtains the binary content of a PemEntry instance.
Type: ?DerBlob
headers
public let headers: Array<(String, String)>
Description: Obtains the entry header of a PemEntry instance.
label
public let label: String
Description: Obtains the label of a PemEntry instance.
Type: String
init(String, DerBlob)
public init(label: String, body: DerBlob)
Description: Constructs a PemEntry object.
Parameters:
func encode()
public func encode(): String
Description: Returns a string in PEM format. The line ending character is generated according to the current operating system.
Returns:
- String: string in PEM format
func header(String)
public func header(name: String): Iterator<String>
Description: Finds the corresponding entry content by entry header name.
Parameters:
- name: String: entry header name
Returns:
func toString()
public override func toString(): String
Description: Returns the length of the label and binary content of the PEM object.
Returns:
- String: length of the label and binary content of the PEM object
struct SerialNumber
public struct SerialNumber <: Equatable<SerialNumber> & Hashable & ToString {
public init(length!: UInt8 = 16)
}
Description: The SerialNumber struct is the sequence number of a digital certificate. A sequence number is the unique identifier of a digital certificate. According to the specifications, the length of a certificate sequence number cannot exceed 20 bytes. For details, see rfc5280.
Parent Type:
init(UInt8)
public init(length!: UInt8 = 16)
Description: Generates a random sequence number of a specified length.
Parameters:
Throws:
- X509Exception: When the value of length is 0 or greater than 20, this exception is thrown.
func hashCode()
public override func hashCode(): Int64
Description: Returns the hash value of a certificate sequence number.
Returns:
- Int64: result obtained after hash calculation is performed on a certificate sequence number object
func toString()
public override func toString(): String
Description: Generates a certificate sequence number string in hexadecimal format.
Returns:
- String: certificate sequence number string
operator func !=(SerialNumber)
public override operator func !=(other: SerialNumber): Bool
Description: Checks whether two certificate sequence numbers are different.
Parameters:
- other: SerialNumber: certificate sequence number to be compared
Returns:
- Bool: If the certificate sequence numbers are different, true is returned. Otherwise, false is returned.
operator func ==(SerialNumber)
public override operator func ==(other: SerialNumber): Bool
Description: Checks whether two certificate sequence numbers are the same.
Parameters:
- other: SerialNumber: certificate sequence number to be compared
Returns:
- Bool: If the certificate sequence numbers are the same, true is returned. Otherwise, false is returned.
struct Signature
public struct Signature <: Equatable<Signature> & Hashable {
}
Description: Indicates the signature of a digital certificate used to verify the identity.
Parent Type:
prop signatureValue
public prop signatureValue: DerBlob
Description: Returns a certificate signature in the binary format.
Type: DerBlob
func hashCode()
public override func hashCode(): Int64
Description: Returns the hash value of a certificate signature.
Returns:
- Int64: result obtained after hash calculation is performed on a certificate signature object
operator func !=(Signature)
public override operator func !=(other: Signature): Bool
Description: Checks whether two certificate signatures are different.
Parameters:
- other: Signature: certificate signature to be compared
Returns:
- Bool: If the certificate signatures are different, true is returned. Otherwise, false is returned.
operator func ==(Signature)
public override operator func ==(other: Signature): Bool
Description: Checks whether two certificate signatures are the same.
Parameters:
- other: Signature: certificate signature to be compared
Returns:
- Bool: If the certificate signatures are the same, true is returned. Otherwise, false is returned.
struct VerifyOption
public struct VerifyOption {
public var time: DateTime = DateTime.now()
public var dnsName: String = ""
public var roots: Array<X509Certificate> = X509Certificate.systemRootCerts()
public var intermediates: Array<X509Certificate> = Array<X509Certificate>()
}
dnsName
public var dnsName: String = ""
Description: Verifies the domain name. The domain name is empty by default. The verification is performed only when a domain name is set.
Type: String
intermediates
public var intermediates: Array<X509Certificate> = Array<X509Certificate>()
Description: Obtains and sets an intermediate certificate chain which is empty by default.
Type: Array<X509Certificate>
roots
public var roots: Array<X509Certificate> = X509Certificate.systemRootCerts()
Description: Obtains and sets a root certificate chain. The system root certificate chain is used by default.
Type: Array<X509Certificate>
time
public var time: DateTime = DateTime.now()
Description: Obtains and sets the verification time. The time when the option is created is used by default.
Type: DateTime
struct X509CertificateInfo
public struct X509CertificateInfo {
public var serialNumber: SerialNumber
public var notBefore: DateTime
public var notAfter: DateTime
public var subject: ?X509Name
public var dnsNames: Array<String>
public var emailAddresses: Array<String>
public var IPAddresses: Array<IP>
public var keyUsage: ?KeyUsage
public var extKeyUsage: ?ExtKeyUsage
public init(
serialNumber!: ?SerialNumber = None,
notBefore!: ?DateTime = None,
notAfter!: ?DateTime = None,
subject!: ?X509Name = None,
dnsNames!: Array<String> = Array<String>(),
emailAddresses!: Array<String> = Array<String>(),
IPAddresses!: Array<IP> = Array<IP>(),
keyUsage!: ?KeyUsage = None,
extKeyUsage!: ?ExtKeyUsage = None
)
}
Description: The X509CertificateInfo struct contains certificate information, including the certificate sequence number, validity period, recognizable name of the entity, domain name, email address, IP address, key usage, and extended key usage.
IPAddresses
public var IPAddresses: Array<IP>
Description: Records the IP address of a certificate.
dnsNames
public var dnsNames: Array<String>
Description: Records the DNS domain name of a certificate.
emailAddresses
public var emailAddresses: Array<String>
Description: Records the email address of a certificate.
extKeyUsage
public var extKeyUsage: ?ExtKeyUsage
Description: Records the extended key usage of a certificate.
Type: ?ExtKeyUsage
keyUsage
public var keyUsage: ?KeyUsage
Description: Records the key usage of a certificate.
Type: ?KeyUsage
notAfter
public var notAfter: DateTime
Description: Records the expiration date of a certificate.
Type: DateTime
notBefore
public var notBefore: DateTime
Description: Records the effective date of a certificate.
Type: DateTime
serialNumber
public var serialNumber: SerialNumber
Description: Records the sequence number of a certificate.
Type: SerialNumber
subject
public var subject: ?X509Name
Description: Records the recognizable name of a certificate entity.
Type: ?X509Name
init(?SerialNumber, ?DateTime, ?DateTime, ?X509Name, Array<String>, Array<String>, Array<IP>, ?KeyUsage, ?ExtKeyUsage)
public init(
serialNumber!: ?SerialNumber = None,
notBefore!: ?DateTime = None,
notAfter!: ?DateTime = None,
subject!: ?X509Name = None,
dnsNames!: Array<String> = Array<String>(),
emailAddresses!: Array<String> = Array<String>(),
IPAddresses!: Array<IP> = Array<IP>(),
keyUsage!: ?KeyUsage = None,
extKeyUsage!: ?ExtKeyUsage = None
)
Description: Constructs an X509CertificateInfo object.
Parameters:
- serialNumber!: ?SerialNumber: digital certificate sequence number; default value: None. When this parameter is used but not set, the default sequence number length is 128 bits.
- notBefore!: ?DateTime: effective time of the digital certificate; default value: None. When this field is used but not set, the default effective time is the time when X509CertificateInfo is created.
- notAfter!: ?DateTime: expiration time of the digital certificate; default value: None. When this field is used but not set, the default expiration time is one year later than notBefore.
- subject!: ?X509Name: user information of the digital certificate; default value: None
- dnsNames!: Array<String>: domain name list; default value: empty string array. The domain name entered must be valid.
- emailAddresses!: Array<String>: email address list; default value: empty string array. The email address entered must be valid.
- IPAddresses!: Array<IP>: IP address list; default value: empty IP array
- keyUsage!: ?KeyUsage: key usage; default value: None
- extKeyUsage!: ?ExtKeyUsage: the extended key usage; default value: None
Throws:
- X509Exception: When the entered IP address list contains an invalid IP address, this exception is thrown.
struct X509CertificateRequestInfo
public struct X509CertificateRequestInfo {
public var subject: ?X509Name
public var dnsNames: Array<String>
public var emailAddresses: Array<String>
public var IPAddresses: Array<IP>
public init(
subject!: ?X509Name = None,
dnsNames!: Array<String> = Array<String>(),
emailAddresses!: Array<String> = Array<String>(),
IPAddresses!: Array<IP> = Array<IP>()
)
}
The X509CertificateRequestInfo struct contains certificate request information, including recognizable the name of the certificate entity, domain name, email address, and IP address.
IPAddresses
public var IPAddresses: Array<IP>
Description: Records the IP address of a certificate signature request.
dnsNames
public var dnsNames: Array<String>
Description: Records the DNS domain name of a certificate signature request.
emailAddresses
public var emailAddresses: Array<String>
Description: Records the email address of a certificate signature request.
subject
public var subject: ?X509Name
Description: Records the recognizable name of the entity in a certificate signature request.
init(?X509Name, Array<String>, Array<String>, Array<IP>)
public init(
subject!: ?X509Name = None,
dnsNames!: Array<String> = Array<String>(),
emailAddresses!: Array<String> = Array<String>(),
IPAddresses!: Array<IP> = Array<IP>()
)
Description: Constructs an X509CertificateRequestInfo object.
Parameters:
- subject!: ?X509Name: user information of the digital certificate; default value: None
- dnsNames!: Array<String>: domain name list; default value: empty string array. The domain name entered must be valid.
- emailAddresses!: Array<String>: email address list;default value: empty string array. The email address entered must be valid.
- IPAddresses!: Array<IP>: IP address list; default value: empty IP array
Throws:
- X509Exception: When the entered IP address list contains an invalid IP address, this exception is thrown.
Exception Class
class X509Exception
public class X509Exception <: Exception {
public init()
public init(message: String)
}
Description: Specifies an exception thrown by the x509 package.
Parent Type:
init()
public init()
Description: Constructs an X509Exception object.
init(String)
public init(message: String)
Description: Constructs an X509Exception object.
Parameters:
- message: String: exception information
x509 Usage
Reading and Parsing Certificates
Note:
The certificate file needs to be prepared in advance.
import std.fs.File
import crypto.x509.*
let readPath = "./files/root_rsa.cer"
main() {
// Reads the local certificate.
let pem = String.fromUtf8(File.readFrom(readPath))
let certificates = X509Certificate.decodeFromPem(pem)
// Parses mandatory fields in the certificate.
let cert = certificates[0]
println(cert)
println("Serial Number: ${cert.serialNumber}")
println("Issuer: ${cert.issuer}")
println("NotBefore: ${cert.notBefore}")
println("NotAfter: ${cert.notAfter}")
println(cert.signatureAlgorithm)
let signature = cert.signature
println(signature.hashCode())
println(cert.publicKeyAlgorithm)
let pubKey = cert.publicKey
println(pubKey.encodeToPem().encode())
// Parses extension fields in the certificate.
println("DNSNames: ${cert.dnsNames}")
println("EmailAddresses: ${cert.emailAddresses}")
println("IPAddresses: ${cert.IPAddresses}")
println("KeyUsage: ${cert.keyUsage}")
println("ExtKeyUsage: ${cert.extKeyUsage}")
//Parses the recognizable name of the certificate user.
println("Subject: ${cert.subject}")
return 0
}
Reading and Verifying Certificates
Note:
The certificate file needs to be prepared in advance.
import std.fs.File
import crypto.x509.*
import std.time.DateTime
let prefixPath = "./files/"
let certFile = "servers.crt"
let rootFile = "roots.crt"
let middleFile = "middles.crt"
func getX509Cert(path: String)
{
let pem = String.fromUtf8(File.readFrom(path))
X509Certificate.decodeFromPem(pem)
}
func testVerifyByTime(cert: X509Certificate, roots: Array<X509Certificate>, middles: Array<X509Certificate>)
{
var opt = VerifyOption()
opt.roots = roots
opt.intermediates = middles
cert.verify(opt)
println("Verify result: ${cert.verify(opt)}")
opt.time = DateTime.of(year: 2023, month: 7, dayOfMonth: 1)
println("Verify result:: ${cert.verify(opt)}")
}
func testVerifyByDNS(cert: X509Certificate)
{
var opt = VerifyOption()
opt.dnsName = "www.example.com"
println("cert DNS names: ${cert.dnsNames}")
let res = cert.verify(opt)
println("Verify result: ${res}")
}
/**
* The relation of certs.
* root[0] root[1]
* / \ |
* mid[0] mid[1] mid[2]
* | |
* server[0] server[1]
*/
func testVerify(cert: X509Certificate, roots: Array<X509Certificate>, middles: Array<X509Certificate>)
{
var opt = VerifyOption()
opt.roots = roots
opt.intermediates = middles
let res = cert.verify(opt)
println("Verify result: ${res}")
}
main() {
// 2 server certs
let certs = getX509Cert(prefixPath + certFile)
// 2 root certs
let roots = getX509Cert(prefixPath + rootFile)
// 3 middle certs
let middles = getX509Cert(prefixPath + middleFile)
// Verify by time: true, false
testVerifyByTime(certs[0], [roots[0]], [middles[0]])
// Verify by dns: false
testVerifyByDNS(certs[0])
// cert0 <- root0: false
testVerify(certs[0], [roots[0]], [])
// cert0 <- middle0 <- root0: true
testVerify(certs[0], [roots[0]], [middles[0]])
// cert0 <- (middle0, middle1, middle2) <- (root0, root1) : true
testVerify(certs[0], roots, middles)
// cert1 <- middle0 <- root0: false
testVerify(certs[1], [roots[0]], [middles[0]])
// cert1 <- middle2 <- root1: true
testVerify(certs[1], [roots[1]], [middles[2]])
// cert1 <- (middle0, middle1, middle2) <- (root0, root1) : true
testVerify(certs[1], roots, middles)
return 0
}
Creating and Parsing Certificates
Note:
The root certificate file needs to be prepared in advance.
import std.fs.*
import crypto.x509.*
import std.time.*
main(){
let x509Name = X509Name(
countryName: "CN",
provinceName: "beijing",
localityName: "haidian",
organizationName: "organization",
organizationalUnitName: "organization unit",
commonName: "x509",
email: "test@email.com"
)
let serialNumber = SerialNumber(length: 20)
let startTime: DateTime = DateTime.now()
let endTime: DateTime = startTime.addYears(1)
let ip1: IP = Array<Byte>([8, 8, 8, 8])
let ip2: IP = Array<Byte>([0, 1, 0, 1, 0, 1, 0, 1, 0, 8, 0, 8, 0, 8, 0, 8])
let parentCertPem = String.fromUtf8(File("./certificate.pem", OpenOption.Open(true, false)).readToEnd())
let parentCert = X509Certificate.decodeFromPem(parentCertPem)[0]
let parentKeyPem = String.fromUtf8(File("./rsa_private_key.pem", OpenOption.Open(true, false)).readToEnd())
let parentPrivateKey = PrivateKey.decodeFromPem(parentKeyPem)
let usrKeyPem = String.fromUtf8(File("./ecdsa_public_key.pem", OpenOption.Open(true, false)).readToEnd())
let usrPublicKey = PublicKey.decodeFromPem(usrKeyPem)
let certInfo = X509CertificateInfo(serialNumber: serialNumber, notBefore: startTime, notAfter: endTime, subject: x509Name, dnsNames: Array<String>(["b.com"]), IPAddresses: Array<IP>([ip1, ip2]));
let cert = X509Certificate(certInfo, parent: parentCert, publicKey: usrPublicKey, privateKey: parentPrivateKey)
println(cert)
println("Serial Number: ${cert.serialNumber}")
println("Issuer: ${cert.issuer}")
println("Subject: ${cert.subject}")
println("NotBefore: ${cert.notBefore}")
println("NotAfter: ${cert.notAfter}")
println(cert.signatureAlgorithm)
println("DNSNames: ${cert.dnsNames}")
println("IPAddresses: ${cert.IPAddresses}")
return 0
}
Creating and Parsing Certificate Signature Requests
Note:
Files such as the private key need to be prepared in advance.
import std.fs.*
import crypto.x509.*
main(){
let x509Name = X509Name(
countryName: "CN",
provinceName: "beijing",
localityName: "haidian",
organizationName: "organization",
organizationalUnitName: "organization unit",
commonName: "x509",
email: "test@email.com"
)
let ip1:IP = Array<Byte>([8, 8, 8, 8])
let ip2:IP = Array<Byte>([0, 1, 0, 1, 0, 1, 0, 1, 0, 8, 0, 8, 0, 8, 0, 8])
let rsaPem = String.fromUtf8(File("./rsa_private_key.pem", OpenOption.Open(true, false)).readToEnd())
let rsa = PrivateKey.decodeFromPem(rsaPem)
let csrInfo = X509CertificateRequestInfo(subject: x509Name, dnsNames: Array<String>(["b.com"]), IPAddresses: Array<IP>([ip1, ip2]));
let csr = X509CertificateRequest(rsa, certificateRequestInfo:csrInfo, signatureAlgorithm: SHA256WithRSA)
println("Subject: ${csr.subject.toString()}")
println("IPAddresses: ${csr.IPAddresses}")
println("dnsNames: ${csr.dnsNames}")
return 0
}
encoding Module
Note:
The encoding module cannot be imported through import encoding. Otherwise, the error message "error: can not find package'encoding'" is displayed during compilation. You are advised to import the encoding subpackage to use the encoding module.
encoding Function Description
The encoding module provides character encoding and decoding capabilities.
It can encode and decode data in Base64, Hex, JSON, and URL formats.
Package List of the encoding Module
The encoding module provides the following packages:
| Name | Description |
|---|---|
| base64 | The base package provides Base64 encoding and decoding for strings. |
| hex | The hex package provides Hex encoding and decoding for strings. |
| json | The json package is used to process json data and implement conversion among String, JsonValue, and DataModel. |
| json.stream | The json.stream package is used for conversion between Cangjie objects and JSON data streams. |
| url | The url package provides URL-related capabilities, including parsing URL components, encoding and decoding URLs, and combining URLs or paths. |
encoding.base64 Package
Function Description
The base package provides Base64 encoding and decoding for strings.
Base64 encoding can convert binary data into a text consisting of only 64 printable characters (A to Z, a to z, 0 to 9, +, and /), enabling secure transmission and storage of binary data in a text environment.
API List
Function
| Name | Description |
|---|---|
| fromBase64String(String) | Decodes a Base64-encoded string. |
| toBase64String(Array<Byte>) | Converts a character array into a Base64-encoded string. |
Function
func fromBase64String(String)
public func fromBase64String(data: String): Option<Array<Byte>>
Description: Decodes Base64-encoded strings.
Parameters:
- data: String: Base64-encoded string to be decoded
Returns:
- Option<Array<Byte>>: If an empty string is entered, Option<Array<Byte>>.Some(Array<Byte>()) is returned. If decoding fails, Option<Array<Byte>>.None is returned.
func toBase64String(Array<Byte>)
public func toBase64String(data: Array<Byte>): String
Description: Converts a Byte array into a Base64-encoded string.
Parameters:
Returns:
- String: string after encoding
Conversion Between Byte Arrays and Base64
import encoding.base64.*
main(): Int64 {
var arr = Array<Byte>([77, 97, 110])
var str = toBase64String(arr)
print("${str},")
var opArr: Option<Array<Byte>> = fromBase64String(str)
var arr2: Array<Byte> = match (opArr) {
case Some(s) => s
case None => Array<Byte>()
}
for (i in 0..arr2.size) {
print("${arr2[i]},")
}
return 0
}
Running result:
TWFu,77,97,110,
encoding.hex Package
Function Description
The hex package provides Hex encoding and decoding for strings.
Hex encoding (also referred to as hexadecimal encoding) converts data into a hexadecimal representation. Hex encoding uses 16 characters to represent data. The 16 characters are digits from 0 to 9 and letters from A to F (case-insensitive, that is, a to f is equivalent to A to F).
API List
Function
| Name | Description |
|---|---|
| fromHexString(String) | Decodes a Hex-encoded string. |
| toHexString(Array<Byte>) | Converts a character array into a Hex-encoded string. |
Function
func fromHexString(String)
public func fromHexString(data: String): Option<Array<Byte>>
Description: Decodes Hex-encoded strings.
Parameters:
- data: String: Hex-encoded string to be decoded
Returns:
- Option<Array<Byte>>: If an empty string is entered, Option<Array<Byte>>.Some(Array<Byte>()) is returned. If decoding fails, Option<Array<Byte>>.None is returned.
func toHexString(Array<Byte>)
public func toHexString(data: Array<Byte>): String
Description: Converts a Byte array into a Hex-encoded string.
Parameters:
Returns:
- String: string after encoding
Conversion Between Byte Arrays and Hex
import encoding.hex.*
main(): Int64 {
var arr = Array<Byte>([65, 66, 94, 97])
var str = toHexString(arr)
print("${str},")
var opArr: Option<Array<Byte>> = fromHexString(str)
var arr2: Array<Byte> = match (opArr) {
case Some(s) => s
case None => Array<Byte>()
}
for (i in 0..arr2.size) {
print("${arr2[i]},")
}
return 0
}
Running result:
41425e61,65,66,94,97,
encoding.json Package
Function Description
The json package is used to process JSON data and implement conversion among String, JsonValue, and DataModel.
JsonValue is the encapsulation of the JSON data format, including object, array, string, number, true, false, and null.
For details about the DataModel, see serialization Package Document.
For details about the JSON syntax rules, see Introduction to JSON.
For details about the JSON data conversion standards, see ECMA-404 The JSON Data Interchange Standard.
API List
Interface
| Name | Description |
|---|---|
| ToJson | Implements conversion between JsonValue and DataModel. |
Class
| Name | Description |
|---|---|
| JsonArray | Creates an empty JsonArray. |
| JsonBool | Encapsulates a specified Bool instance into a JsonBool instance. |
| JsonFloat | Encapsulates a specified Float64 instance into a JsonFloat instance. |
| JsonInt | Encapsulates a specified Int64 instance into a JsonInt instance. |
| JsonNull | Converts a JsonNull instance into a string. |
| JsonObject | Creates an empty JsonObject instance. |
| JsonString | Encapsulates a specified String instance into a JsonString instance. |
| JsonValue | Specifies the JSON data layer and converts data between JsonValue and String. |
Enumeration
| Name | Description |
|---|---|
| JsonKind | Indicates a type of JsonValue. |
Exception Class
| Name | Description |
|---|---|
| JsonException | Used in the scenario where an exception occurs when the JsonValue type is used. |
Interface
interface ToJson
public interface ToJson {
static func fromJson(jv: JsonValue): DataModel
func toJson(): JsonValue
}
Description: Implements conversion between JsonValue and DataModel.
static func fromJson(JsonValue)
static func fromJson(jv: JsonValue): DataModel
Description: Converts JsonValue to the object DataModel.
Parameters:
Returns:
func toJson()
func toJson(): JsonValue
Description: Performs self-conversion to JsonValue.
Returns:
Throws:
- JsonException: If the conversion fails, this exception is thrown.
extend DataModel <: ToJson
extend DataModel <: ToJson
Description: Implements the ToJson interface for the DataModel type.
Parent Type:
static func fromJson(JsonValue)
public static func fromJson(jv: JsonValue): DataModel
Description: Converts JsonValue to the object DataModel.
Parameters:
Returns:
func toJson()
public func toJson(): JsonValue
Description: Performs self-conversion to JsonValue.
Returns:
Throws:
- JsonException: If the conversion fails, this exception is thrown.
Class
class JsonArray
public class JsonArray <: JsonValue {
public init()
public init(list: ArrayList<JsonValue>)
public init(list: Array<JsonValue>)
}
Description: Specifies an implementation subclass of JsonValue used to encapsulate JSON data of the array type.
Parent Type:
Example:
For details, see JsonArray Usage Example.
init()
public init()
Description: Creates an empty JsonArray.
init(ArrayList<JsonValue>)
public init(list: ArrayList<JsonValue>)
Description: Encapsulates a specified ArrayList instance into a JsonArray instance.
Parameters:
init(Array<JsonValue>)
public init(list: Array<JsonValue>)
Description: Encapsulates a specified Array instance into a JsonArray instance.
Parameters:
func add(JsonValue)
public func add(jv: JsonValue): JsonArray
Description: Adds JsonValue data to JsonArray.
Parameters:
Returns:
func get(Int64)
public func get(index: Int64): Option<JsonValue>
Description: Obtains JsonValue corresponding to the specified index in JsonArray and encapsulates it using Option<JsonValue>.
Parameters:
- index: Int64: specified index
Returns:
func getItems()
public func getItems(): ArrayList<JsonValue>
Description: Obtains the items data in JsonArray.
Returns:
func kind()
public func kind(): JsonKind
Description: Returns the JsonKind type (JsArray) of the current JsonArray instance.
Returns:
func size()
public func size(): Int64
Description: Obtains the JsonValue quantity in JsonArray.
Returns:
func toJsonString()
public func toJsonString(): String
Description: Converts JsonArray to a JSON string (with spaces and newline characters).
Returns:
- String: JSON string after conversion
func toJsonString(Int64, Bool, String)
public func toJsonString(depth: Int64, bracketInNewLine!: Bool = false, indent!: String = " "): String
Description: Converts JsonArray to a JSON string. This function specifies the initial indentation depth, indentation string, and whether to wrap a line after the first parenthesis.
Parameters:
- depth: Int64: specified indentation depth
- bracketInNewLine!: Bool: whether to wrap a line after the first parenthesis. If the value of this parameter is
true, a new line is started after the first parenthesis and is indented according to the specified depth. - indent!: String: specified indentation string; default value: two spaces. Only spaces and tab characters are allowed for the indentation string.
Returns:
- String: JSON string after conversion
Throws:
- IllegalArgumentException: If depth is negative or indent contains characters other than ' ' and '\t', this exception is thrown.
func toString()
public func toString(): String
Description: Converts JsonString to a string.
Returns:
- String: string after conversion
operator func [](Int64)
public operator func [](index: Int64): JsonValue
Description: Obtains JsonValue corresponding to the specified index in JsonArray.
Parameters:
- index: Int64: specified index
Returns:
Throws:
- JsonException: If index is not a valid index of JsonArray, this exception is thrown.
class JsonBool
public class JsonBool <: JsonValue {
public init(bv: Bool)
}
Description: Specifies an implementation subclass of JsonValue used to encapsulate JSON data of the Boolean type.
Parent Type:
init(Bool)
public init(bv: Bool)
Description: Encapsulates a specified Bool instance into a JsonBool instance.
func getValue()
public func getValue(): Bool
Description: Obtains the actual value of a JsonBool instance.
Returns:
- Bool: actual value of the instance
func kind()
public func kind(): JsonKind
Description: Returns the JsonKind type (JsBool) of the current JsonBool instance.
Returns:
func toJsonString()
public func toJsonString(): String
Description: Converts JsonBool to a JSON string (with spaces and newline characters).
Returns:
- String: JSON string after conversion
func toString()
public func toString(): String
Description: Converts JsonBool to a string.
Returns:
- String: string after conversion
class JsonFloat
public class JsonFloat <: JsonValue {
public init(fv: Float64)
public init(v: Int64)
}
Description: Specifies an implementation subclass of JsonValue used to encapsulate JSON data of the floating-point type.
Parent Type:
init(Float)
public init(fv: Float64)
Description: Encapsulates a specified Float64 instance into a JsonFloat instance.
Parameters:
init(Int64)
public init(v: Int64)
Description: Encapsulates a specified Int64 instance into a JsonFloat instance.
Parameters:
func getValue()
public func getValue(): Float64
Description: Obtains the actual value of a JsonFloat instance.
Returns:
- Float64: actual value of the instance
func kind()
public func kind(): JsonKind
Description: Returns the JsonKind type (JsFloat) of the current JsonFloat instance.
Returns:
func toJsonString()
public func toJsonString(): String
Description: Converts JsonFloat to a JSON string (with spaces and newline characters).
Returns:
- String: JSON string after conversion
func toString()
public func toString(): String
Description: Converts JsonFloat to a string.
Returns:
- String: string after conversion
class JsonInt
public class JsonInt <: JsonValue {
public init(iv: Int64)
}
Description: Specifies an implementation subclass of JsonValue used to encapsulate JSON data of the integer type.
Parent Type:
init(Int64)
public init(iv: Int64)
Description: Encapsulates a specified Int64 instance into a JsonInt instance.
Parameters:
func getValue()
public func getValue(): Int64
Description: Obtains the actual value of a JsonInt instance.
Returns:
- Int64: actual value of the instance
func kind()
public func kind(): JsonKind
Description: Returns the JsonKind type (JsInt) of the current JsonInt instance.
Returns:
func toJsonString()
public func toJsonString(): String
Description: Converts JsonInt to a JSON string (with spaces and newline characters).
Returns:
- String: JSON string after conversion
func toString()
public func toString(): String
Description: Converts JsonInt to a string.
Returns:
- String: string after conversion
class JsonNull
public class JsonNull <: JsonValue
Description: Specifies an implementation subclass of JsonValue used to encapsulate JSON data of null.
Parent Type:
func kind()
public func kind(): JsonKind
Description: Returns the JsonKind type (JsNull) of the current JsonNull instance.
Returns:
func toJsonString()
public func toJsonString(): String
Description: Converts JsonNull to a JSON string (with spaces and newline characters).
Returns:
- String: JSON string after conversion
func toString()
public func toString(): String
Description: Converts JsonNull to a string.
Returns:
- String: string after conversion
class JsonObject
public class JsonObject <: JsonValue {
public init()
public init(map: HashMap<String, JsonValue>)
}
Description: Specifies an implementation subclass of JsonValue used to encapsulate JSON data of the object type.
Parent Type:
init()
public init()
Description: Creates an empty JsonObject instance.
init()
public init(map: HashMap<String, JsonValue>)
Description: Encapsulates a specified HashMap instance into a JsonObject instance.
func containsKey(String)
public func containsKey(key: String): Bool
Description: Checks whether key exists in JsonObject.
Parameters:
- key: String: specified key
Returns:
- Bool: If the key exists, true is returned. Otherwise, false is returned.
func get(String)
public func get(key: String): Option<JsonValue>
Description: Obtains JsonValue corresponding to key in JsonObject and encapsulates it using Option<JsonValue>.
Parameters:
- key: String: specified key
Returns:
func getFields()
public func getFields(): HashMap<String, JsonValue>
Description: Obtains the fields data in JsonObject.
Returns:
- HashMap < String, JsonValue >: fields data of the JsonObject
func kind()
public func kind(): JsonKind
Description: Returns the JsonKind type (JsObject) of the current JsonObject instance.
Returns:
- JsonKind: JsonKind type (JsObject) of the current JsonObject instance
func put(String, JsonValue)
public func put(key: String, v: JsonValue): Unit
Description: Adds JsonValue data corresponding to key to JsonObject.
Parameters:
func size()
public func size(): Int64
Description: Obtains the number of fields stored in string-JsonValue in JsonObject.
Returns:
- Int64: size of fields in JsonObject
func toJsonString()
public func toJsonString(): String
Description: Converts JsonObject to a JSON string (with spaces and newline characters).
Returns:
- String: JSON string after conversion
func toJsonString(Int64, Bool, String)
public func toJsonString(depth: Int64, bracketInNewLine!: Bool = false, indent!: String = " "): String
Description: Converts JsonObject to a JSON string. This function specifies the initial indentation depth, indentation string, and whether to wrap a line after the first parenthesis.
Parameters:
- depth: Int64: indentation depth
- bracketInNewLine!: Bool: whether to wrap a line after the first parenthesis. If the value of this parameter is
true, a new line is started after the first parenthesis and is indented according to the specified depth. - indent!: String: specified indentation string; default value: two spaces. Only spaces and tab characters are allowed for the indentation string.
Returns:
- String: JSON string after conversion
Throws:
- IllegalArgumentException: If depth is negative or indent contains characters other than ' ' and '\t', this exception is thrown.
func toString()
public func toString(): String
Description: Converts JsonObject to a string.
Returns:
- String: string after conversion
operator func [](String)
public operator func [](key: String): JsonValue
Description: Obtains JsonValue corresponding to key in JsonObject.
Parameters:
- key: String: specified key
Returns:
Throws:
- JsonException: If key is not a valid key of JsonObject, this exception is thrown.
class JsonString
public class JsonString <: JsonValue {
public init(sv: String)
}
Description: Specifies an implementation subclass of JsonValue used to encapsulate JSON data of the string type.
Parent Type:
init(String)
public init(sv: String)
Description: Encapsulates a specified String instance into a JsonString instance.
func getValue()
public func getValue(): String
Description: Obtains the actual value of a JsonString instance.
Returns:
- String: actual value of the instance
func kind()
public func kind(): JsonKind
Description: Returns the JsonKind type (JsString) of the current JsonString instance.
Returns:
- JsonKind: JsonKind type(JsString) of the current JsonString instance
func toJsonString()
public func toJsonString(): String
Description: Converts JsonString to a JSON string (with spaces and newline characters).
Returns:
- String: JSON string after conversion
func toString()
public func toString(): String
Description: Converts JsonString to a string.
Returns:
- String: string after conversion
class JsonValue
sealed abstract class JsonValue <: ToString
Description: Specifies the JSON data layer used for conversion between JsonValue and String data.
The abstract class JsonValue provides interfaces for conversion between the String type and specific JSON types and provides the function of determining JSON types.
Parent Type:
Example:
For details, see Conversion Between JsonValue and String.
static func fromStr(String)
public static func fromStr(s: String): JsonValue
Description: Parses string data into JsonValue. For integers, the leading '0b', '0o', and '0x' (case insensitive) are supported, indicating binary, octal, and hexadecimal, respectively. If the string fails to be parsed, the error character as well as the numbers of rows and columns are printed. The number of columns is counted from the non-space character in the row where the error character is located.
When JSON parses conversion of String into JsonValue, the escape character \ must be followed by an escape character (b, f, n, r, t, u, \, ", or /) supported by JSON. \u is in the format of **\uXXXX, where X is a hexadecimal number. For example, \u0041 represents character 'A'.
Parameters:
- s: String: string to be passed in. Currently, ? and special characters are not supported.
Returns:
Throws:
- JsonException: If the memory allocation fails or an error occurs during string parsing, this exception is thrown.
Example:
import encoding.json.*
main() {
println(JsonString("\b | \f | \n | \r | \t | A | \\ | \" | /").toString())
println(JsonValue.fromStr("\"\\b\"").toString())
println(JsonValue.fromStr("\"\\f\"").toString())
println(JsonValue.fromStr("\"\\n\"").toString())
println(JsonValue.fromStr("\"\\r\"").toString())
println(JsonValue.fromStr("\"\\t\"").toString())
println(JsonValue.fromStr("\"\\u0041\"").toString())
println(JsonValue.fromStr("\"\\\\\"").toString())
println(JsonValue.fromStr("\"\\\"\"").toString())
println(JsonValue.fromStr("\"\\/\"").toString())
}
Running result:
"\b | \f | \n | \r | \t | A | \\ | \" | /"
"\b"
"\f"
"\n"
"\r"
"\t"
"A"
"\\"
"\""
"/"
func asArray()
public func asArray(): JsonArray
Description: Converts JsonValue to JsonArray.
Returns:
Throws:
- JsonException: If the conversion fails, this exception is thrown.
func asBool()
public func asBool(): JsonBool
Description: Converts JsonValue to JsonBool.
Returns:
Throws:
- JsonException: If the conversion fails, this exception is thrown.
func asFloat()
public func asFloat(): JsonFloat
Description: Converts JsonValue to JsonFloat.
Returns:
Throws:
- JsonException: If the conversion fails, this exception is thrown.
func asInt()
public func asInt(): JsonInt
Description: Converts JsonValue to JsonInt
Returns:
Throws:
- JsonException: If the conversion fails, this exception is thrown.
func asNull()
public func asNull(): JsonNull
Description: Converts JsonValue to JsonNull
Returns:
Throws:
- JsonException: If the conversion fails, this exception is thrown.
func asObject()
public func asObject(): JsonObject
Description: Converts JsonValue to JsonObject.
Returns:
- JsonObject: JsonObject after conversion
Throws:
- JsonException: If the conversion fails, this exception is thrown.
func asString()
public func asString(): JsonString
Description: Converts JsonValue to JsonString.
Returns:
- JsonString: JsonString after conversion
Throws:
- JsonException: If the conversion fails, this exception is thrown.
func kind()
public func kind(): JsonKind
Description: Returns the JsonKind type of the current JsonValue instance.
Returns:
func toJsonString()
public func toJsonString(): String
Description: Converts JsonValue to a JSON string (with spaces and newline characters).
Returns:
- String: JSON string after conversion
func toString()
public func toString(): String
Description: Converts JsonValue to a string.
Returns:
- String: string after conversion
Enumeration
enum JsonKind
public enum JsonKind {
| JsNull
| JsBool
| JsInt
| JsFloat
| JsString
| JsArray
| JsObject
}
Description: Indicates the specific types of JsonValue.
JsArray
JsArray
Description: Indicates the array type in the JSON type.
JsBool
JsBool
Description: Indicates the true or false type.
JsFloat
JsFloat
Description: Indicates the number type of a floating-point number.
JsInt
JsInt
Description: Indicates the number type of an integer.
JsNull
JsNull
Description: Indicates the null type.
JsObject
JsObject
Description: Indicates the object type in the JSON type.
JsString
JsString
Description: Indicates the string type.
Exception
class JsonException
public class JsonException <: Exception {
public init()
public init(message: String)
}
Description: Indicates the exception class of the JSON package used in the scenario where an exception occurs when the JsonValue type is used.
Parent Type:
init()
public init()
Description: Constructs a JsonException instance that does not contain any exception information.
init(String)
public init(message: String)
Description: Constructs a JsonException instance according to specified exception information.
Parameters:
- message: String: specified exception information
JsonArray Usage Example
In the following example of using JsonArray, a JsonArray object is constructed, some JsonValue values are added to the object, and the JsonArray object is printed in two formats.
import encoding.json.*
import std.collection.*
main() {
var a: JsonValue = JsonNull()
var b: JsonValue = JsonBool(true)
var c: JsonValue = JsonBool(false)
var d: JsonValue = JsonInt(7363)
var e: JsonValue = JsonFloat(736423.546)
var list: ArrayList<JsonValue> = ArrayList<JsonValue>()
var list2: ArrayList<JsonValue> = ArrayList<JsonValue>()
var map = JsonObject()
var map1 = JsonObject()
map1.put("a", JsonString("jjjjjj"))
map1.put("b", b)
map1.put("c", JsonString("hhhhh"))
list2.append(b)
list2.append(JsonInt(3333333))
list2.append(map1)
list2.append(JsonString("sdfghgfasd"))
list.append(b)
list.append(a)
list.append(map)
list.append(c)
list.append(JsonArray(list2))
list.append(d)
list.append(JsonString("ddddddd"))
list.append(e)
var result: JsonValue = JsonArray(list)
println("func toString result is:")
println(result.toString())
println("func toJsonString result is:")
println(result.toJsonString())
0
}
Running result:
func toString result is:
[true,null,{},false,[true,3333333,{"a":"jjjjjj","b":true,"c":"hhhhh"},"sdfghgfasd"],7363,"ddddddd",736423.546]
func toJsonString result is:
[
true,
null,
{},
false,
[
true,
3333333,
{
"a": "jjjjjj",
"b": true,
"c": "hhhhh"
},
"sdfghgfasd"
],
7363,
"ddddddd",
736423.546
]
Conversion between JsonValue and String
In the following example of the conversion between JsonValue and String, JsonValue.fromStr is used to convert a JSON string into JsonValue, and then the JsonValue object is printed in two formats.
import encoding.json.*
main() {
var str = ##"[true,"kjjjke\"eed",{"sdfd":"ggggg","eeeee":[341,false,{"nnnn":55.87}]},3422,22.341,false,[22,22.22,true,"ddd"],43]"##
var jv: JsonValue = JsonValue.fromStr(str)
var res = jv.toString()
var prettyres = jv.toJsonString()
println(res)
println(prettyres)
0
}
Running result:
[true,"kjjjke\"eed",{"sdfd":"ggggg","eeeee":[341,false,{"nnnn":55.87}]},3422,22.341,false,[22,22.22,true,"ddd"],43]
[
true,
"kjjjke\"eed",
{
"sdfd": "ggggg",
"eeeee": [
341,
false,
{
"nnnn": 55.87
}
]
},
3422,
22.341,
false,
[
22,
22.22,
true,
"ddd"
],
43
]
Conversion Between JsonValue and DataModel
In the following example of the conversion between a JSON string and a custom type, the Serializable interface is implemented for the Person type, and then the conversions from JSON string to the custom type and from the custom type to JSON string are performed.
import serialization.serialization.*
import encoding.json.*
class Person <: Serializable<Person> {
var name: String = ""
var age: Int64 = 0
var loc: Option<Location> = Option<Location>.None
public func serialize(): DataModel {
return DataModelStruct().add(field<String>("name", name)).add(field<Int64>("age", age)).add(field<Option<Location>>("loc", loc))
}
public static func deserialize(dm: DataModel): Person {
var dms = match (dm) {
case data: DataModelStruct => data
case _ => throw Exception("this data is not DataModelStruct")
}
var result = Person()
result.name = String.deserialize(dms.get("name"))
result.age = Int64.deserialize(dms.get("age"))
result.loc = Option<Location>.deserialize(dms.get("loc"))
return result
}
}
class Location <: Serializable<Location>{
var country: String = ""
var province: String = ""
public func serialize(): DataModel {
return DataModelStruct().add(field<String>("country", country)).add(field<String>("province", province))
}
public static func deserialize(dm: DataModel): Location {
var dms = match (dm) {
case data: DataModelStruct => data
case _ => throw Exception("this data is not DataModelStruct")
}
var result = Location()
result.country = String.deserialize(dms.get("country"))
result.province = String.deserialize(dms.get("province"))
return result
}
}
main() {
var js = ##"{
"name": "A",
"age": 30,
"loc": {
"country": "China",
"province": "Beijing"
}
}"##
var jv = JsonValue.fromStr(js)
var dm = DataModel.fromJson(jv)
var A = Person.deserialize(dm)
println("name == ${A.name}")
println("age == ${A.age}")
println("country == ${A.loc.getOrThrow().country}")
println("province == ${A.loc.getOrThrow().province}")
println("====================") // The upper part implements the conversion from JSON string to the custom type, and the lower part implements the conversion from the custom type to JSON string.
dm = A.serialize()
var jo = dm.toJson().asObject()
println(jo.toJsonString())
0
}
Running result:
name == A
age == 30
country == China
province == Beijing
====================
{
"name": "A",
"age": 30,
"loc": {
"country": "China",
"province": "Beijing"
}
}
encoding.json.stream Package
Function Description
The json.stream package is used for conversion between Cangjie objects and JSON data streams.
This package provides the JsonWriter and JsonReader classes. The JsonWriter class provides the serialization capability for converting Cangjie objects into JSON data streams. The JsonReader class provides the deserialization capability for converting JSON data streams into Cangjie objects.
Currently, the following types support the conversion with JSON data streams:
-
Basic data types: String, Int8, Int16, Int32, Int64, Float16, Float32, Float64, UInt8, UInt16, UInt32, and UInt64
-
Set type: Array<T>, ArrayList<T>, and HashMap<String, T>
-
Other types: Option<T>, BigInt, and Decimal
API List
Interface
| Name | Description |
|---|---|
| JsonDeserializable<T> | Reads a Cangjie object from JsonReader. |
| JsonSerializable | Provides an interface for serializing a type to a JSON data stream. |
Class
| Name | Description |
|---|---|
| JsonReader | Provides the deserialization capability for converting a JSON data stream into a Cangjie object. |
| JsonWriter | Provides the capability of serializing a Cangjie object to a JSON data stream. |
Enumeration
| Name | Description |
|---|---|
| JsonToken | Indicates the structure, name, or value type in a JSON-encoded string. |
Struct
| Name | Description |
|---|---|
| WriteConfig | Indicates the serialization format of JsonWriter. |
Interface
interface JsonDeserializable<T>
public interface JsonDeserializable<T> {
static func fromJson(r: JsonReader): T
}
Description: Reads a Cangjie object from JsonReader.
The following object types are supported:
-
Basic data types: integer, floating-point, Boolean, and string
-
Collection types: Array, ArrayList, HashMap, and Option
static func fromJson(JsonReader)
static func fromJson(r: JsonReader): T
Description: Reads an object of the T type from the JsonReader instance specified by r.
Parameters:
- r: JsonReader: JsonReader instance from which the deserialization result is read
Returns:
- T: instance of the
Ttype
Throws:
- IllegalStateException: If the JSON data in the input stream is not in the required format, this exception is thrown.
extend BigInt <: JsonDeserializable<BigInt>
extend BigInt <: JsonDeserializable<BigInt>
Description: Implements the JsonDeserializable interface for the BigInt type.
Parent Type:
static func fromJson(JsonReader)
public static func fromJson(r: JsonReader): BigInt
Description: Reads a BigInt from JsonReader.
Parameters:
- r: JsonReader: JsonReader instance from which the deserialization result is read
Returns:
- BigInt: instance of the BigInt type
extend Bool <: JsonDeserializable<Bool>
extend Bool <: JsonDeserializable<Bool>
Description: Implements the JsonDeserializable interface for the Bool type.
Parent Type:
static func fromJson(JsonReader)
public static func fromJson(r: JsonReader): Bool
Description: Reads a Bool from JsonReader.
Parameters:
- r: JsonReader: JsonReader instance from which the deserialization result is read
Returns:
- Bool: instance of the Bool type
extend DateTime <: JsonDeserializable<DateTime>
extend DateTime <: JsonDeserializable<DateTime>
Description: Implements the JsonDeserializable interface for the DateTime type.
Parent Type:
static func fromJson(JsonReader)
public static func fromJson(r: JsonReader): DateTime
Description: Reads a DateTime instance from JsonReader.
This function parses the read string according to the RFC3339 specifications. The fractional second format is supported. For details about the function, see func parse(String) of DateTime.
Parameters:
- r: JsonReader: JsonReader instance from which the deserialization result is read
Returns:
- DateTime: instance of the DateTime type
Throws:
- TimeParseException: When normal parsing cannot be performed, this exception is thrown.
extend Float16 <: JsonDeserializable<Float16>
extend Float16 <: JsonDeserializable<Float16>
Description: Implements the JsonDeserializable interface for the Float16 type.
Parent Type:
static func fromJson(JsonReader)
public static func fromJson(r: JsonReader): Float16
Description: Reads a Float16 from JsonReader.
Parameters:
- r: JsonReader: JsonReader instance from which the deserialization result is read
Returns:
- Float16: instance of the Float16 type
Throws:
- OverflowException: When the data read exceeds the allowed range, this exception is thrown.
extend Float32 <: JsonDeserializable<Float32>
extend Float32 <: JsonDeserializable<Float32>
Description: Implements the JsonDeserializable interface for the Float32 type.
Parent Type:
static func fromJson(JsonReader)
public static func fromJson(r: JsonReader): Float32
Description: Reads a Float32 from JsonReader.
Parameters:
- r: JsonReader: JsonReader instance from which the deserialization result is read
Returns:
- Float32: instance of the Float32 type
Throws:
- OverflowException: When the data read exceeds the allowed range, this exception is thrown.
extend Float64 <: JsonDeserializable<Float64>
extend Float64 <: JsonDeserializable<Float64>
Description: Implements the JsonDeserializable interface for the Float64 type.
Parent Type:
static func fromJson(JsonReader)
public static func fromJson(r: JsonReader): Float64
Description: Reads a Float64 from JsonReader.
Parameters:
- r: JsonReader: JsonReader instance from which the deserialization result is read
Returns:
- Float64: instance of the Float64 type
Throws:
- OverflowException: When the data read exceeds the allowed range, this exception is thrown.
extend String <: JsonDeserializable<String>
extend String <: JsonDeserializable<String>
Description: Implements the JsonDeserializable interface for the String type.
Parent Type:
static func fromJson(JsonReader)
public static func fromJson(r: JsonReader): String
Description: Reads a String from JsonReader.
The deserialization result of String varies according to the next JsonToken.
- When the next
JsonTokenisJsonString, the readStringis escaped according to the standard ECMA-404 The JSON Data Interchange Standard in the deserialization process. - When the next
JsonTokenis one ofJsonNumber,JsonBool, andJsonNulltype, the original string of the nextvaluefield is read and returned. - If the next
JsonTokenis of another type, an exception is thrown when this function is called.
Parameters:
- r: JsonReader: JsonReader instance from which the deserialization result is read
Returns:
- String: instance of the String type
extend Int16 <: JsonDeserializable<Int16>
extend Int16 <: JsonDeserializable<Int16>
Description: Implements the JsonDeserializable interface for the Int16 type.
Parent Type:
static func fromJson(JsonReader)
public static func fromJson(r: JsonReader): Int16
Description: Reads a Int16 from JsonReader.
Parameters:
- r: JsonReader: JsonReader instance from which the deserialization result is read
Returns:
- Int16: instance of the Int16 type
Throws:
- OverflowException: When the data read exceeds the allowed range, this exception is thrown.
extend Int32 <: JsonDeserializable<Int32>
extend Int32 <: JsonDeserializable<Int32>
Description: Implements the JsonDeserializable interface for the Int32 type.
Parent Type:
static func fromJson(JsonReader)
public static func fromJson(r: JsonReader): Int32
Description: Reads a Int32 from JsonReader.
Parameters:
- r: JsonReader: JsonReader instance from which the deserialization result is read
Returns:
- Int32: instance of the Int32 type
Throws:
- OverflowException: When the data read exceeds the allowed range, this exception is thrown.
extend Int64 <: JsonDeserializable<Int64>
extend Int64 <: JsonDeserializable<Int64>
Description: Implements the JsonDeserializable interface for the Int64 type.
Parent Type:
static func fromJson(JsonReader)
public static func fromJson(r: JsonReader): Int64
Description: Reads a Int64 from JsonReader.
Parameters:
- r: JsonReader: JsonReader instance from which the deserialization result is read
Returns:
- Int64: instance of the Int64 type
Throws:
- OverflowException: When the data read exceeds the allowed range, this exception is thrown.
extend Int8 <: JsonDeserializable<Int8>
extend Int8 <: JsonDeserializable<Int8>
Description: Implements the JsonDeserializable interface for the Int8 type.
Parent Type:
static func fromJson(JsonReader)
public static func fromJson(r: JsonReader): Int8
Description: Reads a Int8 from JsonReader.
Parameters:
- r: JsonReader: JsonReader instance from which the deserialization result is read
Returns:
- Int8: instance of the Int8 type
Throws:
- OverflowException: When the data read exceeds the allowed range, this exception is thrown.
extend IntNative <: JsonDeserializable<IntNative>
extend IntNative <: JsonDeserializable<IntNative>
Description: Implements the JsonDeserializable interface for the IntNative type.
Parent Type:
static func fromJson(JsonReader)
public static func fromJson(r: JsonReader): IntNative
Description: Reads a IntNative from JsonReader.
Parameters:
- r: JsonReader: JsonReader instance from which the deserialization result is read
Returns:
- IntNative: instance of the IntNative type
Throws:
- OverflowException: When the data read exceeds the allowed range, this exception is thrown.
extend UInt16 <: JsonDeserializable<UInt16>
extend UInt16 <: JsonDeserializable<UInt16>
Description: Implements the JsonDeserializable interface for the UInt16 type.
Parent Type:
static func fromJson(JsonReader)
public static func fromJson(r: JsonReader): UInt16
Description: Reads a UInt16 from JsonReader.
Parameters:
- r: JsonReader: JsonReader instance from which the deserialization result is read
Returns:
- UInt16: instance of the UInt16 type
Throws:
- OverflowException: When the data read exceeds the allowed range, this exception is thrown.
extend UInt32 <: JsonDeserializable<UInt32>
extend UInt32 <: JsonDeserializable<UInt32>
Description: Implements the JsonDeserializable interface for the UInt32 type.
Parent Type:
static func fromJson(JsonReader)
public static func fromJson(r: JsonReader): UInt32
Description: Reads a UInt32 from JsonReader.
Parameters:
- r: JsonReader: JsonReader instance from which the deserialization result is read
Returns:
- UInt32: instance of the UInt32 type
Throws:
- OverflowException: When the data read exceeds the allowed range, this exception is thrown.
extend UInt64 <: JsonDeserializable<UInt64 >
extend UInt64 <: JsonDeserializable<UInt64>
Description: Implements the JsonDeserializable interface for the UInt64 type.
Parent Type:
static func fromJson(JsonReader)
public static func fromJson(r: JsonReader): UInt64
Description: Reads a UInt64 from JsonReader.
Parameters:
- r: JsonReader: JsonReader instance from which the deserialization result is read
Returns:
- UInt64: instance of the UInt64 type
Throws:
- OverflowException: When the data read exceeds the allowed range, this exception is thrown.
extend UInt8 <: JsonDeserializable<UInt8>
extend UInt8 <: JsonDeserializable<UInt8>
Description: Implements the JsonDeserializable interface for the UInt8 type.
Parent Type:
static func fromJson(JsonReader)
public static func fromJson(r: JsonReader): UInt8
Description: Reads a UInt8 from JsonReader.
Parameters:
- r: JsonReader: JsonReader instance from which the deserialization result is read
Returns:
- UInt8: instance of the UInt8 type
Throws:
- OverflowException: When the data read exceeds the allowed range, this exception is thrown.
extend UIntNative <: JsonDeserializable<UIntNative>
extend UIntNative <: JsonDeserializable<UIntNative>
Description: Implements the JsonDeserializable interface for the UIntNative type.
Parent Type:
static func fromJson(JsonReader)
public static func fromJson(r: JsonReader): UIntNative
Description: Reads a UIntNative from JsonReader.
Parameters:
- r: JsonReader: JsonReader instance from which the deserialization result is read
Returns:
- UIntNative: instance of the UIntNative type
Throws:
- OverflowException: When the data read exceeds the allowed range, this exception is thrown.
extend<T> Array<T> <: JsonDeserializable<Array<T>> where T <: JsonSerializable
extend<T> Array<T> <: JsonDeserializable<Array<T>> where T <: JsonDeserializable<T>
Description: Implements the JsonDeserializable interface for the Array<T> type.
Parent Type:
static func fromJson(JsonReader)
public static func fromJson(r: JsonReader): Array<T>
Description: Reads an Array from JsonReader.
Parameters:
- r: JsonReader: JsonReader instance from which the deserialization result is read
Returns:
- Array<T>: instance of the Array type
extend<T> ArrayList<T> <: JsonDeserializable<ArrayList<T>> where T <: JsonSerializable
extend<T> ArrayList<T> <: JsonDeserializable<ArrayList<T>> where T <: JsonDeserializable<T>
Description: Implements the JsonDeserializable interface for the ArrayList type.
Parent Type:
static func fromJson(JsonReader)
public static func fromJson(r: JsonReader): ArrayList<T>
Description: Reads an ArrayList from JsonReader.
Parameters:
- r: JsonReader: JsonReader instance from which the deserialization result is read
Returns:
- ArrayList <T>: instance of the ArrayList type
extend<T> Option <T> <: JsonDeserializable<Option<T>> where T <: JsonSerializable
extend<T> Option<T> <: JsonDeserializable<Option<T>> where T <: JsonDeserializable<T>
Description: Implements the JsonDeserializable interface for the Option type.
Parent Type:
static func fromJson(JsonReader)
public static func fromJson(r: JsonReader): Option<T>
Description: Reads an Option from JsonReader.
Parameters:
- r: JsonReader: JsonReader instance from which the deserialization result is read
Returns:
- Option<T>: instance of the Option type
extend<K, V> HashMap<K, V> <: JsonDeserializable<HashMap<K, V>> where V <: JsonDeserializable<V>, K <: String
extend<K, V> HashMap<K, V> <: JsonDeserializable<HashMap<K, V>> where V <: JsonDeserializable<V>, K <: String
Description: Implements the JsonDeserializable interface for the HashMap type.
Parent Type:
static func fromJson(JsonReader)
public static func fromJson(r: JsonReader): HashMap<K, V>
Description: Reads a HashMap from JsonReader.
Parameters:
- r: JsonReader: JsonReader instance from which the deserialization result is read
Returns:
- HashMap<K, V>: instance of the HashMap<K, V> type
interface JsonSerializable
public interface JsonSerializable {
func toJson(w: JsonWriter): Unit
}
Description: Provides an interface for serializing a type to a JSON data stream.
This interface is used together with JsonWriter. JsonWriter can write a type that implements the JsonSerializable interface to a stream.
func toJson(JsonWriter)
func toJson(w: JsonWriter): Unit
Description: Writes a type that implements the JsonSerializable interface to the JsonWriter instance specified by the w parameter.
Parameters:
- w: JsonWriter: JsonWriter instance to which the serialization result is written
extend BigInt <: JsonSerializable
extend BigInt <: JsonSerializable
Description: Provides an interface for serializing BigInt data to a JSON data stream.
Parent Type:
func toJson(JsonWriter)
public func toJson(w: JsonWriter): Unit
Description: Writes the BigInt type to the JsonWriter instance specified by the w parameter.
Parameters:
- w: JsonWriter: JsonWriter instance to which the serialization result is written
extend Bool <: JsonSerializable
extend Bool <: JsonSerializable
Description: Provides an interface for serializing the Bool type to a JSON data stream.
Parent Type:
func toJson(JsonWriter)
public func toJson(w: JsonWriter): Unit
Description: Writes the Bool type to the JsonWriter instance specified by the w parameter.
Parameters:
- w: JsonWriter: JsonWriter instance to which the serialization result is written
extend DateTime <: JsonSerializable
extend DateTime <: JsonSerializable
Description: Implement the JsonSerializable interface for the DateTime type.
Parent Type:
func toJson(JsonWriter)
public func toJson(w: JsonWriter): Unit
Description: Serializes the DateTime type to a stream.
The function of this function is associated with the dateTimeFormat property in writeConfig of JsonWriter. This interface exports DateTime to the target stream in the format specified by the dateTimeFormat property. The format can be controlled by modifying the dateTimeFormat property.
Parameters:
- w: JsonWriter: JsonWriter instance to which the serialization result is written
extend Float16 <: JsonSerializable
extend Float16 <: JsonSerializable
Description: Provides an interface for serializing the Float16 type to a JSON data stream.
Parent Type:
func toJson(JsonWriter)
public func toJson(w: JsonWriter): Unit
Description: Writes the Float16 type to the JsonWriter instance specified by the w parameter.
Parameters:
- w: JsonWriter: JsonWriter instance to which the serialization result is written
extend Float32 <: JsonSerializable
extend Float32 <: JsonSerializable
Description: Provides an interface for serializing the Float32 type to a JSON data stream.
Parent Type:
func toJson(JsonWriter)
public func toJson(w: JsonWriter): Unit
Description: Writes the Float32 type to the JsonWriter instance specified by the w parameter.
Parameters:
- w: JsonWriter: JsonWriter instance to which the serialization result is written
extend Float64 <: JsonSerializable
extend Float64 <: JsonSerializable
Description: Provides an interface for serializing the Float64 type to a JSON data stream.
Parent Type:
func toJson(JsonWriter)
public func toJson(w: JsonWriter): Unit
Description: Writes the Float64 type to the JsonWriter instance specified by the w parameter.
Parameters:
- w: JsonWriter: JsonWriter instance to which the serialization result is written
extend String <: JsonSerializable
extend String <: JsonSerializable
Description: Provides an interface for serializing the String type to a JSON data stream.
Parent Type:
func toJson(JsonWriter)
public func toJson(w: JsonWriter): Unit
Description: Writes the String type to the JsonWriter instance specified by the w parameter. Written string
Parameters:
- w: JsonWriter: JsonWriter instance to which the serialization result is written
extend Int16 <: JsonSerializable
extend Int16 <: JsonSerializable
Description: Provides an interface for serializing the Int16 type to a JSON data stream.
Parent Type:
func toJson(JsonWriter)
public func toJson(w: JsonWriter): Unit
Description: Writes the Int16 type to the JsonWriter instance specified by the w parameter.
Parameters:
- w: JsonWriter: JsonWriter instance to which the serialization result is written
extend Int32 <: JsonSerializable
extend Int32 <: JsonSerializable
Description: Provides an interface for serializing the Int32 type to a JSON data stream.
Parent Type:
func toJson(JsonWriter)
public func toJson(w: JsonWriter): Unit
Description: Writes the Int32 type to the JsonWriter instance specified by the w parameter.
Parameters:
- w: JsonWriter: JsonWriter instance to which the serialization result is written
extend Int64 <: JsonSerializable
extend Int64 <: JsonSerializable
Description: Provides an interface for serializing the Int64 type to a JSON data stream.
Parent Type:
func toJson(JsonWriter)
public func toJson(w: JsonWriter): Unit
Description: Writes the Int64 type to the JsonWriter instance specified by the w parameter.
Parameters:
- w: JsonWriter: JsonWriter instance to which the serialization result is written
extend Int8 <: JsonSerializable
extend Int8 <: JsonSerializable
Description: Provides an interface for serializing the Int8 type to a JSON data stream.
Parent Type:
func toJson(JsonWriter)
public func toJson(w: JsonWriter): Unit
Description: Writes the Int8 type to the JsonWriter instance specified by thew parameter.
Parameters:
- w: JsonWriter: JsonWriter instance to which the serialization result is written
extend IntNative <: JsonSerializable
extend IntNative <: JsonSerializable
Description: Provides an interface for serializing the IntNative type to a JSON data stream.
Parent Type:
func toJson(JsonWriter)
public func toJson(w: JsonWriter): Unit
Description: Writes the IntNative type to the JsonWriter instance specified by the w parameter.
Parameters:
- w: JsonWriter: JsonWriter instance to which the serialization result is written
extend UInt16 <: JsonSerializable
extend UInt16 <: JsonSerializable
Description: Provides an interface for serializing the UInt16 type to a JSON data stream.
Parent Type:
func toJson(JsonWriter)
public func toJson(w: JsonWriter): Unit
Description: Writes the UInt16 type to the JsonWriter instance specified by the w parameter.
Parameters:
- w: JsonWriter: JsonWriter instance to which the serialization result is written
extend UInt32 <: JsonSerializable
extend UInt32 <: JsonSerializable
Description: Provides an interface for serializing the UInt32 type to a JSON data stream.
Parent Type:
func toJson(JsonWriter)
public func toJson(w: JsonWriter): Unit
Description: Writes the UInt32 type to the JsonWriter instance specified by the w parameter.
Parameters:
- w: JsonWriter: JsonWriter instance to which the serialization result is written
extend UInt64 <: JsonSerializable
extend UInt64 <: JsonSerializable
Description: Provides an interface for serializing the UInt64 type to a JSON data stream.
Parent Type:
func toJson(JsonWriter)
public func toJson(w: JsonWriter): Unit
Description: Writes the UInt64 type to the JsonWriter instance specified by the w parameter.
Parameters:
- w: JsonWriter: JsonWriter instance to which the serialization result is written
extend UInt8 <: JsonSerializable
extend UInt8 <: JsonSerializable
Description: Provides an interface for serializing the UInt8 type to a JSON data stream.
Parent Type:
func toJson(JsonWriter)
public func toJson(w: JsonWriter): Unit
Description: Writes the UInt8 type to the JsonWriter instance specified by the w parameter.
Parameters:
- w: JsonWriter: JsonWriter instance to which the serialization result is written
extend UIntNative <: JsonSerializable
extend UIntNative <: JsonSerializable
Description: Provides an interface for serializing the UIntNative type to a JSON data stream.
Parent Type:
func toJson(JsonWriter)
public func toJson(w: JsonWriter): Unit
Description: Writes the UIntNative type to the JsonWriter instance specified by the w parameter.
Parameters:
- w: JsonWriter: JsonWriter instance to which the serialization result is written
extend<T> Array<T> <: JsonSerializable where T <: JsonSerializable
extend<T> Array<T> <: JsonSerializable where T <: JsonSerializable
Description: Provides an interface for serializing the Array<T> type to a JSON data stream.
Parent Type:
func toJson(JsonWriter)
public func toJson(w: JsonWriter): Unit
Description: Writes the Array<T> type to the JsonWriter instance specified by the w parameter.
Parameters:
- w: JsonWriter: JsonWriter instance to which the serialization result is written
extend<T> ArrayList<T> <: JsonSerializable where T <: JsonSerializable
extend<T> ArrayList<T> <: JsonSerializable where T <: JsonSerializable
Description: Provides an interface for serializing the ArrayList<T> type to a JSON data stream.
Parent Type:
func toJson(JsonWriter)
public func toJson(w: JsonWriter): Unit
Description: Writes the ArrayList<T> type to the JsonWriter instance specified by the w parameter.
Parameters:
- w: JsonWriter: JsonWriter instance to which the serialization result is written
extend<T> Option<T> <: JsonSerializable where T <: JsonSerializable
extend<T> Option<T> <: JsonSerializable where T <: JsonSerializable
Description: Provides an interface for serializing the Option<T> type to a JSON data stream.
Parent Type:
func toJson(JsonWriter)
public func toJson(w: JsonWriter): Unit
Description: Writes the Option<T> type to the JsonWriter instance specified by the w parameter.
Parameters:
- w: JsonWriter: JsonWriter instance to which the serialization result is written
extend<K, V> HashMap<K, V> <: JsonSerializable where V <: JsonSerializable, K <: String
extend<K, V> HashMap<K, V> <: JsonSerializable where V <: JsonSerializable, K <: String
Description: Provides an interface for serializing the HashMap<K, V> type to a JSON data stream.
Parent Type:
func toJson(JsonWriter)
public func toJson(w: JsonWriter): Unit
Description: Writes the HashMap<K, V> type to the JsonWriter instance specified by the w parameter.
Parameters:
- w: JsonWriter: JsonWriter instance to which the serialization result is written
Class
class JsonReader
public class JsonReader {
public init(inputStream: InputStream)
}
Description: Provides the deserialization capability for converting JSON data streams into Cangjie objects.
Example:
For details about the usage example, see Deserialization Using Json Stream.
init(InputStream)
public init(inputStream: InputStream)
Description: Creates a JsonReader according to an input stream. When the JsonReader reads data from the input stream, the empty characters ('\0', '\t', '\n', '\r') that are not in JsonString are skipped.
Parameters:
- inputStream: InputStream: JSON data stream to be input
func endArray()
public func endArray(): Unit
Description: Consumes a character ']' after skipping the whitespace character from the current position of the input stream. endArray must have a corresponding startArray.
Throws:
- IllegalStateException: If the JSON data in the input stream is not in the required format, this exception is thrown.
func endObject()
public func endObject(): Unit
Description: Consumes a character '}' after skipping the whitespace character from the current position of the input stream. endObject must have a corresponding startObject.
Throws:
- IllegalStateException: If the JSON data in the input stream is not in the required format, this exception is thrown.
func peek()
public func peek(): Option<JsonToken>
Description: Obtains the type of the next JsonToken of an input stream. The format of the next JsonToken may not be correct.
Example: If the next character in the input stream is 't', the obtained JsonToken is JsonToken.Bool, but readValue<Bool>() may not be successfully called.
Returns:
Throws:
- IllegalStateException: If the next character of the input stream is none of the following: n, t, f,", 0 to 9, -, {, }, [, and ], this exception is thrown.
func readName()
public func readName(): String
Description: Reads a name from the current position of the input stream.
Returns:
- String: name value read
Throws:
- IllegalStateException: If the JSON data in the input stream is not in the required format, this exception is thrown.
func readValue<T>() where T <: JsonDeserializable<T>
public func readValue<T>(): T where T <: JsonDeserializable<T>
Description: Reads a value from the current position of the input stream.
Note:
When the generic T is of the String type, the return value of this function varies according to the next JsonToken.
When the next JsonToken is JsonString, the read String is escaped according to the standard ECMA-404 The JSON Data Interchange Standard in the deserialization process.
When the next JsonToken is one of JsonInt, JsonFloat, JsonBool, and JsonNull, the original string of the next
valuefield is read and returned.If the next JsonToken is of another type, an exception is thrown when this function is called.
Returns:
- T: read value
Throws:
- IllegalStateException: If the JSON data in the input stream is not in the required format, this exception is thrown.
func skip()
public func skip(): Unit
Description: Skips a group of data from the current position of the input stream.
Note:
The rules for Skip are as follows:
If next token is a value, the value is skipped without format check.
If next token is a name, the combination of name and value is skipped.
If next token is BeginArray, this array is skipped.
If next token is BeginObject, this object is skipped.
If next token is EndArray, EndObject, or None, no operation is performed, and peek still returns EndArray, EndObject, or None.
Throws:
- IllegalStateException: If the JSON data in the input stream is not in the required format, this exception is thrown.
func startArray()
public func startArray(): Unit
Description: Consumes a character '[' after skipping the whitespace character from the current position of the input stream.
Throws:
- IllegalStateException: If the JSON data in the input stream is not in the required format, this exception is thrown.
func startObject()
public func startObject(): Unit
Description: Consumes a character '{' after skipping the whitespace character from the current position of the input stream.
Throws:
- IllegalStateException: If the JSON data in the input stream is not in the required format, this exception is thrown.
class JsonWriter
public class JsonWriter {
public init(out: OutputStream)
}
JsonWriter provides the capability of serializing Cangjie objects to OutputStream.
JsonWriter must be used together with interface JsonSerializable. JsonWriter can write a type that implements the JsonSerializable interface to a stream by using writeValue.
Note:
JsonWriter uses the cache to reduce the number of I/Os when data is written to a stream. Before ending the use of JsonWriter, the flush function must be called to ensure that all data in the cache is written to the stream.
Example:
For details about the usage example, see Serialization Using Json Stream.
init(OutputStream)
public init(out: OutputStream)
Description: Indicates a constructor used to construct an instance for writing data to out.
Parameters:
- out: OutputStream: target stream
var writeConfig
public var writeConfig = WriteConfig.compact
Description: Obtains and sets the serialization format configuration. For details, see WriteConfig.
func endArray()
public func endArray(): Unit
Description: Ends the serialization of the current JSON array.
Throws:
- IllegalStateException: When the current writer does not have a matched startArray, this exception is thrown.
func endObject()
public func endObject(): Unit
Description: Ends the serialization of the current JSON object.
Throws:
- IllegalStateException: When no JSON object should be ended due to the status of the current writer, this exception is thrown.
func flush()
public func flush(): Unit
Description: Writes data in the cache to out and calls the flush method of out.
func jsonValue()
public func jsonValue(value: String): JsonWriter
Description: Writes an original string that complies with the JSON value specifications to a stream.
Note:
This function does not escape value or add double quotation marks to the input parameter. It is advised to use this function if the user can ensure that the input value complies with the data conversion standard ECMA-404 The JSON Data Interchange Standard.
Returns:
- JsonWriter: To facilitate chain call, the return value is the reference of the current JsonWriter.
Throws:
- IllegalStateException: When value should not be written due to the status of the current writer, this exception is thrown.
func startArray()
public func startArray(): Unit
Description: Starts to serialize a new JSON array. Each startArray must have a corresponding endArray.
Throws:
- IllegalStateException: When no JSON array should be written due to the status of the current writer, this exception is thrown.
func startObject()
public func startObject(): Unit
Description: Starts to serialize a new JSON object. Each startObject must have a corresponding endObject.
Throws:
- IllegalStateException: When no JSON object should be written due to the status of the current writer, this exception is thrown.
func writeName(String)
public func writeName(name: String): JsonWriter
Description: Writes name in an object struct.
Returns:
- JsonWriter: current JsonWriter reference
Throws:
- IllegalStateException: When the string specified by the
nameparameter should not be written due to the status of the current JsonWriter, this exception is thrown.
func writeNullValue()
public func writeNullValue(): JsonWriter
Description: Writes JSON value null to a stream.
Returns:
- JsonWriter: To facilitate chain call, the return value is the reference of the current JsonWriter.
Throws:
- IllegalStateException: When value should not be written due to the status of the current writer, this exception is thrown.
func writeValue<T>(T) where T <: JsonSerializable
public func writeValue<T>(v: T): JsonWriter where T <: JsonSerializable
Description: Writes a type that implements the JsonSerializable interface to a stream. This interface calls the toJson method of the generic T to write data to an output stream.
The json.stream package implements JsonSerializable for the basic types Int64, UInt64, Float64, Bool, and String. It also implements JsonSerializable for Array, ArrayList, and HashMap of the Collection type.
Returns:
- JsonWriter: reference of the current JsonWriter
Throws:
- IllegalStateException: When value should not be written due to the status of the current writer, this exception is thrown.
Enumeration
enum JsonToken
public enum JsonToken <: Equatable<JsonToken> & Hashable{
| JsonNull
| JsonBool
| JsonNumber
| JsonString
| BeginArray
| EndArray
| BeginObject
| EndObject
| Name
}
Description: Indicates the struct, name, or value type in a JSON-encoded string.
JsonToken is usually used together with JsonReader.peek(). The processing method is determined by the return value.
Parent Type:
BeginArray
BeginArray
Description: Indicates the start of an array in JSON. If JsonReader.peek() returns this type, JsonReader.startArray() can be used for reading.
BeginObject
BeginObject
Description: Indicates the start of an object in JSON. If JsonReader.peek() returns this type, JsonReader.startObject() can be used for reading.
EndArray
EndArray
Description: Indicates the end of an array in JSON. If JsonReader.peek() returns this type, JsonReader.endArray() can be used for reading.
EndObject
EndObject
Description: Indicates the end of an object in JSON. If JsonReader.peek() returns this type, JsonReader.endObject() can be used for reading.
JsonBool
JsonBool
Description: Indicates the bool type of JSON. If JsonReader.peek() returns this type, JsonReader.readValue<Bool>() can be used for reading.
JsonNull
JsonNull
Description: Indicates the null type of JSON. If JsonReader.peek() returns this type, JsonReader.readValue<Option<T>>() can be used for reading.
JsonNumber
JsonNumber
Description: Indicates the number type of JSON. If JsonReader.peek() returns this type, JsonReader.readValue<Float64>() can be used for reading.
JsonString
JsonString
Description: Indicates the string type of JSON. If JsonReader.peek() returns this type, JsonReader.readValue<String>() can be used for reading.
Name
Name
Description: Indicates name in an object. If JsonReader.peek() returns this type, JsonReader.readName() can be used for reading.
func hashCode()
public func hashCode(): Int64
Description: Obtains the hashCode value of a JsonToken object.
Returns:
- Int64: hashCode value
operator func !=(JsonToken)
public operator func !=(that: JsonToken): Bool
Description: Checks whether two JsonToken objects are not equal.
Parameters:
Returns:
- Bool: If the current instance is not equal to that, true is returned. Otherwise, false is returned.
operator func ==(JsonToken)
public operator func ==(that: JsonToken): Bool
Description: Checks whether two JsonToken objects are equal.
Parameters:
Returns:
- Bool: If the current instance is equal to that, true is returned. Otherwise, false is returned.
Struct
struct WriteConfig
public struct WriteConfig {
public static let compact: WriteConfig
public static let pretty: WriteConfig
public mut prop htmlSafe: Bool
public mut prop indent: String
public mut prop newline: String
public mut prop useSpaceAfterSeparators: Bool
public mut prop dateTimeFormat: DateTimeFormat
}
Description: Indicates the serialization format of JsonWriter.
Example:
For details about the usage example, see [WriteConfig Usage Example](../json_stream_samples/sample_json_writeconfig.md#writeconfig-Usage Example).
static let compact
public static let compact: WriteConfig
Description: Provides a compact serialization format.
Note:
The property values of compact are as follows:
- newline: "", which is an empty string
- indent: "", which is an empty string
- useSpaceAfterSeparators: false
- htmlSafe: false
- dateTimeFormat: DateTimeFormat.RFC3339
Type: WriteConfig
Example:
{"Name":"zhangsan","Age":18,"Scores":[88.8,99.9],"Class":{"Name":"Class A","Students Number":33}}
static let pretty
public static let pretty: WriteConfig
Description: Provides a neat serialization format.
Note:
The property values of pretty are as follows:
- newline: "\n"
- indent: " ", which is a string containing four spaces
- useSpaceAfterSeparators: true
- htmlSafe: false
- dateTimeFormat: DateTimeFormat.RFC3339
Type: WriteConfig
Example:
{
"Name": "zhangsan",
"Age": 18,
"Scores": [
88.8,
99.9
],
"Class": {
"Name": "Class A",
"Students Number": 33
}
}
prop dateTimeFormat
public mut prop dateTimeFormat: DateTimeFormat
Description: Controls the format when serializing the DateTime type. The function is the same as that of func toString(DateTimeFormat) of DateTime.
Type: DateTimeFormat
prop htmlSafe
public mut prop htmlSafe: Bool
Description: Specifies whether to escape HTML characters <, >, &, =, and '.
If this value is true, HTML characters are escaped to Unicode-encoded strings.
This option is valid only for string literals in json value.
Type: Bool
prop indent
public mut prop indent: String
Description: Specifies the indentation string entered at each indentation level during serialization. The value must match the regular expression ^[ \t]*$.
When the preceding line break takes effect, the value is used as the padding character after the line break.
Type: String
Throws:
- IllegalArgumentException: When the set string contains characters other than ' ' or '\t', this exception is thrown.
prop newline
public mut prop newline: String
Description: Specifies the newline character entered during serialization. The value must match the regular expression ^[\r\n]*$.
If the value is not an empty string and is valid, line breaks are generated when JsonWriter calls startObject and startArray operations, elements are inserted, and end operations of startObject and startArray are performed.
If the value is an empty string, no line break is triggered.
Type: String
Throws:
- IllegalArgumentException: When the set string contains characters other than '\r' or '\n', this exception is thrown.
prop useSpaceAfterSeparators
public mut prop useSpaceAfterSeparators: Bool
Description: Specifies whether to add a space after ':' and ',' during serialization.
If the value is true, a space is automatically written each time a field name or an array element is inserted.
This option is valid only for fields in json Object and elements in json Array.
Type: Bool
Deserialization Using Json Stream
The code is as follows:
import encoding.json.stream.*
import std.io.*
import std.collection.*
class A <: JsonDeserializable<A> {
var key1: Option<String> = None
var key2: Bool = false
var key3: Float64 = 0.0
var key4: String = ""
var key5: Array<Int64> = Array<Int64>()
var key6: HashMap<String, String> = HashMap<String, String>()
public static func fromJson(r: JsonReader): A {
var res = A()
while (let Some(v) <- r.peek()) {
match(v) {
case BeginObject =>
r.startObject()
while(r.peek() != EndObject) {
let n = r.readName()
match (n) {
case "key1" => res.key1 = r.readValue<Option<String>>()
case "key2" => res.key2 = r.readValue<Bool>()
case "key3" => res.key3 = r.readValue<Float64>()
case "key4" => res.key4 = r.readValue<String>()
case "key5" => res.key5 = r.readValue<Array<Int64>>()
case "key6" => res.key6 = r.readValue<HashMap<String, String>>()
case _ => ()
}
}
r.endObject()
break
case _ => throw Exception()
}
}
return res
}
func toString(): String {
return "${key1}\n${key2}\n${key3}\n${key4}\n${key5}\n${key6}"
}
}
main() {
let jsonStr = ##"{"key1": null, "key2": true, "key3": 123.456, "key4": "string", "key5": [123, 456], "key6": {"key7": " ", "key8": "\\a"}}"##
var bas = ByteArrayStream()
unsafe { bas.write(jsonStr.rawData()) }
var reader = JsonReader(bas)
var obj = A.fromJson(reader)
println(obj.toString())
}
Running result:
None
true
123.456000
string
[123, 456]
[(key7, ), (key8, \a)]
Serialization Using Json Stream
The code is as follows:
import encoding.json.stream.*
import std.io.ByteArrayStream
class Image <: JsonSerializable {
var width: Int64
var height: Int64
var title: String
var ids: Array<Int64>
public init() {
width = 0
height = 0
title = ""
ids = Array<Int64>()
}
public func toJson(w: JsonWriter): Unit {
w.startObject() // start encoding an object
w.writeName("Width").writeValue(width) // write name and value pair in current object
w.writeName("Height").writeValue(height)
w.writeName("Title").writeValue(title)
w.writeName("Ids").writeValue<Array<Int64>>(ids) //use class Array's func toJson
w.endObject()// end current object
}
}
main(){
let image = Image()
image.width = 800
image.height = 600
image.title = "View from 15th Floor"
image.ids = [116, 943, 234, 38793]
let stream = ByteArrayStream() // output
let writer = JsonWriter(stream) // init a JsonWriter
writer.writeValue(image) // serialize image to JSON
writer.flush()
println(String.fromUtf8(stream.readToEnd()))
}
Running result:
{"Width":800,"Height":600,"Title":"View from 15th Floor","Ids":[116,943,234,38793]}
WriteConfig Usage Example
The code is as follows:
import encoding.json.stream.{JsonWriter, WriteConfig, JsonSerializable}
import std.io.ByteArrayStream
main() {
// Constructs JsonWriter.
let buffer = ByteArrayStream()
let writer = JsonWriter(buffer)
// Sets the JSON write format.
let fmtCfg = WriteConfig.pretty
writer.writeConfig = fmtCfg
// Writes a JSON serialization string according to the preceding write configuration.
writer.writeValue(MyObj())
// Prints the JSON serialization string.
println(String.fromUtf8(buffer.bytes()))
0
}
// Class that supports JSON serialization
class MyObj <: JsonSerializable {
public func toJson(w: JsonWriter): Unit {
w.startObject()
w.writeName("Name").writeValue("zhangsan")
w.writeName("Age").writeValue(18)
w.writeName("Scores").writeValue([88.8, 99.9])
w.writeName("Class")
w.startObject()
w.writeName("Name").writeValue("Class A")
w.writeName("Students Number").writeValue(33)
w.endObject()
w.endObject()
w.flush()
}
}
Running result:
{
"Name": "zhangsan",
"Age": 18,
"Scores": [
88.8,
99.9
],
"Class": {
"Name": "Class A",
"Students Number": 33
}
}
encoding.url Package
Function Description
The url package provides URL-related capabilities, including parsing URL components, encoding and decoding URLs, and combining URLs or paths.
Uniform Resource Locator (URL) is an address used to identify the location of a resource on the Internet. A URL includes protocol, host name, path, and query parameters. The protocol refers to the protocol (such as HTTP and FTP) used to access resources. The host name refers to the domain name or IP address of the server where the resource is located. The path refers to the specific location of the resource. The query parameter is a string used to transfer parameters. The URL is the only way to identify resources on the Internet, and can be used to access various resources such as web pages, images, and videos.
Generally, the URL is in the following format:
scheme://host[:port]/path[?query][#fragment]
In the preceding format:
scheme: protocol, such ashttp,https, andftphost: host name or IP addressport: port number, which is optional and is the default port number of the protocol by defaultpath: resource path, for example,/index.htmland/blog/post/123query: query parameter, which is optional, for example,?page=2&sort=descfragment: document fragment identifier, which is optional, for example,#section-1
For example, the URL of https://www.example.com/blog/post/123?page=2&sort=desc#section-1 is in the following format:
- scheme: https
- host:
www.example.com - path: /blog/post/123
- query: ?page=2&sort=desc
- fragment: #section-1
The reason and basic process of URL encoding are as follows:
URL encoding is a process of converting non-ASCII characters in a URL to ASCII characters with better readability. This is because only ASCII characters are allowed in a URL. Non-ASCII characters may cause URL parsing errors or transmission failures.
The URL encoding process is as follows:
- Convert a URL string to a byte array.
- Convert each non-
ASCIIcharacter to aUTF-8encoded byte sequence. - Convert each byte to two hexadecimal numbers.
- Add a percent sign (%) before each hexadecimal number.
- Concatenate all encoded characters to form an encoded URL string.
For example, if URL encoding is performed on the string "Hello, World!", the result is "%E4%BD%A0%E5%A5%BD%EF%BC%8C%E4%B8%96%E7%95%8C%EF%BC%81".
API List
Class
| Name | Description |
|---|---|
| Form | Stores HTTP request parameters in key-value pairs. A key can correspond to multiple values, and the values are stored in arrays. |
| URL | Provides functions used to parse URLs and other related functions. |
| UserInfo | Indicates the username and password in the URL. |
Exception Class
| Name | Description |
|---|---|
| UrlSyntaxException | Specifies a URL parsing exception class. |
Class
class Form
public class Form {
public init()
public init(queryComponent: String)
}
Description: Stores the form information of HTTP requests in key-value pairs. Generally, the form is the query component of the request URL.
A key can correspond to multiple values, which are stored as arrays. The ampersand & is used to separate multiple key-value pairs. The left part of the equal sign (=) is the key value, and the right part is the value. (There may be no equal sign (=) or the value may be empty)
init()
public init()
Description: Constructs a default Form instance.
init(String)
public init(queryComponent: String)
Description: Constructs a Form instance according to a query string encoded by URL, that is, the query component of the URL instance.
Parses the query string encoded by URL to obtain several key-value pairs and adds them to the newly constructed Form instance.
Parameters:
- queryComponent: String: a string of the query component of URL, excluding the question mark (
?) before the component
Throws:
- IllegalArgumentException When the URL string contains bytes that do not conform to the UTF8 encoding rules, this exception is thrown.
- UrlSyntaxException: If the URL string contains invalid escape characters, this exception is thrown.
func add(String, String)
public func add(key: String, value: String): Unit
Description: Adds a key-value mapping. If the key already exists, the value is added to the end of the original value array.
Parameters:
- key: String: the specified key, which can be a new one
- value: String: Adds the value to the value array corresponding to the specified key
func clone()
public func clone(): Form
Description: Clones Form
Returns:
func get(String)
public func get(key: String): Option<String>
Description: Obtains the first value according to the key.
Examples:
- When the query component is
a=b,form.get("a")obtainsSome(b). - When the query component is
a=,form.get("a")obtainsSome(). - When the query component is
a,form.get("a")obtainsSome(). - When the query component is
a,form.get("c")obtainsNone.
Parameters:
- key: String: the specified key
Returns:
func getAll(String)
public func getAll(key: String): ArrayList<String>
Description: Obtains all values corresponding to a specified key.
Parameters:
- key: String: the key specified by a user, which is used to obtain the corresponding value
Returns:
- ArrayList<String>: the array corresponding to all values obtained according to the specified key If the specified key does not exist, an empty array is returned.
func isEmpty()
public func isEmpty(): Bool
Description: Checks whether Form is empty.
Returns:
- Bool: If yes, true is returned. Otherwise, false is returned.
func remove(String)
public func remove(key: String): Unit
Description: Deletes a key and its value.
Parameters:
- key: String: the key to be deleted
func set(String, String)
public func set(key: String, value: String): Unit
Description: Resets the value of a specified key.
Parameters:
func toEncodeString()
public func toEncodeString(): String
Description: Encodes the key-value pairs in a form using percent-encoding.
Unreserved characters are not encoded. A space is encoded as '+'.
Note:
RFC 3986 defines unreserved characters as follows: unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
Returns:
- String: string after encoding
class URL
public class URL <: ToString {
public init(scheme!: String, hostName!: String, path!: String)
}
Description: Provides functions used to parse URL and other related functions.
The content encoded by the percent sign (%) in a string is decoded and stored in the corresponding component. The initial value is stored in the corresponding raw property. The username and password (if any) in URL are also parsed according to RFC 3986.
Note:
RFC 3986 clearly states that user information stored in plaintext may be disclosed in any scenario. Therefore, it is recommended that user information not stored in plaintext in URLs.
Parent Type:
prop fragment
public prop fragment: ?String
Description: Obtains an anchor component after decoding, which is represented by a string.
Type: ?String
prop hostName
public prop hostName: String
Description: Obtains a host name after decoding, which is represented by a string.
Type: String
prop opaque
public prop opaque: String
Description: Obtains an opaque part in URL, which is represented by a string.
Type: String
prop path
public prop path: String
Description: Obtains a path after decoding, which is represented by a string.
Type: String
prop port
public prop port: String
Description: Obtains a port number, which is represented by a string. An empty string indicates that there is no port number.
Type: String
prop query
public prop query: ?String
Description: Obtains a query component after decoding, which is represented by a string.
Type: ?String
prop queryForm
public prop queryForm: Form
Description: Obtains a query component after decoding, which is represented by a Form instance.
Type: Form
prop rawFragment
public prop rawFragment: ?String
Description: Obtains an anchor component before decoding, which is represented by a string.
Type: ?String
prop rawPath
public prop rawPath: String
Description: Obtains a path before decoding, which is represented by a string.
Type: String
prop rawQuery
public prop rawQuery: ?String
Description: Obtains a query component before decoding, which is represented by a string.
Type: ?String
prop rawUserInfo
public prop rawUserInfo: UserInfo
Description: Obtains username and password information before decoding, which is represented by a UserInfo instance.
Type: UserInfo
prop scheme
public prop scheme: String
Description: Obtains the scheme in URL, which is represented by a string.
Type: String
prop userInfo
public prop userInfo: UserInfo
Description: Obtains username and password information after decoding, which is represented by a UserInfo instance.
Type: UserInfo
init(String, String, String)
public init(scheme!: String, hostName!: String, path!: String)
Description: Constructs a URL instance.
The following requirements must be met during instance construction:
- If the hostName is specified, a scheme is required.
- The instance cannot contain only one scheme parameter.
- If the scheme and path exist, the path must be an absolute path.
Parameters:
- scheme!: String: scheme type
- hostName!: String: host name without a port number
- path!: String: path of the requested resource
Throws:
- UrlSyntaxException: If the constructed instance does not meet the requirements, this exception is thrown.
static func mergePaths(String, String)
public static func mergePaths(basePath: String, refPath: String): String
Description: Combines two paths.
Combination rule: Appends the reference path refPath to the last segment of the base path basePath. If refPath is an absolute path, the value after combination is the original value of refPath. If refPath is not an absolute path, it is appended to the end of the last slash (/) in basePath. All results are standardized (the dot (.), double dots (..), and consecutive slashes (/) in the path are optimized). For a specific behavior, refer to the following example. For details, refer to RFC 3986.
To combine URLs, use resolveURL.
Examples:
- If
/a/b/cand/dare combined,/dis output. - If
/a/b/canddare combined,/a/b/dis output. - If
/a/b/andd/e/../fare combined,/a/b/d/fis output. - If
/a/b/c/and./../../gare combined,/a/gis output.
Parameters:
Returns:
- String: the path after combination and standardization
static func parse(String)
public static func parse(rawUrl: String): URL
Description: Parses an original URL string into a URL object.
This function decomposes URL by component, decodes it, and stores it in the corresponding component property. The rawXXX properties (URL properties whose prefix is raw) store the original values which are not encoded or decoded.
For examples, see "Usage of the URL Parsing Function parse" (./../url_samples/url_parse.md#url-Usage of the Parsing Function parse).
Note:
This function can be used to parse the username and password (if any) in the URL, and it complies with the parsing function of RFC 3986. However, RFC 3986 also clearly states that user information stored in plaintext may be disclosed in any scenario. Therefore, it is recommended that user information not stored in plaintext in URLs.
Parameters:
Returns:
Throws:
- UrlSyntaxException: If the URL string contains invalid characters, this exception is thrown.
- IllegalArgumentException: If the encoded character does not comply with the
UTF-8byte sequence rule, this exception is thrown.
func isAbsoluteURL()
public func isAbsoluteURL(): Bool
Description: Checks whether URL is an absolute URL (when a scheme exists, URL is an absolute URL).
Returns:
- Bool: If a scheme exists, true is returned. Otherwise, false is returned.
func replace(Option<String>, Option<String>, Option<String>, Option<String>, Option<String>, Option<String>, Option<String>)
public func replace(scheme!: Option<String> = None, userInfo!: Option<String> = None,
hostName!: Option<String> = None, port!: Option<String> = None, path!: Option<String> = None,
query!: Option<String> = None, fragment!: Option<String> = None): URL
Description: Replaces the components of a URL object and returns a new URL object.
The following conditions must be met during replacement:
- If the scheme is empty, the host name must be empty.
- If the host name is empty, the user information or port number must be empty.
- If the scheme is not empty, the host name and path cannot be empty at the same time.
- If the scheme is not empty, the path must be an absolute path.
- All components must be valid characters.
Parameters:
- scheme!: Option<String>: scheme component
- userInfo!: Option<String>: user information
- hostName!: Option<String>: host name
- port!: Option<String>: port number
- path!: Option<String>: resource path
- query!: Option<String>: query component
- fragment!: Option<String>: anchor component
Returns:
Throws:
- UrlSyntaxException: If the conditions for replacement are not met, this exception is thrown.
func resolveURL(URL)
public func resolveURL(ref: URL): URL
Description: Generates a new URL instance with the current URL instance as the basic URL instance according to RFC 3986 and by referring to the passed URL instance.
For example, as shown below, http://a/b/c/d;p?q is the basic URL, the reference URL is on the left of the equal sign (=), and the new URL is on the right of the equal sign (=).
- "g" = "http://a/b/c/g"
- "/g" = "http://a/g"
- "g?y" = "http://a/b/c/g?y"
- "g?y#s" = "http://a/b/c/g?y#s"
- "../" = "http://a/b/"
For details about URL generation rules, see RFC 3968.
Parameters:
Returns:
func toString()
public func toString(): String
Description: Obtains the string value of the current URL instance.
The hostName is encoded, and the other part is the value of the rawXXX property (the URL property whose prefix is raw). The value is combined based on the URL component composition sequence to obtain the return value of the function.
Returns:
class UserInfo
public class UserInfo <: ToString {
public init()
public init(userName: String)
public init(userName: String, passWord: String)
public init(userName: String, passWord: Option<String>)
}
Description: Indicates the username and password information in a URL.
Note:
RFC 3986 clearly states that user information stored in plaintext may be disclosed in any scenario. Therefore, it is recommended that user information not stored in plaintext in URLs.
Parent Type:
init()
public init()
Description: Creates a UserInfo instance.
init(String)
public init(userName: String)
Description: Creates a UserInfo instance according to the username.
Parameters:
- userName: String: username
init(String, Option<String>)
public init(userName: String, passWord: Option<String>)
Description: Creates a UserInfo instance according to the username and password. Parameters:
init(String, String)
public init(userName: String, passWord: String)
Description: Creates a UserInfo instance according to the username and password. Parameters:
func password()
public func password(): Option<String>
Description: Obtains the password.
Note:
RFC 3986 clearly states that user information stored in plaintext may be disclosed in any scenario. Therefore, it is recommended that user information not stored in plaintext in URLs.
Returns:
func toString()
public func toString(): String
Description: Converts the current UserInfo instance to a string.
Returns:
func username()
public func username(): String
Description: Obtains the username.
Returns:
- String: the username in string format
Exception Class
class UrlSyntaxException
public class UrlSyntaxException <: Exception {
public init(reason: String)
public init(input: String, reason: String)
}
Description: Specifies the URL parsing exception class.
Parent Type:
init(String)
public init(reason: String)
Description: Constructs a UrlSyntaxException instance according to the error cause.
Parameters:
- reason: String: cause of the parsing error
init(String, String)
public init(input: String, reason: String)
Description: Constructs a UrlSyntaxException instance according to the URL and error cause.
Parameters:
init(String, String, String)
public init(input: String, reason: String, pos: String)
Description: Constructs a UrlSyntaxException instance according to the URL string, the error cause, and the part that fails to be parsed.
Parameters:
- input: String: native URL or its segments
- reason: String: cause of the parsing error
- pos: String: the part that fails to be parsed in the given URL string
Form Construction and Usage
Form Construction and Usage of the Function get
Creates a Form class and uses get to obtain the value mapped to the key.
Code:
In this example, the function get of the Form class is used to obtain the value 2 of the specified key = 1.
import encoding.url.*
main(): Int64 {
var s = Form("1=2&2=3&1=2&&")
print(s.get("1").getOrThrow())
return 0
}
Running result:
2
Form Construction and Usage of the Function get in the Case of Duplicate Keys
Creates a Form class and uses get to obtain the value mapped to the key.
Code:
In this example, the function get of the Form class is used to obtain the first value %6AD of the specified key = 1. %6A in the value is decoded to** j**. Therefore, the value jD is obtained.
import encoding.url.*
main(): Int64 {
var s = Form("2=3&1=%6AD&1=2")
// Decodes **%6A** into **j**. For duplicate keys, get is called to obtain the first value **jD**.
print(s.get("1").getOrThrow())
return 0
}
Running result:
jD
Form Construction and Usage of Other Functions
Calls add, set, and clone to print the changes before and after the output.
Code:
import encoding.url.*
main(): Int64 {
var f = Form()
// Adds values **v1** and **v2** to the key **k**.
f.add("k", "v1")
f.add("k", "v2")
// When the get method is called, the first value is obtained.
println(f.get("k").getOrThrow())
// Sets the value of the key **k** to **v**.
f.set("k", "v")
println(f.get("k").getOrThrow())
let clone_f = f.clone()
// Adds a key-value pair to the cloned clone_f.
clone_f.add("k1", "v1")
// Uses get to obtain the value **v1**.
println(clone_f.get("k1").getOrThrow())
// The original f does not have the key **k1**. Therefore, the value is the default value **kkk**.
println(f.get("k1") ?? "kkk")
0
}
Running result:
v1
v
v1
kkk
Usage of the URL Parsing Function parse
Uses parse to parse a URL string and generate a URL object.
Code:
In the example, a URL is parsed to obtain a URL object, and each property of the object is printed.
import encoding.url.*
main(): Int64 {
// Calls the URL static function parse to parse the URL and obtain the object named URL.
var url = URL.parse("http://www.example.com:80/path%E4%BB%93%E9%A2%89?key=value%E4%BB%93%E9%A2%89#%E4%BD%A0%E5%A5%BD")
// Prints the component properties of the URL.
println("url.scheme = ${url.scheme}")
println("url.opaque = ${url.opaque}")
println("url.userInfo = ${url.userInfo}")
println("url.rawUserInfo = ${url.rawUserInfo}")
println("url.hostName = ${url.hostName}")
println("url.port = ${url.port}")
println("url.path = ${url.path}")
println("url.rawPath = ${url.rawPath}")
println("url.query = ${url.query.getOrThrow()}")
println("url.rawQuery = ${url.rawQuery.getOrThrow()}")
println("url.fragment = ${url.fragment.getOrThrow()}")
println("url.rawfragment = ${url.rawFragment.getOrThrow()}")
println("url = ${url}")
return 0
}
Running result:
url.scheme = http
url.opaque =
url.userInfo =
url.rawUserInfo =
url.hostName = www.example.com
url.port = 80
url.path = /path Cangjie
url.rawPath = /path%E4%BB%93%E9%A2%89
url.query = key=value Cangjie
url.rawQuery = key=value%E4%BB%93%E9%A2%89
url.fragment = Hello
url.rawfragment = %E4%BD%A0%E5%A5%BD
url = http://www.example.com:80/path%E4%BB%93%E9%A2%89?key=value%E4%BB%93%E9%A2%89#%E4%BD%A0%E5%A5%BD
fuzz Module
Note:
The fuzzy module cannot be imported using the import fuzzy command. Otherwise, an error indicating that the fuzzy package cannot be found is reported during compilation. (error: can not find package'fuzz'). You are advised to import the fuzzy subpackage to use the fuzzy module.
Function Description
The fuzz module provides the fuzzing capability based on coverage feedback. It automatically generates a large amount of random input data to detect the stability and security of the target software in various exceptions.
Package List of the Fuzz Module
The fuzz module provides the following packages:
| Name | Description |
|---|---|
| fuzz | Provides developers with the fuzzing engine of Cangjie and corresponding APIs based on coverage feedback, so that the developers can compile code to test APIs. |
fuzz.fuzz Package
Function Description
Fuzzing is an automated software testing method designed to detect vulnerabilities and errors in software. It executes software programs by continuously inputting random or mutated test cases, and guides the test direction based on the program coverage information.
The fuzz package provides developers with the fuzz engine of Cangjie and corresponding APIs based on coverage feedback. Developers can compile code to test APIs. Currently, fuzzing can be performed through the byte stream (Array<UInt8>) mutated by the fuzzing engine or the standard data type (FuzzDataProvider) that complies with Cangjie.
This package must be used together with the coverage feedback instrumentation function (SanitizerCoverage). For beginners, learn to use the C language fuzz tool libFuzzer first.
This package depends on the libclang_rt.fuzzer_no_main.a static library provided by the LLVM suite compiler-rt. Currently, Linux and macOS are supported while Windows is not supported.
Generally, a package management tool can be used to install this package. For example, in Ubuntu 22.04, run the sudo apt install clang command to install this package. After the installation, the corresponding libclang_rt.fuzzer_no_main.a file (for example, /usr/lib/llvm-14/lib/clang/14.0.0/lib/linux/libclang_rt.fuzzer_no_main-x86_64.a) can be found in the directory specified by clang -print-runtime-dir, and it is used for file linking.
API List
Class
| Name | Description |
|---|---|
| Fuzzer | Provides the creation of fuzz tools. |
| FuzzerBuilder | Creates the Fuzzer class. |
| FuzzDataProvider | Specifies a tool class used to convert the byte stream of mutation data to standard Cangjie basic data. |
| DebugDataProvider | Inherits the DataProvider type and adds debugging information. |
Exception Class
| Name | Description |
|---|---|
| ExhaustedException | Specifies an exception thrown when the remaining data is insufficient for data conversion. |
Constants and Variables
let FUZZ_VERSION
public let FUZZ_VERSION = "1.0.0"
Description: Represents the fuzz version.
Type: String
Class
class DebugDataProvider
public class DebugDataProvider <: FuzzDataProvider
Description: Inherits the FuzzDataProvider type with additional debugging information.
Parent Type:
func consumeAll()
public override func consumeAll(): Array<UInt8>
Description: Converts all data into a UInt8 array.
Returns:
func consumeAllAsAscii()
public override func consumeAllAsAscii(): String
Description: Converts all data into the Ascii String type.
Returns:
func consumeAllAsString()
public override func consumeAllAsString(): String
Description: Converts all data into the utf8 String type.
Returns:
func consumeAsciiString(Int64)
public override func consumeAsciiString(maxLength: Int64): String
Description: Converts data into an Ascii String instance.
Parameters:
Returns:
func consumeBool()
public override func consumeBool(): Bool
Description: Converts data into a Bool instance.
Returns:
func consumeBools(Int64)
public override func consumeBools(count: Int64): Array<Bool>
Description: Converts a specified amount of data into a Bool array.
Parameters:
- count: Int64: amount of data to be converted.
Returns:
func consumeByte()
public override func consumeByte(): Byte
Description: Converts data into a Byte instance.
Returns:
func consumeBytes(Int64)
public override func consumeBytes(count: Int64): Array<Byte>
Description: Converts a specified amount of data into a Byte array.
Parameters:
- count: Int64: amount of data to be converted.
Returns:
func consumeFloat32()
public override func consumeFloat32(): Float32
Description: Converts data into a Float32 instance.
Returns:
func consumeFloat64()
public override func consumeFloat64(): Float64
Description: Converts data into a Float64 instance.
Returns:
func consumeInt16()
public override func consumeInt16(): Int16
Description: Converts data into an Int16 instance.
Returns:
func consumeInt16s(Int64)
public override func consumeInt16s(count: Int64): Array<Int16>
Description: Converts a specified amount of data into an Int16 array.
Parameters:
- count: Int64: amount of data to be converted.
Returns:
func consumeInt32()
public override func consumeInt32(): Int32
Description: Converts data to an Int32 instance.
Returns:
func consumeInt32s(Int64)
public override func consumeInt32s(count: Int64): Array<Int32>
Description: Converts a specified amount of data into an Int32 array.
Parameters:
- count: Int64: amount of data to be converted.
Returns:
func consumeInt64()
public override func consumeInt64(): Int64
Description: Converts data into an Int64 instance.
Returns:
func consumeInt64s(Int64)
public override func consumeInt64s(count: Int64): Array<Int64>
Description: Converts a specified amount of data into an Int64 array.
Parameters:
- count: Int64: amount of data to be converted.
Returns:
func consumeInt8()
public override func consumeInt8(): Int8
Description: Converts data into an Int8 instance.
Returns:
func consumeInt8s(Int64)
public override func consumeInt8s(count: Int64): Array<Int8>
Description: Converts a specified amount of data into an Int8 array.
Parameters:
- count: Int64: amount of data to be converted.
Returns:
func consumeRune()
public override func consumeRune(): Rune
Description: Converts data into a Rune instance.
Returns:
func consumeString(Int64)
public override func consumeString(maxLength: Int64): String
Description: Converts data into a utf8 String instance.
Parameters:
Returns:
func consumeUInt16()
public override func consumeUInt16(): UInt16
Description: Converts data into a UInt16 instance.
Returns:
func consumeUInt16s(Int64)
public override func consumeUInt16s(count: Int64): Array<UInt16>
Description: Converts a specified amount of data into a UInt16 array.
Parameters:
- count: Int64 - Specify the amount of data to be converted.
Returns:
func consumeUInt32()
public override func consumeUInt32(): UInt32
Description: Converts data into a UInt32 instance.
Returns:
func consumeUInt32s(Int64)
public override func consumeUInt32s(count: Int64): Array<UInt32>
Description: Converts a specified amount of data into a UInt32 array.
Parameters:
- count: Int64: amount of data to be converted.
Returns:
func consumeUInt64()
public override func consumeUInt64(): UInt64
Description: Converts data into a UInt64 instance.
Returns:
func consumeUInt64s(Int64)
public override func consumeUInt64s(count: Int64): Array<UInt64>
Description: Converts a specified amount of data into a UInt64 array.
Parameters:
- count: Int64: amount of data to be converted.
Returns:
func consumeUInt8()
public override func consumeUInt8(): UInt8
Description: Converts data into a UInt8 instance.
Returns:
func consumeUInt8s(Int64)
public override func consumeUInt8s(count: Int64): Array<UInt8>
Description: Converts a specified amount of data into a UInt8 array.
Parameters:
- count: Int64: amount of data to be converted.
Returns:
func wrap(FuzzDataProvider)
public static func wrap(dp: FuzzDataProvider): DebugDataProvider
Description: Creates a DebugDataProvider instance based on the FuzzDataProvider instance.
Parameters:
- dp: FuzzDataProvider: FuzzDataProvider type instance.
Returns:
- DebugDataProvider: type instance.
class Fuzzer
public class Fuzzer {
public init(targetFunction: (Array<UInt8>) -> Int32)
public init(targetFunction: (Array<UInt8>) -> Int32, args: Array<String>)
public init(targetFunction: (FuzzDataProvider) -> Int32)
public init(targetFunction: (FuzzDataProvider) -> Int32, args: Array<String>)
}
Description: Provides the creation of fuzzing tools. You can create Fuzzer of the corresponding type according to the function targetFunction for fuzzing and the specific parameters args, such as the fuzzing times, initial seed, and maximum length of generated data.
init((Array<UInt8>) -> Int32)
public init(targetFunction: (Array<UInt8>) -> Int32)
Description: Creates a Fuzzer instance according to the target function that takes the UInt8 array as a parameter and Int32 as a return value.
Parameters:
- targetFunction: (Array<UInt8>) ->Int32: the target function that takes the UInt8 array as a parameter and Int32 as a return value
init((Array<UInt8>) -> Int32, Array<String>)
public init(targetFunction: (Array<UInt8>) -> Int32, args: Array<String>)
Description: Creates a Fuzzer instance according to the target function that takes the UInt8 array as a parameter and Int32 as a return value, as well as the fuzzing parameters.
Parameters:
- targetFunction: (Array<UInt8>) ->Int32: the target function that takes the UInt8 array as a parameter and Int32 as a return value
- args: Array<String>: fuzzing parameters
init((FuzzDataProvider) -> Int32)
public init(targetFunction: (FuzzDataProvider) -> Int32)
Description: Creates a Fuzzer instance according to a target function that takes a FuzzDataProvider array as a parameter and Int32 as a return value.
Parameters:
- targetFunction: (FuzzDataProvider) ->Int32: target function that takes the FuzzDataProvider array as a parameter and Int32 as a return value.
init((FuzzDataProvider) -> Int32, Array<String>)
public init(targetFunction: (FuzzDataProvider) -> Int32, args: Array<String>)
Description: Creates a Fuzzer instance according a target function and fuzzing runtime parameters. The target function takes a FuzzDataProvider array as a parameter and Int32 as a return value.
Parameters:
- targetFunction: (FuzzDataProvider) ->Int32: target function that takes the FuzzDataProvider array as a parameter and Int32 as a return value****
- args: Array<String>: fuzzing parameters
func disableDebugDataProvider()
public func disableDebugDataProvider(): Unit
Description: Disables the debugging information printing function, so that when FuzzDataProvider.consumeXXX is called, the return value is not printed to stdout.
func disableFakeCoverage()
public func disableFakeCoverage(): Unit
Description: Disables the impact of calling enableFakeCoverage on fuzzing.
func enableDebugDataProvider()
public func enableDebugDataProvider(): Unit
Description: Enables the debugging information printing function, so that when FuzzDataProvider.consumeXXX is called, the return value is printed to stdout. This function is disabled by default.
func enableFakeCoverage()
public func enableFakeCoverage(): Unit
Description: Creates a false coverage feedback area to keep fuzzing ongoing. In the FuzzDataProvider mode, libfuzzer may exit for no coverage due to insufficient data in the first several rounds. This function is disabled by default.
func getArgs()
public func getArgs(): Array<String>
Description: Obtains fuzzing parameters.
Returns:
func setArgs(Array<String>)
public func setArgs(args: Array<String>): Unit
Description: Sets fuzzing parameters.
Parameters:
func setTargetFunction((Array<UInt8>) -> Int32)
public func setTargetFunction(targetFunction: (Array<UInt8>) -> Int32): Unit
Description: Sets a fuzzing target function.
Parameters:
- targetFunction: (Array<UInt8>) ->Int32: target function that takes the UInt8 array as a parameter and Int32 as a return value
func setTargetFunction((FuzzDataProvider) -> Int32)
public func setTargetFunction(targetFunction: (FuzzDataProvider) -> Int32): Unit
Description: Sets a fuzzing target function.
Parameters:
- targetFunction: (FuzzDataProvider) ->Int32: target function that takes the FuzzDataProvider array as a parameter and Int32 as a return value.
func startFuzz()
public func startFuzz(): Unit
Description: Performs fuzzing.
class FuzzerBuilder
public class FuzzerBuilder {
public init(targetFunction: (Array<UInt8>) -> Int32)
public init(targetFunction: (FuzzDataProvider) -> Int32)
}
Description: Creates the Fuzzer class.
init((Array<UInt8>) -> Int32)
public init(targetFunction: (Array<UInt8>) -> Int32)
Description: Creates a FuzzerBuilder instance according to the target function that takes the UInt8 array as a parameter and Int32 as a return value.
Parameters:
- targetFunction: (Array<UInt8>) ->Int32: target function that takes the UInt8 array as a parameter and Int32 as a return value
init((FuzzDataProvider) -> Int32)
public init(targetFunction: (FuzzDataProvider) -> Int32)
Description: Creates a FuzzerBuilder instance according to a target function that takes a FuzzDataProvider array as a parameter and Int32**** as a return value.
Parameters:
- targetFunction: (FuzzDataProvider) ->Int32: target function that takes the FuzzDataProvider array as a parameter and Int32 as a return value.
func build()
public func build(): Fuzzer
Description: Generates a Fuzzer instance.
Returns:
func setArgs(Array<String>)
public func setArgs(args: Array<String>): FuzzerBuilder
Description: Sets fuzzing parameters.
Parameters:
Returns:
- FuzzerBuilder: the current FuzzerBuilder instance
func setTargetFunction((Array<UInt8>) -> Int32)
public func setTargetFunction(targetFunction: (Array<UInt8>) -> Int32): FuzzerBuilder
Description: Sets a fuzzing target function.
Parameters:
- targetFunction: (Array<UInt8>) ->Int32: the target function that takes the UInt8 array as a parameter and Int32 as a return value
Returns:
- FuzzerBuilder: the current FuzzerBuilder instance
func setTargetFunction((FuzzDataProvider) -> Int32)
public func setTargetFunction(targetFunction: (FuzzDataProvider) -> Int32): FuzzerBuilder
Description: Sets a fuzzing target function.
Parameters:
- targetFunction: (FuzzDataProvider) ->Int32: target function that takes the FuzzDataProvider array as a parameter and Int32 as a return value.
Returns:
- FuzzerBuilder: the current FuzzerBuilder instance
class FuzzDataProvider
public open class FuzzDataProvider {
public let data: Array<UInt8>
public var remainingBytes: Int64
public var offset: Int64
}
Description: Specifies a tool class designed to convert the byte stream of mutated data into standard basic Cangjie data.
Currently, the following data structures are supported.
| Target Type | API | Description |
|---|---|---|
| Bool | consumeBool() | Obtains one Bool value. If the length of the mutated data is insufficient, ExhaustedException is thrown. |
| Array<Bool> | consumeBools(count: Int64) | Obtains N Bool values. If the mutated data is insufficient, ExhaustedException is thrown. |
| Byte | consumeByte() | Obtains one Byte value. If the mutated data is insufficient, ExhaustedException is thrown. |
| Array<Byte> | consumeBytes(count: Int64) | Obtains N Byte values. If the mutated data is insufficient, ExhaustedException is thrown. |
| UInt8 | consumeUInt8() | Obtains one UInt8 value. If the mutated data is insufficient, ExhaustedException is thrown. |
| UInt16 | consumeUInt16() | Obtains one UInt16 value. If the mutated data is insufficient, ExhaustedException is thrown. |
| UInt32 | consumeUInt32() | Obtains one UInt32 value. If the mutated data is insufficient, ExhaustedException is thrown. |
| UInt64 | consumeUInt64() | Obtains one UInt64 value. If the mutated data is insufficient, ExhaustedException is thrown. |
| Int8 | consumeInt8() | Obtains one Int8 value. If the mutated data is insufficient, ExhaustedException is thrown. |
| Int16 | consumeInt16() | Obtains one Int16 value. If the mutated data is insufficient, ExhaustedException is thrown. |
| Int32 | consumeInt32() | Obtains one Int32 value. If the mutated data is insufficient, ExhaustedException is thrown. |
| Int64 | consumeInt64() | Obtains one Int64 value. If the mutated data is insufficient, ExhaustedException is thrown. |
| Float32 | consumeFloat32() | Obtains one Float32 value. If the mutated data is insufficient, ExhaustedException is thrown. |
| Float64 | consumeFloat64() | Obtains one Float64 value. If the mutated data is insufficient, ExhaustedException is thrown. |
| Array<UInt8> | consumeUInt8s(count: Int64) | Obtains N UInt8 values. If the mutated data is insufficient, ExhaustedException is thrown. |
| Array<UInt16> | consumeUInt16s(count: Int64) | Obtains N UInt16 values. If the mutated data is insufficient, ExhaustedException is thrown. |
| Array<UInt32> | consumeUInt32s(count: Int64) | Obtains N UInt32 values. If the mutated data is insufficient, ExhaustedException is thrown. |
| Array<UInt64> | consumeUInt64s(count: Int64) | Obtains N UInt64 values. If the mutated data is insufficient, ExhaustedException is thrown. |
| Array<Int8> | consumeInt8s(count: Int64) | Obtains N Int8 values. If the mutated data is insufficient, ExhaustedException is thrown. |
| Array<Int16> | consumeInt16s(count: Int64) | Obtains N Int16 values. If the mutated data is insufficient, ExhaustedException is thrown. |
| Array<Int32> | consumeInt32s(count: Int64) | Obtains N Int32 values. If the mutated data is insufficient, ExhaustedException is thrown. |
| Array<Int64> | consumeInt64s(count: Int64) | Obtains N Int64 values. If the mutated data is insufficient, ExhaustedException is thrown. |
| Rune | consumeRune() | Obtains one Rune value. If the mutated data is insufficient, ExhaustedException is thrown. |
| String | consumeAsciiString(maxLength: Int64) | Obtains one pure ASCII String of length 0 to maxLength. The length can be 0. |
| String | consumeString(maxLength: Int64) | Obtains one UTF8 String of length 0 to maxLength. The length can be 0. |
| Array<UInt8> | consumeAll() | Converts the remaining data in FuzzDataProvider into a byte array. |
| String | consumeAllAsAscii() | Converts the remaining data in FuzzDataProvider into a pure ASCII String. |
| String | consumeAllAsString() | Converts the remaining data in FuzzDataProvider into a UTF8 String, leaving extra characters at the end unconsumed. |
When insufficient data is available, most of the above APIs will throw an ExhaustedException when called. However, during fuzz function development, it is usually unnecessary to handle this exception explicitly. By default, the fuzzing framework will capture ExhaustedException throws and inform libfuzzer that the current run is invalid, prompting the next mutation iteration. Over time, as execution progresses, the mutated data length will gradually increase until it meets the FuzzDataProvider requirement.
If max_len is reaches but the FuzzDataProvider requirement is still not met, the process exits. To resolve this, modify the fuzz test case (recommended) or increase the max_len (not recommended).
let data
public let data: Array<UInt8>
Description: Specifies the mutated data.
var offset
public var offset: Int64
Description: Specifies the number of bytes that have been converted.
Type: Int64
var remainingBytes
public var remainingBytes: Int64
Description: Specifies the number of bytes remaining to be converted.
Type: Int64
func consumeAll()
public open func consumeAll(): Array<UInt8>
Description: Converts all data into a UInt8 array.
Returns:
func consumeAllAsAscii()
public open func consumeAllAsAscii(): String
Description: Converts all data into an Ascii String.
Returns:
func consumeAllAsString()
public open func consumeAllAsString(): String
Description: Converts all data into a utf8 String.
Returns:
func consumeAsciiString(Int64)
public open func consumeAsciiString(maxLength: Int64): String
Description: Converts data into an ASCII String instance.
Parameters:
Returns:
func consumeBool()
public open func consumeBool(): Bool
Description: Converts data into a Bool instance.
Returns:
func consumeBools(Int64)
public open func consumeBools(count: Int64): Array<Bool>
Description: Converts a specified amount of data into a Bool array.
Parameters:
- count: Int64: amount of data to be converted.
Returns:
func consumeByte()
public open func consumeByte(): Byte
Description: Converts data into a Byte instance.
Returns:
func consumeBytes(Int64)
public open func consumeBytes(count: Int64): Array<Byte>
Description: Converts a specified amount of data into a Byte array.
Parameters:
- count: Int64: amount of data to be converted.
Returns:
func consumeFloat32()
public open func consumeFloat32(): Float32
Description: Converts data into a Float32 instance.
Returns:
func consumeFloat64()
public open func consumeFloat64(): Float64
Description: Converts data into a Float64 instance.
Returns:
func consumeInt16()
public open func consumeInt16(): Int16
Description: Converts data into an Int16 instance.
Returns:
func consumeInt16s(Int64)
public open func consumeInt16s(count: Int64): Array<Int16>
Description: Converts a specified amount of data into an Int16 array.
Parameters:
- count: Int64: amount of data to be converted.
Returns:
func consumeInt32()
public open func consumeInt32(): Int32
Description: Converts data into an Int32 instance.
Returns:
func consumeInt32s(Int64)
public open func consumeInt32s(count: Int64): Array<Int32>
Description: Converts a specified amount of data into an Int32 array.
Parameters:
- count: Int64: amount of data to be converted.
Returns:
func consumeInt64()
public open func consumeInt64(): Int64
Description: Converts data into an Int64 instance.
Returns:
func consumeInt64s(Int64)
public open func consumeInt64s(count: Int64): Array<Int64>
Description: Converts a specified amount of data into an Int64 array.
Parameters:
- count: Int64: amount of data to be converted.
Returns:
func consumeInt8()
public open func consumeInt8(): Int8
Description: Converts data into an Int8 instance.
Returns:
func consumeInt8s(Int64)
public open func consumeInt8s(count: Int64): Array<Int8>
Description: Converts a specified amount of data into an Int8 array.
Parameters:
- count: Int64: amount of data to be converted.
Returns:
func consumeRune()
public open func consumeRune(): Rune
Description: Converts data into a Rune instance.
Returns:
func consumeString(Int64)
public open func consumeString(maxLength: Int64): String
Description: Converts data into a utf8 String instance.
Parameters:
Returns:
func consumeUInt16()
public open func consumeUInt16(): UInt16
Description: Converts data into a UInt16 instance.
Returns:
func consumeUInt16s(Int64)
public open func consumeUInt16s(count: Int64): Array<UInt16>
Description: Converts a specified amount of data into a UInt16 array.
Parameters:
- count: Int64: amount of data to be converted.
Returns:
func consumeUInt32()
public open func consumeUInt32(): UInt32
Description: Converts data into a UInt32 instance.
Returns:
func consumeUInt32s(Int64)
public open func consumeUInt32s(count: Int64): Array<UInt32>
Description: Converts a specified amount of data into a UInt32 array.
Parameters:
- count: Int64: amount of data to be converted.
Returns:
func consumeUInt64()
public open func consumeUInt64(): UInt64
Description: Converts data into a UInt64 instance.
Returns:
func consumeUInt64s(Int64)
public open func consumeUInt64s(count: Int64): Array<UInt64>
Description: Converts a specified amount of data into a UInt64 array.
Parameters:
- count: Int64: amount of data to be converted.
Returns:
func consumeUInt8()
public open func consumeUInt8(): UInt8
Description: Converts data into a UInt8 instance.
Returns:
func consumeUInt8s(Int64)
public open func consumeUInt8s(count: Int64): Array<UInt8>
Description: Converts a specified amount of data into a UInt8 array.
Parameters:
- count: Int64: amount of data to be converted.
Returns:
static func withCangjieData(Array<UInt8>)
public static func withCangjieData(data: Array<UInt8>): FuzzDataProvider
Description: Generates a FuzzDataProvider instance using Array<UInt8> data.
Parameters:
Returns:
- FuzzDataProvider: constructed FuzzDataProvider instance.
static func withNativeData(CPointer<UInt8>, Int64)
public static unsafe func withNativeData(data: CPointer<UInt8>, length: Int64): FuzzDataProvider
Description: Generates a FuzzDataProvider instance using C pointer data.
Parameters:
Returns:
- FuzzDataProvider: constructed FuzzDataProvider instance.
Exception Class
class ExhaustedException
public class ExhaustedException <: Exception {
public init()
public init(message: String)
}
Description: Specifies an exception thrown when the remaining data is insufficient for data conversion.
Parent Type:
init()
public init()
Description: Creates an ExhaustedException instance.
init(String)
public init(message: String)
Description: Creates an ExhaustedException instance.
Parameters:
- message: String: exception information
Testing the Function of Guessing Characters
- Compiles the API to be tested. Only when the input array length is 8 and the content is the ASCII characters corresponding to "Cangjie!", an exception is thrown. In the case of random input, up to 264 guesses are performed to trigger an exception.
- Creates a fuzzer and calls the API to be tested to enter the main process.
// Imports the dependent class.
import fuzz.fuzz.Fuzzer
main() {
// Creates a fuzzer and starts the fuzzing process.
Fuzzer(api).startFuzz()
return 0
}
// Imports the tested function. An exception is thrown when specific conditions are met. The exception is captured by the fuzzer.
public func api(data: Array<UInt8>): Int32 {
if (data.size == 8 && data[0] == b'C' && data[1] == b'a' && data[2] == b'n' && data[3] == b'g' && data[4] == b'j' &&
data[5] == b'i' && data[6] == b'e' && data[7] == b'!') {
throw Exception("TRAP")
}
return 0
}
The compilation command for Linux is cjc fuzz_main.cj --link-options="--whole-archive $CANGJIE_HOME/lib/linux_x86_64_llvm/libclang_rt.fuzzer_no_main.a -no-whole-archive -lstdc++" --sanitizer-coverage-inline-8bit-counters.
The compilation command for macOS is cjc fuzz_main.cj --link-options="$CANGJIE_HOME/lib/linux_x86_64_llvm/libclang_rt.fuzzer_no_main.a -lc++" --sanitizer-coverage-inline-8bit-counters.
Description:
- The link-options is a link-time option. The fuzz library depends on the
LLVMFuzzerRunDriversymbol, which needs to be defined by developers.- Cangjie stores a modified libFuzzer in $CANGJIE_HOME/lib/linux_x86_64_llvm/libclang_rt.fuzzer_no_main.a. This libFuzzer is enhanced compared with the standard libFuzzer. For details, see Experimental Feature - Coverage Information Printing.
- Use the
find $(clang -print-runtime-dir) -name "libclang_rt.fuzzer_no_main*.a"command to search for the static library files installed on the local end.
whole-archive libfuzzer.ais required for Linux compilation because the basic libraries such aslibfuzzer.a,libcangjie-fuzz-fuzz.a, and libc are called from left to right when CJC calls the LD backend. As a result, theLLVMFuzzerRunDriversymbol on whichlibcangjie-fuzz-fuzz.adepends cannot be found. The solutions are as follows:- Place
libfuzzer.aafterlibcangjie-fuzz-fuzz.a. - Use
whole-archive libfuzzer.ato avoid the problem that symbols cannot be found.
- Place
-lstdc++(Linux) /-lc++(macOS) is used to link the std library on which libFuzzer depends.--sanitizer-coverage-inline-8bit-countersis a compilation option ofcjcand performs coverage feedback instrumentation on the currentpackage. For details, see the CJC compiler user guide.- Other advanced parameters include
--sanitizer-coverage-trace-compares(for improving fuzzing mutation efficiency) and--sanitizer-coverage-pc-table(for printing coverage information after fuzzing).
- Other advanced parameters include
Similar to libfuzzer, it can run directly. After several seconds (depending on the CPU performance), a crash occurs and the input data is "Cangjie!".
Running result:
$ ./main
INFO: Seed: 246468919
INFO: Loaded 1 modules (15 inline 8-bit counters): 15 [0x55bb7c76dcb0, 0x55bb7c76dcbf),
INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
INFO: A corpus is not provided, starting from an empty corpus
#2 INITED ft: 4 corp: 1/1b exec/s: 0 rss: 28Mb
#420 NEW ft: 5 corp: 2/9b lim: 8 exec/s: 0 rss: 28Mb L: 8/8 MS: 3 CrossOver-InsertByte-InsertRepeatedBytes-
#1323 NEW ft: 6 corp: 3/17b lim: 14 exec/s: 0 rss: 28Mb L: 8/8 MS: 3 InsertByte-InsertByte-CrossOver-
#131072 pulse ft: 6 corp: 3/17b lim: 1300 exec/s: 65536 rss: 35Mb
#262144 pulse ft: 6 corp: 3/17b lim: 2600 exec/s: 65536 rss: 41Mb
#295225 NEW ft: 7 corp: 4/25b lim: 2930 exec/s: 73806 rss: 43Mb L: 8/8 MS: 2 ShuffleBytes-ChangeByte-
#514006 NEW ft: 8 corp: 5/33b lim: 4096 exec/s: 73429 rss: 53Mb L: 8/8 MS: 1 ChangeByte-
#524288 pulse ft: 8 corp: 5/33b lim: 4096 exec/s: 74898 rss: 53Mb
#1048576 pulse ft: 8 corp: 5/33b lim: 4096 exec/s: 61680 rss: 78Mb
#1064377 NEW ft: 9 corp: 6/41b lim: 4096 exec/s: 62610 rss: 79Mb L: 8/8 MS: 1 ChangeByte-
#1287268 NEW ft: 10 corp: 7/49b lim: 4096 exec/s: 61298 rss: 90Mb L: 8/8 MS: 1 ChangeByte-
#2097152 pulse ft: 10 corp: 7/49b lim: 4096 exec/s: 59918 rss: 128Mb
#2875430 NEW ft: 11 corp: 8/57b lim: 4096 exec/s: 61179 rss: 165Mb L: 8/8 MS: 2 ChangeBinInt-ChangeByte-
#4194304 pulse ft: 11 corp: 8/57b lim: 4096 exec/s: 59918 rss: 227Mb
#4208258 NEW ft: 12 corp: 9/65b lim: 4096 exec/s: 60117 rss: 228Mb L: 8/8 MS: 3 CrossOver-CrossOver-ChangeBit-
[WARNING]: Detect uncatched exception, maybe caused by bugs, exit now
An exception has occurred:
Exception: TRAP
at default.api(std/core::Array<...>)(/data/Cangjie/fuzz_main.cj:14)
at _ZN7default3apiER_ZN8std$core5ArrayIhE_cc_wrapper(/data/Cangjie/fuzz_main.cj:0)
at libfuzzerCallback(fuzz/fuzz/callback.cj:20)
[INFO]: data is: [67, 97, 110, 103, 106, 105, 101, 33]
[INFO]: data base64: Q2FuZ2ppZSE=
crash file will stored with libfuzzer
==899957== ERROR: libFuzzer: fuzz target exited
SUMMARY: libFuzzer: fuzz target exited
MS: 1 ChangeByte-; base unit: 7d8b0108ce76a937161065eafcde95bbf3d47dbf
0x43,0x61,0x6e,0x67,0x6a,0x69,0x65,0x21,
Cangjie!
artifact_prefix='./'; Test unit written to ./crash-555e7af32a2ceb585cdd9ce810c4804e65d41cea
Base64: Q2FuZ2ppZSE=
Usage of the cj-fuzz Function by CJVM
Difference Description
CJVM cannot load the .a files, and it can only load the .so files.
cj-fuzz depends on libclang_rt.fuzzer_no_main.a and libcangjie-fuzz-fuzzFFI.a, for which a dynamic link library should be generated by running the following command:
clang++ -shared -Wl,--whole-archive libclang_rt.fuzzer_no_main.a ${CANGJIE_HOME}/lib/linux_x86_64_jet/libcangjie-fuzz-fuzzFFI.a -Wl,--no-whole-archive -o libcangjie-fuzz-fuzzFFI.so
Running cj-fuzz
- Run the preceding command to obtain
libcangjie-fuzz-fuzzFFI.so. cjc fuzz_main.cj --sanitizer-coverage-inline-8bit-counters ${CANGJIE_HOME}/modules/linux_x86_64_jet/fuzz/fuzz.bc -lcangjie-fuzz-fuzzFFI:--sanitizer-coverage-inline-8bit-counters: Enables coverage instrumentation.${CANGJIE_HOME}/modules/linux_x86_64_jet/fuzz/fuzz.bc: Proactively links to the bytecode of the fuzz package of the fuzz module.-lcangjie-fuzz-fuzzFFI: Specifies the name of the dependency library. During the running, libcangjie-fuzz-fuzzFFI.so is searched for dynamic loading.
LD_LIBRARY_PATH=/path/to/lib:${LD_LIBRARY_PATH} cj main.cbc:- Modifies LD_LIBRARY_PATH as required.
- Executes the CBC file.
The actual effect is as follows:
cp /usr/lib/llvm-14/lib/clang/14.0.0/lib/linux/libclang_rt.fuzzer_no_main-x86_64.a .
clang++ -shared -Wl,--whole-archive libclang_rt.fuzzer_no_main-x86_64.a ${CANGJIE_HOME}/lib/linux_x86_64_jet/libcangjie-fuzz-fuzzFFI.a -Wl,--no-whole-archive -o libcangjie-fuzz-fuzzFFI.so
cjc --sanitizer-coverage-inline-8bit-counters fuzz_main.cj ${CANGJIE_HOME}/modules/linux_x86_64_jet/fuzz/fuzz.bc -lcangjie-fuzz-fuzzFFI
LD_LIBRARY_PATH=/path/to/lib:${LD_LIBRARY_PATH} cj main.cbc
>>>>
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 3156944264
INFO: Loaded 1 modules (21 inline 8-bit counters): 21 [0x5627041690a0, 0x5627041690b5),
INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
INFO: A corpus is not provided, starting from an empty corpus
#2 INITED ft: 4 corp: 1/1b exec/s: 0 rss: 52Mb
#488 NEW ft: 5 corp: 2/9b lim: 8 exec/s: 0 rss: 53Mb L: 8/8 MS: 1 InsertRepeatedBytes-
#12303 NEW ft: 6 corp: 3/17b lim: 122 exec/s: 0 rss: 54Mb L: 8/8 MS: 5 CrossOver-ChangeBit-ShuffleBytes-ShuffleBytes-ChangeByte-
#20164 NEW ft: 7 corp: 4/25b lim: 198 exec/s: 0 rss: 54Mb L: 8/8 MS: 1 ChangeByte-
#180030 NEW ft: 8 corp: 5/33b lim: 1780 exec/s: 180030 rss: 55Mb L: 8/8 MS: 1 ChangeByte-
#524288 pulse ft: 8 corp: 5/33b lim: 4096 exec/s: 174762 rss: 55Mb
#671045 NEW ft: 9 corp: 6/41b lim: 4096 exec/s: 167761 rss: 55Mb L: 8/8 MS: 5 InsertByte-ChangeByte-ChangeBit-ChangeByte-EraseBytes-
#758816 NEW ft: 10 corp: 7/49b lim: 4096 exec/s: 151763 rss: 55Mb L: 8/8 MS: 1 ChangeByte-
#1048576 pulse ft: 10 corp: 7/49b lim: 4096 exec/s: 149796 rss: 55Mb
#1947938 NEW ft: 11 corp: 8/57b lim: 4096 exec/s: 162328 rss: 55Mb L: 8/8 MS: 2 InsertByte-EraseBytes-
#2097152 pulse ft: 11 corp: 8/57b lim: 4096 exec/s: 161319 rss: 55Mb
#3332055 NEW ft: 12 corp: 9/65b lim: 4096 exec/s: 151457 rss: 55Mb L: 8/8 MS: 2 ChangeByte-ChangeBit-
[WARNING]: Detect uncatched exception, maybe caused by bugs, exit now
An exception has occurred:
Exception: TRAP
at default.api(/cjvm_demo/test.cj:20)
at default.api(/cjvm_demo/test.cj:0)
at fuzz/fuzz.libfuzzerCallback(/cangjie/lib/src/fuzz/fuzz/callback.cj:34)
at fuzz/fuzz.Fuzzer.startFuzz(/cangjie/lib/src/fuzz/fuzz/fuzzer.cj:223)
at default.<main>(/cjvm_demo/test.cj:5)
at default.user.main(<unknown>:0)
[INFO]: data is: [67, 97, 110, 103, 106, 105, 101, 33]
[INFO]: crash file will stored with libfuzzer
==33946== ERROR: libFuzzer: fuzz target exited
SUMMARY: libFuzzer: fuzz target exited
MS: 1 ChangeByte-; base unit: 1719c2c0bbc676f5b436528c183e4743a455d66a
0x43,0x61,0x6e,0x67,0x6a,0x69,0x65,0x21,
Cangjie!
artifact_prefix='./'; Test unit written to ./crash-555e7af32a2ceb585cdd9ce810c4804e65d41cea
Base64: Q2FuZ2ppZSE=
Testing by Using the DataProvider Function
In addition to the method of testing APIs using byte streams, the fuzz package provides the FuzzDataProvider class to generate standard data types from mutated data sources more friendly, facilitating API testing.
public func api2(dp: FuzzDataProvider): Int32 {
if(dp.consumeBool() && dp.consumeByte() == b'A' && dp.consumeuint32() == 0xdeadbeef){
throw Exception("TRAP")
}
return 0
}
In this case, --sanitizer-coverage-trace-compares can effectively improve the fuzzing efficiency.
In DataProvider mode, the return value of each API cannot be checked. Therefore, Fuzzer.enableDebugDataProvider() and DebugDataProvider are provided. Call enableDebugDataProvider() before startFuzz to print logs each time consumeXXX is called during fuzzing.
For example, after the preceding code triggers an exception, add enableDebugDataProvider and recompile the code. The result is as follows:
import fuzz.fuzz.*
main() {
let fuzzer = Fuzzer(api2)
fuzzer.enableDebugDataProvider()
fuzzer.startFuzz()
return 0
}
Running result:
./main crash-d7ece8e77ff25769a5d55eb8d3093d4bace78e1b
Running: crash-d7ece8e77ff25769a5d55eb8d3093d4bace78e1b
[DEBUG] consumeBool return true
[DEBUG] consumeByte return 65
[DEBUG] consumeUInt32 return 3735928559
[WARNING]: Detect uncatched exception, maybe caused by bugs, exit now
An exception has occurred:
Exception: TRAP
at default.api2(fuzz/fuzz::FuzzDataProvider)(/tmp/test.cj:12)
at _ZN7default4api2EC_ZN9fuzz$fuzz16FuzzDataProviderE_cc_wrapper(/tmp/test.cj:0)
at libfuzzerCallback(fuzz/fuzz/callback.cj:0)
[INFO]: data is: [191, 65, 239, 190, 173, 222]
Using FakeCoverage to Prevent Abnormal Termination of Fuzzing in DataProvider Mode
When libfuzzer <= 14 is linked and in DataProvider mode, read this section if an error similar to the following occurs:
ERROR: no interesting inputs were found. Is the code instrumented for coverage? Exiting.
Since libfuzzer 15, this feature has been fixed so that the execution does not stop even if the input is rejected during initialization.
Note: Ensure that coverage feedback is inserted into the tested library. This error occurs when no coverage feedback instrumentation is available.
Currently, the fuzz backend is connected to libFuzzer. When libFuzzer is started, an empty byte stream is input first, and then a byte stream containing only one '\n' is input to probe the function to be tested. After the two inputs, the coverage is checked for its increase. In DataProvider mode, if data is consumed before the API of the library to be tested is called, the data is returned in advance due to insufficient data length. As a result, libFuzzer considers that the coverage is zero.
For example, the following code triggers this error:
Code that triggers the error:
// main.cj
import fuzz.fuzz.*
main() {
let f = Fuzzer(api)
f.disableFakeCoverage()
f.startFuzz()
return 0
}
// fuzz_target.cj, with sancov
public func api(dp: FuzzDataProvider): Int32 {
if (dp.consumeBool() && dp.consumeBool()) {
throw Exception("TRAP!")
}
return 0
}
Running result:
...
ERROR: no interesting inputs were found. Is the code instrumented for coverage? Exiting.
...
Therefore, Fake Coverage needs to be used to create false coverage information so that libFuzzer considers that the module to be tested is instrumented during initialization. After DataProvider collects sufficient data, effective fuzzing can be performed. This mode is called the Fake Coverage mode.
Replace disableFakeCoverage() with enableFakeCoverage() to continue fuzzing and trigger the trap.
In addition to the Fake Coverage mode, some unimportant APIs of the function to be tested can be called in the test case to transfer the coverage information to libFuzzer. This also enables fuzzing to continue.
// main.cj
import fuzz.fuzz.*
main() {
let f = Fuzzer(api)
f.enableFakeCoverage()
f.startFuzz()
return 0
}
// fuzz_target.cj, with sancov
public func api(dp: FuzzDataProvider): Int32 {
if (dp.consumeBool() && dp.consumeBool()) {
throw Exception("TRAP!")
}
return 0
}
Running result:
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 3187548846
INFO: Loaded 2 modules (8 inline 8-bit counters): 7 [0x55bf83ea8790, 0x55bf83ea8797), 1 [0x55bf83e97b00, 0x55bf83e97b01),
INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
INFO: A corpus is not provided, starting from an empty corpus
#2 INITED ft: 5 corp: 1/1b exec/s: 0 rss: 33Mb
#9 NEW ft: 6 corp: 2/2b lim: 4 exec/s: 0 rss: 33Mb L: 1/1 MS: 2 CopyPart-ChangeByte-
[WARNING]: Detect uncatched exception, maybe caused by bugs, exit now
An exception has occurred:
Exception: TRAP!
...
...
Printing the Usage of Fuzz
Use -help=1 to print help information and -seed=246468919 to specify the seed of a random number.
Running result:
$ ./main -help=1 exit 130
Usage:
To run fuzzing pass 0 or more directories.
program_name [-flag1=val1 [-flag2=val2 ...] ] [dir1 [dir2 ...] ]
To run individual tests without fuzzing pass 1 or more files:
program_name [-flag1=val1 [-flag2=val2 ...] ] file1 [file2 ...]
Experimental Feature - Coverage Information Printing
The Cangjie fuzzer can use -print_coverage=1 as the startup parameter to run the fuzzer and collect statistics on the test status of functions. This feature, which has been continuously optimized, is related only to the output coverage report and does not affect the fuzzing process.
This function requires intrusive modification of libFuzzer. To use this function, link to the built-in libFuzzer (path: $CANGJIE_HOME/lib/{linux_x86_64_llvm, linux_aarch64_llvm}/libclang_rt-fuzzer_no_main.a).
Enable both --sanitizer-coverage-inline-8bit-counters and --sanitizer-coverage-pc-table during compilation.
Example of output by libFuzzer in the C language
./a.out -print_coverage=1
COVERAGE:
COVERED_FUNC: hits: 5 edges: 6/8 LLVMFuzzerTestOneInput /tmp/test.cpp:5
UNCOVERED_PC: /tmp/test.cpp:6
UNCOVERED_PC: /tmp/test.cpp:9
Example of output by CJ-Fuzz in Cangjie language
./main -print_coverage=1 -runs=100
Done 100 runs in 0 second(s)
COVERAGE:
COVERED_FUNC: hits: 1 edges: 3/12 ttt <unknown cj filename>:<unknown cj line number>
UNCOVERED_PC: <unknown cj filename>:<unknown cj line number>
UNCOVERED_PC: <unknown cj filename>:<unknown cj line number>
UNCOVERED_PC: <unknown cj filename>:<unknown cj line number>
UNCOVERED_PC: <unknown cj filename>:<unknown cj line number>
UNCOVERED_PC: <unknown cj filename>:<unknown cj line number>
UNCOVERED_PC: <unknown cj filename>:<unknown cj line number>
UNCOVERED_PC: <unknown cj filename>:<unknown cj line number>
UNCOVERED_PC: <unknown cj filename>:<unknown cj line number>
UNCOVERED_PC: <unknown cj filename>:<unknown cj line number>
UNCOVERED_FUNC: hits: 0 edges: 0/2 main <unknown cj filename>:<unknown cj line number>
COVERED_FUNC: hits: 1 edges: 1/1 ttt_cc_wrapper <unknown cj filename>:<unknown cj line number>
Solution to Missing Stack Backtracking
Currently, the following three warnings are displayed by default when fuzzing is started, because the following three functions are currently not implemented in cj-fuzz.
WARNING: Failed to find function "__sanitizer_acquire_crash_state".
WARNING: Failed to find function "__sanitizer_print_stack_trace".
WARNING: Failed to find function "__sanitizer_set_death_callback".
The fuzzing process may end in the following three cases:
- An exception is thrown.
- A timeout error occurs.
- The program crashes in C language when a library written in C language is called by Cangjie language.
If an exception is thrown, the fuzz framework prints stack backtracking after capturing the exception. Therefore, stack backtracking will not be missing.
Timeout and C program crash are caused because SIGNAL is triggered in the native code, and they are not exceptions in Cangjie. As a result, stack backtracking is missing.
libFuzzer attempts to use functions such as __sanitizer_acquire_crash_state, __sanitizer_print_stack_trace, and __sanitizer_set_death_callback to handle exceptions. __sanitizer_print_stack_trace prints stack backtracking. Currently, these functions are implemented in the asan module of llvm compiler-rt.
Therefore, it is advised to add the following static library files and link options during linking:
/usr/lib/llvm-14/lib/clang/14.0.0/lib/linux/libclang_rt.asan-x86_64.a -lgcc_s --eh-frame-hdr
/usr/lib/llvm-14/lib/clang/14.0.0/lib/linux/libclang_rt.asan-x86_64.a: The .a file implements__sanitizer_print_stack_trace. Therefore, it is directly used for convenience.-lgcc_sstack backtracking depends on gcc_s.- The eh_frame_hdr section is generated during
--eh-frame-hdrld linking to help complete stack backtracking.
Optional environment variable: ASAN_SYMBOLIZER_PATH=$CANGJIE_HOME/third_party/llvm/bin/llvm-symbolizer, which may be useful in some cases.
Two sets of stack backtracking are obtained: Exception.printStackTrace and __sanitizer_print_stack_trace. The content is as follows:
[WARNING]: Detect uncatched exception, maybe caused by bugs, exit now
An exception has occurred:
Exception: TRAP!
at default.ttt(std/core::Array<...>)(/data/cangjie/libs/fuzz/ci_fuzzer0.cj:11)
at _ZN7default3tttER_ZN8std$core5ArrayIhE_cc_wrapper(/data/cangjie/libs/fuzz/ci_fuzzer0.cj:0)
at libfuzzerCallback(/data/cangjie/libs/fuzz/fuzz/callback.cj:34)
[INFO]: data is: [0, 202, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]
[INFO]: crash file will stored with libfuzzer
==425243== ERROR: libFuzzer: fuzz target exited
#0 0x563a233fadf1 in __sanitizer_print_stack_trace (/data/cangjie/libs/fuzz/main+0x280df1)
#1 0x563a2337c0b8 in fuzzer::PrintStackTrace() (/data/cangjie/libs/fuzz/main+0x2020b8)
#2 0x563a2338726c in fuzzer::Fuzzer::ExitCallback() (/data/cangjie/libs/fuzz/main+0x20d26c)
#3 0x7f485cf36494 in __run_exit_handlers stdlib/exit.c:113:8
#4 0x7f485cf3660f in exit stdlib/exit.c:143:3
#5 0x563a23224e68 in libfuzzerCallback$real /data/cangjie/libs/fuzz/fuzz/callback.cj:62:18
#6 0x7f485d22718b in CJ_MCC_N2CStub (/data/cangjie/output/runtime/lib/linux_x86_64_llvm/libcangjie-runtime.so+0x2718b)
#7 0x563a2322fc26 in libfuzzerCallback /data/cangjie/libs/fuzz/fuzz/callback.cj:20
#8 0x563a23387883 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/data/cangjie/libs/fuzz/main+0x20d883)
#9 0x563a2338a3f9 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) (/data/cangjie/libs/fuzz/main+0x2103f9)
#10 0x563a23387e49 in fuzzer::Fuzzer::MutateAndTestOne() (/data/cangjie/libs/fuzz/main+0x20de49)
#11 0x563a2338a2b5 in fuzzer::Fuzzer::Loop(std::vector<fuzzer::SizedFile, std::allocator<fuzzer::SizedFile>>&) (/data/cangjie/libs/fuzz/main+0x2102b5)
#12 0x563a23377a12 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/data/cangjie/libs/fuzz/main+0x1fda12)
#13 0x563a231ad2b6 in fuzz_fake$fuzz::Fuzzer::startFuzz() /data/cangjie/libs/fuzz/fuzz/fuzzer.cj:200:13
#14 0x563a23405fad in default::main() /data/cangjie/libs/fuzz/ci_fuzzer0.cj:5:5
#15 0x563a23405fe7 in user.main /data/cangjie/libs/fuzz/<stdin>
#16 0x563a234060e1 in cj_entry$ (/data/cangjie/libs/fuzz/main+0x28c0e1)
#17 0x7f485d227220 (/data/cangjie/output/runtime/lib/linux_x86_64_llvm/libcangjie-runtime.so+0x27220)
#18 0x7f485d223898 (/data/cangjie/output/runtime/lib/linux_x86_64_llvm/libcangjie-runtime.so+0x23898)
#19 0x7f485d2607b9 in CJ_CJThreadEntry (/data/cangjie/output/runtime/lib/linux_x86_64_llvm/libcangjie-runtime.so+0x607b9)
log Module
Function Description
The log module provides functions for managing and printing logs.
Package List of the log Module
The log module provides the following packages:
| Name | Description |
|---|---|
| log | Provides a single log API that abstracts actual log implementation. |
Log Package
Function Description
The log package provides a single log API that abstracts the actual log implementation.
API List
Function
| Name | Description |
|---|---|
| getGlobalLogger(Array<Attr>) | Obtains a global Logger object. |
| setGlobalLogger(Logger) | Sets a global Logger object. |
Type Alias
| Name | Description |
|---|---|
| Attr | Specifies the key-value pair type of a log message, which is the type alias of (String, LogValue). |
Interface
| Name | Description |
|---|---|
| LogValue | Provides an interface for serializing a Cangjie data type to a log output target. |
Class
| Name | Description |
|---|---|
| Logger | Provides basic log printing and management functions. |
| LogRecord | Records log messages. |
| LogWriter | Provides the capability of serializing a Cangjie data type to a log output target. |
| NoopLogger | Implementats NO-OP of Logger. |
Struct
| Name | Description |
|---|---|
| LogLevel | Specifies the log level struct. |
Exception Class
| Name | Description |
|---|---|
| LogException | Handles log-related exceptions. |
Type Alias
type Attr
public type Attr = (String, LogValue)
Description: Specifies the key-value pair type of a log message, which is the type alias of (String, LogValue).
Function
func getGlobalLogger(Array<Attr>)
public func getGlobalLogger(attrs: Array<Attr>): Logger
Description: Obtains a Logger object.
If the attrs parameter is not transferred, the same Logger object is obtained. If the attrs parameter is transferred, a copy of the Logger object containing the specified properties is created.
Parameters:
- attrs: Array<Attr>: log data key-value pair properties, which are contained in the obtained Logger object.
Returns:
func setGlobalLogger(Logger)
public func setGlobalLogger(logger: Logger): Unit
Description: Sets a global Logger object.
Note that this function should be called only once during the lifecycle of the program. Any log events that occur before setGlobalLogger is called are ignored.
This function does not need to be manually called. The log implementation provider should provide the initialization method that contains the method to call this method.
Parameters:
Interface
interface LogValue
public interface LogValue {
func writeTo(w: LogWriter): Unit
}
Description: Provides an interface for serializing a type to the log output target.
This interface is used together with LogWriter. LogWriter can use writeValue to write the types that implement the LogValue interface to the log output target.
func writeTo(LogWriter)
func writeTo(w: LogWriter): Unit
Description: Writes the type that implements the LogValue interface to the LogWriter instance specified by the w parameter.
Parameters:
extend Bool <: LogValue
extend Bool <: LogValue
Description: Implements the LogValue interface for the Bool type.
Parent Type:
func writeTo(LogWriter)
public func writeTo(w: LogWriter): Unit
Description: Serializes the Bool type to a stream.
Parameters:
extend Exception <: LogValue
extend Exception <: LogValue
Description: Implements the LogValue interface for the Exception type.
Parent Type:
func writeTo(LogWriter)
public func writeTo(w: LogWriter): Unit
Description: Serializes the Exception type to a stream.
Parameters:
extend Int64 <: LogValue
extend Int64 <: LogValue
Description: Implements the LogValue interface for the Int64 type.
Parent Type:
func writeTo(LogWriter)
public func writeTo(w: LogWriter): Unit
Description: Serializes the Int64 type to a stream.
Parameters:
extend Float64 <: LogValue
extend Float64 <: LogValue
Description: Implements the LogValue interface for the Float64 type.
Parent Type:
func writeTo(LogWriter)
public func writeTo(w: LogWriter): Unit
Description: Serializes the Float64 type to a stream.
Parameters:
extend String <: LogValue
extend String <: LogValue
Description: Implements the LogValue interface for the String type.
Parent Type:
func writeTo(LogWriter)
public func writeTo(w: LogWriter): Unit
Description: Serializes the String type to a stream.
Parameters:
extend DateTime <: LogValue
extend DateTime <: LogValue
Description: Implements the LogValue interface for the DateTime type.
Parent Type:
func writeTo(LogWriter)
public func writeTo(w: LogWriter): Unit
Description: Serializes the DateTime type to a stream.
Parameters:
extend Duration <: LogValue
extend Duration <: LogValue
Description: Implements the LogValue interface for the Duration type.
Parent Type:
func writeTo(LogWriter)
public func writeTo(w: LogWriter): Unit
Description: Serializes the Duration type to a stream.
Parameters:
extend Array <: LogValue
extend<T> Array<T> <: LogValue where T <: LogValue
Description: Implements the LogValue interface for the Array<T> type.
Parent Type:
func writeTo(LogWriter)
public func writeTo(w: LogWriter): Unit
Description: Serializes the Array<T> type to a stream.
Parameters:
extend HashMap <: LogValue
extend<K, V> HashMap<K, V> <: LogValue where K <: String, V <: LogValue
Description: Implements the LogValue interface for the HashMap<K, V> type.
Parent Type:
func writeTo(LogWriter)
public func writeTo(w: LogWriter): Unit
Description: Serializes the HashMap<K, V> type to a stream.
Parameters:
extend TreeMap <: LogValue
extend<K, V> TreeMap<K, V> <: LogValue where K <: String, V <: LogValue
Description: Implements the LogValue interface for the TreeMap<K, V> type.
Parent Type:
func writeTo(LogWriter)
public func writeTo(w: LogWriter): Unit
Description: Serializes the TreeMap<K, V> type to a stream.
Parameters:
extend Option <: LogValue
extend<T> Option<T> <: LogValue where T <: LogValue
Description: Implements the LogValue interface for the Option<T> type.
Parent Type:
func writeTo(LogWriter)
public func writeTo(w: LogWriter): Unit
Description: Serializes the Option<T> type to a stream.
Parameters:
Class
class Logger
public abstract class Logger <: Resource {
public mut open prop level: LogLevel
public open func withAttrs(attrs: Array<Attr>): Logger
public open func log(record: LogRecord): Unit
public func enabled(level: LogLevel): Bool
public open func log(level: LogLevel, message: String, attrs: Array<Attr>): Unit
public open func log(level: LogLevel, message: () -> String, attrs: Array<Attr>): Unit
public func fatal(message: String, attrs: Array<Attr>): Unit
public func fatal(message: () -> String, attrs: Array<Attr>): Unit
public func error(message: String, attrs: Array<Attr>): Unit
public func error(message: () -> String, attrs: Array<Attr>): Unit
public func warn(message: String, attrs: Array<Attr>): Unit
public func warn(message: () -> String, attrs: Array<Attr>): Unit
public func info(message: String, attrs: Array<Attr>): Unit
public func info(message: () -> String, attrs: Array<Attr>): Unit
public func debug(message: String, attrs: Array<Attr>): Unit
public func debug(message: () -> String, attrs: Array<Attr>): Unit
public func trace(message: String, attrs: Array<Attr>): Unit
public func trace(message: () -> String, attrs: Array<Attr>): Unit
}
Description: Provides basic log printing and management functions.
Parent Type:
prop level
public mut open prop level: LogLevel
Description: Obtains and modifies the logging level.
Type: LogLevel
func debug(String, Array<Attr>)
public func debug(message: String, attrs: Array<Attr>): Unit
Description: Prints DEBUG-level logs.
Parameters:
func debug(() -> String, Array<Attr>)
public func debug(message: () -> String, attrs: Array<Attr>): Unit
Description: Prints DEBUG-level logs.
Parameters:
func enabled(LogLevel)
public func enabled(level: LogLevel): Bool
Description: Determines whether to record log messages of a specified log level.
This function allows a caller to determine whether logs will be discarded in advance to avoid time-consuming log message parameter calculation.
Parameters:
- level: LogLevel: log level
Returns:
- Bool: Returns
trueif the specified log level is enabled; otherwise, returnsfalse.
func error(String, Array<Attr>)
public func error(message: String, attrs: Array<Attr>): Unit
Description: Prints ERROR-level logs.
Parameters:
func error(() -> String, Array<Attr>)
public func error(message: () -> String, attrs: Array<Attr>): Unit
Description: Prints ERROR-level logs.
Parameters:
func fatal(String, Array<Attr>)
public func fatal(message: String, attrs: Array<Attr>): Unit
Description: Prints FATAL-level logs.
Parameters:
func fatal(() -> String, Array<Attr>)
public func fatal(message: () -> String, attrs: Array<Attr>): Unit
Description: Prints FATAL-level logs.
Parameters:
func info(String, Array<Attr>)
public func info(message: String, attrs: Array<Attr>): Unit
Description: Prints INFO-level logs.
Parameters:
func info(() -> String, Array<Attr>)
public func info(message: () -> String, attrs: Array<Attr>): Unit
Description: Prints INFO-level logs.
Parameters:
func log(LogLevel, String, Array<Attr>)
public open func log(level: LogLevel, message: String, attrs: Array<Attr>): Unit
Description: Specifies a common function for printing logs. The log level must be specified.
Parameters:
- level: LogLevel: log level
- message: String: log message
- attrs: Array<Attr>: log data key-value pairs
func log(LogLevel, () -> String, Array<Attr>)
public open func log(level: LogLevel, message: () -> String, attrs: Array<Attr>): Unit
Description: Specifies a common function for printing logs. The log level must be specified.
Parameters:
- level: LogLevel: log level
- message: () -> String: log message
- attrs: Array<Attr>: log data key-value pairs
func log(LogRecord)
public open func log(record: LogRecord): Unit
Description: Prints logs.
Parameters:
- record: LogRecord: log level
func trace(String, Array<Attr>)
public func trace(message: String, attrs: Array<Attr>): Unit
Description: Prints TRACE-level logs.
Parameters:
func trace(() -> String, Array<Attr>)
public func trace(message: () -> String, attrs: Array<Attr>): Unit
Description: Prints TRACE-level logs.
Parameters:
func warn(String, Array<Attr>)
public func warn(message: String, attrs: Array<Attr>): Unit
Description: Prints WARN-level logs.
Parameters:
func warn(() -> String, Array<Attr>)
public func warn(message: () -> String, attrs: Array<Attr>): Unit
Description: Prints WARN-level logs.
Parameters:
func withAttrs(Array<Attr>)
public open func withAttrs(attrs: Array<Attr>): Logger
Description: Creates a copy of the current object. The new copy contains the specified attributes.
Parameters:
Returns:
class LogRecord
public class LogRecord {
public init(time: DateTime, level: LogLevel, msg: String, attrs: Array<Attr>)
public prop time: DateTime
public prop level: LogLevel
public mut prop message: String
public mut prop attrs: Array<Attr>
public func clone(): LogRecord
}
Description: Represents a log message.
The recorded structure is passed as a parameter to the log method of the Logger class. The log provider processes these structures to display the log messages. Records are automatically created by log objects and therefore are invisible to log users.
init(DateTime, LogLevel, String, Array<Attr>)
public init(time: DateTime, level: LogLevel, msg: String, attrs: Array<Attr>)
Description: Creates a LogRecord instance and specifies the timestamp, logging level, log message, and log data key-value pair.
Parameters:
- time: DateTime: timestamp when a log is recorded
- level: LogLevel: log level
- msg: String: log message
- attrs: Array<Attr>: log data key-value pairs
prop attrs
public mut prop attrs: Array<Attr>
Description: Obtains or sets log data key-value pairs.
prop level
public prop level: LogLevel
Description: Obtains the logging level. Only logs whose levels are lower than or equal to the value of this parameter are printed.
Type: LogLevel
prop message
public mut prop message: String
Description: Obtains or sets log messages.
Type: String
prop time
public prop time: DateTime
Description: Obtains the timestamp when a log is printed.
Type: DateTime
func clone()
public func clone(): LogRecord
Description: Creates a copy of the current object.
Returns:
- LogRecord: the copy of the current object
class LogWriter
public abstract class LogWriter {
public func writeNone(): Unit
public func writeInt(v: Int64): Unit
public func writeUInt(v: UInt64): Unit
public func writeBool(v: Bool): Unit
public func writeFloat(v: Float64): Unit
public func writeString(v: String): Unit
public func writeDateTime(v: DateTime): Unit
public func writeDuration(v: Duration): Unit
public func writeKey(v: String): Unit
public func writeValue(v: LogValue): Unit
public func startArray(): Unit
public func endArray(): Unit
public func startObject(): Unit
public func endObject(): Unit
}
Description: Provides the capability of serializing Cangjie objects into log output targets.
LogWriter must be used together with interface LogValue. LogWriter can use the writeValue methods to write the types that implement the LogValue interface to the log output target.
func endArray()
public func endArray(): Unit
Description: Ends the serialization of the current LogValue array.
Throws:
- IllegalStateException: If the current writer does not have a matched startArray, this exception is thrown.
func endObject()
public func endObject(): Unit
Description: Ends the serialization of the current LogValue object.
Throws:
- IllegalStateException: If a LogValue object should not be ended according to the current writer status, this exception is thrown.
func startArray()
public func startArray(): Unit
Description: Starts to serialize a new LogValue array. Each startArray must correspond to an endArray.
Throws:
- IllegalStateException: If a LogValue array should not be written according to the current writer status, this exception is thrown.
func startObject()
public func startObject(): Unit
Description: Starts to serialize a new LogValue object. Each startObject must correspond to an endObject.
Throws:
- IllegalStateException: If a LogValue object should not be written according to the current writer status, this exception is thrown.
func writeBool(Bool)
public func writeBool(v: Bool): Unit
Description: Writes the Bool value to the log output target.
Parameters:
Throws:
- IllegalStateException: If the value should not be written to the log output target according to the current writer status, this exception is thrown.
func writeFloat(Float64)
public func writeFloat(v: Float64): Unit
Description: Writes the Float64 value to the log output target.
Parameters:
Throws:
- IllegalStateException: If the value should not be written to the log output target according to the current writer status, this exception is thrown.
func writeDateTime(DateTime)
public func writeDateTime(v: DateTime): Unit
Description: Writes the DateTime value to the log output target.
Parameters:
Throws:
- IllegalStateException: If the value should not be written to the log output target according to the current writer status, this exception is thrown.
func writeDuration(Duration)
public func writeDuration(v: Duration): Unit
Description: Writes the Duration value to the log output target.
Parameters:
Throws:
- IllegalStateException: If the value should not be written to the log output target according to the current writer status, this exception is thrown.
func writeException(Exception)
public func writeException(v: Exception): Unit
Description: Writes the Exception value to the log output target.
Parameters:
Throws:
- IllegalStateException: If the value should not be written to the log output target according to the current writer status, this exception is thrown.
func writeInt(Int64)
public func writeInt(v: Int64): Unit
Description: Writes the Int64 value to the log output target.
Parameters:
Throws:
- IllegalStateException: If the value should not be written to the log output target according to the current writer status, this exception is thrown.
func writeKey(String)
public func writeKey(v: String): Unit
Description: Writes a name to the log output target.
Parameters:
- v: String: key value to be written
Throws:
- IllegalStateException: If the current writer status should not be written into the string specified by the
nameparameter, this exception is thrown.
func writeNone()
public func writeNone(): Unit
Description: Writes None to the log output target. The format is determined by the logger provider.
Throws:
- IllegalStateException: If the value should not be written to the log output target according to the current writer status, this exception is thrown.
func writeString(String)
public func writeString(v: String): Unit
Description: Writes the String value to the log output target.
Parameters:
Throws:
- IllegalStateException: If the value should not be written to the log output target according to the current writer status, this exception is thrown.
func writeValue(LogValue)
public func writeValue(v: LogValue): Unit
Description: Writes the type that implements the LogValue interface to the log output target. This interface calls the writeTo method of LogValue to write data to the log output target.
The log package has implemented LogValue for the extension of the basic types Int64, Float64, Bool and String, and has implemented LogValue for the extension of the DateTime, Duration, Collection types Array, HashMap, TreeMap, and Option<T>.
Parameters:
Throws:
- IllegalStateException: If the value should not be written to the log output target according to the current writer status, this exception is thrown.
class NoopLogger
public class NoopLogger <: Logger {
public init()
public prop level: LogLevel
public func log(record: LogRecord): Unit
public func log(level: LogLevel, message: String, attrs: Array<Attr>): Unit
public func log(level: LogLevel, message: () -> String, attrs: Array<Attr>): Unit
public func withAttrs(attrs: Array<Attr>): Logger
public func isClosed(): Bool
public func close(): Unit
}
Description: Specifies the NO-OP implementation of Logger, which discards all logs.
Parent Type:
init()
public init()
Description: Creates a NoopLogger instance.
prop level
public mut prop level: LogLevel
Description: Only obtains the OFF logging level. The logging level setting does not take effect.
Type: LogLevel
func close()
public func close(): Unit
Description: Implements NOOP.
func isClosed()
public func isClosed(): Bool
Description: Implements NOOP.
Returns:
- Bool.
func log(LogLevel, String, Array<Attr>)
public func log(level: LogLevel, message: String, attrs: Array<Attr>): Unit
Description: Implements NOOP.
Parameters:
- level: LogLevel: log level
- message: String: log message
- attrs: Array<Attr>: log data key-value pairs
func log(LogLevel, () -> String, Array<Attr>)
public func log(level: LogLevel, message: () -> String, attrs: Array<Attr>): Unit
Description: Implements NOOP.
Parameters:
- level: LogLevel: log level
- message: () -> String: log message
- attrs: Array<Attr>: log data key-value pairs
func log(LogRecord)
public func log(record: LogRecord): Unit
Description: Implements NOOP.
Parameters:
- record: LogRecord: log level
func withAttrs(Array<Attr>)
public func withAttrs(attrs: Array<Attr>): Logger
Description: Implements NOOP.
Parameters:
Struct
struct LogLevel
public struct LogLevel <: ToString & Comparable<LogLevel>
Description: Specifies the log level struct.
Seven logging levels are defined, which are OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, and ALL in ascending order.
It is expected that only log entries whose levels are lower than or equal to the specified logging level will be printed to the output stream.
Parent Type:
let name: String
public let name: String
Description: Specifies the log level name.
let value: Int32
public let value: Int32
Description: Specifies the log level value.
init(String, Int32)
public const init(name: String, value: Int32)
Description: Specifies a constructor of constants, which is used to create the LogLevel object.
Parameters:
static const ALL
public static const ALL = LogLevel("ALL", -0x8000_0000)
Description: Obtains a static constant instance of the logging level of ALL.
static const DEBUG
public static const DEBUG = LogLevel("DEBUG", 2000)
Description: Obtains a static constant instance of the logging level of DEBUG.
static const ERROR
public static const ERROR = LogLevel("ERROR", 5000)
Description: Obtains a static constant instance of the logging level of ERROR.
static const FATAL
public static const FATAL = LogLevel("FATAL", 6000)
Description: Obtains a static constant instance of the logging level of FATAL.
static const INFO
public static const INFO = LogLevel("INFO", 3000)
Description: Obtains a static constant instance of the logging level of INFO.
static const OFF
public static const OFF = LogLevel("OFF", 0x7FFF_FFFF)
Description: Obtains a static constant instance of the logging level of OFF.
static const TRACE
public static const TRACE = LogLevel("TRACE", 1000)
Description: Obtains a static constant instance of the logging level of TRACE.
static const WARN
public static const WARN = LogLevel("WARN", 4000)
Description: Obtains a static constant instance of the logging level of WARN.
func compare(LogLevel)
public func compare(rhs: LogLevel): Ordering
Description: Checks the size relationship between the current LogLevel type instance and the LogLevel type instance pointed by parameters.
Parameters:
- that: LogLevel: the other instance to be compared with the current instance
Returns:
- Ordering: If the current instance is greater than the other instance, Ordering.GT is returned. If the current instance is equal to the other instance, Ordering.EQ is returned. If the current instance is less than the other instance, Ordering.LT is returned.
func toString()
public func toString(): String
Description: Obtains the name of a log level.
Returns:
- String: name of the current log level
operator func ==(LogLevel)
public operator func ==(rhs: LogLevel): Bool
Description: Compares two log levels.
Parameters:
- rhs: LogLevel:
targetto be compared with the current log level
Returns:
- Bool: If the current log level is equal to
target,trueis returned. Otherwise,falseis returned.
operator func !=(LogLevel)
public operator func !=(rhs: LogLevel): Bool
Description: Compares two log levels.
Parameters:
- rhs: LogLevel:
targetto be compared with the current log level
Returns:
- Bool: If the current log level is not equal to
target,trueis returned. Otherwise,falseis returned.
operator func >=(LogLevel)
public operator func >=(rhs: LogLevel): Bool
Description: Compares two log levels.
Parameters:
- rhs: LogLevel:
targetto be compared with the current log level
Returns:
- Bool: If the current log level is higher than or equal to
target,trueis returned. Otherwise,falseis returned.
operator func <=(LogLevel)
public operator func <=(rhs: LogLevel): Bool
Description: Compares two log levels.
Parameters:
- rhs: LogLevel:
targetto be compared with the current log level
Returns:
- Bool: If the current log level is lower than or equal to
target,trueis returned. Otherwise,falseis returned.
operator func >(LogLevel)
public operator func >(rhs: LogLevel): Bool
Description: Compares two log levels.
Parameters:
- rhs: LogLevel:
targetto be compared with the current log level
Returns:
- Bool: If the current log level is higher than
target,trueis returned. Otherwise,falseis returned.
operator func <(LogLevel)
public operator func <(rhs: LogLevel): Bool
Description: Compares two log levels.
Parameters:
- rhs: LogLevel:
targetto be compared with the current log level
Returns:
- Bool: If the current log level is lower than
target,trueis returned. Otherwise,falseis returned.
Exception Class
class LogException
public open class LogException <: Exception
Description: Handles log-related exceptions.
Parent Type:
init()
public init()
Description: Specifies a constructor without parameters.
init(String)
public init(message: String)
Description: Creates a LogException instance according to exception information.
Parameters:
- message: String: exception information
Log Printing Example
Log Recording in the Library Development Scenario
The following is an example of printing logs during the development of a Cangjie library.
Code:
import log.*
public class PGConnection {
let objId: Int64 = 1
let logger = getGlobalLogger(("name", "PGConnection"))
public func close(): Unit {
logger.trace("driver conn closed", ("id", objId))
}
}
Running result:
2021/08/05 08:20:42.696645 TRACE msg="driver conn closed" id=1 name="PGConnection"
Log Printing in the Application Development Scenario
The following is an example of user-defined PasswordFilter and TextLogger log printing.
Code:
import std.time.*
import std.io.{OutputStream, ByteArrayStream, BufferedOutputStream}
import std.console.Console
import std.fs.*
import std.collection.{ArrayList, Map, HashMap}
import std.collection.concurrent.NonBlockingQueue
import std.sync.AtomicBool
import std.time.{Duration, DateTime}
import log.{LogValue, LogWriter, Logger, Attr, LogRecord, LogLevel}
import log
public class PasswordFilter <: Logger {
var _level = LogLevel.INFO
let processor: Logger
public init(logger: Logger) {
processor = logger
}
public mut prop level: LogLevel {
get() {
_level
}
set(v) {
_level = v
}
}
public func withAttrs(attrs: Array<Attr>): Logger {
this
}
// log
public func log(level: LogLevel, message: String, attrs: Array<Attr>): Unit {
let record: LogRecord = LogRecord(DateTime.now(), level, message, attrs)
log(record)
}
// lazy
public func log(level: LogLevel, message: () -> String, attrs: Array<Attr>): Unit {
let record: LogRecord = LogRecord(DateTime.now(), level, message(), attrs)
log(record)
}
// Filters by key-value pair name and changes the password value to "*****".
public func log(record: LogRecord): Unit {
var attrs = record.attrs.clone()
for (i in 0..attrs.size) {
var attr = attrs[i]
if (attr[0] == "password") {
attrs[i] = (attr[0], "***")
}
}
let r = LogRecord(record.time, record.level, record.message, attrs)
processor.log(r)
}
public func isClosed(): Bool {
false
}
public func close(): Unit {
}
}
main() {
let o = ByteArrayStream()
let tl = TextLogger(Console.stdOut)
tl.level = LogLevel.TRACE
let l = PasswordFilter(tl)
log.setGlobalLogger(l)
let logger = log.getGlobalLogger([("name", "main")])
let user = User()
// Common information log.
logger.info("Hello, World!", ("k1", [[1, 4], [2, 5], [3]]), ("password", "v22222"))
// Records diagnostic logs. If the **DEBUG** level is disabled, this function is returned and the log information is not actually written to the output file.
logger.debug("Logging in user ${user.name} with birthday ${user.birthdayCalendar}")
// Records time consumption logs in lazy mode.
logger.log(LogLevel.ERROR, "long-running operation msg", ("k1", 100), ("k2", user.birthdayCalendar),
("oper", ToStringWrapper({=> "Some long-running operation returned"})))
logger.log(LogLevel.ERROR, "long-running operation msg", ("sourcePackage", @sourcePackage()),
("sourceFile", @sourceFile()), ("sourceLine", @sourceLine()), ("birthdayCalendar", user.birthdayCalendar),
("oper", ToStringWrapper({=> "Some long-running operation returned"})))
let m = HashMap<String, String>()
m.put("k1", "1")
m.put("k2", "2")
m.put("k3", "3")
logger.trace({=> "Some long-running operation returned"}, ("k1", m))
let m2 = HashMap<String, LogValue>()
m2.put("g1", m)
// If the **TRACE** level is disabled, the lambda expression is not executed.
logger.trace({=> "Some long-running operation returned"}, ("k2", m2))
// Console.stdOut.write(o.bytes())
// Console.stdOut.flush()
}
public class User {
public prop name: String {
get() {
"foo"
}
}
public prop birthdayCalendar: DateTime {
get() {
DateTime.now()
}
}
}
public class ToStringWrapper <: ToString & LogValue {
let _fn: () -> String
public init(fn: () -> String) {
_fn = fn
}
public func toString(): String {
return _fn()
}
public func writeTo(w: LogWriter): Unit {
w.writeValue(_fn())
}
}
func expensiveOperation(): String {
for (i in 0..1000000) {
unsafe {
let b = LibC.malloc<Byte>(count: 1000)
LibC.free(b)
}
}
"Some long-running operation returned"
}
public class TextLogger <: Logger {
let w: TextLogWriter
let opts = HashMap<String, String>()
let _closed = AtomicBool(false)
let queue = NonBlockingQueue<LogRecord>()
let bo: BufferedOutputStream<OutputStream>
let _attrs = ArrayList<Attr>()
var _level = LogLevel.INFO
public init(output: OutputStream) {
bo = BufferedOutputStream<OutputStream>(output)
w = TextLogWriter(bo)
}
public mut prop level: LogLevel {
get() {
_level
}
set(v) {
_level = v
}
}
public func withAttrs(attrs: Array<Attr>): Logger {
if (attrs.size > 0) {
let nl = TextLogger(w.out)
nl._attrs.appendAll(attrs)
return nl
}
return this
}
// log
public func log(level: LogLevel, message: String, attrs: Array<Attr>): Unit {
if (this.enabled(level)) {
let record: LogRecord = LogRecord(DateTime.now(), level, message, attrs)
log(record)
}
}
// lazy
public func log(level: LogLevel, message: () -> String, attrs: Array<Attr>): Unit {
if (this.enabled(level)) {
let record: LogRecord = LogRecord(DateTime.now(), level, message(), attrs)
log(record)
}
}
public func log(record: LogRecord): Unit {
// write time
w.writeKey("time")
w.writeValue(record.time)
w.writeString(" ")
// write level
w.writeKey("level")
w.writeString(record.level.toString())
w.writeString(" ")
// write message
w.writeKey("msg")
w.writeValue(record.message)
w.writeString(" ")
// write source
// write attrs
for (i in 0..record.attrs.size) {
let attr = record.attrs[i]
w.writeKey(attr[0])
w.writeValue(attr[1])
if (i < record.attrs.size - 1) {
w.writeString(" ")
}
}
w.writeString("\n")
bo.flush()
}
public func isClosed(): Bool {
_closed.load()
}
public func close(): Unit {
if (isClosed()) {
return
}
_closed.store(true)
}
}
class TextLogWriter <: LogWriter {
var out: OutputStream
init(out: OutputStream) {
this.out = out
}
public func writeNone(): Unit {
out.write("None".toArray())
}
public func writeInt(v: Int64): Unit {
out.write(v.toString().toArray())
}
public func writeUInt(v: UInt64): Unit {
out.write(v.toString().toArray())
}
public func writeBool(v: Bool): Unit {
out.write(v.toString().toArray())
}
public func writeFloat(v: Float64): Unit {
out.write(v.toString().toArray())
}
public func writeString(v: String): Unit {
out.write(v.toArray())
}
public func writeDateTime(v: DateTime): Unit {
out.write(v.toString().toArray())
}
public func writeDuration(v: Duration): Unit {
out.write(v.toString().toArray())
}
public func writeKey(v: String): Unit {
out.write(v.toString().toArray())
out.write("=".toArray())
}
public func writeValue(v: LogValue): Unit {
match (v) {
case vv: String =>
out.write("\"".toArray())
out.write(vv.toArray())
out.write("\"".toArray())
case vv: ToString =>
out.write("\"".toArray())
out.write(vv.toString().toArray())
out.write("\"".toArray())
case _ =>
out.write("\"".toArray())
v.writeTo(this)
out.write("\"".toArray())
}
}
public func startArray(): Unit {
out.write("[".toArray())
}
public func endArray(): Unit {
out.write("]".toArray())
}
public func startObject(): Unit {
out.write("{".toArray())
}
public func endObject(): Unit {
out.write("}".toArray())
}
}
Running result:
time="2024-06-17T14:10:07.1861349Z" level=INFO msg="Hello, World!" k1="[[1, 4], [2, 5], [3]]" password="***"
time="2024-06-17T14:10:07.1864929Z" level=DEBUG msg="Logging in user foo with birthday 2024-06-17T14:10:07.1864802Z"
time="2024-06-17T14:10:07.1869579Z" level=ERROR msg="long-running operation msg" k1="100" k2="2024-06-17T14:10:07.186957Z" oper="Some long-running operation returned"
time="2024-06-17T14:10:07.18742Z" level=ERROR msg="long-running operation msg" sourcePackage="log" sourceFile="main.cj" sourceLine="76" birthdayCalendar="2024-06-17T14:10:07.1874188Z" oper="Some long-running operation returned"
time="2024-06-17T14:10:07.1879195Z" level=TRACE msg="Some long-running operation returned" k1="[(k1, 1), (k2, 2), (k3, 3)]"
time="2024-06-17T14:10:07.1881599Z" level=TRACE msg="Some long-running operation returned" k2="{g1="[(k1, 1), (k2, 2), (k3, 3)]"}"
net Module
Note:
Do not import the net module by running the import net command. Otherwise, an error indicating that the net package cannot be found will be reported during compilation (error: can not find package 'net'). You are advised to import the net subpackage to use the net module.
Function Description
The net module provides capabilities related to network communication.
At the HTTP application layer, the net module supports the implementation of HTTP/1.1, HTTP/2, or WebSocket on a client or server.
At the TLS transport layer, the net module supports the encrypted network communication based on TLS 1.2 or TLS 1.3.
Package List of the net Module
The net module provides the following packages:
| Name | Description |
|---|---|
| http | Supports the implementation of the HTTP/1.1, HTTP/2, and WebSocket protocols on a server or client. |
| tls | Provides capabilities such as creating TLS servers, performing TLS handshakes based on protocols, sending and receiving encrypted data, and restoring TLS sessions, and is used for secure encrypted network communication. |
net.http Package
Function Description
The HTTP package provides the server and client implementation of the HTTP/1.1, HTTP/2, and WebSocket protocols.
For details about the protocols, see RFC 9110, 9112, 9113, 9218, and 7541.
This package depends on the SSL and crypto dynamic library files of OpenSSL 3. Therefore, related tools must be installed in advance.
- For
Linux, perform the following operations:- Install the
OpenSSL 3development tool package using the package management tool of the system if the tool supports the installation, and ensure that the system installation directory contains thelibssl.so,libssl.so.3,libcrypto.so, andlibcrypto.so.3dynamic library files. For example, onUbuntu 22.04, run thesudo apt install libssl-devcommand to install thelibssl-devtool package. - Download and install the
OpenSSL 3.*x*.*x*source code compilation software package if the preceding method fails, and ensure that the installation directory contains thelibssl.so,libssl.so.3,libcrypto.so, andlibcrypto.so.3dynamic library files. Then, use either of the following methods to ensure that the system linker can find these files:- Install OpenSSL in the system path if it has not been installed in the system.
- Set the directory where the OpenSSL development tool package files are located to the environment variables
LD_LIBRARY_PATHandLIBRARY_PATHif OpenSSL is installed in a user-defined directory.
- Install the
- For
Windows, perform the following operations:- Download and install the
OpenSSL 3.*x*.*x*source code compilation software package for the x64 architecture, or download and install theOpenSSL 3.*x*.*x*software package precompiled by a third party for developers. - Ensure that the installation directory contains the
libssl.dll.a(orlibssl.lib),libssl-3-x64.dll,libcrypto.dll.a(orlibcrypto.lib), andlibcrypto-3-x64.dlllibrary files. - Set the directory containing
libssl.dll.a(orlibssl.lib) andlibcrypto.dll.a(orlibcrypto.lib) to the environment variableLIBRARY_PATH, and the directory containinglibssl-3-x64.dllandlibcrypto-3-x64.dllto the environment variablePATH.
- Download and install the
- For
macOS, perform the following operations:- Run the
brew install openssl@3command to install OpenSSL, and ensure that the system installation directory contains thelibcrypto.dylibandlibcrypto.3.dylibdynamic library files. - Download and install the
OpenSSL 3.*x*.*x*source code compilation software package if the preceding method fails, and ensure that the installation directory contains thelibcrypto.dylibandlibcrypto.3.dylibdynamic library files. Then, use either of the following methods to ensure that the system linker can find these files:- Install OpenSSL in the system path if it has not been installed in the system.
- Set the directory where the OpenSSL development tool package files are located to the environment variables
DYLD_LIBRARY_PATHandLIBRARY_PATHif OpenSSL is installed in a user-defined directory.
- Run the
If OpenSSL 3 is not installed or an earlier version is installed, the program may fail to work with a TLS-related exception thrown.
http
The user can select the HTTP version, for example, HTTP/1.1 or HTTP/2. Most APIs of HTTP packets support both protocol versions. The two protocol versions need to be distinguished only when a user uses a specific function of a version, for example, chunked transfer-encoding in HTTP/1.1 and server push in HTTP/2.
The HTTP library uses HTTP/1.1 by default. To use HTTP/2, the developer needs to configure TLS for the client and server and set ALPN to h2. HTTP/1.1 cannot be upgraded to HTTP/2 through Upgrade: h2c.
If the handshake for creating an HTTP/2 connection fails, the client and server automatically fall back to HTTP/1.1.
-
The user uses ClientBuilder to create a Client instance with multiple parameters available, such as httpProxy, logger, cookieJar, redirect, and connection pool size.
-
The user uses ServerBuilder to create a Server instance with multiple parameters available, such as addr, port, logger, and distributor.
A user-defined logger must be thread-safe.
Most parameters of the client and server cannot be modified after construction. To modify these parameters, a new Client or Server instance must be constructed. This implementation provides explicit functions for parameters that can be dynamically modified, such as cert and CA hot update on the server.
-
A user can use a Client instance to send HTTP requests and receive HTTP responses.
-
A user can use a Server instance to configure the request forwarding processor and start the HTTP server. In the server handler, the user can obtain the detailed information about the request sent by the client through HttpContext and construct the response to be sent to the client. The server creates a ProtocolService instance based on the client's request. A Server instance supports both HTTP/1.1 and HTTP/2.
-
On the client, the user uses HttpRequestBuilder to construct a request with multiple parameters available, such as method, URL, version, headers, body, and trailers. A request cannot be modified after construction.
-
On the server, the user uses HttpResponseBuilder to construct a response with multiple parameters available, such as status, headers, body, and trailers. A response cannot be modified after construction.
In addition, this implementation provides some tool classes for users to construct common responses. For example, a user can use RedirectHandler to construct a redirect response, and use NotFoundHandler to construct a 404 response.
WebSocket
This implementation provides sub-protocol negotiation for WebSocket, including basic frame decoding, reading, message sending, frame encoding, ping, pong, and closing.
The user uses WebSocket.upgradeFromClient to upgrade HTTP/1.1 or HTTP/2 used by a Client instance to WebSocket, and then uses the returned WebSocket instance for WebSocket communication.
In a handler on the server, the user uses WebSocket.upgradeFromServer to upgrade HTTP/1.1 or HTTP/2 to WebSocket, and then uses the returned WebSocket instance for WebSocket communication.
According to the protocol, in HTTP/1.1, the upgraded WebSocket connection is established on the TCP/TLS connection. In HTTP/2, the upgraded WebSocket connection is established on a stream of the HTTP/2 connection. In HTTP/1.1, the close operation directly closes the TCP/TLS connection. In HTTP/2, the close operation closes only a stream on the connection.
API List
Function
| Name | Description |
|---|---|
| handleError(HttpContext, UInt16) | Specifies a shortcut HTTP request processing function used to return error requests. |
| notFound(HttpContext) | Specifies a shortcut HTTP request processing function used to return the 404 response. |
| upgrade(HttpContext) | Obtains StreamingSocket from the handler to support protocol upgrade and process CONNECT requests. |
Interface
| Name | Description |
|---|---|
| CookieJar | Specifies a tool used by the client to manage cookies. |
| HttpRequestDistributor | Specifies an HTTP request distributor interface used to distribute a request to the corresponding HttpRequestHandler based on the path in the URL. |
| HttpRequestHandler | Specifies an HTTP request handler. |
| ProtocolServiceFactory | Sets the HTTP service instance factory used to generate ProtocolService instances. |
Class
| Name | Description |
|---|---|
| Client | Specifies the Client class. A user can use a Client instance to send HTTP/1.1 or HTTP/2 requests. |
| ClientBuilder | Constructs Client instances. Since there is no public constructor for Client instance construction, the user can obtain Client instances only by using ClientBuilder. If the ClientBuilder document does not specify the supported version, the configuration is valid in both HTTP/1.1 and HTTP/2. |
| Cookie | HTTP is stateless. To obtain the client status and provide personalized services, the server can use Cookie to maintain a stateful session. |
| FileHandler | Handles file download or upload. |
| FuncHandler | Specifies the HttpRequestHandler interface wrapper class, which wraps a single function into an HttpRequestHandler. |
| HttpContext | Specifies the HTTP request context used as a parameter of the HttpRequestHandler.handle function on the server. |
| HttpHeaders | Indicates the header and trailer in an HTTP packet with the add, delete, modify, and query operations defined. |
| HttpRequest | Specifies the HTTP request class. |
| HttpRequestBuilder | Specifies the HttpRequestBuilder class used to construct HttpRequest instances. |
| HttpResponse | Specifies the HTTP response class. |
| HttpResponseBuilder | Constructs an HttpResponse instance. |
| HttpResponsePusher | Sets the HTTP/2 server push. |
| HttpResponseWriter | Specifies the HTTP response message body writer, which allows a user to control the sending process of the message body. |
| NotFoundHandler | Specifies a convenient HTTP request handler and 404 Not Found handler. |
| OptionsHandler | Specifies a convenient HTTP handler used to process OPTIONS requests. The "Allow: OPTIONS, GET, HEAD, POST, PUT, or DELETE" response header is always returned. |
| ProtocolService | Specifies an HTTP service instance, which provides HTTP services for a single client connection, including parsing client request packets, distributing requests, and sending responses. |
| RedirectHandler | Specifies a convenient HTTP handler used to return redirection responses. |
| Server | Specifies the server class providing the HTTP service. |
| ServerBuilder | Provides a server instance builder. |
| WebSocket | Provides classes related to the WebSocket service and read, write, and close functions for the WebSocket connection. The user can use the upgradeFrom function to obtain a WebSocket connection. |
| WebSocketFrame | Specifies the basic unit used by WebSocket for reading. |
Enumeration
| Name | Description |
|---|---|
| FileHandlerType | Sets the FileHandler mode to upload or download. |
| Protocol | Defines the HTTP protocol type enumeration. |
| WebSocketFrameType | Defines the enumeration types of WebSocketFrame. |
Struct
| Name | Description |
|---|---|
| HttpStatusCode | Specifies a 3-digit code indicating the response status of Hypertext Transfer Protocol (HTTP) of the web server. |
| ServicePoolConfig | Configures the HTTP server coroutine pool. |
| TransportConfig | Specifies a transport layer configuration class used by the server to establish a connection. |
Exception Class
| Name | Description |
|---|---|
| ConnectionException | Specifies the TCP connection exception class of HTTP. |
| CoroutinePoolRejectException | Specifies the exception class of HTTP coroutine pool rejecting processing requests. |
| HttpException | Specifies the common exception class of HTTP. |
| HttpStatusException | Specifies the response status exception class of HTTP. |
| HttpTimeoutException | Specifies the timeout exception class of HTTP. |
| WebSocketException | Specifies the common exception class of WebSocket. |
Function
func handleError(HttpContext, UInt16)
public func handleError(ctx: HttpContext, code: UInt16): Unit
Description: Specifies a shortcut HTTP request processing function used to return error requests.
Parameters:
- ctx: HttpContext: HTTP request context
- code: UInt16: HTTP response code
func notFound(HttpContext)
public func notFound(ctx: HttpContext): Unit
Description: Specifies a shortcut HTTP request processing function used to return the 404 response.
Parameters:
- ctx: HttpContext: HTTP request context
func upgrade(HttpContext)
public func upgrade(ctx: HttpContext): StreamingSocket
Description: Obtains StreamingSocket in the handler to support protocol upgrade and process CONNECT requests.
- When this function is called, a response is sent based on ctx.responseBuilder. Only the status code and response header are sent.
- When this function is called, ctx.request.body is left empty and data can no longer be read through body.read(...). The body data that is not read is stored in the returned StreamingSocket.
Parameters:
- ctx: HttpContext: request context
Returns:
- StreamingSocket: underlying connection (or a stream for HTTP/2) used for subsequent read and write
Throws:
- HttpException: If the underlying connection (or the stream for HTTP/2) fails to be obtained, this exception is thrown.
Interface
interface CookieJar
public interface CookieJar {
prop isHttp: Bool
prop rejectPublicSuffixes: ArrayList<String>
static func createDefaultCookieJar(rejectPublicSuffixes: ArrayList<String>, isHttp: Bool): CookieJar
static func parseSetCookieHeader(response: HttpResponse): ArrayList<Cookie>
static func toCookieString(cookies: ArrayList<Cookie>): String
func clear(): Unit
func getCookies(url: URL): ArrayList<Cookie>
func removeCookies(domain: String): Unit
func storeCookies(url: URL, cookies: ArrayList<Cookie>): Unit
}
Description: The CookieJar is used by the Client to manage the Cookie.
It has two static functions:
- toCookieString: converts ArrayList<Cookie> to a string to set the Cookie header of a request.
- parseSetCookieHeader: parses the
Set-Cookieheader in the received response.
If CookieJar is configured for Client, Cookie is automatically received, sent, and parsed.
Note:
prop isHttp
prop isHttp: Bool
Description: Specifies whether the CookieJar is used for the HTTP protocol.
- If isHttp is set to true, only the Cookie instances from the HTTP protocol are stored.
- If isHttp is set to false, only the Cookie instances from non-HTTP protocols are stored, and the Cookie instances for which httpOnly is set are not stored.
Type: Bool
prop rejectPublicSuffixes
prop rejectPublicSuffixes: ArrayList<String>
Description: Obtains the public suffixes configuration. The configuration is a domain blacklist and rejects the Cookie whose domain value is public suffixes.
Note:
If the Cookie is from the same host as the domain, the blacklist does not take effect.
static func createDefaultCookieJar(ArrayList<String>, Bool)
static func createDefaultCookieJar(rejectPublicSuffixes: ArrayList<String>, isHttp: Bool): CookieJar
Description: Constructs the default CookieJar instance for managing Cookie.
For details about the management requirements of the default CookieJar, see RFC 6265 5.3..
Parameters:
- rejectPublicSuffixes: ArrayList<String>: public suffixes configured by the user. For Cookie management, cookies whose domain value is public suffixes (except the Cookie from the same host as the domain) are rejected for security purposes. For details about public suffixes, see PUBLIC SUFFIX LIST.
- isHttp: Bool: whether the CookieJar is used for the HTTP protocol. If isHttp is set to true, only the Cookie instances from the HTTP protocol are stored.
Returns:
static func parseSetCookieHeader(HttpResponse)
static func parseSetCookieHeader(response: HttpResponse): ArrayList<Cookie>
Description: Parses the Set-Cookie header in the response.
This function is used to parse the Set-Cookie header in a response and return the parsed ArrayList<Cookie>. For details about the rules for parsing the Set-Cookie header, see RFC 6265 5.2..
Parameters:
- response: HttpResponse: response to be parsed
Returns:
static func toCookieString(ArrayList<Cookie>)
static func toCookieString(cookies: ArrayList<Cookie>): String
Description: Converts ArrayList<Cookie> to a string for the Cookie header.
This function is used to convert the input ArrayList<Cookie> array to the Cookie header string format specified by the protocol. For details, see RFC 6265 5.4.4..
Parameters:
Returns:
func clear()
func clear(): Unit
Description: Clears all Cookie instances.
By default, the CookieJarImpl clears all Cookie instances in the CookieJar.
func getCookies(URL)
func getCookies(url: URL): ArrayList<Cookie>
Description: Obtains ArrayList<Cookie> from the CookieJar.
For details about the requirements of the function that obtains ArrayList<Cookie> for cookieJarImpl by default, see RFC 6265 5.4.. The obtained ArrayList<Cookie> can be converted to the value string of the Cookie header by calling toCookieString.
Parameters:
Returns:
func removeCookies(String)
func removeCookies(domain: String): Unit
Description: Removes the Cookie of a domain from the CookieJar.
Note:
By default, the CookieJarImpl removes only the Cookie of the specific domain, while the Cookie of the subdomains of the domain is not removed.
Parameters:
Throws:
- IllegalArgumentException: If the input domain is an empty string or invalid, this exception is thrown. For details about the rules for valid domains, see the Cookie parameter document.
func storeCookies(URL, ArrayList<Cookie>)
func storeCookies(url: URL, cookies: ArrayList<Cookie>): Unit
Description: Saves ArrayList<Cookie> to CookieJar.
If the number of Cookie instances stored in the CookieJar exceeds the upper limit (3000), at least 1,000 Cookie instances must be cleared from the CookieJar before other instances can be saved. For details about the priority for clearing the Cookie instances in the CookieJar, see RFC 6265 5.3.12..
Cookie instances are cleared in the following sequence:
- Expired Cookie instances
- Cookie instances other than the first 50 ones
- Cookie instances with the same priority but having an earlier
last-accesstime
Parameters:
interface HttpRequestDistributor
public interface HttpRequestDistributor
Description: Specifies an HTTP request distributor interface which distributes a request to the corresponding HttpRequestHandler based on the path in the URL.
Note:
This implementation provides a default HttpRequestDistributor, which is not thread-safe. By default,
ProtocolServiceinstances of HTTP/1.1 and HTTP/2 in the Cangjie standard library are provided. In addition, the register operation can be performed only before the server is started. A register operation after the server is started leads to an undefined result. If the user wants to perform a register operation after the server is started, a thread-safe HttpRequestDistributor is required for implementation.
func distribute(String)
func distribute(path: String): HttpRequestHandler
Description: Distributes request handlers. If the corresponding request handler is not found, NotFoundHandler and status code 404 are returned.
Parameters:
- path: String: request path
Returns:
- HttpRequestHandler: The request handler is returned.
func register(String, (HttpContext) -> Unit)
func register(path: String, handler: (HttpContext) -> Unit): Unit
Description: Registers request handlers.
Parameters:
- path: String: request path
- handler: (HttpContext) ->Unit: request processing function
Throws:
- HttpException: If a request handler has been registered in the request path, this exception is thrown.
func register(String, HttpRequestHandler)
func register(path: String, handler: HttpRequestHandler): Unit
Description: Registers request handlers.
Parameters:
- path: String: request path
- handler: HttpRequestHandler: request handler
Throws:
- HttpException: If a request handler has been registered in the request path, this exception is thrown.
interface HttpRequestHandler
public interface HttpRequestHandler {
func handle(ctx: HttpContext): Unit
}
Description: Specifies the HTTP request handler.
The HTTP server processes the HTTP request from the client through the handler. In the handler, the user can obtain the detailed information about the HTTP request, including the header and body, construct the HTTP response, including the header and body, and send the response to the client directly (alternatively, the response can be sent by the server).
When building an HTTP server, the user needs to register one or more handlers through the HttpRequestDistributor of the server. When an HTTP request from the client is received, the distributor distributes the request to the corresponding handler based on the path of the URL in the request.
Note:
To prevent the DNS rebinding attack, the application verifies the value of the Host request header of the request in the handler logic to check whether the value is an authoritative host name recognized by the application.
func handle(HttpContext)
func handle(ctx: HttpContext): Unit
Description: Processes HTTP requests.
Parameters:
- ctx: HttpContext: HTTP request context
interface ProtocolServiceFactory
public interface ProtocolServiceFactory {
func create(protocol: Protocol, socket: StreamingSocket): ProtocolService
}
Description: Sets the HTTP service instance factory which is used to generate ProtocolService instances.
The default implementation is provided for ServerBuilder. By default, ProtocolService instances of HTTP/1.1 and HTTP/2 in the Cangjie standard library are provided.
func create()
func create(protocol: Protocol, socket: StreamingSocket): ProtocolService
Description: Creates a protocol service instance based on the protocol.
Parameters:
- protocol: Protocol: protocol version, such as HTTP1_0, HTTP1_1, and HTTP2_0
- socket: StreamingSocket: socket from the client
Returns:
- ProtocolService: protocol service instance
Class
class Client
public class Client
Description: Sends HTTP requests and supports being closed at any time. Users can use a Client instance to send HTTP/1.1 or HTTP/2 requests.
Note:
If the Client document does not specify the supported version, the configuration is valid in both HTTP/1.1 and HTTP/2.
prop autoRedirect
public prop autoRedirect: Bool
Description: Specifies whether to enable automatic redirection for a client. By default, status code 304 indicates no redirection.
Type: Bool
prop connector
public prop connector: (SocketAddress) -> StreamingSocket
Description: A client calls this function to connect to the server.
Type: (SocketAddress) -> StreamingSocket
prop cookieJar
public prop cookieJar: ?CookieJar
Description: Stores all Cookie instances of a client. If this parameter is set to None, Cookie is disabled.
Type: ?CookieJar
prop enablePush
public prop enablePush: Bool
Description: Specifies whether the client-side HTTP/2 supports server push. The default value is true.
Type: Bool
prop headerTableSize
public prop headerTableSize: UInt32
Description: Obtains the initial value of the HTTP/2 Hpack dynamic table on a client. The default value is 4096.
Type: UInt32
prop httpProxy
public prop httpProxy: String
Description: Obtains the client-side HTTP proxy. By default, the value of the system environment variable http_proxy is used. The value is a string in the format of "http://host:port", for example, "http://192.168.1.1:80".
Type: String
prop httpsProxy
public prop httpsProxy: String
Description: Obtains the client-side HTTPS proxy. By default, the value of the system environment variable https_proxy is used. The value is a string in the format of "http://host:port", for example, "http://192.168.1.1:443".
Type: String
prop initialWindowSize
public prop initialWindowSize: UInt32
Description: Obtains the initial value of the HTTP/2 flow control window on a client. The default value is 65535. The value ranges from 0 to 2^31 – 1.
Type: UInt32
prop logger
public prop logger: Logger
Description: Obtains the client-side logger. The setting of logger.level takes effect immediately. The logger should be thread-safe.
Type: Logger
prop maxConcurrentStreams
public prop maxConcurrentStreams: UInt32
Description: Obtains the initial maximum number of concurrent HTTP/2 flows on a client. The default value is 2^31 – 1.
Type: UInt32
prop maxFrameSize
public prop maxFrameSize: UInt32
Description: Obtains the initial maximum frame size of HTTP/2 on a client. The default value is 16384. The value ranges from 2^14 to 2^24 – 1.
Type: UInt32
prop maxHeaderListSize
public prop maxHeaderListSize: UInt32
Description: Obtains the maximum header size of HTTP/2 supported by a client. The size refers to the sum of the maximum allowed lengths of all header fields in the response header, including the lengths of all field names and field values, and pseudo header overhead automatically added to each field. (Generally, each field has a 32-byte overhead, including the pseudo header information added by the HTTP/2 protocol to the header field.) By default, this maximum length is set to UInt32.Max.
Type: UInt32
prop poolSize
public prop poolSize: Int64
Description: Configures the size of the connection pool used by an HTTP/1.1 client, which also means the maximum number of concurrent connections to the same host (host:port).
Type: Int64
prop readTimeout
public prop readTimeout: Duration
Description: Obtains the timeout for reading the entire response set on a client. The default value is 15s.
Type: Duration
prop writeTimeout
public prop writeTimeout: Duration
Description: Obtains the timeout for write requests set on a client. The default value is 15s.
Type: Duration
func close()
public func close(): Unit
Description: Closes all connections established by a client. After this function is called, requests cannot be sent.
func connect(String, HttpHeaders, Protocol)
public func connect(url: String, header!: HttpHeaders = HttpHeaders(), version!: Protocol = HTTP1_1): (HttpResponse, ?StreamingSocket)
Description: Sends a CONNECT request to establish a tunnel with the server and returns the connection successfully established. Such connection is closed by the user. If the server returns 2xx, the connection is established successfully. Otherwise, the connection fails. (Automatic redirection is not supported. The connection fails if the server returns 3xx.)
Parameters:
- url: String: URL of the request
- header!: HttpHeaders: request header, which is empty by default
- version!: Protocol: protocol (HTTP1_1 by default) of the request
Returns:
- (HttpResponse,?StreamingSocket): A tuple type is returned. The HttpResponse instance indicates the response body returned by the server, and the Option<StreamingSocket> instance indicates the connection after headers are returned when the request is successful.
Throws:
- UrlSyntaxException: When the URL does not comply with the URL parsing specifications, this exception is thrown.
- IllegalArgumentException: When the encoded character does not comply with the UTF-8 byte sequence rule, this exception is thrown.
- Other exceptions are the same as those in func send.
func delete(String)
public func delete(url: String): HttpResponse
Description: Specifies a shortcut request function whose request method is DELETE.
Parameters:
- url: String: URL of the request
Returns:
- HttpResponse: response sent by the server
Throws:
- UrlSyntaxException: When the URL does not comply with the URL parsing specifications, this exception is thrown.
- IllegalArgumentException: When the encoded character does not comply with the UTF-8 byte sequence rule, this exception is thrown.
- Other exceptions are the same as those in func send.
func get(String)
public func get(url: String): HttpResponse
Description: Specifies a shortcut request function whose request method is GET.
Parameters:
- url: String: URL of the request
Returns:
- HttpResponse: response sent by the server
Throws:
- UrlSyntaxException: When the URL does not comply with the URL parsing specifications, this exception is thrown.
- IllegalArgumentException: When the encoded character does not comply with the UTF-8 byte sequence rule, this exception is thrown.
- Other exceptions are the same as those in func send.
func getTlsConfig()
public func getTlsConfig(): ?TlsClientConfig
Description: Obtains the TLS layer configuration set by a client.
Returns:
- ?TlsClientConfig: TLS layer configuration set by the client. If it is not set, None is returned.
func head(String)
public func head(url: String): HttpResponse
Description: Specifies a shortcut request function whose request method is HEAD.
Parameters:
- url: String: URL of the request
Returns:
- HttpResponse: response sent by the server
Throws:
- UrlSyntaxException: When the URL does not comply with the URL parsing specifications, this exception is thrown.
- IllegalArgumentException: When the encoded character does not comply with the UTF-8 byte sequence rule, this exception is thrown.
- Other exceptions are the same as those in func send.
func options(String)
public func options(url: String): HttpResponse
Description: Specifies a shortcut request function whose request method is OPTIONS.
Parameters:
- url: String: URL of the request
Returns:
- HttpResponse: response sent by the server
Throws:
- UrlSyntaxException: When the URL does not comply with the URL parsing specifications, this exception is thrown.
- IllegalArgumentException: When the encoded character does not comply with the UTF-8 byte sequence rule, this exception is thrown.
- Other exceptions are the same as those in func send.
func post(String, Array<UInt8>)
public func post(url: String, body: Array<UInt8>): HttpResponse
Description: Specifies a shortcut request function whose request method is POST.
Parameters:
Returns:
- HttpResponse: response sent by the server
Throws:
- UrlSyntaxException: When the URL does not comply with the URL parsing specifications, this exception is thrown.
- IllegalArgumentException: When the encoded character does not comply with the UTF-8 byte sequence rule, this exception is thrown.
- Other exceptions are the same as those in func send.
func post(String, InputStream)
public func post(url: String, body: InputStream): HttpResponse
Description: Specifies a shortcut request function whose request method is POST.
Parameters:
- url: String: URL of the request
- body: InputStream: request body
Returns:
- HttpResponse: response sent by the server
Throws:
- UrlSyntaxException: When the URL does not comply with the URL parsing specifications, this exception is thrown.
- IllegalArgumentException: When the encoded character does not comply with the UTF-8 byte sequence rule, this exception is thrown.
- Other exceptions are the same as those in func send.
func post(String, String)
public func post(url: String, body: String): HttpResponse
Description: Specifies a shortcut request function whose request method is POST.
Parameters:
Returns:
- HttpResponse: response sent by the server
Throws:
- UrlSyntaxException: When the URL does not comply with the URL parsing specifications, this exception is thrown.
- IllegalArgumentException: When the encoded character does not comply with the UTF-8 byte sequence rule, this exception is thrown.
- Other exceptions are the same as those in func send.
func put(String, Array<UInt8>)
public func put(url: String, body: Array<UInt8>): HttpResponse
Description: Specifies a shortcut request function whose request method is PUT.
Parameters:
Returns:
- HttpResponse: response sent by the server
Throws:
- UrlSyntaxException: When the URL does not comply with the URL parsing specifications, this exception is thrown.
- IllegalArgumentException: When the encoded character does not comply with the UTF-8 byte sequence rule, this exception is thrown.
- Other exceptions are the same as those in func send.
func put(String, InputStream)
public func put(url: String, body: InputStream): HttpResponse
Description: Specifies a shortcut request function whose request method is PUT.
Parameters:
- url: String: URL of the request
- body: InputStream: request body
Returns:
- HttpResponse: response sent by the server
Throws:
- UrlSyntaxException: When the URL does not comply with the URL parsing specifications, this exception is thrown.
- IllegalArgumentException: When the encoded character does not comply with the UTF-8 byte sequence rule, this exception is thrown.
- Other exceptions are the same as those in func send.
func put(String, String)
public func put(url: String, body: String): HttpResponse
Description: Specifies a shortcut request function whose request method is PUT.
Parameters:
Returns:
- HttpResponse: response sent by the server
Throws:
- UrlSyntaxException: When the URL does not comply with the URL parsing specifications, this exception is thrown.
- IllegalArgumentException: When the encoded character does not comply with the UTF-8 byte sequence rule, this exception is thrown.
- Other exceptions are the same as those in func send.
func send(HttpRequest)
public func send(req: HttpRequest): HttpResponse
Description: Specifies a common request function, which sends HttpRequest to the server in URL and receives HttpResponse.
Note:
- For HTTP/1.1, if the request to be sent contains a body, ensure that either Content-Length or Transfer-Encoding: chunked is set. If the body is sent in chunked mode, the maximum size of each chunk is 8,192 bytes. If the body sent by the user is a self-implemented InputStream class, the user must ensure that either Content-Length or Transfer-Encoding: chunked is set. If the user uses a default body to send a request and both Content-Length and Transfer-Encoding: chunked are missing, a Content-Length header whose value is body.size is added by default.
- If Content-Length is set, ensure that its value is correct. If the body to be sent is greater than or equal to the value of Content-Length, the data whose length is the value of Content-Length is sent. If the body to be sent is a default body and is less than the value of Content-Length, HttpException is thrown. If the body is a self-implemented InputStream class, the result is unpredictable (read request timeout on the server or response receiving timeout on the client may occur).
- The upgrade function is sent through the upgradeFromClient interface of WebSocket or the upgrade interface of Client. An exception will be thrown when another function of the client is called to send the upgrade request.
- According to the protocol, a TRACE request cannot carry content. Therefore, an exception is thrown when the user sends a TRACE request with a body.
- By default, the number of HTTP/1.1 connections to the same server cannot exceed 10. The response body needs to be read by calling the
body.read(buf: Array<Byte>)function. A connection can be reused by client objects only after the body is read. Otherwise, a new connection is still created even for the same server. If the number of connections exceeds the upper limit during connection creation, HttpException is thrown.- The body.read function returns 0 after reading the body. If the connection is interrupted during the read, ConnectionException is thrown.
- If a 101 response code is received for the HTTP/1.1 upgrade request, the protocol is switched and the connection is not managed by the client.
- The notes for the following shortcut request functions are the same as those for the send function.
Parameters:
- req: HttpRequest: request sent
Returns:
- HttpResponse: response returned by the server for processing the request
Throws:
- UrlSyntaxException: If URL in the request is incorrect, this exception is thrown.
- SocketException: If an error occurs in socket connection, this exception is thrown.
- ConnectionException: If data is read from the connection that has been closed by the peer end, this exception is thrown.
- SocketTimeoutException: If socket connection times out, this exception is thrown.
- TlsException: If TLS connection fails to be established or the communication is abnormal, this exception is thrown.
- HttpException: If the user uses an API not included in the HTTP library to upgrade WebSocket, this exception is thrown.
- HttpTimeoutException: If the request or HttpResponse.body read times out, this exception is thrown.
func upgrade(HttpRequest)
public func upgrade(req: HttpRequest): (HttpResponse, ?StreamingSocket)
Description: Sends a request and upgrades the protocol. The user sets the request header and the upgraded connection is returned (if the upgrade is successful). Such connection is closed by the user.
Note:
- If the server returns 101, the upgrade is successful and StreamingSocket is obtained.
- Mandatory request headers:
- Upgrade: protocol-name ["/" protocol-version]
- Connection: Upgrade (automatically added when the request header contains the Upgrade field)
- HTTP/1.0 or HTTP/2 is not supported.
- HttpRequest of the HTTP/1.1 CONNECT method is not supported.
Parameters:
- req: HttpRequest: request sent during upgrade
Returns:
- (HttpResponse,?StreamingSocket): A tuple is returned. The HttpResponse instance indicates the response returned by the server. The ?StreamingSocket instance indicates the obtained underlying connection. If the upgrade fails, None is returned.
Throws:
- HttpException -
- The request packet or response packet does not comply with the protocol.
- The request packet does not contain the Upgrade header.
- A CONNECT request is sent.
- A TRACE request with a body is sent.
- SocketException, ConnectionException: Socket connection is abnormal or closed.
- SocketTimeoutException: Socket connection times out.
- TlsException: TLS connection fails to be established or the communication is abnormal.
class ClientBuilder
public class ClientBuilder {
public init()
}
Description: Constructs a Client instance. Client does not have any public constructor. Users can obtain Client instances only by using ClientBuilder. If the ClientBuilder document does not specify the supported version, the configuration is valid in both HTTP/1.1 and HTTP/2.
init()
public init()
Description: Creates a new ClientBuilder instance.
func autoRedirect(Bool)
public func autoRedirect(auto: Bool): ClientBuilder
Description: Configures whether to enable automatic redirection for a client. A redirection requests resources in the Location header. According to the protocol, Location can contain only one URI reference: Location = URI-reference. For details, see RFC 9110 10.2.2.. By default, status code 304 indicates no redirection.
Parameters:
- auto: Bool: The default value is true, indicating that automatic redirection is enabled.
Returns:
- ClientBuilder: reference of the current ClientBuilder instance
func build()
public func build(): Client
Description: Constructs a Client instance.
Returns:
- Client: Client instance constructed by using the configuration in the current ClientBuilder instance
Throws:
- IllegalArgumentException: If the configuration contains invalid parameters, this exception is thrown.
func connector((SocketAddress)->StreamingSocket)
public func connector(connector: (SocketAddress)->StreamingSocket): ClientBuilder
Description: A client calls this function to connect to the server.
Parameters:
- connector: (SocketAddress) ->StreamingSocket: The input parameter is the SocketAddress instance, and the return value type is the function type of StreamingSocket.
Returns:
- ClientBuilder: reference of the current ClientBuilder instance
func cookieJar(?CookieJar)
public func cookieJar(cookieJar: ?CookieJar): ClientBuilder
Description: Stores all Cookie instances of a client.
Parameters:
- cookieJar: ?CookieJar: By default, an empty CookieJar is used. If this parameter is set to None, Cookie is disabled.
Returns:
- ClientBuilder: reference of the current ClientBuilder instance
func enablePush(Bool)
public func enablePush(enable: Bool): ClientBuilder
Description: Configures whether the client-side HTTP/2 supports server push.
Parameters:
- enable: Bool: The default value is true.
Returns:
- ClientBuilder: reference of the current ClientBuilder instance
func headerTableSize(UInt32)
public func headerTableSize(size: UInt32): ClientBuilder
Description: Configures the initial value of the HTTP/2 Hpack dynamic table on a client.
Parameters:
- size: UInt32: The default value is 4096.
Returns:
- ClientBuilder: reference of the current ClientBuilder instance
func httpProxy(String)
public func httpProxy(addr: String): ClientBuilder
Description: Sets the HTTP proxy of a client. By default, the value of the system environment variable http_proxy is used.
Parameters:
- addr: String: The format is
"http://host:port", for example,"http://192.168.1.1:80".
Returns:
- ClientBuilder: reference of the current ClientBuilder instance
func httpsProxy(String)
public func httpsProxy(addr: String): ClientBuilder
Description: Sets the HTTPS proxy of a client. By default, the value of the system environment variable https_proxy is used.
Parameters:
- addr: String: The format is
"http://host:port", for example,"http://192.168.1.1:443".
Returns:
- ClientBuilder: reference of the current ClientBuilder instance
func initialWindowSize(UInt32)
public func initialWindowSize(size: UInt32): ClientBuilder
Description: Configures the initial value of the HTTP/2 flow control window on a client.
Parameters:
- size: UInt32: The default value is 65535. The value ranges from 0 to 2^31 – 1.
Returns:
- ClientBuilder: reference of the current ClientBuilder instance
func logger(Logger)
public func logger(logger: Logger): ClientBuilder
Description: Sets the client-side logger. The default logger level is INFO. The logger content is written to Console.stdout.
Parameters:
- logger: Logger: The logger must be thread-safe. By default, the built-in thread-safe logger is used.
Returns:
- ClientBuilder: reference of the current ClientBuilder instance
func maxConcurrentStreams(UInt32)
public func maxConcurrentStreams(size: UInt32): ClientBuilder
Description: Configures the initial maximum number of concurrent HTTP/2 flows on a client.
Parameters:
- size: UInt32: The default value is 2^31 – 1.
Returns:
- ClientBuilder: reference of the current ClientBuilder instance
func maxFrameSize(UInt32)
public func maxFrameSize(size: UInt32): ClientBuilder
Description: Configures the initial maximum frame size of HTTP/2 on a client.
Parameters:
- size: UInt32: The default value is 16384. The value ranges from 2^14 to 2^24 – 1.
Returns:
- ClientBuilder: reference of the current ClientBuilder instance
func maxHeaderListSize(UInt32)
public func maxHeaderListSize(size: UInt32): ClientBuilder
Description: Obtains the maximum header size of HTTP/2 supported by a client. The size refers to the sum of the maximum allowed lengths of all header fields in the response header, including the lengths of all field names and field values, and pseudo header overhead automatically added to each field. (Generally, each field has a 32-byte overhead, including the pseudo header information added by the HTTP/2 protocol to the header field.) By default, this maximum length is set to UInt32.Max.
Parameters:
- size: UInt32: maximum length of the HTTP/2 response headers received by the client
Returns:
- ClientBuilder: reference of the current ClientBuilder instance
func noProxy()
public func noProxy(): ClientBuilder
Description: After this function is called, the client does not use any proxy.
Returns:
- ClientBuilder: reference of the current ClientBuilder instance
func poolSize(Int64)
public func poolSize(size: Int64): ClientBuilder
Description: Configures the size of the connection pool used by an HTTP/1.1 client, which also means the maximum number of concurrent connections to the same host (host:port).
Parameters:
- size: Int64: The default value is 10. The value of poolSize must be greater than 0.
Returns:
- ClientBuilder: reference of the current ClientBuilder instance
Throws:
- HttpException: If the input parameter is less than or equal to 0, this exception is thrown.
func readTimeout(Duration)
public func readTimeout(timeout: Duration): ClientBuilder
Description: Sets the maximum duration for a client to read a response.
Parameters:
- timeout: Duration: The default value is 15s. Duration.Max indicates that the duration is not limited. A negative Duration is replaced with Duration.Zero.
Returns:
- ClientBuilder: reference of the current ClientBuilder instance
func tlsConfig(TlsClientConfig)
public func tlsConfig(config: TlsClientConfig): ClientBuilder
Description: Sets the TLS layer configuration which is not set by default.
Parameters:
- config: TlsClientConfig: configuration information required for supporting the TLS client
Returns:
- ClientBuilder: reference of the current ClientBuilder instance
func writeTimeout(Duration)
public func writeTimeout(timeout: Duration): ClientBuilder
Description: Sets the maximum duration for a client to send a request.
Parameters:
- timeout: Duration: The default value is 15s. Duration.Max indicates that the duration is not limited. A negative Duration is replaced with Duration.Zero.
Returns:
- ClientBuilder: reference of the current ClientBuilder instance
class Cookie
public class Cookie {
public init(name: String, value: String, expires!: ?DateTime = None, maxAge!: ?Int64 = None,
domain!: String = "", path!: String = "", secure!: Bool = false, httpOnly!: Bool = false)
}
Description: HTTP is stateless. To obtain the client status and provide personalized services, the server can use Cookie to maintain a stateful session.
Note:
- When the user accesses a site for the first time, the server sends the name/value pair and attribute-value to the user proxy through the
Set-Cookieheader. The user proxy can then add the name/value to the Cookie header in subsequent requests to the site.- The Cookie class provides functions for constructing Cookie objects, converting Cookie objects to
Set-Cookieheader values, and obtaining the attribute values of Cookie objects.- For details about the requirements and functions of attributes of Cookie, see RFC 6265.
- In the following content, names such as cookie-name, cookie-value, and expires-av are subject to the terms in RFC 6265. See the protocol for details.
prop cookieName
public prop cookieName: String
Description: Obtains the cookie-name value of a Cookie object.
Type: String
prop cookieValue
public prop cookieValue: String
Description: Obtains the cookie-value value of a Cookie object.
Type: String
prop domain
public prop domain: String
Description: Obtains the domain-av value of a Cookie object.
Type: String
prop expires
public prop expires: ?DateTime
Description: Obtains the expires-av value of a Cookie object.
Type: ?DateTime
prop httpOnly
public prop httpOnly: Bool
Description: Obtains the httpOnly-av value of a Cookie object.
Type: Bool
prop maxAge
public prop maxAge: ?Int64
Description: Obtains the max-age-av value of a Cookie object.
Type: ?Int64
prop others
public prop others: ArrayList<String>
Description: Obtains the attributes that are not parsed.
prop path
public prop path: String
Description: Obtains the path-av value of a Cookie object.
Type: String
prop secure
public prop secure: Bool
Description: Obtains the secure-av value of a Cookie object.
Type: Bool
init(String, String, ?DateTime, ?Int64, String, String, Bool, Bool)
public init(name: String, value: String, expires!: ?DateTime = None, maxAge!: ?Int64 = None,
domain!: String = "", path!: String = "", secure!: Bool = false, httpOnly!: Bool = false)
Description: Provides the public constructor for Cookie objects. Note: This constructor checks whether the input attributes meet the protocol requirements. If the requirement is not met, IllegalArgumentException is thrown. For details, see RFC 6265 4.1.1..
Note:
For all attributes of Cookie, only cookie-name and cookie-value are mandatory. The name and value parameters are mandatory, but the value parameter can be an empty string.
Parameters:
-
name: String: cookie-name attribute
name = token token = 1*tchar tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA -
value: String: cookie-value attribute
value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE ) cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E ; US-ASCII characters excluding CTLs, ; whitespace DQUOTE, comma, semicolon, ; and backslash -
expires!: ?DateTime: Set the expiration time of Cookie. The default value is None. The time must be later than year 1601.
-
maxAge!: ?Int64: maximum lifetime of Cookie. The default value is None. If the Cookie has both the expires and maxAge attributes, the Cookie is maintained only until the end of the session. (It is maintained until the Client is closed. A Cookie with expiration time set is no longer maintained after the Client is closed.)
max-age-av = "Max-Age=" non-zero-digit *DIGIT non-zero-digit = %x31-39 ; digits 1 through 9 DIGIT = %x30-39 ; digits 0 through 9 -
domain!: String: empty string by default, indicating that the client receives the Cookie and sends the Cookie only to the origin server. If a valid domain is set, the client receives the Cookie and sends the Cookie only to all subdomains of the domain (only when other attribute requirements are met).
domain = <subdomain> | " " <subdomain> ::= <label> | <subdomain> "." <label> <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ] <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str> <let-dig-hyp> ::= <let-dig> | "-" <let-dig> ::= <letter> | <digit> <letter> ::= any one of the 52 alphabetic characters A through Z in upper case and a through z in lower case <digit> ::= any one of the ten digits 0 through 9 RFC 1035 2.3.1. RFC 1123 2.1. eliminates the restriction that the first character of a label must be a letter. Therefore, the requirements for a domain are as follows: 1. It consists of several labels, with the total length less than or equal to 255 characters. 2. Labels are separated by periods (.). Each label contains a maximum of 63 characters. 3. A label must start and end with a digit or letter, and the middle character of a label must be a digit, letter, or hyphen (-). -
path!: String: empty string by default. The client calculates the default path attribute based on the URL. For details, see RFC 6265 5.1.4. The client receives the Cookie and sends the Cookie only to all subdirectories of the path (only when other attribute requirements are met).
path = <any RUNE except CTLs or ";"> RUNE = <any [USASCII] character> CTLs = <controls> -
secure!: Bool: The default value is false. If the value is true, the Cookie is sent only in requests under secure protocols.
-
httpOnly!: Bool: The default value is false. If the value is true, the Cookie is sent only in requests under HTTP protocols.
Throws:
- IllegalArgumentException: If the input parameter does not meet the protocol requirements, this exception is thrown.
func toSetCookieString()
public func toSetCookieString(): String
Description: Provides a function for converting Cookie to a string so that the server can set the Set-Cookie header.
Note:
- The attributes (including name and value) of the Cookie are checked when the object is created. Therefore, the toSetCookieString() function does not throw exceptions.
- The mandatory attribute of Cookie is cookie-pair, that is, cookie-name = cookie-value. cookie-value can be an empty string. The toSetCookieString() function writes only the configured attribute into the string, which means only "cookie-name=" is mandatory and whether other attributes exist depends on whether they are set.
Returns:
- String: string object used to set the
Set-Cookieheader
class FileHandler
public class FileHandler <: HttpRequestHandler {
public init(path: String, handlerType!: FileHandlerType = DownLoad, bufferSize!: Int64 = 64 * 1024)
}
Description: Handles file download or upload.
File download:
- The path of the file to be downloaded needs to be input for constructing the FileHandler. Currently, one FileHandler can handle the download of only one file.
- Only the GET request method can be used to download files. If other request methods are used, status code 400 is returned.
- If the file does not exist, status code 404 is returned.
File upload:
- An existing directory path needs to be input for constructing the FileHandler. The files uploaded to the server are stored in this directory.
- Only the POST request method can be used to upload files. If other request methods are used, status code 400 is returned.
- The HTTP packet for data upload must be in
multipart/form-dataformat, and the value of theContent-Typeheader field must bemultipart/form-data; boundary=----XXXXX. - Names of the files uploaded are stored in the
form-datapacket. The packet data format isContent-Disposition: form-data; name="xxx"; filename="xxxx", and the file name is the value of thefilenamefield. - Currently, form-data must contain the filename field.
- If the request packet is incorrect, status code 400 is returned.
- If another exception is thrown, for example, a file processing exception is thrown, status code 500 is returned.
Parent Type:
init(String, FileHandlerType, Int64)
public init(path: String, handlerType!: FileHandlerType = DownLoad, bufferSize!: Int64 = 64 * 1024)
Description: Specifies the constructor of FileHandler.
Parameters:
- path: String: file or directory path string input for constructing the FileHandler. Only an existing directory path can be input in the upload mode. If the path contains "../", the expected path to be input must be a standardized absolute path.
- handlerType!: FileHandlerType: working mode of the current FileHandler for constructing the FileHandler. The default mode is the download mode.
- bufferSize!: Int64: size of the buffer internally read from or written to network. The default size is 64 x 1024 (64 KB). If the value is less than 4096, 4096 is used.
Throws:
- HttpException: If the path does not exist, this exception is thrown.
func handle(HttpContext)
public func handle(ctx: HttpContext): Unit
Description: Processes response data based on requests.
Parameters:
- ctx: HttpContext: HTTP request context
class FuncHandler
public class FuncHandler <: HttpRequestHandler {
public FuncHandler((HttpContext) -> Unit)
}
Description: Specifies an HttpRequestHandler interface wrapper class, which wraps a single function into HttpRequestHandler.
Parent Type:
FuncHandler((HttpContext) -> Unit)
public FuncHandler(let handler: (HttpContext) -> Unit)
Description: Specifies the constructor of FuncHandler.
Parameters:
- handler: (HttpContext) -> Unit: processing function used to call handle
func handle(HttpContext)
public func handle(ctx: HttpContext): Unit
Description: Processes an HTTP request.
Parameters:
- ctx: HttpContext: HTTP request context
class HttpContext
public class HttpContext
Description: Specifies the HTTP request context used as the parameter of the HttpRequestHandler.handle function on the server.
prop clientCertificate
public prop clientCertificate: ?Array<X509Certificate>
Description: Obtains the HTTP certificate of a client.
Type: ?Array<X509Certificate>
prop request
public prop request: HttpRequest
Description: Obtains an HTTP request.
Type: HttpRequest
prop responseBuilder
public prop responseBuilder: HttpResponseBuilder
Description: Obtains the HTTP response builder.
Type: HttpResponseBuilder
class HttpHeaders
public class HttpHeaders <: Iterable<(String, Collection<String>)> {
public init()
}
Description: This class indicates the header and trailer in an HTTP packet and defines related add, delete, modify, and query operations.
Note:
- The header and trailer are key-value mapping sets, consisting of several field-lines. Each field-line contains a key (field-name) and several values (field-value).
- The field-name consists of token characters, which are case-insensitive. In this class, the characters are stored in lowercase format.
- The field-value consists of vchar (visible US-ASCII characters), SP, and HTAB. It cannot be empty or contain spaces at the beginning or end.
- For details, see rfc 9110.
Parent Type:
- Iterable<(String, Collection<String>)>
Example:
Example-Field: Foo, Bar
key: Example-Field, value: Foo, Bar
field-name = token
token = 1*tchar
tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*"
/ "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
/ DIGIT / ALPHA
; any VCHAR, except delimiters
init()
public init()
Description: Creates an HttpHeaders instance.
func add(String, String)
public func add(name: String, value: String): Unit
Description: Adds a specified key-value pair. If the name field already exists, its value is added to the corresponding value list. If the name field does not exist, the name field and its value are added.
Parameters:
- name: String: field name of HttpHeaders
- value: String: field value of HttpHeaders
Throws:
- HttpException: If the input name or value contains invalid elements, this exception is thrown.
func del(String)
public func del(name: String): Unit
Description: Deletes the key-value pair of a specified name.
Parameters:
- name: String: name of the field deleted
func get(String)
public func get(name: String): Collection<String>
Description: Obtains the value corresponding to a specified name.
Parameters:
- name: String: field name, which is case-insensitive
Returns:
- Collection<String>: value collection corresponding to the name. If the specified name does not exist, an empty collection is returned.
func getFirst(String)
public func getFirst(name: String): ?String
Description: Obtains the first value corresponding to a specified name.
Parameters:
- name: String: field name, which is case-insensitive
Returns:
- ?String: first value corresponding to the name. If the specified name does not exist, None is returned.
func isEmpty()
public func isEmpty(): Bool
Description: Checks whether the current instance is empty, that is, checks there is no key-value pair.
Returns:
- Bool: If the current instance is empty, true is returned. Otherwise, false is returned.
func iterator()
public func iterator(): Iterator<(String, Collection<String>)>
Description: Obtains an iterator that can be used to traverse all key-value pairs.
Returns:
- Iterator <(String, Collection<String>) >: iterator of the key-value collection
func set(String, String)
public func set(name: String, value: String): Unit
Description: Sets a specified key-value pair. If the name already exists, the input value overwrites the previous one.
Parameters:
- name: String: field name of HttpHeaders
- value: String: field value of HttpHeaders
Throws:
- HttpException: If the input name or value contains invalid elements, this exception is thrown.
class HttpRequest
public class HttpRequest <: ToString
Description: This class is an HTTP request class.
When sending a request, a client needs to construct an HttpRequest instance, encode the instance into a byte packet, and send the packet.
When processing a request, the server parses the received request into an HttpRequest instance and sends it to the handler function.
Parent Type:
prop body
public prop body: InputStream
Description: Obtains a body.
Note:
- The body does not support concurrent read.
- By default, the read function of the InputStream implementation class does not support multiple reads.
Type: InputStream
prop bodySize
public prop bodySize: Option<Int64>
Description: Obtains the length of a request body.
- If the body is not set, bodySize is Some(0).
- If the body length is known, that is, the body is input through Array<UInt8> or String, or the input InputStream has a definite length (length >= 0), bodySize is Some(Int64).
- If the body length is unknown, that is, the body is input through a user-defined InputStream instance and the InputStream instance does not have a definite length (length < 0), bodySize is set to None.
prop close
public prop close: Bool
Description: Specifies whether the request header contains Connection: close.
- For the server, if close is set to true, the connection is closed after the request is fulfilled.
- For a client, if close is set to true, the client needs to close the connection if the server does not close the connection after receiving the response.
Type: Bool
prop form
public prop form: Form
Description: Obtains the form information in the request.
- If the POST, PUT, or PATCH method is used and content-type contains application/x-www-form-urlencoded, the request body is obtained and parsed in form format.
- If neither the POST, PUT, nor PATCH method is used, the query field in the request URL is obtained.
Note:
- If this API is used to read the body and the body has been consumed, the body cannot be read through body.read.
- If the form is not in the Form format, the UrlSyntaxException exception is thrown.
Type: Form
prop headers
public prop headers: HttpHeaders
Description: Obtains headers. For details about headers, see the HttpHeaders class. After headers are obtained, the HttpHeaders instance function can be called to modify headers of the request.
Type: HttpHeaders
prop method
public prop method: String
Description: Obtains a method, for example, "GET" or "POST". The method of a request instance cannot be modified.
Type: String
prop readTimeout
public prop readTimeout: ?Duration
Description: Specifies the request-level read timeout of the request. None indicates that the read timeout is not set. Some(Duration) indicates that the read timeout is set.
Type: ?Duration
prop remoteAddr
public prop remoteAddr: String
Description: Obtains the peer address (client address) by the server. The format is ip:port, which cannot be set by users. If a user-defined request object calls this attribute, "" is returned. If the server handler calls this attribute, the client address is returned.
Type: String
prop trailers
public prop trailers: HttpHeaders
Description: Obtains trailers. For details about trailers, see the HttpHeaders class. After trailers are obtained, the HttpHeaders instance function can be called to modify trailers of the request.
Type: HttpHeaders
prop url
public prop url: URL
Description: Obtains the URL accessed by a client.
Type: URL
prop version
public prop version: Protocol
Description: Obtains the HTTP version, such as HTTP1_1 and HTTP2_0. The version of a request instance cannot be changed.
Type: Protocol
prop writeTimeout
public prop writeTimeout: ?Duration
Description: Specifies the request-level write timeout of the request. None indicates that the write timeout is not set. Some(Duration) indicates that the write timeout is set.
Type: ?Duration
func toString()
public override func toString(): String
Description: Converts a request to a string, including start line, headers, body size, and trailers.
For example, "GET /path HTTP/1.1\r\nhost: www.example.com\r\n\r\nbody size: 5\r\nbar: foo\r\n".
Returns:
- String: string representation of the request
class HttpRequestBuilder
public class HttpRequestBuilder {
public init()
}
Description: The HttpRequestBuilder class is used to construct HttpRequest instances.
init()
public init()
Description: Constructs a new HttpRequestBuilder.
init(HttpRequest)
public init(request: HttpRequest)
Description: Constructs an HttpRequestBuilder having the request attribute through a request. Since the body is an InputStream, operations on the original request body affect the HttpRequest body copy. The headers and trailers of HttpRequestBuilder are deep copies of the input parameter request. Other elements are shallow copies of the input parameter request because they are immutable objects.
Parameters:
- request: HttpRequest: HttpRequest objects input
func addHeaders(HttpHeaders)
public func addHeaders(headers: HttpHeaders): HttpRequestBuilder
Description: Adds the key-value pairs in HttpHeaders to the request header.
Parameters:
- headers: HttpHeaders: header objects input
Returns:
- HttpRequestBuilder: reference of the current HttpRequestBuilder instance
func addTrailers(HttpHeaders)
public func addTrailers(trailers: HttpHeaders): HttpRequestBuilder
Description: Adds the key-value pairs in HttpHeaders to the request trailer.
Parameters:
- trailers: HttpHeaders: trailer objects input
Returns:
- HttpRequestBuilder: reference of the current HttpRequestBuilder instance
func body(Array<UInt8>)
public func body(body: Array<UInt8>): HttpRequestBuilder
Description: Sets the request body. If the body has been set, calling this function replaces the original body.
Parameters:
Returns:
- HttpRequestBuilder: reference of the current HttpRequestBuilder instance
func body(InputStream)
public func body(body: InputStream): HttpRequestBuilder
Description: Sets the request body. If the body has been set, calling this function replaces the original body.
Parameters:
- body: InputStream: request body in stream format
Returns:
- HttpRequestBuilder: reference of the current HttpRequestBuilder instance
func body(String)
public func body(body: String): HttpRequestBuilder
Description: Sets the request body. If it has been set, calling this function replaces the original body. If this function is called to set the request body, the body is represented by the built-in InputStream implementation class, and its size is known.
Parameters:
- body: String: request body in string format
Returns:
- HttpRequestBuilder: reference of the current HttpRequestBuilder instance
func build()
public func build(): HttpRequest
Description: Generates an HttpRequest instance based on the HttpRequestBuilder instance.
Returns:
- HttpRequest: HttpRequest instance constructed based on the current HttpRequestBuilder instance
func connect()
public func connect(): HttpRequestBuilder
Description: Constructs a shortcut request function whose request method is "CONNECT".
Returns:
- HttpRequestBuilder: reference of the current HttpRequestBuilder instance
func delete()
public func delete(): HttpRequestBuilder
Description: Constructs a shortcut request function whose request method is "DELETE".
Returns:
- HttpRequestBuilder: reference of the current HttpRequestBuilder instance
func get()
public func get(): HttpRequestBuilder
Description: Constructs a shortcut request function whose request method is "GET".
Returns:
- HttpRequestBuilder: reference of the current HttpRequestBuilder instance
func head()
public func head(): HttpRequestBuilder
Description: Constructs a shortcut request function whose request method is "HEAD".
Returns:
- HttpRequestBuilder: reference of the current HttpRequestBuilder instance
func header(String, String)
public func header(name: String, value: String): HttpRequestBuilder
Description: Adds a specified key-value pair to the request header according to the same rule as that of the add function of the HttpHeaders class.
Parameters:
Returns:
- HttpRequestBuilder: reference of the current HttpRequestBuilder instance
Throws:
- HttpException: If the input name or value contains invalid elements, this exception is thrown.
func method(String)
public func method(method: String): HttpRequestBuilder
Description: Sets the request method. The default request method is "GET".
Parameters:
- method: String: request method, which must consist of token characters. If an empty string is input, the method value is automatically set to "GET".
Returns:
- HttpRequestBuilder: reference of the current HttpRequestBuilder instance
Throws:
- HttpException: If the parameter method is invalid, this exception is thrown.
func options()
public func options(): HttpRequestBuilder
Description: Constructs a shortcut request function whose request method is "OPTIONS".
Returns:
- HttpRequestBuilder: reference of the current HttpRequestBuilder instance
func post()
public func post(): HttpRequestBuilder
Description: Constructs a shortcut request function whose request method is "POST".
Returns:
- HttpRequestBuilder: reference of the current HttpRequestBuilder instance
func priority(Int64, Bool)
public func priority(urg: Int64, inc: Bool): HttpRequestBuilder
Description: Sets the shortcut function for a priority header. Calling this function generates a priority header, for example, "priority: urgency=x, i". If the priority field is set by using the function for setting the request header, calling this function is invalid. If this function is called for multiple times, the last call prevails.
Parameters:
- urg: Int64: request priority. The value ranges from 0 to 7, where 0 indicates the highest priority.
- inc: Bool: whether incremental request processing is required. If the value is true, the server needs to concurrently process requests with the same urg and inc. If the value is false, the server does not concurrently process requests.
Returns:
- HttpRequestBuilder: reference of the current HttpRequestBuilder instance
func put()
public func put(): HttpRequestBuilder
Description: Constructs a shortcut request function whose request method is "PUT".
Returns:
- HttpRequestBuilder: reference of the current HttpRequestBuilder instance
func readTimeout(Duration)
public func readTimeout(timeout: Duration): HttpRequestBuilder
Description: Sets the read timeout of the request. If the input Duration is negative, it is automatically converted to 0. If the read timeout is set, it is used for the request. If not, the timeout of the request is subject to the Client.
Parameters:
- timeout: Duration: read timeout of the request set by the user
Returns:
- HttpRequestBuilder: reference of the current HttpRequestBuilder instance
func setHeaders(HttpHeaders)
public func setHeaders(headers: HttpHeaders): HttpRequestBuilder
Description: Sets the request header. If it has been set, calling this function replaces the original header.
Parameters:
- headers: HttpHeaders: header objects input
Returns:
- HttpRequestBuilder: reference of the current HttpRequestBuilder instance
func setTrailers(HttpHeaders)
public func setTrailers(trailers: HttpHeaders): HttpRequestBuilder
Description: Sets the request trailer. If it has been set, calling this function replaces the original trailer.
Parameters:
- headers: HttpHeaders: trailer objects input
Returns:
- HttpRequestBuilder: reference of the current HttpRequestBuilder instance
func trace()
public func trace(): HttpRequestBuilder
Description: Constructs a shortcut request function whose request method is "TRACE".
Returns:
- HttpRequestBuilder: reference of the current HttpRequestBuilder instance
func trailer(String, String)
public func trailer(name: String, value: String): HttpRequestBuilder
Description: Adds a specified key-value pair to the request trailer according to the same rule as that of the add function of the HttpHeaders class.
Parameters:
Returns:
- HttpRequestBuilder: reference of the current HttpRequestBuilder instance
Throws:
- HttpException: If the input name or value contains invalid elements, this exception is thrown.
func url(String)
public func url(rawUrl: String): HttpRequestBuilder
Description: Sets the request URL. By default, the URL is an empty URL object.
Parameters:
- rawUrl: String: string to be parsed into a URL object. For details about the string format, see the URL.parse function.
Returns:
- HttpRequestBuilder: reference of the current HttpRequestBuilder instance
Throws:
- IllegalArgumentException: When the encoded character does not comply with the UTF-8 byte sequence rule, this exception is thrown.
func url(URL)
public func url(url: URL): HttpRequestBuilder
Description: Sets the request URL. By default, the URL is an empty URL object, that is, URL.parse("").
Parameters:
- url: URL: URL object
Returns:
- HttpRequestBuilder: reference of the current HttpRequestBuilder instance
func version(Protocol)
public func version(version: Protocol): HttpRequestBuilder
Description: Sets the HTTP protocol version of a request. The default version is UnknownProtocol(""). A client automatically selects a protocol according to the TLS configuration.
Parameters:
- version: Protocol: protocol version
Returns:
- HttpRequestBuilder: reference of the current HttpRequestBuilder instance
func writeTimeout(Duration)
public func writeTimeout(timeout: Duration): HttpRequestBuilder
Description: Sets the write timeout of the request. If the input Duration is negative, it is automatically converted to 0. If the write timeout is set, it is used for the request. If not, the write timeout of the request is subject to the Client.
Parameters:
- timeout: Duration: write timeout of the request set by the user
Returns:
- HttpRequestBuilder: reference of the current HttpRequestBuilder instance
class HttpResponse
public class HttpResponse <: ToString
Description: Specifies the HTTP response class.
This class defines the interfaces related to response in HTTP and enables a client to read the response returned by the server.
Parent Type:
prop body
public prop body: InputStream
Description: Obtains a body.
Note:
- The body does not support concurrent read.
- By default, the read function of the InputStream implementation class does not support multiple reads.
Type: InputStream
prop bodySize
public prop bodySize: Option<Int64>
Description: Obtains the length of a response body.
- If the body is not set, bodySize is Some(0).
- If the body length is known, that is, the body is input through Array<UInt8> or String, or the input InputStream has a definite length (length >= 0), bodySize is Some(Int64).
- If the body length is unknown, that is, the body is input through a user-defined InputStream instance and the InputStream instance does not have a definite length (length < 0), bodySize is None.
prop close
public prop close: Bool
Description: Specifies whether the response header contains Connection: close.
For the server, if close is set to** true**, the connection is closed after the request is fulfilled.
For a client, if close is set to true, the client needs to close the connection if the server does not close the connection after receiving the response.
Type: Bool
prop headers
public prop headers: HttpHeaders
Description: Obtains headers. For details about headers, see the HttpHeaders class. After headers are obtained, the HttpHeaders instance function can be called to modify headers of the request.
Type: HttpHeaders
prop request
public prop request: Option<HttpRequest>
Description: Obtains the request corresponding to the response. The default value is None.
Type: Option<HttpRequest>
prop status
public prop status: UInt16
Description: Obtains the status code of a response. The default value is 200. A status code consists of three digits ranging from 100 to 599. For details, see RFC 9110.
Type: UInt16
prop trailers
public prop trailers: HttpHeaders
Description: Obtains trailers. For details about trailers, see the HttpHeaders class. After trailers are obtained, the HttpHeaders instance function can be called to modify trailers of the request.
Type: HttpHeaders
prop version
public prop version: Protocol
Description: Obtains the protocol version of a response. The default value is HTTP1_1.
Type: Protocol
func getPush()
public func getPush(): ?ArrayList<HttpResponse>
Description: Obtains the server push response. If None is returned, the server push function is disabled. If an empty ArrayList is returned, no response is pushed by the server.
Returns:
- ?<ArrayList<HttpResponse>>: list of responses pushed by the server
func toString()
public override func toString(): String
Description: Converts a response to a string, including status-line, headers, body size, and trailers.
For example, HTTP/1.1 200 OK\r\ncontent-length: 5\r\n\r\nbody size: 5\r\nbar: foo\r\n.
Returns:
- String: string representation of the response
class HttpResponseBuilder
public class HttpResponseBuilder {
public init()
}
Description: Constructs an HttpResponse instance.
init()
public init()
Description: Constructs a new HttpResponseBuilder.
func addHeaders(HttpHeaders)
public func addHeaders(headers: HttpHeaders): HttpResponseBuilder
Description: Adds the key-value pairs in HttpHeaders to the response header.
Parameters:
- headers: HttpHeaders: header objects input
Returns:
- HttpResponseBuilder: reference of the current HttpResponseBuilder instance
func addTrailers(HttpHeaders)
public func addTrailers(trailers: HttpHeaders): HttpResponseBuilder
Description: Adds the key-value pairs in HttpHeaders to the response trailer.
Parameters:
- trailers: HttpHeaders: trailer objects input
Returns:
- HttpResponseBuilder: reference of the current HttpResponseBuilder instance
func body(Array<UInt8>)
public func body(body: Array<UInt8>): HttpResponseBuilder
Description: Sets the response body. If it has been set, calling this function replaces the original body.
Parameters:
Returns:
- HttpResponseBuilder: reference of the current HttpResponseBuilder instance
func body(InputStream)
public func body(body: InputStream): HttpResponseBuilder
Description: Sets the response body. If it has been set, calling this function replaces the original body.
Parameters:
- body: InputStream: response body in stream format
Returns:
- HttpResponseBuilder: reference of the current HttpResponseBuilder instance
func body(String)
public func body(body: String): HttpResponseBuilder
Description: Sets the response body. If it has been set, calling this function replaces the original body. If this function is called to set the request body, the body is represented by the built-in InputStream implementation class, and its size is known.
Parameters:
- body: String: response body in string format
Returns:
- HttpResponseBuilder: reference of the current HttpResponseBuilder instance
func build()
public func build(): HttpResponse
Description: Generates an HttpResponse instance based on the HttpResponseBuilder instance.
Returns:
- HttpResponse: HttpResponse instance constructed based on the current HttpResponseBuilder instance
func header(String, String)
public func header(name: String, value: String): HttpResponseBuilder
Description: Adds a specified key-value pair to the response header according to the same rule as that of the add function of the HttpHeaders class.
Parameters:
Returns:
- HttpResponseBuilder: reference of the current HttpResponseBuilder instance
Throws:
- HttpException: If the input name or value contains invalid elements, this exception is thrown.
func request(HttpRequest)
public func request(request: HttpRequest): HttpResponseBuilder
Description: Sets the request corresponding to the response.
Parameters:
- request: HttpRequest: request corresponding to the response
Returns:
- HttpResponseBuilder: reference of the current HttpResponseBuilder instance
func setHeaders(HttpHeaders)
public func setHeaders(headers: HttpHeaders): HttpResponseBuilder
Description: Sets the response header. If it has been set, calling this function replaces the original header.
Parameters:
- headers: HttpHeaders: header objects input
Returns:
- HttpResponseBuilder: reference of the current HttpResponseBuilder instance
func setTrailers(HttpHeaders)
public func setTrailers(trailers: HttpHeaders): HttpResponseBuilder
Description: Sets the response trailer. If it has been set, calling this function replaces the original trailer.
Parameters:
- headers: HttpHeaders: trailer objects input
Returns:
- HttpResponseBuilder: reference of the current HttpResponseBuilder instance
func status(UInt16)
public func status(status: UInt16): HttpResponseBuilder
Description: Sets the HTTP response status code.
Parameters:
- status: UInt16: value of the status code input
Returns:
- HttpResponseBuilder: reference of the current HttpResponseBuilder instance
Throws:
- HttpException: If the response status code is beyond the range from 100 to 599, this exception is thrown.
func trailer(String, String)
public func trailer(name: String, value: String): HttpResponseBuilder
Description: Adds a specified key-value pair to the response trailer according to the same rule as that of the add function of the HttpHeaders class.
Parameters:
Returns:
- HttpResponseBuilder: reference of the current HttpResponseBuilder instance
Throws:
- HttpException: If the input name or value contains invalid elements, this exception is thrown.
func version(Protocol)
public func version(version: Protocol): HttpResponseBuilder
Description: Sets the HTTP response protocol version.
Parameters:
- version: Protocol: protocol version
Returns:
- HttpResponseBuilder: reference of the current HttpResponseBuilder instance
class HttpResponsePusher
public class HttpResponsePusher
Description: Sets the HTTP/2 server push.
Note:
After receiving the request, if the server considers that the client needs some associated resources later, the server may push the resources to the client in advance. A server push consists of a push request and a push response. To enable server push, call the push function to send a push request and register the handler corresponding to the request with the server to generate a push response. A client can be configured to reject push from the server. Nested push is not allowed, that is, the push cannot be sent again in the handler corresponding to the push request. In the case of nested push, the server rejects the push and prints logs.
static func getPusher(HttpContext)
public static func getPusher(ctx: HttpContext): ?HttpResponsePusher
Description: Obtains the HttpResponsePusher instance. If a client rejects the push, None is returned.
Parameters:
- ctx: HttpContext: HTTP request context
Returns:
- ?HttpResponsePusher: HttpResponsePusher obtained
func push(String, String, HttpHeaders)
public func push(path: String, method: String, header: HttpHeaders): Unit
Description: Sends a push request to a client. path indicates the request address, method indicates the request method, and header indicates the request header.
Parameters:
- path: String: request address of the push
- method: String: request method of the push
- header: HttpHeaders: request header of the push
class HttpResponseWriter
public class HttpResponseWriter {
public HttpResponseWriter(let ctx: HttpContext)
}
Description: Specifies the HTTP response message body writer, which allows users to control the sending process of the message body.
Note:
When the write function is called for the first time, the header and the body input through parameters are sent immediately. After that, each time the write function is called, the body input through parameters is sent. For HTTP/1.1, if transfer-encoding: chunked is set, a chunk is sent each time the write function is called. For HTTP/2, the specified data is encapsulated and sent each time the write function is called.
HttpResponseWriter(HttpContext)
public HttpResponseWriter(let ctx: HttpContext)
Description: Constructs an HttpResponseWriter instance.
Parameters:
- ctx: HttpContext: HTTP request context
func write(Array<Byte>)
public func write(buf: Array<Byte>): Unit
Description: Sends data in the buf to a client.
Parameters:
Throws:
- HttpException: The request method is "HEAD" or the response status code is "1XX", "204", or "304".
- HttpException: The connection is closed.
- HttpException: The response protocol version is HTTP/1.0.
- HttpException: The response connection has been upgraded to WebSocket.
class NotFoundHandler
public class NotFoundHandler <: HttpRequestHandler {
public init()
}
Description: Specifies a convenient HTTP request handler and 404 Not Found handler.
Parent Type:
init()
public init()
Description: Constructs a NotFoundHandler object.
func handle(HttpContext)
public func handle(ctx: HttpContext): Unit
Description: Processes HTTP requests and returns status code 404.
Parameters:
- ctx: HttpContext: HTTP request context
class OptionsHandler
public class OptionsHandler <: HttpRequestHandler {
public init()
}
Description: Specifies a convenient HTTP handler used to process OPTIONS requests. The "Allow: OPTIONS, GET, HEAD, POST, PUT, or DELETE" response header is always returned.
Parent Type:
init()
public init()
Description: Constructs a NotFoundHandler object.
func handle(HttpContext)
public func handle(ctx: HttpContext): Unit
Description: Processes HTTP OPTIONS requests.
Parameters:
- ctx: HttpContext: HTTP request context
class ProtocolService
public abstract class ProtocolService
Description: Specifies an HTTP service instance which provides HTTP services for a single client connection, including parsing client request packets, distributing requests, and sending responses.
prop server
open protected mut prop server: Server
Description: Returns a Server instance and sets it to a bound Server instance. The default implementation is provided.
func serve
protected func serve(): Unit
Description: Processes connection requests from clients. No default implementation is provided.
func closeGracefully
open protected func closeGracefully(): Unit
Description: Gracefully closes a connection. This function is implemented by default and does not require any operation.
func close
open protected func close(): Unit
Description: Forcibly closes a connection. This function is implemented by default and does not require any operation.
class RedirectHandler
public class RedirectHandler <: HttpRequestHandler
Description: Specifies a convenient HTTP handler used to return redirection responses.
Parent Type:
init(String, UInt16)
public init(url: String, code: UInt16)
Description: Specifies the constructor of RedirectHandler.
Parameters:
- url: String: URL of the Location header in the redirection response
- code: UInt16: response code of the redirection response
Throws:
- HttpException: If the URL is empty or the response code is not status code 3XX (except 304), this exception is thrown.
func handle(HttpContext)
public func handle(ctx: HttpContext): Unit
Description: Processes HTTP requests and returns redirection responses.
Parameters:
- ctx: HttpContext: HTTP request context
class Server
public class Server
Description: Specifies the Server class that provides the HTTP service.
Note:
- Enabling the service: waits for the user connection and responds to the user's HTTP request at the specified address and port.
- Disabling the service, including closing all existing connections.
- A mechanism for registering handlers for processing HTTP requests is provided, which distributes requests to corresponding handlers according to registration information.
- The TLS certificate hot update mechanism is provided.
- The shutdown callback mechanism is provided.
- The Logger.level is used to enable or disable log printing, including printing logs of the corresponding level as required.
- If the Server document does not specify the supported version, the configuration is valid in both HTTP/1.1 and HTTP/2.
prop addr
public prop addr: String
Description: Obtains the listening address of the server in IP or domain name format.
Type: String
prop distributor
public prop distributor: HttpRequestDistributor
Description: Obtains the request distributor which distributes requests to corresponding handlers according to URLs.
Type: HttpRequestDistributor
prop enableConnectProtocol
public prop enableConnectProtocol: Bool
Description: Specifies whether the packets sent by the peer end support the protocol upgrade using the connect method. The value true indicates that the protocol upgrade using the connect method is supported. This is valid only for HTTP/2.
Type: Bool
prop headerTableSize
public prop headerTableSize: UInt32
Description: Obtains the initial value of the HTTP/2 Hpack dynamic table on the server. The default value is 4096.
Type: UInt32
prop httpKeepAliveTimeout
public prop httpKeepAliveTimeout: Duration
Description: Obtains the timeout set on the server for maintaining a persistent connection. This is valid only for HTTP/1.1.
Type: Duration
prop initialWindowSize
public prop initialWindowSize: UInt32
Description: Limits the initial window size of the packet stream sent by the peer end. This is valid only for HTTP/2. The default value is 65535. The value ranges from 0 to 2^31 – 1.
Type: UInt32
prop listener
public prop listener: ServerSocket
Description: Obtains the socket bound to the server.
Type: ServerSocket
prop logger
public prop logger: Logger
Description: Obtains the server-side logger. The setting of logger.level takes effect immediately. The logger should be thread-safe.
Type: Logger
prop maxConcurrentStreams
public prop maxConcurrentStreams: UInt32
Description: Specifies the maximum number of requests that can be concurrently processed by a connection. This is valid only for HTTP/2.
Type: UInt32
prop maxFrameSize
public prop maxFrameSize: UInt32
Description: Specifies the maximum length of a frame in a packet sent by the peer end. This is valid only for HTTP/2. The default value is 16384. The value ranges from 2^14 to 2^24 – 1.
Type: UInt32
prop maxHeaderListSize
public prop maxHeaderListSize: UInt32
Description: Obtains the maximum header size of HTTP/2 supported by a client. The size refers to the sum of the maximum allowed lengths of all header fields in the response header, including the lengths of all field names and field values, and pseudo header overhead automatically added to each field. (Generally, each field has a 32-byte overhead, including the pseudo header information added by the HTTP/2 protocol to the header field.) By default, this maximum length is set to UInt32.Max.
Type: UInt32
prop maxRequestBodySize
public prop maxRequestBodySize: Int64
Description: Obtains the maximum size of the request body of a read request set by the server. This is valid only for HTTP/1.1 requests without "Transfer-Encoding: chunked" set.
Type: Int64
prop maxRequestHeaderSize
public prop maxRequestHeaderSize: Int64
Description: Obtains the maximum size of the request header of a read request set by the server. This is valid only for HTTP/1.1. For HTTP/2, maxHeaderListSize is applicable.
Type: Int64
prop port
public prop port: UInt16
Description: Obtains the listening port of the server.
Type: UInt16
prop protocolServiceFactory
public prop protocolServiceFactory: ProtocolServiceFactory
Description: Obtains the protocol service factory which generates the service instances required by each protocol.
Type: ProtocolServiceFactory
prop readHeaderTimeout
public prop readHeaderTimeout: Duration
Description: Obtains the timeout for reading a request header set by the server.
Type: Duration
prop readTimeout
public prop readTimeout: Duration
Description: Obtains the timeout for reading the entire request set by the server.
Type: Duration
prop servicePoolConfig
public prop servicePoolConfig: ServicePoolConfig
Description: Obtains the coroutine pool configuration instance.
Type: ServicePoolConfig
prop transportConfig
public prop transportConfig: TransportConfig
Description: Obtain the transport layer configuration set by the server.
Type: TransportConfig
prop writeTimeout
public prop writeTimeout: Duration
Description: Obtains the write response timeout set by the server.
Type: Duration
func afterBind(()->Unit)
public func afterBind(f: ()->Unit): Unit
Description: Registers the callback function on server startup. This function is called after the ServerSocket instance bind is called and before accept is called. Repeatedly calling this function overwrites the previously registered function.
Parameters:
- f: () ->Unit: callback function. The input parameter is empty, and the return value is of the Unit type.
func close()
public func close(): Unit
Description: Closes the server. After the server is closed, it does not read or process requests. If the server is closed repeatedly (using close or closeGracefully), only the first operation takes effect.
func closeGracefully()
public func closeGracefully(): Unit
Description: Closes the server. After the server is closed, it does not read requests. If the server is processing a request, it will be closed after the processing is complete.
func getTlsConfig()
public func getTlsConfig(): ?TlsServerConfig
Description: Obtains the TLS layer configuration set by the server.
Returns:
- ?TlsClientConfig: TLS layer configuration set by the client. If it is not set, None is returned.
func onShutdown(()->Unit)
public func onShutdown(f: ()->Unit): Unit
Description: Registers the callback function on server shutdown. This callback function is called on server shutdown. Repeatedly calling this function overwrites the previously registered function.
Parameters:
- f: () ->Unit: callback function. The input parameter is empty, and the return value is of the Unit type.
func serve()
public func serve(): Unit
Description: Starts the server process. Repeated startup is not supported.
h1 request check and processing:
- If the request-line does not comply with the request-line = method SP request-target SP HTTP-version rule in RFC 9112, response code 400 is returned.
- The method consists of tokens and is case-sensitive. The request-target is the URL that can be parsed. The HTTP-version is HTTP/1.0 or HTTP/1.1. Otherwise, response code 400 is returned.
- The headers name and value must comply with specific rules. Otherwise, status code 400 is returned. For details, see the description of the HttpHeaders class.
- When the size of headers exceeds the value of maxRequestHeaderSize set by the server, response code 431 is automatically returned.
- The headers must contain the "host" request header and the value must be unique. Otherwise, response code 400 is returned. The "content-length" and "transfer-encoding" request headers cannot coexist in the headers. Otherwise, response code 400 is returned.
- After the value of the request header "transfer-encoding" is separated by commas (,), the last value must be "chunked" and the previous values cannot be "chunked". Otherwise, response code 400 is returned.
- The value of "content-length" in the request header must support parsing to the Int64 type and cannot be a negative value. Otherwise, response code 400 is returned. When the value exceeds the value of maxRequestBodySize set by the server, response code 413 is returned.
- If "content-length" and "transfer-encoding: chunked" do not exist in headers, no body exists by default.
- The value of the request header "trailer" cannot contain "transfer-encoding", "trailer", or "content-length".
- If the value of the request header "expect" contains values other than "100-continue", status code 417 is returned.
- HTTP/1.0 uses non-persistent connections by default. To keep a persistent connection, you need to include the request headers "connection: keep-alive" and "keep-alive: timeout = XX, max = XX", which will keep the connection alive within the specified timeout period. HTTP/1.1 uses persistent connection by default. If the request fails to be parsed, the connection is closed.
- The trailer can exist only in chunked mode, and the name of an entry in the trailer must be contained in the "trailer" request header. Otherwise, the entry is automatically deleted.
h1 response check and processing:
- If the user does not configure response, response code 200 is automatically returned.
- If the received request contains the request header "connection: close" but the response header "connection" is not added during response configuration or the value of the response header "connection" does not contain "close", "connection: close" is automatically added. If the received request does not contain the request header "connection: close" and the response header does not contain "connection: keep-alive", "connection: close" is automatically added.
- If headers contain a hop-by-hop response header, such as "proxy-connection", "keep-alive", "te", "transfer-encoding", or "upgrade", such header is automatically added to the response header "connection" as a value.
- The response header "date" is automatically added, and the "date" provided by the user is ignored.
- If the request method is "HEAD" or the response status code is "1XX", "204", or "304", the body is left empty.
- If the body length is known, it is compared with the response header "content-length". If the response header "content-length" does not exist, it is automatically added with its value being the body length. If the length of the response header "content-length" is greater than the body length, HttpException is thrown in the handler. If it is less than the body length, the body is truncated and the length of the sent body is the value of "content-length".
- The "set-cookie" headers in the response are sent separately, while other headers with the same name are combined for sending.
- When a request that contains the request header "expect: 100-continue" is processed, response code 100 is automatically sent to the client when body.read() of the request is called. Users are not allowed to send response whose status code is 100. If such response is sent, the server is considered abnormal.
To enable the h2 service, the value of supportedAlpnProtocols in tlsConfig must contain "h2". If the result of ALPN negotiation at the TLS layer is h2, the h2 service is enabled.
h2 request check and processing:
- The headers name and value must comply with specific rules. For details, see the description of the HttpHeaders class. In addition, the name cannot contain uppercase characters. Otherwise, the RST frame is sent to close the stream, that is, the response cannot be guaranteed.
- The trailers name and value must comply with the same rules. Otherwise, the stream is closed.
- The headers cannot contain "connection", "transfer-encoding", "keep-alive", "upgrade", or "proxy-connection." Otherwise, the stream is closed.
- If the "te" header exists, its value must be "trailers". Otherwise, the stream is closed.
- If the "host" header and ":authority" pseudo header exist, the value of "host" must be the same as that of ":authority". Otherwise, the stream is closed.
- If the "content-length" header exists, each value of "content-length" must support parsing to the Int64 type. If there are multiple values, the values must be the same. Otherwise, the stream is closed.
- If the "content-length" header and the body exist, the value of "content-length" must be the same as the body size. Otherwise, the stream is closed.
- If the "trailer" header exists, its value cannot contain "transfer-encoding", "trailer", or "content-length". Otherwise, the stream is closed.
- The CONNECT method is supported only in the WebSocket upgrade scenario. Otherwise, the stream is closed.
- The pseudo headers must contain ":method", ":scheme", and ":path". The value of ":method" must consist of tokens, the value of ":scheme" must be "https", and the value of ":path" cannot be empty. Otherwise, the stream is closed.
- The name of an entry in the trailer must be included in the "trailer" header. Otherwise, the entry is automatically deleted.
- The size of request headers cannot exceed the value of maxHeaderListSize. Otherwise, the connection is closed.
h2 response check and processing:
- If the response to the HEAD request contains a body, the body is automatically deleted.
- The "date" field is automatically added, and the "date" provided by the user is ignored.
- "connection", "transfer-encoding", "keep-alive", "upgrade", or "proxy-connection" contained in headers is automatically deleted.
- The "set-cookie" headers in the response are sent separately, while other headers with the same name are combined for sending.
- If headers contain "content-length" and the request method is not "HEAD", "content-length" is deleted.
- If the request method is "HEAD," then:
- If the headers contain "content-length" but "content-length" is invalid (it cannot be parsed to an Int64 value or contains multiple different values), HttpException is thrown when the user calls the write function of the HttpResponseWriter class to trigger verification. If the user does not perform such operation, logs are printed.
- If the headers contain "content-length", response.body.length is not –1, and the value of "content-length" is inconsistent with that of body.length, the handling method is the same as that in 6.1.
- If the headers contain "content-length" and response.body.length is –1, or the value of body.length is the same as that of "content-length", the "content-length" header is retained.
- The entries in the trailer must be included in the "trailer" header. Otherwise, the entries are automatically deleted.
- If an exception is thrown in the handler and the user does not call the write function to send partial response, response code 500 is returned. If the user has called the write function to send partial response, the RST frame is sent to close the stream.
After the h2 server sends a response, if the stream status is not CLOSED, the h2 server sends an RST frame with the NO_ERROR error code to close the stream to prevent the processed stream from occupying server resources.
h2 flow control:
- The initial value of the connection flow window is 65535. Each time a DATA frame is received, WINDOW-UPDATE at the connection layer is returned. When data is sent, if the value of the connection flow window is negative, the thread that sends data is blocked until the value becomes positive.
- The initial value of the stream flow window can be set by the user. The default value is 65535. Each time a DATA frame is received, WINDOW-UPDATE at the stream layer is returned. When data is sent, if the value of the stream flow window is negative, the thread that sends data is blocked until the value becomes positive.
h2 request priority:
- Requests can be processed by urgency. By default, the h2 service processes requests concurrently. When concurrent resources are insufficient, requests are processed by urgency. Requests with a higher priority are processed preferentially.
Default ProtocolServiceFactory protocol options:
- For TCP connections, the HTTP/1.1 server is used.
- For TLS connections, the HTTP protocol version is determined based on the result of ALPN negotiation. If the negotiation result is "HTTP/1.0", "HTTP/1.1", or "", the HTTP/1.1 server is used. If the negotiation result is "h2", the HTTP/2 server is used. Otherwise, the request is not processed, logs are printed, and the connection is closed.
Throws:
- SocketException: If listening on a port fails, this exception is thrown.
func updateCA(Array<X509Certificate>)
public func updateCA(newCa: Array<X509Certificate>): Unit
Description: Performs hot update for the CA certificate.
Parameters:
- newCa: Array<X509Certificate>: CA certificate
Throws:
- IllegalArgumentException: If parameters contain empty characters, this exception is thrown.
- HttpException: If tlsConfig is not configured on the server, this exception is thrown.
func updateCA(String)
public func updateCA(newCaFile: String): Unit
Description: Performs hot update for the CA certificate.
Parameters:
- newCaFile: String: CA certificate file
Throws:
- IllegalArgumentException: If parameters contain empty characters, this exception is thrown.
- HttpException: If tlsConfig is not configured on the server, this exception is thrown.
func updateCert(Array<X509Certificate>, PrivateKey)
public func updateCert(certChain: Array<X509Certificate>, certKey: PrivateKey): Unit
Description: Performs hot update for the TLS certificate.
Parameters:
- certChain: Array<X509Certificate>: certificate chain
- certKey: PrivateKey: certificate-matched private key
Throws:
- HttpException: If tlsConfig is not configured on the server, this exception is thrown.
func updateCert(String, String)
public func updateCert(certificateChainFile: String, privateKeyFile: String): Unit
Description: Performs hot update for the TLS certificate.
Parameters:
- certificateChainFile: String: certificate chain file
- privateKeyFile: String: certificate-matched private key file
Throws:
- IllegalArgumentException: If parameters contain empty characters, this exception is thrown.
- HttpException: If tlsConfig is not configured on the server, this exception is thrown.
class ServerBuilder
public class ServerBuilder {
public init()
}
Description: Provides a Server instance constructor.
The following parameters can be used to construct an HTTP Server:
- IP address or port
- Thread-safe logger
- HttpRequestDistributor, which is used to register handlers and distribute requests
- HTTP/2 settings
- shutdown callback
- transport, including the listener, connection, and configuration
- protocol service, which provides the HTTP protocol parsing service
Default implementation is provided for parameters except for address, port, and shutdown callback. The user does not need to specify other parameters when constructing the server. If the ServerBuilder document does not specify the supported version, the configuration is valid in both HTTP/1.1 and HTTP/2.
init()
public init()
Description: Creates a ServerBuilder instance.
func addr(String)
public func addr(addr: String): ServerBuilder
Description: Sets the listening address of the server. If the listener is set, this value is ignored.
Parameters:
Returns:
- ServerBuilder: reference of the current ServerBuilder
func afterBind(()->Unit)
public func afterBind(f: ()->Unit): ServerBuilder
Description: Registers the callback function on server startup. This function is called after the ServerSocket instance bind is called and before accept is called. Repeatedly calling this function overwrites the previously registered function.
Parameters:
- f: () ->Unit: callback function. The input parameter is empty, and the return value is of the Unit type.
Returns:
- ServerBuilder: reference of the current ServerBuilder
func build()
public func build(): Server
Description: Constructs a Server instance based on the configured attributes.
Returns:
Throws:
- IllegalArgumentException: If the parameter is invalid, this exception is thrown.
func distributor(HttpRequestDistributor)
public func distributor(distributor: HttpRequestDistributor): ServerBuilder
Description: Sets the request distributor which distributes requests to corresponding handlers according to URLs. If this parameter is not set, the default request distributor is used.
Parameters:
- distributor: HttpRequestDistributor: user-defined request distributor instance
Returns:
- ServerBuilder: reference of the current ServerBuilder
func enableConnectProtocol(Bool)
public func enableConnectProtocol(flag: Bool): ServerBuilder
Description: Specifies whether the local end receives CONNECT requests. The default value is false. This is valid only for HTTP/2.
Parameters:
- flag: Bool: whether the local end receives the CONNECT request
Returns:
- ServerBuilder: reference of the current ServerBuilder
func headerTableSize(UInt32)
public func headerTableSize(size: UInt32): ServerBuilder
Description: Sets the initial value of the HTTP/2 Hpack dynamic table on the server. The default value is 4096.
Parameters:
- size: UInt32: maximum
table sizeused by the local end to encode the response header
Returns:
- ServerBuilder: reference of the current ServerBuilder
func httpKeepAliveTimeout(Duration)
public func httpKeepAliveTimeout(timeout: Duration): ServerBuilder
Description: Specifies the keepalive duration of a connection on the server. If a client does not send a request again within the keepalive duration, the server closes the persistent connection. By default, the interval of sending requests is not limited. This is valid only for HTTP/1.1.
Parameters:
- timeout: Duration: timeout for maintaining a persistent connection. A negative value of the Duration is replaced with Duration.Zero.
Returns:
- ServerBuilder: reference of the current ServerBuilder
func initialWindowSize(UInt32)
public func initialWindowSize(size: UInt32): ServerBuilder
Description: Specifies the initial window size for receiving packets of each stream on the current server. The default value is 65535. This is valid only for HTTP/2. The value ranges from 0 to 2^31 – 1.
Parameters:
- size: UInt32: initial window size for receiving packets of a stream on the local end
Returns:
- ServerBuilder: reference of the current ServerBuilder
func listener(ServerSocket)
public func listener(listener: ServerSocket): ServerBuilder
Description: The server calls this function to bind and listen to a specified socket.
Parameters:
- listener: ServerSocket: bound socket
Returns:
- ServerBuilder: reference of the current ServerBuilder
func logger(Logger)
public func logger(logger: Logger): ServerBuilder
Description: Sets the server-side logger. The default logger level is INFO. The logger content is written to Console.stdout.
Parameters:
- logger: Logger: The logger must be thread-safe. By default, the built-in thread-safe logger is used.
Returns:
- ServerBuilder: reference of the current ServerBuilder
func maxConcurrentStreams(UInt32)
public func maxConcurrentStreams(size: UInt32): ServerBuilder
Description: Sets the maximum number of requests that can be concurrently processed by the local end and the number of requests that can be concurrently sent by the peer end. The default value is 100. This is valid only for HTTP/2.
Parameters:
- size: UInt32: maximum number of requests that can be concurrently processed by the local end
Returns:
- ServerBuilder: reference of the current ServerBuilder
func maxFrameSize(UInt32)
public func maxFrameSize(size: UInt32): ServerBuilder
Description: Sets the maximum length of a frame received by the local end to limit the length of a frame sent by the peer end. The default value is 16384. This is valid only for HTTP/2. The value ranges from 2^14 to 2^24 – 1.
Parameters:
- size: UInt32: maximum length of a frame received by the local end
Returns:
- ServerBuilder: reference of the current ServerBuilder
func maxHeaderListSize(UInt32)
public func maxHeaderListSize(size: UInt32): ServerBuilder
Description: Obtains the maximum header size of HTTP/2 supported by a client. The size refers to the sum of the maximum allowed lengths of all header fields in the response header, including the lengths of all field names and field values, and pseudo header overhead automatically added to each field. (Generally, each field has a 32-byte overhead, including the pseudo header information added by the HTTP/2 protocol to the header field.) By default, this maximum length is set to UInt32.Max.
Parameters:
- size: UInt32: maximum length of a packet header received by the local end
Returns:
- ServerBuilder: reference of the current ServerBuilder
func maxRequestBodySize(Int64)
public func maxRequestBodySize(size: Int64): ServerBuilder
Description: Sets the maximum length of a request body that the server allows a client to send. If the length of a request body exceeds this value, response code 413 is returned. The default value is 2 MB. This is valid only for HTTP/1.1 requests without "Transfer-Encoding: chunked" set.
Parameters:
- size: Int64: maximum size of a request body that can be received. The value 0 indicates that the size is not limited.
Returns:
- ServerBuilder: reference of the current ServerBuilder
Throws:
- IllegalArgumentException: If the input parameter size is less than 0, this exception is thrown.
func maxRequestHeaderSize(Int64)
public func maxRequestHeaderSize(size: Int64): ServerBuilder
Description: Sets the maximum length of a request header that the server allows a client to send. If the length of a request header exceeds this value, response code 431 is returned. This is valid only for HTTP/1.1. For HTTP/2, maxHeaderListSize is applicable.
Parameters:
- size: Int64: maximum size of a request header that can be received. The value 0 indicates that the size is not limited.
Returns:
- ServerBuilder: reference of the current ServerBuilder
Throws:
- IllegalArgumentException: If the input parameter size is less than 0, this exception is thrown.
func onShutdown(()->Unit)
public func onShutdown(f: ()->Unit): ServerBuilder
Description: Registers the callback function on server shutdown. This callback function is called on server shutdown. Repeatedly calling this function overwrites the previously registered function.
Parameters:
- f: () ->Unit: callback function. The input parameter is empty, and the return value is of the Unit type.
Returns:
- ServerBuilder: reference of the current ServerBuilder
func port(UInt16)
public func port(port: UInt16): ServerBuilder
Description: Sets the listening port of the server. If the listener is set, this value is ignored.
Parameters:
- port: UInt16: port number
Returns:
- ServerBuilder: reference of the current ServerBuilder
func protocolServiceFactory(ProtocolServiceFactory)
public func protocolServiceFactory(factory: ProtocolServiceFactory): ServerBuilder
Description: Sets the protocol service factory which generates the service instances required by each protocol. If this parameter is not set, the default factory is used.
Parameters:
- factory: ProtocolServiceFactory: user-defined factory instance
Returns:
- ServerBuilder: reference of the current ServerBuilder
func readHeaderTimeout(Duration)
public func readHeaderTimeout(timeout: Duration): ServerBuilder
Description: Sets the maximum duration for the server to read the request header of a request sent by a client. If the duration exceeds the value set, no read operation is performed and the connection is closed. By default, the read duration is not limited.
Parameters:
- timeout: Duration: timeout for reading a request header. A negative value of the Duration is replaced with Duration.Zero.
Returns:
- ServerBuilder: reference of the current ServerBuilder
func readTimeout(Duration)
public func readTimeout(timeout: Duration): ServerBuilder
Description: Sets the maximum duration for the server to read a request. If the duration exceeds the value set, no read operation is performed and the connection is closed. By default, the read timeout is not specified.
Parameters:
- timeout: Duration: timeout for reading a request. A negative value input is replaced with Duration.Zero.
Returns:
- ServerBuilder: reference of the current ServerBuilder
func servicePoolConfig(ServicePoolConfig)
public func servicePoolConfig(cfg: ServicePoolConfig): ServerBuilder
Description: Configures the coroutine pool used during service. For details, see the ServicePoolConfig struct.
Parameters:
- cfg: ServicePoolConfig: coroutine pool configuration
Returns:
- ServerBuilder: reference of the current ServerBuilder
func tlsConfig(TlsServerConfig)
public func tlsConfig(config: TlsServerConfig): ServerBuilder
Description: Sets the TLS layer configuration which is not set by default.
Parameters:
- config: TlsServerConfig: configuration information required for supporting the TLS service
Returns:
- ServerBuilder: reference of the current ServerBuilder
func transportConfig(TransportConfig)
public func transportConfig(config: TransportConfig): ServerBuilder
Description: Sets the transport layer configuration. For details about the default configuration, see the description of the TransportConfig struct.
Parameters:
- config: TransportConfig: transport layer configuration information
Returns:
- ServerBuilder: reference of the current ServerBuilder
func writeTimeout(Duration)
public func writeTimeout(timeout: Duration): ServerBuilder
Description: Sets the maximum duration for the server to send a response. If the duration exceeds the value set, no write operation is performed and the connection is closed. By default, the write timeout is not specified.
Parameters:
Returns:
- ServerBuilder: reference of the current ServerBuilder
class WebSocket
public class WebSocket
Description: Provides classes related to the WebSocket service and read, write, and close functions for the WebSocket connection. The user uses the upgradeFrom function to obtain the WebSocket connection.
- By calling
read()to read a WebSocketFrame, the user can know the frame type through WebSocketFrame.frameType and whether the frame is segmented through WebSocketFrame.fin. write(frameType: WebSocketFrameType, byteArray: Array<UInt8>)is called with the message type and message byte passed to send a WebSocket message. If a control frame is written, the message is not sent in fragments. If a data frame (Text or Binary) is written, the message is sent in multiple fragments based on the size of the underlying buffer.
For details, see the following interface description. The interface behavior is subject to RFC 6455.
prop logger
public prop logger: Logger
Description: Specifies a logger.
Type: Logger
prop subProtocol
public prop subProtocol: String
Description: Obtains the subProtocol negotiated with the peer end. During the negotiation, the client provides a list of subProtocols ranked by preference, and the server selects one or zero subprotocols from the list.
Type: String
static func upgradeFromClient(Client, URL, Protocol, ArrayList<String>, HttpHeaders)
public static func upgradeFromClient(client: Client, url: URL,
version!: Protocol = HTTP1_1,
subProtocols!: ArrayList<String> = ArrayList<String>(),
headers!: HttpHeaders = HttpHeaders()): (WebSocket, HttpHeaders)
Description: Provides a function for an upgrade to the WebSocket protocol on a client.
Note:
The upgrade process on a client is as follows: The client object and URL object are passed to construct an upgrade request. After the request is sent to the server, the client verifies the response. If the handshake is successful, the WebSocket object is returned for WebSocket communication, and the HttpHeaders object with response header 101 is returned to the user. Extensions are not supported. If the subprotocol negotiation is successful, the user can view the subprotocol by calling the subProtocol of returned WebSocket.
Parameters:
- client: Client: client object used for the request
- version!: Protocol: HTTP version used to create a socket. Only HTTP1_1 and HTTP2_0 can be upgraded to WebSocket.
- url: URL: URL object used for the request. During the WebSocket upgrade, the URL scheme must be ws or wss.
- subProtocols!: ArrayList<String>: user-defined list of subprotocols ranked by preference. It is empty by default. If the user configures the list, it is sent to the server with the update request.
- headers!: HttpHeaders: optional headers, such as cookies, sent along with the update request
Returns:
- (WebSocket, HttpHeaders): If the upgrade is successful, the WebSocket object is returned for communication together with the header of response code 101.
Throws:
- SocketException: If the underlying connection is incorrect, this exception is thrown.
- HttpException: If an error occurs upon handshake during the HTTP request process, this exception is thrown.
- WebSocketException: If the upgrade fails, or the upgrade response verification fails, this exception is thrown.
static func upgradeFromServer(HttpContext, ArrayList<String>, ArrayList<String>, (HttpRequest) -> HttpHeaders)
public static func upgradeFromServer(ctx: HttpContext, subProtocols!: ArrayList<String> = ArrayList<String>(),
origins!: ArrayList<String> = ArrayList<String>(),
userFunc!:(HttpRequest) -> HttpHeaders = {_: HttpRequest => HttpHeaders()}): WebSocket
Description: Provides a function for an upgrade to the WebSocket protocol on the server. This function is usually used in handlers.
The upgrade process on the server is as follows: After receiving an upgrade request from a client, the server verifies the request. If the verification is successful, the server returns response code 101 and the WebSocket object for WebSocket communication.
- The user configures the supported subprotocol and origin whitelists by setting the subProtocols and origins parameters. If the subProtocols parameter is not set, subprotocols are not supported. If the origins parameter is not set, handshake requests from all origins are accepted.
- The user uses userFunc to define the upgrade request processing behavior, such as cookie processing. The input userFunc requires an HttpHeaders object, which is returned to the client through a 101 response. (The object is not returned if the upgrade fails.)
- WebSocket extensions are not supported currently. Therefore, if extensions negotiation occurs during handshake, WebSocketException is thrown.
- Only HTTP1_1 and HTTP2_0 can be upgraded to WebSocket.
Parameters:
- ctx: HttpContext: HTTP request context. Parameters input to the handler are directly passed to upgradeFromServer.
- subProtocols!: ArrayList<String>: user-defined list of subprotocols. The default value is empty, indicating that subprotocols are not supported. If the user configures the list, the first subprotocol in the upgrade request is used as the subprotocol of the upgraded WebSocket. The user can view the subprotocol by calling the subProtocol of returned WebSocket.
- origins!: ArrayList<String>: user-defined list of origins from which handshakes are accepted. If the list is not defined, handshakes from all origins are accepted. If the list is defined, only handshakes from the origins defined in the list are accepted.
- userFunc!: (HttpRequest) ->HttpHeaders: user-defined function for processing upgrade requests. This function returns HttpHeaders.
Returns:
func closeConn()
public func closeConn(): Unit
Description: Provides a function for closing the underlying WebSocket connection.
Note:
The underlying connection is directly closed. The close process must comply with the handshake process specified in the protocol. That is, the local end sends a Close frame to the peer end and waits for a Close frame from the peer end. The underlying connection can be closed only after the handshake process is complete.
func read()
public func read(): WebSocketFrame
Description: Reads a frame from a connection. If the data on the connection is not ready, the read thread is blocked. This is not thread-safe. (That is, multi-thread read is not supported for the same WebSocket object.)
The read function returns a WebSocketFrame object. The user can call the frameType and fin attribute of WebSocketFrame to determine the frame type and whether the frame called is segmented. The raw binary data array Array<UInt8> is obtained by using the payload function of WebSocketFrame.
- For a segmented frame, first segment: fin == false, frameType == TextWebFrame or BinaryWebFrame; intermediate segment: fin == false, frameType == ContinuationWebFrame; tail segment: fin == true, frameType == ContinuationWebFrame.
- For a non-segmented frame, fin == true, frameType != ContinuationWebFrame.
Note:
- Data frames (Text or Binary) can be segmented. The user needs to call the read function for multiple times to read all segments (that is, receiving a complete message), and then splice the payloads of the segments in the sequence they are received. The payload of the Text frame is in UTF-8 format. After receiving a complete message, the user calls the String.fromUtf8 function to convert the spliced payload to a string. The meaning of the payload of the binary frame is determined by the application that uses the payload. After receiving the complete message, the user sends the spliced payload to the upper-layer application.
- Control frames (Close, Ping, and Pong) cannot be segmented.
- A control frame cannot be segmented, but can be inserted between data frame segments. No other data frame is allowed between data frame segments. Data frame segments with inserted data frames are considered as errors.
- If the client receives the masked frame, or the server receives the unmasked frame, the underlying connection is interrupted and an exception is thrown.
- If the rsv1, rsv2, and rsv3 bits are set (extensions are not supported currently, so the rsv bit must be 0), the underlying connection is interrupted and an exception is thrown.
- If a frame type (other than Continuation, Text, Binary, Close, Ping, and Pong) that is not supported is received, the underlying connection is interrupted and an exception is thrown.
- If a control frame (Close, Ping, or Pong) whose payload length is greater than 125 bytes or a segmented control frame is received, the underlying connection is interrupted and an exception is thrown.
- If a frame whose payload length is greater than 20 MB is received, the underlying connection is interrupted and an exception is thrown.
- If read is called after the connection is closed using closeConn, an exception is thrown.
Returns:
- WebSocketFrame: WebSocketFrame object read
Throws:
- SocketException: underlying connection error
- WebSocketException: If a frame that does not comply with the protocol is received, a Close frame is sent to the peer end to indicate the error information and the underlying connection is interrupted.
- ConnectionException: If data is read from the connection that has been closed by the peer end, this exception is thrown.
func write(WebSocketFrameType, Array<UInt8>, Int64)
public func write(frameType: WebSocketFrameType, byteArray: Array<UInt8>, frameSize!: Int64 = FRAMESIZE): Unit
Description: Sends data. This is not thread-safe. (That is, multi-thread write is not supported for the same WebSocket object.)
Note:
The write function sends data to the peer end in the form of WebSocket frames.
- If the size of the input byteArray is greater than frameSize (4 x 1024 bytes by default) when a data frame (Text or Binary) is sent, the data frame (text or binary) is divided into payloads whose size is less than or equal to frameSize and sent in segments. Otherwise, the data frame is not segmented.
- If the size of the input byteArray must be less than or equal to 125 bytes when a control frame (Close, Ping, or Pong) is sent, the first two bytes of the Close frame are status codes. For details about available status codes, see RFC 6455 7.4. According to the Status Codes protocol, after a Close frame is sent, data frames cannot be sent. Otherwise, an exception is thrown.
- The user needs to ensure that the input byteArray complies with the protocol. For example, the payload of the Text frame must be encoded in UTF-8 format. If frameSize is set for the data frame, the value must be greater than 0. Otherwise, an exception is thrown.
- If the value of frameSize is less than or equal to 0 when a data frame is sent, an exception is thrown.
- If the input data is greater than 125 bytes when the user sends a control frame, an exception is thrown.
- If the user inputs a frame type other than Text, Binary, Close, Ping, and Pong type, an exception is thrown.
- If an invalid status code is input when the Close frame is sent or the reason data exceeds 123 bytes, an exception is thrown.
- If data frames are sent after the Close frame is sent, an exception is thrown.
- If write is called after the connection is closed using closeConn, an exception is thrown.
Parameters:
- frameType: WebSocketFrameType: type of the frame to be sent
- byteArray: Array<UInt8>: payload (in binary format) of the frame to be sent
- frameSize!: Int64: size of the frame segment. The default size is 4 x 1024 bytes. The frameSize is not valid for control frames.
Throws:
- SocketException: If the underlying connection is incorrect, this exception is thrown.
- WebSocketException: If the input frame type or data is invalid, this exception is thrown.
func writeCloseFrame(?UInt16, String)
public func writeCloseFrame(status!: ?UInt16 = None, reason!: String = ""): Unit
Description: Sends the Close frame.
Note:
According to the protocol, data frames cannot be sent after the Close frame is sent. If the user does not set the status, the reason is not sent (that is, the reason must be sent with the status). The payload of the control frame does not exceed 125 bytes. The first two bytes of the Close frame are the status. Therefore, the reason cannot exceed 123 bytes. If write is called after the connection is closed using closeConn, an exception is thrown.
Parameters:
- status!: ?UInt16: status code of the Close frame sent. The default value is None, indicating that the status code and reason are not sent.
- reason!: String: description of closing a connection. This parameter is an empty string by default, and it is converted to UTF-8 when being sent. This parameter is used for debugging, and it may be unreadable.
Throws:
- WebSocketException: If an invalid status code is input or the reason data exceeds 123 bytes, this exception is thrown.
func writePingFrame(Array<UInt8>)
public func writePingFrame(byteArray: Array<UInt8>): Unit
Description: Provides a shortcut function for sending Ping frames. If write is called after the connection is closed using closeConn, an exception is thrown.
Parameters:
Throws:
- SocketException: If the underlying connection is incorrect, this exception is thrown.
- WebSocketException: If the input data is greater than 125 bytes, this exception is thrown.
func writePongFrame(Array<UInt8>)
public func writePongFrame(byteArray: Array<UInt8>): Unit
Description: Provides a shortcut function for sending Pong frames. If write is called after the connection is closed using closeConn, an exception is thrown.
Parameters:
Throws:
- SocketException: If the underlying connection is incorrect, this exception is thrown.
- WebSocketException: If the input data is greater than 125 bytes, this exception is thrown.
class WebSocketFrame
public class WebSocketFrame
Description: Specifies the basic unit used by WebSocket for read.
WebSocketFrame provides three attributes, where fin and frameType indicate the frame type and whether the frame is segmented. Payload is the payload of the frame.
- For a segmented frame, first segment: fin == false, frameType == TextWebFrame or BinaryWebFrame;
- intermediate segment: fin == false, frameType == ContinuationWebFrame;
- tail segment: fin == true, frameType == ContinuationWebFrame.
- For a non-segmented frame, fin == true, frameType != ContinuationWebFrame.
- The user can obtain WebSocketFrame only by calling the read function of the WebSocket object. Data frames can be segmented. If the user receives a segmented frame, the read function must be called for multiple times until a complete message is received, and the payloads of all segments must be spliced in the sequence they are received.
Note:
Since the control frame may be inserted between frame segments, the user needs to separately process the control frame when splicing the payloads of frame segments. Only control frames can be inserted between frame segments. Other data frames between frame segments are considered as errors.
prop fin
public prop fin: Bool
Description: Obtains the fin attribute of WebSocketFrame. fin and frameType indicate the frame type and whether the frame is segmented.
Type: Bool
prop frameType
public prop frameType: WebSocketFrameType
Description: Obtains the frame type of WebSocketFrame. fin and frameType indicate the frame type and whether the frame is segmented.
Type: WebSocketFrameType
prop payload
public prop payload: Array<UInt8>
Description: Obtains the frame payload of WebSocketFrame. For a segmented data frame, after receiving a complete message, the user needs to splice the payloads of all segments in the sequence they are received.
Enumeration
enum FileHandlerType
public enum FileHandlerType {
| DownLoad
| UpLoad
}
Description: Sets the FileHandler mode to upload or download.
DownLoad
DownLoad
Description: Sets the FileHandler to the download mode.
UpLoad
UpLoad
Description: Sets the FileHandler to the upload mode.
enum Protocol
public enum Protocol <: Equatable<Protocol> & ToString {
| HTTP1_0
| HTTP1_1
| HTTP2_0
| UnknownProtocol(String)
}
Description: Defines the HTTP protocol type enumeration.
Parent Type:
HTTP1_0
HTTP1_0
Description: Defines HTTP1_0.
HTTP1_1
HTTP1_1
Description: Defines HTTP1_1.
HTTP2_0
HTTP2_0
Description: Defines HTTP2_0.
UnknownProtocol(String)
UnknownProtocol(String)
Description: Defines the unknown HTTP protocol.
func toString()
public override func toString(): String
Description: Obtains the HTTP protocol version string.
Returns:
- String: HTTP protocol version string
operator func != (Protocol)
public override operator func != (that: Protocol): Bool
Description: Checks whether enumerated values are not equal.
Parameters:
- that: Protocol: enumerated value to be compared
Returns:
- Bool: If the current instance is not equal to
that,trueis returned. Otherwise,falseis returned.
operator func == (Protocol)
public override operator func == (that: Protocol): Bool
Description: Checks whether enumerated values are equal.
Parameters:
- that: Protocol: enumerated value to be compared
Returns:
- Bool: If the current instance is equal to
that,trueis returned. Otherwise,falseis returned.
enum WebSocketFrameType
public enum WebSocketFrameType <: Equatable<WebSocketFrameType> & ToString {
| ContinuationWebFrame
| TextWebFrame
| BinaryWebFrame
| CloseWebFrame
| PingWebFrame
| PongWebFrame
| UnknownWebFrame
}
Description: Defines the enumeration type of WebSocketFrame.
Parent Type:
ContinuationWebFrame
ContinuationWebFrame
Description: Defines the unfinished fragmented frame in the WebSocket protocol.
TextWebFrame
TextWebFrame
Description: Defines the text frame in the WebSocket protocol.
BinaryWebFrame
BinaryWebFrame
Description: Defines the data frame in the WebSocket protocol.
CloseWebFrame
CloseWebFrame
Description: Defines the close frame in the WebSocket protocol.
PingWebFrame
PingWebFrame
Description: Defines the heartbeat frame in the WebSocket protocol.
PongWebFrame
PongWebFrame
Description: Defines the heartbeat frame in the WebSocket protocol.
UnknownWebFrame
UnknownWebFrame
Description: Defines unknown frames in the WebSocket protocol.
func toString()
public override func toString(): String
Description: Obtains the WebSocket frame type string.
Returns:
operator func != (WebSocketFrameType)
public override operator func != (that: WebSocketFrameType): Bool
Description: Checks whether enumerated values are not equal.
Parameters:
- that: WebSocketFrameType: enumerated value to be compared
Returns:
- Bool: If the current instance is not equal to
that,trueis returned. Otherwise,falseis returned.
operator func == (WebSocketFrameType)
public override operator func == (that: WebSocketFrameType): Bool
Description: Checks whether enumerated values are equal.
Parameters:
- that: WebSocketFrameType: enumerated value to be compared
Returns:
- Bool: If the current instance is equal to
that,trueis returned. Otherwise,falseis returned.
Struct
struct HttpStatusCode
public struct HttpStatusCode
Description: Specifies a 3-digit code that indicates the response status of Hypertext Transfer Protocol (HTTP) of the web server.
Status codes are defined in RFC 9110 and in extended specifications RFC2518, RFC 3229, RFC 4918, RFC 5842, RFC 7168, and RFC 8297.
The first digit of all status codes indicates one of the following five types of response:
- 1xx (information): indicates an interim response for the communication connection status or request progress before the requested operation is completed and the final response is sent.
- 2xx (success): indicates that the client's request has been successfully received, understood, and accepted.
- 3xx (redirection): indicates that the user proxy needs to take further actions to complete the request.
- 4xx (client error): indicates that an error occurs on the client.
- 5xx (server error): indicates that the server is aware of an error or it cannot fulfill the request.
static const STATUS_ACCEPTED
public static const STATUS_ACCEPTED: UInt16 = 202
Description: The server has accepted the request but has not processed it.
Type: Int64
static const STATUS_ALREADY_REPORTED
public static const STATUS_ALREADY_REPORTED: UInt16 = 208
Description: The message body is an XML message.
Type: Int64
static const STATUS_BAD_GATEWAY
public static const STATUS_BAD_GATEWAY: UInt16 = 502
Description: The server, when attempting to fulfill the request as a gateway or proxy, receives an invalid response from its upstream server.
Type: Int64
static const STATUS_BAD_REQUEST
public static const STATUS_BAD_REQUEST: UInt16 = 400
Description: The request cannot be understood by the server due to incorrect syntax or request parameters.
Type: Int64
static const STATUS_CONFLICT
public static const STATUS_CONFLICT: UInt16 = 409
Description: The request cannot be fulfilled due to a conflict with the current state of the requested resource.
Type: Int64
static const STATUS_CONTINUE
public static const STATUS_CONTINUE: UInt16 = 100
Description: This interim response is issued while request processing continues. It alerts the client to wait for a final response.
Type: Int64
Note:
The client should continue sending the remaining part of the request, or ignore the response if the request has been fulfilled. The server must send a final response to the client after the request is fulfilled.
static const STATUS_CREATED
public static const STATUS_CREATED: UInt16 = 201
Description: The request has been fulfilled and resulted in a new resource being created, and the URI of the resource has been returned with the Location header information.
Type: Int64
static const STATUS_EARLY_HINTS
public static const STATUS_EARLY_HINTS: UInt16 = 103
Description: Preloads CSS and JS files in advance.
Type: Int64
static const STATUS_EXPECTATION_FAILED
public static const STATUS_EXPECTATION_FAILED: UInt16 = 417
Description: The server fails to meet the Expect request header information.
Type: Int64
static const STATUS_FAILED_DEPENDENCY
public static const STATUS_FAILED_DEPENDENCY: UInt16 = 424
Description: The current request fails due to an error in a previous request.
Type: Int64
static const STATUS_FORBIDDEN
public static const STATUS_FORBIDDEN: UInt16 = 403
Description: The server has understood the request but refuses to fulfill it.
Type: Int64
static const STATUS_FOUND
public static const STATUS_FOUND: UInt16 = 302
Description: Assigns a new temporary URI.
Type: Int64
Note:
The requested resource has been assigned a new temporary URI. The client should send subsequent requests to the original URI.
static const STATUS_GATEWAY_TIMEOUT
public static const STATUS_GATEWAY_TIMEOUT: UInt16 = 504
Description: The response from the upstream server (identified by the URI, such as HTTP, FTP, and LDAP) or secondary server (such as DNS) times out.
Type: Int64
static const STATUS_GONE
public static const STATUS_GONE: UInt16 = 410
Description: The requested resource is no longer available on the server and no forwarding address is known.
Type: Int64
static const STATUS_HTTP_VERSION_NOT_SUPPORTED
public static const STATUS_HTTP_VERSION_NOT_SUPPORTED: UInt16 = 505
Description: The server does not support or refuses to support the HTTP version used in the request.
Type: Int64
static const STATUS_IM_USED
public static const STATUS_IM_USED: UInt16 = 226
Description: The server has fulfilled the request for the resource, and the response represents the result of one or more instance operations applied to the current instance.
Type: Int64
static const STATUS_INSUFFICIENT_STORAGE
public static const STATUS_INSUFFICIENT_STORAGE: UInt16 = 507
Description: The server fails to store the content required to fulfill the request.
Type: Int64
static const STATUS_INTERNAL_SERVER_ERROR
public static const STATUS_INTERNAL_SERVER_ERROR: UInt16 = 500
Description: The server encountered an unexpected condition which prevented it from processing the request.
Type: Int64
static const STATUS_LENGTH_REQUIRED
public static const STATUS_LENGTH_REQUIRED: UInt16 = 411
Description: The server refuses to accept the request without a defined Content-Length header.
Type: Int64
static const STATUS_LOCKED
public static const STATUS_LOCKED: UInt16 = 423
Description: The current resource is locked.
Type: Int64
static const STATUS_LOOP_DETECTED
public static const STATUS_LOOP_DETECTED: UInt16 = 508
Description: The server detects infinite recursion when processing a request.
Type: Int64
static const STATUS_METHOD_NOT_ALLOWED
public static const STATUS_METHOD_NOT_ALLOWED: UInt16 = 405
Description: The request function specified in the request line cannot be used to request the response resource.
Type: Int64
static const STATUS_MISDIRECTED_REQUEST
public static const STATUS_MISDIRECTED_REQUEST: UInt16 = 421
Description: The request is directed to a server that cannot generate a response.
Type: Int64
static const STATUS_MOVED_PERMANENTLY
public static const STATUS_MOVED_PERMANENTLY: UInt16 = 301
Description: Assigns a new permanent URI.
Type: Int64
Note:
The requested resource has been assigned a new permanent URI and any future references to this resource will be redirected to this URI.
static const STATUS_MULTIPLE_CHOICES
public static const STATUS_MULTIPLE_CHOICES: UInt16 = 300
Description: The requested resource has a series of optional feedback information. Each feedback has its own address and browser-driven negotiation information.
Type: Int64
Note:
The user or browser can select a preferred address for redirection.
static const STATUS_MULTI_STATUS
public static const STATUS_MULTI_STATUS: UInt16 = 207
Description: The members bound to the DAV have been listed before the (multi-state) response and are not included again.
Type: Int64
static const STATUS_NETWORK_AUTHENTICATION_REQUIRED
public static const STATUS_NETWORK_AUTHENTICATION_REQUIRED: UInt16 = 511
Description: Network authentication is required.
Type: Int64
static const STATUS_NON_AUTHORITATIVE_INFO
public static const STATUS_NON_AUTHORITATIVE_INFO: UInt16 = 203
Description: The server has successfully processed the request.
Type: Int64
Note:
The returned entity header metadata is not a definite set valid on the original server, but a copy from the local or a third party.
static const STATUS_NOT_ACCEPTABLE
public static const STATUS_NOT_ACCEPTABLE: UInt16 = 406
Description: The content characteristics of the requested resource cannot meet the conditions listed in the request header. Therefore, the response entity cannot be generated.
Type: Int64
static const STATUS_NOT_EXTENDED
public static const STATUS_NOT_EXTENDED: UInt16 = 510
Description: The policy required for obtaining resource is not met.
Type: Int64
static const STATUS_NOT_FOUND
public static const STATUS_NOT_FOUND: UInt16 = 404
Description: The request fails because the requested resource is not found on the server.
Type: Int64
static const STATUS_NOT_IMPLEMENTED
public static const STATUS_NOT_IMPLEMENTED: UInt16 = 501
Description: The server does not support a function required to fulfill the request.
Type: Int64
static const STATUS_NOT_MODIFIED
public static const STATUS_NOT_MODIFIED: UInt16 = 304
Description: The requested resource has not been modified. When the server returns this status code, it does not return any resources.
Type: Int64
Note:
The client usually caches the resources that have been accessed. When the client wants to receive the resources that are modified after the specified date, it provides a header to indicate such resources.
static const STATUS_NO_CONTENT
public static const STATUS_NO_CONTENT: UInt16 = 204
Description: The server has successfully fulfilled the request but does not return any content.
Type: Int64
static const STATUS_OK
public static const STATUS_OK: UInt16 = 200
Description: The request has succeeded. The response headers or data body expected by the request will be returned together with the response.
Type: Int64
static const STATUS_PARTIAL_CONTENT
public static const STATUS_PARTIAL_CONTENT: UInt16 = 206
Description: The server has successfully processed some GET requests.
Type: Int64
static const STATUS_PAYMENT_REQUIRED
public static const STATUS_PAYMENT_REQUIRED: UInt16 = 402
Description: Reserves status code for future requirements.
Type: Int64
static const STATUS_PERMANENT_REDIRECT
public static const STATUS_PERMANENT_REDIRECT: UInt16 = 308
Description: The request and all future requests should use the other URI.
Type: Int64
static const STATUS_PRECONDITION_FAILED
public static const STATUS_PRECONDITION_FAILED: UInt16 = 412
Description: One or more preconditions specified in the request header field are not met when the server verifies the preconditions.
Type: Int64
static const STATUS_PRECONDITION_REQUIRED
public static const STATUS_PRECONDITION_REQUIRED: UInt16 = 428
Description: Specifies some preconditions that must be met when the client sends an HTTP request.
Type: Int64
static const STATUS_PROCESSING
public static const STATUS_PROCESSING: UInt16 = 102
Description: The processing continues.
Type: Int64
static const STATUS_PROXY_AUTH_REQUIRED
public static const STATUS_PROXY_AUTH_REQUIRED: UInt16 = 407
Description: Identity authentication must be performed on the proxy server.
Type: Int64
static const STATUS_REQUESTED_RANGE_NOT_SATISFIABLE
public static const STATUS_REQUESTED_RANGE_NOT_SATISFIABLE: UInt16 = 416
Description: The requested range is invalid.
Type: Int64
Note:
The request contains the
Rangerequest header, and any data range specified in theRangedoes not overlap the available range of the current resource. In addition, theIf-Rangerequest header is not defined in the request.
static const STATUS_REQUEST_CONTENT_TOO_LARGE
public static const STATUS_REQUEST_CONTENT_TOO_LARGE: UInt16 = 413
Description: The size of the entity data submitted in the request exceeds the processing capability of the server.
Type: Int64
static const STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE
public static const STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE: UInt16 = 431
Description: The request header field is too large.
Type: Int64
static const STATUS_REQUEST_TIMEOUT
public static const STATUS_REQUEST_TIMEOUT: UInt16 = 408
Description: The request times out. The client fails to send a request within the waiting time of the server.
Type: Int64
static const STATUS_REQUEST_URI_TOO_LONG
public static const STATUS_REQUEST_URI_TOO_LONG: UInt16 = 414
Description: The URI length of the request exceeds the length that the server can interpret.
Type: Int64
static const STATUS_RESET_CONTENT
public static const STATUS_RESET_CONTENT: UInt16 = 205
Description: The server successfully processes the request and does not return any content. The requester is expected to reset the document view.
Type: Int64
static const STATUS_SEE_OTHER
public static const STATUS_SEE_OTHER: UInt16 = 303
Description: The response to the current request can be found on the other URL, and the client should access the resource using GET method.
Type: Int64
static const STATUS_SERVICE_UNAVAILABLE
public static const STATUS_SERVICE_UNAVAILABLE: UInt16 = 503
Description: The server is temporarily maintained or overloaded.
Type: Int64
static const STATUS_SWITCHING_PROTOCOLS
public static const STATUS_SWITCHING_PROTOCOLS: UInt16 = 101
Description: The server understands the client's request and uses the Upgrade header field to instruct the client to use different protocols to fulfill the request.
Type: Int64
Note:
After sending the last blank line of the response, the server switches to the protocols defined in the Upgrade message header.
static const STATUS_TEAPOT
public static const STATUS_TEAPOT: UInt16 = 418
Description: The server cannot process the request and sends a status code called "I am a teapot" to the client. This code should not be taken seriously.
Type: Int64
static const STATUS_TEMPORARY_REDIRECT
public static const STATUS_TEMPORARY_REDIRECT: UInt16 = 307
Description: Performs temporary redirection.
Type: Int64
static const STATUS_TOO_EARLY
public static const STATUS_TOO_EARLY: UInt16 = 425
Description: The server is unwilling to take risks to process the request.
Type: Int64
static const STATUS_TOO_MANY_REQUESTS
public static const STATUS_TOO_MANY_REQUESTS: UInt16 = 429
Description: There are too many requests.
Type: Int64
static const STATUS_UNAUTHORIZED
public static const STATUS_UNAUTHORIZED: UInt16 = 401
Description: The request requires user authentication.
Type: Int64
static const STATUS_UNAVAILABLE_FOR_LEGAL_REASONS
public static const STATUS_UNAVAILABLE_FOR_LEGAL_REASONS: UInt16 = 451
Description: The request is unavailable for legal reasons.
Type: Int64
static const STATUS_UNPROCESSABLE_ENTITY
public static const STATUS_UNPROCESSABLE_ENTITY: UInt16 = 422
Description: The format of the request is correct, but no response is given due to semantic errors.
Type: Int64
static const STATUS_UNSUPPORTED_MEDIA_TYPE
public static const STATUS_UNSUPPORTED_MEDIA_TYPE: UInt16 = 415
Description: The server does not support the media format in the request.
Type: Int64
Note:
The request is refused because the entity of the request is in a format not supported by the server in terms of the current request function and requested resources.
static const STATUS_UPGRADE_REQUIRED
public static const STATUS_UPGRADE_REQUIRED: UInt16 = 426
Description: The server rejects the request sent by the client using the current protocol, but can accept the request sent by using an upgraded protocol.
Type: Int64
static const STATUS_USE_PROXY
public static const STATUS_USE_PROXY: UInt16 = 305
Description: Uses a proxy. The requested resource must be accessed through a proxy.
Type: Int64
static const STATUS_VARIANT_ALSO_NEGOTIATES
public static const STATUS_VARIANT_ALSO_NEGOTIATES: UInt16 = 506
Description: An internal configuration error occurs on the server.
Type: Int64
struct ServicePoolConfig
public struct ServicePoolConfig
Description: Configures the HTTP Server coroutine pool.
Note:
Each time an HTTP/1.1 Server receives a request, it obtains a coroutine from the pool for processing. If the task waiting queue is full, the request is rejected and the connection is interrupted. An HTTP/2 Server obtains several coroutines from the pool for processing. If the task waiting queue is full, the processing is blocked until there are idle coroutines.
let capacity
public let capacity: Int64
Description: Obtains the coroutine pool capacity.
Type: Int64
let preheat
public let preheat: Int64
Description: Obtains the number of coroutines that are started before the service is started.
Type: Int64
let queueCapacity
public let queueCapacity: Int64
Description: Obtains the maximum number of waiting tasks in the buffer.
Type: Int64
init(Int64, Int64, Int64)
public init(
capacity!: Int64 = 10 ** 4,
queueCapacity!: Int64 = 10 ** 4,
preheat!: Int64 = 0
)
Description: Constructs a ServicePoolConfig instance.
Parameters:
- capacity!: Int64: coroutine pool capacity. The default value is 10000.
- queueCapacity!: Int64: maximum number of waiting tasks in the buffer. The default value is 10000.
- preheat!: Int64: number of coroutines that are started before the service is started. The default value is 0.
Throws:
- IllegalArgumentException: If the value of capacity, queueCapacity, or preheat is less than 0, or the value of preheat is greater than that of capacity, this exception is thrown.
struct TransportConfig
public struct TransportConfig
Description: Specifies a transport layer configuration class used by the server to establish a connection.
prop keepAliveConfig
public mut prop keepAliveConfig: SocketKeepAliveConfig
Description: Sets and reads the message keepalive configuration of the connection at the transport layer. The default idle time for configuration is 45s, the interval for sending probe packets is 5s, and the number of probe packets sent before the connection is considered invalid is 5. The actual time granularity may vary according to the operating system.
Type: SocketKeepAliveConfig
prop readBufferSize
public mut prop readBufferSize: ?Int64
Description: Sets and reads the read buffer size of the connection at the transport layer. The default value is None. If the value is less than 0, IllegalArgumentException is thrown after the server service connection is established.
Note:
When the default value is used, the actual buffer size is determined by the operating system.
Type: ?Int64
prop readTimeout
public mut prop readTimeout: Duration
Description: Sets and reads the read timeout of the connection at the transport layer. If the value is less than 0, it is set to 0. The default value is Duration.Max.
Type: Duration
prop writeBufferSize
public mut prop writeBufferSize: ?Int64
Description: Sets and reads the write buffer size of the connection at the transport layer. The default value is None. If the value is less than 0, IllegalArgumentException is thrown after the server service connection is established.
Note:
When the default value is used, the actual buffer size is determined by the operating system.
Type: ?Int64
prop writeTimeout
public mut prop writeTimeout: Duration
Description: Sets and reads the write timeout of the connection at the transport layer. If the value is less than 0, it is set to 0. The default value is Duration.Max.
Type: Duration
Exception Class
class ConnectionException
public class ConnectionException <: Exception {
public init(message: String)
}
Description: Specifies the TCP connection exception class of HTTP.
Parent Type:
init(String)
public init(message: String)
Description: Creates a ConnectionException instance.
Parameters:
- message: String: exception information
class CoroutinePoolRejectException
public class CoroutinePoolRejectException <: Exception {
public init(message: String)
}
Description: Specifies the exception class of HTTP coroutine pool rejecting processing requests.
Parent Type:
init(String)
public init(message: String)
Description: Creates a CoroutinePoolRejectException instance.
Parameters:
- message: String: exception information
class HttpException
public class HttpException <: Exception {
public init(message: String)
}
Description: Specifies the common exception class of HTTP.
Parent Type:
init(String)
public init(message: String)
Description: Creates an HttpException instance.
Parameters:
- message: String: exception information
class HttpStatusException
public class HttpStatusException <: Exception {
public init(message: String)
}
Description: Specifies the response status exception class of HTTP.
Parent Type:
init(String)
public init(message: String)
Description: Creates an HttpStatusException instance.
Parameters:
- message: String: exception information
class HttpTimeoutException
public class HttpTimeoutException <: Exception {
public init(message: String)
}
Description: Specifies the timeout exception class of HTTP.
Parent Type:
init(String)
public init(message: String)
Description: Creates an HttpTimeoutException instance.
Parameters:
- message: String: exception information
class WebSocketException
public class WebSocketException <: Exception {
public init(message: String)
}
Description: Specifies the common exception class of WebSocket.
Parent Type:
init(String)
public init(message: String)
Description: Creates a WebSocketException instance.
Parameters:
- message: String: exception information
client
Hello World
import net.http.*
main () {
// 1 Constructs a client instance.
let client = ClientBuilder().build()
// 2 Sends a request.
let rsp = client.get("http://example.com/hello")
// 3 Reads the response.
println(rsp)
// 4 Closes the connection.
client.close()
}
Running result:
HTTP/1.1 200 OK
accept-ranges: bytes
age: 258597
cache-control: max-age=604800
content-type: text/html
date: Wed, 05 Jun 2024 02:19:26 GMT
etag: "3147526947"
expires: Wed, 12 Jun 2024 02:19:26 GMT
last-modified: Thu, 17 Oct 2019 07:18:26 GMT
server: ECAcc (lac/55A4)
vary: Accept-Encoding
x-cache: HIT
content-length: 1256
connection: close
body size: 1256
User-defined Client Network Configuration
import std.socket.{TcpSocket, SocketAddress}
import std.convert.Parsable
import std.fs.*
import net.tls.*
import crypto.x509.X509Certificate
import net.http.*
// This program can be executed only when an existing valid file path is configured.
main () {
// 1. User-defined configuration
// TLS configuration
var tlsConfig = TlsClientConfig()
let pem = String.fromUtf8(File("/rootCerPath", OpenOption.Open(true, false)).readToEnd())
tlsConfig.verifyMode = CustomCA(X509Certificate.decodeFromPem(pem))
tlsConfig.alpnProtocolsList = ["h2"]
// connector
let TcpSocketConnector = { sa: SocketAddress =>
let socket = TcpSocket(sa)
socket.connect()
return socket
}
// 2 Constructs a client instance.
let client = ClientBuilder()
.tlsConfig(tlsConfig)
.enablePush(false)
.connector(TcpSocketConnector)
.build()
// 3 Sends a request.
let rsp = client.get("https://example.com/hello")
// 4 Reads the response.
let buf = Array<UInt8>(1024, item: 0)
let len = rsp.body.read(buf)
println(String.fromUtf8(buf.slice(0, len)))
// 5 Closes the connection.
client.close()
}
chunked and trailer in the Request
import std.io.*
import std.fs.*
import net.http.*
func checksum(chunk: Array<UInt8>): Int64 {
var sum = 0
for (i in chunk) {
if (i == b'\n') {
sum += 1
}
}
return sum / 2
}
// This program can be executed only when an existing valid file path is configured.
main () {
// 1 Constructs a client instance.
let client = ClientBuilder().build()
var requestBuilder = HttpRequestBuilder()
let file = File("./res.jpg", OpenOption.Open(true, false))
let sum = checksum(file.readToEnd())
let req = requestBuilder
.method("PUT")
.url("https://example.com/src/")
.header("Transfer-Encoding","chunked")
.header("Trailer","checksum")
.body(FileBody("./res.jpg"))
.trailer("checksum", sum.toString())
.build()
let rsp = client.send(req)
println(rsp)
client.close()
}
class FileBody <: InputStream {
var file: File
init(path: String) { file = File(path, OpenOption.Open(true, false))}
public func read(buf: Array<UInt8>): Int64 {
file.read(buf)
}
}
Configuring the Proxy
import net.http.*
main () {
// 1 Constructs a client instance.
let client = ClientBuilder()
.httpProxy("http://192.168.0.1:8080")
.build()
// 2 Sends a request. All requests are sent to port **8080** of 192.168.0.1 instead of example.com.
let rsp = client.get("http://example.com/hello")
// 3 Reads the response.
println(rsp)
// 4 Closes the connection.
client.close()
}
cookie
Client
import net.http.*
import encoding.url.*
import std.socket.*
import std.time.*
import std.sync.*
main() {
// 1 Starts the socket server.
let serverSocket = TcpServerSocket(bindAt: 0)
serverSocket.bind()
let fut = spawn {
serverPacketCapture(serverSocket)
}
sleep(Duration.millisecond * 10)
// The client reads cookie from the Set-Cookie header in the response and saves it to the cookieJar.
// When a request is initiated next time, the cookie is sent in the Cookie header of the request.
// 2 Starts the client.
let client = ClientBuilder().build()
let port = serverSocket.localAddress.port
var u = URL.parse("http://127.0.0.1:${port}/a/b/c")
var r = HttpRequestBuilder()
.url(u)
.build()
// 3 Sends a request.
client.send(r)
sleep(Duration.second * 2)
r = HttpRequestBuilder()
.url(u)
.build()
// 4 Sends a new request, obtains the cookie from the CookieJar, and converts the cookie to the value in the Cookie header.
// cookie 2=2 has expired. Therefore, only cookie 1=1 is sent.
client.send(r)
// 5 Closes the client.
client.close()
fut.get()
serverSocket.close()
}
func serverPacketCapture(serverSocket: TcpServerSocket) {
let buf = Array<UInt8>(500, item: 0)
let server = serverSocket.accept()
var i = server.read(buf)
println(String.fromUtf8(buf[..i]))
// GET /a/b/c HTTP/1.1
// host: 127.0.0.1:44649
// user-agent: CANGJIEUSERAGENT_1_1
// connection: keep-alive
// content-length: 0
//
// cookie1 valid for 4 seconds
let cookie1 = Cookie("1", "1", maxAge: 4, domain: "127.0.0.1", path: "/a/b/")
let setCookie1 = cookie1.toSetCookieString()
// cookie2 valid for 2 seconds
let cookie2 = Cookie("2", "2", maxAge: 2, path: "/a/")
let setCookie2 = cookie2.toSetCookieString()
// The server sends the Set-Cookie header, and the client parses the header and saves it to the CookieJar.
server.write("HTTP/1.1 204 ok\r\nSet-Cookie: ${setCookie1}\r\nSet-Cookie: ${setCookie2}\r\nConnection: close\r\n\r\n".toArray())
let server2 = serverSocket.accept()
i = server2.read(buf)
// Receives a request with a cookie from the client.
println(String.fromUtf8(buf[..i]))
// GET /a/b/c HTTP/1.1
// host: 127.0.0.1:34857
// cookie: 1=1
// user-agent: CANGJIEUSERAGENT_1_1
// connection: keep-alive
// content-length: 0
//
server2.write("HTTP/1.1 204 ok\r\nConnection: close\r\n\r\n".toArray())
server2.close()
}
Running result:
GET /a/b/c HTTP/1.1
host: 127.0.0.1:37359
user-agent: CANGJIEUSERAGENT_1_1
connection: keep-alive
content-length: 0
GET /a/b/c HTTP/1.1
host: 127.0.0.1:37359
cookie: 1=1
user-agent: CANGJIEUSERAGENT_1_1
connection: keep-alive
content-length: 0
Server
import net.http.*
main () {
// The server sends the cookie to the client by saving it in the Set-Cookie header.
// 1 Constructs a server instance.
let server = ServerBuilder()
.addr("127.0.0.1")
.port(8080)
.build()
// 2 Registers the HttpRequestHandler.
server.distributor.register("/index", {httpContext =>
let cookie = Cookie("name", "value")
httpContext.responseBuilder.header("Set-Cookie", cookie.toSetCookieString()).body("Hello Cangjie!")
})
// 3 Starts the service.
server.serve()
}
log
import std.log.*
import net.http.*
main () {
// 1 Constructs a server instance.
let server = ServerBuilder()
.addr("127.0.0.1")
.port(8080)
.build()
// 2 Registers the HttpRequestHandler.
server.distributor.register("/index", {httpContext =>
httpContext.responseBuilder.body("Hello Cangjie!")
})
// 3 Starts the logger.
server.logger.level = DEBUG
// The logger on the client is started through client.logger.level = DEBUG.
// 4 Starts the service.
server.serve()
}
Running result:
2024/01/25 17:23:54.344205 DEBUG Logger [Server#serve] bindAndListen(127.0.0.1, 8080)
server
Hello Cangjie
import net.http.ServerBuilder
main () {
// 1 Constructs a server instance.
let server = ServerBuilder()
.addr("127.0.0.1")
.port(8080)
.build()
// 2 Registers the HttpRequestHandler.
server.distributor.register("/index", {httpContext =>
httpContext.responseBuilder.body("Hello Cangjie!")
})
// 3 Starts the service.
server.serve()
}
Registering a Handler Through the Request Distributor
import net.http.{ServerBuilder, HttpRequestHandler, FuncHandler}
main () {
// 1 Constructs a server instance.
let server = ServerBuilder()
.addr("127.0.0.1")
.port(8080)
.build()
var a: HttpRequestHandler = FuncHandler({ httpContext =>
httpContext.responseBuilder.body("index")
})
var b: HttpRequestHandler = FuncHandler({ httpContext =>
httpContext.responseBuilder.body("id")
})
var c: HttpRequestHandler = FuncHandler({ httpContext =>
httpContext.responseBuilder.body("help")
})
server.distributor.register("/index", a)
server.distributor.register("/id", b)
server.distributor.register("/help", c)
// 2 Starts the service.
server.serve()
}
User-defined Request Distributor and Handler
import net.http.*
import std.collection.HashMap
class NaiveDistributor <: HttpRequestDistributor {
let map = HashMap<String, HttpRequestHandler>()
public func register(path: String, handler: HttpRequestHandler): Unit {
map.put(path, handler)
}
public func distribute(path: String): HttpRequestHandler {
if (path == "/index") {
return PageHandler()
}
return NotFoundHandler()
}
}
// Returns a simple HTML page.
class PageHandler <: HttpRequestHandler {
public func handle(httpContext: HttpContext): Unit {
httpContext.responseBuilder.body("<html></html>")
}
}
main () {
// 1 Constructs a server instance.
let server = ServerBuilder()
.addr("127.0.0.1")
.port(8080)
.distributor(NaiveDistributor()) // User-defined distributor
.build()
// 2 Starts the service.
server.serve()
}
User-defined Server Network Configuration
import std.fs.*
import net.tls.*
import crypto.x509.{X509Certificate, PrivateKey}
import net.http.*
// This program can be executed only when an existing valid file path is configured.
main () {
// 1. User-defined configuration
// TCP configuration
var transportCfg = TransportConfig()
transportCfg.readBufferSize = 8192
// The matched certificate and private key file paths need to be input for TLS configuration.
let pem0 = String.fromUtf8(File("/certPath", OpenOption.Open(true, false)).readToEnd())
let pem02 = String.fromUtf8(File("/keyPath", OpenOption.Open(true, false)).readToEnd())
var tlsConfig = TlsServerConfig(X509Certificate.decodeFromPem(pem0), PrivateKey.decodeFromPem(pem02))
tlsConfig.supportedAlpnProtocols = ["h2"]
// 2 Constructs a server instance.
let server = ServerBuilder()
.addr("127.0.0.1")
.port(8080)
.transportConfig(transportCfg)
.tlsConfig(tlsConfig)
.headerTableSize(10 * 1024)
.maxRequestHeaderSize(1024 * 1024)
.build()
// 3 Registers the HttpRequestHandler.
server.distributor.register("/index", {httpContext =>
httpContext.responseBuilder.body("Hello Cangjie!")
})
// 4 Starts the service.
server.serve()
}
chunked and trailer in the response
import net.http.*
import std.io.*
import std.collection.HashMap
func checksum(chunk: Array<UInt8>): Int64 {
var sum = 0
for (i in chunk) {
if (i == UInt8(UInt32(r'\n'))) {
sum += 1
}
}
return sum / 2
}
main () {
// 1 Constructs a server instance.
let server = ServerBuilder()
.addr("127.0.0.1")
.port(8080)
.build()
// 2 Registers the HttpRequestHandler.
server.distributor.register("/index", {httpContext =>
let responseBuilder = httpContext.responseBuilder
responseBuilder.header("transfer-encoding", "chunked") // Sets the response header.
responseBuilder.header("trailer", "checkSum")
let writer = HttpResponseWriter(httpContext)
var sum = 0
for (_ in 0..10) {
let chunk = Array<UInt8>(10, item: 0)
sum += checksum(chunk)
writer.write(chunk) // Sends immediately.
}
responseBuilder.trailer("checkSum", "${sum}") // Sends after the handler ends.
})
// 3 Starts the service.
server.serve()
}
Processing the Redirection Request
import net.http.*
main () {
// 1 Constructs a server instance.
let server = ServerBuilder()
.addr("127.0.0.1")
.port(8080)
.build()
// 2 Registers the HttpRequestHandler.
server.distributor.register("/redirecta",RedirectHandler("/movedsource", 308))
server.distributor.register("/redirectb",RedirectHandler("http://www.example.com", 308))
// 3 Starts the service.
server.serve()
}
TLS Certificate Hot Loading
import std.fs.*
import net.tls.*
import crypto.x509.{X509Certificate, PrivateKey}
import net.http.*
// This program can be executed only when an existing valid file path is configured.
main() {
// 1 TLS configuration
let pem0 = String.fromUtf8(File("/certPath", OpenOption.Open(true, false)).readToEnd())
let pem02 = String.fromUtf8(File("/keyPath", OpenOption.Open(true, false)).readToEnd())
var tlsConfig = TlsServerConfig(X509Certificate.decodeFromPem(pem0), PrivateKey.decodeFromPem(pem02))
tlsConfig.supportedAlpnProtocols = ["http/1.1"]
let pem = String.fromUtf8(File("/rootCerPath", OpenOption.Open(true, false)).readToEnd())
tlsConfig.verifyMode = CustomCA(X509Certificate.decodeFromPem(pem))
// 2 Constructs a server instance and starts the service.
let server = ServerBuilder()
.addr("127.0.0.1")
.port(8080)
.tlsConfig(tlsConfig)
.build()
spawn {
server.serve()
}
// 3 Updates the TLS certificate and private key. The new certificate and private key are used for subsequent requests.
server.updateCert("/newCerPath", "/newKeyPath")
// 4 Updates the CA, which is used for two-way authentication. The new CA is used for subsequent requests.
server.updateCA("/newRootCerPath")
}
server push
Valid only for HTTP/2.
client:
import std.fs.*
import std.collection.ArrayList
import net.tls.*
import crypto.x509.X509Certificate
import net.http.*
// This program can be executed only when an existing valid file path is configured.
// client:
main() {
// 1 TLS configuration
var tlsConfig = TlsClientConfig()
let pem = String.fromUtf8(File("/rootCerPath", OpenOption.Open(true, false)).readToEnd())
tlsConfig.verifyMode = CustomCA(X509Certificate.decodeFromPem(pem))
tlsConfig.alpnProtocolsList = ["h2"]
// 2 Constructs a client instance.
let client = ClientBuilder()
.tlsConfig(tlsConfig)
.build()
// 3 Sends a request and receives a response.
let response = client.get("https://example.com/index.html")
// 4 Receives a pushResponse. In this example, it refers to the response of client.get("http://example.com/picture.png").
let pushResponses: Option<ArrayList<HttpResponse>> = response.getPush()
client.close()
}
server:
import std.fs.*
import net.tls.*
import crypto.x509.{X509Certificate, PrivateKey}
import net.http.*
// This program can be executed only when an existing valid file path is configured.
main() {
// 1 TLS configuration
let pem0 = String.fromUtf8(File("/certPath", OpenOption.Open(true, false)).readToEnd())
let pem02 = String.fromUtf8(File("/keyPath", OpenOption.Open(true, false)).readToEnd())
var tlsConfig = TlsServerConfig(X509Certificate.decodeFromPem(pem0), PrivateKey.decodeFromPem(pem02))
tlsConfig.supportedAlpnProtocols = ["h2"]
// 2 Constructs a server instance.
let server = ServerBuilder()
.addr("127.0.0.1")
.port(8080)
.tlsConfig(tlsConfig)
.build()
// 3 Registers the handler of the original request.
server.distributor.register("/index.html", {httpContext =>
let pusher = HttpResponsePusher.getPusher(httpContext)
match (pusher) {
case Some(pusher) =>
pusher.push("/picture.png", "GET", httpContext.request.headers)
case None =>
()
}
})
// 4 Registers the handler of pushRequest.
server.distributor.register("/picture.png", {httpContext =>
httpContext.responseBuilder.body("picture.png")
})
// 4 Starts the service.
server.serve()
}
webSocket
import net.http.*
import encoding.url.*
import std.time.*
import std.sync.*
import std.collection.*
import std.log.*
let server = ServerBuilder()
.addr("127.0.0.1")
.port(0)
.build()
// client:
main() {
// 1 Starts the server.
spawn { startServer() }
sleep(Duration.millisecond * 200)
let client = ClientBuilder().build()
let u = URL.parse("ws://127.0.0.1:${server.port}/webSocket")
let subProtocol = ArrayList<String>(["foo1", "bar1"])
let headers = HttpHeaders()
headers.add("test", "echo")
// 2 Completes handshake with WebSocket and obtains the WebSocket instance.
let websocket: WebSocket
let respHeaders: HttpHeaders
(websocket, respHeaders) = WebSocket.upgradeFromClient(client, u, subProtocols: subProtocol, headers: headers)
client.close()
println("subProtocol: ${websocket.subProtocol}") // fool1
println(respHeaders.getFirst("rsp") ?? "") // echo
// 3 Sends and receives a message.
// Sends "hello".
websocket.write(TextWebFrame, "hello".toArray())
// Receives a message.
let data = ArrayList<UInt8>()
var frame = websocket.read()
while(true) {
match(frame.frameType) {
case ContinuationWebFrame =>
data.appendAll(frame.payload)
if (frame.fin) {
break
}
case TextWebFrame | BinaryWebFrame =>
if (!data.isEmpty()) {
throw Exception("invalid frame")
}
data.appendAll(frame.payload)
if (frame.fin) {
break
}
case CloseWebFrame =>
websocket.write(CloseWebFrame, frame.payload)
break
case PingWebFrame =>
websocket.writePongFrame(frame.payload)
case _ => ()
}
frame = websocket.read()
}
println("data size: ${data.size}") // 4097
println("last item: ${String.fromUtf8(Array(data)[4096])}") // a
// 4 Closes WebSocket.
// Receives and sends CloseFrame.
websocket.writeCloseFrame(status: 1000)
let websocketFrame = websocket.read()
println("close frame type: ${websocketFrame.frameType}") // CloseWebFrame
println("close frame payload: ${websocketFrame.payload}") // 3, 232
// Closes the underlying connection.
websocket.closeConn()
server.close()
}
func startServer() {
// 1 Registers the handler.
server.distributor.register("/webSocket", handler1)
server.logger.level = OFF
server.serve()
}
// server:
func handler1(ctx: HttpContext): Unit {
// 2 Completes handshake with WebSocket and obtains the WebSocket instance.
let websocketServer = WebSocket.upgradeFromServer(ctx, subProtocols: ArrayList<String>(["foo", "bar", "foo1"]),
userFunc: {request: HttpRequest =>
let value = request.headers.getFirst("test") ?? ""
let headers = HttpHeaders()
headers.add("rsp", value)
headers
})
// 3 Sends and receives a message.
// Receives "hello".
let data = ArrayList<UInt8>()
var frame = websocketServer.read()
while(true) {
match(frame.frameType) {
case ContinuationWebFrame =>
data.appendAll(frame.payload)
if (frame.fin) {
break
}
case TextWebFrame | BinaryWebFrame =>
if (!data.isEmpty()) {
throw Exception("invalid frame")
}
data.appendAll(frame.payload)
if (frame.fin) {
break
}
case CloseWebFrame =>
websocketServer.write(CloseWebFrame, frame.payload)
break
case PingWebFrame =>
websocketServer.writePongFrame(frame.payload)
case _ => ()
}
frame = websocketServer.read()
}
println("data: ${String.fromUtf8(Array(data))}") // hello
// Sends 4,097 letters a.
websocketServer.write(TextWebFrame, Array<UInt8>(4097, item: 97))
// 4 Closes WebSocket.
// Receives and sends CloseFrame.
let websocketFrame = websocketServer.read()
println("close frame type: ${websocketFrame.frameType}") // CloseWebFrame
println("close frame payload: ${websocketFrame.payload}") // 3, 232
websocketServer.write(CloseWebFrame, websocketFrame.payload)
// Closes the underlying connection.
websocketServer.closeConn()
}
Running result:
subProtocol: foo1
echo
data: hello
data size: 4097
last item: a
close frame type: CloseWebFrame
close frame payload: [3, 232]
close frame type: CloseWebFrame
close frame payload: [3, 232]
net.tls Package
Function Description
The TLS package provides secure communications over a computer network with its capabilities such as creating TLS servers, performing TLS handshakes based on protocols, sending and receiving encrypted data, and restoring TLS sessions.
This package supports TLS 1.2 and TLS 1.3.
This package depends on the SSL and crypto dynamic library files of OpenSSL 3. Therefore, related tools must be installed in advance.
- For
Linux, perform the following operations:- Install the
OpenSSL 3development tool package using the package management tool of the system if the tool supports the installation, and ensure that the system installation directory contains thelibssl.so,libssl.so.3,libcrypto.so, andlibcrypto.so.3dynamic library files. For example, onUbuntu 22.04, run thesudo apt install libssl-devcommand to install thelibssl-devtool package. - Download and install the
OpenSSL 3.*x*.*x*source code compilation software package if the preceding method fails, and ensure that the installation directory contains thelibssl.so,libssl.so.3,libcrypto.so, andlibcrypto.so.3dynamic library files. Then, use either of the following methods to ensure that the system linker can find these files:- Install OpenSSL in the system path if it has not been installed in the system.
- Set the directory where the OpenSSL development tool package files are located to the environment variables
LD_LIBRARY_PATHandLIBRARY_PATHif OpenSSL is installed in a user-defined directory.
- Install the
- For
Windows, perform the following operations:- Download and install the
OpenSSL 3.*x*.*x*source code compilation software package for the x64 architecture, or download and install theOpenSSL 3.*x*.*x*software package precompiled by a third party for developers. - Ensure that the installation directory contains the
libssl.dll.a(orlibssl.lib),libssl-3-x64.dll,libcrypto.dll.a(orlibcrypto.lib), andlibcrypto-3-x64.dlllibrary files. - Set the directory containing
libssl.dll.a(orlibssl.lib) andlibcrypto.dll.a(orlibcrypto.lib) to the environment variableLIBRARY_PATH, and the directory containinglibssl-3-x64.dllandlibcrypto-3-x64.dllto the environment variablePATH.
- Download and install the
- For
macOS, perform the following operations:- Run the
brew install openssl@3command to install OpenSSL, and ensure that the system installation directory contains thelibcrypto.dylibandlibcrypto.3.dylibdynamic library files. - Download and install the
OpenSSL 3.*x*.*x*source code compilation software package if the preceding method fails, and ensure that the installation directory contains thelibcrypto.dylibandlibcrypto.3.dylibdynamic library files. Then, use either of the following methods to ensure that the system linker can find these files:- Install OpenSSL in the system path if it has not been installed in the system.
- Set the directory where the OpenSSL development tool package files are located to the environment variables
DYLD_LIBRARY_PATHandLIBRARY_PATHif OpenSSL is installed in a user-defined directory.
- Run the
Note:
If
OpenSSL 3is not installed or an earlier version is installed, the program may fail to work with the following exception thrown: TlsException: Can not load openssl library or function xxx.
API List
Class
| Name | Description |
|---|---|
| TlsSessionContext | The server enables the session feature to restore sessions and stores sessions for client authentication. |
| TlsSocket | Creates an encrypted transmission channel between the client and server. |
Enumeration
| Name | Description |
|---|---|
| CertificateVerifyMode | Certificate authentication mode. |
| SignatureAlgorithm | Specifies the signature algorithm type. The signature algorithm is used to ensure the identity authentication, integrity, and authenticity of transmitted data. |
| SignatureSchemeType | Specifies the encryption algorithm type, which is used to protect the security and privacy of network communication. |
| SignatureType | Specifies the signature algorithm type, which is used for authenticity authentication. |
| TlsClientIdentificationMode | Specifies the mode for the server to authenticate the client certificate. |
| TlsVersion | Specifies the TLS protocol version. |
Struct
| Name | Description |
|---|---|
| CipherSuite | Specifies the cipher suite in TLS. |
| TlsClientConfig | Specifies the client configuration. |
| TlsServerConfig | Specifies the server configuration. |
| TlsSession | After the TLS handshake with the client is successful, a session is generated. If the connection is lost due to some reasons, the client can reuse the session by using the session ID and skip the handshake process. |
Exception Class
| Name | Description |
|---|---|
| TlsException | Indicates the exception type thrown when an error occurs during TLS processing. |
Class
class TlsSessionContext
public class TlsSessionContext <: Equatable<TlsSessionContext> & ToString
Description: This class indicates the TLS session context and provides information for the client to ensure that the server connected to the client is the same instance, and is used to verify the validity of the client during connection reuse.
Note:
When a client attempts to resume a session, both parties must ensure that they are resuming the session with an authorized peer.
Parent Type:
static func fromName(String)
public static func fromName(name: String): TlsSessionContext
Description: Creates a TlsSessionContext instance by name.
Obtains the TlsSessionContext object through the name saved by TlsSessionContext. This name is used to distinguish TLS servers so clients rely on this name to avoid accidental attempts to resume connection to the wrong server. It is not necessarily to use crypto-secure names here as the underlying implementation does the job. Two TlsSessionContext instances returned from this function with the same name could be non-equal and not guaranteed to be replaceable despite the same name they are created from. Although they are created from the same name, the server instance should create a TlsSessionContext throughout the lifecycle and use it with every TlsSocket.server() calling.
Parameters:
- name: String: session context name
Returns:
- TlsSessionContext: session context
func toString()
public override func toString(): String
Description: Generates a session context name string.
Returns:
- String: TlsSessionContext: session context name string
operator func !=(TlsSessionContext)
public override operator func !=(other: TlsSessionContext)
Description: Checks whether the names of two TlsSessionContext instances are different.
Parameters:
- other: TlsSessionContext: the other session context object to be compared with
Returns:
- Unit: If the names of the two TlsSessionContext objects are different,
trueis returned. Otherwise,falseis returned.
operator func ==(TlsSessionContext)
public override operator func ==(other: TlsSessionContext)
Description: Checks whether the names of two TlsSessionContext instances are the same.
Parameters:
- other: TlsSessionContext: the other session context object to be compared with
Returns:
- Unit: If the names of the two TlsSessionContext objects are the same,
trueis returned. Otherwise,falseis returned.
class TlsSocket
public class TlsSocket <: StreamingSocket & ToString & Equatable<TlsSocket> & Hashable
Description: TlsSocket is used to create an encrypted transmission channel between a client and server.
Parent Type:
prop alpnProtocolName
public prop alpnProtocolName: ?String
Description: Reads the negotiated application layer protocol name.
Type: ?String
Throws:
- TlsException: If the TLS handshake on socket is not complete or the local TLS socket is closed, this exception is thrown.
- IllegalMemoryException: If memory allocation fails, this exception is thrown.
prop cipherSuite
public prop cipherSuite: CipherSuite
Description: Gets the cipher suite negotiated after a handshake.
Note:
The cipher suite includes an encryption algorithm, a hash function used for message authentication, and a key exchange algorithm.
Type: CipherSuite
Throws:
- TlsException: If the TLS handshake on socket is not complete or the local TLS socket is closed, this exception is thrown.
prop clientCertificate
public prop clientCertificate: ?Array<X509Certificate>
Description: Obtains the client certificate provided by the client. On a client, it is the local certificate. On a server, it is the peer certificate.
Note:
If the peer end does not send a certificate, the API may fail to obtain the peer certificate and None is returned. For details, see peerCertificate.
Type: ?Array<X509Certificate>
Throws:
- TlsException: If the TLS handshake on socket is not complete or the local TLS socket is closed, this exception is thrown.
prop domain
public prop domain: ?String
Description: Reads the negotiated server host name.
- TlsException: If the TLS handshake on socket is not complete or the local TLS socket is closed, this exception is thrown.
Type: ?String
prop localAddress
public override prop localAddress: SocketAddress
Description: Reads the local address of TlsSocket.
Type: SocketAddress
Throws:
- SocketException: If the underlying TCP socket is closed on the local end, this exception is thrown.
- TlsException: If the TLS socket on the local end is closed, this exception is thrown.
prop peerCertificate
public prop peerCertificate: ?Array<X509Certificate>
Description: Obtains the peer certificate. On a client, this function is the same as that of serverCertificate. On a server, this function is the same as that of clientCertificate on the server.
Note:
If the peer end is not required to send the certificate during the handshake, the peer certificate cannot be obtained and None is returned.
When the session mechanism is used to restore the connection, neither party sends the certificate. The API behavior is as follows:
- On the server, if the peer certificate is obtained when the original connection is restored, the server caches the peer certificate and obtains the cached certificate.
- On the client, the peer certificate of the original connection is not cached. In this case, the peer certificate cannot be obtained and None is returned.
Type: ?Array<X509Certificate>
Throws:
- TlsException: If the TLS handshake on socket is not complete or the local TLS socket is closed, this exception is thrown.
prop readTimeout
public override mut prop readTimeout: ?Duration
Description: Sets and obtains the read timeout for reading and writing TlsSocket.
Type: ?Duration
Throws:
- SocketException: If the underlying TCP socket is closed on the local end, this exception is thrown.
- TlsException: If the TLS socket on the local end is closed, this exception is thrown.
- IllegalArgumentException: If the set read timeout is negative, this exception is thrown.
prop remoteAddress
public override prop remoteAddress: SocketAddress
Description: Reads the remote address of TlsSocket.
Type: SocketAddress
Throws:
- SocketException: If the underlying TCP socket is closed on the local end, this exception is thrown.
- TlsException: If the TLS socket on the local end is closed, this exception is thrown.
prop serverCertificate
public prop serverCertificate: Array<X509Certificate>
Description: The server certificate chain is provided by the server or preconfigured in the server configuration. On a server, it is the local certificate obtained from the client. On a client, it is the peer certificate obtained from the server.
Note:
If the peer end does not send a certificate, the API may fail to obtain the peer certificate and None is returned. For details, see peerCertificate.
Type: Array<X509Certificate>
Throws:
- TlsException: If the TLS handshake on socket is not complete or the local TLS socket is closed, this exception is thrown.
prop session
public prop session: ?TlsSession
Description: Reads the TLS session ID. After the handshake is successful, the client captures the ID of the current session. The ID can be used to reuse the session, saving the time for establishing a TLS connection. If the connection fails to be established, None is returned.
Note:
The server does not capture the ID of the current session. Therefore, the value is always None.
Type: ?TlsSession
Throws:
- TlsException: If the TLS handshake on socket is not complete, this exception is thrown.
prop socket
public prop socket: StreamingSocket
Description: Obtains StreamingSocket used for TlsSocket creation.
Type: StreamingSocket
Throws:
- TlsException: If the TLS socket on the local end is closed, this exception is thrown.
prop tlsVersion
public prop tlsVersion: TlsVersion
Description: Reads the negotiated TLS version.
Type: TlsVersion
Throws:
- TlsException: If the TLS handshake on socket is not complete or the local TLS socket is closed, this exception is thrown.
prop writeTimeout
public override mut prop writeTimeout: ?Duration
Description: Sets and obtains the write timeout for reading and writing TlsSocket.
Type: ?Duration
Throws:
- SocketException: If the underlying TCP socket is closed on the local end, this exception is thrown.
- TlsException: If the TLS socket on the local end is closed, this exception is thrown.
- IllegalArgumentException: If the set write timeout is negative, this exception is thrown.
static func client(StreamingSocket, ?TlsSession, TlsClientConfig)
public static func client(
socket: StreamingSocket,
session!: ?TlsSession = None,
clientConfig!: TlsClientConfig = TlsClientConfig()
): TlsSocket
Description: Creates a client TLS socket at a specified address according to the passed StreamingSocket instance. The socket can be used for client TLS handshakes and sessions.
Parameters:
- socket: StreamingSocket: client TCP socket that has connected to the server
- session!: ?TlsSession: TLS session ID. If there is available TLS session, this ID can be used to restore the historical TLS session, saving the time for establishing a TLS connection. However, negotiation may still fail even this session is used. The default value is
None. - clientConfig!: TlsClientConfig: client configuration. The default value is TlsClientConfig().
Returns:
static func server(StreamingSocket, ?TlsSessionContext, TlsServerConfig)
public static func server(
socket: StreamingSocket,
sessionContext!: ?TlsSessionContext = None,
serverConfig!: TlsServerConfig
): TlsSocket
Description: Creates a server TLS socket at a specified address according to the passed StreamingSocket instance. The socket can be used for server TLS handshakes and sessions.
Parameters:
- socket: StreamingSocket: socket received after the TCP connection is established.
- sessionContext!: ?TlsSessionContext: TLS session ID. If there is available TLS session, this ID can be used to restore the historical TLS session, saving the time for establishing a TLS connection. However, negotiation may still fail even this session is used. The default value is None.
- serverConfig!: TlsServerConfig: server configuration. The default value is TlsServerConfig().
Returns:
func close()
public func close(): Unit
Description: Closes a socket.
Throws:
- SocketException: If the underlying connection cannot be closed, this exception is thrown.
func handshake(?Duration)
public func handshake(timeout!: ?Duration = None): Unit
Function: Performs a TLS handshake. Renegotiation handshake is not supported. Therefore, this function can be called only once. The called object can be TlsSocket of the client or server.
Parameters:
- timeout!: ?Duration: handshake timeout. The default value is None. In this case, the timeout is not set, and the default timeout (30s) is used.
Throws:
- SocketException: If the underlying TCP socket is closed on the local end, this exception is thrown.
- SocketTimeoutException: If the underlying TCP socket connection times out, this exception is thrown.
- TlsException: When the handshake starts or ends or when a system error occurs during the handshake, this exception is thrown.
- IllegalArgumentException: If the set handshake timeout is negative, this exception is thrown.
func hashCode()
public override func hashCode(): Int64
Description: Returns the hash value of the TLS socket object.
Returns:
- Int64: result obtained after hash calculation is performed on the TLS socket object
func isClosed()
public func isClosed(): Bool
Description: Indicates whether the socket is closed.
Returns:
- Bool: If the socket is closed, true is returned. Otherwise, false is returned.
func read(Array<Byte>)
public override func read(buffer: Array<Byte>): Int64
Description: Reads data from TlsSocket.
Parameters:
Returns:
- Int64: number of bytes of the data read
Throws:
- SocketException: If the underlying TCP socket is closed on the local end, this exception is thrown.
- TlsException: If
bufferis empty, TlsSocket is not connected, or a system error occurs when data is read, this exception is thrown.
func toString()
public func toString(): String
Description: Obtains the string representation of a socket. The string content indicates the current socket status.
Note:
For example, when the current socket is ready for handshake, the API returns "TlsSocket(TcpSocket (${local address} - > ${peer address}), ready for handshake)".
Returns:
- String: TLS connection string
func write(Array<Byte>)
public func write(buffer: Array<Byte>): Unit
Description: Writes data to TlsSocket.
Parameters:
Throws:
- SocketException: If the underlying TCP socket is closed on the local end, this exception is thrown.
- TlsException: If the socket is closed, TlsSocket is not connected, or a system error occurs when data is written, this exception is thrown.
operator func !=(TlsSocket)
public override operator func !=(other: TlsSocket)
Description: Checks whether two TlsSocket sockets reference different instances.
Parameters:
- other: TlsSocket: the other TLS socket to be compared with
Returns:
- Unit: If the two instances compared are different,
trueis returned. Otherwise,falseis returned.
operator func ==(TlsSocket)
public override operator func ==(other: TlsSocket)
Description: Check whether two TlsSocket sockets reference the same instance.
Parameters:
- other: TlsSocket: the other TLS socket to be compared with
Returns:
- Unit: If the two instances compared are the same,
trueis returned. Otherwise,falseis returned.
Enumeration
enum CertificateVerifyMode
public enum CertificateVerifyMode {
| CustomCA(Array<X509Certificate>)
| Default
| TrustAll
}
Description: Represents the processing mode for certificate verification.
Note:
In CustomCA mode, the certificate path can be defined by a user. This mode applies to the scenario where the user certificate cannot be set to the system certificate.
In the certificate authentication mode, after a TCP connection is established, the client and server can exchange certificates. In default mode, the system certificate is used.
In the development and test phase, the TrustAll mode can be used. In this mode, the local end does not verify the peer certificate. In this mode, the local end trusts any connection object. This mode is used only in the development and test phase.
CustomCA(Array<X509Certificate>)
CustomCA(Array<X509Certificate>)
Description: Indicates that the verification is performed according to the provided CA list.
Default
Default
Description: Indicates the default verification mode. The certificate is verified according to the system CA.
TrustAll
TrustAll
Description: Indicates that all certificates are trusted.
enum SignatureAlgorithm
public enum SignatureAlgorithm <: ToString & Equatable<SignatureAlgorithm> {
| SignatureAndHashAlgorithm(SignatureType, HashType)
| SignatureScheme(SignatureSchemeType)
}
Description: Represents the signature algorithm type. The signature algorithm is used to guarantee the identity authentication, integrity, and authenticity of transmitted data.
Parent Type:
SignatureAndHashAlgorithm(SignatureType, HashType)
SignatureAndHashAlgorithm(SignatureType, HashType)
Description: Indicates which signature and hash algorithm pair are used for digital signature. In TLS 1.2 and later versions, the signature and hash algorithm types are included in the current type.
SignatureScheme(SignatureSchemeType)
SignatureScheme(SignatureSchemeType)
Description: Represents the signature scheme which is recommended in the industry in TLS 1.3 and later versions.
func toString()
public func toString():String
Description: Converts the current instance to the string representation of the signature algorithm.
Returns:
- String: name of the signature algorithm
operator func !=(SignatureAlgorithm)
public operator func !=(other: SignatureAlgorithm) : Bool
Description: Checks whether two signature algorithm types are different.
Parameters:
- other: SignatureAlgorithm: the other signature algorithm type to be compared with
Returns:
- Bool: If the two signature algorithm types are different,
trueis returned. Otherwise,falseis returned.
operator func ==(SignatureAlgorithm)
public operator func ==(other: SignatureAlgorithm) : Bool
Description: Checks whether two signature algorithm types are the same
Parameters:
- other: SignatureAlgorithm: the other signature algorithm type to be compared with
Returns:
- Bool: If the two signature algorithm types are the same,
trueis returned. Otherwise,falseis returned.
enum SignatureSchemeType
public enum SignatureSchemeType <: ToString & Equatable<SignatureSchemeType> {
| RSA_PKCS1_SHA256
| RSA_PKCS1_SHA384
| RSA_PKCS1_SHA512
| ECDSA_SECP256R1_SHA256
| ECDSA_SECP384R1_SHA384
| ECDSA_SECP521R1_SHA512
| RSA_PSS_RSAE_SHA256
| RSA_PSS_RSAE_SHA384
| RSA_PSS_RSAE_SHA512
| ED25519
| ED448
| RSA_PSS_PSS_SHA256
| RSA_PSS_PSS_SHA384
| RSA_PSS_PSS_SHA512
}
Description: Represents the encryption algorithm type, which is used to guarantee the security and privacy of network communication.
Parent Type:
ECDSA_SECP256R1_SHA256
ECDSA_SECP256R1_SHA256
Description: Creates an enumeration instance of the ECDSA_SECP256R1_SHA256 type, indicating that the encryption algorithm type is ECDSA_SECP256R1_SHA256.
ECDSA_SECP384R1_SHA384
ECDSA_SECP384R1_SHA384
Description: Creates an enumeration instance of the ECDSA_SECP384R1_SHA384 type, indicating that the encryption algorithm type is ECDSA_SECP384R1_SHA384.
ECDSA_SECP521R1_SHA512
ECDSA_SECP521R1_SHA512
Description: Creates an enumeration instance of the ECDSA_SECP521R1_SHA512 type, indicating that the encryption algorithm type is ECDSA_SECP521R1_SHA512.
ED25519
ED25519
Description: Creates an enumeration instance of the ED25519 type, indicating that the encryption algorithm type is ED25519.
ED448
ED448
Description: Creates an enumeration instance of the ED448 type, indicating that the encryption algorithm type is ED448.
RSA_PKCS1_SHA256
RSA_PKCS1_SHA256
Description: Creates an enumeration instance of the RSA_PKCS1_SHA256 type, indicating that the encryption algorithm type is RSA_PKCS1_SHA256.
RSA_PKCS1_SHA384
RSA_PKCS1_SHA384
Description: Creates an enumeration instance of the RSA_PKCS1_SHA384 type, indicating that the encryption algorithm type is RSA_PKCS1_SHA384.
RSA_PKCS1_SHA512
RSA_PKCS1_SHA512
Description: Creates an enumeration instance of the RSA_PKCS1_SHA512 type, indicating that the encryption algorithm type is RSA_PKCS1_SHA512.
RSA_PSS_PSS_SHA256
RSA_PSS_PSS_SHA256
Description: Creates an enumeration instance of the RSA_PSS_PSS_SHA256 type, indicating that the encryption algorithm type is RSA_PSS_PSS_SHA256.
RSA_PSS_PSS_SHA384
RSA_PSS_PSS_SHA384
Description: Creates an enumeration instance of the RSA_PSS_PSS_SHA384 type, indicating that the encryption algorithm type is RSA_PSS_PSS_SHA384.
RSA_PSS_PSS_SHA512
RSA_PSS_PSS_SHA512
Description: Creates an enumeration instance of the RSA_PSS_PSS_SHA512 type, indicating that the encryption algorithm type is RSA_PSS_PSS_SHA512.
RSA_PSS_RSAE_SHA256
RSA_PSS_RSAE_SHA256
Description: Creates an enumeration instance of the RSA_PSS_RSAE_SHA256 type, indicating that the encryption algorithm type is RSA_PSS_RSAE_SHA256.
RSA_PSS_RSAE_SHA384
RSA_PSS_RSAE_SHA384
Description: Creates an enumeration instance of the RSA_PSS_RSAE_SHA384 type, indicating that the encryption algorithm type is RSA_PSS_RSAE_SHA384.
RSA_PSS_RSAE_SHA512
RSA_PSS_RSAE_SHA512
Description: Creates an enumeration instance of the RSA_PSS_RSAE_SHA512 type, indicating that the encryption algorithm type is RSA_PSS_RSAE_SHA512.
func toString()
public func toString(): String
Description: Specifies the string representation of an encryption algorithm type.
For example, the string identification of RSA_PKCS1_SHA256 is "rsa_pkcs1_sha256".
Returns:
- String: the string representation of the encryption algorithm type
operator func !=(SignatureSchemeType)
public operator func !=(other: SignatureSchemeType): Bool
Description: Checks whether two encryption algorithm types are different.
Parameters:
- other: SignatureSchemeType: the other encryption algorithm type to be compared with
Returns:
- Bool: If the two encryption algorithm types are different, true is returned. Otherwise, false is returned.
operator func ==(SignatureSchemeType)
public operator func ==(other: SignatureSchemeType): Bool
Description: Checks whether two encryption algorithm types are the same.
Parameters:
- other: SignatureSchemeType: the other encryption algorithm type to be compared with
Returns:
- Bool: If the two encryption algorithm types are the same, true is returned. Otherwise, false is returned.
enum SignatureType
public enum SignatureType <: ToString & Equatable<SignatureType> {
| DSA
| ECDSA
| RSA
}
Description: Represents the signature algorithm type, which is used for authenticity authentication. For details, see RFC5246 7.4.1.4.1.
Parent Type:
DSA
DSA
Description: Creates an enumeration instance of the DSA type, indicating that the digital signature algorithm is used.
ECDSA
ECDSA
Description: Creates an enumeration instance of the ECDSA type, indicating that the elliptic curve digital signature algorithm is used.
RSA
RSA
Description: Creates an enumeration instance of the RSA type, indicating that the RSA encryption algorithm is used.
func toString()
public func toString(): String
Description: Converts the current instance to the string representation of the signature algorithm.
Returns:
- String: name of the signature algorithm
operator func !=(SignatureType)
public operator func !=(other: SignatureType) : Bool
Description: Checks whether two signature algorithms are different.
Parameters:
- other: SignatureType: the other signature algorithm type to be compared with
Returns:
- Bool: If the two signature algorithm types are different,
trueis returned. Otherwise,falseis returned.
operator func ==(SignatureType)
public operator func ==(other: SignatureType) : Bool
Description: Checks whether two signature algorithms are the same.
Parameters:
- other: SignatureType: the other signature algorithm type to be compared with
Returns:
- Bool: If the two signature algorithm types are the same,
trueis returned. Otherwise,falseis returned.
enum TlsClientIdentificationMode
public enum TlsClientIdentificationMode {
| Disabled
| Optional
| Required
}
Description: Represents the mode for the server to authenticate the client certificate.
Disabled
Disabled
Description: Indicates that the server does not verify the client certificate, and the client does not need to send the certificate and public key, that is, one-way authentication.
Optional
Optional
Description: Indicates that the server verifies the client certificate, but the client does not need to provide the certificate and public key. This mode is one-way authentication. If the client provides the certificate and public key, it is the two-way authentication mode.
Required
Required
Description: Indicates that the server verifies the client certificate and requires the client to provide the certificate and public key, that is, two-way authentication.
enum TlsVersion
public enum TlsVersion <: ToString {
| V1_2
| V1_3
| Unknown
}
Description: Represents the TLS protocol version.
Parent Type:
Unknown
Unknown
Description: Represents an unknown protocol version.
V1_2
V1_2
Description: Represents TLS 1.2.
V1_3
V1_3
Description: Represents TLS 1.3.
func toString()
public override func toString(): String
Description: Returns the string representation of the current TlsVersion.
Returns:
- String: the string representation of the current TlsVersion
Struct
struct CipherSuite
public struct CipherSuite <: ToString & Equatable<CipherSuite>
Description: Represents the cipher suite in TLS.
Parent Type:
static prop allSupported
public static prop allSupported: Array<CipherSuite>
Description: Returns all supported cipher suites.
Returns: array for storing cipher suites
Type: Array<CipherSuite>
func toString()
public func toString(): String
Description: Returns the cipher suite name.
Returns:
- String: cipher suite name
operator func !=(CipherSuite)
public operator func !=(that: CipherSuite): Bool
Description: Checks whether two cipher suites are not equal.
Parameters:
- that: CipherSuite: the other cipher suite to be compared with
Returns:
- Bool: If the two cipher suites are not equal,
trueis returned. Otherwise,falseis returned.
operator func ==(CipherSuite)
public operator func ==(that: CipherSuite): Bool
Description: Checks whether two cipher suites are equal.
Parameters:
- that: CipherSuite: the other cipher suite to be compared with
Returns:
- Bool: If the two cipher suites are equal,
trueis returned. Otherwise,falseis returned.
struct TlsClientConfig
public struct TlsClientConfig
Description: Represents the client configuration.
var keylogCallback
public var keylogCallback: ?(TlsSocket, String) -> Unit = None
Description: Represents a callback function for the handshake process. It provides the initial TLS key data for debugging and decryption.
Type: ?(TlsSocket, String) -> Unit
var verifyMode
public var verifyMode: CertificateVerifyMode = CertificateVerifyMode.Default
Description: Sets or obtains the certificate authentication mode. The default value is Default.
Type: CertificateVerifyMode
prop alpnProtocolsList
public mut prop alpnProtocolsList: Array<String>
Description: Negotiates the application layer protocol. If the list is empty, the client does not negotiate the application layer protocol.
Throws:
- IllegalArgumentException: If the elements in the list contain the '\0' character, this exception is thrown.
prop cipherSuitesV1_2
public mut prop cipherSuitesV1_2: ?Array<String>
Description: Represents the TLS 1.2-based cipher suite.
Throws:
- IllegalArgumentException: If the elements in the list contain the '\0' character, this exception is thrown.
prop cipherSuitesV1_3
public mut prop cipherSuitesV1_3: ?Array<String>
Description: Represents the TLS 1.3-based cipher suite.
Throws:
- IllegalArgumentException: If the elements in the list contain the '\0' character, this exception is thrown.
prop clientCertificate
public mut prop clientCertificate: ?(Array<X509Certificate>, PrivateKey)
Description: Represents the client certificate and private key.
Type: ?(Array<X509Certificate>, PrivateKey)
prop domain
public mut prop domain: ?String
Description: Represents the server host address (SNI) required for read and write. None indicates that the SNI is not required.
Type: ?String
Throws:
- IllegalArgumentException: If the parameters contain the '\0' character, this exception is thrown.
prop maxVersion
public mut prop maxVersion: TlsVersion
Description: Represents the latest TLS version supported.
Note:
If
maxVersionis set butminVersionis not set, or if the setmaxVersionis earlier thanminVersion, TlsException is thrown during handshake.
Type: TlsVersion
prop minVersion
public mut prop minVersion: TlsVersion
Description: Represents the earliest TLS version supported.
Note:
If
minVersionis set butmaxVersionis not set, or if the setminVersionis later thanmaxVersion, TlsException is thrown during handshake.
Type: TlsVersion
prop securityLevel
public mut prop securityLevel: Int32
Description: Specifies the security level of the client. The default value is 2. The value ranges from 0 to 5. For details about the parameter description, see the description of openssl-SSL_CTX_set_security_level.
Type: Int32
prop signatureAlgorithms
public mut prop signatureAlgorithms: ?Array<SignatureAlgorithm>
Description: Specifies the signature and hash algorithm for order preserving. If the value is None or the list is empty, the client uses the default list. After the list is specified, the client may not send inappropriate signature algorithms.
For details, see RFC5246 7.4.1.4.1 (TLS 1.2) and RFC8446 4.2.3 (TLS 1.3).
Type: ?Array<SignatureAlgorithm>
init()
public init()
Description: Constructs TlsClientConfig.
struct TlsServerConfig
public struct TlsServerConfig
Description: Represents the server configuration.
var clientIdentityRequired
public var clientIdentityRequired: TlsClientIdentificationMode = Disabled
Description: Sets or obtains the client authentication mode required by the server. By default, the client is not required to authenticate the server certificate or send its certificate.
Type: TlsClientIdentificationMode
var keylogCallback
public var keylogCallback: ?(TlsSocket, String) -> Unit = None
Description: Represents a callback function for the handshake process. It provides the initial TLS key data for debugging and decryption.
Type: ?(TlsSocket, String) -> Unit
var verifyMode
public var verifyMode: CertificateVerifyMode = CertificateVerifyMode.Default
Description: Sets or obtains the authentication mode. By default, the system certificate is authenticated.
Type: CertificateVerifyMode
prop cipherSuitesV1_2
public mut prop cipherSuitesV1_2: Array<String>
Description: Represents the TLS 1.2-based cipher suite.
Throws:
- IllegalArgumentException: If the elements in the list contain the**'\0'** character, this exception is thrown.
prop cipherSuitesV1_3
public mut prop cipherSuitesV1_3: Array<String>
Description: Represents the TLS 1.3-based cipher suite.
Throws:
- IllegalArgumentException: If the elements in the list contain the '\0' character, this exception is thrown.
prop dhParameters
public mut prop dhParameters: ?DHParamters
Description: Specifies the DH key parameters of the server. The default value is None. By default, the parameter values automatically generated by OpenSSL are used.
Type: ?DHParamters
prop maxVersion
public mut prop maxVersion: TlsVersion
Description: Represents the latest TLS version supported.
Note:
If
maxVersionis set butminVersionis not set, or if the setmaxVersionis earlier thanminVersion, TlsException is thrown during handshake.
Type: TlsVersion
prop minVersion
public mut prop minVersion: TlsVersion
Description: Represents the earliest TLS version supported.
Note:
If
minVersionis set butmaxVersionis not set, or if the setminVersionis later thanmaxVersion, TlsException is thrown during handshake.
Type: TlsVersion
prop securityLevel
public mut prop securityLevel: Int32
Description: Specifies the security level of the server. The default value is 2. The optional parameter value ranges from 0 to 5. For details about the parameter value, see the description of openssl-SSL_CTX_set_security_level. Description: Specifies the security level of the server. The default value is 2. The value ranges from 0 to 5. For details about the parameter description, see the description of openssl-SSL_CTX_set_security_level.
Type: Int32
Throws:
- IllegalArgumentException: If the value is not in the range from 0 to 5, this exception is thrown.
prop serverCertificate(Array<X509Certificate>, PrivateKey)
public mut prop serverCertificate: (Array<X509Certificate>, PrivateKey)
Description: Represents the server certificate and corresponding private key file.
Type: (Array<X509Certificate>, PrivateKey)
prop supportedAlpnProtocols
public mut prop supportedAlpnProtocols: Array<String>
Description: Negotiates the application layer protocol. If the client attempts to negotiate this protocol, the server selects the name of the protocol that intersects with the client. If the client does not attempt to negotiate the protocol, the configuration is ignored.
Throws:
- IllegalArgumentException: If the elements in the list contain the '\0' character, this exception is thrown.
init(Array<X509Certificate>, PrivateKey)
public init(certChain: Array<X509Certificate>, certKey: PrivateKey)
Description: Constructs a TlsServerConfig object.
Parameters:
- certChain: Array<X509Certificate>: certificate object
- certKey: PrivateKey: private key object.
struct TlsSession
public struct TlsSession <: Equatable<TlsSession> & ToString & Hashable
Description: Indicates the established client session. This struct instance cannot be created by users, and its internal struct is invisible to users.
After the TLS handshake with the client is successful, a session is generated. If the connection is lost due to some reasons, the client can reuse the session by using the session ID and skip the handshake process.
Parent Type:
func hashCode()
public override func hashCode(): Int64
Description: Generates a session ID hash value.
Returns:
- Int64: session ID hash value
func toString()
public override func toString(): String
Description: Generates a session ID string.
Returns:
- String: TlsSession: session ID string
operator func !=(TlsSession)
public override operator func !=(other: TlsSession)
Description: Checks whether two session IDs are different.
Parameters:
- other: TlsSession: the other session object to be compared with
Returns:
- Unit: If the two session objects are different,
trueis returned. Otherwise,falseis returned.
operator func ==(TlsSession)
public override operator func ==(other: TlsSession)
Description: Checks whether two session IDs are the same.
Parameters:
- other: TlsSession: the other session object to be compared with
Returns:
- Unit: If the two session objects are the same,
trueis returned. Otherwise,falseis returned.
Exception Class
class TlsException
public class TlsException <: Exception
Description: This class is an exception thrown when an error occurs during TLS processing.
Parent Type:
init()
public init()
Description: Creates a TlsException instance. The exception information is empty.
init(String)
public init(message: String)
Description: Creates a TlsException instance according to the exception information.
Parameters:
- message: String: exception information
Certificate and Public Key on the Server Stored in the Same File
import std.{fs.*, collection.*}
import net.tls.*
import crypto.x509.{X509Certificate,PrivateKey, Pem, PemEntry,DerBlob}
let certificatePath = "/etc/myserver/cert-and-key.pem"
func parsePem(text: String): (Array<X509Certificate>, PrivateKey) {
let pem = Pem.decode(text)
let chain = pem |>
filter<PemEntry> { entry => entry.label == PemEntry.LABEL_CERTIFICATE } |>
map<PemEntry, X509Certificate> { entry => X509Certificate.decodeFromDer(entry.body ?? DerBlob()) } |>
collectArray
let key = (pem |>
filter<PemEntry> { entry => entry.label == PemEntry.LABEL_PRIVATE_KEY} |>
map<PemEntry, PrivateKey> { entry => PrivateKey.decodeDer(entry.body ?? DerBlob()) } |>
first) ?? throw Exception("No private key found in the PEM file")
if (chain.isEmpty()) {
throw Exception("No certificates found in the PEM file")
}
return (chain, key)
}
func readTextFromFile(path: String): String {
var fileString = ""
try (file = File(path, OpenOption.Open(true, false))) {
fileString = String.fromUtf8(file.readToEnd())
()
}
fileString
}
main() {
// Parses the certificate and private key.
let pem = readTextFromFile(certificatePath)
let (certificate, privateKey) = parsePem(pem)
var _ = TlsServerConfig(certificate, privateKey)
// Enables the HTTPS service. For details, see the examples provided for other servers.
}
Client Example
import std.socket.TcpSocket
import crypto.x509.{X509Certificate,PrivateKey}
import net.tls.*
main() {
var config = TlsClientConfig()
config.verifyMode = TrustAll
config.alpnProtocolsList = ["h2"]
// Used to restore a session.
var lastSession: ?TlsSession = None
while (true) {// Reconnects the loop.
try (socket = TcpSocket("127.0.0.1", 8443)) {
socket.connect() // Establishes the TCP connection.
try (tls = TlsSocket.client(socket, clientConfig: config, session: lastSession)) {
try {
tls.handshake() // then we are negotiating TLS
lastSession = tls.session // If the negotiation is successful, the TLS session is stored for next reconnection.
} catch (e: Exception) {
lastSession = None // If the negotiation fails, the session is deleted.
throw e
}
// The TLS instance is complete.
tls.write("Hello, peer! Let's discuss our personal secrets.\n".toArray())
}
} catch (e: Exception) {
println("client connection failed ${e}, retrying...")
}
}
}
Certificate Hot Update
import std.socket.StreamingSocket
import crypto.x509.{X509Certificate,PrivateKey}
import net.tls.*
class MyServer {
private var currentConfig: TlsServerConfig
init(initialConfig: TlsServerConfig) { currentConfig = initialConfig }
/**
* Changing a certificate with a key affects only new connections.
*/
public mut prop certificate: (Array<X509Certificate>, PrivateKey) {
get() { currentConfig.serverCertificate }
set(newCertificate) { currentConfig.serverCertificate = newCertificate }
}
public func onAcceptedConnection(client: StreamingSocket) {
try (tls = TlsSocket.server(client, serverConfig: currentConfig)) {
tls.handshake()
}
}
}
Server Example
import std.fs.{File, OpenOption}
import std.socket.{TcpServerSocket, TcpSocket}
import crypto.x509.{X509Certificate, PrivateKey}
import net.tls.*
// Paths of the certificate and private key defined by the user
let certificatePath = "./files/apiserver.crt"
let certificateKeyPath = "./files/apiserver.key"
main() {
// Parses the certificate and private key.
let pem = readTextFromFile(certificatePath)
let keyText = readTextFromFile(certificateKeyPath)
let certificate = X509Certificate.decodeFromPem(pem)
let privateKey = PrivateKey.decodeFromPem(keyText)
let config = TlsServerConfig(certificate, privateKey)
// (Optional) Allows TLS session restoration.
let sessions= TlsSessionContext.fromName("my-server")
try (server = TcpServerSocket(bindAt:8443)) {
server.bind()
server.acceptLoop { clientSocket =>
try (tls = TlsSocket.server(clientSocket, serverConfig: config, sessionContext: sessions)) {
tls.handshake()
let buffer = Array<Byte>(100, item: 0)
tls.read(buffer)
println(buffer) // operate received data.
}
}
}
}
// Uses the helper function to simplify the sample code.
extend TcpServerSocket {
func acceptLoop(handler: (TcpSocket) -> Unit) {
while (true) {
let client = accept()
spawn {
try {
handler(client)
} finally {
client.close()
}
}
}
}
}
func readTextFromFile(path: String): String {
var str = ""
try (file = File(path, OpenOption.Open(true, false))) {
str = String.fromUtf8(file.readToEnd())
}
str
}
Serialization Module
Note:
The serialization module cannot be directly imported through the import serialization command. Otherwise, an error indicating that the serialization package cannot be found is reported during compilation. (error: can not find package'serialization'). You are advised to import the serialization subpackage to use the serialization module.
Function Description
The serialization module provides the serialization and deserialization capabilities.
Package List of the Serialization Module
The serialization module provides the following packages:
| Name | Description |
|---|---|
| serialization | The serialization package provides the serialization and deserialization capabilities. |
serialization.serialization Package
Function Description
The serialization package provides the serialization and deserialization capabilities.
Serialization is the process of translating a data structure or an object state into a format that can be stored (for example, files in secondary storage devices and data buffers in primary storage devices) or transmitted (for example, data streams over computer networks) and reconstructed later (possibly in the same or a different computer environment). Relatively, deserialization refers to a reverse operation of extracting a data structure from a series of bytes.
User-defined types can be serialized and deserialized by implementing the Serializable interface.
API List
Function
| Name | Description |
|---|---|
| field<T>(String, T) | Encapsulates a group of name and data into a Field object. |
Interface
| Name | Description |
|---|---|
| Serializable | Specifies serialization. |
Class
| Name | Description |
|---|---|
| DataModel | Intermediate data layer. |
| DataModelBool | This class is a subclass of DataModel and is used to encapsulate data of the Bool type. |
| DataModelFloat | This class is a subclass of DataModel and is used to encapsulate data of the Float64 type. |
| DataModelInt | This class is a subclass of DataModel and is used to encapsulate data of the Int64 type. |
| DataModelNull | This class is a subclass of DataModel and is used to encapsulate data of the Null type. |
| DataModelSeq | This class is a subclass of DataModel and is used to encapsulate data of the ArrayList<DataModel> type. |
| DataModelString | This class is a subclass of DataModel and is used to encapsulate data of the String type. |
| DataModelStruct | This class is a subclass of DataModel and is used to convert class objects to DataModel. |
| Field | Stores elements of DataModelStruct. |
Exception Class
| Name | Description |
|---|---|
| DataModelException | Exception class of DataModel. |
Function
func field<T>(String, T) where T <: Serializable<T>
public func field<T>(name: String, data: T) : Field where T <: Serializable<T>
Description: Encapsulates a group of data (name and data) into a Field object. Processes a group of data (name and data), serializes data to the DataModel type, and encapsulates name and data into the Field object.
Parameters:
- name: String: String type.
- data: T:
Ttype. TheTtype must implement the Serializable<T> interface.
Returns:
Interface
interface Serializable
public interface Serializable<T> {
func serialize(): DataModel
static func deserialize(dm: DataModel): T
}
Description: Specifies serialization.
func deserialize(DataModel)
static func deserialize(dm: DataModel): T
Description: Deserializes DataModel into an object.
Note:
The following types support the implementation of Serializable:
- Basic data types, including the integer type, floating point type, Boolean type, and string type
- Collection type, including Array, ArrayList, HashSet, HashMap, and Option
- A user-defined type that implements Serializable<T>
Returns:
- T: deserialized object
func serialize()
func serialize(): DataModel
Description: Serializes an object into DataModel.
Returns:
extend<T> Array<T> <: Serializable<Array<T>> where T <: Serializable<T>
extend<T> Array<T> <: Serializable<Array<T>> where T <: Serializable<T>
Parent Type:
- Serializable<Array<T>>
func deserialize(DataModel)
static public func deserialize(dm: DataModel): Array<T>
Description: Deserializes DataModel to Array<T>.
Parameters:
Returns:
Throws:
- DataModelException: If the
dmtype is not DataModelSeq, this exception is thrown.
func serialize()
public func serialize(): DataModel
Description: Serializes Array<T> to DataModelSeq.
Returns:
- DataModel: DataModelSeq after serialization
extend<T> ArrayList<T> <: Serializable<ArrayList<T>> where T <: Serializable<T>
extend<T> ArrayList<T> <: Serializable<ArrayList<T>> where T <: Serializable<T>
Parent Type:
func deserialize(DataModel)
static public func deserialize(dm: DataModel): ArrayList<T>
Description: Deserializes DataModel to ArrayList<T>.
Parameters:
Returns:
Throws:
- DataModelException: If the
dmtype is not DataModelSeq, this exception is thrown.
func serialize()
public func serialize(): DataModel
Description: Serializes ArrayList<T> to DataModelSeq.
Returns:
- DataModel: DataModelSeq after serialization
extend Bool <: Serializable
extend Bool <: Serializable<Bool>
Parent Type:
func deserialize(DataModel)
static public func deserialize(dm: DataModel): Bool
Description: Deserializes DataModel to Bool.
Parameters:
Returns:
Throws:
- DataModelException: If the
dmtype is not DataModelBool, this exception is thrown.
func serialize()
public func serialize(): DataModel
Description: Serializes Bool to DataModelBool.
Returns:
- DataModel: DataModelBool after serialization
extend Float16 <: Serializable
extend Float16 <: Serializable<Float16>
Extends Float16 to implement Serializable.
Parent Type:
func deserialize(DataModel)
static public func deserialize(dm: DataModel): Float16
Description: Deserializes DataModel to Float16.
Parameters:
Returns:
Throws:
- DataModelException: If the
dmtype is not DataModelFloat, this exception is thrown.
func serialize()
public func serialize(): DataModel
Description: Serializes Float16 to DataModelFloat.
Returns:
- DataModel: DataModelFloat after serialization
extend Float32 <: Serializable
extend Float32 <: Serializable<Float32>
Parent Type:
func deserialize(DataModel)
static public func deserialize(dm: DataModel): Float32
Description: Deserializes DataModel to Float32.
Parameters:
Returns:
Throws:
- DataModelException: If the
dmtype is not DataModelFloat, this exception is thrown.
func serialize()
public func serialize(): DataModel
Description: Serializes Float32 to DataModelFloat.
Returns:
- DataModel: DataModelFloat after serialization
extend Float64 <: Serializable
extend Float64 <: Serializable<Float64>
Parent Type:
func deserialize(DataModel)
static public func deserialize(dm: DataModel): Float64
Description: Deserializes DataModel to Float64.
Parameters:
Returns:
Throws:
- DataModelException: If the
dmtype is not DataModelFloat, this exception is thrown.
func serialize()
public func serialize(): DataModel
Description: Serializes Float64 to DataModelFloat.
Returns:
- DataModel: DataModelFloat after serialization
extend HashMap <: Serializable
extend<K, V> HashMap<K, V> <: Serializable<HashMap<K, V>> where K <: Serializable<K> & Hashable & Equatable<K>, V <: Serializable<V>
Parent Type:
- Serializable<HashMap<K, V>>
func deserialize(DataModel)
static public func deserialize(dm: DataModel): HashMap<K, V>
Description: Deserializes DataModel to HashMap<K, V>.
Parameters:
Returns:
Throws:
- DataModelException: If the
dmtype is not DataModelStruct or if Field in thedmof the DataModelStruct type is not of the String type, this exception is thrown.
func serialize()
public func serialize(): DataModel
Description: Serializes HashMap<K, V> to DataModelSeq.
Returns:
- DataModel: DataModelSeq after serialization
Throws:
- DataModelException: If Key in the current HashMap instance is not of the String type, this exception is thrown.
extend<T> HashSet<T> <: Serializable<HashSet<T>> where T <: Serializable<T> & Hashable & Equatable<T>
extend<T> HashSet<T> <: Serializable<HashSet<T>> where T <: Serializable<T> & Hashable & Equatable<T>
Parent Type:
- Serializable<HashSet<T>>
func deserialize(DataModel)
static public func deserialize(dm: DataModel): HashSet<T>
Description: Deserializes DataModel to HashSet<T>.
Parameters:
Returns:
Throws:
- DataModelException: If the
dmtype is not DataModelSeq, this exception is thrown.
func serialize()
public func serialize(): DataModel
Description: Serializes HashSet<T> to DataModelSeq.
Returns:
- DataModel: DataModelSeq after serialization
extend Int16 <: Serializable
extend Int16 <: Serializable<Int16>
Parent Type:
func deserialize(DataModel)
static public func deserialize(dm: DataModel): Int16
Description: Deserializes DataModel to Int16.
Parameters:
Returns:
Throws:
- DataModelException: If the
dmtype is not DataModelInt, this exception is thrown.
func serialize()
public func serialize(): DataModel
Description: Serializes Int16 to DataModelInt.
Returns:
- DataModel: DataModelInt after serialization
extend Int32 <: Serializable
extend Int32 <: Serializable<Int32>
Parent Type:
func deserialize(DataModel)
static public func deserialize(dm: DataModel): Int32
Description: Deserializes DataModel to Int32.
Parameters:
Returns:
Throws:
- DataModelException: If the
dmtype is not DataModelInt, this exception is thrown.
func serialize()
public func serialize(): DataModel
Description: Serializes Int32 to DataModelInt.
Returns:
- DataModel: DataModelInt after serialization
extend Int64 <: Serializable
extend Int64 <: Serializable<Int64>
Parent Type:
func deserialize(DataModel)
static public func deserialize(dm: DataModel): Int64
Description: Deserializes DataModel to Int64.
Parameters:
Returns:
Throws:
- DataModelException: If the
dmtype is not DataModelInt, this exception is thrown.
func serialize()
public func serialize(): DataModel
Description: Serializes Int64 to DataModelInt.
Returns:
- DataModel: DataModelInt after serialization
extend Int8 <: Serializable
extend Int8 <: Serializable<Int8>
Parent Type:
func deserialize(DataModel)
static public func deserialize(dm: DataModel): Int8
Description: Deserializes DataModel to Int8.
Parameters:
Returns:
Throws:
- DataModelException: If the
dmtype is not DataModelInt, this exception is thrown.
func serialize()
public func serialize(): DataModel
Description: Serializes Int8 to DataModelInt.
Returns:
- DataModel: DataModelInt after serialization
extend<T> Option<T> <: Serializable<Option<T>> where T <: Serializable<T>
extend<T> Option<T> <: Serializable<Option<T>> where T <: Serializable<T>
Parent Type:
- Serializable<Option<T>>
func deserialize()
static public func deserialize(dm: DataModel): Option<T>
Description: Deserializes DataModel to Option<T>.
Parameters:
Returns:
func serialize()
public func serialize(): DataModel
Description: Serializes T in Option<T> to DataModel.
Returns:
extend Rune <: Serializable
extend Rune <: Serializable<Rune>
Parent Type:
func deserialize(DataModel)
static public func deserialize(dm: DataModel): Rune
Description: Deserializes DataModel to Rune.
Parameters:
Returns:
- Rune: characters after deserialization
Throws:
- DataModelException: If the
dmtype is not DataModelString, this exception is thrown. - Exception: If the
dmtype is not Rune, this exception is thrown.
func serialize()
public func serialize(): DataModel
Description: Serializes Rune to DataModelString.
Returns:
- DataModel: DataModelString after serialization
extend String <: Serializable
extend String <: Serializable<String>
Parent Type:
func deserialize(DataModel)
static public func deserialize(dm: DataModel): String
Description: Deserializes DataModel to String.
Parameters:
Returns:
Throws:
- DataModelException: If the
dmtype is not DataModelString, this exception is thrown.
func serialize()
public func serialize(): DataModel
Description: Serializes String to DataModelString.
Returns:
- DataModel: DataModelString after serialization
extend UInt16 <: Serializable
extend UInt16 <: Serializable<UInt16>
Parent Type:
func deserialize(DataModel)
static public func deserialize(dm: DataModel): UInt16
Description: Deserializes DataModel to UInt16.
Parameters:
Returns:
Throws:
- DataModelException: If the
dmtype is not DataModelInt, this exception is thrown.
func serialize()
public func serialize(): DataModel
Description: Serializes UInt16 to DataModelInt.
Returns:
- DataModel: DataModelInt after serialization
extend UInt32 <: Serializable
extend UInt32 <: Serializable<UInt32>
Parent Type:
func deserialize(DataModel)
static public func deserialize(dm: DataModel): UInt32
Description: Deserializes DataModel to UInt32.
Parameters:
Returns:
Throws:
- DataModelException: If the
dmtype is not DataModelInt, this exception is thrown.
func serialize()
public func serialize(): DataModel
Description: Serializes UInt32 to DataModelInt.
Returns:
- DataModel: DataModelInt after serialization
extend UInt64 <: Serializable
extend UInt64 <: Serializable<UInt64>
Parent Type:
func deserialize(DataModel)
static public func deserialize(dm: DataModel): UInt64
Description: Deserializes DataModel to UInt64.
Parameters:
Returns:
Throws:
- DataModelException: If the
dmtype is not DataModelInt, this exception is thrown.
func serialize()
public func serialize(): DataModel
Description: Serializes UInt64 to DataModelInt.
Returns:
- DataModel: DataModelInt after serialization
extend UInt8 <: Serializable
extend UInt8 <: Serializable<UInt8>
Parent Type:
func deserialize(DataModel)
static public func deserialize(dm: DataModel): UInt8
Description: Deserializes DataModel to UInt8.
Parameters:
Returns:
Throws:
- DataModelException: If the
dmtype is not DataModelInt, this exception is thrown.
func serialize()
public func serialize(): DataModel
Description: Serializes UInt8 to DataModelInt.
Returns:
- DataModel: DataModelInt after serialization
Class
class DataModel
public abstract class DataModel
Description: This class is an intermediate data layer.
class DataModelBool
public class DataModelBool <: DataModel {
public init(bv: Bool)
}
Description: This class is a subclass of DataModel and is used to encapsulate Bool data.
Parent Type:
init(Bool)
public init(bv: Bool)
Description: Constructs a DataModelBool instance with initial data.
Parameters:
func getValue()
public func getValue(): Bool
Description: Obtains data from DataModelBool.
Returns:
- Bool:
valueof the Bool type in DataModelBool
class DataModelFloat
public class DataModelFloat <: DataModel {
public init(fv: Float64)
public init(v: Int64)
}
Description: This class is a subclass of DataModel and is used to encapsulate Float64 data.
Parent Type:
init(Float64)
public init(fv: Float64)
Description: Constructs a DataModelFloat instance with initial data.
Parameters:
init(Int64)
public init(v: Int64)
Description: Constructs a DataModelFloat instance with initial data.
Parameters:
func getValue()
public func getValue(): Float64
Description: Obtains data from DataModelFloat.
Returns:
- Float64:
valueof the Float64 type in DataModelFloat
class DataModelInt
public class DataModelInt <: DataModel {
public init(iv: Int64)
}
Description: This class is a subclass of DataModel and is used to encapsulate Int64 data.
Parent Type:
init(Int64)
public init(iv: Int64)
Description: Constructs a DataModelInt instance with initial data.
Parameters:
func getValue()
public func getValue(): Int64
Description: Obtains data from DataModelInt.
Returns:
- Int64:
valueof the Int64 type in DataModelInt
class DataModelNull
public class DataModelNull <: DataModel
Description: This class is a subclass of DataModel and is used to encapsulate Null data.
Parent Type:
class DataModelSeq
public class DataModelSeq <: DataModel {
public init()
public init(list: ArrayList<DataModel>)
}
Description: This class is a subclass of DataModel and is used to encapsulate ArrayList<DataModel> data.
Parent Type:
init()
public init()
Description: Constructs a DataModelSeq instance with empty parameters. By default, the data is empty ArrayList<DataModel>.
init(ArrayList<DataModel>)
public init(list: ArrayList<DataModel>)
Description: Constructs a DataModelSeq instance with initial data.
Parameters:
func add(DataModel)
public func add(dm: DataModel)
Description: Adds DataModel data to the end of DataModelSeq.
Parameters:
func getItems()
public func getItems(): ArrayList<DataModel>
Description: Obtains data from DataModelSeq.
Returns:
- ArrayList<DataModel>: ArrayList<DataModel> data in DataModelSeq
class DataModelString
public class DataModelString <: DataModel {
public init(sv: String)
}
Description: This class is a subclass of DataModel and is used to encapsulate String data.
Parent Type:
init(String)
public init(sv: String)
Description: Constructs DataModelString with initial data.
Parameters:
func getValue()
public func getValue(): String
Description: Obtains data from DataModelString.
Returns:
- String:
valueof the String type in DataModelString
class DataModelStruct
public class DataModelStruct <: DataModel {
public init()
public init(list: ArrayList<Field>)
}
Description: This class is a subclass of DataModel and is used to convert class objects to DataModel.
Parent Type:
init()
public init()
Description: Constructs ArrayList<Field> with empty parameters and whose DataModelStructfields is empty by default.
init(ArratList<Field>)
public init(list: ArrayList<Field>)
Description: Constructs DataModelStruct with initial data.
Parameters:
func add(Field)
public func add(fie: Field): DataModelStruct
Description: Adds data fie to DataModelStruct.
Parameters:
Returns:
- DataModelStruct: new DataModelStruct obtained
func get(String)
public func get(key: String): DataModel
Description: Obtains the data corresponding to key.
Parameters:
Returns:
- DataModel: value of the DataModel type. If the corresponding value is not found, DataModelNull is returned.
func getFields()
public func getFields(): ArrayList<Field>
Description: Obtains a DataModelStruct data set.
Returns:
class Field
public class Field {
public init(name: String, data: DataModel)
}
Description: Stores DataModelStruct elements.
init(String, DataModel)
public init(name: String, data: DataModel)
Description: Specifies the constructor of Field.
Parameters:
- name: String:
namefield value. When thenamefield is"", its behavior is the same as that when it is in other strings. - data: DataModel:
datafield value
func getData()
public func getData(): DataModel
Description: Obtains the data field.
Returns:
func getName()
public func getName(): String
Description: Obtains the name field.
Returns:
Exception Class
class DataModelException
public class DataModelException <: Exception
Description: Represents the DataModel exception class.
Parent Type:
init()
public init()
Description: Creates a DataModelException instance.
init(String)
public init(message: String)
Description: Creates a DataModelException instance according to the exception information.
Parameters:
- message: String: exception information string
class Serialization and Deserialization
import serialization.serialization.*
import std.math.*
import encoding.json.*
/* Serializes and deserializes user-defined types by implementing the Serializable API. */
class Abc <: Serializable<Abc> {
var name: String = "Abcde"
var age: Int64 = 555
var loc: Option<Location> = Option<Location>.None
/* Implements the serialization method of the Serializable interface. */
public func serialize(): DataModel {
return DataModelStruct().add(field<String>("name", name)).add(field<Int64>("age", age)).add(field<Option<Location>>("loc", loc))
}
/* Implements the deserialization method. */
public static func deserialize(dm: DataModel): Abc {
let dms = match (dm) {
case data: DataModelStruct => data
case _ => throw Exception("this data is not DataModelStruct")
}
let result = Abc()
result.name = String.deserialize(dms.get("name"))
result.age = Int64.deserialize(dms.get("age"))
result.loc = Option<Location>.deserialize(dms.get("loc"))
return result
}
}
class Location <: Serializable<Location> {
var time: Int64 = 666
var heheh: Rune = 'T'
/* Implements the serialization method of the Serializable interface. */
public func serialize(): DataModel {
return DataModelStruct().add(field<Int64>("time", time)).add(field<Rune>("heheh", heheh))
}
/* Implements the deserialization method. */
public static func deserialize(dm: DataModel): Location {
let dms = match (dm) {
case data: DataModelStruct => data
case _ => throw Exception("this data is not DataModelStruct")
}
let result = Location()
result.time = Int64.deserialize(dms.get("time"))
result.heheh = Rune.deserialize(dms.get("heheh"))
return result
}
}
main(): Unit {
let dd = Abc()
let aa: JsonValue = dd.serialize().toJson()
let bb: JsonObject = (aa as JsonObject).getOrThrow()
let v1 = (bb.get("name").getOrThrow() as JsonString).getOrThrow()
let v2 = (bb.get("age").getOrThrow() as JsonInt).getOrThrow()
let v3 = bb.get("loc").getOrThrow()
println(v1.getValue())
println(v2.getValue())
println(v3.toString())
println("===========")
let aaa = ##"{"age": 123, "loc": { "heheh": "H", "time": 45 }, "name": "zhangsan"}"##
let bbb = JsonValue.fromStr(aaa)
let ccc = (bbb as JsonObject).getOrThrow()
let v4 = (ccc.get("name").getOrThrow() as JsonString).getOrThrow()
let v5 = (ccc.get("age").getOrThrow() as JsonInt).getOrThrow()
let v6 = (ccc.get("loc").getOrThrow() as JsonObject).getOrThrow()
let v7 = (v6.get("time").getOrThrow() as JsonInt).getOrThrow()
let v8 = (v6.get("heheh").getOrThrow() as JsonString).getOrThrow()
println(v4.getValue())
println(v5.getValue())
println(v7.getValue())
println(v8.getValue())
}
Running result:
Abcde
555
null
===========
zhangsan
123
45
H
HashSet and HashMap Serialization
import std.collection.*
import serialization.serialization.*
import encoding.json.*
main(): Unit {
let s: HashSet<Values> = HashSet<Values>([Values(3), Values(5), Values(7)])
let seris: DataModel = s.serialize()
println(seris.toJson().toJsonString())
println("===========")
let m: HashMap<String, Values> = HashMap<String, Values>([("1", Values(3)), ("2", Values(6)), ("3", Values(9))])
let serim: DataModel = m.serialize()
print(serim.toJson().toJsonString())
}
class Values <: Hashable & Equatable<Values> & Serializable<Values> {
var m_data: Int64
init(m_data: Int64) {
this.m_data = m_data
}
public func hashCode(): Int64 {
return this.m_data
}
public operator func ==(right: Values): Bool {
let a = (this.m_data == right.m_data)
if (a) { return true } else { return false }
}
public operator func !=(right: Values): Bool {
let a = (this.m_data != right.m_data)
if (a) { return true } else { return false }
}
/* Implements the serialization method of the Serializable interface. */
public func serialize(): DataModel {
return DataModelStruct().add(field<Int64>("m_data", m_data))
}
/* Implements the deserialization method. */
public static func deserialize(dm: DataModel): Values {
let dms: DataModelStruct = match (dm) {
case data: DataModelStruct => data
case _ => throw Exception("this data is not DataModelStruct")
}
let result = Values(0)
result.m_data = Int64.deserialize(dms.get("m_data"))
return result
}
}
Running result:
[
{
"m_data": 3
},
{
"m_data": 5
},
{
"m_data": 7
}
]
===========
{
"1": {
"m_data": 3
},
"2": {
"m_data": 6
},
"3": {
"m_data": 9
}
}
Cangjie IDE Plug-in User Guide
Function Description
Cangjie provides the Visual Studio Code plug-in (VSCode for short). After the Cangjie plug-in and Cangjie SDK are installed in VSCode, you can use the language service, project management, compilation and building, debugging, formatting, and code coverage statistics functions. This document describes how to install the Cangjie plug-in in VSCode and how to use the functions provided by the plug-in.
Note:
The static code check capability is being built. You are not advised to perform operations related to CodeCheck. Otherwise, a message may be displayed indicating that cjlint does not exist.
Downloading Software
Download the VSCode installation package from the VSCode official website. Version 1.67 or later is recommended. To download the Cangjie plug-in, go to Cangjie download center, select the required version, and click the IDE installation package (VSCode).
| Download Item | Description | Required |
|---|---|---|
| Visual Studio Code | IDE | Yes |
| IDE installation package (VSCode) | Cangjie plug-in | Yes |
Installing VSCode
Windows
Run the VSCode installation file (for example, VSCodeUserSetup-x64.exe) and select a path as prompted to install VSCode.
Linux
Local installation
-
Decompress the downloaded package (for example, VSCode-linux-x64) and save it to a custom location.
-
Run the following command to grant the execute permission to code:
chmod 777 ./VSCode-linux-x64/code chmod 777 ./VSCode-linux-x64/bin/code -
Run the following command to start VSCode:
./VSCode-linux-x64/bin/code
Remote installation
-
Search for Remote - SSH in VSCode and click Install.

-
If you use Remote - SSH for remote work, VSCode automatically installs the server on the remote host. Currently, linux_arm64 supports only the Remote - SSH mode.
macOS
Decompress the downloaded package (for example, VSCode-darwin-universal.zip) and drag the decompressed .app file to the application to complete the VSCode installation.
Installing the Cangjie Plug-in
Decompress the downloaded package to obtain the .vsix plug-in file.
Open the file resource manager in VSCode, find the .vsix plug-in file to be installed, and click OK.

You can view the installed plug-ins in the INSTALLED directory.

Installing the Cangjie SDK
The Cangjie SDK provides command line tools such as Cangjie Package Manager (CJPM), Cangjie compilation command (cjc), and Cangjie Formatter (cjfmt). After the Cangjie SDK is correctly installed and configured, you can use functions such as project management, compilation and building, formatting, and coverage statistics. You can download the SDK in either of the following ways:
- Offline manual installation. Download the SDK installation package from the official website and install the Cangjie SDK on the local host.
- Installation using VSCode. The Cangjie plug-in provides the functions of downloading and updating the latest Cangjie SDK. You can download the latest Cangjie SDK and deploy it in the local environment in VSCode.
Downloading SDK
You can manually download the Cangjie SDK at Cangjie download center.
Windows
For Windows, download Cangjie-version-windows_x64.exe or Cangjie-version-windows_x64.zip.
Download the SDK and save it to the local host. If the .exe file is downloaded, run the file, select the installation path as prompted, and record the path. If the .zip file is downloaded, decompress the file and record the storage path.
The directory structure of the SDK folder is as follows:
cangjie
├── bin
├── lib
├── modules
├── runtime
├── third_party
├── tools
├── envsetup.bat
├── envsetup.ps1
└── envsetup.sh
Linux
For Linux_x64, download Cangjie-version-linux_x64.tar.gz.
For Linux_AArch64, download Cangjie-version-linux_aarch64.tar.gz.
Download the SDK, save it to the local host, and record the storage path. The directory structure is as follows:
cangjie
├── bin
├── include
├── lib
├── modules
├── runtime
├── third_party
├── tools
└── envsetup.sh
macOS
For macOS_x86_64, download Cangjie-version-darwin_x64.tar.gz.
For macOS_AArch64, download Cangjie-version-darwin_aarch64.tar.gz.
Download the SDK, save it to the local host, and record the storage path. The directory structure is as follows:
cangjie
├── bin
├── lib
├── modules
├── runtime
├── third_party
├── tools
└── envsetup.sh
Setting SDK Path
After the Cangjie plug-in is installed, you can configure the SDK path. Click the gear icon in the lower left corner and select Settings.

Alternatively, right-click the plug-in and choose Extension Settings from the shortcut menu. The Settings page is displayed.

Enter Cangjie in the search box and select Cangjie Language Support in the sidebar.

Configuring the CJNative Backend
-
Find Cangjie Sdk: Option. Select CJNative (the default option) as the backend type.
-
Find Cangjie Sdk Path: CJNative Backend. Enter the absolute path of the CJNative backend SDK folder.
-
Restart VSCode for the modification to take effect.

Validating the Installation
Open the VSCode command panel by pressing Ctrl + Shift + P (or Command + Shift + P in macOS), and select cangjie: Create Cangjie Project View.

If the Create New Cangjie Project page is displayed, the Cangjie SDK is successfully installed.

Constraints
Constraint 1
The Cangjie plug-in provides language services only for the Cangjie source code in the folder opened by developers. For example, the opened folder is the root directory PROJECTROOT of the Cangjie project. If the module name is not specified, the name of the PROJECTROOT directory is used as the module name by default to facilitate the import of packages in src. PROJECTROOT/src is the source code of Cangjie in src (supporting language services). All other source code in the PROJECTROOT directory is called non-src Cangjie source code (supporting language services). The Cangjie source code outside the PROJECTROOT directory is called external source code (not supporting language services currently).
Constraint 2
Each folder in a non-src directory serves as a package. The declaration of the package name and the compilation method of the package are the same as those of the top-level package (default package) in the src directory. The Cangjie source code in the non-src directory can be imported to packages in the standard library and custom packages in the src directory. Packages in the non-src directory cannot be imported to other packages.
Constraint 3
In Linux, Windows, and macOS, you need to set the Cangjie SDK path first.
Language Service
Function Description
The language service tool provides the following functions for developers: syntax highlight, autocomplete, definition redirection, reference search, error diagnosis, selection highlight, floating prompt, signature help, and renaming.
Code Highlight
Open the .cj file in the Cangjie project in VSCode. The code is highlighted. Different themes of VSCode are highlighted in different colors. Operators, classes, comments, functions, keywords, numbers, package names, strings, and variables can be highlighted.

Autocomplete
Use VSCode to open the .cj file in the Cangjie project and enter a keyword, variable, or period (.). The candidate content is displayed on the right of the cursor. Use the up and down arrow keys to quickly select the desired content (you need to switch to the default input method), and press Enter or Tab to complete the content.


Modular supplement is provided for functions with parameters or generics. That is, when a function has parameters or generics, parameter formatting completion is displayed after you select function completion, as shown in the following figure. After filling in the value, press Tab to switch to the next parameter until the modular completion is complete, or press Esc to exit the selected module in advance.

Definition Jump
Open the .cj file in the Cangjie project in VSCode, hover the mouse pointer over the target, press Ctrl, and click the left mouse button to trigger the definition jump; or right-click the target symbol and choose Go to Definition from the shortcut menu to execute the definition jump; or press F12 to execute the definition jump.

Note
If definition jump is used at a symbol, you are redirected to the symbol definition. Cross-file jump is supported. If definition jump is used at the symbol definition, and the symbol has not been referenced, the cursor jumps to the left of the symbol. If a symbol is referenced elsewhere, a reference lookup is triggered.
Cross-Language Redirection
The language service plug-in supports the redirection from Cangjie language to C language. You can open the .cj file in the Cangjie project in VSCode, hover the mouse pointer over the Cangjie interoperability function, press Ctrl, and click the left mouse button to trigger the definition jump; or right-click the target symbol and choose Go to Definition from the shortcut menu; or press F12 to perform the definition jump.
Prerequisites
- Huawei-developed C++ plug-in is installed on the local host.
- The directory for storing the C language source code to be redirected to is set on the Cangjie plug-in.
- The build folder is in the current project to store the compile_commands.json file (which can be generated by running the CMake command) for creating the index file of the specified folder.
Jump Effect
The foreign function searches for the corresponding C language function in the directory set by the developer. If the function is found, the function location in the C language source code is displayed. Except for the preceding scenario, the original definition redirection of the plug-in is retained.

Search for Reference
You can open the .cj file in the Cangjie project in VSCode, right-click the target symbol, and choose Find All References from the shortcut menu to preview the symbol reference. You can click a preview item to go to the corresponding reference.

Error Diagnosis
You can open the .cj file in the Cangjie project in VSCode. If the source code file contains code that does not comply with Cangjie syntax or semantic rules, a red wavy underline is displayed in the related code segment, as shown in the following figure. When the cursor hovers over the code segment, an error message is displayed. After modification, the error is automatically cleared.

Selection Highlight
You can open the .cj file in the Cangjie project in VSCode. When you move the cursor to a variable or function name, the declaration and usage of the variable in the current file are highlighted.

Floating Tips
You can open the .cj file in the Cangjie project in VSCode. When the cursor hovers over a variable, the type information is displayed.

When the cursor hovers over a function name, the function prototype is displayed.

Definition Search
You can open the .cj file in the Cangjie project in VSCode, press Ctrl + T, and enter the symbol definition name in the search box that is displayed. The search result is displayed. You can click an item in the search result to go to the corresponding definition location.

Currently, the following definition types can be searched: class, interface, enum, struct, typealias, toplevel function, toplevel variable, prop, enum constructor, member function, and member variable.
Rename
You can open the .cj file in the Cangjie project in VSCode, right-click the name to be modified, and choose Rename Symbol from the shortcut menu or press F2 to open the rename edit box.

After editing, you can press Enter to complete the renaming.

Currently, the following types can be renamed: class, interface, enum, struct, func, type, generic, variable, and custom macro.
Outline View Display
You can open the .cj file in the Cangjie project in VSCode. The outline of the current file is displayed in the OUTLINE view on the left. Currently, a two-layer structure is supported. The first layer is the declarations defined in toplevel, and the second layer is the constructors and members.

Currently, the following types can be displayed in the outline view: class, interface, enum, struct, typealias, toplevel function, toplevel variable, prop, enum constructor, member function, and member variable.
Breadcrumb Navigation
You can open any .cj file in the Cangjie project in VSCode, move the cursor to a symbol, and click the breadcrumb navigation icon. The current location of the symbol and the path of the symbol in the entire project are displayed.

Currently, the following types support breadcrumb navigation: class, interface, enum, struct, typealias, toplevel function, toplevel variable, prop, enum constructor, member function, and member variable.
Signature Help
VSCode triggers signature help when a left parenthesis and a comma are entered. The prompt box keeps moving with the cursor as long as it is within the function parameter range. (Signature help can coexist with the autocompletion function.) As shown in the following figure, you can view the parameter information of the current function and the highlight effect of the current function location parameter.

Type Hierarchy Display
You can open the .cj file in the Cangjie project in VSCode, right-click the custom name to be viewed, and choose Show Type Hierarchy from the shortcut menu. The type hierarchy is displayed on the left. By default, the object type is the parent class of all classes and is not displayed in this function.
Currently, the following types support hierarchy display: class, interface, enum, and struct.

You can click the icon marked in the figure to switch between the subclass and parent class.

Call Type Hierarchy
You can open the .cj file in the Cangjie project in VSCode, right-click the function name, and choose Show Call Hierarchy from the shortcut menu. The call type hierarchy of the function is displayed on the left.

You can click the marked icon to switch between the calling function and the called function.

Creating a Cangjie Project
The following figure shows the directory structure of a Cangjie project.
Project_name: user-defined name
├── src: code directory
│ └── main.cj: source code file
└── cjpm.toml: default configuration file cjpm.toml
Using the VSCode Command Panel
In VSCode, press F1 or press Ctrl + Shift + P (Command + Shift + P for macOS) to open the command panel. Perform the following steps to create a Cangjie project.
Step 1: Select the command for creating a Cangjie project.

Step 2: Select Cangjie backend.

Step 3: Select a project template.

Step 4: Select a project path.

Step 5: Enter the project name.
Select a path for storing the project and enter the project name.
Step 6: Create the project and open it.

Using a Visualization View
In VSCode, press F1 or press Ctrl + Shift + P (Command + Shift + P for macOS) to open the command panel. Perform the following steps to create a Cangjie project.
Step 1: Select the command for creating a Cangjie visualization project.

Step 2: Open the Create New Cangjie Project page.

Step 3: Select a project template.

Step 4: Select a project path.
Select a path for storing the project and enter the project name.
Step 5: Enter the project name.

Step 6: Click Confirm to create and open the project.

Compilation and Building
The compilation and building capabilities of the Cangjie project provided in VSCode depend on the cjpm tool. This tool requires that the module of the opened Cangjie project contain standard cjpm.toml file. If the file does not exist, you can run the cjc command on the terminal to compile the project.
In VSCode, you can run commands on the command panel, run commands on the terminal, click the Run button to run a project, or click the Hammer button to compile a project.
Compilation Modes
Running Commands on the Command Panel
In VSCode, press F1 or press Ctrl + Shift + P (Command + Shift + P for macOS) to open the command panel. Enter Cangjie to quickly find the following compilation commands.
-
Select
Cangjie: Parallelled Buildto perform parallel compilation.
After parallel compilation is performed, the
targetdirectory is generated in the project folder. Areleasefolder is available in thetargetdirectory. Thereleasefolder contains three directories:.build-logsdirectory,bindirectory, and a directory with the same name as the project. Thebindirectory stores executable files (the executable files are generated only whenoutput-typeofcjpm.tomlis set toexecutable). The directory with the same name as the project stores the intermediate files generated during compilation.The information about whether the compilation is successful is displayed on the output panel.
-
Select
Cangjie: Build With Verboseto perform compilation and display compilation logs.
In addition to compilation, this compilation parameter also prints compilation logs.
-
Select
Cangjie: Build With Debugto generate the target file of the debug version.The compilation result of this command contains debug information for debugging.
-
Select
Cangjie: Build With Coverageto generate coverage information.The compilation result of this command contains coverage information.
-
Select
Cangjie: Build With Aliasto perform compilation and specify the name of the output executable file.
After you run this command and press Enter, an input box is displayed. You need to assign a new name to the project compilation result. This command is valid only when
output-typeofcjpm.tomlis set toexecutable. -
Select
Cangjie: Build With Incrementto perform incremental compilation.This command is used to specify incremental compilation.
-
Select
Cangjie: Build With CustomizedOptionto transparently transmit commands in thecjpm.tomlfile by condition.
To use this option, you need to configure the
customized-optionfield in thecjpm.tomlfile, enterBuild With CustomizedOptionon the command panel, and press Enter to select the required parameters. You can select multiple parameters.
If the
customized-optionfield is not configured incjpm.tomland this command is executed, the plug-in prompts you to configure the field first. -
Select
Cangjie: Build With TargetDirto perform compilation and generate the compilation product in the specified path.After this command is executed, you can specify the output path of the compilation product. If you do not specify the path, the path specified by the
target-dirfield incjpm.tomlis used by default.
If the entered path is different from that specified by the
target-dirfield in cjpm.toml, a message is displayed, asking you whether to overwrite thetarget-dirfield in cjpm.toml. If you select Yes, thetarget-dirfield in cjpm.toml is overwritten by the entered value.
After the command is executed successfully, the compilation product is generated in the specified path.
-
Select
Cangjie: Build With Jobsto customize the maximum concurrency before compilation.You can run this command to customize the maximum concurrency before compilation. The input parameter can be any number in the range of (0, Number of CPU cores x 2].
If you enter a non-digit number in the input box, the operation is terminated, along with the message "Invaild input! The input should be number."
If the value entered in the input box exceeds the supported range (0, Number of CPU cores x 2], the number of CPU cores is used by default, and an alarm is displayed indicating that the value is out of the range.
-
Select
Cangjie: Build With MultiParameterto perform multi-parameter compilation.Multiple parameters can be added for compilation of a Cangjie project. After the
Build With MultiParametercommand is found on the command panel, select the parameters to be added. Whether to display the--targetparameter depends on thecross-compile-configurationfield incjpm.toml. If you do not configurecross-compile-configuration, the--targetoption is hidden. Whether to display the--<customized-option>parameter depends on thecustomized-optionfield in cjpm.toml. If you do not configurecustomized-option, the--<customized-option>option is hidden.
Select the parameters to be added, and then press Enter or click OK. You can also click the left arrow on the page to reselect compilation parameters.
If
cjpm build --output=<name>is selected, you need to enter an alias string and press Enter to run the command.
If
cjpm build --target=<name>is selected, you can select a platform for cross compilation.If
cjpm build --<customized-option>is selected, you can select the transparent transmission parameter.
The compilation result of the add command is the sum of the execution results of these commands.
-
Select
Cangjie: Update Cjpm.tomlto update the cjpm.lock file.After modifying the
cjpm.tomlfile, you need to run this command to update thecjpm.lockfile. If you modify thecjpm.tomlfile on the UI, you do not need to manually perform this operation. -
Select
Cangjie: Execute Test Fileto compile the unit test product, execute the corresponding unit test case, and print the test result. -
Select
Cangjie: Test With NoRunto compile the corresponding test product. -
Select
Cangjie: Test With SkipBuildto execute the test product if the test product exists. -
Select
Cangjie: Test With Jobsto customize the maximum concurrency before executing the unit test. The operation is the same asBuild With Jobs. -
Select
Cangjie: Test With MultiParameterto execute the unit test with multiple parameters.After the command is selected, enter the path of the package to be tested. If you do not need to specify it, press Enter. You can implement a multipacket concurrent unit test by entering the paths of multiple packages and separating them with spaces.

Select the parameters to be added.

If
--filter=<value>is selected, you need to enter the expression for filtering the test subset.
The complete
cjpm testcommand can be executed after the expression for filtering the test subset is entered. The execution result is displayed on the Output panel.If
cross-compile-configurationandcustomized-optionare configured in the cjpm.toml file,--target=<name>and--<customized-option>are available.
If
--target=<name>is selected, you need to select the corresponding platform.
The
--targetparameter can be set toaarch64-hm-gnuonly on the SUSE platform.If
--<customized-option>is selected, you need to select customized options.
-
Select
Cangjie: Clean Build Resultto clear the compilation result (in the build directory of the project). -
Select
Cangjie: Check Circular Dependenciesto detect file dependencies. -
Select
Cangjie: Edit Configuration (UI)to open the configuration UI.
Running Commands on the Terminal
You can run the cjpm command on the VSCode terminal panel to compile a Cangjie project. If it is the first time that you use VSCode, you need to restart the VSCode to perform the cjpm operation on the terminal.

Clicking the Run Button to Run a Project
You can click the Run button in the .cj file editing area to run the entire Cangjie project.

If output-type is set to executable for the entire project, the running result is displayed on the terminal panel. Otherwise, only the compilation result is displayed.
The compilation process executed by clicking the Run button is based on the configurations of the cjpm.toml file and cjpm_build_args.json.
Clicking the Hammer Button to Compiling a Project
You can click the Hammer button in the .cj file editing area to compile the entire Cangjie project.

The compilation process performed by clicking the Hammer button is the same as that performed by clicking the Run button, and is also performed based on the configurations of the cjpm.toml file and cjpm_build_args.json. The difference is that if output-type is set to executable for the entire project, the entire project is executed after the compilation performed by clicking the Run button is complete, whereas the project is not executed after the compilation performed by clicking the Hammer button is complete.
Configuring Build Parameters in a Visualized Style
During compilation, you need to configure the cjpm.toml and cjpm_build_args.json files in the project directory in one of the following ways.
- Directly modify the
cjpm.tomlandcjpm_build_args.jsonfiles.

- Press F1 or press Ctrl + Shift + P (Command + Shift + P for macOS) to open the command panel. Run the
Cangjie: Edit Configuration (UI)command on the command panel to open the visualized edit UI.

- Click the brush icon in the upper right corner of the edit page to go to the visualized edit UI.

For the cjpm_build_args.json configuration in the .vscode directory of the project file, you can check or enter the parameters to be used for compilation. The modifications are synchronized to the cjpm_build_args.json file.
For the cjpm.toml file configuration in the project, you can enter the content and move the cursor out of the input box for the configuration to take effect in the cjpm.toml file.
Note:
When the
cjpm.tomlfile and parameter configuration UI of the Cangjie project are displayed in the editing area of VSCode at the same time, modifications to thecjpm.tomlfile are not synchronized to the UI.
For the build parameter cross-compile-configuration, you can click Add Configuration in cross-compile-configuration to add options.
Set key and compile-option, and click the Tick button or press Enter to synchronize with the cjpm.toml file. To delete a configuration, click the Cross button corresponding to the configuration.
If you click the Tick button or press Enter without setting the first field key in the added configuration, a message is displayed, indicating that the first field needs to be set. In this scenario, the submitted content is not synchronized to the cjpm.toml file. The configuration remains on the UI until the UI is refreshed. The content keeps consistent with that in the cjpm.toml file. package-configuration is similar to cross-compile-configuration. The following figure shows the scenario where the first field is empty in an added configuration of package-configuration.

The methods for adding and modifying the package-configuration parameter is the same as those for cross-compile-configuration. The output-type field includes the following drop-down list options: executable, static, dynamic, and null. The initial type of an added configuration field is null. You can select a value as required. If the type is null, the field is deleted after it is synchronized to the cjpm.toml file.
Note:
When you configure the
cjpm.tomlfile on the UI, only the equal mark (=) in the--cfgpath configured in thecustomized-optionparameter need to be escaped, and other characters do not need to be escaped. However, you need to add escape characters when directly configuring thecjpm.tomlfile. For example, when configuringcompile-optionfor p1 of thepackage-configurationfield, on the UI, you only need to add quotation marks to the value of--link-options, that is,--link-options="-rpath=xxx"; in the cjpm.toml file, you need to set the value to--link-options=\"-rpath=xxx\". If the--cfgpath configured for thecustomized-optionparameter on the UI contains an equal mark (=), on the UI, the equal mark (=) needs to be escaped, that is,--cfg="D:/projects/cang\=jie"; in the cjpm.toml file, you need to fill in--cfg=\"D:/projects/cang\\=jie\".
The methods for adding and modifying the customized-option parameter is the same as those for cross-compile-configuration.
Note:
Built-in conditions cannot be set for conditions of
customized-option(@When[os = = "Linux"] cannot be used as a condition ofcustomized-option, that is, "cfg1" : "--cfg ="os=Linux"" is not allowed). Only customized conditions can be added. For details, see Conditional Compilation in Cangjie > Language Guide.
Importing Third-Party Libraries
Import Method
Note:
Third-party libraries can be imported only to the main module of the currently opened Cangjie project. For other sub-modules, the third-party libraries can be opened as projects for use.
In the Cangjie project, you can import third-party libraries and perform configuration in the cjpm.toml file.
dependencies: specifies projects on which the current Cangjie module depends. It contains the configuration information of other modules required for the current build, including the version number and path. Both of the two options need to be configured. Otherwise, the execution fails and an error is reported. You are advised to use this method to import project dependencies.
dev-dependencies: has the same usage and format as the dependencies field. This field specifies the dependencies used only during development, not the dependencies required for building the main project, for example, dependencies used only during testing. If the developer is the library author, this field should be used for dependencies that are not required by downstream users of the library.
bin-dependencies: imported as dependencies unless there are special requirements. Currently, the Cangjie plug-in supports only local bin-dependencies configuration.
Currently, package of Cangjie module dependencies can be imported in two ways. The following describes how to import three packages of the pro0 and pro1 modules.
test
├── pro0
│ ├── libpro0_xoo.so
│ ├── xoo.cjo
│ ├── libpro0_yoo.so
│ └── yoo.cjo
├── pro1
│ ├── libpro1_zoo.so
│ └── zoo.cjo
├── src
│ └── main.cj
└── cjpm.toml
Method 1: Import through package-option.
[target]
[target.x86_64-w64-mingw32]
[target.x86_64-w64-mingw32.bin-dependencies]
[target.x86_64-w64-mingw32.bin-dependencies.package-option]
pro0_xoo = "./test/pro0/xoo.cjo"
pro0_yoo = "./test/pro0/yoo.cjo"
pro1_zoo = "./test/pro1/zoo.cjo"
This option uses the map structure, where the name pro0_xoo is used as the key and corresponds to libpro0_xoo.so; and the path of the frontend .cjo file is used as the value. .a and .so corresponding to the .cjo file need to be placed in the same path, and the corresponding .cjo module file and the module name source file need to be placed in the same folder which cannot contain any other files or folders.
Method 2: Import through path-option.
[target]
[target.x86_64-w64-mingw32]
[target.x86_64-w64-mingw32.bin-dependencies]
path-option = ["./test/pro0", "./test/pro1"]
This option is a string array structure where each element indicates the name of the path to be imported. cjpm automatically imports all Cangjie library packages meeting a specific rule in the path. The specific rule here is that the library name format is module name_package name. Packages whose library names do not meet the rule can be imported only through the package-option option.
If the same package is imported through package-option and path-option at the same time, the package-option field has higher priority.
The following figure shows the navigation bar view.

You can import the modules required by the project in the corresponding import mode subdirectories. On the navigation bar, click the brush icon to access the UI.

ffi: is an external C library on which the current Cangjie module depends. The information required for depending on the library is configured, including the name and path fields. CANGJIE LIBRARY in the view bar of the resource manager allows you to add such external libraries easily.
After the project is initialized, you can click the plus sign (+) next to the corresponding dependency type to add a third-party library.

You can click the minus sign (-) on a third-party library to delete the library.
You can also click the Edit button in the view bar to open the third-party library import UI to import or delete a third-party library.

The preceding delete and add operations are all synchronized to the cjpm.toml file of the project.
Import Constraints
- If dynamic link libraries (C library and Cangjie library) are required for a project, you need to set
LD_LIBRARY_PATHand runexport LD_LIBRARY_PATH=xxx:$LD_LIBRARY_PATH. - The modification in the
cjpm.tomlfile does not directly affect treeView or UI. You need to click treeView or UI for manual update. - If you add an external library to the library category in treeView and the library category directory is closed, you need to open the directory to view the added external library.
- Currently, the fields on the UI do not support the function of displaying content on hover.
- The UI is not an external library added by developers, and its path is the same as that in the
cjpm.tomlfile. Absolute paths are displayed for libraries and treeViews added by developers.
Debug Service
Function Description
The Cangjie programming language provides a visualized debug service for developers to debug Cangjie programs. This plug-in provides the following functions:
- Launch: starts the debugging process.
- Attach: attaches to a started process.
- Supports source code breakpoints, function breakpoints, data breakpoints, and assembly breakpoints.
- Supports single-step debugging in source code, run to cursor, step-in, step-out, continue, pause, restart, and stop debugging.
- Supports Cangjie-C interoperability debug, continue Cangjie code, and step in C code.
- Supports single-step, step-in, and step-out in assembly.
- Supports expression evaluation.
- Supports viewing and modifying variables.
- Supports viewing variables on the debugging console.
- Supports viewing output information of programs to be debugged.
- Supports reverse debugging.
- Supports Unittest running and debugging.
Notes
- If you use the VSCode debug service for the first time, see the VSCode Debug Service User Guide.
- Currently, the debug service can be installed and used in VSCode of the Windows and Linux versions.
- Restricted by the debugger, if a conditional breakpoint exists in the loop code, the PAUSE operation may cause subsequent debugging to fail.
- Modifying variables in the VARIABLES view does not trigger update of the variables that have dependencies.
- If the debug service depends on the liblldb file in the Cangjie SDK package, you need to configure the Cangjie SDK path in advance.
- The debugging plug-in client communicates with the server through Socket. The plug-in automatically searches for an available port from port 9995 and starts the Socket server on 127.0.0.1 to listen on this port.
Starting Debugging
Launch Mode
Cangjie Project Debugging
- If the
launch.jsonfile is not created, choose Run and Debug > Cangjie(cjdb) Debug to start debugging. - If the
launch.jsonfile is created, in thelaunch.jsonfile, choose Add Configuration > Cangjie Debug (CJNative): launch > Build And Debug Cangjie Project to add debugging configurations and select the added configurations to start debugging.
Single File Debugging
To debug a single file, right-click the Cangjie source file to be debugged and choose Cangjie: Build and Debug File from the shortcut menu. This operation generates the compilation configuration file task.json and compilation script, executes the script based on task.json configurations to compile a debuggable binary file, and then starts debugging.
Debugging a Manually Compiled Executable File
- Use the cjc compiler or cjpm to manually compile a debuggable binary file.
- Choose Run and Debug > Cangjie(cjdb) Debug > Cangjie (CJNative): launch > Choose Executable File Later to start debugging.
Debugging Macro-Expanded Code in Launch debugMacro Mode
Debug the code file (with the filename extension .marcocall) with the debug macro expanded. In this case, the original file corresponding to the macro cannot be debugged.
Debugging a Remote Process (from Linux to Linux)
During remote process debugging in launch mode, the debug service pushes the locally compiled binary file to the remote platform and then remotely debugs the binary file.
- Start lldb-server on the remote platform. You are advised to start the cjdb lldb-server in /cangjie/third_party/llvm/lldb/bin/lldb-server by running the command
/**/**/cangjie/third_party/llvm/lldb/bin/lldb-server p --listen "*:1234" --server. - Use the cjc compiler or cjpm to manually compile a debuggable binary file on the local host.
- Click Run and Debug to start debugging.
The following is a launch.json configuration example.
{
"name": "Cangjie Debug (cjdb): test",
"program": "/**/**/test",
"request": "launch",
"type": "cangjieDebug",
"externalConsole": false,
"remote": true,
"remoteCangjieSdkPath": "/**/**/cangjie",
"remoteFilePath": "/**/**/test",
"remoteAddress": "1.1.1.1:1234",
"remotePlatform": "remote-linux"
}
Configuration Attributes
| Attribute | Type | Description |
|---|---|---|
| program | string | Specifies the full path of the debugged process, for example, /home/cangjieProject/build/bin/main. The file is pushed to the remote platform. |
| remote | boolean | Starts the remote launch process. The value of remote is set to true. |
| remoteCangjieSdkPath | string | Specifies the path of the remote Cangjie SDK. |
| remoteFilePath | string | Specifies the full path for storing pushed files on the remote platform. Ensure that the path /home/test/ is valid and exists. main is the name of the file pushed to the remote platform. Example: /home/cangjieProject/build/bin/main. |
| remoteAddress | string | Specifies the IP address of the host where the debugged process is located and the listen port number of lldb-server, in the data format of ip:port. |
| remotePlatform | string | Specifies the remote platform. Only remote-linux is supported. |
| env | object | Sets the runtime environment variables for the program to be debugged. This configuration overwrites the system environment variables. To add configurations to the system configuration, append ${env:PATH} to the configuration item. For example: "PATH":"/home/user/bin: ${env:PATH}", "LD_LIBRARY_PATH":"/home/user/bin:${env:LD_LIBRARY_PATH}". |
Attach Mode
Debugging a Local Process
- In the
launch.jsonfile, choose Add Configuration > Cangjie Debug (CJNative) : attach to add debugging configurations, and select the added configurations to start debugging. - In the displayed dialog box, select the process to be debugged to start debugging.
Debugging a Remote Process
- Compile a debugable binary file on the local host and copy the file to the remote host.
- Start lldb-server on the remote host. You are advised to start cjdb lldb-server in /cangjie/third_party/llvm/lldb/bin/lldb-server by running the command
/**/**/cangjie/third_party/llvm/lldb/bin/lldb-server p --listen "*:1234" --server. - Start the binary file to be debugged on the remote host.
- Configure the
launch.jsonfile on the local host and start debugging.
launch.json configuration attributes:
{
"name": "Cangjie Debug (cjdb): test",
"processId": "8888",
"program": "/**/**/test",
"request": "attach",
"type": "cangjieDebug",
"remote": true,
"remoteAddress": "1.1.1.1:1234",
"remotePlatform": "remote-linux"
}
Configuration Attributes
| Attribute | Type | Description |
|---|---|---|
| processId | string | Specifies the PID of the process to be debugged. If the PID is configured, attach the PID first. If the PID is not configured, attach the program. |
| program | string | Specifies the full path of the debugged process, for example, /home/cangjieProject/build/bin/main. |
| remote | boolean | If configuration is to be attached to a local process, remote is set to false; if configuration is to be attached to a remote process, remote is set to true. |
| remoteAddress | string | Specifies the IP address of the host where the debugged process is located and listen port number of lldb-server for remote debugging, in the data format of ip:port. |
| remotePlatform | string | Specifies the remote platform for remote debugging. Only remote-linux is supported. |
Viewing Debugging Information
When a process is in the stopped state, you can view breakpoints, current threads, stack information, and variables on the left side of the VSCode UI. You can edit breakpoints and modify variables. You can also move the cursor over a variable name in the Editor window to view the variable value. You can view the output information of the program to be debugged in the TERMINAL window.

Expression Evaluation
- In the WATCH window, click Add or double-click in the blank area, and enter an expression.
- Enter an expression in the Debug Console window.
- In the Editor window, double-click a variable, right-click the variable, and choose Evaluate in Debug Console from the shortcut menu.
Program Control
-
Click the icons on the top debugging toolbar to control a program, including running in single step, stepping in, stepping out, continuing, pausing, restarting, or stopping the program.

-
Right-click at the cursor and choose Run to Cursor from the shortcut menu.

-
Right-click in the source code view and choose Open Disassembly View from the shortcut menu.

Debugging Console
Running cjdb Commands
Enter cjdb commands on the debugging console to debug a program. The command needs to start with -exec. The subcommand to be executed needs to be a correct cjdb command.
The following is an example of running the cjdb command n to perform single-step debugging:
-exec n

Viewing Variables
Enter a variable name on the debugging console to view the variable value.

Reverse Debugging
Note
- Reverse debugging is based on record replay. After the reverse debugging function is enabled, the debug service records all stop points (breakpoints and single steps) of forward debugging and debugging information such as threads, stacks, and variables at the stop points. In reverse debugging mode, you can view the debugging information of historical record points.
Configuration
Click the gear icon in the lower left corner, select Settings, enter cangjie in the search box, find Reverse Debug, and check Enable reverse debug to enable automatic recording of historical stop points of program debugging. In addition, you can configure the number of automatically recorded threads, number of stacks, variable scope, number of expansion layers of sub-variables of complex variables, and number of sub-variables. After the configuration is modified, restart the Cangjie debugging console.

Toolbar
Click the clock icon on the top debugging toolbar to enter the reverse debugging mode. Use the forward/reverse continue and forward/reverse single-step to control a program on the toolbar to view historical thread, stack, and variable information, as shown in the following figure.

Click the block icon on the top debugging toolbar to exit the reverse debugging mode. The debugging returns to the last stop point of the forward debugging, as shown in the following figure.

Reverse Breakpoint
Notes:
- The reverse breakpoint is a special source code log point. Forward debugging does not stop, and no log messages for logging reverse breakpoints are automatically generated during this process.
- During forward debugging, you can set a reverse breakpoint in advance. The debug service background records the debugging information of the reverse breakpoints of the process.
- In reverse debugging mode, a reverse breakpoint is used as a stop point (breakpoint type). You can view the debugging information such as thread stack variables at the breakpoint.
- In reverse debugging mode, reverse breakpoints cannot be set.
Reverse breakpoint setting mode:
-
Right-click in the Cangjie source file editor view and choose Cangjie: Add Reverse Breakpoint from the shortcut menu to set a reverse breakpoint for the line where the cursor is located.

-
Right-click the Cangjie source file and choose Cangjie: Add Auto Reverse Breakpoints from the shortcut menu. The plug-in analyzes the entry and exit positions of the functions in the file and automatically sets reverse breakpoints.

-
Right-click a folder and choose Cangjie: Add Auto Reverse Breakpoints from the shortcut menu. The plug-in analyzes the entry and exit positions of the functions in the Cangjie source file in the folder and automatically sets reverse breakpoints.

Timeline
Note:
The timeline displays all stop points (breakpoints and single steps) recorded in reverse debugging mode. You can drag the timeline to view historical stop points.
The entry of the timeline is in the lower right area of VSCode. You can right-click the tab line in the lower right area and choose Cangjie Debug Timeline from the shortcut menu to enable or disable the timeline, as shown in the following figure. You can also choose View > Open View to enable the timeline.

- There are left and right cursors on the main timeline. You can drag the left and right cursors to select a time area. After an area is selected, the cursor changes to a hand shape when it is placed above the selected area. In this case, you can drag the area leftward or rightward.
- Place the cursor on the main timeline. When the cursor changes to a cross, hold down the cursor and drag it forward or backward to set the area that the cursor is moved over to a new time area.
- You can hold down Ctrl and scroll the mouse wheel to zoom in or zoom out the selected area.
- Each timeline identifies a Cangjie thread or system thread.
When you click a record point on the timeline, the editor view is refreshed synchronously (locating the source code line), and the debugging information view is refreshed synchronously (displaying the thread, stack frame, and variables of the record point).
Running and Debugging unittest
Prerequisites
The unit test code of a module is in the following structure: The .cj file indicates the source code of a package, and the name of the corresponding unit test code file ends with _test.cj. For details about how to write the unit test code, see the standard library user manual.
├── src
│ ├── koo
│ │ ├── koo.cj
│ │ └── koo_test.cj
│ ├── zoo
│ │ ├── zoo.cj
│ │ └── zoo_test.cj
│ ├── main.cj
│ └── main_test.cj
└── cjpm.toml
How to Use
- Click the Run button on the
@Test/@TestCasedeclaration line to run the unit test class or unit test case. - Click the Debug button on the
@Test/@TestCasedeclaration line to debug the unit test class or unit test case.
DAP Communication Log
The debugging service client communicates with the server using the DAP protocol. Communication logs can be used to locate faults. The log path is /.cangjie/debug/logs/server.
You can click the gear icon in the lower left corner, choose Settings, enter cangjie in the search box, find Debug, and select Enable DAPCommunication Log to enable service communication log debugging.

Formatting
To format a Cangjie file, right-click the code editing area in VSCode and choose [Cangjie] Format from the shortcut menu or press Ctrl + Alt + F to run the formatting command, as shown in the following figure.

For the Cangjie project, you can select a file in the resource manager of VSCode or right-click a folder and choose [Cangjie] Format from the shortcut menu to format the selected file or folder, as shown in the following figure.

Coverage Statistics
The coverage statistics function is used to generate the coverage report of the Cangjie language program.
Note:
If the selected folder does not contain a Cangjie file, no coverage report is generated.
You can start coverage statistics in two ways.
-
Right-click the code editing area of VSCode and choose [Cangjie] Coverage from the shortcut menu, or press Ctrl + Alt + G to run the command for generating the coverage report of the current Cangjie file, as shown in the following figure.

-
In the resource manager of VSCode, select a file or right-click a folder and choose [Cangjie] Coverage from the shortcut menu to generate a coverage report for the selected file or folder, as shown in the following figure.

On the generated coverage report page, you can click the file name to view the coverage details.
Cangjie Command Line Tool User Guide
Cangjie provides a series of command line tools for developers. After the Cangjie tool chain is successfully installed, you can use these command line tools according to the user manual. For details about how to install the Cangjie tool chain, see Quick Start Guide.
Package Manager
Overview
Cangjie Package Manager (CJPM) is an official Cangjie package management tool. It is used to manage and maintain the module system of Cangjie projects, provide a simple and unified compilation entry, and support customized compilation commands.
Usage
You can run the cjpm -h command to view the main interface. The main interface consists of the following parts from top to bottom: current command description, usage example, available subcommands, available options, and more prompts.
Cangjie Package Manager
Usage:
cjpm [subcommand] [option]
Available subcommands:
init Init a new cangjie module
check Check the dependencies
update Update cjpm.lock
tree Display the package dependencies in the source code
build Compile the current module
run Compile and run an executable product
test Unittest a local package or module
clean Clean up the target directory
install Install a cangjie binary
uninstall Uninstall a cangjie binary
Available options:
-h, --help help for cjpm
-v, --version version for cjpm
Use "cjpm [subcommand] --help" for more information about a command.
A basic command is as follows:
cjpm build --help
cjpm is the name of the main program, build is the available subcommand, and --help is the available option. (Both long and short option formats are supported, and they have the same effect.)
The following result is displayed after successful execution:
Compile a local module and all of its dependencies.
Usage:
cjpm build [option]
Available options:
-h, --help help for build
-i, --incremental enable incremental compilation
-j, --jobs <N> the number of jobs to spawn in parallel during the build process
-V, --verbose enable verbose
-g enable compile debug version target
--coverage enable coverage
--cfg enable the customized option 'cfg'
-m, --member <value> specify a member module of the workspace
--target <value> generate code for the given target platform
--target-dir <value> specify target directory
-o, --output <value> specify product name when compiling an executable file
-l, --lint enable cjlint code check
--mock enable support of mocking classes in tests
--skip-script disable script 'build.cj'.
Commands
init
The init command is used to initialize a new Cangjie module or workspace. During module initialization, the cjpm.toml file is created in the current folder by default, and the src source code folder is created. If the module product is executable, the default main.cj file is generated in the src directory, and hello world is printed after compilation. During workspace initialization, only the cjpm.toml file is created. By default, the existing Cangjie modules in the path are scanned and added to the members field. If the cjpm.toml file or the main.cj file in the source folder already exists, the corresponding file creation step is skipped.
init has the following configurable options:
--name <value>: specifies therootpackage name for a new module. By default, the name of the upper-level folder is used.--path <value>: specifies the path of a new module. By default, the current folder is used.--type=<executable|static|dynamic>: specifies the product type of a new module. The default value isexecutable.--workspace: creates a workspace configuration file. When this option is specified, other options are ignored automatically.
Example:
Input: cjpm init
Output: cjpm init success
Input: cjpm init --name demo --path project
Output: cjpm init success
Input: cjpm init --type=static
Output: cjpm init success
check
The check command is used to check the dependencies required in a project. Upon successful execution, it will print the valid package compilation order.
check has the following configurable options:
-m, --member <value>: specifies a single module as the check entry in the workspace only.--no-tests: does not display test-related dependencies after this option is configured.--skip-script: skips the compilation and execution of the build script after this option is configured.
Example:
Input: cjpm check
Output:
The valid serial compilation order is:
b.pkgA -> b
cjpm check success
Input: cjpm check
Output:
Error: cyclic dependency
b.B -> c.C
c.C -> d.D
d.D -> b.B
Output description: b.B indicates a subpackage in the module whose root package is b.
Input: cjpm check
Output:
Error: can not find the following dependencies
pro1.xoo
pro1.yoo
pro2.zoo
update
update is used to update the content of the cjpm.toml file to the cjpm.lock file. If the cjpm.lock file does not exist, this file is generated. The cjpm.lock file records metadata such as the versions of git dependencies, which is used for the next build.
update has the following configurable options:
--skip-script: skips the compilation and execution of the build script after this option is configured.
Input: cjpm update
Output: cjpm update success
tree
The tree command is used to visualize the package dependency relationships in the Cangjie source code.
tree has the following configurable options:
-p, --package <value>: specifies a package as the root node to display its subdependency packages. The value is the package name.--invert <value>: specifies a package as the root node and reverses the dependency tree to display the packages that depend on it. The value is the package name.--depth <N>: specifies the maximum depth of the dependency tree. The value is a non-negative integer. If this option is specified, all packages are used as the root nodes by default.Nindicates the maximum depth for each subnode in the dependency tree.--target <value>: analyzes the dependency items of the specified target platform and displays the dependency relationships.--no-tests: excludes dependencies listed in thetest-dependenciesfield.-V, --verbose: displays detailed information about each package node, including the package name, version number, and package path.--skip-script: skips the compilation and execution of the build script after this option is configured.
Input: cjpm tree
Output:
|-- a
└── a.aoo
└── a.coo
└── a.boo
└── a.coo
|-- a.doo
└── a.coo
|-- a.eoo
cjpm tree success
Input: cjpm tree --depth 2 -p a
Output:
|-- a
└── a.aoo
└── a.coo
└── a.boo
└── a.coo
cjpm tree success
Input: cjpm tree --depth 0
Output:
|-- a
|-- a.eoo
|-- a.aoo
|-- a.boo
|-- a.doo
|-- a.coo
cjpm tree success
Input: cjpm tree --invert a.coo --verbose
Output:
|-- a.coo 1.2.0 (.../src/coo)
└── a.aoo 1.1.0 (.../src/aoo)
└── a 1.0.0 (.../src)
└── a.boo 1.1.0 (.../src/boo)
└── a 1.0.0 (.../src)
└── a.doo 1.3.0 (.../src/doo)
cjpm tree success
build
The build command is used to build the current Cangjie project. Before running this command, the system checks the dependencies. After the check is passed, the cjc command is called to build the project.
build has the following configurable options:
-i, --incremental: specifies incremental compilation. By default, full compilation is performed.-j, --jobs <N>: specifies the maximum number of parallel compilation jobs. The final maximum number is the smaller value betweenNand2 x Number of CPU cores.-V, --verbose: displays compilation logs.-g: generates the output product of thedebugversion.--mock: enables a class in the build version to be used formocktesting.--coverage: generates coverage information. By default, the coverage function is disabled.--cfg: transparently transmits the customizedcfgoption incjpm.tomlafter this option is specified.-m, --member <value>: specifies a single module as the compilation entry in the workspace only.--target-dir <value>: specifies the path for storing output products.-o, --output <value>: specifies the name of the executable file to be output. The default name ismain(main.exeforWindows).--target <value>: enables cross-compiling the code to the target platform. For details about the configuration ofcjpm.toml, see target.-l, --lint: calls the Cangjie language static check tool to check code during compilation.--skip-script: skips the compilation and execution of the build script after this option is configured.
Note:
- The
-i, --incrementaloption only enables incremental compilation at thecjpmpackage level. Developers can transparently transmit the--incremental-compileoption through thecompile-optionfield in the configuration file to enable the function-level incremental functionality provided by thecjccompiler.- Currently,
-i, --incrementalsupports only source code-based incremental analysis. If there are changes to the imported library contents, developers will need to perform a full build again. The code static check capability is being built. The options-l and --lintare unavailable currently. Otherwise, the compilation fails because the related tool does not exist.
By default, intermediate files generated during compilation are stored in the target folder, and executable files are stored in the target/release/bin or target/debug/bin folder, depending on the compilation mode. To provide reproducible builds, this command will create the cjpm.lock file which contains the exact versions of all transitive dependencies, ensuring that they are used for all subsequent builds. To update this file, use the update command. If it is necessary to guarantee reproducible builds for all project participants, this file should be committed to the version control system.
Example:
Input: cjpm build -V
Output:
compile package module1.package1: cjc --import-path "target/release" --output-dir "target/release/module1" -p "src/package1" --output-type=staticlib -o libmodule1.package1.a
compile package module1: cjc --import-path "target/release" --output-dir "target/release/bin" -p "src" --output-type=exe -o main
cjpm build success
Input: cjpm build
Output: cjpm build success
Note:
According to the specifications of Cangjie package management, only valid source code packages that meet the requirements can be correctly included in the compilation scope. If a
no '.cj' file-related alarm is generated during compilation, the source code file may not be compiled because the corresponding package does not comply with the specifications. In this case, modify the code directory structure by referring to Specifications of Cangjie Package Management.
run
The run command is used to run the binary product built by the current project.
run has the following configurable options:
--name <value>: specifies the name of the binary file to run. If it is not specified, the default valuemainis used. The binary output in the workspace is stored in thetarget/release/bindirectory by default.--build-args <value>: specifies the argument that controls thecjpmcompilation process.--skip-build: skips the compilation process and runs directly.--run-args <value>: transparently transmits arguments to the binary product being run.--target-dir <value>: specifies the path for storing products being run.-g: runs the product of thedebugversion.-V, --verbose: displays run logs.--skip-script: skips the compilation and execution of the build script after this option is configured.
Example:
Input: cjpm run
Output: cjpm run success
Input: cjpm run -g // The cjpm build -i -g command is executed by default.
Output: cjpm run success
Input: cjpm run --build-args="-s -j16" --run-args="a b c" -V
Output: cjpm run success
test
test is used to compile and run the unit test cases of the Cangjie file. After the test cases are executed, the test results are printed. The compilation products are stored in the target/release/unittest_bin folder by default. For details about how to write the unit test case code, see the std.unittest library description in the Cangjie Programming Language Library API.
This command can be used to specify the path of a single package to be tested. Multiple single packages can be specified, for example, cjpm test path1 path2. If no path is specified, the module-level unit test is performed by default. The prerequisite for executing test is that the build compilation of the current project is successful.
The structure of unit test code in a module is as follows, where xxx.cj stores the source code of the package and xxx_test.cj stores the unit test code:
│ └── src
│ ├── koo
│ │ ├── koo.cj
│ │ └── koo_test.cj
│ ├── main.cj
│ └── main_test.cj
│ ├── cjpm.toml
│ └── pro0
│ ├── cjpm.toml
│ └── zoo
│ ├── zoo.cj
│ └── zoo_test.cj
Multi-module test scenario
Input: cjpm test
Output:
--------------------------------------------------------------------------------------------------
TP: test, time elapsed: 177921 ns, RESULT:
TCS: TestM, time elapsed: 177921 ns, RESULT:
[ PASSED ] CASE: sayhi (177921 ns)
Summary: TOTAL: 1
PASSED: 1, SKIPPED: 0, ERROR: 0
FAILED: 0
--------------------------------------------------------------------------------------------------
TP: test.koo, time elapsed: 134904 ns, RESULT:
TCS: TestK, time elapsed: 134904 ns, RESULT:
[ PASSED ] CASE: sayhi (134904 ns)
Summary: TOTAL: 1
PASSED: 1, SKIPPED: 0, ERROR: 0
FAILED: 0
--------------------------------------------------------------------------------------------------
TP: pro0.zoo, time elapsed: 132013 ns, RESULT:
TCS: TestZ, time elapsed: 132013 ns, RESULT:
[ PASSED ] CASE: sayhi (132013 ns)
Summary: TOTAL: 1
PASSED: 1, SKIPPED: 0, ERROR: 0
FAILED: 0
--------------------------------------------------------------------------------------------------
Project tests finished, time elapsed: 444838 ns, RESULT:
TP: pro0.*, time elapsed: 132013 ns, RESULT:
PASSED:
TP: pro0.zoo, time elapsed: 132013 ns
TP: test.*, time elapsed: 312825 ns, RESULT:
PASSED:
TP: test.koo, time elapsed: 312825 ns
TP: test, time elapsed: 312825 ns
Summary: TOTAL: 3
PASSED: 3, SKIPPED: 0, ERROR: 0
FAILED: 0
--------------------------------------------------------------------------------------------------
cjpm test success
Single-package test scenario
Input: cjpm test src/koo
Output:
--------------------------------------------------------------------------------------------------
TP: test.koo, time elapsed: 160133 ns, RESULT:
TCS: TestK, time elapsed: 160133 ns, RESULT:
[ PASSED ] CASE: sayhi (160133 ns)
Summary: TOTAL: 1
PASSED: 1, SKIPPED: 0, ERROR: 0
FAILED: 0
--------------------------------------------------------------------------------------------------
Project tests finished, time elapsed: 160133 ns, RESULT:
TP: test.*, time elapsed: 160133 ns, RESULT:
PASSED:
TP: test.koo, time elapsed: 160133 ns
Summary: TOTAL: 1
PASSED: 1, SKIPPED: 0, ERROR: 0
FAILED: 0
--------------------------------------------------------------------------------------------------
cjpm test success
Multi-package test scenario
Input: cjpm test src/koo src
Output:
--------------------------------------------------------------------------------------------------
TP: test.koo, time elapsed: 168204 ns, RESULT:
TCS: TestK, time elapsed: 168204 ns, RESULT:
[ PASSED ] CASE: sayhi (168204 ns)
Summary: TOTAL: 1
PASSED: 1, SKIPPED: 0, ERROR: 0
FAILED: 0
--------------------------------------------------------------------------------------------------
TP: test, time elapsed: 171541 ns, RESULT:
TCS: TestM, time elapsed: 171541 ns, RESULT:
[ PASSED ] CASE: sayhi (171541 ns)
Summary: TOTAL: 1
PASSED: 1, SKIPPED: 0, ERROR: 0
FAILED: 0
--------------------------------------------------------------------------------------------------
Project tests finished, time elapsed: 339745 ns, RESULT:
TP: test.*, time elapsed: 339745 ns, RESULT:
PASSED:
TP: test.koo, time elapsed: 339745 ns
TP: test, time elapsed: 339745 ns
Summary: TOTAL: 2
PASSED: 2, SKIPPED: 0, ERROR: 0
FAILED: 0
--------------------------------------------------------------------------------------------------
cjpm test success
test has the following configurable options:
--no-run: compiles only unit test products.--skip-build: executes only unit test products.-j, --jobs <N>: specifies the maximum number of parallel compilation jobs. The final maximum number is the smaller value betweenNand2 x Number of CPU cores.-V, --verbose: enables the generation of unit test logs.-g: generates the unit test product of thedebugversion. The product is stored in thetarget/debug/unittest_binfolder.--bench: runs only the test cases marked with the@benchmacro.--target-dir <value>: specifies the path for storing single-side products.--coverage: works with thecjcovcommand to generate the coverage report of the unit test. Whencjpm test --coverageis used to collect coverage statistics,mainin the source code is not executed as the program entry. Therefore,mainis displayed as uncovered. It is recommended that you do not manually write redundantmainafter usingcjpm test.--cfg: transparently transmits the customizedcfgoption incjpm.tomlafter this option is specified.-m, --member <value>: tests a single module in the workspace only.--target <value>: enables cross-compiling the unit test results of the target platform. For details about the configuration ofcjpm.toml, see target.--filter <value>: filters the subset of the test. The format ofvalueis as follows:--filter=*: matches all test classes.--filter=*.*: matches all test cases of all test classes (same result as*).--filter=*.*Test,*.*case*: matches all test cases ending withTestor containingcasein their names in all test classes.--filter=MyTest*.*Test,*.*case*,-*.*myTest: matches all test cases ending withTestor containingcasein their names in test classes starting withMyTest, but excludes test cases containingmyTest.
--random-seed <N>: specifies the value of a random seed.--no-color: disables colored output on the console.--timeout-each <value>: specifies the default timeout interval for each test case. The format of value is%d[millis|s|m|h].--parallel: specifies how test cases should be executed in parallel. The format ofvalueis as follows:<BOOL>:trueorfalse. Iftrueis specified, test classes can be run in parallel, and the number of parallel processes is controlled by the number of CPU cores on the OS.nCores: specifies that the number of parallel test processes must be equal to the number of available CPU cores.NUMBER: specifies the number of parallel test processes. The value must be a positive integer.NUMBERnCores: specifies the number of parallel test processes as a multiple of the number of available CPU cores. The value must be a positive number (floating-point number or integer).
--report-path <value>: specifies the path for generating the test report.--report-format <value>: specifies the report output format. Currently, the unit test report supports only thexmlformat (case-insensitive). If other values are used, an exception is thrown.The performance test report supports only thecsvandcsv-rawformats.--skip-script: skips the compilation and execution of the build script after this option is configured.
The following are examples of running cjpm test with different options:
Input:
cjpm test src --coverage
cjcov --root=./ --html-details -o html_output
Output: cjpm test success
Coverage generation: An HTML file is generated in the html_output directory. The name of the coverage report file is fixed to index.html.
Input: cjpm test --bench
Output: cjpm test success
Input: cjpm test src --bench
Output: cjpm test success
Input: cjpm test src --filter=*
Output: cjpm test success
Input: cjpm test src --report-path=reports --report-format=xml
Output: cjpm test success
Note:
cjpm testautomatically builds all packages withmocksupport. Therefore, you can performmocktests on customized classes or classes that depend on the source module. To mock classes from binary dependencies, you should build them withmocksupport usingcjpm build --mock. Note thatcjpm testwith the--benchoption does not include fullmocksupport to avoid any overhead introduced bymockhandling in the compiler during benchmark tests. When the--benchoption is used, the compiler will not throw an error ifmockis used, allowing regular tests and benchmark tests to be compiled together. However, it is important to avoid running benchmark tests that usemock, as this will result in a runtime exception.
install
The install command is used to install a Cangjie project. Before this command is executed, the project is first compiled, and then the compiled product is installed to the specified path. The installed product is named after the Cangjie project (with the .exe suffix on Windows). The project product installed via install must be of the executable type.
install has the following configurable options:
-V, --verbose: displays installation logs.-g: generates the installation product of thedebugversion.--path <value>: specifies the local path where the project is installed. The default value is the project in the current path.--root <value>: specifies the installation path of the executable file. If not configured, the default value is$HOME/.cjpmonLinux/macOSor%USERPROFILE%/.cjpmonWindows. If configured, the executable will be installed at the path specified byvalue.-m, --member <value>: specifies a single module as the compilation entry to install a single module in the workspace only.--target-dir <value>: specifies the path for storing compilation products.--name <value>: specifies the name of the product to be installed.--git <value>: specifiesurlof thegitproject to be installed.--branch <value>: specifies the branch of thegitproject to be installed.--tag <value>: specifiestagof thegitproject to be installed.--commit <value>: specifiescommit IDof thegitproject to be installed.--list: prints the list of installed products.--skip-build: skips the compilation phase and directly installs the product. It takes effect only in the local installation scenario when the project compilation is complete.-j, --jobs <N>: specifies the maximum number of parallel compilation jobs. The final maximum number is the smaller value betweenNand2 x Number of CPU cores.--cfg: transparently transmits the customizedcfgoption incjpm.tomlafter this option is specified.--skip-script: skips the compilation and execution of the build script of the module to be installed after this option is configured.
Note the following when using the install command:
- There are two installation methods: installing a local project (using
--pathto configure the project path), and installing agitproject (using--gitto configure the projecturl). You can only configure one method at a time, otherwise,installwill throw an error. If neither is configured, the local project in the current directory is installed by default. - Incremental compilation is enabled by default when
installis used to compile a project. - The
git-related configurations (--branch,--tag, and--commit) are effective only if--gitis specified. Otherwise, they will be ignored. When multiplegit-related configurations are specified, only the highest-priority configuration takes effect. The priority is--commit>--branch>--tag. - If an executable file with the same name already exists, the original file will be replaced.
- Assume that the installation path is
root. (rootis the configured installation path. Ifrootis not configured, the default path is used.) The executable file is installed inroot/bin. - If the project has dynamic library dependencies, the libraries required by the executable program will be installed in
root/libsand organized into directories based on the program name. Developers must ensure these directories are included in the relevant environment paths (LD_LIBRARY_PATHonLinux/macOSorPATHonWindows) to use the libraries. - The default installation path is
$HOME/.cjpmonLinux/macOSand%USERPROFILE%/.cjpmonWindows. This path is added toPATHinenvsetup. - After a
gitis installed, the corresponding compiled product directory will be cleared. - If the project contains only one executable file product, specifying
--namewill rename it before installation. If there are multiple executable file products, specifying--namewill only install the product with the given name. - When
--listis configured,installwill print the list of installed products. In this case, all configuration options except--rootare ignored. After--rootis configured,--listwill print the list of installed products in the configured path. Otherwise, the list in the default path is printed.
Example:
cjpm install --path path/to/project # Install from the local path path/to/project.
cjpm install --git url # Install from the corresponding git URL.
uninstall
The uninstall command is used to uninstall a Cangjie project and delete the corresponding executable files and dependency files.
To uninstall a product, you need to specify the name parameter for the product. If multiple names are provided, the uninstall command will remove them one by one. You can use --root <value> to specify the path of the executable file to be uninstalled. If not configured, the default value is $HOME/.cjpm on Linux/macOS or %USERPROFILE%/.cjpm on Windows. If configured, the products installed in value/bin and the dependencies installed in value/libs are uninstalled.
clean
The clean command is used to clean temporary products (the target folder) generated during the build process. This command can use the short option -g to specify that only the products of the debug version are cleaned. This command can use the long option --target-dir <value> to specify the path for storing the product to be cleaned. You need to ensure the security of cleaning the directory. If the cjpm build --coverage or cjpm test --coverage function is used, the cov_output folder and the *.gcno and *.gcda files in the current directory are cleaned. In addition, this command can skip the compilation and execution of the build script through the --skip-script configuration option.
The clean command has multiple configurable options:
-gis used to specify cleaning only thedebugversion artifacts.--target-dir <value>is used to specify the path where the artifacts to be cleaned are stored. Developers need to ensure the safety of cleaning this directory themselves.--skip-scriptwhen configured, will skip the compilation and execution of the build scripts for the modules to be cleaned.
Example:
Input: cjpm clean
Output: cjpm clean success
Input: cjpm clean --target-dir temp
Output: cjpm clean success
Note:
On
Windows, cleaning the executable file or parent directory of a subprocess immediately after the subprocess is executed may fail. If this problem occurs, you can try thecleancommand again after a short delay.
Description of Module Configuration Files
The module configuration file cjpm.toml is used to configure basic information, dependencies, compilation options, and other related content. The cjpm primarily relies on this file for parsing and execution. The module name can be renamed in cjpm.toml, but the package name cannot be renamed in cjpm.toml.
The code in the configuration file is as follows:
[package] # Single-module configuration field, which cannot coexist with the workspace field.
cjc-version = "0.53.1" # Minimum required version of 'cjc', which is required.
name = "demo" # Module name and root package name, which are required.
description = "nothing here" # Description, which is optional.
version = "1.0.0" # Module version information, which is required.
compile-option = "" # Additional compilation command option, which is optional.
link-option = "" # Transparent transmission option of the linker, which is optional and can transparently transmit secure compilation commands.
output-type = "executable" # Type of the compilation output product, which is required.
src-dir = ""# Path for storing the source code, which is optional.
target-dir = ""# Path for storing the product, which is optional.
package-configuration = {} # Single-package configuration option, which is optional.
[workspace] # Workspace management field, which cannot coexist with the package field.
members = [] # Workspace member module list, which is required.
build-members = [] # List of compiled modules in the workspace, which is optional and must be a subset of the member module list.
test-members = [] # List of test modules in the workspace, which is optional and must be a subset of the compiled module list.
compile-option = "" # Additional compilation command option applied to all workspace member modules, which is optional.
link-option = "" # Transparent transmission option of the linker applied to all workspace member modules, which is optional.
target-dir = ""# Path for storing the product, which is optional.
[dependencies] # Configuration options of source code dependency.
coo = { git = "xxx",branch = "dev" , version = "1.0.0"} # Import the git dependency. The version field can be left empty.
doo = { path = "./pro1" ,version = "1.0.0"} # Import the source code dependency. The version field can be left empty.
[test-dependencies] # Dependency configuration options in the test phase. The format is the same as that of dependencies.
[script-dependencies] # Dependency configuration options of the build script. The format is the same as that of dependencies.
[ffi.c] # Imports `c` library dependencies.
clib1.path = "xxx"
[profile] # Command profile configuration item.
build = {}
test = {}
customized-option = {}
[target.x86_64-unknown-linux-gnu] # Backend-platform isolation configuration item.
compile-option = "value1" # Additional compilation command option, applicable to the compilation process of a specific target and the compilation process with the target specified as the target cross-compilation platform, which is optional.
link-option = "value2" # Linker transparent transmission option, applicable to the compilation process of a specific target and the compilation process with the target specified as the target cross-compilation platform, which is optional.
[target.x86_64-w64-mingw32.dependencies] # Source code dependency configuration item for the corresponding target, which is optional.
[target.x86_64-w64-mingw32.test-dependencies] # Test-phase dependency configuration item for the corresponding target, which is optional.
[target.x86_64-unknown-linux-gnu.bin-dependencies] # Cangjie binary library dependencies, applicable to the compilation process of a specific target and the compilation process with the target specified as the target cross-compilation platform, which is optional.
path-option = ["./test/pro0", "./test/pro1"]
[target.x86_64-unknown-linux-gnu.bin-dependencies.package-option]
"pro0.xoo" = "./test/pro0/pro0.xoo.cjo"
"pro0.yoo" = "./test/pro0/pro0.yoo.cjo"
"pro1.zoo" = "./test/pro1/pro1.zoo.cjo"
If the preceding fields are not used in cjpm.toml, they are left blank by default. (For the path, the default value is the path of the configuration file.)
"cjc-version"
The earliest version of the Cangjie compiler must be compatible with the current environment version. A valid Cangjie version number consists of three numeric segments, separated by dots (.). Each segment is a natural number and does not contain unnecessary leading zeros. Example:
0.53.1is a valid version number.0.053.1is not a valid version number;053contains an unnecessary0.0.2e.1is not a valid version number, and2eis not a natural number.
"name"
Name of the current Cangjie module, which is also the name of the root package of the module.
A valid Cangjie module name must be a valid identifier. An identifier can contain letters, digits, and underscores, and must start with a letter, for example, cjDemo or cj_demo_1.
Note:
Currently, Cangjie module names cannot be Unicode characters. A Cangjie module name needs to be a valid identifier that contains only ASCII characters.
"description"
Description of the current Cangjie module, which has no format restriction.
"version"
Version number of the current Cangjie module, which is managed by the module owner and used for module validation. The format of the module version number is the same as that of cjc-version.
"compile-option"
Extra compilation options passed to cjc. When multiple modules are compiled, compile-option set for each module takes effect for all packages in the module.
Example:
compile-option = "-O1 -V"
The command entered here will be inserted into the compilation command when build is executed. Multiple commands can be separated by spaces. For details about the available commands, see "Compilation Options" in Cangjie Programming Language Developer Guide.
"link-option"
Compilation option of the linker, which can transparently transmit secure compilation commands as follows:
link-option = "-z noexecstack -z relro -z now --strip-all"
Note:
The commands configured in
link-optionare automatically transparently transmitted to the packages corresponding to the dynamic libraries and executable products during compilation.
"output-type"
Type of the compiled output product, which can be either an executable program or a library. The following table lists the related input. If you want this field to be automatically filled with static when cjpm.toml is generated, run the cjpm init --type=static --name=modName command. If the type is not specified, the executable type is generated by default. This field can be set to executable only for the main module.
| Input | Description |
|---|---|
| "executable" | Executable program |
| "static" | Static library |
| "dynamic" | Dynamic library |
| Others | Error information |
"src-dir"
This field can be used to specify the path for storing the source code. If this field is not specified, the src folder is used by default.
"target-dir"
This field specifies the path for storing compilation products. If this field is not specified, the target folder is used by default. If a folder is specified in this field, the folder will be deleted when cjpm clean is executed. You need to ensure the security of cleaning the folder.
Note:
If the
--target-diroption is specified during compilation, it has a higher priority.
target-dir = "temp"
"package-configuration"
Single-package configurable options of each module. This is a map structure where the package name is the key, and the configuration information of a single package is the value. The configurable information includes the output type and condition option. These options can be configured as required. For example, the output type of the demo.aoo package in the demo module is specified as the dynamic library type, and the -g command is transparently transmitted to the demo.aoo package during compilation.
[package.package-configuration."demo.aoo"]
output-type = "dynamic"
compile-option = "-g"
If compatible compilation options are configured in different fields, the priority for generating commands is as follows:
[package]
compile-option = "-O1"
[package.package-configuration.demo]
compile-option = "-O2"
# The profile field is described below:
[profile.customized-option]
cfg1 = "-O0"
Input: cjpm build --cfg1 -V
Output: cjc --import-path build -O0 -O1 -O2 ...
By configuring this field, multiple binary products can be generated at the same time, and the -o, --output <value> option becomes invalid. The following is an example:
Example of the source code structure (the module name is demo):
`-- src
|-- aoo
| `-- aoo.cj
|-- boo
| `-- boo.cj
|-- coo
| `-- coo.cj
`-- main.cj
Configuration example:
[package.package-configuration."demo.aoo"]
output-type = "executable"
[package.package-configuration."demo.boo"]
output-type = "executable"
Example of multiple binary products:
❯ cjpm build
cjpm build success
❯ tree target/release/bin
target/release/bin
|-- demo.aoo
|-- demo.boo
`-- demo
"workspace"
This field can be used to manage multiple modules as a workspace. The following configuration options are supported:
members = ["aoo", "path/to/boo"]: lists the local source code modules contained in the workspace. Both absolute and relative paths are supported. The member of this field must be a module and cannot be another workspace.build-members = []: specifies a module to be compiled. If it is not specified, all modules in the workspace are compiled by default. The members of this field must be contained in themembersfield.test-members = []: specifies a module to be tested. If it is not specified, all modules in the workspace are tested by default. The members of this field must be contained in thebuild-membersfield.compile-option = "": specifies a public compilation option of the workspace, which is optional.link-option = "": specifies a public link option of the workspace, which is optional.target-dir = "": specifies a path for storing workspace products, which is optional. The default value istarget.
Public configuration options in the workspace take effect for all member modules. For example, if the source code dependency of [dependencies] xoo = { path = "path_xoo"} is configured, all member modules can directly use the xoo module, and you do not need to configure the source code dependency in cjpm.toml of each submodule.
Note:
The
packagefield is used to configure the general information of the module. Thepackagefield and theworkspacefield cannot be in the samecjpm.tomlfield. All fields except thepackagefield can be used in the workspace.
Example of a workspace directory:
root_path
│ └─ aoo
│ ├─ src
│ └─ cjpm.toml
│ └─ boo
│ ├─ src
│ └─ cjpm.toml
│ └─ coo
│ ├─ src
│ └─ cjpm.toml
└─ cjpm.toml
Example of the configuration file of a workspace:
[workspace]
members = ["aoo", "boo", "coo"]
build-members = ["aoo", "boo"]
test-members = ["aoo"]
compile-option = "-Woff all"
[dependencies]
xoo = { path = "path_xoo" }
[ffi.c]
abc = { path = "libs" }
"dependencies"
This field is used to import other dependent Cangjie modules through source code. It contains information about other modules required for the current build. Currently, this field supports local path dependency, and remote git dependency.
To specify a local dependency, use the path field, and it must contain a valid local path. For example, the code structures of the pro0 and pro1 submodules and the main module are as follows:
|-- pro0
| |-- cjpm.toml
| `-- src
| `-- zoo
| `-- zoo.cj
|-- pro1
| |-- cjpm.toml
| `-- src
| |-- xoo
| | `-- xoo.cj
| `-- yoo
| `-- yoo.cj
|-- cjpm.toml
`-- src
|-- aoo
| `-- aoo.cj
|-- boo
| `-- boo.cj
`-- main.cj
After the following configuration is performed in cjpm.toml of the main module, the pro0 and pro1 modules can be used in the source code.
[dependencies]
pro0 = { path = "./pro0" }
pro1 = { path = "./pro1" }
To specify a remote git dependency, use the git field, and it must contain a valid URL in any format supported by git. To configure the git dependency, you can configure a maximum of one branch, tag, and commitId fields. These fields allow you to select a specific branch, tag, or commit hash. If multiple such fields are configured, only the configuration with the highest priority takes effect. The priority sequence is commitId > branch > tag. In addition, there is an optional version field, which is used to check whether the dependency has the correct version and whether there is no unexpected update. For example, after the following configuration, you can use the pro0 and pro1 modules of a specific git repository address in the source code:
[dependencies]
pro0 = { git = "git://github.com/org/pro0.git", tag = "v1.0.0"}
pro1 = { git = "https://gitee.com/anotherorg/pro1", branch = "dev"}
In this case, cjpm downloads the latest version of the corresponding repository and saves the current commit-hash in the cjpm.lock file. All subsequent cjpm calls will use the saved version until cjpm update is executed.
Generally, authentication is required to access the git repository. cjpm does not require credentials to be provided. Therefore, the existing git authentication support should be used. If the protocol used for git is https, you need to use an existing git credential helper. On Windows, you can install the credential helper when installing git. This helper is used by default. On Linux, refer to the git-config configuration description for details on setting up a credential helper. If the protocol is ssh or git, key-based authentication should be used. If the key is protected by a passphrase, you need to ensure that ssh-agent is running and add the key using ssh-add before using cjpm.
The dependencies field can use output-type to specify the compilation product type. The specified type can be different from the compilation product type on which the source code depends and can only be static or dynamic, as shown in the following:
[dependencies]
pro0 = { path = "./pro0", output-type = "static" }
pro1 = { git = "https://gitee.com/anotherorg/pro1", output-type = "dynamic" }
After the preceding configuration is complete, the output-type configuration in cjpm.toml of pro0 and pro1 is ignored, and the products of the two modules are compiled into the static and dynamic types, respectively.
"test-dependencies"
The format is the same as that of the dependencies field. It is used to specify dependencies that are used only during testing, not those required to build the main project. Module developers should use this field for dependencies that downstream users of this module do not need to be aware of.
The dependencies in test-dependencies can be used only for test files whose names are in the xxx_test.cj format. These dependencies will not be compiled during compilation. The configuration format of test-dependencies in cjpm.toml is the same as that of dependencies.
"script-dependencies"
The format is the same as that of the dependencies field. It is used to specify the dependencies that are used only in the build script, not those required to build the main project. For details about the functions related to build scripts, see Build Script.
"ffi.c"
Configuration of the c library on which the Cangjie module depends. This field configures the information required for dependency on the library, including the library name and path.
Developers need to compile a dynamic library or static library and place it in the path. For details, see the following example.
Instructions for calling an external c dynamic library in Cangjie:
- Run the
clang -shared -fPIC hello.c -o libhello.socommand in the file path to compile the correspondinghello.cfile into the.solibrary. - Modify the
cjpm.tomlfile of the project and configure theffi.cfield, as shown in the example below../src/is the relative path to the compiledlibhello.sofrom the current directory, andhellois the library name. - Run
cjpm buildto successfully compile the project.
[ffi.c]
hello = { path = "./src/" }
"profile"
profile is a configuration option used to control the default configuration options of a specific command during its execution. Currently, the following scenarios are supported: build, test, run, and customized-option.
"profile.build"
[profile.build]
lto = "full" # Specifies whether to enable the link time optimization (LTO) compilation mode. Only the Linux platform supports this function.
incremental = true # Specifies whether to enable incremental compilation by default.
These are control options of the compilation process. All fields are optional, and if not configured, they will not take effect. Only the profile.build option of the top-level module takes effect.
The value of lto can be full or thin, which corresponds to the two compilation modes supported by LTO. Full LTO merges all compilation modules and performs global optimization. This mode can maximize the optimization potential and requires a longer compilation time. Thin LTO uses parallel optimization on multiple modules and supports incremental compilation during linking by default. The compilation time of thin LTO is shorter than that of full LTO. However, thin LTO loses more global information, so the optimization effect is not as good as that of full LTO.
"profile.test"
[profile.test] # Example
noColor = true
timeout-each = "4m"
randomSeed = 10
bench = true
reportPath = "reports"
reportFormat = "xml"
[profile.test.compilation-options]
verbose = true
no-run = false
lto = "thin"
mock = "on"
[profile.test.env]
MY_ENV = { value = "abc" }
cjHeapSize = { value = "32GB", splice-type = "replace" }
PATH = { value = "/usr/bin", splice-type = "prepend" }
Test configuration allows specifying options for compiling and running test cases. All fields are optional, and if not configured, they will not take effect. Only the profile.test option of the top-level module takes effect. The list of options matches those provided by cjpm test on the console. If an option is configured both in the configuration file and via the console, the console option takes precedence. Runtime options supported by profile.test:
bench: specifies whether test cases should be run as performance benchmarks. The value can betrueorfalse.filter: specifies a test case filter. The value type is a string, and the format is the same as that of--filterin test.timeout-each <value>: specifies the default timeout interval for each test case. The format of value is%d[millis|s|m|h].parallel: specifies how test cases should be executed in parallel. The format ofvalueis as follows:<BOOL>:trueorfalse. Iftrueis specified, test classes can be run in parallel, and the number of parallel processes is controlled by the number of CPU cores on the OS.nCores: specifies that the number of parallel test processes must be equal to the number of available CPU cores.NUMBER: specifies the number of parallel test processes. The value must be a positive integer.NUMBERnCores: specifies the number of parallel test processes as a multiple of the number of available CPU cores. The value must be a positive number (floating-point number or integer).
option:<value>: defines runtime options in conjunction with@Configuration. For example:randomSeed: specifies the value of a random seed. The value is a positive integer.noColor: specifies whether to disable color in the console output. The value can betrueorfalse.reportPath: specifies the path where the test execution report is generated. The path cannot be configured using@Configuration.reportFormat: specifies the report output format. Currently, the unit test report supports only thexmlformat (case-insensitive). If other values are used, an exception is thrown. The format cannot be configured using@Configuration. The performance test report supports only thecsvandcsv-rawformats.
compilation-options: indicates the supported compilation options. The options are as follows:verbose: specifies whether to display detailed compilation information. The parameter value type isBOOL, that is, the value can betrueorfalse.no-run: specifies whether to only compile unit test products. The parameter value type isBOOL, that is, the value can betrueorfalse.lto: specifies whether to enable the LTO compilation mode. The value can bethinorfull. Currently, the Windows platform does not support this function.mock: explicitly sets the mock mode. The value can beon,off, andruntime-error.
env: supports the configuration of temporary environment variables when an executable file is run during the execution of thetestcommand. The value ofkeyis the name of the environment variable to be configured. The configuration options are as follows:value: specifies the value of the environment variable.splice-type: specifies the environment variable concatenation mode, which is optional. The default value isabsent. There are four possible values:absent: This configuration only takes effect if no environment variable with the same name exists; if such variable exists, the configuration is ignored.replace: This configuration replaces the existing environment variable with the same name.prepend: This configuration prepends the value to the existing environment variable.append: This configuration appends the value to the existing environment variable.
"profile.run"
Option for running an executable file. You can configure the environment variable env when running the executable with the run command. The configuration method is the same as that of profile.test.env.
"profile.customized-option"
[profile.customized-option]
cfg1 = "--cfg=\"feature1=lion, feature2=cat\""
cfg2 = "--cfg=\"feature1=tiger, feature2=dog\""
cfg3 = "-O2"
Custom options can be transparently transmitted to cjc through --cfg1 --cfg3. customized-option configured for each module takes effect for all packages in the module. For example, when the cjpm build --cfg1 --cfg3 command is executed, the command transparently transmitted to cjc is --cfg="feature1=lion, feature2=cat" -O2.
Note:
The condition value must be a valid identifier.
"target"
Multi-backend and multi-platform isolation option, which is used to configure a series of different configuration options for different backends and platforms. The target configuration method is as follows:
[target.x86_64-unknown-linux-gnu] # Linux configuration items
compile-option = "value1" # Additional compilation command option
link-option = "value2" # Transparent transmission option of the linker
[target.x86_64-unknown-linux-gnu.dependencies] # Source code dependency configuration item
[target.x86_64-unknown-linux-gnu.test-dependencies] # Test-phase dependency configuration item
[target.x86_64-unknown-linux-gnu.bin-dependencies] # Cangjie binary library dependencies
path-option = ["./test/pro0", "./test/pro1"]
[target.x86_64-unknown-linux-gnu.bin-dependencies.package-option]
"pro0.xoo" = "./test/pro0/pro0.xoo.cjo"
"pro0.yoo" = "./test/pro0/pro0.yoo.cjo"
"pro1.zoo" = "./test/pro1/pro1.zoo.cjo"
[target.x86_64-unknown-linux-gnu.debug] # debug configuration item for Linux
[target.x86_64-unknown-linux-gnu.debug.test-dependencies]
[target.x86_64-unknown-linux-gnu.release] # release configuration item for Linux
[target.x86_64-unknown-linux-gnu.release.bin-dependencies]
You can add a series of configuration items for a target by configuring the target.target-name field. You can run the cjc -v command in the corresponding Cangjie environment to obtain the target name. The Target item in the command output is the target name corresponding to the environment. At the cjvm backend, the target name is fixedly cjvm.
The configuration items can be configured for a specific target and are applicable to the compilation process of this target and also to the cross compilation process where any other target specifies this target as the target platform. The configuration items are as follows:
compile-option: specifies additional compilation command options.link-option: transparent transmission option of the linkerdependencies: configuration option of source code dependency. The structure is the same as that of thedependenciesfield.test-dependencies: configuration option of dependencies in the test phase. The structure is the same as that of thetest-dependenciesfield.bin-dependencies: Cangjie binary library dependency. The structure is described in the following sections.compile-macros-for-target: macro package control option during cross compilation. This option does not distinguish thedebugandreleasecompilation modes.
Developers can configure the target.target-name.debug and target.target-name.release fields to configure extra settings specific to the target in debug and release compilation modes. The configurable configuration options are the same as those described above. The configuration options configured for this type of field apply only to the corresponding compilation mode of the target.
"target.target-name[.debug/release].bin-dependencies"
This field is used to import the compiled Cangjie library product file that is applicable to the specified target. The following describes how to import the three packages of the pro0 and pro1 modules.
Note:
This field is not recommended unless otherwise specified. Use the
dependenciesfield to import the module source code.
├── test
│ └── pro0
│ ├── libpro0.xoo.so
│ └── pro0.xoo.cjo
│ ├── libpro0.yoo.so
│ └── pro0.yoo.cjo
│ └── pro1
│ ├── libpro1.zoo.so
│ └── pro1.zoo.cjo
└── src
└── main.cj
├── cjpm.toml
Method 1: Import via package-option
[target.x86_64-unknown-linux-gnu.bin-dependencies.package-option]
"pro0.xoo" = "./test/pro0/pro0.xoo.cjo"
"pro0.yoo" = "./test/pro0/pro0.yoo.cjo"
"pro1.zoo" = "./test/pro1/pro1.zoo.cjo"
The package-option option is a map structure, where the name pro0.xoo is used as the key (in toml configuration files, strings containing . should be enclosed in ""), and the value is libpro0.xoo.so. The path of the frontend file cjo is used as the value. The .a or .so file corresponding to the cjo must be placed in the same path.
Method 2: Import via path-option
[target.x86_64-unknown-linux-gnu.bin-dependencies]
path-option = ["./test/pro0", "./test/pro1"]
The path-option option is a string array structure, where each element represents the path to be imported. cjpm automatically imports all Cangjie library packages that meet the rule in the path. The rule is that the library name is in the format of Module name.Package name. Packages whose library names do not follow this rule can only be imported using the package-option option.
Note:
If the same package is imported using both
package-optionandpath-option, thepackage-optionfield has a higher priority.
An example of the source main.cj calling the pro0.xoo, pro0.yoo, and pro1.zoo packages is shown below:
import pro0.xoo.*
import pro0.yoo.*
import pro1.zoo.*
main(): Int64 {
var res = x + y + z // x, y, and z are values defined in pro0.xoo, pro0.yoo, and pro1.zoo, respectively.
println(res)
return 0
}
"target.target-name.compile-macros-for-target"
This field is used to configure the cross-compilation method of macro packages, and there are three possible scenarios:
Method 1: By default, only the products of the local platform are compiled during cross compilation. The products of the target platform are not compiled. The compilation takes effect for all macro packages in the module.
[target.Target platform]
compile-macros-for-target = ""
Method 2: During cross-compilation, both the local platform and target platform products are compiled. The compilation takes effect for all macro packages in the module.
[target.Target platform]
compile-macros-for-target = "all" # The configuration option is a string. The value must be "all".
Method 3: Certain macro packages within the module are compiled for both the local platform and the target platform during cross-compilation. Other unspecified macro packages will follow the default behavior of method 1.
[target.Target platform]
compile-macros-for-target = ["pkg1", "pkg2"] # The configuration option is in the format of string and number. The value is a list of macro package names.
Rules for merging target-related fields
The content in the target configuration option may also exist in other options of the cjpm.toml file. For example, the compile-option field may also exist in the package field. The difference is that the compile-option field in the package field is applied to all targets. cjpm merges all applicable configurations for these duplicate fields in a specific way. The following uses the debug compilation mode of x86_64-unknown-linux-gnu as an example. The target configuration is as follows:
[package]
compile-option = "compile-0"
link-option = "link-0"
[dependencies]
dep0 = { path = "./dep0" }
[test-dependencies]
devDep0 = { path = "./devDep0" }
[target.x86_64-unknown-linux-gnu]
compile-option = "compile-1"
link-option = "link-1"
[target.x86_64-unknown-linux-gnu.dependencies]
dep1 = { path = "./dep1" }
[target.x86_64-unknown-linux-gnu.test-dependencies]
devDep1 = { path = "./devDep1" }
[target.x86_64-unknown-linux-gnu.bin-dependencies]
path-option = ["./test/pro1"]
[target.x86_64-unknown-linux-gnu.bin-dependencies.package-option]
"pro1.xoo" = "./test/pro1/pro1.xoo.cjo"
[target.x86_64-unknown-linux-gnu.debug]
compile-option = "compile-2"
link-option = "link-2"
[target.x86_64-unknown-linux-gnu.debug.dependencies]
dep2 = { path = "./dep2" }
[target.x86_64-unknown-linux-gnu.debug.test-dependencies]
devDep2 = { path = "./devDep2" }
[target.x86_64-unknown-linux-gnu.debug.bin-dependencies]
path-option = ["./test/pro2"]
[target.x86_64-unknown-linux-gnu.debug.bin-dependencies.package-option]
"pro2.xoo" = "./test/pro2/pro2.xoo.cjo"
When the target configuration option coexists with the public configuration options of cjpm.toml or other target configuration options at different levels, the configuration options are merged based on the following priorities:
targetconfigurations indebug/releasemode.targetconfigurations irrelevant todebug/release.- Public configurations.
For example, the preceding target configuration options are merged based on the following rules:
compile-option: All applicable configuration options with the same name are merged based on the priority. The configuration option with a higher priority is appended later. In this example, for thex86_64-unknown-linux-gnutarget indebugmode, the final effectivecompile-optionvalue iscompile-0 compile-1 compile-2. Inreleasemode, it will becompile-0 compile-1, and for othertargets, onlycompile-0will apply.link-option: same as above.dependencies: Source code dependencies are directly merged. If a dependency conflict occurs, an error is reported. In this example, for thex86_64-unknown-linux-gnutarget indebugmode, the final effective dependencies aredep0,dep1, anddep2. Inreleasemode, onlydep0anddep1will apply. For othertargets, onlydep0will apply.test-dependencies: same as above.bin-dependencies: Binary dependencies are merged according to priority. If a conflict occurs, only the dependency with a higher priority is added. The configuration with the same priority is added to thepackage-optionconfiguration first. In this example, for thex86_64-unknown-linux-gnutarget indebugmode, the binary dependencies from./test/pro1and./test/pro2are added. Inreleasemode, only the binary dependencies from./test/pro1are added. Since there are no public configurations forbin-dependencies, no binary dependencies will be applied for othertargets.
In this cross-compilation scenario, if the x86_64-unknown-linux-gnu target is specified as the target on another platform, the configuration for target.x86_64-unknown-linux-gnu will also be merged with the public configuration options according to the rules mentioned above and applied. In addition, if in debug mode, the configuration options from target.x86_64-unknown-linux-gnu.debug will also be applied.
Environment Variables
In the cjpm.toml file, you can use environment variables to configure field values. cjpm obtains environment variable values from the current running environment and replaces them with the actual values. For example, the following dependencies field uses the environment variable to configure the path:
[dependencies]
aoo = { path = "${DEPENDENCY_PATH}/aoo" }
When reading module aoo, cjpm obtains the value of the DEPENDENCY_PATH variable and replaces it with the actual value to obtain the final path of module aoo.
The following lists the fields that can use environment variables.
- Field in the single module configuration field
package:- Single-package compilation option
compile-optionin the single-package configuration itempackage-configuration
- Single-package compilation option
- Fields in the workspace management field
workspace:- Member module list
members - Compilation module list
build-members - Test module list
test-members
- Member module list
- Fields present in both
packageandworkspace:- Compilation option
compile-option - Global compilation option
override-compile-option - Link option
link-option - Compilation product path
target-dir
- Compilation option
pathfield of the local dependency in the build dependency listdependenciespathfield of the local dependency in the test dependency listtest-dependenciespathfield of the local dependency in the build script dependency listscript-dependencies- Custom transparent transmission option
customized-optionin the command profile configuration itemprofile pathfield in the externalclibrary configuration itemffi.c- Fields in the platform isolation option
target:- Compilation option
compile-option - Global compilation option
override-compile-option - Link option
link-option pathfield of the local dependency in the build dependency listdependenciespathfield of the local dependency in the test dependency listtest-dependenciespathfield of the local dependency in the build script dependency listscript-dependenciespath-optionandpackage-optionfields in the binary dependency fieldbin-dependencies
- Compilation option
Configuration and Cache Folders
The path for storing the files downloaded by cjpm through git can be specified by the CJPM_CONFIGenvironment variable. If not specified, the default path is $HOME/.cjpm on Linux and %USERPROFILE%/.cjpm on Windows.
Others
Specifications of Cangjie Package Management
In the Cangjie package management specifications, a file directory is identified as a valid source code package when the following requirements are met:
- At least one Cangjie code file is directly contained.
- Its parent package (including the parent package of this parent package, up to the
rootpackage) is also a valid source code package. Therootpackage of a module does not have a parent package, so only condition 1 needs to be met.
For example, the following shows a cjpm project demo:
demo
│ └── src
│ ├── main.cj
│ └── pkg0
│ ├── aoo
│ │ └── aoo.cj
│ └── boo
│ └── boo.cj
│ ├── cjpm.toml
The directory corresponding to demo.pkg0 does not directly include the Cangjie code, so demo.pkg0 is not a valid source code package. Although the demo.pkg0.aoo and demo.pkg0.boo packages directly include the Cangjie code files aoo.cj and boo.cj, the upstream package demo.pkg0 is not a valid source code package, so the two packages are not valid source code packages.
When cjpm identifies a package like demo.pkg0 that does not directly contain the Cangjie file, it treats the package as a non-source code package, ignores all its subpackages, and prints the following warning:
Warning: there is no '.cj' file in directory 'demo/src/pkg0', and its subdirectories will not be scanned as source code
Therefore, if you need to configure a valid source code package, the package needs to directly contain at least one Cangjie code file, and all its upstream packages need to be valid source code packages. Taking the project demo as an example, if you want demo.pkg0, demo.pkg0.aoo, and demo.pkg0.boo to be identified as valid source code packages, you can add a Cangjie code file to demo/src/pkg0.
demo
│ └── src
│ ├── main.cj
│ └── pkg0
│ ├── pkg0.cj
│ ├── aoo
│ │ └── aoo.cj
│ └── boo
│ └── boo.cj
│ ├── cjpm.toml
demo/src/pkg0/pkg0.cj needs to be a Cangjie code file that complies with the package management specifications. It may contain no function code, for example, in the following format:
package demo.pkg0
Command Extension
cjpm provides a command extension mechanism, allowing developers to extend cjpm commands using executable files named in the form of cjpm-xxx(.exe).
For the executable file cjpm-xxx (or cjpm-xxx.exe on Windows), if the path of the file is configured in the system environment variable PATH, you can run the executable file as follows:
cjpm xxx [args]
args indicates the list of arguments that may be required for cjpm-xxx(.exe). The preceding command is equivalent to:
cjpm-xxx(.exe) [args]
Running cjpm-xxx(.exe) may depend on some dynamic libraries. In this case, you need to manually add the directory where the required dynamic library is located to the environment variable.
The following uses cjpm-demo as an example. The executable file is obtained by compiling the following Cangjie code:
import std.os.*
import std.collection.*
main(): Int64 {
var args = ArrayList<String>(getArgs())
if (args.size < 1) {
eprintln("Error: failed to get parameters")
return 1
}
println("Output: ${args[0]}")
return 0
}
After the directory is added to PATH, run the corresponding command to run the executable file and obtain the corresponding output.
Input: cjpm demo hello,world
Output: hello,world
The existing commands in cjpm have higher priorities. Therefore, these commands cannot be extended in this mode. For example, even if an executable file named cjpm-build exists in the system environment variable, running cjpm build will not execute cjpm-build. Instead, you need to run cjpm and enter build as a parameter.
Build Script
cjpm provides a build script mechanism, allowing you to define behaviors that cjpm should execute before and after specific commands.
The source file of the build script is named build.cj and is located in the home directory of the Cangjie project, that is, at the same level as cjpm.toml. When you run the init command to create a Cangjie project, cjpm does not create a build.cj by default. You can create and edit a build.cj in the specified location based on the following template format:
// build.cj
import std.os.*
// Case of pre/post codes for 'cjpm build'.
/* called before `cjpm build`
* Success: return 0
* Error: return any number except 0
*/
// func stagePreBuild(): Int64 {
// // process before "cjpm build"
// 0
// }
/*
* called after `cjpm build`
*/
// func stagePostBuild(): Int64 {
// // process after "cjpm build"
// 0
// }
// Case of pre/post codes for 'cjpm clean'.
/* called before `cjpm clean`
* Success: return 0
* Error: return any number except 0
*/
// func stagePreClean(): Int64 {
// // process before "cjpm clean"
// 0
// }
// For other options, define stagePreXXX and stagePostXXX in the same way.
/*
* Error code:
* 0: success.
* other: cjpm will finish running command. Check target-dir/build-script-cache/module-name/script-log for error outputs defind by user in functions.
*/
main(): Int64 {
match (getArgs()[0]) {
// Add operation here with format: "pre-"/"post-" + optionName
// case "pre-build" => stagePreBuild()
// case "post-build" => stagePostBuild()
// case "pre-clean" => stagePreClean()
case _ => 0
}
}
cjpm allows you to use build scripts to define the behavior before and after a series of commands. For example, for the build command, you can define pre-build in the match of the main function to execute the stagePreBuild function before the build command is executed (there is no requirement on the name of the function). Post-build behaviors can be similarly defined by adding a post-build case. For other commands, the pre- and post-command behaviors are defined in a similar way, simply by adding the corresponding pre/post options and the relevant functions.
Once pre- and post-behaviors for a command are defined, cjpm will first compile the build.cj file and execute the corresponding pre- and post-actions when running that command. For example, after pre-build and post-build are defined, running cjpm build will follow these steps:
- Before compilation, compile
build.cj. - Execute the function corresponding to
pre-build. - Compile the
cjpm buildprocess. - After compilation,
cjpmexecutes the function corresponding topost-build.
The build script supports the following commands:
build,test: These support bothpreandpostprocesses defined in the build scripts of dependent modules.run,install: These only supportpreandpostprocesses for the respective module, orpre-buildandpost-buildprocesses for dependent modules during compilation.check,tree,update: These support only thepreandpostbuild script processes for the respective module.clean: This only supports theprebuild script process for the respective module.
If --skip-script is configured when these commands are executed, the compilation and execution of all build scripts, including the build scripts of dependent modules, are skipped.
The usage of the build script is described as follows:
- The return value of a function must meet certain requirements. When the function is executed successfully, it should return
0. If it fails, it should return any non-zeroInt64type value. - All output from
build.cjwill be redirected to the project directorybuild-script-cache/[target|release]/[module-name]/bin/script-log. If you add any output in the function, it can be viewed in this file. - If
build.cjdoes not exist in the root directory of the project,cjpmis executed as usual. Ifbuild.cjexists and the pre- and post-command behaviors are defined, the command will be aborted whenbuild.cjfails to be compiled or the function returns a non-zero value, even if the command can be executed. - In the multi-module scenario, the
build.cjbuild script of a dependent module takes effect in the compilation and unit test processes. The output of the dependent module script is also redirected to the corresponding log file underbuild-script-cache/[target|release].
For example, the following build script build.cj defines the behaviors before and after build:
import std.os.*
func stagePreBuild(): Int64 {
println("PRE-BUILD")
0
}
func stagePostBuild(): Int64 {
println("POST-BUILD")
0
}
main(): Int64 {
match (getArgs()[0]) {
case "pre-build" => stagePreBuild()
case "post-build" => stagePostBuild()
case _ => 0
}
}
When the cjpm build command is executed, cjpm executes stagePreBuild and stagePostBuild. After cjpm build is executed, the following information is displayed in the script-log file:
PRE-BUILD
POST-BUILD
The build script can import dependent modules through the script-dependencies field in cjpm.toml. The format is the same as that of dependencies. For example, if the following configuration exists in cjpm.toml, the aoo module is imported, and the aoo module has a method named aaa():
[script-dependencies]
aoo = { path = "./aoo" }
Then, you can import the dependency to the build script and use the aaa() interface in the dependency as follows:
import std.os.*
import aoo.*
func stagePreBuild(): Int64 {
aaa()
0
}
func stagePostBuild(): Int64 {
println("POST-BUILD")
0
}
main(): Int64 {
match (getArgs()[0]) {
case "pre-build" => stagePreBuild()
case "post-build" => stagePostBuild()
case _ => 0
}
}
The build script dependency (script-dependencies) is independent of source-related dependencies (such as dependencies and test-dependencies). This means that source code and test code cannot use the dependent modules specified in script-dependencies, and build scripts cannot use the modules listed in dependencies or test-dependencies. If you need to use the same module in both the build script and the source/test code, you must configure the module in both script-dependencies and dependencies/test-dependencies.
Usage of Cross-Platform Build Scripts
Like Cangjie source code, build scripts can use built-in compilation condition variables os and backend to isolate the pre- and post-command behavior on different platforms. For example, the following code:
@When[os == "Linux"]
func stagePreBuild(): Int64 {
println("Linux pre build")
0
}
@When[os == "Windows"]
func stagePreBuild(): Int64 {
println("Windows pre build")
0
}
When you compile and build in the Linux and Windows systems, different results are printed in script-log.
In addition, in the cross compilation scenario, if you need to define the pre- and post-command behavior for a specific target platform in build.cj, the system platform on which cjpm is running does not change. Therefore, os and backend cannot be used to distinguish the pre-compiled behavior. For this scenario, cjpm provides the customized condition variable target. Developers can use this condition variable in build.cj to define the behavior of a specific target platform. For example, the following code:
@When[target == "x86_64-unknown-linux-gnu"]
func stagePreBuild(): Int64 {
println("x86_64-unknown-linux-gnu pre build")
0
}
@When[target == "x86_64-w64-mingw32"]
func stagePreBuild(): Int64 {
println("x86_64-w64-mingw32 pre build")
0
}
When cjpm build --target x86_64-w64-mingw32 is executed for cross compilation on the x86_64-unknown-linux-gnu platform, build.cj executes the pre-build behavior under the target == "x86_64-w64-mingw32" condition and prints x86_64-w64-mingw32 pre build.
Examples
The following uses the Cangjie project directory structure as an example to describe how to use cjpm. For details about the source code file examples in the directory, see Source Code. The module name of this Cangjie project is test.
cj_project
│ ├── pro0
│ │ ├── cjpm.toml
│ │ └── src
│ │ └── zoo
│ │ ├── zoo.cj
│ │ └── zoo_test.cj
│ │ ├── pro0.cj
│ └── src
│ ├── koo
│ │ ├── koo.cj
│ │ └── koo_test.cj
│ ├── main.cj
│ └── main_test.cj
│ ├── cjpm.toml
Usage of init and build
-
Create a Cangjie project and compile the xxx
.cjsource code file, such as thekoopackage andmain.cjfile shown in the structure.cjpm init --name test --path .../cj_project mkdir kooThe
srcfolder and the defaultcjpm.tomlfile are automatically generated. -
If the current module needs to depend on an external
pro0module, create apro0module and its configuration file, and then compile the source code file of the module. You need to create asrcfolder in thepro0module, create the root packagepro0.cjfor thepro0module in thesrcfolder, and place the compiled package in thesrcfolder, such as thezoopackage shown in the structure.mkdir pro0 && cd pro0 cjpm init --name pro0 --type=static mkdir src/zoo -
If the main module depends on
pro0, configure thedependenciesfield in the configuration file of the main module according to the description in this manual. After the configuration is correct, run thecjpm buildcommand. The generated executable file is stored in thetarget/release/bin/directory.cd cj_project vim cjpm.toml cjpm build cjpm run
Usage of test and clean
-
After compiling the xxx
_test.cjunit test file corresponding to each file, run the following code to perform the unit test. The generated file is stored in thetarget/release/unittest_bindirectory.cjpm testOr
cjpm test src src/koo pro/src/zoo -
Manually delete middleware such as
target,cov_output,*.gcno, and*.gcda.cjpm clean
Source Code
cj_project/src/main.cj
package test
import pro0.zoo.*
import test.koo.*
main(): Int64 {
let res = z + k
println(res)
let res2 = concatM("a", "b")
println(res2)
return 0
}
func concatM(s1: String, s2: String): String {
return s1 + s2
}
cj_project/src/main_test.cj
package test
import std.unittest.*//testfame
import std.unittest.testmacro.*//macro_Defintion
@Test
public class TestM{
@TestCase
func sayhi(): Unit {
@Assert(concatM("1", "2"), "12")
@Assert(concatM("1", "3"), "13")
}
}
cj_project/src/koo/koo.cj
package test.koo
public let k: Int32 = 12
func concatk(s1: String, s2: String): String {
return s1 + s2
}
cj_project/src/koo/koo_test.cj
package test.koo
import std.unittest.*//testfame
import std.unittest.testmacro.*//macro_Defintion
@Test
public class TestK{
@TestCase
func sayhi(): Unit {
@Assert(concatk("1", "2"), "12")
@Assert(concatk("1", "3"), "13")
}
}
cj_project/pro0/src/pro0.cj
package pro0
cj_project/pro0/src/zoo/zoo.cj
package pro0.zoo
public let z: Int32 = 26
func concatZ(s1: String, s2: String): String {
return s1 + s2
}
cj_project/pro0/src/zoo/zoo_test.cj
package pro0.zoo
import std.unittest.*//testfame
import std.unittest.testmacro.*//macro_Defintion
@Test
public class TestZ{
@TestCase
func sayhi(): Unit {
@Assert(concatZ("1", "2"), "12")
@Assert(concatZ("1", "3"), "13")
}
}
cj_project/cjpm.toml
[package]
cjc-version = "0.40.2"
description = "nothing here"
version = "1.0.0"
name = "test"
output-type = "executable"
[dependencies]
pro0 = { path = "pro0" }
cj_project/pro0/cjpm.toml
[package]
cjc-version = "0.40.2"
description = "nothing here"
version = "1.0.0"
name = "pro0"
output-type = "static"
Debugger
Overview
cjdb is a Cangjie program command-line debugger developed based on lldb. It provides the following features for Cangjie developers:
- Loading a target program in launch or attach mode
- Setting source/function/conditional breakpoints
- Setting watchpoints
- Running the program by using
s,n,finish, andcontinue - Viewing and modifying variables by using
printandset - Calculating expressions
- Viewing Cangjie threads by using
cjthread
Usage
Loading a Target Program in launch or attach Mode
Loading a Target Program in launch Mode
There are two launch modes:
-
Load the target program while starting the debugger.
~/0901/cangjie_test$ cjdb test (cjdb) target create "test" Current executable set to '/0901/cangjie-linux-x86_64-release/bin/test' (x86_64). (cjdb) -
Start the debugger, and then run the
filecommand to load the target program.~/0901/cangjie_test$ cjdb (cjdb) file test Current executable set to '/0901/cangjie/test' (x86_64). (cjdb)
Debugging the Target Program in attach Mode
For a running program, you can debug the target program in attach mode.
~/0901/cangjie-linux-x86_64-release/bin$ cjdb
(cjdb) attach 15325
Process 15325 stopped
* thread #1, name = 'test', stop reason = signal SIGSTOP
frame #0: 0x00000000004014cd test`default.main() at test.cj:7:9
4 var a : Int32 = 12
5 a = a + 23
6 while (true) {
-> 7 a = 1
8 }
9 a = test(10, 34)
10 return 1
thread #2, name = 'FinalProcessor', stop reason = signal SIGSTOP
frame #0: 0x00007f48c12fc065 libpthread.so.0`__pthread_cond_timedwait at futex-internal.h:205
thread #3, name = 'PoolGC_1', stop reason = signal SIGSTOP
frame #0: 0x00007f48c12fbad3 libpthread.so.0`__pthread_cond_wait at futex-internal.h:88
thread #4, name = 'MainGC', stop reason = signal SIGSTOP
frame #0: 0x00007f48c12fc065 libpthread.so.0`__pthread_cond_timedwait at futex-internal.h:205
thread #5, name = 'schmon', stop reason = signal SIGSTOP
frame #0: 0x00007f48c0fe17a0 libc.so.6`__GI___nanosleep(requested_time=0x00007f48a8ffcb70, remaining=0x0000000000000000) at nanosleep.c:28
Executable module set to "/0901/cangjie-linux-x86_64-release/bin/test".
Architecture set to: x86_64-unknown-linux-gnu.
Setting Breakpoints
Setting a Source Code Breakpoint
breakpoint set --file test.cj --line line_number
--line specifies the line number.
--file specifies the file.
For a single file, you only need to enter the line number. For multiple files, you need to add the file name.
b test.cj:4 is short for breakpoint set --file test.cj --line 4.
Example: breakpoint set --line 2
(cjdb) b 2
Breakpoint 1: where = test`default.main() + 13 at test.cj:4:3, address = 0x0000000000401491
(cjdb) b test.cj : 4
Breakpoint 2: where = test`default.main() + 13 at test.cj:4:3, address = 0x0000000000401491
(cjdb)
Setting a Function Breakpoint
breakpoint set --name function_name
--name specifies the function name for setting a function breakpoint.
b test is short for breakpoint set --name test.
Example: breakpoint set --method test
(cjdb) b test
Breakpoint 3: where = test`default.test(int, int) + 19 at test.cj:12:10, address = 0x0000000000401547
(cjdb)
Setting a Conditional Breakpoint
breakpoint set --file xx.cj --line line_number --condition expression
--file specifies the file.
--condition specifies the condition, supporting ==, !=, >, <, >=, <=, and, and or.
The abbreviation is b -f test.cj -l 4 -c a==12.
Example: breakpoint set --file test.cj --line 4 --condition a==12
(cjdb) breakpoint set --file test.cj --line 4 --condition a==12
Breakpoint 2: where = main`default::main() + 60 at test.cj:4:9, address = 0x00005555555b62d0
(cjdb) c
Process 3128551 resuming
Process 3128551 stopped
* thread #1, name = 'schmon', stop reason = breakpoint 2.1
frame #0: 0x00005555555b62d0 main`default::main() at test.cj:4:9
1 main(): Int64 {
2
3 var a : Int32 = 12
-> 4 a = a + 23
5 return 1
6 }
Only basic variable conditions (Int8, Int16, Int32, Int64, UInt8, UInt16, UInt32, UInt64, Float32, Float64, Bool, and Rune) are supported. Float16 variable conditions are not supported.
Setting Watchpoints
watchpoint set variable -w read variable_name
-w specifies the watchpoint type, supporting read, write, or read_write.
wa s v is short for watchpoint set variable.
Example: watchpoint set variable -w read a
(cjdb) wa s v -w read a
Watchpoint created: Watchpoint 1: addr = 0x7fffddffed70 size = 8 state = enabled type = r
declare @ 'test.cj:27'
watchpoint spec = 'a'
new value: 10
(cjdb)
Watchpoints can be set only for basic types.
Running the Target Program
Run the command r (run).
(cjdb) r
Process 2884 launched: '/0901/cangjie-linux-x86_64-release/bin/test' (x86_64)
Process 2884 stopped
* thread #1, name = 'test', stop reason = breakpoint 1.1 2.1
frame #0: 0x0000000000401491 test`default.main() at test.cj:4:3
1
2 main(): Int64 {
3
-> 4 var a : Int32 = 12
5 a = a + 23
6 a = test(10, 34)
7
The program stops at the initialization breakpoint.
Execution
Single-Step Execution: n (next)
(cjdb) n
Process 2884 stopped
* thread #1, name = 'test', stop reason = step over
frame #0: 0x0000000000401498 test`default.main() at test.cj:5:7
2 main(): Int64 {
3
4 var a : Int32 = 12
-> 5 a = a + 23
6 a = test(10, 34)
7 return 1
8 }
(cjdb)
Lines 4 and 5 are executed.
Continuing Execution Until the Next Breakpoint: c (continue)
(cjdb) c
Process 2884 resuming
Process 2884 stopped
* thread #1, name = 'test', stop reason = breakpoint 3.1
frame #0: 0x0000000000401547 test`default.test(a=10, b=34) at test.cj:12:10
9
10 func test(a : Int32, b : Int32) : Int32 {
11
-> 12 return a + b
13 }
14
(cjdb)
Entering a Function: s
(cjdb) n
Process 5240 stopped
* thread #1, name = 'test', stop reason = step over
frame #0: 0x00000000004014d8 test`default.main() at test.cj:6:7
3
4 var a : Int32 = 12
5 a = a + 23
-> 6 a = test(10, 34)
7 return 1
8 }
9
(cjdb) s
Process 5240 stopped
* thread #1, name = 'test', stop reason = step in
frame #0: 0x0000000000401547 test`default.test(a=10, b=34) at test.cj:12:10
9
10 func test(a : Int32, b : Int32) : Int32 {
11
-> 12 return a + b
13 }
14
(cjdb)
When a function is called, you can run the s command to enter the definition declaration of the called function.
Exiting a Function: finish
(cjdb) s
Process 5240 stopped
* thread #1, name = 'test', stop reason = step in
frame #0: 0x0000000000401547 test`default.test(a=10, b=34) at test.cj:12:10
9
10 func test(a : Int32, b : Int32) : Int32 {
11
-> 12 return a + b
13 }
14
(cjdb) finish
Process 5240 stopped
* thread #1, name = 'test', stop reason = step out
Return value: (int) $0 = 44
frame #0: 0x00000000004014dd test`default.main() at test.cj:6:7
3
4 var a : Int32 = 12
5 a = a + 23
-> 6 a = test(10, 34)
7 return 1
8 }
9
(cjdb)
Run the finish command to exit the current function and return to the previous call stack function.
Viewing Variables
Viewing Local Variables: locals
(cjdb) locals
(Int32) a = 12
(Int64) b = 68
(Int32) c = 13
(Array<Int64>) array = {
[0] = 2
[1] = 4
[2] = 6
}
(pkgs.Rec) newR2 = {
age = 5
name = "string"
}
(cjdb)
When the debugger stops at a certain position in the program, you can use locals to view all local variables within the scope of the current function's lifecycle. Only the variables that have been initialized up to the current position can be viewed. The uninitialized variables cannot be viewed.
Viewing a Single Variable: print variable_name
Example: print b
(cjdb) print b
(Int64) $0 = 110
(cjdb)
Run the print command (p for short), followed by the name of the variable to be viewed.
Viewing a String Variable
(cjdb) print newR2.name
(String) $0 = "string"
(cjdb)
Viewing Struct and Class Variables
(cjdb) print newR2
(pkgs.Rec) $0 = {
age = 5
name = "string"
}
(cjdb)
Viewing an Array
(cjdb) print array
(Array<Int64>) $0 = {
[0] = 2
[1] = 4
[2] = 6
[3] = 8
}
(cjdb) print array[1..3]
(Array<Int64>) $1 = {
[1] = 4
[2] = 6
}
(cjdb)
The basic types (Int8, Int16, Int32, Int64, UInt8, UInt16, UInt32, UInt64, Float16, Float32, Float64, Bool, Unit, and Rune) are supported.
A range with the interval [start..end) is supported. Reverse order is not supported.
An error message is displayed when an invalid range or a range of the non-array type is viewed.
(cjdb) print array
(Array<Int64>) $0 = {
[0] = 0
[1] = 1
}
(cjdb) print array[1..3]
error: unsupported expression
(cjdb) print array[0][0]
error: unsupported expression
Viewing CString Variables
(cjdb) p cstr
(cro.CString) $0 = "abc"
(cjdb) p cstr
(cro.CString) $1 = null
Viewing Global Variables: globals
(cjdb) globals
(Int64) pkgs.Rec.g_age = 100
(Int64) pkgs.g_var = 123
(cjdb)
You can run the print command followed by the name of a single global variable to view it, instead of using the print + Package name + Variable name format. For example, to view the global variable g_age, run the following command:
(cjdb) p g_age
(Int64) $0 = 100
(cjdb)
Modifying Variables
(cjdb) set a=30
(Int32) $4 = 30
(cjdb)
You can use set to modify the value of a local variable. Only the basic numeric types (Int8, Int16, Int32, Int64, UInt8, UInt16, UInt32, UInt64, Float32, and Float64) are supported.
For Bool variables, you can modify them using the value 0 (for false) and non-zero values (for true). For Rune variables, you can modify them using the corresponding ASCII codes.
(cjdb) set b = 0
(Bool) $0 = false
(cjdb) set b = 1
(Bool) $1 = true
(cjdb) set c = 0x41
(Rune) $2 = 'A'
(cjdb)
If the modified value is not a number or is out of the variable's range, an error message is displayed.
(cjdb) p c
(Rune) $0 = 'A'
(cjdb) set c = 'B'
error: unsupported expression
(cjdb) p b
(Bool) $1 = false
(cjdb) set b = true
error: unsupported expression
(cjdb) p u8
(UInt8) $3 = 123
(cjdb) set u8 = 256
error: unsupported expression
(cjdb) set u8 = -1
error: unsupported expression
Expression Evaluation
Viewing Literals
Example: expr 3
(cjdb) expr 3
(Int64) $0 = 3
(cjdb)
Viewing Variable Names
Example: expr a
(cjdb) expr a
(Int64) $0 = 3
(cjdb)
Viewing Arithmetic Expressions
Example: expr a + b
(cjdb) expr a + b
(Int64) $0 = 3
(cjdb)
Viewing Relational Expressions
Example: expr a > b
(cjdb) expr a > b
(Bool) $0 = false
(cjdb)
Viewing Logical Expressions
Example: expr a && b
(cjdb) expr true && false
(Bool) $0 = false
(cjdb)
Viewing Suffix Expressions
Example: expr a.b
(cjdb) expr value.member
(Int64) $0 = 1
(cjdb)
Example: expr a[b]
(cjdb) expr array[2]
(Int64) $0 = 3
(cjdb)
Supported expression calculations: include but is not limited to literals, variable names, parenthesized expressions, arithmetic expressions, relational expressions, conditional expressions, loop expressions, member access expressions, index access expressions, interval expressions, and bitwise operation expressions.
Note:
The following expression calculations are not supported: generic function calls, function calls with named arguments, extensions, interpolated strings, and function names. The Float16 type is not supported.
Viewing Cangjie Threads
You can view the id and frame information of Cangjie threads, but cannot switch Cangjie threads.
Viewing All Cangjie Threads
(cjdb) cjthread list
cjthread id: 1, state: running name: cjthread1
frame #0: 0x000055555557c140 main`ab::main() at varray.cj:16:1
cjthread id: 2, state: pending name: cjthread2
frame #0: 0x00007ffff7d8b9d5 libcangjie-runtime.so`CJ_CJThreadPark + 117
(cjdb)
Viewing a Cangjie Thread Call Stack
View the call stack of a specified Cangjie thread.
(cjdb) cjthread backtrace 1
cjthread #1 state: pending name: cangjie
frame #0: 0x00007ffff7d8b9d5 libcangjie-runtime.so`CJ_CJThreadPark + 117
frame #1: 0x00007ffff7d97252 libcangjie-runtime.so`CJ_TimerSleep + 66
frame #2: 0x00007ffff7d51b5d libcangjie-runtime.so`CJ_MRT_FuncSleep + 33
frame #3: 0x0000555555591031 main`std/sync::sleep(std/time::Duration) + 45
frame #4: 0x0000555555560941 main`default::lambda.0() at complex.cj:9:3
frame #5: 0x000055555555f68b main`default::std/core::Future<Unit>::execute(this=<unavailable>) at future.cj:124:35
frame #6: 0x00007ffff7d514f1 libcangjie-runtime.so`___lldb_unnamed_symbol1219 + 7
frame #7: 0x00007ffff7d4dc52 libcangjie-runtime.so`___lldb_unnamed_symbol1192 + 114
frame #8: 0x00007ffff7d8b09a libcangjie-runtime.so`CJ_CJThreadEntry + 26
(cjdb)
In the cjthread backtrace 1 command, 1 indicates the specified cjthread ID.
Precautions
-
The program being debugged must be a compiled
debugversion, such as the program file compiled using the following command:cjc -g test.cj -o test -
After you define a generic object and step into the
initfunction of the object during debugging, the function name displayed in the stack information contains two package names. One is the name of the package where the generic object is instantiated, and the other is the name of the package where the generic definition is located.* thread #1, name = 'main', stop reason = step in frame #0: 0x0000000000404057 main`default.p1.Pair<String, Int64>.init(a="hello", b=0) at a.cj:21:9 18 let x: T 19 let y: U 20 public init(a: T, b: U) { -> 21 x = a 22 y = b 23 } -
For
Enumtype display, if theEnumconstructor has parameters, the display format is as follows:enum E { Ctor(Int64, String) | Ctor } main() { var temp = E.Ctor(10, "String") 0 } ======================================== (cjdb) p temp (E) $0 = Ctor { arg_1 = 10 arg_2 = "String" }arg_xis not a printable member variable.Enumitself does not contain a member variable namedarg_x. -
cjdbis built based onlldb, so it supports the native basic functions oflldb. For details, see the lldb official website.
FAQ
-
In the
dockerenvironment,cjdbreportserror: process launch failed: 'A' packet returned an error: 8.root@xxx:/home/cj/cangjie-example#cjdb ./hello (cjdb) target create "./hello" Current executable set to '/home/cj/cangjie-example/hello' (x86_64). (cjdb) b main Breakpoint 1: 2 locations. (cjdb) r error: process launch failed: 'A' packet returned an error: 8 (cjdb)Cause: The SYS_PTRACE permission is not enabled when the
dockercontainer is created.Action: Add the following options when creating a container and delete the existing container:
docker run --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --security-opt apparmor=unconfined -
cjdbreportsstop reason = signal XXX.Process 32491 stopped * thread #2, name = 'PoolGC_1', stop reason = signal SIGABRT frame #0: 0x00007ffff450bfb7 lib.so.6`__GI_raise(sig=2) at raise.c:51Cause: The program continuously generates the
SIGABRTsignal, which triggers the debugger to pause.Action: Run the following command to ignore such signals:
(cjdb) process handle --pass true --stop false --notify true SIGBUS NAME PASS STOP NOTIFY =========== ===== ===== ====== SIGBUS true false true (cjdb) -
cjdbdoes not capture theSIGSEGVsignal.Cause: By default,
cjdbdoes not capture theSIGSEGVsignal during startup.Action: Run the following command to capture this signal during debugging:
(cjdb)process handle -p true -s true -n true SIGSEGV NAME PASS STOP NOTIFY =========== ===== ===== ====== SIGSEGV true true true (cjdb) -
cjdbcannot access thecatchblock by using debugging commands such asnextands.Cause: Cangjie uses the
LLVMLandingPadmechanism to handle exceptions. However, this mechanism cannot determine whichcatchblock captures the exception thrown from thetryblock due to the lack of clear control flow. As a result, the code to be executed cannot be determined. This issue also exists inclang++.Action: If you need to debug the code in the
catchblock, set a breakpoint in thecatchblock.(cjdb) b 31 Breakpoint 2: where = main`default::test(Int64) + 299 at a.cj:31:18, address = 0x000055555557caff (cjdb) n Process 1761640 stopped * thread #1, name = 'schmon', stop reason = breakpoint 2.1 frame #0: 0x000055555557caff main`default::test(a=0) at a.cj:31:18 28 s = 12/a 29 } catch (e:Exception) { 30 ->31 error_result = e.toString() 32 println(error_result) 33 } 34 s (cjdb) -
In
windowsandmacOS, an expression calculation error is reported:Expression can't be run, because there is no JIT compiled function.Cause: Some expressions cannot be used in
windowsandmacOS, including type conversion expressions, assignment expressions, function calls, displaying variables of the custom type, and displaying variables of thecollectiontype. -
In
macOS, theaarch64architecture reports an error during the debugging of some environments:Connection shut down by remote side while waiting for reply to initial handshake packet.Cause: The debugging service exits abnormally in some systems.
Solution: Delete the
third_party/llvm/bin/debugserverfile and restart the debugging.
Appendix
cjdb-specific Commands
| Command | Abbreviation | Function | Description |
|---|---|---|---|
| globals | None | Displays global variables. | No parameter. |
| locals | None | Displays local variables. | No parameter. |
| p | Displays a single variable. | The parameter is a variable name, for example, print variable_name. | |
| expression | expr | Displays an expression. | The parameter is an expression, for example, expr variable_name + 1. |
| set | None | Modifies variables. | The parameter is an expression, for example, set variable_name = value. |
| finish | None | Causes the function to exit. | No parameter. |
| cjthread | None | Displays lightweight threads. | No parameter. |
Formatting Tool
Function Description
CJFMT(Cangjie Formatter) is an automatic code formatting tool developed based on the Cangjie programming specifications.
Usage
- You can install the CJFMT plug-in on DevEco.
- You can run
cjfmt [option] file [option] fileto use CJFMT.
cjfmt -h help information and options
Usage:
cjfmt -f fileName [-o fileName]
cjfmt -d fileDir [-o fileDir]
Options:
-h Show usage
eg: cjfmt -h
-f Specifies the file in the required format. The value can be a relative path or an absolute path.
eg: cjfmt -f test.cj
-d Specifies the file directory in the required format. The value can be a relative path or an absolute path.
eg: cjfmt -d test/
-o <value> Output. If a single file is formatted, '-o' is followed by the file name. Relative and absolute paths are supported;
If a file in the file directory is formatted, a path must be added after -o. The path can be a relative path or an absolute path.
eg: cjfmt -f a.cj -o ./fmta.cj
eg: cjfmt -d ~/testsrc -o ./testout
-c <value> Specify the format configuration file, relative and absolute paths are supported.
If the specified configuration file fails to be read, cjfmt will try to read the default configuration file in CANGJIE_HOME.
eg: cjfmt -f a.cj -c ./config/cangjie-format.toml
eg: cjfmt -d ~/testsrc -c ~/home/project/config/cangjie-format.toml
-l <region> Only format lines in the specified region for the provided file. Only valid if a single file was specified.
Region has a format of [start:end] where 'start' and 'end' are integer numbers representing first and last lines to be formated in the specified file.
Line count starts with 1.
eg: cjfmt -f a.cj -o ./fmta.cj -l 1:25
Formatting a File
cjfmt -f
- Formats and overwrites the source file. Both relative and absolute paths are supported.
cjfmt -f ../../../test/uilang/Thread.cj
- The
-ooption is used to create a.cjfile and export the formatted code. For the source file and output file, both relative and absolute paths are supported.
cjfmt -f ../../../test/uilang/Thread.cj -o ../../../test/formated/Thread.cj
Formatting a Directory
cjfmt -d
- The
-doption allows you to specify the directory for scanning the Cangjie source code and format the Cangjie source code in the directory. Both relative and absolute paths are supported.
cjfmt -d test/ //The source file directory is a relative directory.
cjfmt -d /home/xxx/test //The source file directory is an absolute directory.
- The
-ooption specifies the output directory. It can be an existing path. If the path does not exist, the related directory structure is created. Both relative and absolute paths are supported. The maximum directory length MAX_PATH varies according to the system. For example, the value of MAX_PATH cannot exceed 260 in Windows or 4096 in Linux.
cjfmt -d test/ -o /home/xxx/testout
cjfmt -d /home/xxx/test -o ../testout/
cjfmt -d testsrc/ -o /home/../testout // The source file folder testsrc/ does not exist. An error message is displayed: error: Source file path not exist!
Formatting a Configuration File
cjfmt -c
- The
-coption allows you to specify a customized formatter configuration file.
cjfmt -f a.cj -c ./cangjie-format.toml
By default, the cangjie-format.toml file contains the following configuration file. The values are also the values of the configuration options of cjfmt.
# indent width
indentWidth = 4 # Range of indentWidth: [0, 8]
# limit length
linelimitLength = 120 # Range of indentWidth: [1, 120]
# line break type
lineBreakType = "LF" # "LF" or "CRLF"
# allow Multi-line Method Chain when it's level equal or greater than multipleLineMethodChainLevel
allowMultiLineMethodChain = false
# if allowMultiLineMethodChain's value is true,
# and method chain's level is equal or greater than multipleLineMethodChainLevel,
# method chain will be formatted to multi-line method chain.
# e.g. A.b().c() level is 2, A.b().c().d() level is 3
# ObjectA.b().c().d().e().f() =>
# ObjectA
# .b()
# .c()
# .d()
# .e()
# .f()
multipleLineMethodChainLevel = 5 # Range of multipleLineMethodChainLevel: [2, 10]
# allow Multi-line Method Chain when it's length greater than linelimitLength
multipleLineMethodChainOverLineLength = true
Notes:
If the customized formatter configuration file fails to be read, the default formatter configuration file
cangjie-format.tomlin the CANGJIE_HOME environment is read. If the default formatter configuration filecangjie-format.tomlin the CANGJIE_HOME environment also fails to be read, the built-in formatting configuration options ofcjfmtare used. If a configuration option in the formatter configuration file fails to be read, the corresponding built-in formatter configuration option ofcjfmtis used instead.
Formatting a Fragment
cjfmt -l
- The
-loption allows you to specify a part of the file to be formatted for formatting. The formatter applies the rules only to the source code within the provided line range. - The
-loption applies only to formatting a single file (-foption). If a directory (-doption) is specified, the-loption is invalid.
cjfmt -f a.cj -o .cj -l 10:25 //Formats only lines 10 to 25.
Formatting Rules
- A source file contains the copyright, package, import, and top-level elements in sequence, and they are separated by blank lines.
[Compliant Code Example]
// Part I: copyright information
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved.
*/
// Part 2: package declaration
package com.huawei.myproduct.mymodule
// Part 3: import declaration
import std.collection.HashMap // Standard library
// Part 4: public element definition
public class ListItem <: Component {
// ...
}
// Part 5: internal element definition
class Helper {
// CODE
}
Note:
The Cangjie formatting tool does not forcibly use blank lines to separate the copyright information from other parts. If you leave one or more blank lines under the copyright information, the formatting tool retains one blank line.
- Use the same space indentation, with four spaces for each indentation.
[Compliant Code Example]
class ListItem {
var content: Array<Int64> // Compliant: Relative class declarations are indented with 4 spaces.
init(
content: Array<Int64>, // Compliant: Function arguments are indented 4 spaces relative to the function declaration.
isShow!: Bool = true,
id!: String = ""
) {
this.content = content
}
}
- Use the unified line feed style for braces. For non-empty block structures, use the K&R style for braces.
[Compliant Code Example]
enum TimeUnit { // Compliant: Opening curly brace follows the declaration at end of line, preceded by 1 space.
Year | Month | Day | Hour
} // Compliant: Closing curly brace is on its own line.
class A { // Compliant: Opening curly brace follows the declaration at end of line, preceded by 1 space.
var count = 1
}
func fn(a: Int64): Unit { // Compliant: Opening curly brace follows the declaration at end of line, preceded by 1 space.
if (a > 0) { // Compliant: Opening curly brace follows the declaration at end of line, preceded by 1 space.
// CODE
} else { // Compliant: Closing curly brace and else are on the same line.
// CODE
} // Compliant: Closing curly brace is on its own line.
}
// lambda function
let add = { base: Int64, bonus: Int64 => // Compliant: Non-empty block in lambda expression follows K&R style.
print("compliant news")
base + bonus
}
- According to the G.FMT.10 rule in the Cangjie programming specifications, use spaces to highlight keywords and important information.
[Compliant Code Example]
var isPresent: Bool = false // Compliant: Variable declaration has one space after colon.
func method(isEmpty!: Bool): RetType { ... } // Compliant: Function definition (name parameter/return type) has one space after colon.
method(isEmpty: isPresent) // Compliant: Passed value of name parameter has one space after colon.
0..MAX_COUNT : -1 // Compliant: No space before and after the range operator interval, one space before and after the colon before step.
var hundred = 0
do { // Compliant: One space between the keyword do and the parenthesis following it.
hundred++
} while (hundred < 100) // Compliant: One space between the keyword while and the parenthesis preceding it.
func fn(paramName1: ArgType, paramName2: ArgType): ReturnType { // Compliant: No spaces between a parenthesis and its internal adjacent character.
...
for (i in 1..4) { // Compliant: The range operator has no spaces on either side.
...
}
}
let listOne: Array<Int64> = [1, 2, 3, 4] // Compliant: Square brackets and parentheses have no spaces inside on either side.
let salary = base + bonus // Compliant: Binary operators have spaces on both sides.
x++ // Compliant: No space between unary operators and operands.
- Reduce unnecessary blank lines to keep the code compact.
[Noncompliant Code Example]
class MyApp <: App {
let album = albumCreate()
let page: Router
// Blank line
// Blank line
// Blank line
init() { // Non-compliant: Type definition uses consecutive blank lines inside
this.page = Router("album", album)
}
override func onCreate(): Unit {
println( "album Init." ) // Non-compliant: Opening and closing braces have blank lines inside.
}
}
- Reduce unnecessary semicolons to prioritize code simplicity.
[Before formatting]
package demo.analyzer.filter.impl; // Redundant semicolon
internal import demo.analyzer.filter.StmtFilter; // Redundant semicolon
internal import demo.analyzer.CJStatment; // Redundant semicolon
func fn(a: Int64): Unit {
println( "album Init." );
}
[After formatting]
package demo.analyzer.filter.impl // Deletes redundant semicolons.
internal import demo.analyzer.filter.StmtFilter // Deletes redundant semicolons.
internal import demo.analyzer.CJStatment // Deletes redundant semicolons.
func fn(a: Int64): Unit {
println( "album Init." ); // Semicolons of an expression are retained as removing them may affect semantics.
}
- Sort modifier keywords based on the priority specified in the G.FMT.12 rule in the Cangjie programming specifications.
The recommended priorities for sorting modifiers for top-level elements:
public
open/abstract
The recommended priorities for sorting modifiers for instance member functions or attributes:
public/protected/private
open
override
The recommended priorities for sorting modifiers for static member functions:
public/protected/private
static
redef
The recommended priorities for sorting modifiers for member variables:
public/protected/private
static
- Formatting of multi-line comments
For comments starting with *, the * symbols are aligned with each other. Comments not starting with * remain as they are.
// Before formatting
/*
* comment
*/
/*
comment
*/
// After formatting
/*
* comment
*/
/*
comment
*/
Precautions
-
CJFMT does not support formatting of code with syntax errors.
-
CJFMT does not support metaprogramming formatting.
Coverage Statistics in Command Line Mode
Function Description
cjcov is an official coverage statistics tool of Cangjie. It is used to generate coverage reports for Cangjie programs.
Usage
You can run cjcov -h to view the command usage, as shown below. It consists of the following sections from top to bottom: Usage, Function, and Options.
Usage: cjcov [options]
A tool used to summarize the coverage in html reports.
Options:
-v, --version Print the version number, then exit.
-h, --help Show this help message, then exit.
-r ROOT, --root=ROOT The root directories of your source files, defaults to '.', the current directory.
File names are reported relative to this root.
-o OUTPUT, --output=OUTPUT The output directories of html reports, defaults to '.', the current directory.
-b, --branches Report the branch coverage. (It is an experimental feature and may generate imprecise branch coverage.)
--verbose Print some detail messages, including parsing data for the gcov file.
--html-details Generate html reports for each source file.
-x, --xml Generate a xml report.
-j, --json Generate a json report.
-k, --keep Keep gcov files after processing.
-s SOURCE, --source=SOURCE The directories of cangjie source files.
-e EXCLUDE, --exclude=EXCLUDE
The cangjie source files starts with EXCLUDE will not be showed in coverage reports.
-i INCLUDE, --include=INCLUDE
The cangjie source files starts with INCLUDE will be showed in coverage reports.
The following shows the basic command usage, where cjcov is the main program name, and --version indicates the displayed cjcov version number. Some configuration items support both long and short options, which have the same effect. You can run cjcov --help to view details.
cjcov -version or cjcov -v
How to Use
Prepare the Cangjie version package > Prepare the Cangjie source code > Use --coverage to build the Cangjie source code and generate a binary file > Run the binary file > cjcov generates the coverage statistics result.
The following is a hello world example of coverage (assuming that the current directory is WORKPATH).
-
Prepare the cangjie version package.
Assuming that the Cangjie version package is decompressed in the
WORKPATHdirectory, runsource WORKPATH/cangjie/envsetup.sh. -
Prepare the Cangjie source code.
The directory structure of the source code is as follows:
src/ └── main.cjThe source code of
main.cjis as follows:main(): Int64 { print("hello world\n") return 0 } -
Compile the source code. In this example,
cjpmis used for compilation.Run the following command in the
WORKPATHdirectory:cjpm init --name test cjpm build --coverageAfter the compilation is complete, the
default.gcnofile is generated in theWORKPATHdirectory. -
Run the compiled binary file.
Run
cjpm run --skip-buildin theWORKPATHdirectory. After the command is executed, thedefault.gcdafile is generated in theWORKPATHdirectory. -
cjcovgenerateshtmldetails.Run
cjcov -o output --html-detailsin theWORKPATHdirectory. For usage of morecjcovparameters, see Command Description.
After the cjcov command is executed, the following files are generated in the WORKPATH/output directory:
output
├── cjcov_logs (This directory stores some cjcov execution logs, which can be ignored.)
│ ├── cjcov.log
│ └── gcov_parse.log
├── index.html (Total coverage report, which can be opened in the browser.)
└── src_main.cj.html (Single file coverage. You can automatically redirected to this file by opening the index.html file.)
Command Description
cjcov -h | --help
Displays basic usage of cjcov.
cjcov -v | --version
Displays cjcov version number. Once -v or --version is specified, other options do not take effect, and only the version number is displayed. If both --version and --help are specified, the system displays version information and then exits.
cjcov --verbose
After this option is specified, some log information is generated in the cjcov_logs directory. This parameter does not take effect by default, that is, intermediate information is not printed by default. The gcov file is an intermediate file generated by cjcov. cjcov analyzes the gcov file in the following format.
==================== start: main.cj.gcov =====================
noncode line numbers:
[0, 0, 0, 0, 1, 2, 6, 7, 9, 10, 11, 15, 17, 18]
uncovered line numbers:
[5]
covered data:
[(16, 1), (3, 1), (4, 1), (8, 1), (12, 1), (13, 1), (14, 1)]
branches data:
line number: 4 ==> data: [(0, 0), (1, 1)]
===================== end: main.cj.gcov =======================
If this option is specified, the coverage data of each gcov file is displayed.
The fields are described as follows:
start: xxx.gcov, end: xxx.gcov: The text between two lines is the coverage data analyzed from thexxx.gcovfile.noncode line numbers: displays the number of a line that is not counted into total code lines. The line number is displayed in white background inhtml, and corresponds to the line starting with-in thegcovfile.uncovered line numbers: displays the data that is not covered. The data is highlighted in red inhtml, and corresponds to the line starting with#####in thegcovfile.covered data: displays the covered data in green in the form of(code line number, coverage count)inhtml. If the number of coverage times is greater than 0, the correspondingExeccolumn isYinhtml, and the data corresponds to the line starting with a digit in thegcovfile.branches data: displays the branch coverage data in the form of(code line number, branch coverage count). Inhtml, the correspondingBranchcolumn has an inverted triangle which displays Number of covered branches/Total number of branches. The data corresponds to the data starting withbranchin thegcovfile.
cjcov --html-details
If this parameter is specified, html for the Cangjie file is generated. The index file includes the index of each html subfile. The html subfiles and index.html are stored in the same directory.
The html subfile name consists of a directory and a file name, which are combined by underscores (_). If the source file is src/main.cj, the generated html file name is src_main.cj.html. If the source file path contains special characters, the special characters are replaced with =. For details, see the section File Name Contains Special Characters.
If this parameter is not specified, no html subfile is generated. The index file displays the coverage data of each html subfile, but does not support redirection to the html subfile.
This parameter does not take effect by default. That is, only one index.html file is generated by default, and no html subfile is generated.
cjcov -x | --xml
If this parameter is specified, the coverage.xml file is generated in the specified output path. The coverage.xml file records the coverage data of all files.
cjcov -j | --json
If this parameter is specified, the coverage.json file is generated in the specified output path. The coverage.json file records the coverage data of all files.
cjcov -k | --keep
If this parameter is specified, the generated gcov intermediate file is not deleted. If the gcov file is not deleted, the number of execution times is accumulated, which may affect the accuracy of coverage data.
This parameter does not take effect by default. That is, the gcov intermediate file is deleted by default.
cjcov -b | --branches
If this parameter is specified, branch coverage information is generated.
This parameter does not take effect by default. That is, the branch coverage information is not generated by default. In this case, the branch coverage percentage in the html report is displayed as -.
cjcov -r ROOT | --root=ROOT
ROOT means that the gcda file can be found in the ROOT directory or its recursive subdirectory. The gcda and gcno files are generated in the same directory by default. You are advised not to manually store the gcda and gcno files separately. Otherwise, the program may fail to run.
If the ROOT directory specified in this parameter does not exist, cjcov displays an error message.
If this parameter is not specified, the current directory is used as the ROOT directory by default.
cjcov -o OUTPUT | --output=OUTPUT
OUTPUT indicates the output path of the html coverage report.
If the OUTPUT directory and its parent directory do not exist, cjcov displays an error message. If the OUTPUT directory does not exist but its parent directory exists, cjcov creates the OUTPUT directory.
If this parameter is not specified, the current directory is used as the OUTPUT directory for storing the html file by default.
-s SOURCE | --source=SOURCE
SOURCE specifies the code path of the Cangjie source file. The total coverage report index.html contains the index of each source file. The file path is a relative path. If the -s SOURCE |--source SOURCE parameter is specified, the path in the SOURCE path list is preferentially used as the reference path of the relative path. If this parameter is not specified, -r ROOT | --root=ROOT is used as the reference path of the relative path. If neither of them is specified, the current path is used as the reference path of the relative path.
Example:
The directory structure of Cangjie code is as follows:
/work/cangjie/tests/API/test01/src/1.cj
/work/cangjie/tests/API/test01/src/2.cj
/work/cangjie/tests/LLVM/test02/src/3.cj
/work/cangjie-tools/tests/LLVM/test01/src/4.cj
/work/cangjie-tools/tests/LLVM/test02/src/5.cj
-
Run the following command in the
/workdirectory:cjcov --root=./ -s "/work/cangjie /work/cangjie-tools/tests" --html-details --output=html_outputThe relative paths of the source files displayed in the html file are as follows:
tests/API/test01/src/1.cj tests/API/test01/src/2.cj tests/LLVM/test02/src/3.cj LLVM/test01/src/4.cj LLVM/test02/src/5.cj -
Run the following command in the
/workdirectory. The--rootand--sourceparameters are not specified, and the current path is used as the reference path of the relative path by default.cjcov --html-details --output=html_outputThe relative paths of the source files displayed in the html file are as follows:
cangjie/tests/API/test01/src/1.cj cangjie/tests/API/test01/src/2.cj cangjie/tests/LLVM/test02/src/3.cj cangjie-tools/tests/LLVM/test01/src/4.cj cangjie-tools/tests/LLVM/test02/src/5.cj
-e EXCLUDE | --exclude=EXCLUDE
EXCLUDE indicates the list of source files for which coverage information does not need to be generated. You can specify directories and files.
Example:
The directory structure of Cangjie code is as follows:
/usr1/cangjie/tests/API/test01/src/1.cj
/usr1/cangjie/tests/API/test01/src/2.cj
/usr1/cangjie/tests/LLVM/test02/src/3.cj
/usr1/cangjie-tools/tests/LLVM/test01/src/4.cj
/usr1/cangjie-tools/tests/LLVM/test02/src/5.cj
Run the following command in the /usr1 directory:
cjcov --root=./ -s "/usr1/cangjie" -e "/usr1/cangjie-tools/tests/LLVM" --html-details --output=html_output
The following are the relative paths of the source files displayed in the html file. The file whose name starts with the /usr1/cangjie-tools/tests/LLVM path is not displayed in the file list of the html file.
tests/API/test01/src/1.cj
tests/API/test01/src/2.cj
tests/LLVM/test02/src/3.cj
-i INCLUDE | --include=INCLUDE
INCLUDE indicates that files whose names start with INCLUDE are displayed in the file list of index.html. You can specify directories and files. If the path specified by -e | --exclude is the same as that specified by -i | --include, an error message is displayed.
Example
The /usr1/cangjie/tests directory structure of Cangjie code is as follows:
├── API
│ └── test01
│ └── src
│ ├── 1.cj
│ └── 2.cj
└── LLVM
└── test02
└── src
└── 3.cj
Run the following command in the /usr1 directory. The -i parameter indicates that the files in the coverage report index.html need to be displayed.
cjcov --root=./ -s "/usr1/cangjie" -i "/usr1/cangjie/tests/API/test01/src/1.cj /usr1/cangjie/tests/LLVM/test02" --html-details --output=html_output
After the preceding command is executed, the file path list in index.html is as follows (tests/API/test01/src/2.cj is not in the list specified by the -i parameter and therefore is not displayed in the file list of the html file):
tests/API/test01/src/1.cj
tests/LLVM/test02/src/3.cj
Special Scenarios
Binary File Cannot Be Executed Normally
If the resident network service program cannot properly end the binary file and generate gcda coverage data, you need to manually run the exit script to generate gcda coverage data.
(1) Save the following script content as stop.sh (the script execution depends on gdb).
#!/bin/sh
SERVER_NAME=$1
pid=`ps -ef | grep $SERVER_NAME | grep -v "grep" | awk '{print $2}'`
echo $pid
gdb -q attach $pid <<__EOF__
p exit(0)
__EOF__
(2) After the resident service program completes the service logic operation coverage, run stop.sh {service_name}. If the resident service process is started by running ./main, run the following command to stop the process to generate gcda data:
sh stop.sh ./main
File Name Contains Special Characters
You are advised to name the file according to Cangjie programming specifications. It is not recommended that the file contains characters other than [0-9a-zA-Z_]. Special characters are replaced with =.
If the file name contains special characters, to ensure html correct redirection, the html file name displayed in index.html is different from the actual html file name, and the special characters in the html file name are replaced with =.
Example:
Code structure:
src
├── 1file#.cj
├── file10_abc.cj
├── file11_.aaa-bbb.cj
├── file12!#aaa!bbb.cj
├── file13~####.cj
├── file14*aa.cj
├── file15`.cj
├── file16(#).cj
├── file2;aa.cj
├── file3,?.cj
├── file4@###.cj
├── file5&cc.cj
├── file6=.cj
├── file7+=.cj
├── file8$.cj
├── file9-aaa.cj
└── main.cj
In the html file names generated, all special characters except [0-9a-zA-Z_.=] are replaced with '=':
.
├── index.html
├── src_1file=.cj.html
├── src_file10_abc.cj.html
├── src_file11_.aaa=bbb.cj.html
├── src_file12==aaa=bbb.cj.html
├── src_file13=####.cj.html
├── src_file14=aa.cj.html
├── src_file15=.cj.html
├── src_file16===.cj.html
├── src_file2=aa.cj.html
├── src_file3==.cj.html
├── src_file4=###.cj.html
├── src_file5=cc.cj.html
├── src_file6=.cj.html
├── src_file7==.cj.html
├── src_file8=.cj.html
├── src_file9=aaa.cj.html
└── src_main.cj.html
Branch Coverage
Branch coverage is still in the trial phase, branch coverage data may be inaccurate.
Currently, it is known that the following expressions may cause inaccurate branch coverage data:
-
try-catch-finallyexpression -
Loop expressions (including
forandwhileexpressions) -
if-elseexpression
Some Code Is Not Recorded in the Line Coverage Data
It is normal that some code is not recorded in the line coverage data. In general, if a line of code contains only definitions and declarations and does not contain actual executable code, the line of code is not counted in the coverage. Currently, the following scenarios are not counted:
-
Definitions of global variables. The following is an example:
let HIGH_1_UInt8: UInt8 = 0b10000000; -
Member variables are only declared but not initialized. The following is an example:
public class StringBuilder <: Collection & ToString { private var myData: Array private var mySize: Int64 private var endIndex: Int64 } -
Only the function declaration is contained, but no function body (including the
foreignfunction) is contained. The following is an example:foreign func cj_core_free(p: CPointer): Unit -
Definitions of the enumeration type. The following is an example:
enum Numeric { NumDay | NumYearDay | NumYearWeek | NumHour12 | NumHour24 | NumMinute | NumSecond } -
Definitions such as class and extend. The line where extend and class are located is not counted in the coverage data. The following is an example:
extend Int8 <: Formatter { // This line wil not account for the coverage. ... } public class StringBuilder <: Collection & ToString { // This line will not account for the coverage. ... }
The main Function in the Source Code Is Not Overwritten
Reasons: When cjc --test is used for compilation, the Cangjie test framework generates a new main function as the program entry. The main function in the source code is no longer used as the program entry and will not be executed.
Suggestions: It is recommended that you do not write extra main after using cjc --test.
FAQs
No llvm-cov Command Is Found
Solution:
Method 1: Set the CANGJIE_HOME environment variable. cjcov can find the llvm-cov command through the CANGJIE_HOME environment variable. If which cjc is displayed as /work/cangjie/bin/cjc and both the /work/cangjie/bin/llvm/bin and /work/cangjie/bin/llvm/lib directories exist, set the environment variable as follows:
export CANGJIE_HOME=/work/cangjie
Method 2: Set the environment variable in /root/.bashrc. For example, if the cjc file is stored in the /work/cangjie/bin/cjc directory, set the environment variable as follows:
export PATH=/work/cangjie/bin/llvm/bin:$PATH
export LIBRARY_PATH=/work/cangjie/bin/llvm/lib:$LIBRARY_PATH
export LD_LIBRARY_PATH=/work/cangjie/bin/llvm/lib:$LD_LIBRARY_PATH
Method 3: Run the llvm-cov command. For example, on ubuntu, run the following command:
apt install llvm-cov
VirtualMachineError OutOfMemoryError Is Displayed
Symptom:
An exception has occurred:
Error VirtualMachineError OutOfMemoryError
Solution: By default, the stack size is 1 MB and the heap size is 256 MB. You are advised to adjust the heap memory size based on the number of files. Generally, the 2 GB memory can meet the requirements in most cases. If the memory is insufficient, increase the memory size according to the actual situation.
Example:
Increase the heap memory size to 2 GB:
export cjHeapSize=2GB
Performance Analyzer
Function Description
cjprof is a performance analysis tool for Cangjie. It provides the following functions:
-
Samples CPU hotspot functions of the Cangjie programs and exports the sampling data.
-
Analyzes the sampling data of hotspot functions and generates a CPU hotspot function statistics report or flame graph.
-
Exports the heap memory information of the Cangjie applications, analyzes the information, and generates an analysis report.
Currently, cjprof runs only in Linux.
Usage
You can run cjprof --help to view the command usage. The record, report, and heap subcommands are supported. They are used to collect CPU hotspot function information, generate CPU hotspot function reports (including flame graphs), and export and analyze heap memory information.
cjprof --help
Usage: cjprof [--help] COMMAND [ARGS]
The supported commands are:
heap Dump heap into a dump file or analyze the heap dump file
record Run a command and record its profile data into data file
report Read profile data file (created by cjprof record) and display the profile
Notes:
cjprof recorddepends on theperfpermission of the system. Therefore, either of the following conditions must be met:
- You need to run the command as the
rootuser or with thesudopermission.- The system parameter
perf_event_paranoid(in the/proc/sys/kernel/perf_event_paranoidfile) is set to -1.Otherwise, you may not have the permission to run the command.
Collecting CPU Hotspot Function Information
Command
cjprof record
Format
cjprof record [<options>] [<command>]
cjprof record [<options>] -- <command> [<options>]
Option
-f, --freq <freq>: specifies the sampling frequency, in Hz. The default value is 1000 Hz. If the value is set to max or exceeds the maximum frequency supported by the system, the maximum frequency supported by the system is used.
-o, --output <file>: specifies the name of the data file generated after the sampling is complete, which is cjprof.data by default.
-p, --pid <pid>: specifies the process ID of the application to be sampled. This option is ignored when <command> is used to start a new application for sampling.
Examples
- Sample a running application.
# Sample a running application (with the process ID 12345) at a sampling frequency of 10000 Hz, and generate the sampling data in a file named sample.data in the current path after sampling.
cjprof record -f 10000 -p 12345 -o sample.data
- Start a new application and sample it.
# Run the `test` application in the current path, with arguments `arg1 arg2`, and sample it at the maximum sampling frequency. Generate the sampling data in a file named `cjprof.data` (default file name) in the current path after sampling.
cjprof record -f max -- ./test arg1 arg2
Precautions
- After sampling starts, it will not end until the sampled program exits. If you need to end the sampling earlier, you can actively stop the sampling by pressing
Ctrl+C.
Generating CPU Hotspot Function Reports
Command
cjprof report
Format
cjprof report [<options>]
Option
-F, --flame-graph: generates a CPU hotspot function flame graph instead of the default text report.
-i, --input <file>: specifies the name of the sampling data file, which is cjprof.data by default.
-o, --output <file>: specifies the name of the generated CPU hotspot function flame graph, which is FlameGraph.svg by default. This option takes effect only when a flame graph is generated.
Examples
- Generate a default text report of CPU hotspot functions.
# Analyze the sampling data in sample.data to generate a text report of CPU hotspot functions.
cjprof report -i sample.data
- Generate a flame graph of CPU hotspot functions.
# Analyze the sampling data in cjprof.data (default file) to generate a CPU hotspot function flame graph named test.svg.
cjprof report -F -o test.svg
Report Form Description
-
The report in text format contains three parts: total function sampling ratio (including subfunctions), function sampling ratio (the function itself), and function name (or address if there is no symbol information). The report results are sorted in descending order of the total function sampling ratio.
-
The horizontal axis in the flame graph indicates the sampling ratio. A wider axis indicates a larger sampling ratio, that is, a longer running time. The vertical axis indicates the call stack, with the parent function at the bottom and the child function at the top.
Exporting and Analyzing Heap Memory
Command
cjprof heap
Format
cjprof heap [<options>]
Option
-D, --depth <depth>: specifies the maximum number of layers for displaying the reference or referenced relationship of an object. The default value is 10. This option takes effect only when --show-reference is specified.
-d, --dump <pid>: exports the heap memory of the Cangjie application at the current time. pid is the application process ID. When the sub-thread ID of the application is specified, the heap memory can also be exported.
-i, --input <file>: specifies the name of the heap memory data file to be analyzed, which is cjprof.data by default.
-o, --output <file>: specifies the name of the heap memory data file to be exported which is cjprof.data by default.
--show-reference[=<objnames>]: displays the object reference relationship in the analysis report. objnames is the name of the object to be displayed. Multiple objects are separated by semicolons (;). If no object is specified, all objects are displayed by default.
--incoming-reference: displays the object referenced relationship, not the reference relationship. It needs to be used together with --show-reference.
-t, --show-thread: displays the Cangjie thread stack and the objects referenced in the stack in the analysis report.
-V, --verbose: prints the analysis logs during analysis of heap memory data files. It is a maintenance and test option.
Examples
- Export heap memory data.
# Dump the heap memory of the running application (with the process ID 12345) at the current moment to a file named heap.data in the current path.
cjprof heap -d 12345 -o heap.data
Note:
When the heap memory data is exported, the
SIG_USR1signal is sent to the process. Proceed with caution if you are not sure whether the target process is a Cangjie application. Otherwise, signals may be falsely sent to the target process, causing unexpected errors.
- Analyze heap memory data and display object information.
# Parse and analyze the heap memory data file named heap.data in the ~ directory, and display the object type name, number of instances, shallow heap size, and deep heap size of each active object in the heap.
cjprof heap -i ~/heap.data
The command output is as follows:
Object Type Objects Shallow Heap Retained Heap
==================== ============= ============= =============
AAA 1 80 400
BBB 4 32 196
CCC 2 16 32
- Analyze heap memory data and display the Cangjie thread stack and object reference.
# Parse and analyze the heap memory data file named cjprof.data (default file) in the current directory, and display the Cangjie thread stacks and the objects referenced in the stacks.
cjprof heap --show-thread
The command output is as follows:
Object/Stack Frame Shallow Heap Retained Heap
=================================== ============= =============
thread0
at Func2() (/home/test/test.cj:10)
<local> AAA @ 0x7f1234567800 80 400
at Func1() (/home/test/test.cj:20)
<local> CCC @ 0x7f12345678c0 16 16
at main (/home/test/test.cj:30)
- Analyze heap memory data and display the object reference relationship.
# Parse and analyze the heap memory data file named cjprof.data (default file) in the current directory, and display the reference relationship between objects of types AAA and BBB.
cjprof heap --show-reference="AAA;BBB"
The command output is as follows:
Objects with outgoing references:
Object Type Shallow Heap Retained Heap
=================================== ============= =============
AAA @ 0x7f1234567800 80 400
BBB @ 0x7f1234567880 32 48
CCC @ 0x7f12345678c0 16 16
CCC @ 0x7f12345678e0 16 16
BBB @ 0x7f1234567880 32 48
CCC @ 0x7f12345678c0 16 16
- Analyze heap memory data and display the object referenced relationship.
# Parse and analyze the heap memory data file named cjprof.data (default file) in the current directory, and display the referenced relationship of objects of type CCC.
cjprof heap --show-reference="CCC" --incoming-reference
The command output is as follows:
Objects with incoming references:
Object Type Shallow Heap Retained Heap
=================================== ============= =============
CCC @ 0x7f12345678c0 16 16
BBB @ 0x7f1234567880 32 48
AAA @ 0x7f1234567800 80 400
CCC @ 0x7f12345678e0 16 16
AAA @ 0x7f1234567800 80 400
Heap Memory Analysis Report
-
The object type name uses
RawArray<Byte>[],RawArray<Half>[],RawArray<Word>[], andRawArray<DWord>[]to indicate 1-byte, 2-byte, 4-byte, and 8-byte primitive arrays of basic data types, respectively. -
The shallow heap refers to the heap memory size occupied by an object. The deep heap refers to the sum of shallow heap sizes of all objects (that is, objects that can be directly or indirectly referenced only through the object) that can be released after the object is garbage collected.
-
When the reference relationship level of an object exceeds the maximum display depth or duplicate objects exist in cyclic reference,
...is used to omit subsequent references.
Exception Stack Restoration Tool
Function Description
cjtrace-recover is a Cangjie tool for restoring exception stack information.
If developers enable appearance obfuscation when compiling the Cangjie application, when the Cangjie application encounters a problem at runtime, the stack information in the thrown exception information is also in an obfuscated state. As a result, it is difficult for developers to locate the problem. cjtrace-recover helps developers restore obfuscated exception stack information to better troubleshoot faults. Specifically, cjtrace-recover can restore the following two types of exception stack information:
- Obfuscated function name
- Obfuscated path name
Usage
You can run cjtrace-recover -h to view the command usage.
cjtrace-recover -h
Usage: cjtrace-recover OPTION
Use symbol mapping files to recover obfuscated exception stacktrace. The supported options are:
-f <file> path to the obfuscated exception stacktrace file
-m <file,...> path to the symbol mapping files
-h display this help and exit
You can use the -f option to specify the file for storing exception stack information and use the -m option to specify the symbol mapping file. cjtrace-recover restores the symbol name and path name in the exception stack information based on the mappings in the symbol mapping file, and outputs the restored exception stack information is output through the standard output (stdout).
Usage Example
Assume that the exception stack information thrown by the obfuscated Cangjie program is as follows:
An exception has occurred:
MyException: this is myexception
at a0(SOURCE:0)
at ah(SOURCE:0)
at c3(SOURCE:0)
at cm0(SOURCE:0)
at cm1(SOURCE:0)
at ci0(:0)
In addition, the symbol mapping file test.obf.map outputted during obfuscation compilation is as follows:
_ZN10mymod.mod111MyException6<init>ER_ZN8std.core6StringE a0 mymod/mod1/mod1.cj
_ZN10mymod.mod115my_common_func1Ev ah mymod/mod1/mod1.cj
_ZN10mymod.mod18MyClassA7myfunc1Eld c3 mymod/mod1/mod1.cj
_ZN7default6<main>Ev cm0 test1/test.cj
user.main cm1
cj_entry$ ci0
You need to save the exception stack information, for example, test_stacktrace to a file. Run the following command to restore the exception stack information:
cjtrace-recover -f test_stacktrace -m test.obf.map
The command output is as follows:
An exception has occurred:
MyException: this is myexception
at mymod.mod1.MyException::init(std.core::String)(mymod/mod1/mod1.cj)
at mymod.mod1.my_common_func1()(mymod/mod1/mod1.cj)
at mymod.mod1.MyClassA::myfunc1(Int64, Float64)(mymod/mod1/mod1.cj)
at default.main()(/home/zzx/repos/obf_test/test1/test.cj)
cjtrace-recover restores the exception stack information on the symbol mapping file and outputs the restored information through the standard output (stdout).