Введение

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

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

Аналогия

Чтобы помочь понять концепцию, приведем аналогию из реальной жизни. Покупатель приходит в магазин, чтобы сделать заказ. Это аналогично первому вызову. Покупатель передает продавцу список товаров, чек на оплату и инструкции по доставке. Это параметры первого вызова, включая функцию обратного вызова, которая соответствует инструкциям по доставке. Подразумевается, что чек будет обналичен и инструкции выполнены. Когда сотрудники магазина могут, они доставляют товары согласно инструкциям, что аналогично вызову функции обратного вызова. Важно отметить, что доставку не обязательно должен осуществлять тот же продавец, который принял заказ. Функция обратного вызова не обязательно должна вызываться функцией, которая приняла её в качестве параметра. Кроме того, доставка не обязательно должна быть выполнена непосредственно покупателю. Функция обратного вызова не обязательно должна быть направлена в функцию, которая её вызвала. На самом деле, функция обычно не передает сама себя в качестве функции обратного вызова. Некоторые считают термин "обратный вызов" вводящим в заблуждение, поскольку вызов (как правило) не происходит обратно к первоначальному вызывающему, как это бывает при телефонном звонке.

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

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

Обработка событий

Возвратный вызов может быть использован для обработки событий. Часто, код, использующий функциональность, регистрирует обратный вызов для определенного типа события. Когда это событие происходит, вызывается обратный вызов. Обратные вызовы часто используются при программировании графического пользовательского интерфейса (GUI) программы, работающей в оконной системе. Приложение предоставляет ссылку на пользовательскую функцию обратного вызова, которую должна вызвать оконная система. Оконная система вызывает эту функцию для уведомления приложения о событиях, таких как щелчки мыши и нажатия клавиш.

Асинхронное действие

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

Реализация

Технология обратного вызова реализуется по-разному в зависимости от языка программирования. В ассемблере, C, C++, Паскале, Modula2 и других языках функция обратного вызова хранится внутри в качестве указателя на функцию. Использование одного и того же способа хранения позволяет различным языкам напрямую обмениваться функциями обратного вызова без необходимости создания уровня взаимодействия на этапе проектирования или во время выполнения. Например, Windows API доступен через множество языков, компиляторов и ассемблеров. C++ также позволяет объектам предоставлять реализацию операции вызова функции. Библиотека стандартных шаблонов принимает эти объекты (называемые функторами) в качестве параметров. Многие динамические языки, такие как JavaScript, Lua, Python, Perl и PHP, позволяют передавать объект функции. Языки CLI, такие как C# и VB.NET, предоставляют типобезопасную инкапсулированную ссылку на функцию, известную как делегат. События и обработчики событий, используемые в языках .NET, обеспечивают механизм обратного вызова. Функциональные языки обычно поддерживают функции первого класса, которые могут передаваться в качестве обратных вызовов другим функциям, храниться как данные или возвращаться из функций. Многие языки, включая Perl, Python, Ruby, Smalltalk, C++ (11+), C# и VB.NET, а также большинство функциональных языков, поддерживают лямбда-выражения – безымянные функции с встроенным синтаксисом, которые обычно используются в качестве обратных вызовов.

В некоторых языках, включая Scheme, ML, JavaScript, Perl, Python, Smalltalk, PHP (начиная с версии 5.3.0), C++ (11+), Java (начиная с версии 8) и многие другие, лямбда-выражение может быть замыканием, то есть иметь доступ к локальным переменным, определенным в контексте, в котором оно определено. В объектно-ориентированном языке программирования, таком как Java до появления аргументов, передающих функции, поведение обратного вызова можно реализовать путем передачи объекта, реализующего интерфейс. Методы этого объекта и являются функциями обратного вызова. В PL/I и ALGOL 60 процедуре обратного вызова может потребоваться доступ к локальным переменным содержащих блоков, поэтому она вызывается через входную переменную, содержащую как точку входа, так и контекстную информацию.

C++

В C++ функтор может использоваться в дополнение к указателю на функцию.