jvoegele

jvoegele

Bond 1.3.0 is out. :tada: The big story since the 1.0 release: Bond now does contract inheritance, and as of 1.3.0, Eiffel-style contract refinement. This is Design by Contract meeting the Liskov Substitution Principle — an abstraction declares contracts, and its implementations inherit (and can deliberately refine) them.

def deps do
  [{:bond, "~> 1.3"}]
end

New to Bond? It brings Design by Contract to Elixir — @pre/@post/@invariant checked at runtime, with failure messages that tell you exactly what was violated and why. The Bond 1.0.0 announcement and the getting-started guide are the best on-ramps.

Contract inheritance (1.2.0)

A behaviour or protocol is a promise about a family of implementations; a contract is the formal content of that promise. Bond now lets you state it once, on the abstraction, and enforces it across every implementation — present and future.

Behaviours — declare @pre/@post on the @callback, and implementers inherit them:

defmodule Ledger do
  use Bond.Behaviour

  @pre positive_amount: amount > 0
  @post non_negative: result >= 0
  @callback withdraw(balance :: non_neg_integer, amount :: pos_integer) :: non_neg_integer
end

defmodule BankAccount do
  use Bond, behaviours: [Ledger]

  @impl true
  def withdraw(balance, amount) when amount <= balance, do: balance - amount
end

BankAccount.withdraw/2 now enforces Ledger’s contract — though it appears nowhere in BankAccount — and a violation is attributed back to the source behaviour.

Protocols — declare contracts on a defprotocol, enforced once at the dispatch boundary, so implementations stay completely ordinary (no Bond awareness required):

defprotocol Sized do
  use Bond.Protocol

  @post non_negative: result >= 0
  def size(data)
end

Every call through Sized.size/1 checks the contract, whichever implementation runs — and it survives protocol consolidation.

New in 1.3.0: Eiffel-style refinement

By default an implementation inherits its contracts verbatim. 1.3.0 lets it deliberately refine them, following Eiffel’s behavioural-subtyping rules — with two distinct keywords that make the (counterintuitive) variance explicit:

  • @pre_weaken weakens the precondition: effective precondition = inherited or weaken (preconditions may only weaken down a hierarchy — contravariance).
  • @post_strengthen strengthens the postcondition: effective postcondition = inherited and strengthen (postconditions may only strengthen — covariance).
defmodule SavingsAccount do
  use Bond, behaviours: [Ledger]

  @impl true
  @pre_weaken zero_ok: amount == 0              # also accept a no-op zero withdrawal
  @post_strengthen audited: log_exists?(result)
  def withdraw(balance, amount), do: ...
end

The distinct keywords are the teaching: using or to weaken a precondition is exactly the Liskov-safe direction, even though it reads backwards at first. Refinement works for protocol implementations too, via use Bond.Protocol.Impl in the defimpl. (Plain @pre/@post on an inherited operation remains a compile error — that syntax was reserved precisely so refinement could slot in with zero migration debt.)

Full rules and examples: the Contract Inheritance guide.

Also since 1.0

  • 1.1.0 — a performance pass: contract checks now gate through :persistent_term (~2.6× cheaper when enabled), plus a new Bond.Config runtime API for toggling contract kinds at runtime.
  • 1.2.1<~ pattern bindings are now correctly accepted in inherited-contract reference validation, and the protocol-contracts guide was merged into a single unified Contract Inheritance guide.

Stability

Everything since 1.0 is additive — no breaking changes — so 1.3.0 is a normal minor release, and the new surface is covered by Bond’s stability guarantees. Compatibility is verified across Elixir 1.16–1.20 in CI.

Thanks & feedback

The contract-inheritance design was shaped by dogfooding it in a real application and by feedback from the earlier threads — thank you. Questions, bug reports, and ideas are very welcome here or on the issue tracker.

Links

Showing Posts 1 to 1

jvoegele

jvoegele OP

For anyone curious about future directions for Bond, I’ve created some forward-looking issues in GitHub issue tracker:

— All posts loaded —

Where Next? Top

Trending in News & Updates Top

sorenone
Today we’re releasing Oban for Python. Not an Oban client in Python. Not a pythonx wrapper embedded in Elixir. Nope, it’s a fully operati...
New
bartblast
I’ll be using this thread to share Hologram patch release announcements. Minor releases will continue to get dedicated threads with blog ...
New
sorenone
This release unifies configuration for queues, repos, and services, swaps opaque timing integers for readable durations, and backports pe...
New
pcharbon
:heart::heart::heart::heart::heart::heart::heart::heart::heart::heart::heart::heart::heart::heart::heart::heart::heart::heart::heart::hea...
New
webofbits
Aludel 0.7.0 is released :tada: Since 0.5.0, Aludel has grown into a much more complete LLM evaluation toolkit for Elixir and Phoenix app...
New
nature
NatureWhistle v0.4.1 is out! :tada: This release is a pretty significant step forward for the project. When I first built NatureWhistle,...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews