World Of Bugs

There are 1.4 billion insects for every human, most of them on your code

The concepts on this post are useful for any language, examples are from Nim.

Defensive Programming usually takes the form of a Unittest,

Unittest checks a "unit" of code, validates using assertions on special test runs,

runs a code block and asserts that the result equals a predefined "sample" result.

This is good, but is has some limitations,

the input, data and context is very often faked (mocked),

the input is usually not asserted because is kinda fixed,

the output is result of the inputs so neither is completely real world,

it runs on "dedicated" automated tests runs.

How can tests be more integrated and close to the code where the bug lives?

Side Effects

Bugs is the entropy of the universe trying to reverse engineer your code while you are still writing it

Side Effect Free programming is focused on eliminating side effects on the code,

and monitoring or controlling them where you can not eliminate them.

Functional programming tries to reduce Side Effects,

without Side Effects the Bugs can not spread on the code, helps reducing Bugs.

Side Effects examples:

Writing to terminal or files, reading from terminal, files or user input.

Mutating in-place of variables, globals, objects, types, data structures.

Date/time functions, Win32 API/Registry, Databases, HTTP, GUI, exceptions.

Nim has Side Effects Tracking, Functional advantages while still using OOP.

Simply changing proc to func will check for side effects on your functions!.

Immutability

Immutability changes everything!

Immutability of variables helps to fight Bugs by not allowing unwanted mutations,

using Immutability whenever possible is very encouraged.

Nim is immutable by default and has 3 kinds of variables:

let its a runtime immutable variable.

its a runtime variable. const its compile-time immutable variable.

its compile-time variable. var its runtime mutable variable.

Contracts

TDD is Poor-Man's Contracts

Some programming languages use a different way of dealing with all this,

languages like Ada or Eiffel, use Design by Contract. Applied Hoare logic.

Contracts can assert on input, data and context on the beginning of a code block,

and can also assert on the result at the end of a code block,

it lives in the code block as close as possible to it, it runs an actual real run,

everything is real inputs, data, context and whatnot,

on programming languages that support compile-time code execution all this can happen at compile time if desired.

Contra

The night is dark and full of errors

Contra reimagines Design By Contract in a modern KISS way,

all the benefits of Assertive Programming on statically typed compiled language,

like everything on Nim it takes a lot of care about performance,

it allows fast contracts with zero cost at runtime with a comfy API,

requires minimal modifications on existing code, just 2 lines to add a Contract.

Lets take a buggy example code and add a Contract to it:



proc myFunction ( mustBePositive : int ): int = result = mustBePositive - 1

Remember that mustBePositive must be Positive, lets use the function:



proc myFunction ( mustBePositive : int ): int = result = mustBePositive - 1 echo myFunction ( 0 )

This is a Bug, mustBePositive is not Positive ( 0 - 1 is -1 ), lets add Contra,

and ensure that there are no Side Effects using func :



import contra func myFunction ( mustBePositive : int ): int = preconditions mustBePositive > 0 # Require postconditions result > 0 # Ensure result = mustBePositive - 1 echo myFunction ( 0 )

The Contract shields our code from the Bug, wont allow the Bug to spread.

preconditions takes preconditions separated by commas, asserts on arguments or local variables.

takes preconditions separated by commas, asserts on arguments or local variables. postconditions takes postconditions separated by commas, must assert on result , can assert on local variables.

To keep things simple, no body nor invariants blocks are required,

you can pass invariants mixed on the postconditions but is optional,

it can be used on JavaScript, interpreted NimScript, runtime and compile-time.

Your CI service can compile and run a binary with all assertions enabled.

Contra adds 0 lines of code to Release build and 9 lines of code to Debug build.

Gulag Driven Development

Make your users work for you

You can now delegate the bug hunting on collaborators and trusted users,

encouraging them to try development binaries compiled with all assertions enabled.

But the same code can also produce a binary with all assertions disabled,

Contra produces no code when build for release, then you pwn on all Benchmarks.

Nim has automatic Dead Code Elimination.

Convert your users into being your Gulag CI!.

Install

nimble install contra

Assuming you already have Nim installed.

Try Nim now, you are missing a ton of cool stuff.

Thank you for playing

👑