How does the scope of the `editor` object work in the Goblins white paper's blog post editor example?

I was reading the Goblins white paper when I got stuck on the blog post example in section 3.3. More specifically, within the definition of the spawn-post-and-editor function, it seems like the get-content method of ^post is able to reference the editor object that is only defined towards the end of spawn-post-and-editor. I am not sure how this is able to work. Is there some aspect of Scheme or Guile Scheme’s semantics that I am missing?

Nice catch - what you’re missing is that it’s a closure. The post and editor variables are both enclosed in the scope of the spawn-post-and-editor function.

It’s the same reason this code works:

(define (test-func)
  (define (inner)
    x)
  (define x 5)
  inner)

…and evaluates to this:

scheme@(guile-user)> ((test-func))
$7 = 5

What you’re seeing are recursive definitions. ^post, ^editor, post, and editor are all defined within spawn-post-and-editor and it’s no problem in Scheme for ^post to refer to editor within the procedure body. Perhaps this rewrite to use letrec will make it more clear to you:

(define* (spawn-post-and-editor #:key title author body)
  (letrec ((^post
            ;; The public blogpost
            (lambda (bcom)
              (methods
               ;; fetches title, author, and body, tags with '*post* symbol
               ((get-content)
                ;; assign data-triple to the current data
                (define data-triple ($ editor 'get-data))
                ;; return tagged with '*post*
                (cons '*post* data-triple)))))
           (^editor
            ;; The editing interface
            (lambda (bcom title author body)
              (methods
               ;; update method can take keyword arguments for
               ;; title, author, and body, but defaults to their current
               ;; definitions
               ((update #:key (title title) (author author) (body body))
                (bcom (^editor bcom title author body)))
               ;; get the current values for title, author, body as a list
               ((get-data)
                (list title author body)))))
           ;; spawn and return the post and editor
           (post (spawn ^post))
           (editor (spawn ^editor title author body)))
    (values post editor)))  ; multi-value return of post, editor

Thanks for the answer, Jonathan.

Thanks for the explanation, David. That does help to clear things up. Would it be possible for your explanation to be added to a future version of the paper? I think this would be really helpful for other non-native Schemers like myself.

Also, would it have been equally valid to change the order of the definitions to be ^editor, editor, ^post and then post? If I understand correctly, perhaps this way it would be clearer that, in this particular case, there does not need to be any recursive dependency between ^post and editor (although I suppose the ^editor constructor itself would still necessarily be recursive).

I think your second suggestion of just changing the definition order would be the better thing to do as the references aren’t actually recursive. That would save us from explaining a finer detail of Scheme. Filed an issue here Change variable definition order in spawn-post-and-editor procedure in spritely-core (#15) · Issues · spritely / Spritely Papers · GitLab

1 Like