# Code a compute graph

## Code

Let's now try writing our own function. This assumes you have a running TinyChain host, following the instructions in [getting-started](https://docs.tinychain.net/guides/getting-started "mention"):

```python
# 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
                    
```

## Test

Check that it works as expected:

```bash
$ python3 test.py
Hello, Name         
```

This requires some scaffolding in order to set up but it's a very convenient starting point for more advanced use cases.

## Understand

If you're curious about how this works under the hood, you can inspect the JSON that gets sent to the host:

```python
# ...
tc.print_json(cxt)  
```

You should see something like:

```javascript
[
    [
        "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:

```python
# ...
@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."
