Destructors

XXML implements RAII (Resource Acquisition Is Initialization) through destructors that automatically clean up resources when objects go out of scope.

Basic Syntax

xxml
[ Class <MyClass> Final Extends None
    [ Private <>
        Property <resource> Types NativeType<"ptr">^;
    ]

    [ Public <>
        Constructor Parameters () -> {
            Set resource = Syscall::malloc(1024);
        }

        Destructor Parameters () -> {
            Run Syscall::free(resource);
        }
    ]
]

Automatic Cleanup

Destructors are called automatically when a variable goes out of scope:

xxml
[ Entrypoint
    {
        // Constructor called here
        Instantiate MyClass^ As <obj> = MyClass::Constructor();

        // ... use obj ...

        // Destructor called automatically at end of scope
    }
]

Note

The compiler automatically inserts destructor calls at the end of each scope, ensuring resources are cleaned up even if the program exits early.

Use Cases

File Handles

xxml
[ Class <FileHandle> Final Extends None
    [ Private <>
        Property <handle> Types NativeType<"ptr">^;
    ]

    [ Public <>
        Constructor Parameters (Parameter <path> Types String%) -> {
            Set handle = openFile(path);
        }

        Destructor Parameters () -> {
            Run closeFile(handle);
        }

        Method <read> Returns String^ Parameters () Do {
            // Read from file
        }
    ]
]

Lock Guards

xxml
[ Class <LockGuard> Final Extends None
    [ Private <>
        Property <mutex> Types Mutex&;
    ]

    [ Public <>
        Constructor Parameters (Parameter <m> Types Mutex&) -> {
            Set mutex = m;
            Run mutex.lock();
        }

        Destructor Parameters () -> {
            Run mutex.unlock();
        }
    ]
]

Destructor Chaining

When a class has properties that are themselves objects with destructors, those destructors are called in reverse order of construction:

xxml
[ Class <Container> Final Extends None
    [ Private <>
        Property <buffer> Types Buffer^;
        Property <logger> Types Logger^;
    ]

    [ Public <>
        Constructor Parameters () -> {
            // logger constructed first, buffer second
            Set logger = Logger::Constructor();
            Set buffer = Buffer::Constructor();
        }

        Destructor Parameters () -> {
            // buffer destructor called first, logger second
            // (reverse order)
        }
    ]
]

Best Practices

  • Always pair resources: If your constructor acquires a resource, your destructor should release it
  • Keep destructors simple: Avoid complex logic or operations that might fail
  • Use RAII wrappers: Create small classes to manage specific resources
  • Don't throw from destructors: Avoid operations that might cause errors during cleanup

Next Steps

Learn about Ownership to understand how destructors integrate with XXML's memory management system.