Strona używa cookies (ciasteczek). Dowiedz się więcej o celu ich używania i zmianach ustawień. Korzystając ze strony wyrażasz zgodę na używanie cookies, zgodnie z aktualnymi ustawieniami przeglądarki.    X

Scala — pierwsze kroki cz.5

Język Scala oprócz tego, że jest językiem o funkcyjnym paradygmacie programowania, to również jest w pełni obiektowa. Istnienie metod i klas statycznych w Javie powoduje, że puryści językowi twierdzą, że nie jest ona w prawdziwym obiektowym językiem programowania. Scala rozwiązała ten problem wprowadzając obiekty, które są czymś zbliżonym do wzorca singletonu. Każda klasa może posiadać odpowiadający jej obiekt o identycznej nazwie co klasa, posiadający tylko jedną wersję powstającą przy uruchamianiu programu. Innym problemem, który udało się rozwiązać jest dziedziczenie wielobazowe, dostępne w Javie tylko w szczątkowej formie interfejsów. W Scali mamy Traits czyli instancje podobne do klas, ale różniące się tym od nich, że nie posiadają konstruktora z parametrem. Klasa może dziedziczyć po jednej zwykłej klasie i równocześnie po wielu Traits. Definiowanie klas ma również pewne drobne ułatwienia jak chociażby fakt, że ciało klasy jest równocześnie jego konstruktorem.

Klasy

Przykładowa definicja klasy: class Licznik { println("Konstruktor") private var suma = 0 def +=(x: Int) = suma += x def -=(x: Int) = suma -= x def ? = suma.toString } Kod napisany w nawiasach klamrowych, jeśli nie jest definicją metody, należy do konstruktora, co możemy sprawdzić tworząc instancję klasy:val l = new LicznikJak widać konstrukcja instancji wymaga słowa kluczowego new, a nawiasy po nazwie klasy są opcjonalne. Słowo Konstruktor zostanie wydrukowane na standardowe wyjście zaraz po utworzeniu instancji klasy Licznik.
Teraz możemy wywoływać metody klasy: l.+=(234) l.? l -= 12 I ? Jak widać możemy wywoływać metody klasycznie z kropkami i nawiasami lub bez nich oddzielając obiekt, nazwę metody i parametr spacją. (Dla metod z kilkoma parametrami muszą być nawiasy). W przypadku metody oznaczonej znakiem zapytania nie można wywołać jej z nawiasami, ponieważ nie zostały one użyte w czasie jej definicji. Definicje klas zostały tutaj napisane w skróconej formie, której używać możemy tylko gdy definicja metody ma tylko jedną linijkę. W przeciwnym przypadku niezbędne są jeszcze nawiasy klamrowe. Podobnie jak w Javie mamy słowa kluczowe private i protected, zaś wszystko co nie jest oznaczone jednym z tych słów uznane jest za publiczne. Aby dodać dodatkowy konstruktor piszemy definicję nowej metody klasy o nazwie this.

Dziedziczenie

class LicznikNazwany(nazwa:String) extends Licznik { override def ? = nazwa + ": " + super.?.toString } Tak jak w Javie możemy dziedziczyć tylko po jednej klasie. Robimy to używając słowa kluczowego extends. Tym razem nasz konstruktor przyjmuje parametr, więc musimy utworzyć instancję tej klasy dodając jej nazwę:val ln = new LicznikNazwany("Licznik1")Próbujemy jak działa klasa:ln += 34 ln ? Po przetestowaniu kodu zobaczymy, że różnica w porównaniu do klasy bazowej polega na dodawaniu do każdego wydruku nazwy licznika. Zauważmy, że w klasie dziecka przy nadpisywaniu metody ? użyto słowa kluczowego override. Jest ono obowiązkowe w takiej sytuacji. Słowo super pozwala upewnić się, że dana metoda jest wywoływana w klasie rodzica.

Obiekty

Obiekt jest czymś podobnym do singletonu. Ma identyczną nazwę z klasą i musi być zdefiniowany w tym samym pliku co dana klasa. Ma on dostęp do wszystkich składowych pól prywatnych klasy. Sam jest dostępny tak jak w Javie obiekt statyczny.

Utwórzmy obiekt towarzyszący naszej klasie:object LicznikNazwany { var licznik = 0; def apply() = { licznik += 1 new LicznikNazwany("Licznik: " + licznik.toString) } }

Możemy dopisać na początku deklaracji klasy LicznikNazwany słowo private, przez co nie da się utworzyć samodzielnie instancji tej klasy. Instancje tej klasy będziemy otrzymywać z naszego stowarzyszonego obiektu, dzięki metodzie apply. Metoda ta jest sposobem na przeładowanie operatora (). Dzięki temu możemy utworzyć instancje klasy LicznikNazwany jako:val licz = LicznikNazwany() Nie jest to wywołanie konstruktora, tylko wywołanie na obiekcie LicznikNazwany metody apply. W taki sposób, jak niektórzy zapewne już zauważyli, utworzyliśmy prostą wersję wzorca projektowego fabryka.

Traits

