Elixir file hierarchy

Over the last week I’ve been learning some Rust in my spare time and saw that they have a convention of storing the top level module for a namespace in a file called mod.rs. In Elixir this would look like this:

├── foo
│   └── bar.ex
│   └── mod.ex

Compared to the Elixir convention of doing this:

├── foo
│   └── bar.ex
└── foo.ex

I thought there were advantages and disadvantages to each approach. The Rust structure groups the top level module together with it’s child modules, but the name mod.ex is a bit ambiguous, and doesn’t immediately stand out from the child modules. The advantage of the Elixir way is that the file structure matches the module namespace.

I’m suggesting this way of doing it:

├── foo
│   └── _foo.ex
│   └── bar.ex

Here a leading underscore is used to indicate the top level module. This means that when you open a folder the first file is the top level module. The file name also includes the module name, which I find convenient (I know at a glance which mod.ex file I am working with).

I talked to the guys at work and they liked the idea. What does the community think? If it’s unpopular we might use it internally, or we might drop the idea if there is a good reason not to do it.

3 Likes

It may be worth noting that with the latest edition of the Rust language they are switching to the pattern used in Elixir

https://doc.rust-lang.org/nightly/edition-guide/rust-2018/module-system/path-clarity.html#no-more-modrs

7 Likes

Well, they are updating the compiler to support either convention as I understand it. Currently mod.rs is required. I like Elixir’s convention better because its easier to search open buffers/tabs if each file has a different name.

1 Like

It was part of Rust 2018, to use it just add edition = "2018" to your Cargo.toml. New projects have this by default now :slight_smile:

4 Likes

I like Elixir’s convention better because it’s easier to search open buffers/tabs if each file has a different name.

Not being able to tell open files apart when they share a file name seems like a deficiency in text editors. Really, the editor should display enough path information to avoid ambiguity. In fact, I recently filed this issue to my text editor’s developers. That said, sharing names in the file tree is a problem for various kinds of tooling, so it probably should not be encouraged.

However, OP’s suggestion avoids this issue, because _foo.ex is not likely to cause conflicts. It may also cause the file to sort higher in directory listings, which can be useful. For this reason, I already use leading underscores on some file names (e.g., partial templates in Phoenix).

Speaking of naming conflicts, however, there are some files which cause this problem when umbrella apps are used. For example, application.ex, config.exs, and mix.exs are duplicated. I’m not suggesting that these files need to be renamed; indeed, I think these naming conflicts may be inherent in the umbrella app approach. However, adding more conflicts doesn’t seem wise…

2 Likes

This is not a limitation of editors, it is simply a trade-off. The wider you make the tabs, the fewer you can display at once. Also in helm for example the buffer list contains multiple columns of information - not just the file name. The wider you make the file name column, the less other information you can display. Sure you could make this all user-configurable and some do but there is always a trade-off and it is not something that can be “fixed” by editors. Good point though that OP’s proposal doesn’t cause this problem. Now if we could just fix index.js

1 Like

I think the fundamental problem is that code bases (and consequently, file trees) keep increasing in size. This puts pressure on all of the support tooling. For example, reduction of build times was a major reason for the development of Golang.

Clearly, each tool has to handle this growth in some manner. My text editor (BBEdit) uses a sidebar with disclosure triangles and such. I asked them to consider extending this as follows:

  • Leave any unambiguous names alone.
  • Add enough of the enclosing file path to clarify any ambiguous names.
  • Use globbing syntax to elide any common directories.
  • Sort by the resulting string.
  • Show as much as will fit in the available width.

They said they have received “a number of prior inquiries like yours about more easily identifying open files, which is an issue we do intend to address going forward, and I’ll be happy to add your feedback to the existing case.”

2 Likes

I really like the suggestion of using an underscore to indicate the top level module.
I’m using this pattern in a lot of my file hierarchies - but it not came into my mind it would improve my elixir project hierarchies also…

1 Like

Exactly this… When you open the foo directory the _foo.ex file sorts to the top as the entrypoint for the namespace MyApp.Foo. All the other modules in the namespace like MyApp.Foo.Bar appear below. Visually I really like seeing the related files in a “context” close together in the same directory with the entrypoint on top. The Elixir convention makes sense from a parent->child hierarchical standpoint mapping module names to directory structure but as the number of namespaces grows I definitely prefer your suggestion.

Elixir doesn’t really care how you structure the source file hierarchy as all the modules in the app get compiled to a flat directory of .beam files… and it’s very easy to move code/files around later if you change your mind. So I’d say if your team likes it then go for it!

4 Likes