# I come to bury .mod files not to praise them

**URL:** <https://fortran-lang.discourse.group/t/i-come-to-bury-mod-files-not-to-praise-them/11128>\
**Category:** Advocacy\
**Created:** [September 25, 2026, 6:33pm UTC](https://fortran-lang.discourse.group/t/i-come-to-bury-mod-files-not-to-praise-them/11128 "2026-09-25T18:33:29Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![certik](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/certik/32/4_2.png) [@certik](https://fortran-lang.discourse.group/u/certik)\
**Post date:** [September 28, 2026, 5:57am UTC](https://fortran-lang.discourse.group/t/i-come-to-bury-mod-files-not-to-praise-them/11128/21 "2026-09-28T05:57:04Z")

</div>

Encouraged by this thread, I decided to simply prototype the namespaces in LFortran: [Namespace imports for modules (use, namespace): prototype by certik · Pull Request #13800 · lfortran/lfortran · GitHub](https://github.com/lfortran/lfortran/pull/13800), here is a nice document describing how it works: [lfortran/doc/src/namespace\_modules.md at 801061698f57664ca0c9b238c1e7db51a35c8725 · certik/lfortran · GitHub](https://github.com/certik/lfortran/blob/801061698f57664ca0c9b238c1e7db51a35c8725/doc/src/namespace_modules.md), there are a lot of tests. I am still working on it, but so far I haven’t seen any blocker or a reason why this cannot work (because it works :).

---

<div class="post-metadata">

**Author:** ![kkifonidis](https://avatars.discourse-cdn.com/v4/letter/k/898d66/32.png) [@kkifonidis](https://fortran-lang.discourse.group/u/kkifonidis)\
**Post date:** [September 28, 2026, 10:27am UTC](https://fortran-lang.discourse.group/t/i-come-to-bury-mod-files-not-to-praise-them/11128/22 "2026-09-28T10:27:43Z")

</div>

> [@MarDie](#):
>
> That is a question of programming paradigm. For object-oriented style (as in C++), a single import would indeed be sufficient. I believe that your example suggests that each module implements a single type (or a few types) and all procedures are bound to that type …

Yes, this is what I meant.

The lack of qualified imports in the language (a la `import numpy as np`) can be overcome by binding all procedures (and the data they operate on) to derived types, and by using only the latter for imports. This amounts to consistent use of encapsulation/data abstraction.

> [@MarDie](#):
>
> When using functional style, a module will contain many functions that operate on it’s arguments only. In that case, namespaces would indicate where these functions come from.

I agree that if a language is supposed to support different programming paradigms, then it should provide all the necessary means to program in those paradigms.

> [@MarDie](#):
>
> If `myType` has no members, i.e. a state, `myVariable` would be the namespace. I still have to decide whether I like this hack.

I’d recommend to view this as far more than a hack, because it allows one to decouple one’s code by doing the next step in this logical chain. Namely, to forego even imports of single concrete types, and to use polymorphism in order to import abstractions (e.g. the future traits) instead, that concrete types must implement.

---

<div class="post-metadata">

**Author:** ![irukoa](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/irukoa/32/3306_2.png) [@irukoa](https://fortran-lang.discourse.group/u/irukoa)\
**Post date:** [September 28, 2026, 6:16pm UTC](https://fortran-lang.discourse.group/t/i-come-to-bury-mod-files-not-to-praise-them/11128/23 "2026-09-28T18:16:40Z")

</div>

There is perhaps another, much simpler direction worth considering. Instead of trying to make `.mod` files smarter, or replacing them with a compiler-managed database, we can avoid making module files part of the build interface altogether.

My proposal is based on C’s `#include` model, using `module` + `submodule`. The convention is: `M90` for interfaces and `F90` for implementations. The implementation file includes its interface:

```fortran
! Foo.F90
#include "Foo.M90"

submodule (Foo) FooImpl
contains
   ![...]
end submodule FooImpl

```

where

```fortran
! Foo.M90
#ifndef FOO_MODULE
#define FOO_MODULE

module Foo
  ![...]
end module Foo
#endif

```

The compiler only needs to process implementation files. The important condition is simply:

> Any implementation that would cause a symbol to be emitted into the corresponding object file must not be part of an interface (`M90`) file.

This makes the interface effectively analogous to a C header, as it can be included in multiple translation units without producing duplicate linker definitions.

The consequence is that the build system no longer consumes `.mod` files. Dependency tracking can then be reduced to the usual C pattern: the build system tracks `#include` dependencies between source files. The price is that the interface is processed again for every translation unit that includes it. I think this is worth considering separately from the “let the compiler own the build database” approach.

---

<div class="post-metadata">

**Author:** ![jwmwalrus](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/jwmwalrus/32/4483_2.png) [@jwmwalrus](https://fortran-lang.discourse.group/u/jwmwalrus)\
**Post date:** [September 28, 2026, 7:32pm UTC](https://fortran-lang.discourse.group/t/i-come-to-bury-mod-files-not-to-praise-them/11128/24 "2026-09-28T19:32:47Z")

</div>

> [@irukoa](#):
>
> ```fortran
> ! Foo.M90
> #ifndef FOO_MODULE
> #define FOO_MODULE
> 
> module Foo
> ![...]
> end module Foo
> #endif
> 
> ```

Hmm…

C++ introduced modules, in part, to try to move away from header-guard-hell (and the `#pragma once` hack). And newer languages (like Go, Rust, Zig) were built around the idea of avoiding just that same hell/hack.

---

<div class="post-metadata">

**Author:** ![irukoa](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/irukoa/32/3306_2.png) [@irukoa](https://fortran-lang.discourse.group/u/irukoa)\
**Post date:** [September 28, 2026, 8:14pm UTC](https://fortran-lang.discourse.group/t/i-come-to-bury-mod-files-not-to-praise-them/11128/25 "2026-09-28T20:14:13Z")

</div>

I agree that `#include` is not elegant. My point is that elegance is not the same thing as functionality. `#include` gives us a simple file composition mechanism to separate an interface from an implementation. Include guards may be a little tedious, but with a simple convention and discipline, they are not a significant obstacle.

The point of the thread is to bury `.mod` files, so I don’t see a need to create a new compilation architecture merely because Go/Rust/Zig solved a similar problem differently. We already have `module` and `submodule`; I’d rather exploit those than reinvent the wheel.

---

<div class="post-metadata">

**Author:** ![themos](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/themos/32/521_2.png) [@themos](https://fortran-lang.discourse.group/u/themos)\
**Post date:** [September 28, 2026, 9:04pm UTC](https://fortran-lang.discourse.group/t/i-come-to-bury-mod-files-not-to-praise-them/11128/26 "2026-09-28T21:04:18Z")

</div>

I asked Claude Code a question:

Q: _btw, thinking about a system to keep Fortran MODULE and SUBMODULE information, I imagine an alternative that uses a per-project (software library or executable) database to keep track not only of timestamps for source files but also of “uses”. For instance, for each MODULE X, the database would record each individual USE statement (naming that same MODULE X) in any other source file/program unit/scope. Can you describe how that would cut down on unnecessary recompilations?_

A: The key insight is that current build systems operate at the wrong granularity – they track file-level or module-level dependencies, but recompilation necessity is determined at the entity interface level. Here is how a USE-tracking database would help:

WHAT THE DATABASE RECORDS

For every compilation unit that contains a USE statement, it records not just “file B uses module M” but:

- Which specific entities from M are accessed (especially if USE M, ONLY: alpha, beta)
- Whether entities are renamed (USE M, local =\> M\_name) and under which local name referenced
- The interface fingerprint of each entity at the time of last compilation of the consumer

For each module definition, it records the interface fingerprint of every public entity.

HOW UNNECESSARY RECOMPILATIONS ARE ELIMINATED

1. Implementation changes that do not touch the public interface  
A subroutine body can be rewritten entirely. If its dummy argument list, result type, and INTENT specifications are unchanged, its interface fingerprint is unchanged. Every consumer that USEs that subroutine can be skipped.
2. Adding new public entities  
If a new subroutine is added to module M, consumers that do not reference it at all are unaffected.
3. Changes to private or internal entities  
Modifications to private module variables, internal subroutines, or local TYPE definitions not exposed in any public interface fingerprint do not propagate at all.
4. Submodule bodies  
A SUBMODULE implements MODULE PROCEDURE bodies – the interface is declared in the parent module and is fixed. Recompiling a submodule cannot possibly require recompilation of any USE consumer of the parent module.
5. ONLY-clause filtering  
USE M, ONLY: alpha means the consumer is entirely insulated from changes to every other entity in M.
6. Rename isolation  
USE M, local =\> M\_name means only M\_name’s fingerprint matters for that consumer.

THE PROPAGATION ALGORITHM

When source file F is recompiled and module M is regenerated:

1. Compute the set D of interface fingerprints that changed
2. If D is empty → no downstream action needed, regardless of file timestamp
3. For each consumer C: compute intersection of D with entities C accesses from M
4. If intersection is empty → skip C
5. If non-empty → recompile C, update stored fingerprints, recurse through C’s consumers

COMPOUNDING BENEFIT ACROSS DEEP DEPENDENCY GRAPHS

In a hierarchy A uses B uses C uses D, a change deep in D affecting only its private implementation would currently force recompilation of C, then B, then A. With the database, the chain stops at D immediately.

RELATION TO EXISTING .MOD FILE APPROACHES

.mod files are binary/opaque and force an all-or-nothing decision. The database reasons at the level of individual entities, handles ONLY-clause filtering, and stores the consumer’s view of the interface rather than just what the module currently exposes.

---

<div class="post-metadata">

**Author:** ![jwmwalrus](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/jwmwalrus/32/4483_2.png) [@jwmwalrus](https://fortran-lang.discourse.group/u/jwmwalrus)\
**Post date:** [September 28, 2026, 10:25pm UTC](https://fortran-lang.discourse.group/t/i-come-to-bury-mod-files-not-to-praise-them/11128/27 "2026-09-28T22:25:40Z")

</div>

I know it’s an LLM just being an LLM, but…

Isn’t that unnecessarily complicated? Full parsing, followed by git diff (for interfaces), followed by `ONLY` tracking (marginally useful, imho) —it’d be faster to just recompile the whole thing, hehehe.

My “slow human” approach would involve just having timestamps of sources and libraries/binaries, custom-preprocessing of sources (you can get module names and USE names from there), and tracking “library-x-provides-module-y”.

---

<div class="post-metadata">

**Author:** ![JohnCampbell](https://avatars.discourse-cdn.com/v4/letter/j/5daacb/32.png) [@JohnCampbell](https://fortran-lang.discourse.group/u/JohnCampbell)\
**Post date:** [September 29, 2026, 7:07am UTC](https://fortran-lang.discourse.group/t/i-come-to-bury-mod-files-not-to-praise-them/11128/28 "2026-09-29T07:07:15Z")

</div>

Since .mod files are opaque, I am not sure I have much of a view on them.  
They could do more.  
Why can’t there be a more formal requirement of the compiler to build an implicit project INTERFACE database, which could be supplemented and checked with explict INTERFACE and all calls.  
I remember in about 1998, using this new F95, I developed an include file of INTERFACE for all routines in my project, only to get errors that the INTERFACE could not be included in itself. I thought it would have been a good debug facility.  
Most compilers now do this in a non-standard way.

Prior to .mod files and modules, include files were very useful for minimising repeated definitions

As for partial recompile, I typically use a batch procedure for complete rebuild, as now few projects take longer that it takes to think if you are ready to test this new coding attempt !  
Compilers have become very good and very fast.

---

<div class="post-metadata">

**Author:** ![themos](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/themos/32/521_2.png) [@themos](https://fortran-lang.discourse.group/u/themos)\
**Post date:** [September 29, 2026, 8:31am UTC](https://fortran-lang.discourse.group/t/i-come-to-bury-mod-files-not-to-praise-them/11128/29 "2026-09-29T08:31:50Z")

</div>

Efficient recompilation may not be on your radar now, but if the AI revolution pans out and your agent is 24/7 searching the solution space, then I expect it to become the bottleneck.

---

<div class="post-metadata">

**Author:** ![JohnCampbell](https://avatars.discourse-cdn.com/v4/letter/j/5daacb/32.png) [@JohnCampbell](https://fortran-lang.discourse.group/u/JohnCampbell)\
**Post date:** [September 29, 2026, 9:37am UTC](https://fortran-lang.discourse.group/t/i-come-to-bury-mod-files-not-to-praise-them/11128/30 "2026-09-29T09:37:48Z")

</div>

> [@themos](#):
>
> if the AI revolution pans out and your agent is 24/7 searching the solution space, then I expect it to become the bottleneck.

I just can’t contemplate that.  
My rebuild cycle is:

devise a change or correction to the code  
implement the change  
rebuild  
modify the test suite to include the change  
do the tests  
review the tests  
cycle ;

I am understanding you are suggesting that AI will speed up all but rebuild.  
I am not so sure on some of the other steps I have suggested 🙂

I am however very impressed with what is claimed claude can do for step 1

---

<div class="post-metadata">

**Author:** ![wspector](https://avatars.discourse-cdn.com/v4/letter/w/47e85d/32.png) [@wspector](https://fortran-lang.discourse.group/u/wspector)\
**Post date:** [September 29, 2026, 2:21pm UTC](https://fortran-lang.discourse.group/t/i-come-to-bury-mod-files-not-to-praise-them/11128/31 "2026-09-29T14:21:20Z")

</div>

> [@JohnCampbell](#):
>
> I remember in about 1998, using this new F95, I developed an include file of INTERFACE for all routines in my project, only to get errors that the INTERFACE could not be included in itself. I thought it would have been a good debug facility.  
> Most compilers now do this in a non-standard way.

Submodules (F2008-onward) allow you to do this.

To me, the main problems with .mod (and .smod) files are:

1.) Each compiler has its own internal details. So there is no interoperability.

2.) Even when using one compiler vendor, version mismatches can occur with newer compilers and older .mod/.smod files and vice versa.

---

<div class="post-metadata">

**Author:** ![pjh503](https://avatars.discourse-cdn.com/v4/letter/p/85e7bf/32.png) [@pjh503](https://fortran-lang.discourse.group/u/pjh503)\
**Post date:** [September 29, 2026, 3:14pm UTC](https://fortran-lang.discourse.group/t/i-come-to-bury-mod-files-not-to-praise-them/11128/32 "2026-09-29T15:14:57Z")

</div>

Exactly - the primary issue with .mod files is they aren’t portable, which causes problems creating and distributing libraries built with Fortran. This is a particular problem since these are exactly the kinds of things for which we want a high-performance language like Fortran.

---

<div class="post-metadata">

**Author:** ![pjh503](https://avatars.discourse-cdn.com/v4/letter/p/85e7bf/32.png) [@pjh503](https://fortran-lang.discourse.group/u/pjh503)\
**Post date:** [September 29, 2026, 3:22pm UTC](https://fortran-lang.discourse.group/t/i-come-to-bury-mod-files-not-to-praise-them/11128/33 "2026-09-29T15:22:46Z")

</div>

Most compilers support a “syntax-only” first pass which can generate mod files, allowing the main build to be done in a far more parallelisable second pass. There is an issue that some of the compilers are pretty slow at the parsing, but for a big project the two-pass method really speeds things up. We found the main ideas here:

> **[Writing Makefiles for Modern Fortran](https://aoterodelaroza.github.io/devnotes/modern-fortran-makefiles/)**
>
> Notes on how to write Makefiles for (modern) fortran programs. Modules, submodules, and automatic dependency generation.

---

<div class="post-metadata">

**Author:** ![RonShepard](https://avatars.discourse-cdn.com/v4/letter/r/a3d4f5/32.png) [@RonShepard](https://fortran-lang.discourse.group/u/RonShepard)\
**Post date:** [September 29, 2026, 4:15pm UTC](https://fortran-lang.discourse.group/t/i-come-to-bury-mod-files-not-to-praise-them/11128/34 "2026-09-29T16:15:39Z")

</div>

> [@pjh503](#):
>
> Most compilers support a “syntax-only” first pass which can generate mod files, […]

I’m curious if anyone has ever suggested that this step become part of the fortran standard itself. The output would be the syntax tree and the module files (which contain the interfaces). It seems like there would be many useful tools that could be built on those outputs, and they would be portable because their contents and formats would be defined by the standard

Is this what LLVM is trying to accomplish?

BTW, when I saw the title of this thread, I wondered if its purpose was the same as the Mark Antony speech, namely to damn modules, but then to highlight all of their good features. 😉

---

<div class="post-metadata">

**Author:** ![certik](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/certik/32/4_2.png) [@certik](https://fortran-lang.discourse.group/u/certik)\
**Post date:** [September 29, 2026, 4:19pm UTC](https://fortran-lang.discourse.group/t/i-come-to-bury-mod-files-not-to-praise-them/11128/35 "2026-09-29T16:19:28Z")

</div>

> [@themos](#):
>
> Efficient recompilation may not be on your radar now, but if the AI revolution pans out and your agent is 24/7 searching the solution space, then I expect it to become the bottleneck.

Speed of compilation has always been essential, that was one of my main motivations to enter the compiler field. AI just makes it obvious.

---

<div class="post-metadata">

**Author:** ![cmaapic](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/cmaapic/32/659_2.png) [@cmaapic](https://fortran-lang.discourse.group/u/cmaapic)\
**Post date:** [September 29, 2026, 4:37pm UTC](https://fortran-lang.discourse.group/t/i-come-to-bury-mod-files-not-to-praise-them/11128/36 "2026-09-29T16:37:24Z")

</div>

I used to support Modula 2 on a variety of platforms when I worked at Imperial College Computer Centre (1978-1986) and mod files weren’t portable then either, so the issue isn’t new.

---

<div class="post-metadata">

**Author:** ![themos](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/themos/32/521_2.png) [@themos](https://fortran-lang.discourse.group/u/themos)\
**Post date:** [September 29, 2026, 11:09pm UTC](https://fortran-lang.discourse.group/t/i-come-to-bury-mod-files-not-to-praise-them/11128/37 "2026-09-29T23:09:46Z")

</div>

> [@pjh503](#):
>
> the primary issue with .mod files is they aren’t portable,

I couldn’t disagree more. That is a non-existent issue. The source format is a perfectly good, portable solution, available right now, in all compilers.

The problem is that our compilers are still in a FORTRAN77/C mindset where a file is considered a significant unit and we had to shoehorn this mindset into a world of modules. The significant units, which determine the minimum necessary amount of work in recompilation, are much “smaller” entities.

---

<div class="post-metadata">

**Author:** ![mleair](https://avatars.discourse-cdn.com/v4/letter/m/ad7895/32.png) [@mleair](https://fortran-lang.discourse.group/u/mleair)\
**Post date:** [September 30, 2026, 2:38am UTC](https://fortran-lang.discourse.group/t/i-come-to-bury-mod-files-not-to-praise-them/11128/38 "2026-09-30T02:38:21Z")

</div>

Flang’s module files are stored as plain, human-readable Fortran text rather than a compiler-specific binary format, so they’re more transparent and in principle easier for another compiler to parse than most binary .mod formats. That said, full portability is probably unattainable regardless of the .mod file’s format: .mod files only capture interface/specification info, while the actual compiled code lives in object files. Unless those object files also share a common calling convention and ABI, you still can’t mix and match across compilers — so .mod format alone isn’t the real portability bottleneck.

---

<div class="post-metadata">

**Author:** ![FedericoPerini](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/federicoperini/32/1750_2.png) [@FedericoPerini](https://fortran-lang.discourse.group/u/FedericoPerini)\
**Post date:** [September 30, 2026, 8:57am UTC](https://fortran-lang.discourse.group/t/i-come-to-bury-mod-files-not-to-praise-them/11128/39 "2026-09-30T08:57:42Z")

</div>

Genuine question for the compiler experts. I have no bandwidth for this rn but I believe that in the AI age it would be really easy to wire a `.mod` reader of any possible `.mod` formats (how many can they be? I guess one per compiler, max 2-3 versions each, so 10? 20? perhaps even less) into an existing Fortran parser (i.e. LFortran).

Now, what would that enable? Could a compiler build code against `.o` objects that were compiled with different compilers? I guess that the data structures and procedure interfaces in the .mod file could be 100% reconstructed, and names fully mangled, but how about the data/vtable layout then?

I guess that if the data layout for the classes could also be dealt with - then BOOM, it’s a solved problem. Imagine MPI modules - vendor gives a compiler-tied version, LFortran+mod-converter does the rest.

---

<div class="post-metadata">

**Author:** ![certik](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/certik/32/4_2.png) [@certik](https://fortran-lang.discourse.group/u/certik)\
**Post date:** [September 30, 2026, 9:20am UTC](https://fortran-lang.discourse.group/t/i-come-to-bury-mod-files-not-to-praise-them/11128/40 "2026-09-30T09:20:01Z")

</div>

@FedericoPerini yes, that can be done. LFortran had a reader for GFortran’s mod files. They change every couple versions, so you have to support all recent ones. Then you can learn what the ABI is for the object files, and then you can probably use it. But we stopped maintaining it, as it’s a lot of work to make it usable.

[Previous page](https://fortran-lang.discourse.group/t/i-come-to-bury-mod-files-not-to-praise-them/11128.md?page=1)

[Next page](https://fortran-lang.discourse.group/t/i-come-to-bury-mod-files-not-to-praise-them/11128.md?page=3)