Są one podobne do klas. Jednak nie mogą posiadać konstruktora. Możemy dziedziczyć po wielu traits bez ograniczeń (używając wiele razy słowa with). Przykładowe wykorzystanie:trait Filozof { def filozofia() { println("Używam RAM, więc jestem") } } abstract class Zwierze { def glos() } class Pies extends Zwierze with Filozof { def glos() {println("Hau hau!")} } val pies = new Pies pies.glos pies.filozofia Traits dają nieco większe możliwości niż interfejsy w Javie, ponieważ mogą dostarczać już gotowy kod, tak jak w tym przypadku Filozof dostarcza metodę filozofia. Interfejsy Javy są w Scali traktowane jako traits z abstrakcyjnymi definicjami metod.
W definicji metody glos() klasy Pies nie musimy używać słowa override, ponieważ definicja tej metody w klasie rodzica jest abstrakcyjna. Abstrakcyjna klasa może mieć również nieabstrakcyjne definicje metod.

Możliwe jest dodawanie traits nie w definicji klasy, tylko przy tworzeniu instancji klasy:class Kot extends Zwierze { def glos() {println("Miau!")} } val kot = new Kot kot.glos val kotFilozof = new Kot with Filozof kotFilozof.filozofia Zatem możemy wytworzyć obiekty o różnym zachowaniu. Daje to dużo możliwości, ale warto jednak stosować umiar.

Przykład

Kod do tej pory przedstawiony jest bardzo prosty i nie oddaje w jaki sposób należy korzystać z obiektowości w języku funkcyjnym. Znacznie lepiej oddaje to przykład kodu jaki możemy znaleźć w "Programming in Scala", której współautorem jest twórca Scali Odersky:class Ulamek(licz: Int, mian: Int) { require( mian != 0) private val dziel = NWD(licz.abs, mian.abs) val li = licz / dziel val mi = mian / dziel def this(licz: Int) = this(licz, 1) def +(ulam: Ulamek): Ulamek = new Ulamek( li * ulam.mi + ulam.li * li, mi * ulam.mi ) def +(i: Int): Ulamek = new Ulamek(licz + i * mi, mi) def -(ulam: Ulamek): Ulamek = new Ulamek( li * ulam.mi - ulam.li * li, mi * ulam.mi ) def -(i: Int): Ulamek = new Ulamek(licz - i * mi, mi) def *(ulam: Ulamek): Ulamek = new Ulamek(li * ulam.li, mi * ulam.mi) def *(i: Int): Ulamek = new Ulamek(li * i, mi) def /(ulam: Ulamek): Ulamek = new Ulamek(li * ulam.mi, mi * ulam.li) def /(i: Int): Ulamek = new Ulamek(li, mi * i) override def toString = li +"/"+ mi def NWD(a: Int, b: Int): Int = if(b == 0) a else NWD(b, a % b) }Kod ten realizuje ułamek zwykły (może być niewłaściwy) o całkowitym liczniku i mianowniku. Typowym zachowaniem dla stylu funkcyjnego jest brak metod w klasie, które mutowałyby samą siebie. Pola klasy są niezmienne (oznaczone jako val). Zdefiniowane są jako publiczne, ale dzięki niemutowalności nie ma potrzeby pisania geterów i seterów. Każda operacja na ułamkach powoduje powstanie nowej wartości. Taki kod dobrze się również sprawdza w przypadku programowania wielowątkowego, nie trzeba się martwić o synchronizację, przekazujemy między wątkami gotową instancję klasy.
Polecenie require sprawdza warunek rzucając wyjątkiem w razie zerowego mianownika. Innym ciekawym udogodnieniem z jakim mamy do czynienia jest tail recursion (rekurancja ogonkowa) i zdolność kompilatora do zamiany jej na iterację. Metoda NWD obliczająca największy wspólny dzielnik jest napisana jako rekurencja, ale tak, że funkcja po zakończeniu nie musi wracać do poprzedniego wywołania w celu obliczenia wartości. Taką rekurencję kompilator Scali automatycznie zamienia w kodzie bajtowym na zwykłą iterację, dzięki czemu jest ona wydajna i nie zajmuje dużo miejsca w pamięci.
Korzystanie z klasy Ulamek może wyglądać następująco:val x = new Ulamek(2, 3) val y = x * x + 1 val z = y / 4 Możemy dodać do niego liczbę typu Int, jednak problemem może być fakt, że nie możemy wykonać np. operacji: val u = 2 + x Problem ten można rozwiązać używając implicit conversion: implicit def intNaUlam(x: Int) = new Ulamek(x)Jeśli spróbujemy teraz dodać do liczby typu Int ułamek, to kompilator zauważy, że nie ma takiej metody w Int, która brałaby jako argument typ Ulamek. Poszuka więc czy w zasięgu jest zdefiniowana metoda implicit, zamieniająca typ Int na Ulamek. Jeśli tak to wykona tę operację. Jest to bardzo wygodne narzędzie do tworzenia wszelkich DSLi, jednak trzeba uważać, żeby nie nadużywać go, ponieważ osobie korzystającej z naszego kodu może nieźle namieszać.

Podumowanie

