I think it’s worth unpacking the nuance behind that question. Namely, why #include
is such a pain in C/C++, why Julia seems to have includes despite being a newer language and if the aforementioned pain points apply.
From a modules/namespacing perspective, the C compilation model has 4 main quirks:
- There is only one global namespace. C++ adds lexical namespacing, and as you can imagine that helps immensely.
- Declaration and implementation are split between header and c/cpp files. As I’ll address in a second, this is a minefield and practically no modern language retains this approach.
- Includes are not syntax aware and can paste code anywhere. Think using an include to add the signature for a function!
- The default object-based linking model necessitates inclusion of the same header in multiple locations. This dramatically increases the chance of multiple inclusions per object and thus header guards.
Now to Julia. Julia’s module system is, as far as I can tell, a near copy of Ruby’s. Contrasting to the C/C++ system:
- Namespaces are pervasive and not purely lexical (modules are first class “objects”).
- Declaration is almost always implementation and thus source files are included directly.
include
is syntax-aware and must only introduce fully-formed constructs (types, variables and functions for Julia). No literal copying and pasting of partial functions.
- Most importantly, code is extracted into external files and then included only as a space-saving measure. This is in contrast to something like PHP where common includes were/are used all the time. Conceptually, this means that reversing all includes and inlining everything into one
.jl
file is semantically equivalent. It also means that duplicate definitions are essentially non-existent unless someone purposefully writes them out multiple times.
Conceptually, you can think of this as a “unity build” in C/C++ projects, where source files are included directly and only limited headers are required for external dependencies. Incidentally, unity builds do not suffer from many of the #include
-related pitfalls that normal C/C++ projects do, but face cultural aversion and a lack of tooling support. Neither of these concerns are present in Julia.
One point I do agree upon is tooling and discoverability. Here though, I’m not sure include
is primarily to blame, but using
. As an example, compare browsing through C# and Java projects on GitHub. The former only has using
and thus makes finding what comes from where difficult, whereas the latter primarily uses import.
However, I’m going to pin this on the tooling and not the language. For example, looking through Python projects was a pain before the new go-to-definition functionality because of varying PYTHONPATH
s. Github’s search functionality is also a dumpster fire on the best of days.
Thankfully you don’t have to. JuliaHub is an invaluable resource (I would say essential infrastructure at this point) even when using an IDE. For local code, there is a LSP plugin for pretty much every mainstream text editor out there.
Philosophical tangent/rant: Despite being a big fan of Vim, I believe the “UNIX is my IDE and text is all you need” crowd has set us back at least 20 years in PLT and PL tooling design. It’s nice to see a) C losing mindshare and b) fewer languages catering to that crowd.
PS: Neural CDEs are great