Вашу позицию понял. Вам не нравится то, что внутри модуля нет ограничений доступа. Поэтому возникает желание раскидать все по разным модулям, в результате модули используются не по прямому назначению, вся идеология модульных языков летит куда подальше...

Вы обращаетесь к аналогии с железной техникой - это хорошая аналогия. Только давайте-ка посмотрим немного под другим ракурсом. Пусть мы с вами делаем не сам автомобиль, а программную техническую систему, которая будет управлять виртуальными моделями автомобилей. Так вот, с точки зрения программного инженера Автомобиль, Карбюратор, Бензобак - это не модули, не части технической системы, это всего лишь типы данных, которые обрабатываются. Это - абстракции предметной области. Их можно называть типами, как в КП, можно классами, как во многих других языках. Однако ваша логика предполагает, что разбиение на модули нашей программной системы будет совпадать с разбиением на модули того самого автомобиля, моделированием которого мы занимаемся. Т.е. в программе действует набор таких активных "роботов"-объектов, каждый из которых является эквивалентом объекта реального мира. Подход заманчивый и соблазнительный, но на практике себя часто не оправдывающий. Если модель достаточно сложна, то при реализации классов не удастся игнорировать реализацию окружающих классов из некоторой группы. В том же С++ приходится использовать декларации friend или иные маневры, позволяющие для тесно связанной группы классов обойти инкапсуляцию.

А теперь представьте другой подход - мы точно также выделяем набор объектов из нашей предметной области, я называю их абстракциями. Затем мы описываем абстракции типами данных нашей программы - поля, методы, все как положено. Но, приступая к реализации, мы не будем делать из этих объектов автономных "роботов", а возьмем другой подход - "кукольный театр". Под каждую группу связанных между собой абстракций-типов-классов (назовите как угодно) выделим общего кукловода - модуль. И вот он-то и станет структурной единицей нашей программной системы. Т.е. структура нашей программной системы не обязательно совпадает (а чаще всего - не совпадает) со структурой той системы, которую мы моделируем. На практике чаще всего происходит именно так.

А при вашем подходе мы дойдем до абсурда. Вот конкретный пример, прямо из ББ (модуль Dialog). Создаем набор типов для работы с деревом: Tree - само дерево, TreeNode - вершина дерева. Пользователь не имеет никакого понятия о реализации этих типов, для него создается набор общих методов. Теперь приступаем к реализации - и сразу же видим, что эти два типа должны иметь полный доступ к внутренностям друг друга. Если заставить их взаимодействовать между собой через тот же интерфейс, который мы описали для пользователя, мы получим красивую, но крайне медленную и бесполезную реализацию. А теперь представьте, что мы пишем не дерево, а операционную систему. Такие группы объектов, которые работают вместе, будут встречаться сплошь и рядом. Что будем делать тогда?
Оказывается, что у каждого объекта есть две стороны - одной он обращен к пользователю, а другой - к тому узлу, в составе которого он работает. И директивы friend в С++ являются очень корявым решением этой проблемы, практически костылем, поэтому основным советом является "используйте friend, только если вы абсолютно уверены, что это нужно". Напротив, модульность в сочетании с ООП - элегантное и системное решение проблемы. ООП помогает нам анализировать предметную область и проектировать нашу систему, модульность помогает нам ее успешно и эффективно реализовывать.

Кроме того, внутри модуля закрывать данные просто не от кого. Во-первых, в КП принято писать модули небольшого размера, обычно до 1000-1500 строк, и помещать в один модуль только тесно связанные типы и процедуры. Во-вторых, за модуль обычно отвечает один человек. И вряд ли найдется пример, когда открытость внутри модуля кому-то помешала. А если мы заменяем одну реализацию на другую - то мы всегда заменяем модуль целиком. Кроме того, в расширяемых системах стремятся не использовать межмодульное наследование реализации, наследуют в основном от асбтрактных типов.

Вышеописанная проблема, кстати, эта одна из причин, почему С++ не особенно жалуют системщики. Торвальдс и Танненбаум очень критически выссказывались по поводу использования С++ при написании ОС. Linux, QNX, ядро Windows - все это написано на голом С. Потому что  если ваш с Мейером подход может себя оправдать при создании прикладных систем, то в системном программировании он безусловно пасует - либо реализация получается очень неэффективной, либо приходится постоянно обходить инкапсуляцию.

Оберон же как раз в первую очередь использовался как язык системного программирования (для прикладных задач он еще только начинает использоваться) - на нем оказалось очень удобно реализовывать операционные системы. И две промышленные системы жесткого реального времени (JBed и XOberon) тому доказательство, не считая исследовательских Oberon-1, Oberon System 3, Blue Bottle. Именно Оберон позволил использовать для ОС ООП без потери эффективности (кстати, и сборку мусора тоже).

Если хотите понять идеологию модульных языков - почитайте материалы в разделе Статьи у нас на сайте - там как раз эта тематика освещается.