# Expressions

On the previous pages we talked a lot about printable expressions and regular expressions. So let's clarify what exactly an expression is.

An expression is a Go expression that yields a value. Valid Expressions are:

1. A variable or constant
2. A Go expression/literal like `"abc"`, `123`, or `"abc" == "def"`.
3. A function call that returns a single value

Additionally, corgi adds a ternary and a "chain" expression. More on that below. And, of course, string interpolation, which you already learned about in the interpolation chapter.

{% hint style="warning" %}
**Implementation Note:** While you can use `` `backtick strings ``\` you cannot span them over multiple lines like you can in Go. Depending on your use case there are better alternatives.
{% endhint %}

## Printable Types

If your expression gets printed, e.g. the value of an attribute, you are restricted to these printable types:

1. `uint`, `uint8`, `uint16`, `uint32`, `uint64`
2. `int`, `int8`, `int16`, `int32`, `int64`
3. `string`
4. `bool`
5. `corgi.HTML`, `corgi.HTMLAttr`, `corgi.CSS`, `corgi.URL`, `corgi.Srcset`, `corgi.JS`, `corgi.JSStr,` and `corgi.JSAttr` in their appropriate contexts (more on them in the Security and Escaping chapter)
6. Any type implementing `fmt.Stringer`
7. A pointer to the above
8. A (possibly typed) `nil` which will print nothing

If you try to print something else, the generated function will return with an error.

## Ternary Expressions

Aside from the expressions listed above, corgi also supports ternary expressions in the form of a special ternary function.

```go
func ?[T any](cond bool, ifTrue, ifFalse T) T
```

`ifTrue` and `ifFalse` can be any Go expression.

`cond` can be any Go expression that yields a `bool` value.

```pug
func Ternary(authenticated, admin bool)

p(class = ?(authenticated, "authed", "anon"))
p(class = ?(authenticated, ?(admin, "admin", "authed"), "anon"))
p(class = ?(authenticated && admin, "admin", "not-admin"))
p= ?(admin, "Hello boss!", "Hello someone.")
p Hello, #{?(admin, "boss", "someone")}.
p #{"Hello " + ?(admin, "boss", "someone")}.
```

Ternary expressions can be used anywhere in a regular Go expression.

## Chain Expressions

You know the problem: You want to access `data.MyField.MySlice[3]`, but `MyField` could be `nil`, and `MySlice` might not even be of length `3`. The solution is to add `if`s that check nilness, length, and map indexes.

However, checks like these create an enormous bloat in template files. This is why corgi adds a second utility that allows you to perform those kind of checks. You can use a `?` to perform zero value checks, length/index checks, and checked type assertions for any expression that consists of only accessing fields/maps/slices.

{% hint style="info" %}
Chain Expressions cannot be embedded inside Go expressions.
{% endhint %}

```pug
// This checks if foo is not zero:
p #{foo?[0]}
// This checks if foo has an index or map entry 0:
p #{foo[0?]}
// This checks if that entry is not zero:
p #{foo[0]?}
// This performs a checked types assertion on that entry:
p #{foo[0].(string)?}
// And this performs all four checks:
p #{foo?[0?]?.(string)?}
```

You can also add a default if your checks fail by appending a `~`. Defaults can be any Go expression.

```pug
p #{foo? ~ "some default value"}
```

Depending on the context you use chain expressions, they behave differently:

1. When assigning a value to an attribute or setting the value of a mixin argument, that attribute or mixin arg will only be set if the value passes all checks. For required arguments you need to provide a default.
2. When used in interpolation and a check fails, nothing will be printed.
3. When used as condition for an `if`, the `if` will only be executed if all checks pass.
4. When used as a range expression in a `for` loop, that loop will only be executed if the value passes all checks.

{% hint style="info" %}
**Technical Note:** Corgi guarantees that it will call each function in a chain expression only once.
{% endhint %}

If the expression yields a pointer that you want to dereference, you can place an `*` at the start of the expression to dereference the resolved value. Defaults are assumed to be already dereferenced.

```pug
mixin foo(bar string) #{bar}

- s := "foo"
  s1 := &s
foo(bar=*s1? ~ "baz")
```

Here are a couple more examples, just to make sure you undestand everything:

{% tabs %}
{% tab title="Corgi" %}

```pug
mixin greet(name="world")
    Hello #{name}!

- var t struct{F *string}

a(href=*t.F?) Click me!
a(href=*t.F? ~ "bar") Click me!

p #{t.F?}

p #+greet(name=*t.F?)
p #+greet(name=*t.F? ~ "universe")

p The value is: #{t.F?}
p The value is #{t.F? ~ "unknown"}

if t.F?
  p The value is: #{t.F}
else
  p The value is not accessible.
```

{% endtab %}

{% tab title="HTML - F is set" %}

```markup



<!-- t := T{F: "foo"} -->

<a href="foo">Click me!</a>
<a href="foo">Click me!</a>

<p>foo</p>

<p>Hello world!</p>
<p>Hello universe!</p>

<p>The value is: foo</p>
<p>The value is: foo</p>


<p>The value is: foo</p>


```

{% endtab %}

{% tab title="HTML - F is not set" %}

```markup



<!-- t := T{F: nil} -->

<a>Click me!</a>
<a href="bar">Click me!</a>

<!-- not rendered -->

<p>Hello foo!</p>
<p>Hello foo!</p>

<p>The value is: </p>
<p>The value is: unknown</p>




<p>The value is not accessible.</p>
```

{% endtab %}
{% endtabs %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://mavolin.gitbook.io/corgi/learning-corgi/expressions.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
