Fortran среди других языков и связь с C
Сравнение Fortran с C++, Python и Julia без фанатизма: где он силён, где проигрывает и как живёт в смешанных проектах.
Связывание языков (interoperability) — возможность вызывать процедуры, написанные на одном языке, из кода на другом; в Fortran стандартизовано модулем
iso_c_bindingдля совместимости с C.
Ни один язык не существует в вакууме. Чтобы трезво решить, когда тянуться за Fortran, нужно понимать его место в экосистеме: с кем он конкурирует, в чём объективно сильнее, где безнадёжно отстаёт и как уживается с соседями в одном проекте. Этот урок завершает вводный раздел сравнительным взглядом — без сектантства «Fortran лучше всех» и без снобизма «кто вообще его учит». Реальность тоньше: язык блестящ в своей нише и неуместен вне её.
Fortran против C и C++
Это главное историческое соперничество в численных вычислениях. Оба компилируемы, оба дают быстрый машинный код, оба используются в HPC. Различия — в философии и удобстве для математики.
Сильная сторона Fortran — выразительность для числодробилок. Операции над массивами целиком, встроенные математические функции, благоприятный алиасинг и хранение по столбцам делают численный код короче и зачастую быстрее без ручной оптимизации. Где C++ требует шаблонов, библиотек вроде Eigen и аккуратной работы с restrict, Fortran даёт то же из коробки. Зато C++ несравнимо универсальнее: метапрограммирование, богатая стандартная библиотека контейнеров, обширная экосистема для всего на свете — от игр до драйверов. Управление ресурсами через RAII и деструкторы в C++ тоньше; Fortran проще, но менее гибок.
| Критерий | Fortran | C / C++ |
| Операции над массивами | встроены в язык | через библиотеки/циклы |
| Скорость числового кода | очень высокая «из коробки» | высокая, но требует усилий |
| Универсальность | узкоспециальная | предельно широкая |
| Порог входа в числодробилки | низкий | выше |
Fortran против Python
Сравнение кажется странным — это языки из разных миров, — но именно их пара встречается чаще всего. Python медленный как интерпретатор, зато удобный для прототипирования, анализа данных и склейки. Распространённый промышленный паттерн: тяжёлое ядро на Fortran, обвязка на Python. Кстати, NumPy под капотом во многом опирается на те же фортрановские BLAS/LAPACK — то есть, считая матрицы в Python, вы зачастую исполняете именно Fortran-код.
Практический вывод прост: если задача — посчитать что-то численно тяжёлое в цикле на миллиарды итераций, Python в чистом виде проиграет Fortran на порядки по скорости. Если задача — быстро собрать прототип, нарисовать графики, обработать таблицу, Fortran избыточен. Зрелый инженер использует оба: моделирует на Fortran, анализирует результаты на Python.
Fortran против Julia
Julia — молодой язык, прямо нацеленный на нишу Fortran: научные вычисления со скоростью компилируемого кода и удобством Python. Она привлекательна динамической разработкой, многократной диспетчеризацией, современной экосистемой. Почему же Fortran не вытеснен? Из-за инерции экосистемы: десятилетия валидированного кода, отлаженные компиляторы, поддержка на всех суперкомпьютерах, кадры, умеющие его читать. Новый проект «с нуля» вполне разумно начать на Julia; но гигантскую климатическую модель никто не перепишет ради моды. Fortran выигрывает не технологически, а исторически и институционально — и в инженерии это весомый аргумент.
Связывание с C: iso_c_binding
В смешанных проектах Fortran-ядро часто вызывают из C или наоборот. Стандарт Fortran 2003 ввёл модуль iso_c_binding, делающий это переносимым. Атрибут bind(c) задаёт совместимое с C соглашение о вызове и имени, а специальные KIND-константы (c_int, c_double) гарантируют одинаковое представление чисел.
module mathlib
use iso_c_binding, only: c_double
implicit none
contains
function square(x) bind(c, name="square") result(y)
real(c_double), value :: x
real(c_double) :: y
y = x * x
end function square
end module mathlib
Со стороны C эта функция видна как обычный прототип, и компоновщик свяжет вызовы по имени square. Атрибут value означает передачу по значению (как в C), а не по ссылке, как принято в Fortran по умолчанию. Этот мост — причина, по которой Fortran органично встраивается в большие гетерогенные системы.
Где Fortran объективно проигрывает
Честный курс обязан назвать слабости языка, иначе картина будет искажённой. Fortran плох в работе со строками и текстом: его символьный тип фиксированной длины неуклюж по сравнению с гибкими строками Python или C++, и парсинг текста на Fortran — мучение. Он беден на структуры данных: в стандартной поставке нет готовых хеш-таблиц, динамических списков, деревьев — то, что в C++ даёт STL, а в Python встроено, здесь приходится писать руками или брать сторонние библиотеки. Его экосистема инструментов — отладчики, профилировщики, пакеты, IDE — несравнимо скромнее, чем у мейнстримных языков, хотя fpm и языковые серверы понемногу это исправляют. И наконец, Fortran почти не применим вне численной ниши: веб, мобильная разработка, системное программирование, скрипты — всё это территория других языков. Признание этих границ не унижает язык, а помогает применять его по назначению: как мощную числодробилку, а не как универсальный инструмент.
Из этих слабостей вытекает и доминирующий архитектурный паттерн современных научных проектов: гетерогенность. Тяжёлое математическое ядро пишут на Fortran ради скорости, управляющую логику, ввод-вывод, парсинг конфигов и визуализацию — на Python или C++, а склеивают всё через iso_c_binding или специальные обёртки. Инженер, который умеет провести границу «что на Fortran, а что вокруг него», ценнее того, кто пытается решить всё одним языком. Fortran в такой системе — не конкурент Python, а его мотор.
Производные типы: немного современности
Чтобы развеять образ «языка голых чисел», стоит упомянуть, что современный Fortran всё же умеет группировать данные в производные типы (derived types) — аналог структур C или записей. Это позволяет описать, скажем, частицу с координатами, скоростью и массой как единое целое, а не три разрозненных массива. Полноценный разбор производных типов и объектно-ориентированных возможностей (введённых в Fortran 2003) выходит за рамки первой половины курса, но важно знать: язык не застрял на уровне 1957 года. Он научился инкапсуляции, наследованию, полиморфизму — пусть и в своём, ориентированном на вычисления стиле. Когда вы встретите в современном коде type :: particle ... end type и обращения вида p%mass, знайте — это та самая эволюция, что превратила примитивный транслятор формул в язык, на котором сегодня пишут большие инженерные системы.
Как работает под капотом
Почему вообще нужен особый модуль для связывания? Дело в различиях бинарных соглашений. Во-первых, искажение имён: компиляторы по-своему меняют имена процедур в объектном файле (добавляют подчёркивания, регистр), и без bind(c, name=...) линковщик может не найти совпадения. Во-вторых, способ передачи аргументов: Fortran исторически передаёт всё по ссылке (адрес), C — скаляры по значению; атрибут value примиряет это. В-третьих, раскладка массивов: Fortran хранит по столбцам, C — по строкам, поэтому многомерный массив «переворачивается» при переходе границы языков. В-четвёртых, совпадение типов: c_double гарантирует, что фортрановский real бинарно совпадёт с сишным double. Модуль iso_c_binding стандартизует все четыре аспекта, превращая хрупкий хак в надёжный механизм.
Полезно осознать, что эта совместимость работает в обе стороны и открывает доступ ко всему миру C-библиотек. Через iso_c_binding фортрановская программа может вызвать функцию из системной библиотеки на C, а C-приложение — использовать высокопроизводительное фортрановское ядро. Именно так Fortran остаётся встроенным в современную инфраструктуру, несмотря на возраст: он не изолирован, а связан стандартным мостом с доминирующим в системном мире языком C. Эта продуманная интероперабельность — одна из причин, по которой объявления о «смерти Fortran» раз за разом оказываются преждевременными: язык умеет работать в команде с другими, а не претендует на одиночество.
Частые ошибки и мифы
- «Fortran всегда быстрее C». Не всегда; на типичных численных циклах разрыв сократился, а на не-численных задачах сравнение бессмысленно. Скорость зависит от кода и флагов.
- «Python заменил Fortran». Python заменил его как язык обвязки и анализа, но тяжёлое ядро под NumPy/SciPy часто остаётся фортрановским.
- Игнорирование смены раскладки при связывании. Передав матрицу из C в Fortran без учёта column-major против row-major, вы получите транспонированные данные и тихо неверный результат.
- Забытый
valueприbind(c). Без него Fortran передаёт скаляр по ссылке, а C ждёт по значению — рассогласование приводит к мусору или падению. - Выбор Fortran «потому что модно». Для веба, мобильных, скриптов он неуместен; язык хорош строго в численной нише.
Итоги
- Fortran силён там, где много арифметики над массивами: HPC, наука, инженерия; вне этой ниши он неуместен.
- Против C/C++ он выигрывает выразительностью для числодробилок, проигрывает в универсальности.
- С Python он не конкурирует, а сотрудничает: тяжёлое ядро на Fortran, анализ и склейка на Python.
- Julia технически нацелена на ту же нишу, но Fortran держится за счёт инерции валидированного кода и экосистемы.
- Модуль
iso_c_bindingиbind(c)делают связывание с C переносимым, решая вопросы имён, передачи и типов. - При связывании языков помните о смене раскладки массивов (по столбцам против по строкам).