отделение декларации от определения

Я действительно хочу использовать D, потому что его языковые конструкции делают поэтому многие вещи, которые мне интересны лучше, чем C++, но почти принудительный сборщик мусора (проблема, обработанная [вроде] здесь), немного менее мощная перегрузка операторов (за исключением opDispatch. opDispatch сексуальна), и следующая проблема немного отталкивает меня.

Возможно ли в D отделить объявление метода от определения? Если да, то как? Если нет, то почему?

Мотивирующий пример для «как»: предоставить небольшой заголовочный файл интерфейсных функций рядом с двоичным объектом, как с заголовком C и библиотекой, чтобы скрыть реализацию от глаз автора пользовательского кода. Предпочтение: вне зависимости от того, взломал ли пользовательский код сборщик мусора или просто компилируется без времени выполнения (например, в комментариях здесь).


d
person user    schedule 05.08.2013    source источник
comment
Прочтите о файлах интерфейса D.   -  person DejanLekic    schedule 06.08.2013
comment
@DejanLekic Я вижу только файлы интерфейса D, указанные в разделах документации по компиляторам. Это компилятор за компилятором или язык? РЕДАКТИРОВАТЬ: Blargh, прочитайте немного дальше о них. Они не являются частью языка. Есть ли решение, которое ЯВЛЯЕТСЯ частью языка?   -  person user    schedule 06.08.2013
comment
Файл интерфейса D просто использует другую часть того же языка D. (На самом деле, компилятору dmd все равно, какое расширение — .d или .di, все они работают одинаково.)   -  person Adam D. Ruppe    schedule 06.08.2013
comment
@AdamD.Ruppe Хорошо, но не могли бы вы уточнить следующую цитату (из dlang.org/ dmd-linux.html#interface_files): файлы интерфейса D имеют некоторое сходство с файлами заголовков C++. Но они не требуются в том смысле, что заголовочные файлы C++, и они не являются частью языка D. Они являются функцией компилятора и служат только для оптимизации процесса сборки.   -  person user    schedule 06.08.2013
comment
@AdamD.Ruppe Я имею в виду, чтобы быть ясным, я не собираюсь быть пуристом и говорить, что файлы .di, не являющиеся частью определения основного языка, являются отключением. Я просто хочу знать, что с ними.   -  person user    schedule 06.08.2013


Ответы (3)


Если я напишу файл D, подобный этому: http://arsdnet.net/dcode/iface/test.d и вы скомпилируете с помощью dmd -c, вы увидите, что он проходит без ошибок; это действительный файл D. Язык позволяет писать прототипы функций без реализации.

Файл .di такой же, просто у него другое имя файла.

Затем указан main: http://arsdnet.net/dcode/main.d, если вы компилируете dmd main, он будет автоматически искать iface/test.d, когда увидит «import iface.test;», найдет этот файл .d или .di, если вы переименуете его, но то же самое, и получите определение вашего интерфейса.

dmd main завершится ошибкой компоновщика, поэтому нам нужно реализовать его: http://arsdnet.net/dcode/impl.d Примечание: impl НЕ импортирует модуль, поэтому он никогда не проверяет другой файл. Синхронизация файлов .di и .d является одной из сложных частей здесь, если только вы не сгенерируете файл интерфейса автоматически, поскольку неопределенные методы дадут ошибки компоновщика, но порядок методов важен: он должен совпадать, и так должно быть. список переменных, если есть общедоступные. В противном случае код использования и код реализации не будут согласовываться с макетом класса.

Опять же, он не проверяет это автоматически, файл реализации вообще не смотрит на "заголовочный" файл, так что это большое отличие от C++, где вы пишете файл заголовка один раз, а затем используете это как в программе использования, так и в файле реализации.

Вы заметите, что в файле реализации также указан класс и т. д. D не поддерживает синтаксис void MyClass::add(int a) {} C++ должен писать метод вне класса.

Насколько я знаю, нет способа заставить файл реализации искать заголовок, если поставить оба в командной строке, то получится: "Ошибка: модуль iface.test из файла iface/test.d конфликтует с другим модулем тест из файла impl.d"

Файлы .di рекомендуется использовать для автоматического создания с помощью dmd -H. Это считывает полный файл реализации и удаляет тела функций, оставляя только определения. Эта часть, вероятно, является ключевой, когда говорят, что это особенность компилятора - файл .di является допустимым и стандартным D, но генерируется с помощью опции компилятора, которая не обязательно должна быть частью других компиляторов.

person Adam D. Ruppe    schedule 06.08.2013
comment
dmd main для просмотра ошибки и dmd main.d impl.d для успешного выполнения. Загрузите оба файла в свою папку. - person Adam D. Ruppe; 24.06.2015

Вы можете объявлять функции без указания их реализации, используя extern, например:

extern(D):
void foo(string name);

Затем просто предоставьте объектный файл/архив с реализацией для связывания. Обратите внимание, что имя модуля является частью искаженного имени функции, поэтому либо для файла заголовка требуется то же имя модуля, что и для скомпилированного модуля, либо вы можете использовать extern(C) для отключения искажения (предотвращает перегрузку и использует соглашение о вызовах C).

person Justin W    schedule 05.08.2013
comment
FWIW, файлы .di — это просто автоматизация этого соглашения. - person BCS; 06.08.2013
comment
@BCS И, таким образом, все это в любом случае оказывается для меня поучительным. Спасибо вам всем. - person user; 07.08.2013

Адам уже все объяснил. Я просто попытаюсь добавить дополнительный пример:

Допустим, вы разрабатываете библиотеку под названием mylib, в которой есть функции foo() и bar(). Ваше тестовое приложение с кодом и библиотекой может выглядеть так при запуске:

mylib.d — файл интерфейса

module mylib;

void foo();
void bar();

mylib_impl.d — определения здесь

module mylib;

import std.stdio;

void foo() {
  writeln("foo()");
}

void bar() {
  writeln("bar()");
}

mylib_test.d — тестовое приложение

// To compile: dmd mylib_impl.d mylib_test.d
// NOTE: we do not compile the "interface" file mylib.d !!
module mylib_test;

import mylib;

int main() {
  foo();
  bar();

  return 0;
}

Теперь не должно быть сложно понять, что у нас есть файлы .di исключительно для удобства и ясности. Если мы решим использовать файл интерфейса, мы переименуем mylib.d в mylib.di, а mylib_impl.d в mylib.d. mylib_test.d останется нетронутым.

person DejanLekic    schedule 06.08.2013
comment
Пакет - это просто каталог. Должно работать без изменений. - person DejanLekic; 24.06.2015