Qi Meeting Sept 26 2025 - drym-org/qi GitHub Wiki

Dope Docstrings

Qi Meeting September 26 2025

Adjacent meetings: Previous | Up | Next

Summary

We discussed how we could use scribble/srcdoc to implement docstrings in a #lang raqit experiment.

Background

Dominik has always been a big advocate of scribble/srcdoc. Sid has always been a fan of docstrings in a language. Pen pineapple apple pen 🕺: Docstrings in a #lang powered by scribble/srcdoc could be the best docstrings in any language, ever!

Dope Docstrings

What if docstrings in your #lang could look like this:

(fun add-two-nums (a b)
  """Add two numbers @racket[a] and @racket[b]."""
  (+ a b))

And could produce docs like this without any extra work:

dope doc output

We rest our case.

How?

For a standalone prototype, create these files:

raqit.rkt

#lang racket/base

(require (for-syntax racket/base
                     syntax/parse)
         scribble/srcdoc
         racket/contract/base
         (for-doc scribble/manual))

(define-syntax (fun stx)
  (syntax-parse stx
    ((_ id:id formals doc body ...)
     #'(begin
         (provide
          (proc-doc/names
           id
           (-> number? number? number?)
           formals
           doc
           ))
         (define id (lambda formals body ...))))))

(fun add-two-nums (a b)
  ("Add two numbers " (racket a) " and " (racket b) ".")
  (+ a b))

(add-two-nums 1 2)

raqit.scrbl

#lang scribble/manual

@title{Raqit}

@require[scribble/extract]

@defmodule["raqit.rkt"]
@include-extracted["raqit.rkt"]

Then run it:

$ scribble +m raqit.scrbl

Adding It to a #lang For Real

To incorporate it into a raqit language experiment with the desired docstring syntax, we felt that what would be needed would be:

  1. A reader extension that parses """ e ... """ as (docstring e ...).

  2. A docstring macro that expands "@-expression" Scribble syntax into raw Racket syntax, i.e., symexes, like in the standalone code example above.

  3. Providing scribble/srcdoc from the language's expander.

Of these, (3) is trivial, (1) should be straightforward once we have the infrastructure for adding reader extensions at all (which we currently don't), so the main challenge would be parsing @-expression syntax into Racket syntax. If we can actually delegate to the at-exp code for this, that would be nice. But it doesn't seem like it would be too bad, either way!

Load Times?

We immediately wondered if Rhombus already implements something like this. As far as we could tell, it does not currently sport docstrings, and we guessed that one reason could be the chain of dependencies that would be implied by using Scribble, which might negatively impact load times.

We don't have any specific performance requirements at this time for #lang raqit, and most likely, there is a place for a user-friendly flowy language that performs well in target use cases (e.g., sequences and (Big) data transformations).

Other Topics

We also talked about challenges at scale in encrypting Big Data, the feasibility of homomorphic encryption with respect to data integrity, neat macros for request parsing and dispatch in developing Racket web apps, spending time in the garden, and train journeys to Brno.

Next Steps

(Some of these are carried over from last time)

  • Ready the inlining PR to be merged and tag for code review.
  • Write phase 1 unit tests for inlining.
  • Define the define-producer, define-transformer, and define-consumer interface for extending deforestation (also encapsulating both naive and stream semantics in the definition), and re-implement existing operations using it.
  • Implement the remaining producers and transformers in racket/list for qi/list.
  • Attach a deforested syntax property in the deforestation pass, and use it in compiler rules tests (instead of string matching).
  • Improve qi/list and deforestation testing by writing a macro to simultaneously test the expansion and the semantics.
  • Investigate whether the deforested operations could be expressed using a small number of core forms like #%producer, #%transformer, #%consumer, and #%stream.
  • Decide on whether there will be any deforested operations provided in (require qi) (without (require qi/list))
  • Review which racket/list forms are actually needed in qi/list
  • Come up with a good way to validate the syntactic arguments to range using contracts.
  • Start organizing qi-lib into qi and qi/base collections
  • Publish qi/class in some form.
  • Implement DAG-like binding rules for branching forms [Syntax Spec parallel binding-spec PR]
  • Formalize Qi's semantics using Redex.
  • Incorporate effects and bindings into Qi's pen-and-paper semantic model.
  • Return to developing Qi's theory of effects, including accounting for binding rules.
  • Write a proof-of-concept for implementing code generation from abstractions of "flow" and "connective tissue" that are set by a context parameter.
  • Why is range-map-car slower against Racket following the Qi 5 release?
  • Decide on appropriate reference implementations to use for comparison in the new benchmarks report and add them.
  • Add reader flow syntax in #lang qi
  • Develop a backwards-incompatibility migration tool using Resyntax, to be used in the next Qi release.

Attendees

Dominik, Sid

⚠️ **GitHub.com Fallback** ⚠️