Nie zamierzałem publikować tego jako odpowiedzi, ale Xeoncross poprosił mnie o to, więc zaczynamy:
(Sidenote: jeśli ktoś mógłby naprawić problem przeceny w małym przykładzie kodu, byłbym wdzięczny).
Erik Max Francis napisał:
„Brandon J. Van Every” napisał:
Co jest lepszego w Ruby niż Python? Jestem pewien, że coś jest. Co to jest? Czy nie byłoby sensowniej pytać o to ludzi Ruby, niż ludzi Python?
Może, ale nie musi, w zależności od swoich celów - na przykład, jeśli cele te obejmują „badanie socjologiczne” społeczności Python, zadawanie pytań tej społeczności może okazać się bardziej ujawniające informacje na ten temat, niż umieszczanie ich gdzie indziej :-). Osobiście chętnie skorzystałem z okazji, by w końcu wykonać jednodniowy samouczek Ruby'a Dave'a Thomasa w OSCON. Pod cienką okleiną różnic składniowych uważam, że Ruby i Python są niesamowicie podobne - gdybym obliczał minimalne drzewo rozpinające spośród prawie każdego zestawu języków, jestem prawie pewien, że Python i Ruby byłyby dwoma pierwszymi, które połączyłyby się w jedno węzeł pośredni :-).
Jasne, robię się zmęczony, w Ruby, wpisywać głupie „koniec” na końcu każdego bloku (zamiast po prostu unindenting) - ale to ja rozumiem, aby uniknąć wpisując równo głupie :
co wymaga Pythona na
początku dnia każdy blok, więc to prawie pranie :-). Inne różnice w składni, takie jak @foo
versus
self.foo
lub większe znaczenie wielkości liter w Ruby vs. Python, są dla mnie tak samo nieistotne.
Inni bez wątpienia opierają swój wybór języków programowania na takich właśnie kwestiach i generują najgorętsze debaty - ale dla mnie to tylko przykład jednego z przepisów prawa Parkinsona w działaniu (kwota na debatę na dany temat jest odwrotnie proporcjonalna do problemu faktyczne znaczenie). Jedną różnicą w składni, którą uważam za ważną, i na korzyść Pythona - ale inni ludzie bez wątpienia będą myśleć odwrotnie - „jak wywołujesz funkcję, która nie przyjmuje parametrów”. W Pythonie (jak w C), aby wywołać funkcję, zawsze stosujesz „operator wywołania” - nawiasy końcowe tuż za wywoływanym obiektem (w tych nawiasach końcowych przechodzą argumenty, które przekazujesz w wywołaniu - jeśli nie podajesz żadnych argumentów, wtedy nawiasy są puste). Pozostawia to jedynie wzmiankę o dowolnym obiekcie, bez udziału operatora, co oznacza jedynie odniesienie do obiektu - w dowolnym kontekście, bez specjalnych przypadków, wyjątków, reguł ad-hoc i tym podobnych. W Ruby (jak w Pascalu), aby wywołać funkcję Z argumentami, przekazujesz argumenty (zwykle w nawiasach, choć nie jest to niezmiennie przypadek) - ALE jeśli funkcja nie przyjmuje argumentów, to po prostu wspomnienie o funkcji wywołuje ją pośrednio. Może to spełniać oczekiwania wielu osób (przynajmniej bez wątpienia tych, których jedyne wcześniejsze doświadczenie w programowaniu dotyczyło Pascala lub innych języków z podobnym „wywołaniem implicit”, takich jak Visual Basic) - ale dla mnie oznacza to sama wzmianka o obiekcie może ZAWSZE oznaczać odwołanie do obiektu LUB wywołanie obiektu, w zależności od typu obiektu - w tych przypadkach, w których nie mogę uzyskać odniesienia do obiektu, po prostu wspominając o nim, będę musiał użyć wyraźnego „podaj mi odniesienie do tego, NIE nazywaj go!” operatorzy, którzy w innym przypadku nie są potrzebni. Wydaje mi się, że wpływa to na „pierwszorzędność” funkcji (lub metod lub innych wywoływalnych obiektów) oraz na możliwość płynnej wymiany obiektów. Dlatego dla mnie ta konkretna różnica w składni jest poważnym czarnym znakiem przeciwko Ruby - ale rozumiem, dlaczego inni mieliby coś innego, nawet jeśli nie mogłem się z nimi bardziej zdecydowanie nie zgodzić :-). Poniżej składni przechodzimy do kilku ważnych różnic w elementarnej semantyce - na przykład ciągi znaków w Rubim są obiektami zmiennymi (jak w C ++), podczas gdy w Pythonie nie można ich modyfikować (jak w Javie lub wierzę w C #). Znów ludzie, którzy oceniają przede wszystkim na podstawie tego, co już znają, mogą pomyśleć, że jest to plus dla Ruby (chyba że znają Javę lub C #, oczywiście :-). Ja myślę, że niezmienne ciągi są doskonałym pomysłem (i nie jestem zaskoczony, że Java, jak sądzę niezależnie, na nowo wymyślił ten pomysł, który był już w Pythonie), chociaż nie miałbym nic przeciwko posiadaniu typu „zmiennego bufora ciągów” (i najlepiej taki, który jest łatwiejszy w użyciu niż własne „bufory łańcuchów” Javy); i nie oceniam tego ze względu na znajomość - przed studiowaniem Javy, oprócz funkcjonalnych języków programowania gdzie ludzie, którzy oceniają przede wszystkim na podstawie tego, co już znają, mogą pomyśleć, że jest to plus dla Ruby (chyba że znają Javę lub C #, oczywiście :-). Ja myślę, że niezmienne ciągi są doskonałym pomysłem (i nie jestem zaskoczony, że Java, jak sądzę niezależnie, na nowo wymyślił ten pomysł, który był już w Pythonie), chociaż nie miałbym nic przeciwko posiadaniu typu „zmiennego bufora ciągów” (i najlepiej taki, który jest łatwiejszy w użyciu niż własne „bufory łańcuchów” Javy); i nie oceniam tego ze względu na znajomość - przed studiowaniem Javy, oprócz funkcjonalnych języków programowania gdzie ludzie, którzy oceniają przede wszystkim na podstawie tego, co już znają, mogą pomyśleć, że jest to plus dla Ruby (chyba że znają Javę lub C #, oczywiście :-). Ja myślę, że niezmienne ciągi są doskonałym pomysłem (i nie jestem zaskoczony, że Java, jak sądzę niezależnie, na nowo wymyślił ten pomysł, który był już w Pythonie), chociaż nie miałbym nic przeciwko posiadaniu typu „zmiennego bufora ciągów” (i najlepiej taki, który jest łatwiejszy w użyciu niż własne „bufory łańcuchów” Javy); i nie oceniam tego ze względu na znajomość - przed studiowaniem Javy, oprócz funkcjonalnych języków programowania gdzie Myślę, że niezmienne ciągi to doskonały pomysł (i nie jestem zaskoczony, że Java, jak sądzę niezależnie, na nowo wymyślił ten pomysł, który był już w Pythonie), chociaż nie miałbym nic przeciwko posiadaniu typu „bufora ciągów zmiennych” (i najlepiej taki, który jest łatwiejszy w użyciu niż własne „bufory łańcuchów” Javy); i nie oceniam tego ze względu na znajomość - przed studiowaniem Javy, oprócz funkcjonalnych języków programowania gdzie Myślę, że niezmienne ciągi to doskonały pomysł (i nie jestem zaskoczony, że Java, jak sądzę niezależnie, na nowo wymyślił ten pomysł, który był już w Pythonie), chociaż nie miałbym nic przeciwko posiadaniu typu „bufora ciągów zmiennych” (i najlepiej taki, który jest łatwiejszy w użyciu niż własne „bufory łańcuchów” Javy); i nie oceniam tego ze względu na znajomość - przed studiowaniem Javy, oprócz funkcjonalnych języków programowania gdziewszystkie dane są niezmienne, wszystkie języki, które znałem, miały zmienne ciągi - ale kiedy po raz pierwszy zobaczyłem ideę ciągów niezmiennych w Javie (której nauczyłem się na długo zanim nauczyłem się Pythona), od razu uderzyło mnie to jako doskonałe, bardzo dobre dla semantyka referencyjna języka programowania wyższego poziomu (w przeciwieństwie do semantyki wartości, która najlepiej pasuje do języków bliższych maszynie i dalej od aplikacji, takich jak C), z łańcuchami jako pierwszorzędnej, wbudowanej (i ładnej) kluczowe) typ danych.
Ruby ma pewne zalety w elementarnej semantyce - na przykład usunięcie „list kontra krotki” Pythona niezwykle subtelne rozróżnienie. Ale przede wszystkim wynik (jak utrzymuję, z prostotą duży plus i subtelne, sprytne rozróżnienia zauważalny minus) jest przeciwny Ruby (np. Mając zarówno zamknięte, jak i półotwarte interwały, z notacjami a..b i .. .b [ktoś chce twierdzić, że to oczywiste, który jest który? -)], jest głupi - oczywiście IMHO!). Ponownie, ludzie, którzy rozważają posiadanie wielu podobnych, ale subtelnie różnych rzeczy w rdzeniu języka PLUS, a nie MINUS, oczywiście policzą te „na odwrót” od ich liczenia :-).
Nie daj się zwieść tym porównaniom, że oba języki są
bardzo dobreinaczej, pamiętajcie. Nie są. Ale jeśli poproszę o porównanie „capelli d'angelo” do „spaghettini”, po wskazaniu, że te dwa rodzaje makaronów są prawie nie do odróżnienia dla nikogo i wymienne w każdym naczyniu, które chcesz przygotować, nieuchronnie miałbym przejść do badania mikroskopowego, w jaki sposób niedostrzegalnie różnią się długości i średnice, w jaki sposób końce pasm zwężają się w jednym przypadku, a nie w drugim itd. - aby spróbować wyjaśnić, dlaczego osobiście wolałbym mieć capelli d „angelo jak makaron w jakimkolwiek bulionie, ale wolałby spaghetti jako pastasciutta niż odpowiednie sosy do tak długich cienkich form makaronów (oliwa z oliwek, mielony czosnek, mielona czerwona papryka i drobno mielone sardele, na przykład - ale jeśli pokroisz czosnek i paprykę zamiast je rozdrobnić, powinieneś wybrać bardziej dźwięczny korpus spaghetti niż cieńszą ulotność spaghetti i dobrze byłoby zrezygnować z achoview i zamiast tego dodać trochę świeżej wiosennej bazylii [ a nawet - jestem heretykiem ...! - liście mięty lekkiej ...] - w ostatniej chwili przed podaniem naczynia). Ups, przepraszam, to pokazuje, że podróżuję za granicę i chyba nie jadłem makaronu od jakiegoś czasu. Ale analogia jest nadal całkiem dobra! -) i radzę zrezygnować z achoview i zamiast tego dodać trochę świeżej wiosennej bazylii [a nawet - jestem heretykiem ...! - liście mięty lekkiej ...] - w ostatniej chwili przed podaniem naczynia). Ups, przepraszam, to pokazuje, że podróżuję za granicę i chyba nie jadłem makaronu od jakiegoś czasu. Ale analogia jest nadal całkiem dobra! -) i radzę zrezygnować z achoview i zamiast tego dodać trochę świeżej wiosennej bazylii [a nawet - jestem heretykiem ...! - liście mięty lekkiej ...] - w ostatniej chwili przed podaniem naczynia). Ups, przepraszam, to pokazuje, że podróżuję za granicę i chyba nie jadłem makaronu od jakiegoś czasu. Ale analogia jest nadal całkiem dobra! -)
Wracając do Pythona i Ruby, dochodzimy do dwóch dużych (pod względem właściwego języka - pozostawienia bibliotek i innych ważnych pomocniczych narzędzi, takich jak narzędzia i środowiska, jak osadzić / rozszerzyć każdy język itp., Poza to na razie - i tak nie miałyby zastosowania do wszystkich IMPLEMENTACJI każdego języka, np. Jython vs Classic Python są dwiema implementacjami języka Python!):
Iteratory i kody kodu Ruby kontra iteratory i generatory Pythona;
RAZEM Ruby, nieokiełznana „dynamika”, w tym możliwość „ponownego otwarcia” dowolnej istniejącej klasy, w tym wszystkich wbudowanych, i zmiany jej zachowania w czasie wykonywania - w porównaniu z ogromną, ale ograniczoną
dynamiką Pythona , która nigdy nie zmienia zachowania istniejącej klasy wbudowane i ich instancje.
Osobiście uważam 1 za obmycie (różnice są tak głębokie, że z łatwością mogłem zobaczyć, jak ludzie nienawidzą albo zbliżają się i odwracają drugie, ale na MOICH osobistych skalach plusy i minusy prawie się zwiększają); i [2] kluczowy problem - taki, który sprawia, że Ruby jest znacznie bardziej odpowiedni do „majsterkowania”, ALE Python równie odpowiedni do stosowania w dużych aplikacjach produkcyjnych. W pewnym sensie jest to zabawne, ponieważ oba języki są tak DUŻO bardziej dynamiczne niż większość innych, że ostatecznie kluczowa różnica między nimi a moim POV powinna się na tym opierać - że Ruby „idzie do jedenastu” pod tym względem (odniesienie tutaj jest oczywiście „Spinal Tap”). W RubyMOGĘ TO ZROBIĆ ! To znaczy, mogę dynamicznie zmieniać wbudowaną klasę ciągów, aby to zrobić
a = „Witaj świecie”
b = „witaj świecie”
jeśli a == b
wypisz „równe! \ n”
jeszcze
wypisz „różne! \ n”
koniec
BĘDZIE drukować „równe”. W Pythonie nie ma możliwości, aby to zrobić. Do celów metaprogramowania, implementacji eksperymentalnych ram i tym podobnych, ta niesamowita dynamiczna zdolność Ruby jest niezwykle wysoka
pociągający. ALE - jeśli mówimy o dużych aplikacjach, opracowanych przez wiele osób i utrzymywanych przez jeszcze więcej, w tym wszelkiego rodzaju bibliotek z różnych źródeł i potrzebujących wejść do produkcji na stronach klienckich ... no cóż, NIE CHCĘ język, który jest tak dynamiczny, dziękuję bardzo. Nienawidzę samego pomysłu, że niektóre biblioteki nieświadomie łamią inne, niepowiązane z sobą te, które polegają na tym, że te łańcuchy są różne - jest to rodzaj głęboko i głęboko ukrytego „kanału”, między fragmentami kodu, które WYGLĄDAJĄ osobno i MUSZĄ BYĆ osobne, co oznacza śmierć programowanie na dużą skalę. Pozwalając dowolnemu modułowi wpływać na zachowanie innych „potajemnie”,
Gdybym musiał użyć Ruby do tak dużej aplikacji, starałbym się polegać na ograniczeniach w stylu kodowania, wielu testach (do ponownego uruchomienia, gdy COKOLWIEK się zmieni - nawet tego, co powinno być całkowicie niezwiązane ...) i tym podobnych, aby zabronić korzystania z tej funkcji języka. Ale moim zdaniem NIE posiadanie tej funkcji jest jeszcze lepsze - tak jak sam Python byłby jeszcze lepszym językiem do programowania aplikacji, gdyby pewna liczba wbudowanych elementów mogła zostać „przybita”, więc WIEDZIAŁEM, że , np.
len("ciao")
ma 4 (zamiast martwić się podświadomie, czy ktoś zmienił wiązanie nazwy len
w __builtins__
module ...). Mam nadzieję, że ostatecznie Python „dopracuje” swoje wbudowane funkcje.
Problem jest jednak niewielki, ponieważ ponowne wiązanie wbudowanych poleceń jest dość przestarzałe, a także rzadką praktyką w Pythonie. W Ruby wydaje mi się to znaczące - podobnie jak zbyt potężne narzędzia
makro innych języków (takich jak, powiedzmy, Dylan), moim zdaniem, stwarzają podobne ryzyko (mam nadzieję, że Python nigdy nie otrzyma tak potężnego systemu makro, nie liczy się urok „pozwalania ludziom definiować własne, specyficzne dla domeny małe języki osadzone w samym języku” - to, IMHO, osłabiłoby wspaniałą przydatność Pythona w programowaniu aplikacji, prezentując „atrakcyjny uciążliwość” niedoszłemu majstrownikowi, który czai się w sercu każdego programisty ...).
Alex