Ограничения статического типа без Inline? - PullRequest
1 голос
/ 22 сентября 2010

Недавно было несколько вопросов, касающихся статических ограничений типа и встроенного:

  1. Использование `inline` в F #
  2. КакФункции компиляции F #, которые могут принимать несколько различных типов параметров в IL?

Меня особенно поразили два оператора:

  1. "Нет путичтобы кодировать это ограничение типа первоклассным способом в скомпилированном коде в .NET. Однако компилятор F # может применить это ограничение на сайте, где он встроен в функцию, так что все операции оператора разрешаются во время компиляции. "

  2. "... но F # может также вставлять между скомпилированными сборками, потому что inline передается через метаданные .NET."

Более поздние, похоже, противоречатбывший.Интересно, почему встраивание вообще должно быть связано с функцией статических ограничений типа.Может ли компилятор F # работать так, как я полагаю, с помощью шаблонов C ++ и обобщений .NET, а также генерировать специфичные для типа и пригодные для повторного использования функции по мере необходимости во время компиляции?

Например:

Полиморфное определение:

let add (lhs:^a) (rhs:^a) = lhs + rhs

Использование:

let a = add 2 3
let b = add 2. 3.
let b = add 4. 5.

Генерируемые компилятором Функции добавления:

let add_int (lhs:int) (rhs:int) = lhs + rhs
let add_float (lhs:float) (rhs:float) = lhs + rhs

Переписано компилятором Использование:

let a = add_int 2 3
let b = add_float 2. 3.
let c = add_float 4. 5.

Я не писатель компилятора и не разработчик языка, хотя темы меня очень интересуют, поэтому, пожалуйста, укажите на мою наивность.

Ответы [ 2 ]

12 голосов
/ 22 сентября 2010

Два бита.

Во-первых, "неужели все так не работает?"Да.«Отдельная компиляция» часто рассматривается как логическое значение, но на самом деле это континуум.Обычно «отдельная компиляция» для статически типизированного языка означает, что мне нужно знать только тип интерфейса / сигнатуры класса / метода, чтобы затем иметь возможность компилировать эту сущность в другом модуле / сборке и либо успешно выполнить и сгенерировать хороший код, либоеще генерировать полезную диагностику о том, что ошибка.Ключевая идея заключается в том, что «подпись типа» является «краткой сводкой основных ограничений».

Вы можете сдвинуть ее в масштабе на другой конец спектра и выполнить типизацию по типу утки.что делают шаблоны F # inline или C ++, где в основном «если вы подключите эти типы данных в тело кода этого метода, будет ли он компилироваться?»Это выполнимо, но обычно его компилируют медленнее и предлагают более плохую диагностику при сбое.Эти последствия объясняются отсутствием «краткой сводки», которая является типичным артефактом «отдельного» в «отдельной компиляции».

(из совершенно другой оси оценки полезности / юзабилити, inline / C ++Модель шаблонов «чрезвычайно гибкая» и «чрезвычайно сложная», тогда как типичные элементы системы типов «менее гибкие, но часто достаточные для выражения большинства абстракций» и «очень простые».)

В любом случае, всевозможно, но если вы делаете вещи «более гибко», чем несколько стандартных хорошо понятных механизмов для типов / обобщений / классов типов, вы склонны падать с обрыва, когда дело доходит до скорости компиляции и качества диагностики ошибок.Таким образом, в F # механизм срабатывает только тогда, когда вы специально запрашиваете его через inline.

Во-вторых, как F # удается "встроить в сборки", когда метаданные .NET не могут выразить эти ограничения?Проще говоря, сборка F # с любым материалом inline содержит дополнительные специфичные для F # метаданные (в дополнение к обычным метаданным .NET), которые в основном представляют "тело кода F #", поэтому они могут быть встроены в сайт вызова ссылочной сборки.Специфичные для F # метаданные встраиваются как «ресурс» в сборку .NET.В F # PowerPack есть модуль чтения метаданных, который позволяет вам «размышлять» над некоторыми из этих дополнительных метаданных F #.(В случае FSharp.Core эти дополнительные метаданные разбиты на файлы FSharp.Core.sigdata и FSharp.Core.optdata, а не внедряются в сборку времени выполнения FSharp.Core.dll. Это уменьшает время выполнения F #,так как вам нужны только sigdata / optdata во время разработки.)

5 голосов
/ 22 сентября 2010

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

Однако есть несколько веских причин, по которым вы можете не использовать его слишком часто:

  • Читаемость сигнатур типов если бы все универсальные методы интерпретировались как методы с "типами шапки", то читаемость сигнатуры типа пострадала бы, потому что у каждого параметра типа был бы большой список методов, которые необходимо реализовать.

  • Совместимость функция / метод, объявленный как inline, не может быть вызван другими языками .NET. Поскольку совместимость весьма важна для F #, кажется разумным предпочесть обычные универсальные методы (которые можно использовать из C #).

Создание специализированных функций, как вы предлагаете (и как это делает компилятор C ++ / CLI), будет другой альтернативой реализации F # (встраивание), но, вероятно, потребует больше усилий. В любом случае вам все равно нужно как-то пометить функцию, чтобы естественным способом написания универсальных функций в F # было использование стандартных обобщений.

И наконец - объяснить противоречие в двух утверждениях. Я считаю, что «inline передается через метаданные .NET» фактически означает, что информация о встраивании хранится в некотором двоичном формате в ресурсах .NET. Это означает, что он является частью сборки .NET, но только F # может это понять.

...