Article View: pl.comp.lang.c
Article #267841Re: Ciemna strona C++
From: Marcin ‘Qrczak’ Kowalczyk
Date: Tue, 04 Dec 2007 19:11
Date: Tue, 04 Dec 2007 19:11
240 lines
12941 bytes
12941 bytes
Dnia 04-12-2007, Wt o godzinie 11:45 +0000, Sektor van Skijlen pisze:
> W Tcl-u zastosowano znacznie sensowniejsze reguły określania co jest
> symbolem, a co nie.
W Tcl-u zastosowano znacznie bezsensowniejsze reguły, które w ogóle
wymagają określania na każdym kroku, jaka jest tekstowa postać symbolu,
w czasie wykonania programu. Pamiętam boty ircowe, w których teksty
po przejściu przez nie dostawały czasem dodatkowe bekslesze bądź klamry,
jeśli składały się z kilku słów.
W Lispie to jest szczegół techniczny obecny wyłącznie w readerze
i printerze. Wykonujący się program może się do tego czasem odwołać,
bo może używać standardowego readera i printera np. do serializacji
albo do pisania logów, ale to jest marginalne użycie, które nie wpływa
na takie sprawy jak odwoływanie się do zmiennych, operacje na kolekcjach
itp.
> > Największy grzech Tcl to
> > nieuznawanie wskaźników, czyli konieczność symulowania ich unikalnymi
> > symbolicznymi nazwami, nieodróżnialnymi od stringów i bez szans na
> > odśmiecanie.
>
> Wskaźnikiem w Tcl-u jest literowa nazwa zmiennej, jaka obowiązuje dla niej
> w danej ramce.
To całkiem głupi wskaźnik, biorąc pod uwagę, że po pierwsze trzeba jakoś
określić, o którą ramkę chodzi, a po drugie ramki może wkrótce nie być -
takiego wskaźnika nie da się oderwać od wykonującej się funkcji.
> Mnie za to drażni sytuacja, w której język "teoretycznie" oparty o składnię
> listy (element1 element2 element3) posiada "słowa kluczowe" i różne
> konstrukcje, sterty symboli, zmieniających znaczenie konstrukcji teoretycznie
> opartych tylko o listę.
>
> Pamiętam jak swego czasu wzięło mnie na ambicję, żeby choć zapoznać się
> gruntownie ze składnią Common Lispa. Jak doszedłem do kolejnego symbolu typu
> `#$, który coś kolejnego ciekawego oznaczał w składni języka, to się poddałem.
To jest tylko powierzchowny lukier składniowy, który rozwija się do
konstrukcji z listami i symbolami jeszcze w readerze. Kod w Lispie
można rozumieć jako strukturę zawierającą tylko trzy rodzaje obiektów:
- pary (cons)
- symbole
- inne stałe (w jednym worku).
> > Nie, dokładnych typów argumentów nie trzeba znać. Na przykład nie trzeba
> > w miejscu wołania wiedzieć, czy argument jest typu int, czy long, ani
> > nie trzeba w żaden sposób jawnie informować o typie wyniku - on musi być
> > odczytywalny automatycznie, skoro jest wyznaczony jednoznacznie przez
> > funkcję.
>
> Jeśli mówimy o java.lang.reflection (skoro już podałeś to jako przykład), to
> niestety nie masz racji. Tam, żeby dobrać się do określonej metody musisz znać
> nie tylko jej nazwę, ale również typy argumentów, które podajesz jako obiekty
> typu Class
Tego nie trzeba znać, wiązanie językowe może to sprawdzić automatycznie.
Można wylistować metody o danej nazwie, obejrzeć ich sygnatury i znaleźć
najlepiej pasujące przeciążenie do danych parametrów.
> (swoją drogą nie wiem, jak się tam podaje typ int, ale może i jest
> coś takiego, jak int.class...).
Jest.
> > A tak jest przy dlsym w C i C++.
>
> Co ty chrzanisz? Od kiedy to w dlsym musisz powiadamiać o dokładnym typie?
>
> Czy chodzi ci o to, że z dlsym dostajesz void* i masz UB jeśli zrzutujesz to
> na nie taki wskaźnik do funkcji jaki tam był podczas kompilacji?
Tak.
> W C++ problem istnieje również, owszem, chociaż nie jest on nie do obejścia
> (w C owszem jest). Można by było dorobić w gcc coś typu takiego makra, które
> po podaniu odpowiedniego symbolu lub deklaracji zwracałoby tekstowo zmanglowaną
> nazwę do wiązania zewnętrznego. Przykładowo (piszę wedle starych reguł, bo mi
> tak wygodniej):
>
> typedef int f_t( int, const char* );
> f_t* pf = dlsym( lib, CXX_MANGLE( f_t, "f" ) );
To może rozwiązać sprawę typów argumentów, ale nie pomaga przy typie wyniku.
> Ok, to wszystko jest jak najbardziej prawda - tylko wyjaśnij mi, dlaczego
> nikt z tej refleksji nie korzysta?
Zapewniam, że się czasem korzysta. Jako przykład podałem Jython.
> Przecież refleksje można by zastosować do zaimplementowania jakiejś sensownej
> postaci wskaźnika do funkcji, którego w Javie potwornie brakuje.
Nie, do tego akurat słabo się nadaje. Wskaźnik do funkcji w statycznie
typowanym języku powinien być statycznie typowany.
Java będzie miała sensowną lambdę natywnie: http://www.javac.info/
> > Może być bez iterowania. Byle dało się użyć elementu znając jego nazwę
> > (dynamicznie) i wiedząc mniej więcej, skąd pochodzi. Może nie być
> > możliwości sprawdzenia, ilu argumentów potrzebuje, byle pomyłka była
> > wykryta, a nie skutkowała zachowaniem niezdefiniowanym. Chcę uzyskać
> > z danej biblioteki interfejs bez zachowania niezdefiniowanego, bo ono
> > nie pasuje do docelowego języka.
>
> Ale nie mów mi, że chciałbyś to jednocześnie móc zrobić nie zagłębiając się
> w szczegóły interfejsu tej biblioteki.
Ależ można, jak pokazuje most między Kogutem a Pythonem. On nie musi
znać poszczególnych pythonowych bibliotek. Dopiero jego użytkownik
musi znać tę bibliotekę, której chce użyć, ale z kolei żeby użyć
z poziomu Koguta biblioteki zaimplementowanej w Pythonie, nie trzeba
napisać ani linijki kodu w Pythonie. A w drugą stronę pisać w drugim
języku coś tam czasem trzeba, ale niewiele.
> > - Odwołać się do pola obiektu znając nazwę pola (odwołanie do pola
> > jest aplikacją do symbolu). To nie jest refleksja, tylko dynamizm.
>
> Zgadza się. Przecież nazwy symbolu nie podajesz w stringu, tylko nazwa
> pola już wcześniej musi być symbolem.
Symbol i string to prawie to samo (w Kogucie tak jak w Scheme, nie tak
jak w Common Lispie, gdzie symbol pełni też funkcję zestawu zmiennych).
Można dynamicznie skonwertować string na symbol i odwrotnie (modulo
specjalny rodzaj symboli prywatnych względem modułu).
> > - Odczytać nazwę typu i nazwę nazwanej funkcji.
>
> Jako string? A co z operacją w drugą stronę?
Jako symbol. A w drugą stronę nie można, bo nazwy typów czy funkcji nie
muszą być unikalne, jeśli są eksportowane przez różne moduły.
Dopiero z obiektu reprezentującego moduł i symbolu można uzyskać nazwany
daną nazwą obiekt.
> > - Dodać nadtyp istniejącego typu.
>
> Zidentyfikowanego w jaki sposób?
Jako obiekt reprezentujący typ. Definicja typu wprowadza taki obiekt.
Obiekt reprezentujący typ służy przede wszystkim do sprawdzania,
jakiego typu jest dany obiekt - w różnych kontekstach: definiowanie
metody funkcji generycznej dla danych typów parametrów, jawne
sprawdzenie, czy obiekt jest danego typu, uzyskanie typu danego obiektu
i porównanie go z innym typem albo wyszukanie w słowniku. Natomiast
w odróżnieniu od Pythona, Smalltalka i Rubego typ nie służy do
tworzenia nowych obiektów tego typu.
> Spoko, że możesz potraktować jako obiekty (wartości etc.) wszystko,
> co się rusza w języku, ale jak to identyfikujesz?
Nie rozumiem pytania. Przez wskaźnik albo przez wyeksportowanie
z jakiegoś modułu pod jakąś nazwą.
> > - Dostać się do prywatnych składników obiektu albo modułu.
>
> Tego to chyba w żadnej refleksji nie można :)
W Javie można.
Common Lisp i Python też nie przewidują wymuszanej prywatności,
tylko konwencje pozwalające uniknąć pogwałcenia prywatności niechcący.
Jeśli ktoś wie, co robi, to może dotrzeć np. do prywatnych definicji
danego modułu albo do prywatnych pól (ale i tam są granice, np. w Lispie
nie ma przenośnej metody na obejrzenie wartości zmiennych wolnych
obiektu będącego funkcją).
> Refleksja chyba nie polega na modyfikacji programu w trakcie wykonania?
Zależy od terminologii. Niektórzy rozróżniają pasywną introspekcję
i aktywną refleksję.
> > - Wylistować podtypów danego typu (nie są nawet fizycznie zebrane
> > w jednym miejscu).
>
> Ale wylistować wszystkie typy, które są pochodnymi określonego typu,
> tylko w zakresie podanych modułów, już chyba można?
Można próbować ręcznie: sprawdzić, co te moduły eksportują, które z tych
rzeczy to typy i które są podtypami danego. Przy czym moduł może nie
eksportować danego typu wprost, ale używać obiektów danego typu i np.
oferować funkcje, które zwracają obiekty tego typu. Typ może być zgoła
tworzony dynamicznie (każda definicja, która może się pojawić globalnie,
może być też użyta lokalnie i na odwrót - z wyjątkiem pewnych konstrukcji
do łączenia z językiem C). Więc to i tak byłoby przybliżenie.
> > - Wylistować istniejących metod danej funkcji generycznej.
>
> Na tej samej zasadzie.
Nie, na innej zasadzie.
Metoda to implementacja danej funkcji generycznej dla danych typów
parametrów. Funkcja generyczna to w zasadzie słownik metod indeksowany
typami wybranych parametrów (modulo możliwość różnych słowników dla
różnych arności w tej samej funkcji generycznej). Metody istnieją tylko
wewnątrz funkcji generycznych. One fizycznie się tam znajdują; inaczej
niż w przypadku Smalltalka, gdzie metody znajdują się w klasach i są
indeksowane nazwami. Tu i tu efekt jest podobny, bo chodzi o znalezienie
implementacji dla danej pary: abstrakcyjnej operacji i typu.
Zatem teoretycznie można by umożliwić listowanie metod danej funkcji.
One są zebrane w jednym miejscu. Common Lisp to ma. Przy czym to
by uniemożliwiło trzymanie tych metod słabymi referencjami, czyli
odśmiecanie ich, jeśli ich typy się odśmiecą (na razie tego nie robię,
ale kiedyś będę).
> > - Wyekstrahować implementacji metody funkcji generycznej dla danych
> > argumentów bez jej wołania.
>
> Nie rozumiem.
Teoretycznie można by udostępnić operację ręcznego odczytu wartości
(metody) dla danego klucza (typu) ze wspomnianego wyżej słownika.
To by się mogło przydać jako ręcznie wykonana optymalizacja: uniknięcie
wielokrotnego dispatchu i wykonanie go np. raz przed pętlą.
Ale tego nie udostępniam, bo to by się kłóciło z gwarancją dawaną
metodom, że będą aplikowane tylko dla obiektów właściwych typów.
Ta gwarancja pozwala wyeliminować dodatkowe upewnianie się, czy typ
jest dobry, w przypadku niskopoziomowych implementacji różnych metod.
> > To, co można, wystarcza np. do tego, żeby interpreterowi Pythona
> > udostępnić funkcjonalność danego modułu Koguta (tudzież zbioru modułów)
> > bez konieczności listowania zawartości tego modułu. Obecnie trzeba
> > jednak statycznie zaimportować ten moduł, tzn. nie można znaleźć go
> > z poziomu Pythona znając dynamicznie jego nazwę.
>
> No ale czy do tego nie potrzebowałeś czasem dorobić odpowiedniej
> przystawki do tego w Pythonie?
Nie rozumiem.
--
__("< Marcin Kowalczyk
\__/ qrczak@knm.org.pl
^^ http://qrnik.knm.org.pl/~qrczak/
Technical Details
Message-ID:
<1196795495.17904.98.camel@qrnik>Path:
mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!news.gazeta.pl!newsfeed.pionier.net.pl!news.internetia.pl!newsfeed.tpinternet.pl!atlantis.news.tpi.pl!news.tpi.pl!not-for-mailReferences:
<fghgeo$spf$1@nemesis.news.tpi.pl> <fghsb4$kpq$1@news.dialog.net.pl> <fgo4c7$mtu$1@news.vectranet.pl> <20071106073039.433f4934@Vorago> <fgqn9m$74j$2@news.vectranet.pl> <618565031.20071107113041@pkierski.net> <fgt6sh$jov$1@news.vectranet.pl> <fgtb6j$nur$1@news.vectranet.pl> <fgv6ba$k14$1@bozon2.softax.pl> <fgvkne$u3b$1@news.vectranet.pl> <fh1tjd$dtt$1@bozon2.softax.pl> <fh2lj6$qkh$1@news.vectranet.pl> <fha3as$pap$1@bozon2.softax.pl> <fhaj8u$e02$1@news.vectranet.pl> <fhf09d$ohq$1@bozon2.softax.pl> <fhfi9l$640$1@news.vectranet.pl> <fhurmu$5d9$1@bozon2.softax.pl> <fhv020$8k1$1@news.vectranet.pl> <fi1bs4$nn3$1@bozon2.softax.pl> <fi27ds$gt1$1@kujawiak.man.lodz.pl> <fi458p$fmv$1@bozon2.softax.pl> <fi9ckc$2u5$1@kujawiak.man.lodz.pl> <1195918508.27382.40.camel@qrnik> <fiee2a$af0$1@kujawiak.man.lodz.pl> <1196084612.2991.60.camel@qrnik> <fj3el2$j5u$1@kujawiak.man.lodz.pl>Show Full Headers
Complete Article Headers
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!news.gazeta.pl!newsfeed.pionier.net.pl!news.internetia.pl!newsfeed.tpinternet.pl!atlantis.news.tpi.pl!news.tpi.pl!not-for-mail From: Marcin ‘Qrczak’ Kowalczyk <qrczak@knm.org.pl> Newsgroups: pl.comp.lang.c Subject: Re: Ciemna strona C++ Date: Tue, 04 Dec 2007 20:11:36 +0100 Organization: tp.internet - http://www.tpi.pl/ Lines: 312 Message-ID: <1196795495.17904.98.camel@qrnik> References: <fghgeo$spf$1@nemesis.news.tpi.pl> <fghsb4$kpq$1@news.dialog.net.pl> <fgo4c7$mtu$1@news.vectranet.pl> <20071106073039.433f4934@Vorago> <fgqn9m$74j$2@news.vectranet.pl> <618565031.20071107113041@pkierski.net> <fgt6sh$jov$1@news.vectranet.pl> <fgtb6j$nur$1@news.vectranet.pl> <fgv6ba$k14$1@bozon2.softax.pl> <fgvkne$u3b$1@news.vectranet.pl> <fh1tjd$dtt$1@bozon2.softax.pl> <fh2lj6$qkh$1@news.vectranet.pl> <fha3as$pap$1@bozon2.softax.pl> <fhaj8u$e02$1@news.vectranet.pl> <fhf09d$ohq$1@bozon2.softax.pl> <fhfi9l$640$1@news.vectranet.pl> <fhurmu$5d9$1@bozon2.softax.pl> <fhv020$8k1$1@news.vectranet.pl> <fi1bs4$nn3$1@bozon2.softax.pl> <fi27ds$gt1$1@kujawiak.man.lodz.pl> <fi458p$fmv$1@bozon2.softax.pl> <fi9ckc$2u5$1@kujawiak.man.lodz.pl> <1195918508.27382.40.camel@qrnik> <fiee2a$af0$1@kujawiak.man.lodz.pl> <1196084612.2991.60.camel@qrnik> <fj3el2$j5u$1@kujawiak.man.lodz.pl> NNTP-Posting-Host: hjd150.internetdsl.tpnet.pl Mime-Version: 1.0 X-Trace: atlantis.news.tpi.pl 1196795562 2739 79.187.237.150 (4 Dec 2007 19:12:42 GMT) X-Complaints-To: usenet@tpi.pl NNTP-Posting-Date: Tue, 4 Dec 2007 19:12:42 +0000 (UTC) In-Reply-To: <fj3el2$j5u$1@kujawiak.man.lodz.pl> X-Mailer: Evolution 2.12.1 PLD Linux Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit