So I've been thinking about this problem off and on for awhile, and I think I have a rather simple solution. I highly doubt I'm the first to think of it, but haven't found any info about a similar idea on the net. So in the interest of science I'm posting it here so anyone interested can attempt to poke holes in the idea, which you folks have been so good at in the past.

This isn't really D related, but I usually like the feedback I get from this community, plus, if there's any value in the idea, maybe it would be a worth while discussion for future directions D might make use of.

I'll be illustrating with Pseudo-code. The basic idea spawns from conceptually separating variables as either "memory owners" or "memory references". Basically, the pseudo-code has three types:

var - Memory Owner, never null, deleted at end of scope**
ref - Memory Reference, can't "own" memory
ptr - Unsafe manually managed memory pointer (like C pointers)

So, 'ptr's aside for now, 'var's would be the only way to allocate memory, and memory is automatically allocated to them at their definition**. Vars would be deleted at the end of their scope (or when they're removed from dynamic-arrays, etc) unless they're returned, in which case they're "injected" into the callers scope, and deleted at the end of that scope. Without too much lengthy explanation, here's some code:

    type Foo
    {
        var bar = 0
    }

    func main
    {
        ref f : Foo
        ref b : int

        scope
        {
            var foo = Foo # allocates Foo

            f => foo      # f points to foo
            f.bar = 1     # foo.bar = 1

            b => f.bar    # b points to foo.bar
            b = 3         # foo.bar = 3

            # auto 'clean up code' at end of scope:
            #
            #     Memory.delete(foo)
            #     f => null
            #
        }

        f.bar = 4 # ERROR: f is null

        var n = 6

        b => n
        b = 7     # n = 7

        # No clean-up code needed, 'n' is stack-allocated
        #
        # Also, notice we didn't need to set 'b' to 'null' at
        # the end of the scope, since it wasn't accessed
        # directly after the end of the scope.
    }

So this is sort of like ref-counted scopes (smart scopes), except the compiler has a higher degree of guarantee on the lifetime of memory, and there's a lot of static analysis that can happen to optimize the clean up code (like how we didn't need to assign 'b' to null in the example above). All "ref counting" would be done through static-analysis at compile-time, and injected by the compiler, so it wouldn't have the runtime overhead of ref-counting, nor would there be a need for "weak references" since references are guaranteed to never "own" memory.

There's more to it of course. For instance, in order to have expanding memory, you'd need the concepts of a dynamic-array and type inheritance. You'd also need to not clean up memory that was returned... so...

    type Foo
    {
        var name : text
        init { name = "Foo" }
        func write { Console.write(name) }
    }

    type Bar : Foo
    {
        init { name = "Bar" }
    }

    ref global_foo : Foo

    func main
    {
        var foos = Foo[]

        foos += Foo     # allocation
        foos += Foo     # allocation
        foos += Bar     # allocation
        foos[].write()  # prints: 'Foo', 'Foo', 'Bar'

        foos -= foos[1] # deallocation
        foos[].write()  # prints: 'Foo', 'Bar'

        # ---

        func getFoo
        {
            var f = Foo
            f.name = "Fip"
            return f
            # no cleanup, since 'f' is returned
        }

        global_foo = getFoo()
        global_foo.write() # prints: 'Fip'

        # auto cleanup:
        #
        #    Memory.delete(foos)
        #    Memory.delete(global_foo)
        #    global_foo => null
        #
    }

Okay, so with that you could have global var arrays, and assign global refs to function return values, etc. If you need extra control, there's also 'ptr' types, which would require manual clean-up. However, 'ptr's would be automatically cleaned when the program exist, so they would be safe to use for global references which only sometimes needed to point to usable memory.

Anyways.. comments and criticisms would be great. Sorry this isn't more D related. Like I said, I hope it does have value D might make use of at some point.

Reply via email to