lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


I had been contemplating building something like Cocoa's autorelease pool
mechanism to work around the inability to yield across a pcall. (So many
ideas for code to write. So little time to actually write code.)

However, given a cheaper, yield-friendly pcall, it may be just as easy to
write:

    function processWithFinalizer( finalizer, success, ... )
        pcall( finalizer )
        if success then
            return ...
        else
            error( select( 1, ... ), 2 )
        end
    end

    function withFileDo( path, func )
        local file = assert( io.open( path ) )
        return processWithFinalizer(
            function()
                file:close()
            end,
        pcall( func, file ) )
    end

Interestingly, the RVM version seems to fix an error in Lua 5.1 in which in
the following code the value of file in the above finalizer has been rebound
to 1:

    withFileDo( myFilePath, -- insert valid file path here
        function( f )
            print( f )
            return 1, 2, 3
        end )

Mark

P.S. One could actually reduce the number of closures being generated while
running this code by doing various things like passing an extra argument to
processWithFinalizer or by writing a custom version that works specifically
with files. That can all be encapsulated as follows:

    function makeProcessWithFinalizer( finalizer )
        -- returns a function taking an argument for the finalizer plus
        -- the results to pass back up from a pcall

        return function( finalizerArg, success, ... )
            pcall( finalizer, finalizerArg ) -- skip the pcall if gutsy
            if success then
                return ...
            else
                error( select( 1, ... ), 2 )
            end
        end
    end

    ----

    local fileFinalizer = makeProcessWithFinalizer(
            function( file ) file:close() end )

    function withFileDo( path, func, ... )
        -- Calls func( file, ... ) where file is the result of
        -- opening the path. Closes the file when done.

        local file = assert( io.open( path ) )
        return fileFinalizer( file, pcall( func, file, ... ) )
    end