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
Hey everyone!
Req is an HTTP client for Elixir that I’ve been working on for quite some time. There is already a lot of HTTP clients out...
New
Samly can be used to enable SAML 2.0 Single Sign On in a Plug/Phoenix application.
This library uses Erlang esaml to provide
plug enabl...
New
Flop is an Elixir library that applies filtering, ordering and pagination parameters to your Ecto queries.
offset-based pagination with...
New
Hobbes is a low-level distributed database for the Elixir programming language.
Hobbes provides a simple, safe, and scalable storage lay...
New
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
Hi all!
I want to present a small library which provides a mix task for generating an Entity-Relationship Diagram for Ecto schemas.
You...
New
Hello
Published a new library - ProcessHub!
ProcessHub is a library designed to manage process distribution within the Elixir cluster. ...
New
Other Trending Topics
I am happy to introduce the very α version of the new programming language compiled to BEAM.
Welcome Cure.
It has literally three kille...
New
I am seeing a lot of aplications of Argumentum ad Vericundiam in software discussions. They do link some piece of writing and point us to...
New
This showed up on my feed.. anyone heard of it? Just hype?
Ox Alpha is a reasoning model designed for coding, sustained ag...
New
It’s not that it’s vocabulary is too advanced. It’s something worse.
I get lost trying to follow even a paragraph written by Claude. It’...
New
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
@hugobarauna, Dr. Dimitrios Koutmos (my brother) and I (Alex Koutmos) have been hard at work on writing a book on how you can use Elixir ...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #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
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #blog-post
- #elixirconf-us
- #elixir-ls
- #ai
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming










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.