Skip to content

Commit

Permalink
Update user guide docs to reflect addition of DynamicScratchVar (#226)
Browse files Browse the repository at this point in the history
  • Loading branch information
michaeldiamant authored Mar 9, 2022
1 parent 51a6562 commit 7c953f6
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 8 deletions.
26 changes: 23 additions & 3 deletions docs/control_structures.rst
Original file line number Diff line number Diff line change
Expand Up @@ -296,9 +296,11 @@ Subroutines
.. note::
Subroutines are only available in TEAL version 4 or higher.

A subroutine is section of code that can be called multiple times from within a program. Subroutines
are PyTeal's equivalent to functions. Subroutines can accept any number of arguments, and these
arguments must be PyTeal expressions. Additionally, a subroutine may return a single value, or no value.
A subroutine is section of code that can be called multiple times from within a program. Subroutines are PyTeal's equivalent to functions. Subroutine constraints include:

* Subroutines accept any number of arguments.
* Subroutine argument types can be any `Expr` (PyTeal expression) or strictly `ScratchVar` (no subclasses allowed). PyTeal applies pass-by-value semantics to `Expr` and pass-by-reference to `ScratchVar`.
* Subroutines return a single value, or no value.

Creating Subroutines
--------------------
Expand All @@ -317,6 +319,24 @@ For example,
def isEven(i):
return i % Int(2) == Int(0)
PyTeal applies these parameter type annotation constraints when compiling subroutine definitions:

* :any:`ScratchVar` parameters *require* a type annotation.
* :any:`Expr` parameters do *not* require a type annotation. PyTeal implicitly declares unannotated parameter types as :any:`Expr`.

Here's an example illustrating `ScratchVar` parameter declaration with parameter type annotations:

.. code-block:: python
@Subroutine(TealType.none)
def swap(x: ScratchVar, y: ScratchVar):
z = ScratchVar(TealType.anytype)
return Seq(
z.store(x.load()),
x.store(y.load()),
y.store(z.load()),
)
Calling Subroutines
-------------------

Expand Down
30 changes: 26 additions & 4 deletions docs/scratch.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ Scratch Space

`Scratch space <https://developer.algorand.org/docs/reference/teal/specification/#scratch-space>`_
is a temporary place to store values for later use in your program. It is temporary because any
changes to scratch space do not persist beyond the current tranasaction. Scratch space can be used
changes to scratch space do not persist beyond the current transaction. Scratch space can be used
in both Application and Signature mode.

Scratch space consists of 256 scratch slots, each capable of storing one integer or byte slice. When
using the :any:`ScratchVar` class to work with scratch space, a slot is automatically assigned to
each variable.

Writing and Reading
~~~~~~~~~~~~~~~~~~~~~~
ScratchVar: Writing and Reading to/from Scratch Space
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

To write to scratch space, first create a :any:`ScratchVar` object and pass in the :any:`TealType`
of the values that you will store there. It is possible to create a :any:`ScratchVar` that can store
Expand All @@ -22,7 +22,7 @@ that no type checking takes places in this situation. It is also possible to man
slot ID the compiler should assign the scratch slot to in the TEAL code. If no slot ID is specified,
the compiler will assign it to any available slot.

To write or read values, use the corresponding :any:`ScratchVar.store` or :any:`ScratchVar.load` methods.
To write or read values, use the corresponding :any:`ScratchVar.store` or :any:`ScratchVar.load` methods. :any:`ScratchVar.store` *must* be invoked before invoking :any:`ScratchVar.load`.

For example:

Expand All @@ -34,3 +34,25 @@ For example:
Assert(myvar.load() == Int(5))
])
anotherVar = ScratchVar(TealType.bytes, 4) # assign this scratch slot to slot #4
DynamicScratchVar: Referencing a ScratchVar
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

:any:`DynamicScratchVar` functions as a pointer to a :any:`ScratchVar` instance.

Reference a :any:`ScratchVar` instance by invoking :any:`DynamicScratchVar.set_index`. :any:`DynamicScratchVar.set_index` *must* be invoked before using :any:`DynamicScratchVar.load` and :any:`DynamicScratchVar.store`.

Here's an example to motivate usage. The example shows how a :any:`DynamicScratchVar` updates the *value* of a referenced :any:`ScratchVar` from 7 to 10.

.. code-block:: python
s = ScratchVar(TealType.uint64)
d = DynamicScratchVar(TealType.uint64)
return Seq(
d.set_index(s),
s.store(Int(7)),
d.store(d.load() + Int(3)),
Assert(s.load() == Int(10)),
Int(1),
)
8 changes: 7 additions & 1 deletion tests/pass_by_ref_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,13 @@ def test_old():


if not OLD_CODE_ONLY:
NEW_CASES = (sub_logcat_dynamic, swapper, wilt_the_stilt, fac_by_ref, sub_mixed)
NEW_CASES = (
sub_logcat_dynamic,
swapper,
wilt_the_stilt,
fac_by_ref,
sub_mixed,
)

def test_swapper():
compile_and_save(swapper)
Expand Down
17 changes: 17 additions & 0 deletions tests/teal/user_guide_snippet_dynamic_scratch_var_expected.teal
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma version 6
int 0
store 1
int 7
store 0
load 1
load 1
loads
int 3
+
stores
load 0
int 10
==
assert
int 1
return
27 changes: 27 additions & 0 deletions tests/user_guide_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import pytest

from pyteal import *

from .compile_asserts import assert_new_v_old, compile_and_save


def user_guide_snippet_dynamic_scratch_var() -> Expr:
"""
The user guide docs use the test to illustrate `DynamicScratchVar` usage. If the test breaks, then the user guide docs must be updated along with the test.
"""

s = ScratchVar(TealType.uint64)
d = DynamicScratchVar(TealType.uint64)

return Seq(
d.set_index(s),
s.store(Int(7)),
d.store(d.load() + Int(3)),
Assert(s.load() == Int(10)),
Int(1),
)


@pytest.mark.parametrize("snippet", [user_guide_snippet_dynamic_scratch_var])
def test_user_guide_snippets(snippet):
assert_new_v_old(snippet)

0 comments on commit 7c953f6

Please sign in to comment.