RAII
Objective: Allocate resources and call given code in context of those resources. Finally clean-up resources despite of the fact if the code signalled an error or not.
Note: In the examples below 123
represents allocated resources.
Python
class Connection:
def __init__(self, address):
self.address = address
def __enter__(self):
print(f"Connection open to {self.address}")
return 123
def __exit__(self, ex_type, ex_val, ex_tb):
print("Connection closed")
with Connection("target") as conn:
print("Doing something well")
with Connection("target") as conn:
raise Exception("Doing something wrong")
Alternatively:
from contextlib import contextmanager
@contextmanager
def Connection(address):
print(f"Connection open to {address}")
try:
yield 123
finally:
print("Connection closed")
with Connection("target") as conn:
print("Doing something well")
with Connection("target") as conn:
raise Exception("Doing something wrong")
Rust
fn connection<F: FnOnce(i32) -> ()> (address: String, f: F ) { println!("Connection open to {}", address); f(123); println!("Connection closed"); } fn main() { connection("target".to_string(), |_conn|{ println!("Doing something well"); }); connection("target".to_string(), |_conn|{ println!("Doing something wrong"); }); connection("target".to_string(), |_conn|{ println!("Doing something miserably wrong"); panic!("Boo"); // connection not closed }); }
Note: doesn't meet objectives in case of a panic. However many applications are made sure that they never panic.
Crystal
def connection(address)
puts "Connection open to #{address}"
begin
yield 123
ensure
puts "Connection closed"
end
end
connection("target") do |conn|
puts "Doing something well"
end
connection("target") do |conn|
raise "Doing something wrong"
end