Рефлексија (програмирање)

У информатици, рефлексија је способност неког рачунарског програма за испитивање (види тип интроспекције) и измену своје структуре и понашања (конкретно вредности, мета-податке, особине и функције) у рантајму.[1]

Историјска позадина

уреди

Најранији рачунари су програмирани на матерњем асемблер језику, који су били по себи одражавани као ова оригинална архитектура која може да се програмира дефинисањем инструкција као и коришћењем података само-модификујућег кода. Као програмирање се преселило у језике високог нивоа, као што је C, ово одражава способност несталу (ван малвера) до програмских језика са одразом уграђеним у њихове типове система појава.

Брајан Кантвел Смитова 1982 докторска дисертација[2][3] увела је појам рачунарске рефлексије у програмским језицима, као и појам мета-кружни преводилац као компонента 3-Lisp.

Примене

уреди

Рефлексија може да се користи за посматрање и допунавање извршавање програма на рантајму. Рефлексија оријентисана програм компонента може пратити извршење кућишта кода и може се модификовати према жељеном циљу у вези са тим кућиштем. Ово се обично постиже динамичком доделом програмског кода у рантајму.

У објектно оријентисаним програмским језицима као што су Јава, рефлексија омогућава преглед класа, интерфејса, поља и метода у току рада не знајући имена интерфејса, поља, метода компилације. Она такође омогућава примерну нових објеката и позивање метода.

Рефлексија се такође може користити за адаптирање датог програма у различитим ситуацијама динамике. На пример, размислите апликацију која користи две различите класе X и Y наизменично да обављају сличне операције. Без рефлексије оријентисаног програмирања, апликација може бити тешко кодирана да позове метод имена класеX и класе Y. Међутим, користећи рефлексија оријентисану парадигму програмирања, апликација може бити дизајнирана и написана да искористи рефлексију у циљу изазивања метода у класама X и Y без хард-кодирања имена метода. Рефлексија-оријентисано програмирање скоро увек захтева додатно знање, оквир, релационо мапирање, а објекат релевантност како би се искористио више генеричко извршење кода.

Рефлексија се често користи као део тестирања софтвера, као што је за стварање Рантајма/примена пробних објеката.

Рефлексија је такође кључна стратегија за метапрограмирања.

У неким објектно-оријентисаним програмским језицима, као што су C# и Јава, рефлексија може да се употреби да обори члан приступачног правила. На пример, рефлексија омогућава да промените вредност поља са ознаком "приватно" у независну класу библиотеке.

Имплементација

уреди

Језик за подршку рефлексије обезбеђује велики број функција које су доступне на рантајму које би иначе било тешко постићи у језику нижег нивоа. Неке од ових функција су могуће до:

  • Откријте и модификује изворни код конструкција (као што је код блокова, класа, метода, протокола, итд) као објекти прве класе на рантајму.
  • Претварање стринга који одговара симболичком имену класе или функције у односу на или упућивање на те класе или функције.
  • Процените стринг као да је изјава изворног кода у рантајму.
  • Креирајте нови тумач за језик бајтока да да нови смисао или циљ за програмирање конструкта.

Ове карактеристике могу се реализовати на различите начине. У МОО-у, рефлексија представља природан део свакодневног програмирања идиома. Када се зову глаголи (методе), разне варијабле као што је глагол (име глагола који се зове) и ово (предмет на који се назива глагол) су насељени да дају контекст позива. Безбедност обично управља приступом саговорничким штос програмно: Како је код саговорника () списак начина на који се тренутни глагол на крају зову, извођење тестова саговорника ()[1] (команде позивају оригиналног корисника) омогућава да се глагол заштити од неовлашћеног коришћења.

Састав језика се ослања на свој рантајм систем да пружи информације о изворном коду. Састав Objective-C извршења, на пример, бележи имена свих метода у блок извршењу, обезбеђујући сто да одговара оним са основним методама (или селекторе за ове методе) састава у програму. У састав језика који подржава рантајм стварање функција, као што је Common Lisp, рантајм окружење мора да садржи компајлер или преводиоца.

Рефлексија се може реализовати за језике који немају уграђене рефлексије објеката помоћу програма трансформације система да дефинишу аутоматске промене изворног кода.

Примери

уреди

Код следеће код комадићи креирају инстанцу foo класе Foo, и позивају методу hello. За сваки програмски језик, нормала и рефлексија на бази секвенце позива се приказује.

У наставку је пример у eC-у:

// без рефлексије
Foo foo { };
foo.hello();

// са рефлексијом
Class fooClass = eSystem_FindClass(__thisModule, "Foo");
Instance foo = eInstance_New(fooClass);
Method m = eClass_FindMethod(fooClass, "hello", fooClass.module);
((void (*)())(void *)m.function)(foo);