Tak jak wspominałem jest to ostatni z zaplanowanych przeze mnie odcinków kursu. Oczywiście nie wyczerpuje to w żadnym stopniu tematu, a jedynie jest lekkim muśnięciem, pokazującym możliwości języka i jego cechy. Mam nadzieję, że przybliżył nieco tematykę osobom, które nie miały jeszcze z nim styczności, a może nawet zachęci niektórych z was do dalszego pogłębiania wiedzy. (Do czego jest mnóstwo książek w tym darmowa pierwsza edycja Programming in Scala. Są dwie po polsku. Można też znaleźć również mnóstwo kursów i tutoriali.) Nie jest to prosta droga bo faktycznie składnia łącząca programowanie funkcyjne i obiektowe wymaga nieco więcej wysiłku niż większość innych języków programowania. Fakt ten został już zauważony przez twórców Scali, wiele dużych firm używających Scali również zwraca na to uwagę. Dlatego jednym z celów zespołu pracującego nad następnymi wersjami ma być właśnie przyjrzenie się składni języka i odrzucenie rzeczy zbędnych, ale w taki sposób, aby nie stracić na ekspresyjności. Zmiany te jednak pojawią się dopiero za jakiś czas, ponieważ w tej chwili trwają prace nad wykorzystaniem nowych cech funkcyjnych JVM w wersji 8, pozwalających uprościć kompilację kodu i przyspieszyć niektóre z bibliotek Scali.
Wydaje mi się, że język ten nie zdobędzie nigdy takiej popularności jak inne języki głównego nurtu. Barierą jest brak wystarczającej ilości programistów, którzy opanowali język i jego narzędzia na odpowiednim poziomie. Można jednak zauważyć, że są dziedziny, gdzie zdobywa on silną pozycję. Jest to głównie Big Data i podobne dziedziny, gdzie przetwarza się dużo danych w wielu wątkach, wykorzystując aktorów. Nie oznacza to, że tylko do tego się nadaje, Osoba (czego jestem sam przykładem), która zainwestuje swój czas w poznanie Scali, doceni szybkość jaką daje pisanie w tym języku aplikacji webowych po stronie serwera w takich frameworkach jak Lift, Spray.io czy Play.
 

programowanie

Komentarze

0 nowych
  #1 06.12.2014 23:34

Ehh. Ta Scala... Więcej boilerplatu się nie dało? Nie lepiej spożytkować tę energię na coś bardziej konstruktywnego zamiast uszczęśliwiania kompilatora? No, nie wiem... może np. tworzenie działającego programu? To poniżej napisałem w niecałą minutę razem z przykładami (Clojure):

(defn NWD [a b]
(if (zero? b) a (NWD b (mod a b))))

(defn | [fnc & more]
(apply map fnc more))

(defn tworz-ulamek
([l] [l 1])
([l m] (if (zero? m)
nil
(let [anwd (NWD (Math/abs l) (Math/abs m))]
[(/ l anwd) (/ m anwd)]))))

- przyklady:

> (def u1 (tworz-ulamek 4 4))
> (def u2 (tworz-ulamek 5 4))
> (def u3 (tworz-ulamek -5 -4))
> u1: [1 1]
> u2: [5 4]
> u3: [-5 -4]

> (| + u1 u2 u3): (5 4)
> (| * u1 u2 u3): (-25 -16)
> (| / u1 u2 u3): (-1/25 -1/16)
> (| - u1 u2 u3): (1 1)
> (| * u1 u2 (| + u3 u1)): (-20 -12)

Miejsce Scali jest na śmietniku.

koneton   6 #2 06.12.2014 23:34

Gdybym jako programista dostał taki kod do poprawy lub zmiany, to bym się pochlastał. ;) Nie raz zmieniałem kod aplikacji, które mają niemal tyle lat co ja i nie wyobrażam sobie, jak można cieszyć się z czegoś takiego jak niejednoznaczność w zapisie kodu (ot chociażby nie wymagalność nawiasów, konstruktory itd.). Może do tworzenia nowego kodu się to przydaje (szybciej? chociaż zalety widzę mizerne), ale do utrzymania go już nie. Z doświadczenia wiem, że praca programisty to w 70% (a może i więcej) to utrzymanie istniejącego kodu.Taki bałagan pracy nie ułatwi.

ilili   8 #3 07.12.2014 05:57

@koneton: niby jaki wpływ na utrzymanie kodu ma opcjonalność nawiasów?

koneton   6 #4 07.12.2014 09:47

@ilili: chociażby:
- brak czytelności
- potencjalne problemy ze zgodnością w kolejnych wersjach języka

  #5 07.12.2014 11:53

Po co chodzić jak można latać: F#

kowgli   6 #6 07.12.2014 12:37

Zgodze się z poprzednikiem. Zdecydowanie wolę nawet rozwlekły, ale samodokumentujący się kod od czegoś takiego. Do pewnych zasosowań naukowych jeszcze rozumiem, ale dla kodu powszechnego użytku, te wszystkie języki funkcyjne to moim zdaniem hipsterska moda, nic więcej. Takie moje zdanie, mogę się mylić.

Kod powinien być opisem problemu możliwie jak najbardziej zrozumiałym dla człowieka. To nie jest matematyka, gdzie im bardziej zwięźle tym większy bajer (tyle, że później nad każdym zdaniem trzeba siedzieć minutę, aby zrozumieć o co chodzi).

Autor edytował komentarz.
  #7 07.12.2014 13:54

Pokazałeś, że można obiektowo i zaczyna się marudzenie, że można obiektowo, ale w Javie jest lepiej, bo są nawiasy :D

@koneton
Kwestia doświadczenia z jękami funkcyjnymi. Do utrzymania takiego kodu nikt nie będzie szukać programisty Javy, tylko programisty Scali, a już prędzej, niż Javy to F#. Jeżeli ktoś chce pisać funkcyjnie, musi posiadać inny zestaw umiejętności i inną wiedzę, niż programista Javy. Musi chociażby dobrze, a nawet bardzo dobrze rozumieć system typów, najlepiej teorię kategorii od strony programistycznej. Bardzo silny, statyczny system typów pozwala na zaoszczędzenie czasu, który byłby poświęcony na pisanie nadmiarowych unit testów. Taki programista powinien też mieć pojęcie o konstruowaniu języków programowania i kompilatorów. W przypadku Scali przydatna będzie wiedza o JVM i samym kompilatorze Scali. Z resztą, od doświadczonego programisty Javy na wysokim szczeblu wymaga się również bardzo specjalistycznej wiedzy popartej głębokim doświadczeniem, bez którego nie odróżniałby się od pilnego studenta zdolnego pisać kod, który tylko jakoś działa.

