Quickstart Guide

For more advanced use cases, see the documentation.

For the Python API documentation, see https://tinychain.readthedocs.io/en/latest/

Hello, World!

TinyChain has one of the simplest imaginable "Hello, World!" programs— just open this link in your browser: http://demo.tinychain.net/state/scalar/value/string?key="Hello, World!"
Some things to notice: TinyChain has four types of Op: GET, PUT, POST, and DELETE. These correspond to HTTP methods . Every TinyChain Op is accessible over HTTP using the corresponding request method.
TinyChain supports object-oriented programming (OOP), including class inheritance. You can see the superclasses of a TinyChain String in its classpath: /state/scalar/string. So, String is a subclass of Value, which is a subclass of Scalar, which is a subclass of State, which is the parent of every TinyChain class. Any TinyChain Value can be constructed using by GETting its class.

Run a TinyChain host

The TinyChain host at demo.tinychain.net is provided for convenience, but it may be slow due to the volume of requests it receives, and it may not always have the latest updates and bugfixes. For the best experience, you should run your own host. This is easy to do with Docker:

# the "docker build" command will output an image ID like "c0c251e99ef1"
docker build https://github.com/haydnv/tinychain.git

# paste the image ID into this command
docker run -it -p 8702:8702/tcp IMAGE_ID ./tinychain --data_dir=/tmp/data
                    
Check that it's working by running your own "Hello, World!" program: http://127.0.0.1:8702/state/scalar/value/string?key="Hello, World!"

Construct a TinyChain compute graph

TinyChain's graph computing model was inspired by TensorFlow v1. The easiest way to try it out is to first install the Python client:

# on very new systems, the command may be "pip" instead of "pip3"
pip3 install tinychain
                    
Let's now try writing our own function:

# new file: test.py

import tinychain as tc

# this is the local TinyChain host you just started with "docker run..."
HOST = tc.host.Host("http://127.0.0.1:8702")

# this endpoint will attempt to run whatever program you send it
# without committing any write operations
ENDPOINT = "/transact/hypothetical"

# define a GET Op
# the type annotations are important!
# without them, TinyChain doesn't know what type to expect the arguments to be
@tc.get_op
def hello(name: tc.String) -> tc.String:
    return tc.String("Hello, {{name}}").render(name=name)

if __name__ == "__main__":
    cxt = tc.Context() # construct a new execution context
    cxt.hello = hello # include our function definition in the context
    cxt.result = cxt.hello("Name") # call the function

    print(HOST.post(ENDPOINT, cxt)) # evaluate the context on the host
                    
Check that it works as expected:

$ python3 test.py
Hello, Name
                    
This requires some scaffolding in order to set up but it's a very convenient starting point for the more advanced use cases covered in the documentation. If you're curious about how this works under the hood, you can inspect the JSON that gets sent to the host:

# ...
tc.print_json(cxt)
                    
You should see something like:

[
    [
        "hello",
        {
            "/state/scalar/op/get": [
                "name",
                [
                    [
                        "String_7f8cf85223d0",
                        "Hello, {{name}}"
                    ],
                    [
                        "_return",
                        {
                            "$String_7f8cf85223d0/render": {
                                "name": {
                                    "$name": []
                                }
                            }
                        }
                    ]
                ]
            ]
        }
    ],
    [
        "result",
        {
            "$hello": [
                "Name"
            ]
        }
    ]
]
                    
In general you shouldn't have to worry about what the generated JSON looks like, but it can be convenient to give explicit names to the internal states of an Op. You can do this by using the cxt or txn keyword—just like Python treats the "self" keyword specially in a method declaration, assigning it a reference to the method's instance, TinyChain treats the cxt or txn keyword specially, assigning it a reference to the Op's execution context. For example:

# ...
@tc.get_op
def hello(cxt, name):
    cxt.template = tc.String("Hello, {{name}}")
    return cxt.template.render(name=name)
# ...
                    
If you again inspect the JSON representation of your compute graph, you'll see that the anonymous "String..." name has been replaced by "template."