Conversely, you should use racket (or even racket/gui) when you just want a convenient language to write some program. The racket language comes with almost all the batteries, and racket/gui adds the rest of the GUI base.
Imagine you are working on a library. You start with one module, but before you know it the set of modules grows to a decent size. Client programs are unlikely to use all of your library’s exports and modules. If, by default, your library includes all features, you may cause unnecessary mental stress and run-time cost that clients do not actually use.
In building the Racket language, we have found it useful to factor
libraries into different layers so that client programs can selectively
import from these bundles. The specific Racket practice is to use the most
prominent name as the default for the module that includes everything. When
it comes to languages, this is the role of racket. A programmer who wishes
to depend on a small part of the language chooses to racket/base instead;
this name refers to the basic foundation of the language. Finally, some of
Racket’s constructs are not even included in racket—
Other Racket libraries choose to use the default name for the small core. Special names then refer to the complete library.
We encourage library developers to think critically about these decisions and decide on a practice that fits their taste and understanding of the users of their library. We encourage developers to use the following names for different places on the "size" hierarchy:
library/kernel, the bare minimal conceievable for the library to be usable;
library/base, a basic set of functionality.
library, an appropriate "default" of functionality corresponding to either library/base or library/full.
library/full, the full library functionality.
Finally, the advice of the previous section, to use racket/base when building a library, generalizes to other libraries: by being more specific in your dependencies, you are a responsible citizen and enable others to have a small (transitive) dependency set.
Macros copy code. Also, Racket is really a tower of macro-implemented languages. Hence, a single line of source code may expand into a rather large core expression. As you and others keep adding macros, even the smallest functions generate huge expressions and consume a lot of space. This kind of space consumption may affect the performance of your project and is therefore to be avoided.
When you design your own macro with a large expansion, try to factor it into a function call that consumes small thunks or procedures.
As you can see, the macro on the left calls a function with a list of the searchable values and a function that encapsulates the body. Every expansion is a single function call. In contrast, the macro on the right expands to many nested definitions and expressions every time it is used.
Racket provides a number of unsafe operations that behave like their related, safe variants but only when given valid inputs. They differ in that they eschew checking for performance reasons and thus behave unpredictably on invalid inputs.
As one example, consider fx+ and unsafe-fx+. When fx+ is applied to a non-fixnum?, it raises an error. In contrast, when unsafe-fx+ is applied to a non-fixnum?, it does not raise an error. Instead it either returns a strange result that may violate invariants of the run-time system and may cause later operations (such as printing out the value) to crash Racket itself.
Do not use unsafe operations in your programs unless you are writing software that builds proofs that the unsafe operations receive only valid inputs (e.g., a type system like Typed Racket) or you are building an abstraction that always inserts the right checks very close to the unsafe operation (e.g., a macro like for). And even in these situations, avoid unsafe operations unless you have done a careful performance analysis to be sure that the performance improvement outweighs the risk of using the unsafe operations.