14 Module reference
14.1 Cache
14.2 Core
14.3 Decode
14.4 File
14.5 Pagetree
14.6 Render
14.7 Setup
14.8 Tag
14.9 Template
14.10 Top
On this page:
#%top
def/  c
8.12

14.10 Top🔗ℹ

 (require pollen/top) package: pollen

You’ll probably never invoke this module directly. But it’s implicitly imported into every Pollen markup file. And if you don’t know what it does, you might end up surprised by some of the behavior you get.

syntax

(#%top . id)

In standard Racket, #%top is the function of last resort, called when id is not bound to any value. As such, it typically reports a syntax error.

Examples:
; Let's call em without defining it
> (em "Bonjour")

em: undefined;

 cannot reference an identifier before its definition

  in module: top-level

; (em "Bonjour") is being converted to ((#%top . em) "Bonjour")
; So calling ((#%top . em) "Bonjour") will give the same result
> ((#%top . em) "Bonjour")

em: undefined;

 cannot reference an identifier before its definition

  in module: top-level

In the Pollen markup environment, however, this behavior is annoying. Because when you’re writing X-expressions, you don’t necessarily want to define all your tags ahead of time.

So Pollen redefines #%top. For convenience, Pollen’s version of #%top assumes that an undefined tag should just refer to an X-expression beginning with that tag (and uses default-tag-function to provide this behavior):

Examples:
; Again, let's call em without defining it, but using pollen/top
> (require pollen/top)
> (em "Bonjour")

'(em "Bonjour")

; (em "Bonjour") is still being converted to ((#%top . em) "Bonjour")
; But now, ((#%top . em) "Bonjour") gives a different result
> ((#%top . em) "Bonjour")

'(em "Bonjour")

The good news is that this behavior means you use any tag you want in your markup without defining it in advance. You can still attach a function to the tag later, which will automatically supersede #%top.

Examples:
> (define (em x) `(span ((style "font-size:100px")) ,x))
> (em "Bonjour")

'(span ((style "font-size:100px")) "Bonjour")

The bad news is that you’ll never get an “unbound identifier” error. These unbound identifiers will happily sail through and be converted to tags.

Examples:
> (require pollen/top)
> (define (em . xs) `(span ((style "font-size:100px")) ,@xs))
; There's a typo in my tag
> (erm "Bonjour")

'(erm "Bonjour")

If you prefer the ordinary Racket-style behavior where unbound identifiers raise an error, define setup:allow-unbound-ids? in your project to be #false.

This isn’t a bug. It’s just a natural consequence of how Pollen’s #%top works. It can, however, make debugging difficult sometimes. Let’s suppose my markup depends on very-important-function, which I don’t import correctly.

Examples:
> (require pollen/top)
> (module vif racket/base
      (define (very-important-function . xs) `(secrets-of-universe ,@xs)))
; Forgot to (require 'vif)
> (very-important-function "Bonjour")

'(very-important-function "Bonjour")

So the undefined-function bug goes unreported. Again, that’s not a bug in Pollen — there’s just no way for it to tell the difference between an identifier that’s deliberately undefined and one that’s inadvertently undefined. If you want to guarantee that you’re invoking a defined identifier, use def/c.

syntax

(def/c id)

Invoke id if it’s a defined identifier, otherwise raise an error. This form reverses the behavior of #%top (in other words, it restores default Racket behavior).

Recall this example from before. In standard Racket, you get an undefined-identifier error.

Examples:
> (module vif racket/base
      (define (very-important-function . xs) `(secrets-of-universe ,@xs)))
; Forgot to (require 'vif)
> (very-important-function "Bonjour")

very-important-function: undefined;

 cannot reference an identifier before its definition

  in module: top-level

But with pollen/top, the issue is not treated as an error.

Examples:
> (require pollen/top)
> (module vif racket/base
      (define (very-important-function . xs) `(secrets-of-universe ,@xs)))
; Forgot to (require 'vif)
> (very-important-function "Bonjour")

'(very-important-function "Bonjour")

By adding def/c, we restore the usual behavior, guaranteeing that we get the defined version of very-important-function or nothing.

Examples:
> (require pollen/top)
> (module vif racket/base
      (define (very-important-function . xs) `(secrets-of-universe ,@xs)))
; Forgot to (require 'vif)
> ((def/c very-important-function) "Bonjour")

very-important-function: undefined;

 cannot reference an identifier before its definition

  in module: top-level