# Inline annotations

A `#:` comment repeats every parameter name of the function below it, so renaming a parameter
means editing two places. Inline annotations put each type next to the name it belongs to, which is
shorter to write and to read, and on ry's runtime they are also checked when the code runs. The
cost is that plain `Rscript` cannot run a file that has them, which is why this is a separate step.
They are on by default; a project that must stay runnable by `Rscript` can
[turn them off](#turning-inline-annotations-off).

You write a type right after a name, and a function's return type after its parameters:

## Inline

```r
apply_discount <- function(price: double, rate: double = 0.2) -> double {
  price * (1 - rate)
}

apply_discount("100")
```

## Comments

```r
#: fn(price: double, [rate]: double) -> double
apply_discount <- function(price, rate = 0.2) {
  price * (1 - rate)
}

apply_discount("100")
```

```text
type-mismatch

  x expected `double`, found `character`
```

Every typed page of this guide already shows this spelling in its Inline tab, and it shares one
type language with `#:` comments, so this page covers only what changes when you switch. Deleting
each inline annotation turns a file into the plain R program it means. That includes `@pure` in
front of `function`, the inline spelling of the `#: @pure` comment that
[strict mode](/type-checking/strict-mode.md#package-files-only-define-things) reads.

Definitions are spelled `type UserId = integer` and `alias Row = list{id: integer}`, and
`@UserId(raw)` creates a value of a nominal type, as [custom types](/type-checking/custom-types.md)
shows. A binding takes `@trust`, `@if-unknown` and `@new` between its `:` and its type, as in
`id: @new UserId <- 5L`. `type` and `alias` are definitions only when a name follows them on the
same line, so R code that uses them as ordinary names keeps working.

## When the two disagree

A statement may carry both spellings. If they give a parameter, the return, or the value different
types, ry uses the inline type and warns:

```r
#: fn(price: double, rate: double) -> double
apply_rate <- function(price: integer, rate) price * rate
```

```text
annotation-mismatch

  ! the inline annotation gives parameter `price` the type `integer`, but the `#:` comment gives it `double`. ry uses the inline type; make the two agree, or delete one
   --[R/both.R:2:31]
 1 | #: fn(price: double, rate: double) -> double
 2 | apply_rate <- function(price: integer, rate) price * rate
   |                               ^^^^^^^
  `->   > the `#:` comment's type is here
         --[R/both.R:1:14]
       1 | #: fn(price: double, rate: double) -> double
         |              ^^^^^^
       2 | apply_rate <- function(price: integer, rate) price * rate
```

A `#:` definition directly above an inline definition of the same name is the same definition
written twice, so it is not a duplicate. ry uses the inline one and warns when the two differ:

```r
#: @type Celsius {double}
type Celsius = integer
```

```text
annotation-mismatch

  ! the inline definition of `Celsius` says `integer`, but the `#:` comment says `double`. ry uses the inline definition; make the two agree, or delete one
```

## Running annotated code

`ry run` runs annotated code on ry's own runtime, where the annotations also become checks: an
argument of the wrong kind fails where the function was called. `ry R` runs it on GNU R as the plain
program it means, with the annotations erased.

```r
scale <- function(values: double, by: double) -> double values * by
scale("a", 1)
```

```text
$ ry run scale.R
Error in scale("a", 1) :
  argument `values` must be `double`, not `character`
Execution halted
```

A check runs when the argument is first used, so lazy arguments stay lazy, and it tests only the
kind of value (`double`, `character`, a list, a function), not its length or class. Both commands
also print the warnings above before the code runs. The
[type system reference](/reference/type-system.md#inline-annotations-at-run-time) has the full rules.

## Turning inline annotations off

Turn inline annotations off when every file must also run under `Rscript` and other R tools, which
cannot parse them:

```toml
[check]
inline-annotations = false
```

ry then reports every inline annotation it finds, so none slips into a file that must stay plain R.
It warns once for the project and again at each annotation:

```text
  ! inline type annotations are turned off (`[check] inline-annotations = false`), so ry does not check them and reports each one it finds

inline-annotation

  ! inline type annotations are turned off (`[check] inline-annotations = false`), so this one is not checked. R itself cannot run this code: delete the annotation, or turn inline annotations back on
```

`ry run` still runs such a file, but nothing checks the annotations. Use `#:` comments in such a
project. The [type system reference](/reference/type-system.md#inline-annotation-syntax) lists every
place an inline annotation may go.
