Отражение (программирование)

Материал из Википедии — свободной энциклопедии
Перейти к навигации Перейти к поиску
Парадигмы программирования

Рефлексивность
Гомоиконность

Отражение (рефлексия; холоним интроспекции, англ. reflection) — процесс, во время которого программа может отслеживать и модифицировать собственную структуру и поведение во время выполнения. Парадигма программирования, положенная в основу отражения, является одной из форм метапрограммирования[1] и называется рефлексивным программированием.

Во время выполнения программных инструкций (кода) компьютеры обрабатывают данные, что приводит к их изменению, при этом компьютеры не изменяют код. Однако, в большинстве современных компьютерных архитектур код хранится как данные, и в некоторых языках программирования реализована возможность обрабатывать собственный код как данные, что приводит к изменению уже самого кода во время его выполнения. Такие самоизменяющиеся программы в основном создаются с помощью высокоуровневых языков программирования, использующих виртуальные машины (например, Smalltalk, скриптовые языки). В меньшей степени рефлексия используется в языках с объявляемыми или статическими типами (например, Си, ML, Haskell, F#).

Понятие рефлексии в языках программирования введено Брайаном Смитом (Brian Cantwell Smith) в докторской диссертации 1982 года[2][3] наряду с понятием метациркулярного вычислителя (англ. Meta-circular evaluator) как компонента 3-Lisp.

Рефлексивно-ориентированное программирование[править | править код]

Рефлексивно-ориентированное программирование, или рефлексивное программирование — функциональное расширение парадигмы объектно-ориентированного программирования. Рефлексивно-ориентированное программирование включает в себя самопроверку, самомодификацию и самоклонирование. Тем не менее, главное достоинство рефлексивно-ориентированной парадигмы заключается в динамической модификации программы, которая может быть определена и выполнена во время работы программы. Некоторые императивные подходы, например, процедурная и объектно-ориентированная парадигмы программирования, указывают, что существует четкая предопределённая последовательность операций обработки данных. Парадигма рефлексивно-ориентированного программирования, тем не менее, добавляет возможность динамической модификации программных инструкций во время работы и их вызова в модифицированном виде. То есть программная архитектура сама определяет, что именно можно делать во время работы исходя из данных, сервисов и специфических операций.

Применение[править | править код]

Рефлексия может использоваться для наблюдения и изменения программы во время выполнения. Рефлексивный компонент программы может наблюдать за выполнением определённого участка кода и изменять себя для достижения желаемой цели. Модификация выполняется во время выполнения программы путём динамического изменения кода.

Рефлексию можно применять и для динамической адаптации программы к различным ситуациям. Например, рассмотрим программу, использующую два разных класса X и Y для выполнения аналогичных операций. Без рефлексии в коде программы методы классов X и Y будут вызываться явно. Если программа спроектирована с применением рефлексивно-ориентированной парадигмы программирования, некоторый участок кода не будет содержать явных вызовов методов классов X и Y; программа выполнит этот участок дважды: сначала для класса X, затем для класса Y.

Реализации[править | править код]

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

  • поиск и модификация конструкций исходного кода (блоков, классов, методов, интерфейсов (протоколов) и т. п.) как объектов первого класса во время выполнения;
  • изменение имён классов и функций во время выполнения;
  • анализ и выполнение строк кода, поступающих извне;
  • создание интерпретатора байткода нового языка.

Реализация этих возможностей возможна разными путями. В языке MOO рефлексия является частью ежедневной идиомы программирования. Все вызываемые методы получают в контексте информацию о том, откуда они вызваны, и ссылки на объекты, к которым они принадлежат. Безопасность контролируется программно с помощью стека вызовов: вызывается callers() для получения списка методов; проверяется, не заблокировал ли callers()[1] сам себя.

Компилируемые языки полагаются на свои среды выполнения, обеспечивающие программы информацией об их исходном коде. Скомпилированный на Objective-C выполняемый файл, например, записывает имена всех методов в один блок, создаёт таблицу соответствия. В компилируемых языках, поддерживающих создание функций во время выполнения, таких как Common Lisp, среда выполнения должна включать компилятор и интерпретатор.

Реализация рефлексии на языках, её не поддерживающих, выполняется с помощью системы трансформации программы для автоматического отслеживания изменений исходного кода.

Примеры[править | править код]

Пример на C#, в котором создаётся экземпляр foo класса Foo и осуществляется вызов метода Hello, не использующий рефлексию и использующий её:

// Без рефлексии
new Foo().Hello();

// С рефлексией
Type type = System.Type.GetType("Foo");
var foo = Activator.CreateInstance(type);
foo.GetType().GetMethod("Hello").Invoke(foo, null);

Аналогичный пример для ECMAScript, JavaScript и ActionScript:

// Без рефлексии
new Foo().hello()
 
// С рефлексией
 
// с допущением, что Foo лежит в this
new this['Foo']()['hello']()
 
// без допущений
new (eval('Foo'))()['hello']()

Примечания[править | править код]

Литература[править | править код]

  • Forman, Ira R. and Forman, Nate. Java Reflection in Action. — Manning Publications Co., 2004. — ISBN 1932394184.
  • Forman, Ira R. and Danforth, Scott H. Putting Metaclasses to Work: A New Dimension in Object-oriented Programming. — Addison Wesley Longman Publishing Co., Inc., 1999. — ISBN 0-201-43305-2.

Ссылки[править | править код]