ECMAScript

уреди

У наставку је пример у ECMAScript-у, и стога важи и за Јаваскрипт и ActionScript:

// без рефлексије
new Foo.hello()

// са рефлексијом

// под претпоставком да Foo борави у овде
new this['Foo']['hello']()

// или без претпоставке
new (eval('Foo'))['hello']()

// или једноставно
eval('new Foo.hello()')

Јава

уреди

У наставку је пример у Јави:

// без рефлексије
Foo foo = new Foo();
foo.hello();

// са рефлексијом
Object foo = Class.forName("complete.classpath.and.Foo").newInstance();
// Алтернативно: Објекат foo = Foo.class.newInstance();
Method m = foo.getClass().getDeclaredMethod("hello", new Class<?>[0]);
m.invoke(foo);

Objective-C

уреди

Следећи пример у Objective-C-у имплицира OpenStep или се користи фондација Кит оквир:

// Foo класа.
@interface Foo : NSObject
- (void)hello;
@end

// Слање "здраво" на пример Foo без рефлексије.
Foo *obj = [[Foo alloc] init];
[obj hello];

// Слање "здраво" на пример Фоо са рефлексијом.
id obj = [[NSClassFromString(@"Foo") alloc] init];
[obj performSelector: @selector(hello)];

Делфи

уреди

Овај Делфи пример претпоставља да TFoo класа је декларисана у јединици под називом Јединица 1:

uses RTTI, Unit1;

procedure WithoutReflection;
var
  Foo: TFoo;
begin
  Foo := TFoo.Create;
  try
    Foo.Hello;
  finally
    Foo.Free;
  end;
end;

procedure WithReflection;
var
  RttiContext: TRttiContext;
  RttiType: TRttiInstanceType;
  Foo: TObject;
begin
  RttiType := RttiContext.FindType('Unit1.TFoo') as TRttiInstanceType;
  Foo := RttiType.GetMethod('Create').Invoke(RttiType.MetaclassType, []).AsObject;
  try
    RttiType.GetMethod('Hello').Invoke(Foo, []);
  finally
    Foo.Free;
  end;
end;

Ово је значајан пример, јер Делфи је без менаџера, потпуно природно састављен језик, за разлику од већине других језика који подржавају размишљање. Његова архитектура језика наслеђује од снажног-откуцаног Паскала, али са значајним утицајем од SmallTalk-а. Упоредите са осталим примерима овде, од којих су многи динамични или скрипте језици као што су Perl, Пајтон или PHP или језици са рантајма као Јава или C#.

У наставку је пример у Perl-у:

# без рефлексије
my $foo = Foo->new;
$foo->hello;

# или
Foo->new->hello;

# са рефлексијом
my $class = "Foo"
my $constructor = "new";
my $method = "hello";

my $f = $class->$constructor;
$f->$method;

# или
$class->$constructor->$method;

# са eval-ом
eval "new Foo->hello;";

У наставку је пример у PHP-у:

// без рефлексије
$foo = new Foo();
$foo->hello();

// са рефлексијом
$reflector = new ReflectionClass('Foo');
$foo = $reflector->newInstance();
$hello = $reflector->getMethod('hello');
$hello->invoke($foo);

// коришћење повратних позива
$foo = new Foo();
call_user_func(array($foo, 'hello'));

// коришћењем променљиве варијабле синтаксе
$className = 'Foo';
$foo = new $className();
$method = 'hello';
$foo->$method();

Пајтон

уреди

У наставку је пример у Пајтону:

# без рефлексије
obj = Foo()
obj.hello()

# са рефлексијом
class_name = "Foo"
method = "hello"
obj = globals()[class_name]()
getattr(obj, method)()

# са eval-ом
eval("Foo().hello()")

У наставку је пример у R-у:

# Без рефлексије, под претпоставком да foo () враћа С3-тип објекат који има методу "здраво"
obj <- foo()
hello(obj)

# са рефлексијом
the.class <- "foo"
the.method <- "hello"
obj <- do.call(the.class, list())
do.call(the.method, alist(obj))

У наставку је пример у Рубију:

# без рефлексије
obj = Foo.new
obj.hello

# са рефлексијом
class_name = "Foo"
method = :hello
obj = Object.const_get(class_name).new
obj.send method

# са eval-ом
eval "Foo.new.hello"

Види још

уреди
  • Тип интроспекција
  • Само-модификујући код
  • Само-домаћински
  • Парадигме програмирања
  • Листа рефлектујућих програмских језика и платформи
  • Огледало (програмирање)

Референце

уреди

Литература

уреди

Спољашње везе

уреди