Rustfbp provides a simple, composable, clearly defined API, with a C ABI for every agent within a Fractalide deployment.


Keywords
flow-based-programming, nix, racket, rust
License
MPL-2.0

Documentation

Fractalide

"Go with the flow", or should one say "Oxidize in the flow"?

Canonical source

The canonical source of this project is hosted on GitLab, and is the preferred place for contributions, however if you do not wish to use GitLab, feel free to make issues, on the mirror. However pull requests will only be accepted on GitLab, to make it easy to maintain.

Quick start

Fractalide is a programming platform which removes three classes of errors associated with:

Memory Safety

Fractalide components are implemented in Rust, a language which gives the programmer fearless control over speed, concurrency and memory safety.

Dependency Hell

Fractalide uses Nix as a replacement for make. Indeed, it seems Fractalide is the first programming language to exclusively use nix as a package manager. Each component is able to setup it's own OS environment, which might include database drivers written in C, specific versions of an executable or pull in a programming language like python. The package manager is lazily evaluated, thus only those dependencies needed will be compiled. This allows us to have an extremely large repository filled with possibly millions of components.

Code reuse

The use of Flow-based programming gives us the ability to combine and concatenate programs in ways never anticipated. Much like the BASH shell coordinates the execution of GNU utils and other executables in neat, sneaky ways. This is a sign of a high reusability factor. Code is like mud, easy to mold when wet, harder when dry, impossible when baked. FBP gives one the ability to keep one's codebase nicely lubricated.

"Flow-based Programming defines applications as networks of "black box" processes, which exchange data across predefined connections by message passing, where the connections are specified externally to the processes. These black box processes can be reconnected endlessly to form different applications without having to be changed internally. FBP is thus naturally component-oriented." - J Paul Morrison.

flow-based programming reduces complexity of your data-processing logic by promoting control flow to first-class citizen of the flow design

— Arnau Orriols (@Arnau_Orriols) February 2, 2016

Slight mindset shift

The goal is to create reusable components that are efficient, solve real world problems and plug into each other, creating flow. As flow is now a first class citizen, it becomes much easier to manipulate. One should not place too much emphasis on component internals when designing for a flow. One should care about the shape of the data, the capnproto contracts, and how data flows through your system. Of equal importance; one should keep in mind when designing components that your code exists within a community. Pick up your litter, keep the paths clean, Be polite when interacting with other components. Once we as a community have reached this point we will be near our goal.

A contrived example of displaying the output of an XOR gate to the terminal:

'maths_boolean:(boolean=false)' -> a xor(maths_boolean_xor) output -> input disp(maths_boolean_print)
'maths_boolean:(boolean=false)' -> b xor()

Explanation:

  • 'maths_boolean:(boolean=false)' is an IIP (Initial Information Packet) which tells the virtual machine to use the maths_boolean capnproto contract which can be found in the contracts/maths/boolean folder. The :(boolean=false) bit puts the value false into the boolean field of maths_boolean
  • -> means message pass the IIP to the input a of xor(). xor() is an initialized variable of the type maths_boolean_xor which can be found in components/maths/boolean/xor folder. Thereafter you may simply refer to xor() without the maths_boolean_xor.
  • output is the output of xor which feeds into input of disp(), which is of type maths_boolean_print located in components/maths/boolean/print
  • IN => means you have an input port interface named IN.
  • What's inbetween IN => and => OUT is the implementation of the subnet.
  • => OUT means you have an output port interface named OUT.
  • Do note, you will see ${component_name} this particular syntax is the nix programming language. It will lazily evaluate to the correct path just before compile time.
  • For more details, follow the setup steps below which will show you how to compile the docs component. This component will teach you how to build a NOT logic gate.

maths_boolean_xor

{ stdenv, buildFractalideSubnet, upkeepers, maths_boolean_not, ip_clone, maths_boolean_and, maths_boolean_or,...}:

buildFractalideSubnet rec {
  src = ./.;
  subnet = ''
    a => input clone1(${ip_clone})
    b => input clone2(${ip_clone})
    clone1() clone[2] -> input not1(${maths_boolean_not}) output -> a and2(${maths_boolean_and})
    clone2() clone[1] -> input not2(${maths_boolean_not}) output -> b and1(${maths_boolean_and})
    clone1() clone[1] -> a and1() output -> a or(${maths_boolean_or})
    clone2() clone[2] -> b and2() output -> b or() output => output
  '';

  meta = with stdenv.lib; {
    description = "Subnet: XOR logic gate";
    homepage = https://gitlab.com/fractalide/fractalide/tree/master/components/maths/boolean/xor;
    license = with licenses; [ mpl20 ];
    maintainers = with upkeepers; [ dmichiels sjmackenzie];
  };
}

maths_boolean_print

extern crate capnp;

#[macro_use]
extern crate rustfbp;

mod contract_capnp {
    include!("maths_boolean.rs");
}
use self::contract_capnp::maths_boolean;

use std::thread;

component! {
    Print,
    inputs(input: maths_boolean),
    inputs_array(),
    outputs(output: maths_boolean),
    outputs_array(),
    option(),
    acc(),
    fn run(&mut self) -> Result<()> {
        let mut ip_a = try!(self.ports.recv("input"));

        let a_reader = try!(ip_a.get_reader());
        let a_reader: maths_boolean::Reader = try!(a_reader.get_root());
        let a = a_reader.get_boolean();

        println!("boolean : {:?}", a);

        let _ = self.ports.send("output", ip_a);

        Ok(())
    }
}

From here, you go native.

Setup

Fractalide supports whatever platform Nix runs on, with the exception of Mac OS as Rust on Nix on Darwin doesn't work.

Please read Don't pipe to your shell, then read the script before you execute it. After you are comfortable with it, let's agree that the below one-liner is convenient. If you insist, there is documentation to type this stuff manually.

Run this command as a user other than root (you will need sudo). To uninstall simply rm -fr /nix. See this blog post for more detailed information.

$ curl https://nixos.org/nix/install | sh (ignore if on nixos)

$ source ~/.nix-profile/etc/profile.d/nix.sh (ignore if on nixos)

Quite possibly your Linux package manager has a Nix package already.

$ git clone https://gitlab.com/fractalide/fractalide.git

$ cd fractalide

$ nix-build --argstr debug true --argstr subnet docs

Congratulations, you just built your first Fractalide executable, now let's run it:

$ ./result/bin/docs

This serves up the Quick Start manual section on http://localhost:8083/docs/manual.html.

This is what the code you just ran looks like.

Happy Hacking!

Collective Code Construction Contract

We use the C4 on this project.