Poza tym Scala świetnie nadaje się do rozwiązywania problemów, w którym to właśnie próba zapisania rozwiązania obiektowo będzie wyglądać niezręcznie, a istnieje cała masa takich problemów na niższym poziomie aplikacji, na poziomie przetwarzania danych. Scala znajdzie też swoje miejsce w małych firmach, przy pracy nad małymi projektami, gdzie można sobie pozwolić na zatrudnienie dobrych ludzi i liczy się przede wszystkim jakość.

TomaszK-Poz   8 #8 07.12.2014 14:57

@kowgli: Kwestia sposobu myślenia. Mi łatwiej sobie wyobrazić kawałki kodu, które są reakcją na coś (coś jak w js). A IF THEN ELSE lasuje mi mózg.
Nawiasy nie są potrzebne do życia, przecież to konwencja, ponadto mamy podświetlanie składni.

ilili   8 #9 07.12.2014 15:18

@koneton: "brak czytelności"
Kwestia opinii, w mojej, opcjonalność nawiasów właśnie poprawia czytelność i to bardzo, w sumie to nie wiem jak dokładnie jest to w przypadku Scali bo nie programuję, ale za to w Ruby wszystkie nawiasy są opcjonalne i niesamowicie to poprawia przejrzystość kodu.

"potencjalne problemy ze zgodnością w kolejnych wersjach języka"
Bitch please... tak możesz pisać o każdej jednej cesze języka, obligatoryjność nawiasów również pod to podpada - w końcu kiedyś mogą stać się opcjonalne...

  #10 07.12.2014 15:25

@ilili:ilili: co jest przejrzystego w tym ze raz moze to byc a raz nie. Jak masz sztywne reguly to wiesz vo i jak a tak to musisz sie zastanawiac ze moze byc tak, moze byc tak albo jeszcze inaczej

mikolaj_s   13 #11 07.12.2014 17:05

@koneton: "Nie raz zmieniałem kod aplikacji, które mają niemal tyle lat co ja i nie wyobrażam sobie, jak można cieszyć się z czegoś takiego jak niejednoznaczność w zapisie kodu (ot chociażby nie wymagalność nawiasów, konstruktory itd.)"

A co za różnica, czy na końcu wyrażania są nawiasy czy nie? Najważniejsze jest co zwraca dane wyrażenie i co robi. Od tego zaś jest dobra nazwa. Przy niemutowalnych polach klasy i tak ich nie zmienisz. A czy to pole czy metoda łatwo sprawdzić. Zaś ta cecha służy głównie do DSLi i nie musisz jej stosować.

"...ale do utrzymania go już nie"

Kod pisze się i szybciej i łatwiej go utrzymać, a to dlatego, ze jest krótszy, szczególnie gdy utrzymuje się styl funkcyjny. Co kto lubi. Pisanie w Scali mi osobiście daje dużego kopa. Szybkość pisania zbliżona do Pythona, ale utrzymanie dużo łatwiejsze.

"Taki bałagan pracy nie ułatwi."

Bałagan będzie taki jak ktoś go sobie zrobi. Faktem jest, że w wielu innych językach trudniej jest napisać bardziej nieczytelnie, ale też się da. Mamy coś za coś, albo ekspresywność i łatwość pisania albo ograniczenie utrudniające psucie kodu, ale za to problemy w napisaniu czegoś innego niż język przewiduje. To co lepsze zależy od projektu i ludzi piszących projekt.

"- brak czytelności "
Doświadczony programista nie wie, że nawiasy i średniki nie decydują o czytelności kodu? ;)

"- potencjalne problemy ze zgodnością w kolejnych wersjach języka"
Na razie nie ma z tym problemu. Być może pojawi się ten problem w wersji 3.0 bo jak pisałem w planach jest uproszczenie i zerwanie kompatybilności wstecznej. Ale to jeszcze pieśń przyszłości.

Autor edytował komentarz.
koneton   6 #12 07.12.2014 17:26

@ilili: Problemem jest brak jednoznaczności. Połowa kodu będzie napisana w jeden sposób, połowa inaczej, a Ty będziesz siedział i płakał zastanawiając się co autorzy mieli na myśli.

mikolaj_s   13 #13 07.12.2014 17:27

@kowgli: "Zdecydowanie wolę nawet rozwlekły, ale samodokumentujący się kod od czegoś takiego."

Ale co to ma wspólnego z nawiasami? Samodokumentujący się kod to nazwy.

" te wszystkie języki funkcyjne to moim zdaniem hipsterska moda, nic więcej. "

Moim zdaniem nie. Raczej projektanci zauważyli, że utrzymanie takiego kodu jest łatwiejsze i tańsze. Natomiast problemem jest fakt, że skoro do tej pory styl funkcyjny nie rozpowszechnił się mimo, że języków funkcyjnych zawsze było sporo, to być może nie jest to łatwe do opanowania dla programistów, albo też nie jest intuicyjne.

"Kod powinien być opisem problemu możliwie jak najbardziej zrozumiałym dla człowieka. "

