首页 > AI前沿 > CobaltC – The Successor to C?

CobaltC – The Successor to C?

Hacker News 2026-08-31 10:26 6 阅读 查看原文
1. Introduction CobaltC is a statically typed systems programming language providing: explicit ownership; deterministic destruction; compiler-checked borrowing; inferred lifetimes; explicit nullability; bounds-safe operations; structured error handling; safe concurrency; explicit unsafe operations; explicit foreign-function interfaces. The language is intended for software requiring predictable resource management, strong memory safety, native execution and controlled interaction with low-level facilities. CobaltC does not require tracing garbage collection. 2. Normative Terminology The words MUST, MUST NOT, SHOULD, SHOULD NOT, and MAY are normative. Implementation-defined means that an implementation chooses the behavior and documents that choice. Undefined behavior is behavior for which this specification imposes no requirements. Safe CobaltC operations MUST NOT introduce undefined behavior merely through ordinary use. 3. Source Files A CobaltC program consists of one or more source modules. Source text is Unicode. Identifiers are case-sensitive. Whitespace separates lexical tokens where necessary and otherwise has no semantic meaning. 4. Comments CobaltC supports line comments: // comment and block comments: /* comment */ Comments have no semantic effect. 5. Keywords The following are reserved: as break case const continue defer else enum extern false fn for if import in interface loop match move mut null return static struct true type unsafe while let is not a CobaltC 1.0 keyword. 6. Identifiers An identifier begins with a Unicode identifier-start character and may contain subsequent identifier characters and digits. Identifiers are case-sensitive. The following therefore represent distinct names: value Value VALUE 7. Literals CobaltC provides: integer literals; floating-point literals; character literals; string literals; Boolean literals; null. Numeric literals MAY use separators where supported by the implementation, provided separators do not alter their value. 8. Modules A module declaration has the form: module example; A module establishes a namespace. Modules MAY import declarations from other modules: import io; Name resolution is lexical and module-aware. An unresolved name is a compile-time error. 9. Declarations CobaltC provides: const static type struct enum interface fn Declarations are introduced into their applicable lexical or module namespace. Inner declarations MAY shadow outer declarations where permitted. 10. Variables A variable is declared using: i32 count = 0; A mutable variable is declared: mut i32 count = 0; An uninitialized declaration is permitted: i32 result; but result MUST be initialized before it is read. 11. Constants Constants use: const i32 maximum = 100; A constant initializer MUST satisfy the implementation's constant-expression requirements. A constant cannot be mutated. 12. Primitive Types CobaltC defines: bool char i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 isize usize f32 f64 The fixed-width integer types have exactly their specified widths. isize and usize are pointer-sized integer types. 13. Compound Types CobaltC supports: structs enums tuples arrays function types managed references raw pointers generic types interface-constrained types Structs and enums are nominal types. Type aliases do not create new nominal types. 14. Managed References The notation: T* represents a managed non-null reference. The notation: T*? represents a nullable managed reference. Managed references participate in ownership, borrowing and lifetime checking. 15. Raw Pointers Raw pointers are represented: raw T* Raw pointers are outside the ordinary managed ownership and lifetime guarantees. Raw-pointer dereference and unrestricted pointer manipulation require an unsafe context. 16. Mutability A mutable binding permits mutation through that binding where no ownership or borrowing rule prohibits the operation. Mutability does not override aliasing rules. For example, having a mutable owner does not permit mutation while an incompatible borrow remains active. 17. Type Compatibility Assignments, function arguments and return values MUST have compatible types. Implicit conversions MUST NOT silently: remove nullability; create ownership; destroy ownership; violate mutability; invalidate a lifetime guarantee; perform unsafe reinterpretation. Explicit conversion facilities MAY be provided. 18. Type Inference CobaltC permits inference where the language grammar and context establish a unique type. Inference MUST preserve all semantic distinctions relevant to: ownership; mutability; nullability; borrowing; lifetime. Inference MUST NOT make an unsafe operation appear safe. 19. Generic Types Generic types and functions are statically checked. Example: fn identity (T value) -> T { return value; } Generic constraints MUST be satisfied before a generic entity is used. 20. Interfaces Interfaces define required operations. Example: interface Printable { fn print(); } A generic constraint may require an implementation: T: Printable The compiler MUST verify that required interface operations exist. 21. Structs A struct defines a nominal aggregate: struct Point { i32 x; i32 y; } Struct fields have declared types. Owned fields participate in the enclosing value's ownership and destruction semantics. 22. Enums An enum defines a finite set of variants: enum Status { Ready, Running, Failed } Variants MAY contain associated values: enum Result { Ok(T), Err(E) } 23. Tuples Tuples combine a fixed number of values. Tuple elements are independently typed. Tuple ownership follows the ownership rules of their elements. 24. Arrays Arrays contain a fixed number of elements: T[N] The length is part of the array type. Safe indexing MUST remain within the valid range. 25. Functions A function is declared: fn add(i32 a, i32 b) -> i32 { return a + b; } The number and types of arguments MUST match the function signature. Ownership and borrowing requirements apply to arguments and return values. 26. Expressions Expressions produce values or perform operations. The core expression categories include: names; literals; calls; construction; member access; indexing; borrowing; unary operators; binary operators; assignment. 27. Operator Precedence From highest to lowest: Binary operators are left-associative unless otherwise specified. Assignment is right-associative. 28. Arithmetic Integer and floating-point operations follow the semantics of their respective types. An operation that cannot safely produce the required result MUST follow the type's specified overflow or failure semantics. Safe arithmetic MUST NOT silently produce memory corruption. 29. Equality Equality requires compatible operands. Value equality compares values according to the type's equality semantics. Where pointer identity is explicitly requested, pointer equality compares identity rather than recursively comparing referents. 30. Assignment Assignment requires a valid mutable destination. Compound assignment follows the corresponding arithmetic or bitwise operation. Assignment does not implicitly transfer ownership unless the operation constitutes a move. 31. Function Calls A call is valid only if: the function is resolvable; the argument count is correct; arguments have compatible types; ownership transfers are valid; borrows remain valid; generic constraints are satisfied. 32. Conditional Execution CobaltC provides: if condition { ... } else { ... } The condition MUST satisfy the Boolean condition requirements. 33. Loops CobaltC provides: while for loop break exits the applicable loop. continue begins the next iteration. 34. Match Pattern matching is provided by match: match value { Some(x) => use(x), None => use_default() } A match over an exhaustively known variant set MUST handle every possible case. The compiler MUST reject statically non-exhaustive matches. 35. Return return transfers control from the current function. Returning an owned value transfers ownership to the caller. Returning a reference is permitted only if its lifetime remains valid after the function returns. A reference to an ordinary local variable MUST NOT be returned. 36. Defer defer schedules work for scope exit: { defer { close_resource(); } use_resource(); } Deferred blocks execute in reverse registration order. Deferred operations themselves obey ordinary ownership and lifetime rules. 37. Definite Initialization A value MUST be initialized before it is read. The compiler MUST perform control-flow-sensitive definite-initialization analysis. This is invalid: i32 value; if condition { value = 10; } print(value); unless the compiler can prove that every path reaching print initializes value. 38. Ownership Ownership is a fundamental part of CobaltC's type and runtime model. An owned value has one responsible owner unless its type explicitly implements shared ownership. The owner is responsible for eventual destruction. 39. Move Semantics A move transfers ownership. File a = open("data.txt")?; File b = move a; After the move, a MUST NOT be used as an owner of the transferred value. A moved-from binding MAY remain in scope, but its moved value is unavailable except as permitted by explicitly defined partial-move rules. 40. Copy Semantics A type may support copying. Implicit copying is permitted only when the type's semantics explicitly permit it. Copying produces an independent value according to the type's copy contract. Copying is not ownership transfer. 41. Partial Moves For aggregate values, an individual owned component MAY be moved independently when the compiler can track the resulting state. A moved component cannot subsequently be used through its original ownership path. Unaffected independent components MAY remain usable. 42. Borrowing A borrow provides access without transferring ownership. A shared borrow provides read access. A mutable borrow provides exclusive mutable access. The fundamental rule is: zero or more compatible shared borrows OR one mutable borrow Conflicting borrows MUST be rejected. 43. Borrow Lifetime A borrow's lifetime MUST NOT exceed the lifetime of its referent. The compiler normally infers ordinary lifetimes. The compiler SHOULD choose the shortest valid lifetime consistent with all uses. 44. Reborrowing A borrow may be temporarily reborrowed when the resulting borrow relationship remains valid and the aliasing rules continue to hold. Reborrowing does not transfer ownership. 45. Aliasing Safe code MUST NOT create an aliasing configuration that violates the ownership model. A mutable access cannot coexist with an incompatible shared or mutable access. This rule applies across library abstractions as well as direct language operations. 46. Collection Borrowing If a collection operation may invalidate references into the collection, the operation MUST NOT occur while an incompatible borrow remains live. For example: mut Vec values = Vec ::new(); i32* first = &values[0]; values.push(10); is rejected when the operation may invalidate first. 47. Destruction Owned values are destroyed deterministically. An ownership responsibility is destroyed exactly once. Moved-from ownership does not cause a second destruction. 48. Scope Destruction For ordinary scope exit: deferred blocks execute; owned locals are destroyed in reverse declaration order; control proceeds to the enclosing scope. An implementation MUST preserve the observable consequences of this ordering. 49. Unwinding If the implementation supports unwinding, scopes exited by supported unwinding MUST perform their specified destruction. An implementation may implement panic unwinding using internal exception mechanisms. 50. Abort An abort terminates execution immediately. Normal destruction is not guaranteed after an abort. 51. Nullability Nullable values are explicitly represented by nullable types. null cannot inhabit a non-nullable type. Before dereferencing a nullable reference, the compiler MUST establish that it is non-null. Flow-sensitive refinement is permitted. 52. Bounds Safety Safe indexing MUST remain within valid bounds. The compiler MAY eliminate runtime bounds checks when validity has been proven statically. Unchecked indexing belongs to unsafe facilities. 53. Option The canonical optional-value type is: enum Option { Some(T), None } Option represents the presence or absence of a value. 54. Result The canonical recoverable-error type is: enum Result { Ok(T), Err(E) } Expected operational failures SHOULD be represented using Result. 55. Error Propagation The ? operator propagates a compatible error from the current operation to the enclosing function. It is not an exception mechanism. 56. Strings String owns UTF-8 text storage. Str represents borrowed UTF-8 text. A valid text value MUST contain valid UTF-8. Arbitrary bytes require byte-oriented APIs. 57. Vec Vec owns dynamically allocated contiguous storage. Its capacity MAY exceed its current length. Operations that change storage in ways that could invalidate active references are governed by the borrowing rules. 58. Slices A slice provides borrowed access to contiguous storage. A slice does not own the underlying storage. A mutable slice provides exclusive mutable access subject to ordinary borrow checking. 59. Box Box represents unique heap ownership. Destroying the Box releases its owned allocation and contained value according to normal destruction rules. 60. Rc Rc provides reference-counted shared ownership in contexts where its concurrency restrictions are satisfied. Reference-counted cycles can prevent destruction. 61. Arc Arc provides shared ownership suitable for concurrent transfer when its contained type satisfies the applicable safety constraints. Reference counting does not itself provide synchronization for arbitrary interior mutation. 62. Weak Weak provides non-owning access to reference-counted objects. A weak reference does not keep its target alive. 63. Threads CobaltC supports concurrent execution through threads. A value transferred to another thread MUST satisfy the required ownership and thread-transfer constraints. A thread MUST NOT retain an ordinary borrow to a local value that can cease to exist before the borrow is used. 64. Synchronization Shared mutable state requires synchronization. The standard synchronization abstractions include: Mutex RwLock Atomic Channel Synchronization guards own their applicable lock state and release it on destruction. 65. Mutex A mutex provides exclusive synchronized access. A lock guard maintains the ownership of the lock while the guard is live. Destroying the guard releases the lock. 66. RwLock A read/write lock permits: multiple compatible readers; or one writer. It MUST NOT simultaneously expose incompatible read and write access. 67. Atomics Atomic operations are indivisible according to the specified atomic type and memory-order semantics. Atomicity does not itself establish ownership or higher-level synchronization. 68. Channels Channels provide communication between execution contexts. Sending a move-only value transfers its ownership according to the channel contract. The sender MUST NOT subsequently use the moved value as its owner. 69. Data Races Safe CobaltC code MUST NOT contain an ordinary unsynchronized data race. The language does not guarantee freedom from logical concurrency errors such as deadlocks or livelocks. 70. Memory Model The memory model defines the ordering guarantees of synchronization and atomic operations. Implementations MAY reorder operations internally provided observable behavior remains consistent with the language's memory model. 71. Unsafe Blocks Unsafe operations require an explicit unsafe context: unsafe { ... } Unsafe permits operations requiring programmer-supplied invariants. It does not make an invalid operation intrinsically correct. 72. Raw Memory Raw-pointer dereference, unchecked memory manipulation and manual allocation/deallocation are unsafe facilities. An implementation MUST NOT treat arbitrary raw memory as automatically satisfying CobaltC's type, lifetime or ownership requirements. 73. Safe Abstractions over Unsafe Code Unsafe implementation code MAY be encapsulated by a safe API. Such an API is valid only if its implementation maintains all invariants promised by its safe interface. 74. Foreign Functions Foreign functions require explicit declarations. The baseline foreign ABI is the C ABI. Foreign functions are not assumed to obey CobaltC ownership, lifetime or safety rules. 75. FFI Ownership Ownership crossing an FFI boundary MUST be defined by the API contract. Possible contracts include: borrowed for call duration caller transfers ownership callee transfers ownership caller retains ownership foreign runtime owns value The ABI alone does not determine ownership. 76. ABI Profiles A target ABI profile specifies at minimum: architecture operating system pointer width endianness alignment calling conventions C ABI mapping atomic capabilities runtime model Binary compatibility is guaranteed only where compatible ABI profiles are used. 77. Runtime A hosted CobaltC program begins through main. The runtime provides the facilities required by the language and standard library, including: allocation; destruction; process integration; panic handling; I/O; concurrency; platform integration. The internal runtime architecture is implementation-defined. 78. Allocation Managed allocation must either produce a valid allocation or produce the specified allocation failure. An implementation MUST NOT expose an invalid managed object as the result of failed allocation. 79. Panic A panic represents an unrecoverable program/runtime failure. An implementation MAY unwind or terminate according to its runtime configuration, provided the selected behavior conforms to the applicable CobaltC rules. 80. Standard I/O Expected I/O failures are represented using Result-style APIs. Typical operations include: open read write close Resource-owning I/O objects release their resources deterministically. 81. Standard Concurrency Types The standard library baseline includes facilities corresponding to: Thread Mutex RwLock Atomic Channel Arc Their implementations may differ by target but their observable contracts MUST conform. 82. Security and Safety Boundary CobaltC's safety guarantees apply to conforming safe code. They do not guarantee: algorithmic correctness; absence of deadlocks; absence of resource exhaustion; absence of denial-of-service conditions; correctness of unsafe code; correctness of foreign code; correctness of violated API preconditions. 83. Diagnostics A conforming compiler MUST reject programs violating normative static rules. Diagnostic categories include: syntax error name-resolution error type error initialization error ownership error use-after-move borrow conflict lifetime violation nullability violation bounds violation non-exhaustive match generic constraint failure invalid assignment Exact diagnostic wording is not normative. Implementations SHOULD identify relevant source locations and, where practical, explain ownership and lifetime relationships. 84. Implementation-Defined Behavior Any implementation-defined property MUST be documented. A compiler cannot claim conformance while silently choosing behavior contrary to a normative requirement. 85. Extensions An implementation MAY provide extensions. Extensions MUST be distinguishable from standard CobaltC behavior. An extension MUST NOT silently change the semantics of a valid CobaltC 1.0.0 program. 86. Conformance Levels Core Conformance Requires the language syntax, type system, static semantics, ownership, borrowing, lifetimes and core safety guarantees. Standard Conformance Requires Core plus the mandatory standard-library baseline. Platform Conformance Requires Standard plus a complete declared runtime and ABI profile for the target. An implementation claiming conformance MUST state its level. 87. Conformance Testing A conformance suite MUST contain positive and negative tests covering: lexing parsing name resolution typing initialization ownership moves copying borrowing lifetimes destruction nullability bounds patterns generics interfaces Option Result collections strings concurrency unsafe boundaries runtime behavior FFI ABI diagnostics regressions A negative test passes when the implementation rejects a program that violates a normative rule. A positive test passes when the implementation accepts a conforming program and provides behavior consistent with the specification. 88. Compatibility A CobaltC 1.0.0 program has stable meaning under conforming implementations. Optimization level MUST NOT change its specified observable semantics. Binary compatibility is separate from source compatibility and depends on the applicable ABI profile. 89. Versioning CobaltC 1.0.0 is a closed language edition. Changes after publication are classified as: editorial corrections; specification errata; future-version language changes. A semantic change MUST NOT be silently presented as CobaltC 1.0.0 behavior. 90. Final Safety Theorem The central semantic guarantee of CobaltC is: A conforming implementation executing conforming safe CobaltC code MUST preserve ownership, initialization, borrowing, lifetime, nullability, bounds and synchronization requirements defined by this specification. In particular, ordinary safe CobaltC operations cannot be used to create: use-before-initialization; use-after-move; double ownership; invalid borrow lifetime; conflicting mutable aliasing; unchecked nullable dereference; unchecked safe out-of-bounds access; ordinary unsynchronized data races. Unsafe and foreign code lie outside these automatic guarantees. 91. Final Reference Model The complete language model is: COBALT VALUE | +-----------+-----------+ | | OWNED BORROWED | | +-----+-----+ lifetime checked | | MOVE COPY | | ownership explicit transfer capability | v deterministic destruction with the following static safety layers: TYPE CHECKING | DEFINITE INITIALIZATION | OWNERSHIP CHECKING | BORROW CHECKING | LIFETIME CHECKING | NULL CHECKING | BOUNDS CHECKING | CONCURRENCY SAFETY | EXPLICIT UNSAFE BOUNDARY 92. Final Status CobaltC Programming Language Specification 1.0.0 Status: FINAL The design is frozen. This document is the consolidated normative baseline. Further changes belong either in editorial corrections/errata or in a subsequent language edition. A Conformance/Example-Program Example This example defines a generic Stack backed by Vec , then demonstrates creating a stack, pushing values, popping values, and handling an empty-stack error. module stack_example; enum Result { Ok(T), Err(E) } enum StackError { Empty } struct Stack { Vec values; } fn Stack_new () -> Stack { return Stack { values: Vec ::new() }; } fn Stack_push (mut Stack * stack, T value) { stack.values.push(value); } fn Stack_pop (mut Stack * stack) -> Result { if stack.values.len() == 0 { return Err(StackError::Empty); } return Ok(stack.values.pop()); } fn Stack_is_empty (Stack * stack) -> bool { return stack.values.len() == 0; } fn main() -> i32 { Stack stack = Stack_new (); Stack_push (&stack, 10); Stack_push (&stack, 20); Stack_push (&stack, 30); match Stack_pop (&stack) { Ok(value) => { print(value); }, Err(StackError::Empty) => { print("stack is empty"); } } match Stack_pop (&stack) { Ok(value) => { print(value); }, Err(StackError::Empty) => { print("stack is empty"); } } return 0; } Semantics Visible in the Example The example intentionally exercises several of the normative semantic rules established by the CobaltC 1.0 specification. Generic types: Stack is a generic nominal type and can be instantiated as Stack . Ownership: Stack stack owns the stack value. The stack in turn owns its contained Vec . Deterministic destruction: when stack leaves its scope, its owned contents are destroyed according to CobaltC's deterministic destruction rules. Borrowing: &stack provides access to the existing stack without transferring ownership to Stack_push or Stack_pop. Mutable borrowing: the mut Stack * parameter permits the called function to modify the borrowed stack while remaining subject to CobaltC's aliasing rules. Ownership-preserving access: Stack_is_empty accepts a non-mutating borrow because it only needs to inspect the stack. Result-based error handling: Stack_pop returns Result instead of using exceptions. Pattern matching: the match expressions distinguish between Ok and Err. Exhaustive matching: both variants of the returned Result are handled, making the match exhaustive. Type safety: the stack is specifically instantiated as Stack , so values inserted into it must satisfy the stack's element type. Bounds safety: the example delegates element removal to Vec rather than performing unchecked indexing. Move semantics: a successful pop transfers the resulting element out of the collection rather than copying it implicitly. Expected Behaviour The three values are pushed in the order 10, 20, 30. Because the stack is last-in, first-out, the first two successful calls to Stack_pop produce: 30 20 If another pop is attempted after the stack is empty, the operation produces Err(StackError::Empty) rather than performing an invalid access. Conformance Significance This is useful as a conformance/example-program example because it exercises the interaction between several parts of the specification rather than testing an isolated feature. In particular, it combines generic types, owned values, borrowing, mutable access, collection semantics, deterministic destruction, Result-based error handling, and exhaustive pattern matching.