The Racket docs indicate that Racket has separate forms for: require
, load
, include
, and import
. Many other languages only contain one of these and are generally used synonymously (although obviously with language specific differences such as #include
in C, and import
in Java).
Since Racket has all four of these, what is the difference between each one and which should I be using in general? Also if each has a specific use, when should I use an alternative type? Also, this question seems to indicate that require
(paired with provide
) is preferred, why?
You are correct, the default one you want is almost always require
(paired with a provide
). These two forms go hand in hand with Racket's modules
and allows you to more easily determine what variables should be scoped in which files. For example, the following file defines three variables, but only exports 2.
#lang racket ; a.rkt
(provide b c)
(define a 1)
(define b 2)
(define c 3)
As per the Racket style guide, the provide should ideally be the first form in your file after the #lang
so that you can easily tell what a module provides. There are a few cases where this isn't possible, but you probably won't encounter those until you start making your own Racket libraries you intend for public distribution. Personally, I still put a file's require
before its provide
, but I do sometimes get flack for it.
In a repl, or another module, you can now require this file and see the variables it provides.
Welcome to Racket v6.12.
> (require "a.rkt")
> c
3
> b
2
> a
; a: undefined;
; cannot reference undefined identifier
; [,bt for context]
There are ways to get around this, but this serves as a way for a module to communicate what its explicit exports are.
This is a more dynamic variant of require. In general you should not use it, and instead use dynamic-require
when you need to load a module dynamically. In this case, load
is effectively a primitive that require
uses behind the scenes. If you are explicitly looking to emulate the top level however (which, to be clear, you almost never do), then load is a fine option. Although in those rare cases, I would still direct you to the racket/load
language. Which interacts exactly as if each form was entered into the repl directly.
#lang racket/load
(define x 5)
(displayln x) ; => prints 5
(define x 6)
(displayln x) ; => prints 6
Include is similar to #include
in C. There are even fewer cases where you should use it. The include
form grabs the s-expression syntax of the given path, and puts it directly in the file where the include
form was. At first, this can appear as a nice solution to allow you to split up a single module into multiple files, or to have a module 'piece' you want to put in multiple files. There are however better ways to do both of those things without using include
, that also don't come with the confusing side effects you get with include.1 One thing to remember if you still insist on using import
, is that the file you are importing probably shouldn't have a #lang
line unless you are explicitly wanting to embed a submodule. (In which case you will also need to have a require
form in addition to the include
).
Finally, import
is not actually a core part of Racket, but is part of its unit system. Units are similar in some ways to modules, but allow for circular dependencies (unit A can depend on Unit B while Unit B depends on Unit A). They have fallen out of favor in recent years due to the syntactic overhead they have.
Also unlike the other forms import
(and additionally export
), take signatures, and relies on an external linker to decide which actual units should get linked together. Units are themselves a complex topic and deserve their own question on how to create and link them.
TLDR; Use require
and provide
. They are the best supported and easiest to understand. The other forms do have their uses, but should be thought of 'advanced uses' only.
1These side effects are the same as you would expect for #include
in C. Such as order being important, and also with expressions getting intermixed in very unpredictable ways.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With