🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: pl.comp.lang.c
Article #310321

Re: Sztuka Kodowania w C++ - Nowa Wersja!

#310321
From: Maciek Godek
Date: Thu, 10 Dec 2020 10:21
76 lines
7823 bytes
środa, 9 grudnia 2020 o 16:35:48 UTC+1 jawors...@adres.pl napisał(a):
> > Swego czasu szukałem historycznego uzasadnienia dla wielodziedziczenia, i jedyne, co znalazłem, to przykład z książki Coxa i Novobilskiego "Object Oriented Programming: An Evolutionary Approach", gdzie dla uzasadnienia wielodziedziczenia posługują się przykładem "zabawkowego samochodu" ("czy jest to rodzaj zabawki, czy rodzaj samochodu?", pytają, odpowiadając sobie, że dzięki wielodziedziczeniu może być "i jednym, i drugim")
> Takie "uzasadnienie" jest dla dzieci. Bo w praktyce zaczynamy od pojęcia zabawki. Wynika to z przypadku użycia w którym głównym aktorem jest dziecko. Kolejne zabawki dziedziczymy z tej klasy. Nie dziedziczymy po klasie samochód, bo żaden prawdziwy samochód nie jest zabawką dla dziecka. Zabawki nie są rodzajem samochodu. Samochodziki są rodzajem zabawki. Tak samo jak dziecko nie jest typem pochodnym od Lalka (dziecko bawi się laką ale nie innym dzieckiem). 
> Hierarchia klas w tym przypadku jest: class Zabawka {...}; class Samochodzik : public Zabawka {...}; I dalej: class Lalka : public Zabawka {...}; 
> To tyle o tym bez sensownym przykładzie. 

Oczywiście, przykład jest bezsensowny, z czym się w 100% zgadzam.
Ale z Twoją hierarchią nie mogę się jednak do końca zgodzić, bo to jest tylko jakaś tam arbitralna specyfikacja, całkowicie oderwana od problemu, który chcemy rozwiązać. Po co w ogóle tworzyć klasę bazową "Zabawka"? Co chcemy w ten sposób osiągnąć?
W Javie nie ma wielodziedziczenia, ale są interfejsy, i jedna klasa może implementować wiele interfejsów.
Co do zasady wydaje mi się trochę dziwne, ale całe programowanie obiektowe w sumie jest dziwne.

Swego czasu robiłem taki eksperyment, żeby modelować hierarchie "zdolności" za pomocą funkcji/domknięć.
W praktyce bardzo to przypominało domieszkowanie ("mix-ins").

Wyszedłem od wizji OOP Alana Kaya, że programowanie obiektowe to obiekty otrzymujące i przekazujące między sobą wiadomości. "Dziedziczenie" czy też "domieszkowanie" odbywało się na poziomie instancji, a nie typów, ale to tylko szczegół techniczny. "Funkcja domieszkująca" dodawała do obiektu nowe zdolności w taki sposób, że mogła przechwytywać komunikaty i albo przekazywać je do obiektu bazowego, albo jakoś je reinterpretować po swojemu.

Kod źródłowy -- wynik eksperymentu -- można znaleźć tutaj:
https://github.com/panicz/sracket/blob/master/5.rkt#L759
a tutaj jest notatka z eksperymentu
https://github.com/panicz/writings/raw/master/talks/racketfest/racketfest.pdf

(niestety, przez brak językowego wsparcia dla takiej techniki programowania w języku Racket, w którym to robiłem, program działał raczej wolno, zwłaszcza jak odpaliłem u kumpla na Raspberry Pi)

szczególnie ciekawe wydaje mi się łączenie tych domieszek,  gromadzi w jednym wyrażeniu całą "hierarchię dziedziczenia"

