jvoegele
Announcing Bond, Design by Contract for Elixir
Bond provides support for contract programming (also known as “Design by Contract”) for Elixir.
The primary goal for Bond is to provide the most feature-complete and thoroughly documented Design by Contract library for Elixir, with a concise and flexible syntax for specifying contracts.
Current and planned features include:
- Function preconditions with
@pre - Function postconditions with
@post - “old” expressions in postconditions
- “check” expressions for arbitrary assertions within a function body
- Predicates (such as
implies?andxor) for use in assertions - Detailed assertion failure reporting
- Incorporation of preconditions and postconditions into @doc for function
- Conditional compilation of contracts per environment
- More detailed assertion failure reporting, including color coding à la
ExUnit - Invariants for structs and/or stateful processes (if possible)
For comparison to other Design by Contract libraries for Elixir, please see the history section of the Bond documentation.
Trending in Announcing
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
In 2021 I started a new library called Tempo with the objective of modelling time as a set of intervals - not as instants. In 2022 I gave...
New
Hello,
I’m sharing my plugin here in forum after some time so it has time to mature and proof yourself.
I use Claude Code daily on a pr...
New
Aloha gang,
There’s a new class of AI model out from TypeSafe. Jev is their flagship model. You can learn about it here:
...
New
I’ve recently created a small library phoenix_vite integrating the vite build tooling with phoenix.
It
provides an igniter.installer t...
New
I needed something like premailer for rails, and after searching, I decided to make an easy-to-use library to handle inline styles and co...
New
If you’ve ever had to debug a BEAM node you know it can be a painful process. Parsing raw data, or dealing with clutter often gets in the...
New
Other Trending Topics
Hey there,
I haven’t seen a list of useful Elixir specific skills for the popular AI tools yet so I’m starting one here with my first.
...
New
Hi everyone :waving_hand:
I wanted to share something I’ve been building — NowBlind, a random chat app designed to help people discover ...
New
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
(I just needed to vent somewhere and LinkedIn is full of hope, or hype, I’m not sure which exactly)
AI dream has many faces, but general...
New
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself.
My main conc...
New
Fly’s CEO posted this recently - Turn And Face The Strange · The Fly Blog
It says that Fly is going all-in on sprites, which is a worry ...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #ai
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #blog-post
- #ecto-query
- #elixirconf-us
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #elixirconf-eu
- #api
- #forms
- #security
- #hex










Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
sbuttgereit
Hi–
Interesting project. I saw this in the docs:
Is the intention that pre/post conditions replace traditional typespecs when used or should they be considered supplemental? If they are a replacement, do they interact with Dialyzer at all? Also, the set-theoretic types, assuming they land, also offer a manner of contract with functionality ramifications, are there thoughts about how this library would relate to that future?
I’ve not looked much beyond a quick search through the docs. But these are the questions I’d need to understand for adoption.
jvoegele
Hi @sbuttgereit,
Contracts are not intended to replace typespecs or set-theoretic types; rather, they are complementary mechanisms.
Typespecs are evaluated at compile-time or with a static analysis tool such as Dialyzer, whereas contracts as implemented by Bond are evaluated at run-time (although they are attached to functions at compile-time so must be valid Elixir code).
The closest analogue to contracts in native Elixir is guard expressions for functions, which allow for making rudimentary “assertions” about function arguments. Assertions in Bond are much more powerful and are not limited to the pre-defined set of functions that are allowed in guard expressions.
jvoegele
@sbuttgereit:
Also note that even if a particular assertion could be implemented as a guard clause or pattern match on a function head, if you are using Bond it might be preferable to implement those assertions as preconditions to the function instead. The reason being is that Bond will provide a much clearer error message if a particular assertion fails, as opposed to a
FunctionClauseErrorwhich would be more difficult to interpret.dimitarvp
Looks like something I’d push for using in the team(s) I’ll be working with.
Though I’d probably only check it out after invariants are added. They complete the picture.
katafrakt
Agreed on both points. This looks very useful already, but invariants would be a very welcome addition.
jvoegele
I’m working through some ideas that I have for adding invariants to Bond.
The challenge is that invariants as used in object-oriented languages (such as Eiffel, where DbC was originally conceived) are embedded in class definitions and the assertions therein have access to the state of the “current” object (
Currentin Eiffel,thisorselfin some other OO languages).In a functional language such as Elixir, we don’t have stateful “objects” that the assertions in invariants could refer to. What kind of invariants could you define for a purely functional Stack module, for example, without having a reference to the “current” stack?
On the other hand, Elixir does have some near analogues in the form of stateful processes, such as
Agents andGenServers. I think it could be possible to use the pid of the process as the notion of “current” for use in invariants, and “tap into” the state of these processes for making assertions about the state.This approach would likely require wrapper modules around
Agentand/orGenServerin order to be able to pass the “current state” to assertions in a hypothetical@invariantclause.I’m still thinking through these ideas, though, and I am definitely open to feedback or alternative approaches to adding invariants to Bond.
dimitarvp
Invariants on function arguments only?
I think you should completely do away with stateful assertions, be those pre-conditions, post-conditions or invariants. Up to you of course but that’s IMO having the potential to become a huge mess and a maintenance nightmare.
jvoegele
Thanks for the feedback @dimitarvp.
You might be right about stateful assertions becoming messy. I had been thinking about invariants as inherently stateful, and which describe properties of the state before and after state transitions. But as you point out, there is probably still value in stateless invariants that use only function arguments.
For example, consider a bounded stack with a capacity fixed at creation time. Such stacks do not allow new items to be pushed if the stack is already full. I can think of a few invariants that I would express at the module level, even for a purely functional, stateless version of such a stack (ignore for now how the
stackvariable binding could be injected into the assertions, I’ll come back to that):Many of these invariant properties could be expressed as postconditions on the relevant functions, but expressing them at the module level as invariants brings to mind a couple of possible advantages:
@moduledocin a similar way that preconditions and postconditions are already added to the@docfor functions.The main complication that I can think of is that this scheme would probably only work for 1-arity functions that use the same name for the lone parameter. Otherwise, what would be the value bound to the
stackvariable in the invariant assertions?I’m also not sure if the
oldexpression in thefixed_capacityassertion in the invariant makes sense. If invariants are to be checked before and after function calls, theoldexpression would fail when evaluated before the function call (at least the way thatoldis currently implemented in Bond). I don’t think Eiffel allowsoldto be used in invariants, presumably for this reason.Curious about your thoughts, or if you (or anyone else) have other ideas about invariants for purely functional code.
jvoegele
I added a new “Contracts in a Concurrent World” guide to the Bond docs, which discusses how to eliminate the need for stateful assertions:
TL;DR - It’s the same old trick used for better testability: separate the pure functional code from stateful code.
zachallaun
A few thoughts about module-level invariants.
Invariants come in two flavors: those that desugar into pre- and post-conditions (ensure invariant holds before and after), and those that desugar into only post-conditions (ensure something holds between the original and new value).
Invariants also need some way to be applied when functions return a wrapped value. Consider your bounded stack – a
pushoperation would definitely want thesize_limited_by_capacityinvariant checked, but it would also likely return{:ok, stack} | :error.Some hypothetical syntax, adapting your above stack example:
This would convey that, prior to the function running, the stack is accessed as
stack(any variable bound in the params), and after the function runs, the stack is accessed only if it matches{:ok, stack}, in which casestackis used.