When you require module, the string parameter from require is passed to the module, which you can access using the syntax of the argument variable ... You can use this to include other dependent modules that are on the same path as the current require ed module, without making it depend on the name of the hard coded module.
In your example, instead of executing:
-- model/a.lua require "model.b"
and
-- view/a.lua require "view.b"
You can do:
-- model/a.lua local thispath = select('1', ...):match(".+%.") or "" require(thispath.."b")
and
-- view/a.lua local thispath = select('1', ...):match(".+%.") or "" require(thispath.."b")
Now, if you change the directory structure, for example. move the view to something like control/subcontrol/foobar , then control/subcontrol/foobar/a.lua (formerly view/a.lua ) will now try to require control/subcontrol/foobar/b.lua instead and "do the right thing".
Of course, main.lua will still need to fully qualify the paths, since you need some way to eliminate the ambiguity between model/a.lua and view/a.lua .
source share