VOID Language lifetime & abstractions

Deterministic cleanup.
Powerful abstractions.

VOID now combines IDisposable, iterator and foreach disposal, using statements/declarations, generic method inference, extension methods, static interface contracts, constrained static calls, and default interface methods without adding a second lifetime or dispatch system.

Completed lifetime & abstraction foundation

Cleanup and abstraction reuse the machinery already underneath VOID.

Disposal lowers through the same structured cleanup model built for exceptions and finally. Generic inference and extension methods reuse normal overload resolution. Static/default interface methods extend the existing interface model rather than introducing a parallel runtime representation.

IDisposable & iterator disposal

Void.IDisposable is part of the root library contract. Collection enumerators and compiler-generated iterators can dispose deterministically, including pending iterator cleanup.

Foreach disposal

Non-array foreach disposes its enumerator on normal completion, early break, return, and exception paths through structured cleanup.

Using statements

C#-style using (...) works with disposable reference and value types, null resources, nesting, exceptions, and normal GC behavior.

Using declarations

using var and typed using declarations dispose resources at scope exit in reverse declaration order across normal and exceptional exits.

Generic method inference

Generic calls can omit explicit type arguments when VOID can infer them through the existing overload resolver and monomorphizer, including constrained and by-reference cases where inference is well-defined.

Extension methods

Static methods with a this first parameter can participate in instance-style call syntax while preserving ordinary instance-member precedence and normal overload resolution.

Static interface methods

Interfaces can require static methods as compile-time contracts, implemented by ordinary public static methods on concrete classes or structs without interface-owned static storage.

Constrained static dispatch

Generic code constrained by an interface can call required static members through the type parameter; monomorphization lowers the call to the concrete static implementation.

Default interface methods

Interface methods may provide bodies. Concrete implementations take precedence, inherited defaults provide fallback behavior, and ambiguous inherited defaults are diagnosed.

One cleanup model

using builds on finally, not beside it.

VOID already had structured exits, rethrow, GC-safe unwinding, and iterator cleanup. Deterministic disposal extends that control-flow foundation, so resource cleanup stays predictable instead of becoming another compiler-only special case.

Deterministic disposal
public sealed class GameFile : IDisposable
{
    public void Dispose()
    {
        Console.WriteLine("closed");
    }
}

using (GameFile file = new GameFile())
{
    Run(file);
}
Generic inference + extension method
public static T Identity<T>(T value)
{
    return value;
}

public static int Twice(this int value)
{
    return value * 2;
}

int value = Identity(21);
Console.WriteLine(value.Twice() == 42);
Constrained static + default interface behavior
public interface IFactory<T>
{
    static T Create();

    string Name()
    {
        return "default";
    }
}

public static T Build<T, TFactory>()
    where TFactory : IFactory<T>
{
    return TFactory.Create();
}

Iterator lifetime

Pattern-captured iterator values follow the same lifetime rules.

Pattern locals and managed intermediate values that survive yield are promoted into normal iterator state-machine storage, remain rooted through suspension and forced GC, and participate in disposal, exception, finally, and teardown cleanup without a parallel capture system.