To jest jeden z powodów dla których przekonałem się do Scali. Nie jest też tak, że w każdym momencie czytania kodu musisz dokładnie rozumieć każdą linijkę. Po to właśnie dzieli się kod na małe funkcje. Programowanie funkcyjne pozwala to robić prościej.

koneton   6 #14 07.12.2014 17:28

@mikolaj_s: Popracuj trochę ze starym kodem zmienianym przez wielu programistów to zmienisz zdanie.
"Kod pisze się i szybciej i łatwiej go utrzymać, a to dlatego, ze jest krótszy" Takiej bzdury dawno nie słyszałem. Zazwyczaj krótszy kod to odwrotność łatwego utrzymania.

mikolaj_s   13 #15 07.12.2014 17:41

@koneton: Piszesz o doświadczeniach z kodem napisanym w innym języku i przenosisz na zupełnie inny. Pracowałeś z kodem napisanym w języku funkcyjnym?

"Takiej bzdury dawno nie słyszałem. Zazwyczaj krótszy kod to odwrotność łatwego utrzymania."
Widocznie należymy do innej szkoły. Moje doświadczenia na ten temat są bliższe temu co pisze Robert Martin w Clean Code.

Frankfurterium   9 #16 07.12.2014 17:41

Aż trochę mi głupio, bo mimo posady zwyczajowego, kręcącego pod tymi wpisami nosem krytyka wydaje mi się, że przedmówcy nieco przesadzają. To znaczy chciałbym nieco mocniejszego sformalizowania niektórych sklaowych konstrukcji, i żeby mniej rzeczy działo się tam "implicit " i "automagicznie" (pamiętam, że tego właśnie słowa sam Odersky nadużywał w którymś nagraniu tutorialowym), ale...

Parę tygodni temu byłem zmuszony użyć Scali jako DSL-a w pewnym frameworku. Wyszło z tego ~300 linii bardzo przyjemnego i czytelnego skryptu. Trochę czasu musiałem poświęcić na uładnianie i dochodzenie co i dlaczego (wtyczka do IntelliJ jest co najwyżej taka-sobie), ale jak na pierwsze komercyjne zderzenie było całkiem OK. Do takich celów Scala nadaje się co najmniej tak dobrze jak wspomniany wyżej Python.

mikolaj_s   13 #17 07.12.2014 17:49

@Frankfurterium: "żeby mniej rzeczy działo się tam "implicit " i "automagicznie" ("

Z tym się zgadza, implicity potrafią nieco utrudnić życie ;)

ilili   8 #18 07.12.2014 20:37

@koneton: What?! Opcjonalność nawiasów nie oznacza że z nawiasami kod działa inaczej i bez inaczej... więc nad czym się tu zastanawiać?

koneton   6 #19 07.12.2014 21:19

@ilili: No właśnie. Popracuj kilka kat nad utrzymaniem kodu to zrozumiesz jaki to ból, gdy masz mis- masz w kodzie, bo każdy programista pisze po swojemu.

DjLeo MODERATOR BLOGA  17 #20 07.12.2014 21:45

Dobra robota...

Konradzinski   7 #21 08.12.2014 00:13

Dziedziczenia po wielu klasach jak i innych "nowoczesnych" (zdaniem niektorych) mechanizmow, nie ma w Javie nie bez powodu - po prostu utrudniaja one analizowanie kodu. Jaki bajzel powstaje w kodzie kiedy uzywa sie kilku dublujacych swoje funkcje mechaizmow oraz mechanizmow nieprzemyslanych (takich, ktore mialy ulawiz zycie, a je utrudniaja - np. template'y), najlepiej wiedza programisci C++.

W 100% zgadzam sie z Koneton'em, ktory mowi to, co wie kazdy stary programista: latwosc analizowania kodu jest w praktyce najwaznejsza cecha komercyjnie wykorzystywanych jezykow.

  #22 08.12.2014 08:20

@koneton: Babrzesz się w jakimś patologicznym kodzie i wnawiasz nam, że wszędzie tak jest?

  #23 08.12.2014 08:24

@Konradzinski: to zależy czy stary programista się rozwijał, czy siedział całe życie w jednym i hejtował nowości, bo one są źródłem zmian przyzwyczajeń.
Ten ostatni zwykle ma gorzej bo budzi się po 10 latach z ręka w nocniku i dziwi że świat się zmienił.

mikolaj_s   13 #24 08.12.2014 08:43

@Anonim (niezalogowany): Jeśli uważasz, że Twój kod robi to samo co podany w artykule przykład to współczuję. W twoim przykładzie działa tylko mnożenie. Może nie bardzo rozumiesz jak przeprowadzać operacje na ułamkach ;)

mikolaj_s   13 #25 08.12.2014 08:44

@Konradzinski: "latwosc analizowania kodu jest w praktyce najwaznejsza cecha komercyjnie wykorzystywanych jezykow."

Też się z tym zgadzam. Tylko akurat rozwlekłość kodu nie pomaga w jego analizie.

ilili   8 #26 08.12.2014 09:18

