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 проще, но менее гибок.

КритерийFortranC / 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 переносимым, решая вопросы имён, передачи и типов.
  • При связывании языков помните о смене раскладки массивов (по столбцам против по строкам).
Проверьте себя
1. Какой распространённый промышленный паттерн объединяет Fortran и Python?
AПолная замена Fortran на Python
BТяжёлое численное ядро на Fortran, обвязка и анализ на Python
CЗапуск Python внутри Fortran построчно
DПеревод Python в Fortran автоматически
2. Зачем в Fortran модуль iso_c_binding и атрибут bind(c)?
AДля ускорения циклов
BДля переносимого связывания с кодом на C (имена, типы, передача аргументов)
CДля параллелизма
DДля работы с массивами
3. Почему Fortran до сих пор не вытеснен более молодыми языками вроде Julia?
AОн технически превосходит все языки во всём
BИз-за инерции экосистемы: десятилетия валидированного кода, компиляторы и кадры
CПотому что Julia не умеет считать
DПотому что Fortran бесплатный, а Julia платная