(define (Box bitboxes)
  (Fitting
   (Stretchable
    (Draggable
     (Situated
      (MouseTracking
       (Hovering
	(KeyboardNavigable
	 (KeyboardFormattable
	  (Selectable
	   (Highlighting
	    (Decorated
	     (Reinterpretable
	      (laid-out horizontally
			(Collection bitboxes)))
	     #:decoration draw-parentheses!))))))))))))


W takim schemacie wielodziedziczenie oczywiście było możliwe, bo funkcja mogłaby dostać więcej niż jeden obiekt bazowy. Ale wtedy "dziedziczący obiekt" (czy właściwie jego twórca) musi zadecydować, do którego obiektu ma przekazać komunikat.

Dlatego jestem podejrzliwy w stosunku do "wielodziedziczenia jako funkcji języka" -- sprawia to, że projektant języka musi podjąć decyzję, którą powinien podjąć projektant klasy. Czyli decyzja jest podejmowana w złym miejscu.

> Podam za to prawdziwy przykład z mojego projektu. Ten problem jaki rozwiązuje wielodziedziczenie jest fundamentalny i (pomijając chamskie kopiowanie kodu w każdej klasie) jest nierozwiązywalny w inny sposób (nawet przez kompozycję). 
> 
> Problem: 
> Dostajemy bibliotekę Qt. Chcemy z niej korzystać w projekcie. Nie chcemy jej zmieniać, w myśl inżynierskiej zasady: "Zamknięte na modyfikacje: otwarte na rozszerzanie." Zakładamy (fałszywie), że Qt spełnia w pełni tą zasadę. 
> Mamy klasę QWidget która jest przodkiem okien i kontrolek Qt. 
> I teraz: chcemy kontrolki Qt sobie dostosować. Zauważamy przy tym, że część funkcjonalności jest wspólna i powinna być w klasie QWidget. Ale tej klasy nie możemy ruszyć (powyższa zasada inżynierii oprogramowania). 
> 
> Rozwiązanie: 
> By nie kopiować kodu w każdej naszej klasie kontrolki musimy zrobić klasę po której dziedziczą wszystkie kontrolki używane przez nas w projekcie. 
> 
> Czyli mamy klasy: 
> class MojaKontrolka {...}; 
> class Etykieta : public QLabel, public MojaKontrolka {...}; 
> class EdycjaWLini : public QLineEdit, public MojaKontrolka {...}; 
> class Edycja : public QTextEdit, public MojaKontrolka {...}; 
> class ListaRozwijana : public QComboBox, public MojaKontrolka {...}; 
> I tak dalej... 
> 
> Ten problem dotyczy każdej większej biblioteki jaką chcemy używać w nietrywialny sposób.

To znaczy, jak mniemam, dotyczy każdej większej biblioteki w C++, stworzonej na podstawie ograniczeń tego języka.

Dla mnie trochę nie jest jasna intencja Twojego kodu -- co to jest "MojaKontrolka"?
Co ona dodaje tych wszystkich klas, takich jak Etykieta czy ListaRozwijana, które jak rozumiem, bazują na analogicznych klasach z biblioteki Qt?
Czy ma jakieś niestatyczne i nie"chronione" metody/pola?

Jeżeli problemem jest "kopiowanie kodu w każdej klasie", to dla mnie jako programisty Lispa uniwersalnym rozwązaniem problemu kopiowania kodu są makra. Nie wiem, czy w tym przypadku to by było dobre rozwiązanie, bo też nie wiem, jaki problem próbujemy tu rozwiązać.

(ja jeszcze nie znalazłem dobrego podejścia do tworzenia graficznych aplikacji. Najlepsze, co do tej pory widziałem, to oparty na Qt Pythonowy framework Enaml, ale on też nadaje się raczej tylko do rzeczy podstawowych)
Technical Details
Message-ID: <f417233e-4d24-4306-9c9d-7ae0e6b699d1n@googlegroups.com>
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!news.icm.edu.pl!newsfeed.pionier.net.pl!goblin2!goblin3!goblin.stu.neva.ru!sewer!alphared!news.uzoreto.com!tr3.eu1.usenetexpress.com!feeder.usenetexpress.com!tr2.iad1.usenetexpress.com!border1.nntp.dca1.giganews.com!nntp.giganews.com!news-out.google.com!nntp.google.com!postnews.google.com!google-groups.googlegroups.com!not-for-mail
References: <478ab743-cd00-4961-88e1-983025db304bn@googlegroups.com> <d9830106-c21a-4564-b45f-0766ef86181fn@googlegroups.com> <cdd14123-89b7-4f80-9f2b-865f1038810an@googlegroups.com> <e38a42c4-36d3-49b6-8644-468f65828f4cn@googlegroups.com> <edd1ce6a-46e1-4883-8943-db4a0da8da33n@googlegroups.com> <8d469f13-e697-4488-8adf-29117a3eeb8cn@googlegroups.com>

Show Full Headers
Complete Article Headers
X-Received: by 2002:ac8:7a6a:: with SMTP id w10mr8071726qtt.55.1607595666143; Thu, 10 Dec 2020 02:21:06 -0800 (PST)
X-Received: by 2002:aed:2ba5:: with SMTP id e34mr8483616qtd.146.1607595665931; Thu, 10 Dec 2020 02:21:05 -0800 (PST)
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!news.icm.edu.pl!newsfeed.pionier.net.pl!goblin2!goblin3!goblin.stu.neva.ru!sewer!alphared!news.uzoreto.com!tr3.eu1.usenetexpress.com!feeder.usenetexpress.com!tr2.iad1.usenetexpress.com!border1.nntp.dca1.giganews.com!nntp.giganews.com!news-out.google.com!nntp.google.com!postnews.google.com!google-groups.googlegroups.com!not-for-mail
Newsgroups: pl.comp.lang.c
Date: Thu, 10 Dec 2020 02:21:05 -0800 (PST)
In-Reply-To: <8d469f13-e697-4488-8adf-29117a3eeb8cn@googlegroups.com>
Complaints-To: groups-abuse@google.com
Injection-Info: google-groups.googlegroups.com; posting-host=83.25.44.185; posting-account=f7iIKQoAAAAkDKpUafc-4IXhmRAzdB5r
NNTP-Posting-Host: 83.25.44.185
References: <478ab743-cd00-4961-88e1-983025db304bn@googlegroups.com> <d9830106-c21a-4564-b45f-0766ef86181fn@googlegroups.com> <cdd14123-89b7-4f80-9f2b-865f1038810an@googlegroups.com> <e38a42c4-36d3-49b6-8644-468f65828f4cn@googlegroups.com> <edd1ce6a-46e1-4883-8943-db4a0da8da33n@googlegroups.com> <8d469f13-e697-4488-8adf-29117a3eeb8cn@googlegroups.com>
User-Agent: G2/1.0
MIME-Version: 1.0
Message-ID: <f417233e-4d24-4306-9c9d-7ae0e6b699d1n@googlegroups.com>
Subject: Re: Sztuka Kodowania w C++ - Nowa Wersja!
From: Maciek Godek <godek.maciek@gmail.com>
Injection-Date: Thu, 10 Dec 2020 10:21:06 +0000
Lines: 143
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit