Implementing Design by Contract (DbC) paradigm in Go?

1,494 views
Skip to first unread message

Alexander Orlov

unread,
Sep 1, 2011, 6:40:12 AM9/1/11
to golan...@googlegroups.com
DbC is a paradigm that is language-agnostic. I has been already implemented by Google for Java using annotations. DbC ensures certain constraints at runtime, so you can catch many errors at runtime.

You can also achieve something like DbC including certain check routines into a function, but there is no standard and regulated way for doing this.

What I want to know is whether it's possible to "implement" or basically use DbC in Go without bloating the code and making it hard to understand. It's all about using a clean and standardized way to declare certain constraints.

André Moraes

unread,
Sep 1, 2011, 3:26:32 PM9/1/11
to golan...@googlegroups.com
Those verifications in Java are done via Java Bytecode manipulation?
Like what HIbernate does for annotated classes?

Since Go have functions as first class values, you could wrap you
function under another function and do the checks.

type fn func(int) int;

func check_fn(to_check fn) fn {
return func(i int) {
if i > 10 { panic("Argument checked"); }
ret = to_check(i)
if i < 10 { panic("Result checked"); }
}
}

--
André Moraes
http://andredevchannel.blogspot.com/

Ziad Hatahet

unread,
Sep 1, 2011, 4:34:57 PM9/1/11
to golan...@googlegroups.com
Microsoft Research has done some pretty cool work on contracts for .NET ( http://research.microsoft.com/en-us/projects/contracts/ ).

The library seems to still be in its infancy, but I really like the idea of ensuring contracts at compile time. Maybe we could introduce something similar in Go? :)

--
Ziad

Kyle Lemons

unread,
Sep 1, 2011, 6:15:52 PM9/1/11
to golan...@googlegroups.com
On Thu, Sep 1, 2011 at 3:40 AM, Alexander Orlov <alexand...@loxal.net> wrote:

One interesting way to do this might be to combine some preprocessing with the interface functionality in Go.

You could write an app that, given a set of Go files, scans for interfaces like:
// constrain
type BlahIface interface {
  // len(a) > 2 && len(a) < 12
  // b > 0 && b < 24
  // c > b
  // len(res) > b
  Func(a string, b int, c float32) (res string)
}

and then generates an object which wraps that interface whose functions adhere to the interface and do the proper checks.  Each comment for each function could be the go syntax conditional of an if statement which must be true.  Sort of dependency injection with sanity checks.
~K

Brad Fitzpatrick

unread,
Sep 1, 2011, 6:26:35 PM9/1/11
to Kyle Lemons, golan...@googlegroups.com
See also http://code.google.com/p/go/issues/detail?id=1765 which I think would permit (perhaps with a couple other little changes), doing this at runtime, without a pre-processor.

Alexander Orlov

unread,
Sep 1, 2011, 7:55:24 PM9/1/11
to André Moraes, golan...@googlegroups.com


2011/9/1 André Moraes <and...@gmail.com>

Those verifications in Java are done via Java Bytecode manipulation?

Yes. They use Pluggable Annotation Processing that was introduced in Java 6. But to use those annotations you have to compile your code with a specific flag referencing the DbC lib:

javac -processor com.google.java.contract.core.apt.AnnotationProcessor YourClass.java

Also you have to add a flag to execute those compiled classes: 

java -javaagent:path/to/agent.jar YourMainClass
 
Like what HIbernate does for annotated classes?

Don't know about Hibernate, I'm using JPA. However the annotations JPA uses, don't rely on any of those flags for compilation and execution.

Since Go have functions as first class values, you could wrap you
function under another function and do the checks.

type fn func(int) int;

func check_fn(to_check fn) fn {
 return func(i int) {
   if i > 10 { panic("Argument checked"); }
   ret = to_check(i)
   if i < 10 { panic("Result checked"); }
 }
}

That's basically a closure? Java doesn't support closures yet, so it has to rely on its annotations (which are also quite nice for this kind of declarations). 
  • But still in this case you have to use check_fn to call fn
  • Aslo the dev must know explicitly that there is a check_fn func which is responsible for validation of fn.

Alexander Orlov

unread,
Sep 1, 2011, 8:05:02 PM9/1/11
to Brad Fitzpatrick, Kyle Lemons, golan...@googlegroups.com
On Fri, Sep 2, 2011 at 12:26 AM, Brad Fitzpatrick <brad...@golang.org> wrote:
See also http://code.google.com/p/go/issues/detail?id=1765 which I think would permit (perhaps with a couple other little changes), doing this at runtime, without a pre-processor.

Sounds nice. It seems like one could implement DbC without great lang spec intrusions.

jimmy frasche

