In daily development, simple and elegant code not only improves the development experience, but also significantly reduces maintenance costs.Modern programming languages continue to introduce various "Syntactic Sugar" to optimize the developer experience, and Cangjie has performed well in this regard.As an engineer who has used Cangjie to develop HarmonyOS Next applications for a long time, this article will systematically sort out the modern characteristics and syntactic sugar in Cangjie's language, and analyze its value in combination with practical scenarios.
Function overload: different parameters of the same name, and the interface is more friendly
Cangjie allows multiple functions of the same name to be defined under the same scope, and calls are automatically distinguished by the number of parameters and types.
Example: Overloading absolute value function
func abs(x: Int64): Int64 {
if (x < 0) { -x } else { x }
}
func abs(x: Float64): Float64 {
if (x < 0.0) { -x } else { x }
}
main() {
println(abs(-10)) // Int version abs
println(abs(-3.14)) // Float version abs
}
Practical experience: Function overloading keeps the API interface unified and concise, improves the calling experience, and enhances the scalability of the code.
Named parameters and default values: Improve code readability and flexibility
1. Named Parameters
When calling a function, you can explicitly specify the parameter name to improve readability and flexibility:
func createUser(name!: String, age!: Int, email!: String) {
println("User: ${name}, Age: ${age}, Email: ${email}")
}
main() {
createUser(name: "Alice", age: 25, email: "alice@example.com")
}
Note: The ! symbol indicates that this is a named parameter when the parameter is defined.
|Advantages | Description |
|--|--|
|Free parameter order | No need to memorize call order |
|More readable | You can understand the meaning of each parameter when you see the call |
2. Default Values
Specify default values for function parameters, and can be omitted when calling:
func sendNotification(msg!: String, urgent!: Bool = false) {
if (urgent) {
println("URGENT: ${msg}")
} else {
println(msg)
}
}
main() {
sendNotification(msg: "Server is down!")
sendNotification(msg: "Database failure!", urgent: true)
}
- The first call uses the default
urget = false. - The second call explicitly specifies
urget = true. Practical experience: The combination of default values and named parameters makes the function API both concise and flexible, avoiding the flood of overloading.
Trailing Lambda: DSL artifact
Cangjie supports trailing Lambda syntax, simplifies code block style calls, and is suitable for domain-specific language (DSL) development.
Example: unless function
func unless(condition: Bool, f: () -> Unit) {
if (!condition) {
f()
}
}
main() {
let a = 5
unless(a > 10) {
println("Condition not met")
}
}
- The last parameter of the
unlessfunction is the function type. - When calling, you can write the Lambda directly outside and omit the brackets.
- Looks as natural as the built-in language structure. |Advantages | Scenarios | |--|--| |More natural code block syntax |Control flow, build DSL | |Readability improvement |More logic intuitive |
Pipeline operator (|>): Clearer data flow
Cangjie introduced the pipeline operator |> to simplify nested function calls and make the data flow clear at a glance.
Example: Data Processing Chain
Traditional nesting writing:
double(increment(double(double(5))))
Use the pipeline operator:
5 |> double |> double |> increment |> double
Both are equivalent, but pipe style:
- More intuitive, reading like processing data on assembly lines.
- Easier to maintain and debug. Combined with higher-order function chain processing:
[1,2,3,4,5]
|> filter({it => it % 2 == 0})
|> map({it => it * 10})
|> forEach({println(it)})
Output:
20
40
Practical experience: Pipeline operators are very practical for complex data processing chains, making logical liquidity better and avoiding deep nested bracket hell.
操作符重载:让自定义类型更自然
Cangjie supports overloading of common operators, so that custom data types can be used naturally like built-in types.
Example: Overload + Operator
struct Point {
let x: Int
let y: Int
operator func +(rhs: Point): Point {
Point(this.x + rhs.x, this.y + rhs.y)
}
}
main() {
let p1 = Point(1, 2)
let p2 = Point(3, 4)
let p3 = p1 + p2
println("${p3.x}, ${p3.y}") // 输出 4, 6
}
| Advantages | Description |
|---|---|
| Close to mathematical expression | Code is more intuition |
| Reduce redundant code | Better user experience |
Property: gracefully control field access
Cangjie has built-in ** attribute (prop/mut prop) ** mechanism, which can be controlled by getter/setter like accessing ordinary fields.
Example: Encapsulation properties
class User {
private var _name: String = ""
mut prop name: String {
get() {
println("Getting name")
_name
}
set(value) {
println("Setting name to ${value}")
_name = value
}
}
}
main() {
let user = User()
user.name = "Alice"
println(user.name)
}
Output:
Setting name to Alice
Getting name
Alice
Practical experience: Attributes can not only encapsulate logic elegantly without destroying the consistency of the object API, but are very useful when data binding, lazy loading, and debugging and monitoring.
Summary
The design of Cangjie Language in HarmonyOS Next takes into account modernity, simplicity and efficiency.This series of modern syntactic sugars has effectively improved developers' development efficiency, code quality, maintenance and scalability.
|Features|Main Improvement|
|--|--|
|Function overload|Interface unified, call naturally|
|Name parameters + default values | API design flexibility |
|Tail Lambda|Build DSL more natural|
|Pipe operators | Data flow is clearer |
|Operator overloading | Custom types seamless integration |
|Attribute mechanism | Encapsulation and ease of use |
In actual projects, mastering and using these features reasonably will improve the code level and help HarmonyOS Next application development.
Top comments (0)