Announcing bracket.cr - Safe Resource Management Pattern

Hello Crystal community!

I’m excited to share a new shard called bracket that implements the bracket pattern for safe resource management in Crystal. This pattern, similar to Python’s context managers or Haskell’s bracket pattern, ensures resources are properly initialized and cleaned up, even when exceptions occur.

Basic Usage

require "bracket"

# Simple example
setup = -> { "my resource" }
teardown = ->(resource : String) { puts "Cleaning up #{resource}"; nil }

Bracket.with_resource(setup, teardown) do |resource|
  puts "Using #{resource}"
end

Features

  • Guarantees resource cleanup even if exceptions occur
  • Type-safe resource handling
  • Simple, functional interface
  • Works with any resource type

Links

I’d love to hear your thoughts and feedback! If you find this useful or have suggestions for improvements, please let me know.

3 Likes

What benefits does this shard provide over just doing this?

resource = "my resource"

begin
  puts "Using #{resource}"
ensure
  puts "Cleaning up #{resource}"
end
1 Like

Also, it can extend a little more in a Java way where if the class is extended from the Autoclosable interface, then it will be used under the hood in a try-with-resources pattern.

for such, some method try(autoclosableInheritedObject, &block) can be used where it will execute the block and then clear the resources.

I am not discouraging the topic starter from what he is doing, but just thinking of some more straightforward way.

brackets are a design pattern. They aren’t very useful for simple cases like eg:

resource = "my resource"

begin
  puts "Using #{resource}"
ensure
  puts "Cleaning up #{resource}"
end

They tend to be more useful for say larger functions with resources of different types, that need to be opened/closed in specific sequence (eg mutexes, locks), and where you don’t want subtle bugs to be introduced later on by re-ordering code.

More info over here:

iirc in java it tends to be a bit more magic, where you’re not always 100% sure if a given class will or won’t autoclose itself?

Haviving a syntactic block structure , helps you to intuitively see the “liveliness” of various objects just by seeing the code on your screen, not by needing to go check the class definition.

2 Likes

I can see that it might make sense to put the cleanup code closeby to the the setup code.
I’m not convinced it is a good idea to use such a micro library for this when you can express the same in regular Crystal code. That’s more straightforward and easy to understand for anyone without being familiar with an external library (even though it’s very small).

In addition to Announcing bracket.cr - Safe Resource Management Pattern - #2 by Blacksmoke16 you could also do something like this for explicitly placing the cleanup code next to the setup.

resource = "my resource"
teardown = ->(resource : String) { puts "Cleaning up #{resource}"; nil }

begin
  puts "Using #{resource}"
ensure
  teardown.call(resource)
end

Optionally extract setup into a proc as well, but for this example it seems unnecessary.

What kinds of bugs would that be though?
The main factor I can think of is that the scope of resource is limited to the block, so you cannot use it outside of it.

There is actually a very similar idiom in Crystal (and Ruby) with yielding resources to a block. It combines the setup and teardown into an explicit method:

def with_resource
  resource = "my resource"
  begin
    yield resource
  ensure
    puts "Cleaning up #{resource}"
  end
end

with_resource do |resource|
  puts "Using #{resource}"
end

This is plain Crystal (or Ruby) so it’s very readable and the callsite is much cleaner than with that bracket call.
IMO this is a stronger pattern and a better abstraction: Setup and teardown are syntactically merged in the same scope.
Also, this trivially allows passing setup parameters. And it’s super composable:

with_resource do |resource|
  with_subresource(resource) do |subresource|
    puts "Using #{subresource}"
  end
end
2 Likes

You’re right to emphasize explicit control structures in Crystal, but what I’m doing with bracket isn’t just syntactic sugar—it’s about structured execution invariants. The idea is to encode delimited execution boundaries as a first-class abstraction, ensuring correctness at the type level while preserving functional-style encapsulation of resources.

Think of it like Python’s with, but fully type-checked, zero-cost, and extendable within Crystal’s existing semantics. The core principle is enforcing state transitions between acquisition, execution, and release in a way that allows recursive execution contexts to be both safe and expressive.

Crystal lacks a built-in bracketed execution pattern, so this fills the gap by formalizing the invariant:

bracket(acquire, release) do |resource|
  use(resource)
end

This isn’t just “another wrapper”—it hardens execution flows by guaranteeing finalization even in nonlocal jumps, early returns, or failures, while keeping it idiomatic and efficient.

Your concerns about explicitness make sense, but bracket isn’t about hiding control flow—it’s about formalizing execution correctness at a fundamental level. If Crystal ever gets first-class linear types or effect tracking, this could integrate even deeper into the type system.

Would be interested in your take on how we could extend this into structured concurrency patterns or effect handlers—since that’s where this naturally scales next.