A miks dane <-> zachowania jest tak fundamentalny, że widzimy go zarówno w assemblerze jak i w haskellu.
Kodziłem zarówno w asemblerze (dużo) jak i w Haskellu (mało) i tam obiektówki raczej nie ma (no chyba, że jak robiłem okienka za pomocą win32api). Obiekt jest wtedy, kiedy za pomocą jednego uchwytu (czyli w praktyce referencji) możemy mieć dostęp zarówno do danych jak i funkcji na nich operujących.
Poniższy kod nie jest obiektowy, bo przetwarzajDane
nie jest składową typu dane
:
var dane = posklejajDane(arg1, arg2, arg3, ..., argN);
przetwarzajDane(dane);
Poniższy kod jest obiektowy jeżeli metoda przetwarzaj
jest polimorficzna (czyli de facto wirtualna):
var dane = posklejajDane(arg1, arg2, arg3, ..., argN);
dane.przetwarzaj();
Gdyby w powyższym kodzie metoda przetwarzaj
była metodą rozszerzającą czy też inną całkowicie statycznie wiązaną metodą to byłoby trochę dyskusyjne czy to bardziej OOP czy może cukier składniowy wyglądający jak OOP. Generalnie zapis xyz.abc()
sugeruje prawie wszystkim obiektówkę, a zapis abc(xyz)
kod nieobiektowy, ale to moim zdaniem zbytnie spłycanie paradygmatu obiektowego.
Rust ma typeclassy (które akurat w tym języku definiuje się za pomocą słówka kluczowego trait
, a nie class
jak w Haskellu), ale zamiast typowego dla Haskella zapisu np. sort list
oferuje zapis list.sort()
. Mimo iż ten zapis z Rusta wygląda jak obiektowy (dla kogoś kto kieruje się powierzchownością, czyli dla zdecydowanej większości programistów) to nadal (pomijając https://doc.rust-lang.org/reference/types/trait-object.html ) pozostaje nieobiektowy, bo opiera się na typeclassach (przy założeniu, że to sort
jest polimorficzną metodą, czyli właśnie z typeclassy).
Typeclassy mają sens generalnie tylko przy językach statycznie typowanych (chodzi o sprawdzanie typów na etapie kompilacji, a reified generics nie mają tu znaczenia). Jednym z założeń typeclasses jest to, że się ich jawnie nie podaje (w sensie ich instancji). Zamiast tego to kompilator, na podstawie statycznie obliczonego typu, sam wyszukuje instancje typeclass i podaje je tam gdzie są potrzebne. Dzięki temu kod wygląda jakby struktury danych magicznie nabywały wbudowanych w nie metod, ale tak nie jest. Typeclassy są zadeklarowane (chodzi o interfejs) i zdefiniowane (chodzi o instancje) poza strukturami danych, więc nie ma OOPowego łączenia stanu i zachowania w jeden byt.