Trouble with submodules

Hi,

I am having some trouble with submodules. The following short program gives an error in DrRacket 9.0:

#lang racket/base

(require 'bar)

(define (foo)
  "foo")

(module bar racket/base
  (provide bar)
  (define (bar)
    "bar"))

It complains about:

require: unknown module
  module name: 'bar

Why does this code not work?

Regards
Rouan

Move the submodule to the top. The top-level forms of the outer modules are processed in order, meaning when Racket gets to (require ‘bar) it hasn’t seen (module bar …) yet.

Thanks.

If I move it to the top then it works in DrRacket for this small example.

I could not find anywhere in the official docs that there is a requirement that submodules must be defined before they are required. Did I miss it or is it undocumented?

I also am trying to use submodules in a bigger project where I have lots of actual .rkt files. In 1 of the files I am trying to use submodules:

#lang racket/base

(module tst2 racket/base
  (provide
    foo)

  (define (foo)
    "fooyoh"))

(provide
  generate-data-entities)

(require
  'tst2
  "../gunit/_module.rkt"
  "../../../sysmodel/core/_module.rkt"
  sunshine-fw/sourcecode/code/oo/ast/builder
  sunshine-fw/slib/data-struct
  threading
  racket/undefined)

Racket then gives me the error:

../../../../bin/racket9_0/share/pkgs/errortrace-lib/errortrace/stacktrace.rkt:409:4: errortrace: unrecognized expression form at top-level: (module tst2 racket/base (#%module-begin (module configure-runtime (quote #%kernel) (#%module-begin (#%require racket/runtime-config) (#%app configure (quote #f)))) (#%provide foo) (define-values (foo) (lambda () (quote "fooyoh")))))

Am I doing something wrong here?

I think we need more context to explain this error. When I comment out the collects and filed I don’t have, I get generate-data-entities not defined, as expected.

It certainly has nothing to do with submodules.

Thanks, I dug a little deeper and narrowed the error I am getting to the import:

sunshine-fw/sourcecode/code/oo/ast/builder

That module exports an identifier called module which interfered with the Racket module form.
If I import that module as prefixed, then my errors go away.

Now the only thing I am still wondering is the requirement that a module must be defined before it is required. I would like the submodules at the bottom of the file not the top really. Is there no way to do this using the (module) form?

This is an outcome of behavior documented in a few places, most clearly in Module Expansion, Phases, and Visits:

A require form not only introduces bindings at expansion time, but also visits the referenced module when it is encountered by the expander.

In other words, the expander will attempt to locate the module's code as soon as it hits the require clause.

Put another way, imports aren't "delayed" until after expansion, they happen on the go. module clauses work similarly, which is why you can require a module that's declared previously in the same file.

Thanks Todd,

That explanation is not as straight forward for new devs learning Racket. I think it would be beneficial to update the Racket Guide or Racket Reference to actually state this explicitly.

I will update my own Racket book with a more explicit explanation of define-a-module-before-requiring-it behaviour :slight_smile:

I will go with putting the submodules at the top as this seems to be per-design of Racket.

Thanks for everyone who put me on the right path.
Always a pleasure to be part of the Racket community.

You may wish to look at Modular Programming.

This might be more flexible than you're thinking?

Just to make sure it's clear, you don't have to put the submodules at the top. You merely need to require the submodule after its definition.

So although you may, you don't have to do:

#lang racket/base

(module m racket/base
  (provide thing)
  (define thing 42))
(require 'm)

thing

You may also do:

#lang racket/base

thing

(module m racket/base
  (provide thing)
  (define thing 42))
(require 'm)

There may also exist multiple requires, so it is not uncommon to see the following layout -- with most things required at the top, plus your submodule require below:

#lang racket/base

(require racket/match
         foobar
         "some-file.rkt")

thing

(module m racket/base
  (provide thing)
  (define thing 42))
(require 'm)

TL;DR:

  1. If you prefer a "top-down" layout with "supporting"/"helper" definitions toward the bottom, and want to think of submodules like that, you totally can do that!

  2. You can think of (module m __) (require 'm) as a pair you always do in that order, preferably right next to each other. You can put that pair, together, in that order, anywhere at the file's top level.

Thanks Greg,

That is awesome and allows more flexible structuring of submodules.

Hazaaaaa :slight_smile: