Skip to content

Structures and Classes ​

Implementation status: struct / class / data class / actor / enum Implemented (including final class Phase 60, data class Phase 50–52 proof macros); inheritance and polymorphism GA (Phase 51–55 + Phase 66 vtable)

SYX provides five kinds of type declaration: struct (value), class (reference), data class (immutable record), actor (concurrency isolation), and enum (ADT, see Chapter 9). This chapter explains "which one to use when" and their memory semantics.

struct ​

A value-type field aggregate. Since Phase 70+, value semantics have been gradually becoming GA (earlier it was an MVP):

swift
struct Point {
    var x: Int
    var y: Int
}

func main() {
    let p = Point(x: 1, y: 2)
    print(p.x)                             // 1
    print(p.y)                             // 2
}
FeatureStatus
Fields var / letImplemented
Construction (in field order)Implemented: Point(1, 2)
mutating funcPartially implemented (basically usable since Phase 60)
Full value-type copyPartially implemented (deep-copy boundaries still evolving)
Codable synthesisThrough the @Codable macro (data class preferred)
swift
struct Counter {
    var value: Int = 0
    mutating func increment() { value = value + 1 }
}

var c = Counter()
c.increment()
print(c.value)                             // 1

mutating: marks methods that modify self; the caller must use var (not let). Calling an unmarked-but-mutating method on a let → S020.

Value semantics: struct assign copies (R-38 · SEM-STRUCT) ​

Assigning a struct copies; mutating the copy must not change the original:

swift,output
// prints: 1\n9
struct Point {
    var x: Int
}

func main() {
    var p = Point(x: 1)
    var q = p
    q.x = 9
    print(p.x)
    print(q.x)
}

class ​

A reference-type object. A SYX class uses ARC reference counting plus the class ObjectRef (since Phase 73):

swift
class Greeter {
    var name: String

    init(name: String) {
        self.name = name
    }

    func hello() {
        print("Hello, \(self.name)")
    }
}

func main() {
    let g = Greeter(name: "World")
    g.hello()                               // "Hello, World"

    let g2 = g                              // Shared reference
    g2.name = "SYX"
    print(g.name)                           // "SYX" (same object)
}
FeatureStatus
Fields var / letImplemented
initImplemented (see Chapter 15)
deinitPartially implemented (triggered when a class ARC count reaches zero, Phase 102/103)
InheritanceGA (Phase 51–55 + Phase 66 vtable)
overrideGA (polymorphic dispatch)
Reference semanticsImplemented

Source: crates/syx-driver/tests/fixtures/parity/inheritance_dispatch.sy

final class ​

Since Phase 60, final class declares a closed type that forbids subclassing:

swift
final class Token {
    let value: String
    init(value: String) { self.value = value }
}
  • final forbids subclassing
  • final lets the compiler devirtualize (static calls)
  • For ADT variant families, use enum (switch exhaustiveness MVP)

data class ​

A declarative syntax for immutable records. The Phase 50–52 proof macros synthesize == / hash / encode / decode automatically on a stored-property data class:

swift
@Equatable
@Hashable
@Codable
data class Point(x: Int, y: Int)

func main() {
    let p1 = Point(x: 1, y: 2)
    let p2 = Point(x: 1, y: 2)
    print(p1 == p2)                        // true
    print(p1.description())                // "Point(x: 1, y: 2)"

    let json = p1.encode()                 // "{\"x\":1,\"y\":2}"
    let back = Point.decode(text: json)
    print(back == p1)                      // true
}
CapabilityStatus
Automatic constructionImplemented (field order)
Automatic description()Implemented ("Type(field: value, ...)")
@Equatable synthesizing ==GA (L1 stored data class)
@Hashable synthesizing hash(into:)GA (L1)
@Codable synthesizing encode/decodeGA (L1 stored); L2 associated-value enums fully automatic
Swift-style automatic copyNot implemented
Hashable L2 genericsNot implemented

Usable without macros: even without @Equatable / @Hashable / @Codable, you still get description(); writing the macros adds witnesses.

There is no Swift-style automatic copy (Not implemented); use explicit construction / with for now:

swift
struct Point {
    var x: Int
    var y: Int
}

func with(_ p: Point, x: Int) -> Point {
    return Point(x: x, y: p.y)
}

ADT Variant Families ​

For closed algebraic data types, use an enum (not the sealed keyword — the lexer has no such keyword):

swift
enum Result<T, E> {
    case ok(T)
    case err(E)
}

History: documentation before Phase 50 described a sealed class; the current lexer does not accept sealed. Use enum for ADTs and final class to forbid subclassing.

actor ​

A concurrency-isolated object (see Chapter 18):

swift
actor Counter {
    var value: Int = 0
    func increment() { self.value = self.value + 1 }
    func current() -> Int { return self.value }
}

let c = Counter()
await c.increment()                       // await is required
print(await c.current())                  // 1
  • actor state is isolated from the outside
  • Cross-actor access requires await
  • Isolation violations → A002 / C001

Selection Guide ​

ScenarioChooseReason
Simple data carrier, needs == / Hashabledata classAutomatic synthesis, minimal code
Shared mutable state, reference semanticsclassARC, reference equality
Concurrency-safe stateactorIsolation, no locks
Value type, stack allocated, performance sensitivestructZero heap allocation
Closed variant family (ADT)enumExhaustiveness + pattern matching
Expressing errors, state machinesenumResult / Optional / Status

Memory Semantics Compared ​

TypeMemoryCopySharing
structStack / inlinedValue copy (partially implemented)Not shared
classHeap (ARC)Reference assignment (shared)Shared
actorHeap (isolated)ReferenceIsolation queue
data classHeap (value semantics)Reference (immutable recommended)Reference
enumStack / heap (per case)Depends on the caseDepends on the case

Complete Example ​

swift
@Equatable
data class User(name: String, age: Int)

class Account {
    let owner: User
    var balance: Int

    init(owner: User, balance: Int) {
        self.owner = owner
        self.balance = balance
    }

    func deposit(_ amount: Int) {
        self.balance = self.balance + amount
    }
}

actor Bank {
    var accounts: Array<Account> = []
    func open(_ a: Account) { self.accounts.append(a) }
    func count() -> Int { return self.accounts.count }
}

func main() {
    let u = User(name: "Alice", age: 30)
    let a = Account(owner: u, balance: 100)
    a.deposit(50)
    print(a.balance)                       // 150
}

Diagnostics ​

CodeTriggerFix
S001Duplicate definitionRename the type
S004Field type mismatchFix it
S010Protocol not satisfiedAdd the conformance
A002Cross-actor access without awaitAdd await
R007! on an Optional fieldUse ?. / if let

Differences from Swift ​

Swift structSYX
Full value-semantics copyPartially implemented
mutating funcImplemented (Phase 60+)
Full class single inheritance + finalImplemented
actor isolationImplemented
data class automatic ==/hash/encodeGA (L1 stored)
Swift-style automatic copyNot implemented
isolated deinitNot implemented (an explicit class deinit is implemented)
inout parametersNot implemented; borrow with &mut T (partially implemented)
Nested typesPartially implemented (see Chapter 21)

Next chapter → Properties

See also → Language Reference: Declarations · Chapter 9, Enumerations · Chapter 11, Properties · Chapter 14, Inheritance · Chapter 19, Macros

SYX · Apache-2.0