@koneton: pracuję, i to niestety mam dużo do czynienia z utrzymaniem kodu, który był przerzucany z rąk do rąk, każdy stosował swoje zasady... masakra. Mam też ostatnio styczność z kodem który jest świetnie utrzymany, czyta się go łatwo, a jak szukam jakiegoś  kawałka kodu to po prostu wiem gdzie jest prawie że z zamkniętymi oczami... A teraz pytanie, który jest napisany z wykorzystaniem języka z opcjonalnymi nawiasami? - Ruby, nigdy w swoim długim życiu nie widziałem tak przejrzystego, czytelnego kodu jak w projektach Railsowych... A opcjonalność nawiasów powoduje jedynie że szybciej i łatwiej się czyta kod, bo jest znacznie mniej "interpunkcji", nie ma najmniejszych problemów ze zrozumieniem kodu, bo w większości przypadków nawiasy nie niosą ze sobą żadnej informacji. To jest dokładnie tak jak w matematyce. Nie musisz pisać
2 + (3 * 5), bo wiadomo że jest to to samo co 2 + 3 * 5...

Konradzinski   7 #27 08.12.2014 22:47

@mikolaj_s: Ale zwiezlosc kodu z cala pewnoscia przeszkadza w jego analizie. Swietnym tego przykladem jest Perl.

  #28 08.12.2014 23:48

@mikolaj_s:
Słaby kod, słaby język. Brak defaultowych niemutowalnych typów generuje tony zbędnego śmiecia. Tak, bo te tony śmiecia nawet na chwilę nie pomagają łapać bugi w kodzie.
np to.:

def -(i: Int): Ulamek = new Ulamek(licz - 1 * mi, mi)

Znajdź błąd.

mikolaj_s   13 #29 09.12.2014 13:16

@Konradzinski: Z Perlem masz rację, ale ten język ma już taki duch, że ścigają się kto napisze bardziej nieczytelnie.

@Anonim:
"Brak defaultowych niemutowalnych typów generuje tony zbędnego śmiecia"

Nie znasz języka więc wypisujesz bzdury. W Scali każdy typ podstawowy jest sam w sobie niemutowalny. Jak napiszesz:
val a = 1
val b = 1
To masz dwie referencje pokazujące na ten sam obiekt, który ma wartość jeden. Do tego użycie val powoduje, że referencje są niezmienne. Niczego Ci więcej do szczęścia nie trzeba.

"def -(i: Int): Ulamek = new Ulamek(licz - 1 * mi, mi)

Znajdź błąd."

Kolejności działań w matematyce uczą już w szkole podstawowej, a zawsze można sobie dodać nawiasy, aby tę kolejność podkreślić. Za to odwrotna notacja polska stosowana w Clojure jest skrajnie nieintuicyjna i dużo czasu minie zanim ktoś przyzwyczai się do niej. Do tego ten stos nawiasów i problemy z dopilnowaniem zamknięcia każdego z nich.

"Słaby kod, słaby język."
Pokaż lepszy, w swoim pierwszym komentarzu nie potrafiłeś napisać kodu, który realizowałby ten ułamek, więc o czym my tu mówimy?

Autor edytował komentarz.
  #30 09.12.2014 14:43

@mikolaj_s: bo mi się nie chce, to twoja brocha by się obronić a nie anonima z komentarza.

Resumując kiepsko i miernie wypadłeś. Wątpię czy kogoś zachęciłeś do Scali. Z resztą nie ma do czego zachęcać... Zwykłe marnotrawstwo czasu i energii.

Dodatkowo widzę, że idziesz w zaparte, bo i buga nie porawiłeś.

mikolaj_s   13 #31 09.12.2014 18:42

@Anonim (niezalogowany):
"bo mi się nie chce, to twoja brocha by się obronić a nie anonima z komentarza. "
Piszesz jakiś denny kod, który niby robi to samo, a w zasadzie tylko jako tako mnoży ułamki i twierdzisz, że jest lepszy. Jeśli tak to napisz go porządnie. Nie potrafisz? To mnie nie przekonasz (i innych pewnie też nie). Sam nie zmuszam Cię do zmiany zdania. I tak samo jak Ty nie muszę niczego bronić.

"Resumując kiepsko i miernie wypadłeś. "
To co dopiero powiedzieć o Twoim komentarzu ;)

"Zwykłe marnotrawstwo czasu i energii. "
Zapewniam Cię, że nie masz racji. W moim przypadku język i narzędzia z nim związane oszczędzają mi mnóstwo czasu i pracy. Nikogo nie zmuszam do niczego, opisuję tylko to co sprawdziło się w moim przypadku.

"Dodatkowo widzę, że idziesz w zaparte, bo i buga nie porawiłeś."
Dziękuję za czujność, faktycznie nie zauważyłem literówki.

Autor edytował komentarz.
  #32 09.12.2014 18:46

Już kiedyś pisałem, by nie dyskutować z tym trolem od Clojure. RaveStar ile ty masz lat? Ogarnij się.

  #33 09.12.2014 20:16

@mikolaj_s: Ja tu nie jestem by kogoś przekonywać. To ty pokazujesz jakie to w Scali cuda na kiju, a ja piszę , że da się jeszcze lepiej i krócej, nawet jakbym poprawił to co u góry skleiłem w notatniku nadal będzie 2-3x krótsze od twojej wypociny nad którą siedziałeś pewnie cały dzień.

Druga sprawa, że pomimo, że użyłeś IDE, a w kodzie roi się od typów zapodałeś zabugowany kod. Literówka? Niech cię najwyższy ma w opiece jak się będziesz tłumaczyć u szefa, że to literówka. Nie przetestowałeś kodu, a śmieci składniowe przesłoniły logikę. Dlatego nie było widać błędu. Nie wiem jak inni,a ale czym to się różni od Java?

