ZetCode

Tcl finally Command

last modified April 3, 2025

The Tcl finally command is used for exception handling and cleanup operations. It ensures code executes regardless of whether an error occurs. This is crucial for resource management and maintaining program stability.

Basic Definition

The finally command is part of Tcl's exception handling mechanism. It works with try to define a block of code that always executes.

Syntax: try {body} finally {cleanup}. The finally block runs after the main body, whether it completes normally or raises an error.

Basic finally Usage

This example shows the simplest usage of finally to ensure cleanup.

basic_finally.tcl
set file [open "data.txt" w]
try {
    puts $file "Important data"
} finally {
    close $file
    puts "File closed successfully"
}

Here, the file is guaranteed to close even if writing fails. The finally block executes regardless of the try block's outcome. This prevents resource leaks.

finally with Error Handling

finally can be combined with catch for error handling.

finally_error.tcl
set result [catch {
    set file [open "nonexistent.txt" r]
    try {
        set data [read $file]
    } finally {
        close $file
    }
} errmsg]

puts "Operation result: $result"
puts "Error message: $errmsg"

This attempts to read a non-existent file. The finally ensures the file handle cleanup, while catch handles the error. Both error handling and cleanup work together.

Multiple finally Blocks

Nested try blocks can each have their own finally.

multiple_finally.tcl
set file1 [open "file1.txt" w]
set file2 [open "file2.txt" w]

try {
    try {
        puts $file1 "Data for file1"
        puts $file2 "Data for file2"
    } finally {
        close $file2
        puts "Closed file2"
    }
} finally {
    close $file1
    puts "Closed file1"
}

This demonstrates nested resource management. Each file gets its own cleanup block. The inner finally runs first, then the outer one.

finally with Return

finally executes even when the try block uses return.

finally_return.tcl
proc test_finally {} {
    set file [open "temp.txt" w]
    try {
        puts $file "Test data"
        return "Early return"
    } finally {
        close $file
        puts "Cleanup done despite return"
    }
}

puts [test_finally]

The procedure returns early, but the finally still runs. This shows finally has higher priority than normal control flow. Resources are properly released.

finally in Loops

finally can be used within loops for per-iteration cleanup.

finally_loop.tcl
foreach file {"a.txt" "b.txt" "c.txt"} {
    set handle [open $file w]
    try {
        puts $handle "Data for $file"
    } finally {
        close $handle
        puts "Closed $file"
    }
}

This processes multiple files with guaranteed cleanup for each. The finally block runs after each iteration, not just at loop end. This prevents accumulation of open handles.

Complex finally Scenario

This shows a more complex scenario with multiple resources and error points.

complex_finally.tcl
set db [sqlite3 open test.db]
set file [open "log.txt" a]

try {
    $db eval {CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)}
    puts $file "Database table created"
    
    $db eval {INSERT INTO users VALUES (1, 'John')}
    puts $file "User inserted"
    
    # Simulate error
    error "Forced error"
} finally {
    $db close
    close $file
    puts "All resources released"
}

This handles database and file operations with comprehensive cleanup. Even with the forced error, both resources are properly closed. The finally block provides robust cleanup.

Best Practices

This tutorial covered the Tcl finally command with practical examples showing its usage in different scenarios for robust error handling.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Tcl Tutorials.