Ostatnio czytając jedną z książek o programowaniu w Objective-C natrafiłem na sformułowanie o polimorfizmie, które spowodowało u mnie wodę z mózgu. Musiałem się nad nim naprawdę zastanowić, gdyż do tej pory w ogóle o tym w takich kategoriach, a jednak. Po dłuższym zastanowieniu się zrewidowałem swoje pojęcie co to jest polimorfizm.

Wszystko zaczęło się od tego zdania:

Polymorphism enables programs to be developed so that objects from different classes can define methods that share the same name.

Kod w Objective-C wykorzystany w zobrazowaniu przykładu w książce (uprościłem go):

@interface A : NSObject

-(void) write;

@end

@implementation A

-(void) write {
	NSLog(@"Hello from A");
}

@end

@interface B : NSObject

-(void) write;

@end

@implementation A

-(void) write {
	NSLog(@"Hello from B");
}

@end

// ... main

A *a = [[A alloc] init];
B *b = [[B alloc] init];

[a write];
[b write];

A to do niego opis:

As mentioned, the capability to share the same method name across different classes is known as polymorphism. Polymorphism enables you to develop a set of classes that each can respond to the same method name. Each class definition encapsulates the code needed to respond to that particular method, and this makes it independent to the other class definitions. This also enables you to later add new classes that can respond to methods with the same name.

Jak to czytaliście to pewnie WAT? się u was w głowie pokazało. Nic dziwnego, w C# wygląda to tak (dosłownie jakbyśmy chcieli przepisać kod Obj-C):

public class A 
{
	public void Wirte() 
	{
		Debug.WriteLine("Hello from A");

	}
}

public class B 
{
	public void Wirte() 
	{
		Debug.WriteLine("Hello from B");

	}
}

// ... main

A a = new A();
B b = new B();

a.Write();
b.Write();

Byśmy tego nie nazwali polimorfizmem, stworzylibyśmy raczej klasę bazową z virtual/abstract method albo lepiej, interfejs i metodę ogólną print dla danej sygnatury (czy lepiej czy nie, to inna kwestia ;)).

Jak się okazuje (co ma ręce i nogi) w Objective-C to zdanie ma jak największy sens – problem z nim (ze zdaniem) polega na tym, że określa ono tak jakby że na tym polega polimorfizm ogólnie, a nie specyficznie do języka.

W Objective-C, który bazuje na Smalltalk mamy styczność z wysyłaniem wiadomośći do obiektu. To znaczy, że kod [obj msg] oznacza wyśli wiadomość msg do obiektu x. I jest to wykonywane przez funkcję objc_msgSend, która przyjmuje dwa podstawowe parametry i jeden opcjonalny:

id objc_msgSend(id theReceiver, SEL theSelector, ...)

id jest w Objective-C odpowiednikiem dynamic w C# (choć pod var też to można ciutkę podciągnąć), zaś SEL jest selektorem danej metody. To co robi Objective-C to za pomocą wskaźnika na obiekt (id jest używane bez *) wyciąga metadane danej klasy i sprawdza czy ona spełnia wymagania podane w SEL i parametrach dodatkowych. Jeżeli tak, to metoda dopiero jest przesyłana do obiektu.

Co oznacza, że każdy obiekt implementujący metodę X podlega polimorfizmowi w Objective-C gdyż jest to sprawdzane nie przez kompilator statycznie (choć jest) ale decyzja o tym, czy obiekt może przyjąć taką wiadomość jest odłożona do czasu wykonania kodu. Czyli możemy podmienić obiekt na inny (jeżeli jest taka możliwość) i też kod zadziała.

W C# możemy zobrazować to za pomocą refleksji – wtedy nas nie interesuje klasa bazowa, jedynie to czy klasa ma taką metodę czy też nie, w JavaScript robimy to po prostu za pomocą odwołania się do własności obiektu przekazanego w parametrze (czyli tak zwane Duck Typing – When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck, czyli jeżeli przekazany obiekt ma własność name to znaczy, że spełnia nasze założenie):

var z = {
	name: 'Some Name'
};

function x (obj) {
	console.log(x.name);
}

x(z);
x({
	name: 'My Name'
});

Tak naprawdę to samo stwierdzenie co do JS można wykorzystać też do Objective-C, oczywiście jak to jest robione to inna sprawa.

Może to co napisałem dla niektórych zabrzmi dziwnie a dla niektórych błacho, albo w ogóle będzie sprzecznie z tym co uważają i co wyczytają w internecie. Jednak dla mnie ma to ręce i nogi, i polimorfizm wcale nie musi być wykonywany za pomocą dziedziczenia czy też generyczności.

2 KOMENTARZE

  1. W zasadzie to tu nie powinno być nic do rewidowania, powinieneś to pamiętać ze studiów. Różnych typów polimorfizmu jest sporo, żaden język obiektowy nie implementuje wszystkich – w większości masz po prostu przeciążanie i przesłanianie, w niektórych jeszcze polimorfizm parametryczny w formie wyrażeń lambda. Opcji jest sporo więcej, tak samo jak np. możliwych modeli obiektowości…

  2. **@Pietia**

    zgadza sie, ze jest duzo, jednak jak piszesz kod w Obj-C to nie pozwoli Ci on wpisac tam metody w danym przykladzie innej niz write gdyz ona nie istnieje – walidacja statyczna. Kompilator zas wywali blad.

    wiec doslownie mowiac przepisanie tego kodu na jezyk C# wyglada tak jak w przykladzie wyzej. a to polimorfizmem w C# nie jest. a nie jest ze wzgledu na to jak jezyk jest stworzony.

    i tu jest pies pogrzebany z tym konkretnym przykladem – trzeba bylo zejsc do podstaw jezyka by sie z twierdzeniem zgodzic :) Autor mogl to sam napisac, zamiast dawac skrot myslowy, przez co potem programisci idacy na rozmowe o prace wala rozne glupoty tam :)

Comments are closed.