Piękno ruby
Załóżmy taką sytuację, że jest uruchomiony jakiś program – obojętnie jaki, ale on powinien być włączony non stop, bez przerwy – dniami, tygodniami, miesiącami. Każda chwila gdy trzeba go wyłączyć to tragedia. Co zatem zrobić, jeśli chcemy wprowadzić do niego zmiany?
Na przykład. Kiedyś miałem bota IRC napisanego w PHP. Co zrobić by wprowadzić do niego zmiany? include() kolejnych plików, eval? Jeszcze gorsze rzeczy? Kiedyś miałem to rozwiązane w postaci prostego języka skryptowego opartego na XML, ale ani to było ładne, ani wygodne. No, oczywiście lepsze niż eval…
W nowym bocie, który już powstał w ruby, było to o niebo łatwiejsze. Zmiana ACL? Zmiana konfiguracji? Zmiana dowolnego miejsca w kodzie? Ależ proszę bardzo.
``load’‘ i po problemie. Wystarczy jeden plik który edytujemy w ramach potrzeb, potem tylko rehash (czyli proste: load „plik.rb”) i wszystkie zmiany zostaną wprowadzone. Można tam trzymać np. klasę która przetwarza tekst wysłany na IRC. Klasa powinna mieć statyczne metody (class Xxx \n def self.metoda \n … \n end \n end) i… tyle. Żadnego kombinowania, żadnych eval ani innych potworków. Czysto, ładnie i przyjemnie. Oczywiście inne języki zapewne też mają podobną funkcjonalność, nie mówię że nie … ale to kolejny powód dlaczego uwielbiam Ruby :)
http://docs.python.org/library/functions.html#reload ftw.
Widzisz, bo Ruby ma (niech mnie ktoś poprawi jeżeli bredzę) nad PHP te przewagę, że pozwala na modyfikowanie już istniejących klas / funkcji. W PHP niestety bez dużej ilości hackowania takie coś nie przejdzie.
Ale z drugiej strony – kto normalny robił by w PHP coś, co musi działać „dnie a nawet miesiące” :-)
Cóż, ten bot w PHP działał tygodniami, a jeśli był wyłączany to właśnie po to, by coś tam dodać. Teraz już takiego wymogu nie ma :)
I w ruby jest też o tyle fajnie, że mogę dowolnie modyfikować nawet systemowe klasy.
http://photo.nomicon.pl/qwpx1.jpg ;-)
Wiesz, sam napisałem bota IRCowego w PHP który pobierał pliki z DCC i odpowiadał pseudolosowo wybierając linijkę z pliku .log i sprawdzając czy pasuje ona do linijki, którą otrzymał używając levenshtein(). Wiesz. Można. Tylko po co. Ostatnio na DZone widziałem serwer FTP w PHP. Można …
To było tylko tak ad. stabilności php ;) dobrze napisany skrypt może działać równie dobrze jak w innych językach. Ale pisanie tego to tragedia… nawet nie ma wielkowątkowości (ruby: Thread.new{ codecodecode }). To co ma to jakaś niedorobiona proteza która i tak nie działa :)
I nie chodzi tylko o możliwości. Po prostu… owszem, można. Ale po co :)
em, tylko modyfikować klasy systemowe, niech mnie ktoś oświeci?
Teraz to ja nie rozumiem :>
Może źle się wyraziłem. Klasy wbudowane w ruby można dowolnie zmodyfikować. Można dorobić dzielenie przez zero, by zwracał 5, jeśli ktoś ma ochotę ;)
Po prostu – klasy są „otwarte”. Brakuje ci jakiejś funkcji przy operacjach tekstowych? Zamiast robić kolejną klasę, po prostu rozszerzasz string. I wtedy wszystkie obiekty tego typu „czyli dowolny napis” będą mieć taką metodę.
no to to nie jest modyfikacja zdaje się, tylko dziedziczenie
To nie jest dziedziczenie, bliżej temu do JSowych prototypów.
To jest modyfikacja. W zwykłym języku robisz dziedziczenie po string, ale co z tego – by trzeba specjalnie definiować. Tutaj „każdy napis” jest obiektem (instancją) typu String. Każda cyfra: 5, będzie instancją obiektu Fixnum. I tak dalej i tak dalej. Możesz sobie to wszystko dowolnie przerabiać, wedle gustu. Może to byc przydatne (np. do wyliczania fib można zrobić zwykła funkcję, lub rozszerzyć Fixnum o taką metodę – wtedy wystarczy np. 5.fib => wynik)
hmm, fajne. chociaż może mieć i wady – dla mnie klasa systemowa powinna być definiowana wszędzie w taki sam sposób, by zapewnić maksymalną przenośność, ale cóż, może to kwestia drugorzędna tak na prawdę
Jak gdzieśtam wysyłasz swój kod, to przecież wystarczy by miał też to zapisane. I wtedy na maszynie X będzie tak samo jak u ciebie.
>>> int.add = lambda(a, b): 5
Traceback (most recent call last):
File „<stdin>”, line 1, in <module>
TypeError: can’t set attributes of built-in/extension type ‘int’
No nie da się w tym akurat przypadku…
Ano. Podmienianie kodu w locie (w jakikolwiek sposób) jest fajne. Warto zdecydowac sie na jakis system modularny, z wersjonowaniem itp.
To realny problem z hot-patchingiem jaki widzialem pare razy w pracy — ludzie nie byli do konca pewni co tak naprawde biega na poszczegolnych serwerach, gdzie ktore latki trzeba jeszcze nalozyc :)
Troche tylko boje sie, ze tak jak PHP przez swoja prostote dal nam w prezencie setki badziewnych, zle napisanych aplikacji, tak Ruby przez swoja elastycznosc da nam setki zle zaprojektowanych aplikacji. Elastycznosc jest super, ale trzeba z niej korzystac z glowa, zwlaszcza w projektach, ktore maja byc utrzymywane przez wiecej niz 1 programiste, lub maja byc udostepniane jako biblioteki (wtedy licza sie wzorce, konwencje i przewidywalnosc).
mam wrażenie że nie tylko ruby to potrafi.
Btw, nie wiem skąd ta moda na „porównywanie się” z php. To tak jak by lekkoatleci porównywali się do kalek bez nóg :> „oo, patrzcie on nie ma nóg i nie biega a ja mam i zasuwam, ha!”
Btw, ruby jest cudny ale z tego co pamiętam (poprawcie jeśli się mylę) trzeba też lubić dużo klepać w C, Ferret afair składał się z 10 klocków kodu w Rubym i 60 klocków w C :> Osobiście lubię C, ale znałem sporo osób które uciekały od tego języka.
Och, dzieci, o Lispie pewnie nie słyszeliście, prawda?
Nie dziadku. Opowiedz nam o Lispie i indianinach!
:D Ja po prostu padam, jak czytam takie teksty:
„Żadnego kombinowania, żadnych eval ani innych potworków.”
Te wszystkie nifty rzeczy w Ruby to nieeleganckie przeniesienie idei z Lispu.
Eh, to się juz robi męczące. Dlaczego wszystko jest tylko badziewną kalką Lisp? Co może być lepszego niż „load ‘plik.rb’”? Wklejanie kilkuset linii kodu nie jest ładniejsze, w żaden sposób. A tak kiedyś już argumentowałeś wyższość Lisp…
W Common Lispie masz REPL i całe środowisko jest interaktywne, nie masz podziału na read, compile i run-time. Nie masz żadnego load, po prostu wczytujesz luzem funkcje, które chcesz podmienić. Ba, masz dostęp do wnętrza środowiska w czasie działania – taki permanentny debugger.
Ale, nie zrozumiesz, dopóki sam nie zobaczysz. W skrócie – też kiedyś pisałem bota na IRCa w CL i jak edytowałem jakąś funkcję to po prostu wciskałem C-c C-c, Emacs wysyłał ją systemu Lispowego, który ją kompilował i wczytywał i wszystko było podmienione.
Czyli jest dokładnie jak w ruby, gdzie można robić w ten sam sposób. Możesz sobie dorabiać metody do klas „wewnętrznych”, co juz opisałem wyżej. Więc nie widzę tu żadnej wyższości, poza tym że w ruby jest o wiele przyjemniejsza składnia. Load po prostu ładuje zmiany z pliku, ale równie dobrze możesz w inny sposób (np z IRB) wrzucać zmiany.
Tak samo, to znaczy jak to wygląda dokładnie z Twojej perspektywy? A bota odpalasz z irb? Bo jeżeli to jest tak samo, to to też całkowicie zerżnęli z Lispu. Ruby to Lisp z zepsutą składnią.
A w CL coś takiego jak dorabianie metod do klas wewnętrznych jest czymś bez sensu, skoro obiektówka ma multimetody… A o składni to lepiej się nie wypowiadaj, bo pewnie nawet nie wiesz, dlaczego składnia jest taka, jaka jest :)
Bota nie odpalam z irb, bo mi zwyczajnie wygodniej wrzucać zmiany do pliku w katalogu dropbox, a potem !rehash wysyłać do bota. Mówię – mogę odpalić z IRB i w locie definiować wszystko. Tylko że chyba lepiej mieć zmiany zapisane w pliku?
Tak, nie wiem dlaczego ktoś sobie wymyślił by składnia była niewygodna, naciągana i denerwująca. Niespecjalnie mnie to interesuje, wybacz. Widzę tak, że napisanie czegoś w ruby to kilka chwil, w lisp to nieustanne klepanie.
Lisp z zepsutą składnią? A może jednak to język który wziął najlepsze z lisp (i innych języków), zostawiając całą resztę w latach 60? Cały bloat, całe bzdurne założenia?
Już kiedyś to mówiłem – to, że język jest prosty (składniowo) nie znaczy że jest dobry.
„Tak, nie wiem dlaczego ktoś sobie wymyślił by składnia była niewygodna, naciągana i denerwująca.”
McCarthy na początku wymyślił do oryginalnego LISPu M-wyrażenia, które wyglądały podobnie do aktualnie spotykanych konstrukcji. S-wyrażenia okazały się być czytelniejsze, wygodniejsze i bardziej funkcjonalne.
„Widzę tak, że napisanie czegoś w ruby to kilka chwil, w lisp to nieustanne klepanie.”
Zabawne, że nigdy nic nie pisałeś w Lispie, a wysuwasz takie tezy.
„Lisp z zepsutą składnią? A może jednak to język który wziął najlepsze z lisp (i innych języków), zostawiając całą resztę w latach 60? Cały bloat, całe bzdurne założenia?”
Lolwat, jakie bzdurne założenia? Lisp od zawsze miał to, co te nowoczesne języki dopiero wprowadzają, vide
http://dodek.jogger.pl/2008/10/26/co-sprawilo-ze-lisp-jest-inny/ .
„Już kiedyś to mówiłem – to, że język jest prosty (składniowo) nie znaczy że jest dobry.”
Składnia jest prosta po to, żeby można było stosować makra. Ale, Ty oczywiście nie wiesz, czym są makra, więc nic dziwnego, że to dla Ciebie żaden argument.
I na koniec cytacik: “Some may say Ruby is a bad rip-off of Lisp or Smalltalk, and I admit that. But it is nicer to ordinary people.” – Matz, LL2 „
Ja nie mówię że sama prostota jest zła. Ale dążenie do idealnie prostego języka, kosztem wygody – to bzdura.
To, że język wprowadził pewne opcje jako pierwszy (a teraz mają je wszystkie) czyni z niego coś, co nadal jest wartościowe? Samo w sobie? Mimo tego że w dzisiejszych czasach nie oferuje nic więcej niż inne języki (a może być zwyczajnie niewygodny)? Mówię tu ogólnie, nie tylko o Lisp.
Nie pisałem? Ok. Ale ty pisałeś. I odpowiednik moich 1-linijkowców to były dziesiątki linii kodu :>
Ad cytat: Tak, i co? Chyba o to chodzi, by język był wygodny i prosty? O to chodzi, by wszystko dało się szybko zrobić, bez żadnych problemów?
Poza tym mi ruby bardziej przypomina perla, ale ok.
„Ale dążenie do idealnie prostego języka, kosztem wygody – to bzdura.”
Ale przecież nie to jest celem. Naprawdę nie wiem, skąd Ci to przyszło do głowy.
I kosztem jakiej wygody? Dla mnie wszystko jest wygodniejsze niż w dowolnym innym języku.
„To, że język wprowadził pewne opcje jako pierwszy (a teraz mają je wszystkie) czyni z niego coś, co nadal jest wartościowe?”
Skoro inni ciągle od niego zrzynają...?
„Mimo tego że w dzisiejszych czasach nie oferuje nic więcej niż inne języki (a może być zwyczajnie niewygodny)?”
Bzdurra. Mówiłem już o makrach, tylko zdawałeś się pominąć to wzrokiem. Jak Ci zwykłe makra nie wystarczają, to masz makra czytnika – w którym innym języku masz kontrolę nad tym, jak parser parsuje kod? Mówiłem o multimetodach – cała obiektówka w CL jest porównywalna tylko ze Smalltalkiem. Nie wspominam już o takich rzeczach jak multiple-values-bind, Turing-kompletnym minijęzyku do definiowania pętli, czy Turing-kompletnym języku format-stringów. A mówienie, że coś jest niewygodne przez osobę, która nigdy tego nie używała, jest kuriozalne.
„Nie pisałem? Ok. Ale ty pisałeś. I odpowiednik moich 1-linijkowców to były dziesiątki linii kodu :>”
Podaj przykład. Owszem, kod w Ruby może być niekiedy nieco krótszy ze względu na dużo szerzej obecny cukier syntaktyczny, ale nigdy nie jest to różnica o czynnik kilkadziesiąt. Taki kod w APLu czy w J i tak będzie krótszy od wszystkiego, co napiszesz w Ruby, ale to jeszcze nie wszystko.
A jakbym chciał mieć cukier syntaktyczny, to bym sobie zmodyfikował parser. Czy w Twoim języku to możliwe?
„Ad cytat: Tak, i co? Chyba o to chodzi, by język był wygodny i prosty? „
Myślę, że „ordinary people” to w tym kontekście miało znaczyć „ludzie, którzy nie mają jeszcze zbyt dużego doświadczenia”. Pytasz „i co?”. I to, że na potwierdzenie mojej tezy, że Ruby jest zerżnięte z Lispu mam słowa samego autora. Próbuj się teraz z tym kłócić.
„O to chodzi, by wszystko dało się szybko zrobić, bez żadnych problemów?”
A tutaj z kolei widzę jakąś dziwną sugestię, jakobym ja w Lispie wszystko robił powoli i to jeszcze z problemami. Niestety, nie trafiłeś.
„Poza tym mi ruby bardziej przypomina perla, ale ok.”
Nic dziwnego, skoro nigdy Lispu nie widziałeś.
Dodek, ciekawi mnie czemu się tak ciskasz, to jest wręcz żenujące. Jak komuś się coś nie podoba to nie widzę powodu żeby mu tym wymachiwać przed nosem…
Szymon, ja jestem jeszcze neofitą, a i poflejmować lubię :) A ciskam się, bo taki delikwent pisze coś, chociaż nawet tego nigdy nie używał, a potem inni czytają to i wyrabiają sobie taką samą opinię.
hm.. też miałem jak Ty i pewnie mi jeszcze całkiem nie przeszło.. a zaczęło przechodzić od czasu jak się zacząłem bawić w studiowanie informatyki ;p
Btw, jeśli ktoś jest aż takim cymbałem że wyrabia sobie opinię na podstawie dyrdmałów które tu produkujemy to kij z nim…
Btw, wiele z tego co Lisp oferuje nie jest ludziom koniecznie potrzebne, jako że zajmują się kodowaniem różnych banałów. Moje ambicje nawet takich banałów nie sięgają więc staram się nie czepiać bliźnich, choć nie zawsze mi to wychodzi ;p
„A jakbym chciał mieć cukier syntaktyczny, to bym sobie zmodyfikował parser. Czy w Twoim języku to możliwe?” oczywiście że jest. W Rubym i w każdym innym :> Jest jeszcze kwestia nakładów, ale to raczej jest potrzebne projektom które mają budżet.. więc wielkiego problemu nie ma. Zwróć uwagę na C++ tzn. moc/QT.
Zastosowania gdzie lisp ma całkowitą przewagę nad Rubym i tym podobnymi są ważne ale też rzadkie i większość ludzi nawet nie musi o nich wiedzieć, o wchodzeniu w szczegóły nie wspominając. Choćby dlatego że nie jest im to do niczego potrzebne.
„w którym innym języku masz kontrolę nad tym, jak parser parsuje kod?” PL/I ;)
„Btw, jeśli ktoś jest aż takim cymbałem że wyrabia sobie opinię na podstawie dyrdmałów które tu produkujemy to kij z nim…”
Zdziwiłbyś się, ile jest takich ludzi, co poczytają coś tu, coś tam i są wielkimi specjalistami :) Takie zajęcie ma nawet specjalną nazwę – „konsultant” :)
„Zwróć uwagę na C++ tzn. moc/QT”
Hm, w sumie to niby co innego, bo to generowanie dodatkowego kodu skryptami, ale efekt podobny, więc who cares :) Można jeszcze mówić, że CL ma to w standardzie, ale tam…
„„w którym innym języku masz kontrolę nad tym, jak parser parsuje kod?” PL/I ;)”
pomyślałem, że w życiu nie widziałem w tym kawałka kodu -> zajrzałem na wikipedię -> żałowałem
Mysle ze taka dyskusja nie ma sensu. pokaz co ma lisp a ruby nie (konkret, nie rzucanie nazwami) lub co mozna tam zrobic lepiej (ladniej, szybciej, wydajniej). moze tak: jak w lisp zbadac kod (profiler), jak mozna czesc kodu zastapic kodem w innym jezyku (np C, dla wydajnosci). jak zrobic wielowatkowy kod? jak wyglada sprawa dodatkowych bibliotek- menedzer ich, instalacja, ilosc dostepnych.
btw. a wiec wyrobiles sobie opinie o pl/1 na podstawie wpisu na wiki, bez doglebnego poznania jezyka?
Myślę, że zalety i wady języków najlepiej weryfikuje praktyka — chyba nikt nie będzie zaprzeczał, że łatwiej zrobić pieniądze na pisaniu czegoś w Rubym niż lispie (tak naprawdę w moim otoczeniu jedyne niehobbystyczne zastosowania lispa jakie widzę w mojej okolicy to algotrading — bardzo dobrze płatne, ale tak niszowe, że nie można w ogóle przebierać w zleceniach (już chyba na erlanga jest większe wzięcie, serio)
„btw. a wiec wyrobiles sobie opinie o pl/1 na podstawie wpisu na wiki, bez doglebnego poznania jezyka?”
Historyczny język podobny do COBOLa i nieco FORTRANa? Widziałem te dwa – jeżeli cokolwiek jest do nich choć trochę podobne, to ja dziękuje.
„jak w lisp zbadac kod (profiler)”
W SBCL masz dwa profilery:
http://www.sbcl.org/manual/Statistical-Profiler.html i http://www.sbcl.org/manual/Deterministic-Profiler.html
„jak mozna czesc kodu zastapic kodem w innym jezyku (np C, dla wydajnosci).”
http://dodek.jogger.pl/2008/10/21/common-lisp-a-biblioteki-dzielone/
Aczkolwiek niewiele jest rzeczy, w których wydajność CL jest niewystarczająca – http://shootout.alioth.debian.org/u32q/benchmark.php?test=all&lang=all&box=1 porównaj sobie, na którym miejscu stoi Lisp, a na którym Ruby.
„jak zrobic wielowatkowy kod?”
http://www.sbcl.org/manual/Threading.html#Threading
W skrócie sprowadza się to do (sb-thread:make-thread #‘funkcja-odpalana-w-wątku), a jak są zrobione mutexy i semafory, to sobie poczytasz.
„jak wyglada sprawa dodatkowych bibliotek- menedzer ich, instalacja, ilosc dostepnych. „
Jest coś na kształt CPAN z Perla – nazywa się asdf-install. Wpisujesz w replu (asdf-install:install :lispbuilder-sdl) i po paru minutach masz zainstalowaną wrapper na SDL.
Ile jest bibliotek? Sporo, ale niestety za mało. Społeczność Lispu jest mała i brakuje do tego ludzi. Jeżeli jednak jakaś funkcjonalność jest oferowana przez bibliotekę w C, to wystarczy zrobić wrapper w CFFI – vide podany wyżej przeze mnie link do wpisu na moim blogu.
Ja z kolei nie odbiję piłeczki, bo to nie ma sensu. Przeczytaj na przykład „On Lisp” Paula Grahama, „Structure and Interpretation of Computer Programs” autorstwa Abelson/Sussman/Sussman i ewentualnie „The Art of the Metaobject Protocol” autorstwa Kiczales/des Rivieres/Bobrow, tam powiedzą Ci wszystko więcej i lepiej.
„Społeczność Lispu jest mała i brakuje do tego ludzi.”
No właśnie.
„Jeżeli jednak jakaś funkcjonalność jest oferowana przez bibliotekę w C, to wystarczy zrobić wrapper w CFFI”
Większość ludzi woli jednak użyć narzędzi, w których nie będą musieli sobie sami jeszcze wrapperów na biblioteki w C pisać. To zawsze dodatkowy koszt. Potem ktoś aktualizuję tę bibliotekę w C, ja muszę aktualizować wrapper… nie lepiej się skoncentrować na pisaniu właściwej aplikacji?
W praktyce nie wygrywa rozwiązanie „najlepsze” (technicznie, ideologicznie, whatever), ale „najszybsze” (gdzie szybkość się też definiuje na X sposobów).
BTW, Lisp(owate) są wolniejsze nawet od .NET i Javy? Wow. Do tej pory myślałem, że lisp wyciąga „near-C performance”.
A że ruby jest powolny, to żadna tajemnica. Najszybszym znanym obecnie interpreterem Ruby’ego jest zdaje się interpreter napisany na jvm (czyli Ruby w Javie). Ale znaczy to też, że pewnie w przyszłości Ruby się rozkręci (bo ma kupę miejsca na poprawę, podczas gdy Lisp… cóż, wiele się już nie zmieni).
ale widzisz, nadal nie podales konkretnego przykladu gdzie lisp jest lepszy. ja to widze ze dla roznych przypadkow jezyki sa rownie wygodne, lub wygodniejszy jest ruby.
nie chodzilo mi o ladowanie bibliotek, bo to nawet php potrafi. chodzi mi o bezposrednie wstawienie kodu C do kodu ruby. zobacz jak dziala inline.
a jak polaczysz inline z builderem to masz taki efekt, ze kod ruby przetlumaczy na C a potem skompiluje i uruchomi.
a pomyslales kiedys ze mala ilosc programistow lisp ma jakis powod? wszystkie jezyki juz maja to co lisp (nawet niech bedzie ze lisp mial pierwszy- co z tego) wiec ludzie sie juz nim nie zajmuja- malo wygodny? denerwujacy? sztywny?
odśledzam wątek jako że nie lubię patrzeć jak się kopie leżącego, lisp wylądował na śmietniku historii razem z cobolem, algolem i pl/1 — niedawno został ubity w miejscu w którym się narodził i rozwinął (MIT). Lisp był forsowany przez różne wybitne osobistości, przez korporacje z kosmicznym kapitałem, przez agencje rządowe — wszystko to bez efektu. To o czymś świadczy :> (konkretniej o tym że nawiasy wąsiaste są lepsze od okrągłych).
Dodek, to co Ty podajesz z wątkami to nie jest opowiedź bo dotyczy jednej z implementacji. Na innej nie pójdzie. Common Lisp nie ma w standardzie ani wątków, ani unikodu, ani nawet socketów. Jako taki jest całkowicie bezużyteczny.
„Potem ktoś aktualizuję tę bibliotekę w C, ja muszę aktualizować wrapper… nie lepiej się skoncentrować na pisaniu właściwej aplikacji?”
Rzadko jest tak, że aktualizacja biblioteki psuje kompatybilność wsteczną.
„BTW, Lisp(owate) są wolniejsze nawet od .NET i Javy? Wow. Do tej pory myślałem, że lisp wyciąga „near-C performance”.”
dotnet i java wyciągają near-C performance, szkod, że o tym nie wiedziałeś.
„podczas gdy Lisp… cóż, wiele się już nie zmieni)”
Gadanie bez pokrycia w argumentach.
„chodzi mi o bezposrednie wstawienie kodu C do kodu ruby. zobacz jak dziala inline.”
Zwykle nie ma potrzeby, bo pod względem operacji matematycznych CL nie ustępuje C, ale to da się zrobić.
„nie chodzilo mi o ladowanie bibliotek, bo to nawet php potrafi.”
PHP potrafi załadować funkcje z DOWOLNEJ biblioteki dzielonej? Ciekawe, nie wiedziałem.
„a jak polaczysz inline z builderem to masz taki efekt, ze kod ruby przetlumaczy na C a potem skompiluje i uruchomi.”
CL jest zwykle od razu kompilowany do maszynowego.
„a pomyslales kiedys ze mala ilosc programistow lisp ma jakis powod?”
Wiesz co? Naprawdę mnie to zastanawia i mogę wymienić jedynie niedostateczną ilość bibliotek. Wielu ludzi jednak, tak jak Ty, ma wyrobioną opinię, chociaż nigdy go tak naprawdę nie używało.
„Lisp był forsowany przez różne wybitne osobistości, przez korporacje z kosmicznym kapitałem, przez agencje rządowe — wszystko to bez efektu. To o czymś świadczy :>”
Bez przesady :) To, dlaczego Lisp się nie przyjął na początku, jest oczywiste. A czy był forsowany przez korporacje? Nic o tym nie wiem, więc raczej kiepsko był forsowany. Wybitnych osobistości też zbyt wiele go nie forsowało.
„Dodek, to co Ty podajesz z wątkami to nie jest opowiedź bo dotyczy jednej z implementacji. Na innej nie pójdzie. Common Lisp nie ma w standardzie ani wątków, ani unikodu, ani nawet socketów. Jako taki jest całkowicie bezużyteczny.”
C, C++ też nie mają wątków ani socketów, a jakoś się trzymają. To nie jest kluczową kwestią. Zresztą, masz implementation-independent bordeaux-thread, masz babel, masz usocket…
Ależ zrozum, nikt LISPowi funkcji nie odbiera. Po prostu w moim wpisie o łatwości wykonania zadania X w ruby, ty piszesz że w LISP jest łatwiej, lepiej itd. Ba, twierdzisz że cały ruby to tylko zepsuty LISP. Teraz to poprzyj przykładami, które obrazują wyższość LISP nad ruby. Ja twierdzę że jest zgoła odwrotnie, zatem z chęcią odpiszę jak dany problem rozwiązać w ruby.
„Rzadko jest tak, że aktualizacja biblioteki psuje kompatybilność wsteczną.”
Super. A jak chcę użyć nowej funkcjonalności?
Co do tego, że w Lispie się nic nie zmieni — serio myślisz, że będzie jakiś przełom i nagle lisp wyskoczy z czymś, co odmieni jego los?
„Wiesz co? Naprawdę mnie to zastanawia i mogę wymienić jedynie niedostateczną ilość bibliotek.”
Ja mogę wymienić jeszcze nieprzyjemną składnię i nadmiar nawiasów (to rzecz gustu). No i fakt, że języki funkcyjne się średnio przyjmują w „ogólnym” IT, bo są zbyt specyficzne.
Po pierwsze, nie myl LISPu z Lispem.
Może na początek system obiektowy CL. Zamiast prostego dispatchingu metody na typ pierwszego argumentu (tj. tak jak w C++, Pythonie czy Ruby) masz multi-dispatch na typy wszystkich argumentów. Klasy są modyfikowalnymi obiektami, masz system metaklas, możliwość modyfikowania sposobu alokacji obiektu, sposobu wybierania metody do wywołania…
Skoro już o metodach mowa, to masz na przykład metody :before, :after czy :around, pozwalające na transparentne wywołanie dodatkowych metod przed lub po innych metodach. Praktyczne zastosowanie? Powiedzmy, że tworzysz system rysujący. Aby to zrobić, specjalizujesz metodę paint dla każdego obiektu dziedziczącego z klasy shape. Żeby nie pisać wielokrotnie tego samego kodu, ogólnie dla obiektów klasy shape, definiujesz metody paint :before i paint :after, które są odpowiedzialne za ustawienie pędzla i transformację układu współrzędnych.
Tworząc ten system dalej stwierdzasz, że często korzystasz z transformacji liniowych układu współrzędnych. Piszesz więc specjalne makro, które modyfikuje składnię języka tworząc nową konstrukcję ułatwiającą pisanie. Dla przykładu – transformacja układu do punktu (600,100) i rysowanie pod kątem 45 stopni może wyglądać tak (bez transformacji byłby to trójkąt o wierzchołkach w (0, 10), (100, 200), (-100. 200)):
(with-transformation (:pos (v 600 100) :angle 45) (draw-polygon* (list (v 00 10) (v 100 200) (v -100 200))))
Dalej. Piszesz na przykład klasę służącą za kontener. Chciałbyś mieć do tego specjalną składnię. Piszesz więc kilkulinijkowe read-macro, które modyfikuje parser, który od tej pory wczytuje Ci #Z(1 2 3 4 5) jako obiekt Twojej klasy kontenerowej.
Z mało ważnych rzeczy masz na przykład złożone (Turing-kompletne) format-stringi, taki przykład:
CL-USER> (format nil „~R,#; and ~}” ‘(1 2 3 4 5))
=> „one, two, three, four, and five, „
Podjęzyk do definiowania pętli (przy okazji ułamki zwykłe jako typ liczbowy)
<pre>
CL-USER> (loop for i from 1/10 to 1 by 1/10
when (evenp (numerator i))
collect i into even-numerators
collect (expt i 2) into squares
finally (return (values even-numerators squares)))
(2/5 4/5)
(1/100 1/25 9/100 4/25 1/4 9/25 49/100 16/25 81/100 1)
</pre>
W gruncie rzeczy Ruby implementuje, co przyznaje sam Matz, wiele fajnych rzeczy z na przykład CL, ale traci dużo na wydajności, poza tym psuje składnię uniemożliwiając makra.
Takie przerzucanie się przykładami nie ma większego sensu, po prostu przeczytaj „On Lisp” Paula Grahama, jest do ściągnięcia za darmo z jego strony.
PS: Kod się psuje u Ciebie w komentarzach, format string wygląda u mnie zupełnie inaczej.
Ale w normalnym wypadku takie rzeczy, jak zmiana sposobu wyboru metody do wywołania nie ma znaczenia dla programisty (może wręcz szkodzić jeśli potrzebujesz konwencji na których wszyscy członkowie projektu mogą „w ciemno” polegać).
Rzeczy takie jak :before czy :around są i owszem, fajne — większość systemów ACL jakie robiłem np. w Javie używała tego (AOP).
Przykład z transformacją nie urzeka mnie jakoś bardziej, niż proste „draw(transform(coords))” czy dorobienie metody drawTransformed() obok draw();
Mamy masę naprawdę fajnych języków do wyboru, a Lisp nie wypada na ich tle wcale tak super.
No nie powiem, te przykłady są interesujące, szczególnie te :after i :before… hmm.
Tylko dwie uwagi: – Naprawdę uważasz że kod dot. ułamków zwykłych jest dobry, czytelny i wygodny? – W ruby nadal możesz stosować makra. proc/yield.
Aaa co do format… zastanawiam się komu się chciało to implementować :o ma obsługę locale?
„Naprawdę uważasz że kod dot. ułamków zwykłych jest dobry, czytelny i wygodny?”
Jest, tylko tutaj w komentarzach wszelkie wcięcia i znaki nowej linii znikają.
http://paste.lisp.org/display/81035#1
„W ruby nadal możesz stosować makra. proc/yield.”
Ale to nie są takie makra jak Lispowe.
Przykład: http://paste.lisp.org/display/81035 Możesz zrobić coś takiego w Ruby?
„Aaa co do format… zastanawiam się komu się chciało to implementować :o”
Więc co, za dobre?
„ma obsługę locale?”
Standard ANSI CL jest z 1984, więc sam sobie odpowiedz.
http://wklej.org/id/97808/ – też się da…
Tu akurat przykład generuje HTML4, nie mam patcha na xhtml, bo nie używam tego stylu.
ech dzieci dzieci, już sie flejmłarów zachciało... jeśli chodzi o aktualizację kodu live, czyli na żyjącym organizmie to erlang jest najlepszy, jako język stworzony z myślą o zastosowaniach telekomunikacyjnych, musi on zapewnić bezawaryjne ładowanie kodu w locie, w połączeniu z jego skalowalnością i odpornością na błędy [fault tolerant] czyni to z erlanga język niemal idealny;-) chociaż sam wolę ruby, żeby nie było:)