▼ 2 Language Concepts
 2.1 Language Constructs 2.2 Testing 2.3 equality 2.4 Combining Multiple Operators 2.5 Modules 2.6 Use 2.7 Brands 2.8 Type Checking 2.9 Spies
 ► 2.9 Spies
 2.9.1 Examples 2.9.2 Minor Notes and Corner Cases 2.9.3 Grammar 2.9.4 Rationale

#### 2.9Spies

Spies are used for convenient display of values for print-style debugging. See Rationale for why this is particularly useful in Pyret.

##### 2.9.1Examples

The shortest use of a spy statement is to print the value of a name:

```x = 10
spy: x end```

This will produce a message like:

The filename will be the name of the file containing the spy statement, not spies.arr as shown here

 Spying (at file:///spies.arr:2:0-2:10) x: 10

On code.pyret.org, you’ll see output like:

Both of these outputs indicate that the name was x and the value was 10. In the text output, the line and column information is printed (this happened at line 2). In the visual output, the x is underlined – clicking it will scroll the editor to the line of the spy statement and highlight the corresponding use of x.

A spy statement can contain more than one name, and will print out all their values:

```x = 10
y = [list: 1, 2, 3]
spy: x, y end```

 Spying (at file:///spies.arr:3:0-3:13) x: 10 y: [list: 1, 2, 3]

A spy statement can also contain a message. This can be helpful for distinguishing between spy statements without looking at their corresponding line numbers:

```fun square(x):
spy "in square": x end
x * x
end

fun cube(x):
spy "in cube": x end
x * x * x
end

square(x)
cube(x)
square(x)```

Will produce:

 Spying "in square" (at file:///spies.arr:2:2-2:24) x: 3 Spying "in cube" (at file:///spies.arr:7:2-7:22) x: 2 Spying "in square" (at file:///spies.arr:2:2-2:24) x: 2

If we want to spy on an expression, rather than just names, we can give the expression a name within the spy statement:

```fun <A> reverse(lst :: List<A>, sofar :: List<A>) -> List<A>:
spy "lengths":
lst-length: lst.length(),
sofar-length: sofar.length(),
sum: lst.length() + sofar.length()
end
cases(List<A>) lst:
| empty => sofar
end
end

check:
reverse([list: "a", "b", "c"], empty) is [list: "c", "b", "a"]
end
```

This produces:

 Spying "lengths" (at file:///spies.arr:2:2-6:5) lst-length: 3 sofar-length: 0 sum: 3 Spying "lengths" (at file://spies.arr:2:2-6:5) lst-length: 2 sofar-length: 1 sum: 3 Spying "lengths" (at file:///spies.arr:2:2-6:5) lst-length: 1 sofar-length: 2 sum: 3 Spying "lengths" (at file:///spies.arr:2:2-6:5) lst-length: 0 sofar-length: 3 sum: 3

##### 2.9.2Minor Notes and Corner Cases

Both types of spy fields can be used in a single spy statement:

```x = 10
spy:
x,
y: 20
end```

Each value that is spied upon is required to have a name. That is, it’s an error to write:

```spy:
2 + 2
end```

The message position can contain expressions, not just string constants, so the message can be computed:

```fun f(n):
n * n
end
for each(i from range(0, 10)):
result = f(i)
spy "iteration " + to-string(i):
result
end
result
end```
##### 2.9.3Grammar

The grammar of spy statements is:

‹spy-stmt›: spy [‹expr›] : ‹spy-body› end ‹spy-body›: ‹spy-field› ([, ‹spy-field›])* ‹spy-field›: NAME | NAME : ‹binop-expr›

##### 2.9.4Rationale

Often, when debugging or explaining a program, it’s useful to display values during execution. It’s common to do this with functions like print. However, both in general, and specifically in Pyret, using a regular function call for debug printing leaves something to be desired. For example, just printing doesn’t track the line and column something was printed at, and when the value of an identifier is printed, its name is lost in the output, forcing the programmer to add extra string output describing the value. More annoyingly in Pyret, since we often add print statements to already-existing code, it becomes a nuisance to add Block Shorthand just to get a debugging print.

For example, consider the reverse example from above:

```fun reverse(lst, sofar):
cases(List<A>) lst:
| empty => sofar
end
end```

We might try to add uses of print to do what the spy statement did:

```fun reverse(lst, sofar):
print(lst.length())
print(sofar.length())
print(lst.length() + sofar.length())
cases(List<A>) lst:
| empty => sofar
end
end```

This has a few problems. First, because Pyret restricts function bodies to have no more than one expression unless Block Shorthand is used, this is an immediate syntax error. We could change the first line to include block: to let Pyret know we want to allow multiple statements.

`fun reverse(lst, sofar) block:`

Second, the uses of print lack context. With this version, we’d simply see sequences of numbers print out, and it would be difficult to discern which came from which print statement, or what the values meant. We could add more string information into the output to label the outputs, which leads to clunky string concatenation expressions like

`print("lst-length: " + to-string(lst.length()))`

This ends up being onerous and error prone.

Finally, for rich values like tables and images, the string representation produced by print isn’t as useful as the rich rendering that Pyret provides in an interface like code.pyret.org.

The spy statement is designed to make it natural and useful to add printed observations to the program, supporting and enhancing the practice of “printf-debugging”.