unread,
Sep 1, 2011, 9:07:09 PM9/1/11
to Alexander Orlov, Brad Fitzpatrick, Kyle Lemons, golan...@googlegroups.com
I wrote a preprocessor that does something like DbC a while a go just
to play with. It's not meant for production code but it does a nice
job sticking boilerplate debug statements in functions. I'd actually
forgotten about it until this thread. I fixed a few compile errors
from not playing with it for a bit, and uploaded it to google code in
case anyone's interested:

https://code.google.com/p/dbgo

André Moraes

unread,
Sep 2, 2011, 12:41:50 PM9/2/11
to golan...@googlegroups.com
> But still in this case you have to use check_fn to call fn?

No, since it is a closure, you call check_fn and then just call the
value returned by check_fn which is a function.

> Aslo the dev must know explicitly that there is a check_fn func which is
> responsible for validation of fn.

Yes

lpa...@gmail.com

unread,
Jun 4, 2014, 9:28:06 AM6/4/14
to golan...@googlegroups.com
(3 years later) -- Hi, I started learning go just recently and noticed as you did that it did not have Dbc, so as my first project I have created a "library" to add design by contract to Go.  It is available here:


Let me know if you have any questions or comments.

James Chacon

unread,
Jun 9, 2014, 9:35:45 AM6/9/14
to lpa...@gmail.com, golan...@googlegroups.com
Hmm....My personal take on that it's not really in line with Go. With multiple return it's really easy to return errors.

So invariant checking very easily becomes

func foo() (string, error) {
 if !invariant {
  return nil, fmt.Errorf("...")
 }
}

Which is a lot easier to deal with than a random library routine panic'ing due to a bug someday you didn't expect. It's also a lot simpler to follow along without having to reference more documentation for simple if checks.

Even with very large coverage ending up in cases where a new logic path fails an invariant isn't uncommon. Especially over time/large input sets. So not bailing hard (ala panic) on the task at hand seems a better path. Granted I come from the server world where keeping it running is just as important as correctness so my perspective is a bit skewed that way.

Clearly there is a trend towards this style but it definitely doesn't feel Go to me.

James



--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Luis Pabon

unread,
Jun 12, 2014, 3:17:45 PM6/12/14
to golan...@googlegroups.com, lpa...@gmail.com
I completely agree that during production, asserts and panics must be used with care.  Design by contract is used during development (debug builds and such) to help identify bugs on a running system by failing fast and recording any possible software state.

- Luis

egon

unread,
Jun 13, 2014, 3:34:46 AM6/13/14
to golan...@googlegroups.com, lpa...@gmail.com


On Thursday, 12 June 2014 22:17:45 UTC+3, Luis Pabon wrote:
I completely agree that during production, asserts and panics must be used with care.  Design by contract is used during development (debug builds and such) to help identify bugs on a running system by failing fast and recording any possible software state.

I disagree, it's like saying that... when learning to drive you should use seat-belts... and when you have your license, you don't need seat-belts anymore. Assertions/Contracts are first-line defense against undefined behavior... e.g. a single bit in RAM randomly flips.

+ egon

Luis Pabon

unread,
Jun 13, 2014, 7:49:14 AM6/13/14
to golan...@googlegroups.com, lpa...@gmail.com
I don't really think this is a black and white issue.  There are situations where asserts (fail fast methodologies) on productions systems is the correct thing to do (like a car computer sensing something fatally wrong).  There are also situations where asserts is not beneficial to the product, and handling the error instead is the correct answer.

Going back to the main discussions, I consider Dbc extremely beneficial, and I suggest to those who have not seen its benefits yet, to try it out :-).

- Luis

egon

unread,
Jun 13, 2014, 8:44:31 AM6/13/14
to golan...@googlegroups.com, lpa...@gmail.com

On Friday, 13 June 2014 14:49:14 UTC+3, Luis Pabon wrote:
I don't really think this is a black and white issue.  There are situations where asserts (fail fast methodologies) on productions systems is the correct thing to do (like a car computer sensing something fatally wrong).  There are also situations where asserts is not beneficial to the product, and handling the error instead is the correct answer.

What I mean is, if it should crash in dev then it should crash in prod. The thing you said before sounded like you meant that we should just "remove the assertions in release build". I do agree that there are cases for assertions and cases for graceful handling.

Removing assertions can only make sense in games and maybe in some scientific computations, i.e. places where you really don't want to take the performance hit.

+ egon

Marko Ristin

unread,
Sep 6, 2018, 12:02:44 PM9/6/18
to golang-nuts
Hi,
I'd like to point you to a go tool that implements contracts (pre and postconditions) as part of documentation. The tool translates the contracts into code by adding it to the function body. It can also automatically remove the checks once you don't need them any more (e.g. in production).

Here is the repository:
https://github.com/Parquery/gocontracts

We are thinking about implementing the invariants in a similar way. Please have a look at this post if you'd like to discuss the details or contribute:
https://groups.google.com/forum/?hl=uk&nomobile=true#!topic/golang-nuts/zKQA0Lh116k

Reply all
Reply to author
Forward
0 new messages