Really nothing impressive. Pokaż coś, co się może przydać i skrócić robotę , a nie, że piszesz tu jakiś dziennik spóźnionego na pociąg Scalowicza. Rozumiem zachwyt, ale Scala to przeszłość. Kiepski kompilator, trudna w testowaniu, boilerplatu wciąż tyle co w Java, a czasem wręcz nie widać różnicy, itp...

Podobne zachwyty widziałem nad C++ kiedy wchodziła Java. I co? Ci co zachwycali się c++ przegrali życie. Wiedza do niczego nie potrzebna.

mikolaj_s   13 #34 09.12.2014 22:50

@Anonim (niezalogowany): Musisz mieć sieczkę zamiast mózgu, szkoda na ciebie czasu

  #35 13.12.2014 16:50

"Język Scala oprócz tego, że jest językiem o funkcyjnym paradygmacie programowania, to również jest w pełni obiektowa."

Niby w jaki sposób w pełni obiektowa? Widziałeś w ogóle w pełni obiektowy język? Poza tym jaki to niby paradygmat funkcyjny zawiera? Lambdy? To może C++ jest funkcyjny? Albo Java, bo też ma lambdy?

Druedain   13 #36 15.12.2014 11:32

Czytając komentarze dochodzę do wniosku, że dla niektórych krótki zapis stał się celem, a nie środkiem.

1. Skoro nawiasy są opcjonalne, to czemu w ogóle się je stosuje? Nie powiecie mi chyba, że nie da się stworzyć języka, w którym parametrów funkcji nie owija się w nawiasy? Bo tu nie chodzi o to, że nawiasy muszą być zawsze, tylko o to by było jednoznacznie. Więc po co w ogóle nawiasy? Czy Haskell ich potrzebuje?... Wy możecie ubóstwiać swój kod bez nawiasów, ale trafi się wam w projekcie osoba wymiatająca, która cały czas wolała nawiasów używać. No to co, nie przyjmiecie go bo używa nawiasów, czy zaakceptujecie jego nawyki? To sobie teraz wyobraźcie to o czym tu ludzie próbują napisać. Będziecie mieć obok siebie ciągle:
doSomethin
doSomethingElse()
doAnotherThing
doTheLastOneThing()
...

2. Niektórzy sprowadzają problem do tego, że programiści Javy nie umieją „myśleć” w Scali. Okej, niech tak będzie. Tylko mi jeszcze teraz powiedzcie gdzie będziecie szukać tych programistów Scali, kiedy nawet dla tej „ograniczonej” Javy są takie braki? I podpowiem wam, nie będzie przepływu ludzi, bo nie żywych bytów brakuje, tylko konkretnie specjalistów, a Scala nie jest prosta.

Druedain   13 #37 15.12.2014 11:34

@Anonim (niezalogowany): C++ ma cechy języków funkcyjnych od czasów wprowadzenia w nim operatora const.

mikolaj_s   13 #38 15.12.2014 15:13

@Druedain: "o sobie teraz wyobraźcie to o czym tu ludzie próbują napisać. Będziecie mieć obok siebie ciągle:
doSomethin
doSomethingElse()
doAnotherThing
doTheLastOneThing() "

W dobrze zorganizowanym projekcie prowadza się zasadę, że wersja bez nawiasów (co można wymusić nie pisząc nawiasów w definicji) jest wersją nie zmieniającą stanu wewnętrznego, zaś z nawiasami przeciwnie. (Tu akurat konieczności nawiasów nie da się wymusić inaczej jak perswazją :) )
Wydaje mi się, że trzymanie się konwencji w formatowaniu kodu jest potrzebne w każdym projekcie, w każdym języku tym bardziej w takim, który pozwala na wiele.

" I podpowiem wam, nie będzie przepływu ludzi, bo nie żywych bytów brakuje, tylko konkretnie specjalistów, a Scala nie jest prosta."

Jak już pisałem, dostępność programistów to największy problem. I biorąc pod uwagę fakt, że języki funkcyjne istnieją już od dawna, a mimo to nie znalazły zastosowania w mianstreamie może być wskazówką, że nie są dla zwykłego programisty zbyt intuicyjne. Stąd pomysł na Scalę jako języka hybrydowego umożliwiającego pisanie w takim paradygmacie jaki nam pasuje. Ale jak sam zauważyłeś wynikiem jest język, który jest nieco bardziej skomplikowany od Javy. Chociaż mi osobiście i tak jest łatwiej się przestawić z języków pochodzących od C niż na takie Clojure stosujące ONT i pełno nawiasów.

Druedain   13 #39 15.12.2014 16:24

@mikolaj_s: Java jest pod tym względem bardziej restrykcyjna, a do tego są przyjęte już pewne standardy pisania kodu i ludzie raczej nie mają z tym większego problemu. Jeśli nie zmieniasz domyślnej konfiguracji popularnych środowisk programistycznych, to najprawdopodobniej będziesz mieć ustawione standardy formatowania zgodne z przyjętymi przez twórców Javy i używających na większą skalę ten język (Oracle, Google, itd.).

A jak to się ma do Scali? Nijak i mająca tu miejsce dyskusja najlepiej to obrazuje. Z jednej strony zachęca się programistów Javy do używania tęgo języka, a z drugiej zachęca się ludzi, którzy wyrośli na funkcyjnych językach. Ci pierwsi będą woleć wszędzie (), a inni nie. Która „połowa” programistów będzie mieć rację, a która będzie musiała zmieniać nawyki budowane latami? (piszę „połowa”, bo prawdopodobnie Javowców w zespole będzie przytłaczająca większość).

