Модульность
От: x-code  
Дата: 10.08.15 09:25
Оценка:
Добрый день! Давайте поговорим про модульность.
Можете рассказать подробно, как устроена модульность и сборка многофайловых проектов (с точки зрения компилятора) в современных компилируемых языках, типа C#, Java, Scala и т.д.?
(спрашиваю, потому что имею опыт только с С++, про который можно сказать что там модульность устроена совершенно безобразно, можно сказать что ее и нет вовсе).

Пример на C#
// файл1
namespace module1
{
    class Program
    {
        static void Main(string[] args)
        {
            module1.Program.Foo();
            module2.Class2.Foo();
        }
        public static void Foo()
        {
            System.Console.WriteLine("1.Foo");
            module2.Class2.Bar();
        }
        public static void Bar()
        {
            System.Console.WriteLine("1.Bar");
        }
    }
}
//файл2
namespace module2
{
    class Class2
    {
        public static void Foo()
        {
            System.Console.WriteLine("2.Foo");
            module1.Program.Bar();
        }

        public static void Bar()
        {
            System.Console.WriteLine("2.Bar");
        }
    }
}


аналогичный пример на java
//файл1
package module1;

public class Program {
    public static void main(String[] args) 
    {
        module1.Program.Foo();
        module2.Class2.Foo();
    }
    public static void Foo()
    {
        System.out.println("1.Foo");
        module2.Class2.Bar();
    }
    public static void Bar()
    {
        System.out.println("1.Bar");
    }
}
//файл2
package module2;

public class Class2 {
    public static void Foo()
    {
        System.out.println("2.Foo");
        module1.Program.Bar();
    }
    
    public static void Bar()
    {
        System.out.println("2.Bar");
    }
}


В обоих примерах сделано перекрестное использование классов и методов между двумя файлами.

Понятно, что от пофайловой компиляции никуда не уйти; в проекте могут быть десятки/сотни тысяч файлов, и загружать их все одновременно в память (чтобы компилятор имел доступ ко всей программе сразу) — неразумно и часто невозможно.

В С/С++ есть деление на cpp и h, которое позволяет компилятору при компиляции каждого файла видеть все определения, используемые в данном cpp файле. Поэтому, если переписать данный пример на С++, то в каждый "cpp" пришлось бы подключать оба "h" файла; и хорошо еще, если в самих "h" файлах не требуется подключение другого "h" (иногда можно решить путем включения одного "h" в другой, иногда — путем предварительных объявлений, но бывает что и это не помогает, если оба "h" используют код друг друга).

А как решается эта проблема в C# или Java? Используется двухпроходная компиляция (сначала собираем всю информацию о доступных классах/методах, кладем ее в общую для всего проекта базу данных, а затем — пофайловая компиляция с использованием этой базы)?
Или что-то еще?

Какие недостатки существуют в таких подходах и пути их устранения? (про с++ не говорим — там вся эта система одни большой недостаток) Может быть кто-то знает какие решения применяются в других языках (D, Go, Rust...)?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.