Z resztą tu się objawia ta wytykana akademickość Scali, a nie pragmatyzm życiowych użytkowników. W kilku firmach byłem i tylko jeden raz byłem w zespole, gdzie były narzucone praktyki formatowania kodu i na serio ktoś się tym przejmował. W reszcie zazwyczaj jest taki rozgardiasz, że znajdziesz wszystkie możliwe wersje formatowania, tylko nie te, które są zalecane.

Bo w praktyce języki czysto funkcyjne są nieżyciowe. Zakładają, że każdy skończył z wyróżnieniem studia informatyczne na uniwersytecie, a nie politechnice (taki skrót myślowy, jakby ktoś nie załapał). Wystarczyło jednak przemycać pewne cechy np. do C#, by ludzie tego zaczęli używać, chwalić i dalej rozwijać.

mikolaj_s   13 #40 15.12.2014 17:58

@Druedain: Ale sam nacisk na języki funkcyjne jaki teraz się obserwuje ma racjonalne podstawy, to nie sama moda. Przede wszystkim łatwiej jest pisać kod wielowątkowy, łatwiej się testuje. Nic dziwnego, że języki funkcyjne znajdują zastosowanie w kodzie produkcyjnym. Oczywiście mają i one swoje wady, które słusznie punktujesz. Jednak są projekty, w których mimo to pokazują swoją przewagę.
Co do formatowania to nie widziałem jeszcze kodu, w którym nie można było go czytać ze względu na formatowanie, użycie bądź nie nawiasów itp., normalni ludzie nie nadużywają bez potrzeby możliwych cech języka. Aczkolwiek kod, który widziałem raczej pochodził od dobrych programistów mających sporą praktykę w pisaniu w Scali.

Druedain   13 #41 16.12.2014 10:03

@mikolaj_s: Co do mody, to również zgadzam się, że za wzrostem popularności stoją życiowe powody, a nie moda. Sam czekam, aż będę mógł Javę 8 używać. **** nie urywa, ale to i tak spory krok na przód.

Co do formatowania, ja, mimo krótkiej kariery, już zbyt często widywałem kod Javy, który ciężko było czytać, by uwierzyć, że w Scali tego się nie zobaczy.

  #42 17.12.2014 19:50

@Druedain: C++ ma cechy języków funkcyjnych tak jak kuternoga ma cechy sprintera. No chyba, że kuternoga startuje w paraolimpiadzie, ale przecież nikt nie użyje C++ tam, gdzie potrzeba bezpieczeństwa i szybkości dużego kodu.

Druedain   13 #43 18.12.2014 09:51

@Anonim (niezalogowany): Oj, widzę, że trafiam w czuły punkt :> .

  #44 18.12.2014 11:47

@Druedain: Oczywiście, że trafiasz, bo Scala pochodzi prawie że w prostej linii od C++. Może C++ troche mniej zorientowany na programowanie funkcyjne, ale reszta to niemal lustrzane odbicie.
Czasy kompilacji, kompatybilność wsteczna, ilość styli składniowych - posadź 20 programistów C++ czy Scali i każ napisać Hello Worlda, to okaże się , że tylko około 18 z nich nie ogarnie tego, to co napisali koledzy. Szybkość rozwoju - dawniej Scala nadrobiała wprowadzaniem nowinek, dziś zrzyna na pałę co się da z innych języków i jest z tym daleko w tyle.

Jedno mogę powiedzeć: nie wiem co będzie po Javie, ale na pewno nie będzie to Scala. Trend idzie w kierunku języków w których wszystko jest immutable by default. Może nie Clojure będzie na topie, może nie Haskell, ale na pewno język ten będzie mieć domyślne niemutowalne struktury danych i nie będzie mieć operatora przypisania "=" lub opertor ten będzie działać jak w Erlangu - jako alias.

Druedain   13 #45 18.12.2014 13:59

@Anonim (niezalogowany): Ale oooo co Ci chodzi??? Jesteś pewny, że trzeba mnie do czegoś przekonywać? Nie pomyliłeś adresata? :>

  #46 19.12.2014 21:40

@Druedain: Nie czytałem poprzednich komentarzy. Po prostu nie interesuje mnie też przekonywanie innych do czegoś. Jednak pokazywać palcem potrafię, a krytykować lubię. A nabijać się z kogoś, kto robi sobie krzywdę uwielbiam. :)

kostek135   8 #47 21.12.2014 01:26

"Z resztą tu się objawia ta wytykana akademickość Scali, a nie pragmatyzm życiowych użytkowników. W kilku firmach byłem i tylko jeden raz byłem w zespole, gdzie były narzucone praktyki formatowania kodu i na serio ktoś się tym przejmował. W reszcie zazwyczaj jest taki rozgardiasz, że znajdziesz wszystkie możliwe wersje formatowania, tylko nie te, które są zalecane. "

Ale po co to, to? Narzucanie formatowania, to chyba jakieś średniowiecze z SVN-em w środku. Podpinasz hook aby przy wypchnięciu do zdalnego repozytorium został użyty skonfigurowany formater kodu w stylu firmowym i tyle. Natomiast przy fetchu do lokalnego ustawiasz drugi, taki jak lubisz ty. Pierwszy powinna dostarczać firma, drugi powinieneś mieć ty, więc czas na setup wynosi około 2 minuty.

  #48 10.01.2015 19:44

Scala... Czy ten język to jakiś żart?

  #49 19.01.2015 20:24

OMG, to Scala jeszcze żyje?