niedziela, 22 grudnia 2013

Otwarcie z mobilizacji + potrawy na święta

Część Artystyczna

Potrawy na święta

Tradycja nakazuje aby przygotować na święta 12 potraw. Z jednej strony ślepa wiara w tradycję strasznie ogłupia jeśli ludzie są odcięci od rodowodu owej tradycji ((W korpo mówi się "Root Cause") ale z drugiej strony jeśli coś ma ogłupiać ludzi niech to będzie tradycja a nie telewizja czy coś takiego.

Poniżej przykładowy stół wilijny statystycznej rodziny polskiej :

Rzeczy które widzimy na zdjęciu to w potocznej mowie suple a w niepotoczne suplementy diety. Suplementy diety nazywają się suplementami ponieważ mają uzupełniać dietę a nie ją zastępować. Jest to ważne gdyż najczęstsza reakcja jaką spotkałem w odpowiedzi na ten temat to połączenie niezrozumienia, negacji i chyba lekkiego przerażenia przed nieznanym.

Wokalizacja owej reakcji zazwyczaj przybiera słowa "nie będę jeść chemii" albo "Jem tylko naturalne rzeczy". Problem polega na zbyt abstrakcyjnym myśleniu - tak, to co może pomóc w programowaniu tutaj akurat działa na naszą niekorzyść. Widzimy ogórek i myślimy ogórek, widzimy pomidor myślimy pomidor...

Chemiczny poziom abstrakcji niżej

Oto kolekcja ciekawych linków :

A żeby na koniec było bardziej intelektualnie to wzmianka o tym jak ołów redukuje IQ

To była wzmianka o chemii tam gdzie standardowy konsument widzi "naturalne produkty żywnościowe". A czy obok złej chemii jest więcej tej dobrej? Niestety nasz przemysł nie wydziela odpadów w postaci witaminy C. Poniżej tabelka żywcem skopiowana z tego artykułu. Procentowa zmiana minerałów i witamin w glebie pomiędzy rokiem 1940 a 1991

MINERALS
VEGETABLE
FRUIT
Sodium
-49%
-29%
Potassium
-16%
-19%
Magnesium
-24%
-16%
Calcium
-46%
-16%
Iron
-27%
-24%
Copper
-76%
-20%
Zinc
-59%
-27%

I Jeszcze na dobicie - link

Świadoma grupa konsumentów

Suplementacja witaminami i minerałami to konieczność. Do tego każdy kto nie pochłania odpowiednich porcji łososia powinien wrzucić do diety Omega3 (a no i podobno łosoś poza Omega3 ma jeszcze trochę rtęci). Jest dużo produktów w aptekach - ja jednak polecam profesjonalne sklepy z suplami dla pakerów. Otóż jeśli sobie zerkniecie na fora zamieszkałe przez ludzi o powierzchni pola większej niż szafa dwudrzwiowa to zauważycie, że niektórzy z nich podchodzą do swojego hobby z ogromną pasją. Na porządku dziennym są posty gdzie jeden czy drugi schab rozbijają dany produkt na czynniki pierwsze i dyskutują pochodzenie każdego ze składników.

To jest właśnie świadoma grupa konsumencka. Tutaj gdy tylko pojawia się jakiś producent, który wali w ch** to od razu jest demaskowany. W przypadku zwykłej żywności są tam jakieś grupy dyskutujące pochodzenie produktów ale chyba większość ludzi po prostu wali do hipermarketu aby kupić coś taniej. A tam to już działa zwykła logistyka - produkt będzie leżał jakiś czas toteż dorzuca się kolekcje "E" aby leżał wystarczająco długo by przynieść zysk a nie stratę. Ludzie kupują to interes się kręci.

I na zakończenie - to co tutaj napisałem ma charakter niefachowego przeglądu literatury fachowej. Zapewne jakiś profesjonalny technolog żywności opisałby to jakoś składniej i dokładniej. To co mogę doradzić od siebie - to mięso z Grota bo tam działa wizja marketingowa "zdrowej" zamiast "taniej". No i tam też gadałem z ekspedientkami i generalnie to czego nie były w stanie namierzyć bez większej ilości konserwantów to chrzan - bo to podobno w naturalnej formie psuje się po dwóch dniach. Jajka to wiadomo - omijać klasę 3 bo to jest prosto z tych farm kurzych gdzie napieprzają w te ptaki antybiotykami z karabinu maszynowego. Ryby kupować jak najmniejsze bo jest szansa, że nawpieprzały się najmniej chemikaliów - no i omijać pangę. Do tego zróbcie sobie eksperyment i zerknijcie latem na rzodkiewki w warzywniakach. Jeśli są wielkości jabłka to jak dla mnie znak, że w danym sklepie pestycydy i inne wynalazki są na porządku dziennym.

I tak poza tym to wesołych świąt.

niedziela, 15 grudnia 2013

CodeRetreat 2013 - Uwagi i wnioski

Frekwencja i alkowigilie

W tym roku zjawiło się mniej ludzi niż poprzednio. Być może jest to spowodowane bliskością Świat i faktem, że firmy organizują swoje Wigilie na których ludzie dzielą się wódko-opłatkiem. Nie jest to w zasadzie żadna przeszkoda bo w sobotę wpadło się kilka osób, które na pewno nie byłyby w stanie prowadzić samochodu. Także pierwsze lesson learn : na kacu też da radę (jest to ważne bo w przyszłym roku pewnie też CR odbędzie w sobotę).

Języki

Chociaż najwięcej było Javy to jednak pojawia się coraz więcej innych: głównie Javascript i Python. Pomału czasy żartów z Javascriptu odchodzą w przeszłość a zaczynają się czasy żartów z ludzi, którzy myślą, że Javascript jest tylko do obsługi onlicków. Był też C++ ale mój mózg odmawia interpretacji tego języka dlatego zazwyczaj patrzyłem się 5 sekund w ekran, pytałem czy jest jakiś dylemat, który mogą pomóc rozwiązać i zazwyczaj przechodziłem dalej.

Object Calisthenics to za mało

Object calisthenics to zestaw ciekawych ćwiczeń-ograniczeń, które wykorzystujemy co roku aby ćwiczyć dobre praktyki obiektowe. No właśnie - obiektowe. Biorąc pod uwagę kierunek w jakim rozwija się Java i inne języki na JVM warto by zrozumieć co tak naprawdę stoi za tymi ćwiczeniami i dlaczego niektóre mogą pomału tracić sens.

Weźmy taki ograniczenie - "one dot per line. W tym przypadku ćwiczenie polega na tym aby nauczyć się lepiej zamykać obiekty i nie wyciągać na zewnątrz ich bebechów. Czyli nie pisać czegoś takiego :

gra.getPlansza().getStrukturaKomorek()
Ale konstrukcja poniżej ma zupełnie inny charakter :
komorki.map(transformuj).filter(tylkoZywe)
Dwa kawałki kodu o zupełnie innym charakterze, o kompletnie innej naturze. Drugi dobry ale pierwszy bardzo niedobry, bardzo bardzo zły.

Może za rok ktoś wymyśli nowy zestaw ograniczeń z ukłonem w kierunku nowych mechanizmów Javy 8? "tylko funkcje jednoparametrowe" albo "wszystko jest funkcją" ?

Ciekawe rozwiązanie

Przy okazji dyskusji and kodem Javascryptowym pojawiło się ciekawe rozwiązanie odnośnie tego jak przygotować aplikację na rozbudowę w kierunku nowych typów komórek.

Prędzej czy później każdy dochodził do reprezentacji otoczenia komórki jak czegoś ala "Sąsiedztwo". Później komórka lub coś innego (w zależności od tego gdzie jest logika transformacji) uzyskuje z Sąsiedztwa informacji o ilości żywych sąsiadów i popycha ewolucję do przodu.

Można też inaczej. Każda nowa komórka może sama dostarczyć algorytm przeżycia a Sąsiedztwo zamieni się w funkcję wyższego rzędu, która ów przepis zmaterializuje. OT coś takiego :

abstract class Cell
case class DeadCell extends Cell{
 //...
}

case class LiveCell extends Cell{
 val lifeCellEvolutionRules:(Int=>Cell)=(liveNeighbours:Int)=> {
   if(Set(2,3).contains(liveNeighbours)) LiveCell()
   else DeadCell()
  }

 def evolve(environment:(Int=>Cell)=>Cell)=environment(lifeCellEvolutionRules)
}

object Game{
 def environmentPrototype(liveNeighbours:Int)(evolutionRules:(Int=>Cell))=evolutionRules(liveNeighbours)
 
 val cell=LiveCell()
 val environment=environmentPrototype(2)_
    cell.evolve(environment)                        //> res1 = LiveCell()
}

Teraz jak dodamy sobie np. komórkę "Zombie" to może ona łatwo sama dostarczyć zasady swojej ewolucji. Uważny czytelnik zauważy, że i tak może być dupa bo nie da się łatwo rozszerzyć starych zasad o nowe typy komórek. Otóż można to łatwo rozwiązać przenosząc zasady ewolucji do odpowiedniego komponentu, który będzie również odpowiednio rozszerzany przez nowy moduł.

trait EvolutionRulesKeeper{
 def evolutionRulesFor(cell:Cell): EnvironmentData=>Cell
}

class BasicEvolutionRules extends EvolutionRulesKeeper{
 protected val rulesForLiveCell=(environmentData:EnvironmentData)=>...
 protected val rulesForDeadCell=(environmentData:EnvironmentData)=>...
 protected val evolutionRules:Map[Cell,EnvironmentData=>Cell]=Map(LiveCell()->rulesForLiveCell,DeadCell()->rulesForDeadCell)
 def evolutionRulesFor(cell:Cell)=evolutionRules(cell)
}

Foty

link do fotek

Wypalenie zawodowe

Ale jeszcze nie moje. Po imprezie była posiadówka w trakcie której jeden kolega opowiadał o szkoleniu gdzie dowiedział się jak rozpoznać nadchodzące wypalenie zawodowe. Podobno najpierw zapierdala się biorąc na siebie coraz więcej i więcej obowiązków aż nagle człowiek pęka. W Holandii podobno jest specjalny typ urlopu, który można wziąć raz w życiu z powodu wypalenia zawodowego. Ja kiedyś zrobiłem sobie trzy miesiące wakacji aby ponownie odnaleźć sens w IT po ponad 2,5 roku pracy w fabryceIT przy cybertaśmie. I jak się okazuje u nas w Polsce jak się zrobi sobie taki urlop to na wszystkich rozmowach kwalifikacyjnych ludzie są zafascynowani tym faktem ;) (niektórzy nazywali to "dziurą w życiorysie zawodowym")

*      *      *

niedziela, 8 grudnia 2013

CodeRetreat 2013 Łódź i wartości edukacyjne

Co gdzie i kiedy

Jeden obraz wart tysiąc słów.

Razem z dwoma innymi prowadzącymi będziemy pomagać każdemu przejść przez ćwiczenia tak aby nauki było jak najwięcej. A jeśli jesteś drogi czytelniku nadal niepewny - poniżej postaram się w tych kilku akapitach zachęcić cię do udziału.

Teoria stojąca za praktyką

To jest prosta a zarazem skuteczna seria ćwiczeń. Wybieramy sobie kilka ograniczeń (np. żadnych ifów) i w trakcie 45 minut staramy się zaimplementować część wybranego problemu z uwzględnieniem tychże ograniczeń. Zazwyczaj w tym miejscu przychodzi czas na jakąś metafarę ze świata karate ale chyba znalazłem coś lepszego - ale to za chwilę.

Jak tak wspominam sobie zeszłoroczne coderetreat i rozmowy wokół tego tematu to oczy me widzą dwa ważne pojęcia, które wydają się być czasem nie do końca zrozumiałe :

  • Proces jest ważniejszy od rezultatu
  • Ograniczenia mają uczyć a nie pomagać

Omówimy je oczywiście w odwrotnej kolejności

Istota treningu

Często ćwiczenia coderetreat porównuje się do ćwiczeń sportowców. Czy to do piłkarza, który godzinami ćwiczy rzuty wolne (nie wiem czy polscy piłkarze ćwiczą godzinami rzuty wolne) czy też skoczka, który godzinami skacze ćwicząc technikę skoku. Można też porównać to do filmu kung fu gdzie młody koleżka spotyka starego dziada, który to okazuje się być mistrzem sztuka walki. Dziadu każe mu walczyć z zasłoniętymi oczyma i młody uczy się wykorzystywać inne zmysły.

Jest być może ciekawsza metafora dla niektórych fanów komputera.

Znałem swego czasu kilku ludzi, którzy bardzo lubili grać w starcrafta. Wchodzili sobie tam online i grali takie nerdowe "mecze". Kosili te kryształy, budowali wojsko i była bijatyka. Wojsko jednostek miało kilka rodzajów i trzeba go było odpowiednio używać w zależności od sytuacji. No i słyszałem takie oto anegdoty, iż ludzie ci spotykali się w kawiarenkach internetowych (tak tak, kiedyś internet był w kawiarenkach) i np. umawiali się, że grają tylko żołnierzykami. Albo, że teraz grają tylko stateczkami latającymi. Po co? Otóż w trakcie normalnej gry i wojennej zawieruchy nigdy nie wiadomo kiedy pojawi się szansa zaatakowania bazy przeciwnika a ty masz tam obok pod ręką trzech żołnierzyków. Czy coś w tym stylu.

Podobne prawa działają na coderetreat. Mamy np. ograniczenie Klasy tylko typu "immutable". Nie oznacza to, że pisanie klasy "Immutable" (żaden słownik nie zwraca mi słowa "niemutowalne" jako poprawnego) są zawsze i wszędzie absolutnie najlepsze. Ćwiczymy po prostu umiejętność pisania klas, które nie mogą mieć żadnych seterów ani innych metod zmieniających stan - czyli witaj łatwiejsza wielowątkowościo i żegnajcie dziwne błędy.

Albo ograniczenie dwa pola na klasę - znowu można łatwo znaleźć ot choćby jeden przykład gdzie to jest niedoskonałe ale stawiając sobie to ograniczenie ćwiczymy pisanie bardziej skonkretyzowanych klas (czyli takich leżących na przeciwnym biegunie niż coś ala *Manager" czy "*Helper" czy inne gówna)

Refleksja procesu

Zacznijmy od dwóch okładek bardzo ciekawych książek :

Każda z nich opisuje "talent" czy "uzdolnienie" (ba - nawet geniusz) jako wynik pewnego procesu a nie wartość wrodzoną danej jednostki. Stoi to w pewnej sprzeczności z tym je**anym ku*wa w du*e popularnym dziś poglądem jakoby ludzkość byłą mieszanką nielicznych liderów otoczonych szarymi masami.

A prawda jest taka, że od najmłodszych lat patologiczny system szkolnictwa a później idiotyczny systemy motywacyjne a korporacjach zabijają w ludziach naturalną pasję tworząc legiony uciekinierów mentalnych szukających azylu w grach komputerowych,serialach TV czy innych używkach. Nie musi tak być.

To jest szalenie złożony proces ale tutaj napiszmy, że aby odnieść wartości z nauki, złapać taki "cug pasji" i poczuć jak nasza wiedza,umiejętności a nawet tożsamość ewoluują - musimy się skupić nie tylko na rezultatach ale i na procesie dochodzenia do nich. To jest znowu mało popularne w świecie Zachodu gdzie "liczą się rezultaty" a na przykład Wschodnia medytacja chyba dopiero wtedy zdobyła pewną popularność gdy zdobyła taką otoczkę "techniki" zwiększenia swojego "performensu"

To jest fajnie opisane w "The talent code". Otóż poza neuronami czy komórkami glejowymi jest jeszcze jedna ciekawa substancja. Mowa o Otoczce Mielinowej, która przyśpiesza połączenia pomiędzy neuronami. Zasada działania jest chyba podobna do akceleratorów cząstek gdzie pole magnetyczne przyśpiesza owe cząstki w odpowiednich tunelach. Wierząc autorowi na słowo - aby zbudować efektywniejsze połączenia nerwowe niezbędna jest autorefleksja nad tym co robimy. Trudno o to w standardowym środowisku pracy gdzie w dobie agresywnych dedlajnów nadszedł "czas napierdalania".

Na koniec

Toteż każdego zachęcam do wzięcia udziału. Na chwilę obecna zostało 14 miejsc.

*      *      *

niedziela, 1 grudnia 2013

Wzorzec Stan w inny sposób

Był swego czasu taki kabareciarz, zwący się Stan Tutaj ale to nie ma żadnego związku z tym artykułem gdyż ja chcę opisać wzorzec Stan tutaj.

Stan

Na necie ilustrację dla tego wzorcu stanowi przykład z włącznikiem światła, który jest totalnie nieludzki tak jak dzisiejsze czasy. Lepszym pomysłem jest wykorzystanie stanu pięknego związku uczuciowego łączącego dwie istoty ludzkie (zazwyczaj o odmiennej płci ale nie wnikam). Dla uproszczenia ograniczymy się do tych dwóch :
  • Kocha
  • Nie Kocha
A zapomnimy o tych stanach :
  • To skomplikowane
  • Graliśmy w słoneczku ale jeszcze ze sobą nie chodzimy

Kod

W obiektówce tworzyło się obiekt, który opakowywał dostęp do stanu i takie tam. Czyli tutaj mielibyśmy coś co symbolizuje związek (miłosny nie Radziecki) i zmiany jego stanu. Ale można też inaczej - zaimplementujmy zmianę stanu... bez zmiany stanu.
def kocha(licznikLudowy:Int):String= if(licznikLudowy==0) "Kocha" else nieKocha(licznikLudowy-1)
def nieKocha(licznikLudowy:Int):String=if(licznikLudowy==0) "Nie Kocha" else kocha(licznikLudowy-1)

kocha(10)                                       //> res0: String = Kocha
kocha(11)                                       //> res1: String = Nie Kocha
Niby fajnie ale teraz się wywali :
 kocha(100000)                                   //> java.lang.StackOverflowErrorSexuNieBedzie

Niestety nie starczyło miejsca na stosie na tyle wywołań tychże dwóch funkcji (stos w informatyce to miejsce gdzie pali się czarownice).

Trampolina

Internet zna rozwiązania tego problemu z zastosowaniem techniki zwanej trampoliną (albo czymś co się wymawia podobnie ale znaczy coś zupełnie innego). Idea jest taka aby ograniczyć skoki do kilku komórek na stosie - czyli takie "Tail recursion" dla kilku funkcji na raz.
def kocha(licznikLudowy:Int):TailRec[String]= if(licznikLudowy==0) done("Kocha") else tailcall(nieKocha(licznikLudowy-1))
def nieKocha(licznikLudowy:Int):TailRec[String]=if(licznikLudowy==0) done("Nie Kocha") else tailcall(kocha(licznikLudowy-1))

kocha(100000).result                            //> res0: String = Kocha

Typ zwracany to już nie jest zwykły string ale String opakowany w TailRec. No i metody wywołujemy poprzez done i tailcall. Będę musiał kiedyś doczytać jak pogrubia się tekst w tej kolrowaczce do kodu.
*      *      *

niedziela, 24 listopada 2013

Wzorzec Command w inny sposób

Ponieważ nie umiem wymyślić ciekawego wstępu do artykułu o wzorcu projektowym dlatego nie tak od razu przejdę do rzeczy. Doszło do mnie kilka opinii (zwłaszcza wczoraj przy wódzie - ja tam dużo nie piję bo to nie jest zdrowe ale inni tak), że poprzedni wpis był za długi i było w nim za mało cycków. Po pierwsze to ludzie wstydźcie się bo takie uwagi są w ogóle bardzo bardzo niedobre, bardzo bardzo złe. Po drugie chociaż bardzo bym chciał to jednak wydaje mi się, że nie mogę sobie wklejać losowych cycków (nawet tych sztucznych) z internetu bo to łamie jakieś tam prawa autorskie. Pozostaje mi tylko nauczyć się rysować cycki w paincie co może nie być złym pomysłem zważywszy na to, że zawsze kiedy koloruję ramki tabelek w css odczuwam niesamowity relaks i spadek ciśnienia krwi.

Wzorzec command bardziej funkcyjnie

Na Wikipedii wzorzec jest opisany i jest nawet przykład w scali - ale ów przykład wydaje mi się trochę lewy :http://en.wikipedia.org/wiki/Command_pattern

Jakby to można było napisać inaczej ?

 type Command = () => Unit
 type KanalInformacji= String=>Unit
Na początku dla porządku zadeklarujmy dwa typy. Ponieważ komenda standardowo ma metodę execute, która nic nie zwraca, więc i tutaj mamy "funkcję" bezzwrotną i bezparametrową. A KanalInformacji to taki typ dla bajeru, że niby wysyłamy coś kanałem informacji. Dodatkowo ostatnio przeczytałem, że posługując się innymi językami ludzie używają trochę innych rejonów w mózgu, więc taki ponglish może być ciekawym sposobem aby zyskać nową perspektywę

 class Egzekutor {
    var historia: Vector[Command] = Vector()
  
  def execute(command:Command)={
   historia=historia :+ command
   command()
  }
  
  def replay()={
   historia.foreach(_.apply)
  }
  }
W odróżnieniu od filmu z Arnoldem powyższy egzekutor po prostu wykonuje komendy i zapisuje je w historii coby replaya strzelić jak trza.

def commandFunction(kanalInformacji:KanalInformacji)(wiadomosc:String)()={
  kanalInformacji(wiadomosc)
}     
def wyslijNaEkran(wiadomosc:String)=println(wiadomosc)
val ekranCommand=commandFunction(wyslijNaEkran)_
val ekranONCommand=ekranCommand("ON")
val ekranOFFCommand=ekranCommand("OFF")
To jest bardzo ale to bardzo ciekawy fragment. PNie wiem jak w tej kolorowance kodu pogrubić konkretne fragmenty także powiem na co trzeba zwrócić uwagę
  1. Trzecia para nawiasów w pierwszej linii. To jest potrzebne aby po wywołaniach w liniach 6 i 7 nie otrzymać wartości a funkcję bezparametrową : ekranONCommand : () => Unit = <function0>. Jeśli można inaczej to ja nie znam.
  2. W linii piątej jest na końcu taki podkreślnik, który oznacza, że aplikujemy tylko pierwszy argument do funkcji i w wyniku mamy : ekranCommand : String => (() => Unit) = <function1>
  3. I generalnie jest zajebista kompozycja. Można sobie tworzyć wiele kanałów komunikacji i wysyłać wiadomości

    egzekutor.execute(ekranONCommand)         //> ON
 egzekutor.execute(ekranONCommand)         //> ON
 egzekutor.execute(ekranOFFCommand)        //> OFF
 egzekutor.execute(ekranOFFCommand)        //> OFF
 egzekutor.execute(ekranONCommand)         //> ON
 egzekutor.replay                          //> ON
                                                  //| ON
                                                  //| OFF
                                                  //| OFF
                                                  //| ON
I elegancko:

Posłowie (W sensie literackim a nie ci złodzieje!)

No i widzimy, że można sobie ładnie zaimplementować wzorzec Command przy pomocy funkcji. Nie wiem czy to tutaj przedstawiłem w 100% pokrywa się z klasycznym wzorcem ale tak w głębi serca mnie to jebie. Pozostaje jeszcze jedna kwestia - co jeśli nie znasz scali i nie możesz rozszyfrować co w tym kodzie jest popisane? Nie przejmuje się - kim jesteś? JESTEŚ ZWYCIĘZCĄ!!!!

*      *      *

poniedziałek, 11 listopada 2013

Programowanie NIeobiektowe

Proponując coś sprzecznego z obiegową opinią - bez względu czy opiera się ona na faktach czy na folklorze ludowym - narażamy się na zmasowany ostrzał z trololo-katiuszy. Na przykład dzieląc się w niektórych wsiach opinią, że niektórzy Niemcy to tak naprawdę mili i uczynni ludzie , zapewne zostaniemy odprowadzeni na widłach do najbliższego dworca PKP (zwłaszcza 11 listopada). Podobnej klasy odpowiedzi mogą nas spotkać na niektórych forach gdy wspomnimy, że są obok rozwiązań obiektowych są inne - nieobiektowe - które też mogą być dobre.

Najpierw zachęta. W Javie 7 chcemy posortować listę Stringów w odwrotnej kolejności. Użyjemy obiektu typu Comparator :

List<String> elements=Arrays.asList("1","2","3");

Collections.sort(elements,new Comparator<String>() {

   @Override
   public int compare(String o1, String o2) {
    return o2.compareTo(o1);
   }
});

for (String element : elements) {
  System.out.println(element);
}

W Javie 8 uzyska się to samo przy pomocy czegoś mniej obiektowego. Po ogarnięciu nowej składni powinno być znacznie czytelniej :

List<String> elements=Arrays.asList("1","2","3");

Collections.sort(elements, (s1, s2) -> s2.compareTo(s1));

elements.forEach( word-> { System.out.println(word); } );

Albo takie coś, filtrowanie i konwersja Stringów do Intów w Javie 7

List<String> elements=Arrays.asList("1","22","11","4444","3","33");

List<Integer> filteredList=new ArrayList<>();

for (String element : elements) {
 if(element.length()==2){
  filteredList.add(Integer.parseInt(element));
 }
}

for (Integer integer : filteredList) {
 System.out.println(integer);
}

I to samo w Javie 8

List<String> elements=Arrays.asList("1","22","11","4444","3","33");

List<Integer> result=elements.stream().filter(e->e.length()==2).map(e->Integer.parseInt(e));

result.forEach( word-> { System.out.println(word); } );

Paradygmaty

Do niedawno żyłem w świadomości, że są tylko dwie szkoły programowania. Pierwsza to ta lśniąca będąca synonimem jakości czyli programowanie obiektowe. Druga uprawiana przez mniej zdolnych ludzi, którzy nie rozumieją jak się programuje obiektowo - programowanie proceduralne. Okazuje się, że jednak nie bo oto jeden z wielu podziałów na paradygmaty wygląda tak :

Otóż poza programowaniem obiektowym i proceduralnym, które są zgrupowane pod kategorią Imperatywne - jest jeszcze jedna kategoria Deklaratywne, w której mamy podkategorię zwaną Programowaniem Funkcyjnym.

Powyższy diagram był dla mnie nie lada zaskoczeniem ( jak to mawiają amerykanie w pornolach "I didn't see it coming" ). Przez dłuższy czas myślałem, że proceduralne,strukturalne czy funkcyjne to jeden ch.. i generalnie ostatni wysyp książek na temat Programowania Funkcyjnego jest spowodowany tym , że rynek lektur obiektowych już się nasycił. I znowu byłem w błędzie. Programowanie Funkcyjne to zupełnie inna para kaloszy i w zasadzie powstało jeszcze przed komputerami zbudowanymi z lamp elektronowych.

Jak to się dzieje, że OOP jest tak popularne? Moim zdaniem aby to zrozumieć należy uzupełnić rysunek o najpopularniejszy obecnie paradygmat w polskich biedronkach informatycznych (a przynajmniej łódzkich)

Otóż wiele osób tonąc w otchłani syfu generowanego przez nierealne deadlajny i pseudo-metodyki projektowe w geście rozpaczy wyciąga rękę po ratunek. I teraz następuje coś takiego jak robienie kroku stojąc pośrodku bieguna północnego czyli gdziekolwiek nie pójdziemy to idziemy na południe. Jeśli dana osoba trafi na materiały o poprawnym podejściu obiektowym to rzecz jasna poprawi jakość kodu technikami obiektowymi (i jest na dobrej drodze aby stać się fanatykiem obiektowym). Jeśli ktoś dla odmiany zacznie stosować poprawnie podejście funkcyjne to również poprawi jakość projektu (i jest na dobrej drodze aby stać się fanatykiem funkcyjnym). Tak czy inaczej idziemy na południe. A, że przynajmniej wśród programistów Javy programowanie obiektowe jest najpopularniejsze to uzyskujemy efekt dodatniego sprzężenia zwrotnego : "Coraz więcej osób używa windowsa gdyż windows jest najpopularniejszy"

Póki kod jest nieczytelny to nie ma znaczenia, którego podejścia użyjemy ponieważ kod o wielkości 10000 linii jest zwyczajnie zjebany bez względu an to czy jest w klasie, funkcji czy procedurze. Dopiero jak to się ogarnie można zastanowić się, które podejście ma jakie zalety.

Jakkolwiek warto tu wspomnieć o jednej ciekawej anomalii w kontekście teorii "Wszystko jest obiektem" - najpopularniejsza i najbardziej przenośna biblioteka Javy wszech czasów nazywa się StringUtils

Programowanie nieobiektowe

Nie chcę nazywać tego paragrafu Programowaniem funkcyjnym gdyż cały czas nie jestem pewny czy moje rozumienie tego tematu jest poprawne. Tak czy inaczej to co mnie uderzyło w trakcie nauki PF to ilość zaufania jakim trzeba obdarzyć autora danego źródła zanim pokaże on jakieś zastosowanie, które mogę użyć w swojej codziennej pracy. Zazwyczaj trzeba cierpliwie odczekać trochę teorii matematycznych oraz przebrnąć przez masę epickich przykładów z szukaniem liczb nieparzystych w zbiorze.

To co spróbuje zrobić poniżej to wyjście od jakiejś tam konstrukcji obiektowej i zakończenie na czymś co ma w zamierzeniach być rozwiązaniem funkcyjnym.

Wizytator

To tak, na początek mamy jakiś obiekt przechowujący kolekcję innych obiektów. Chcemy bez ujawniania jak ta kolekcja jest zaimplementowana dać możliwość operowania na niej w sposób wszelaki. Z tego co pamiętam takie coś robi się przy pomocy wzorca wizytator

public class Company {

 private List<? extends User> users;

 public List<String> visitAll(Visitor visitor){
   List<String> resultList=new LinkedList<>();
   for (User user : users) {
     String result=visitor.apply(user);
     resultList.add(result);
   }
   return resultList;
 }
}
public interface Visitor {
   String apply(User user);
}
public class CapitalizingFirstNameVisitor implements Visitor{

  @Override
  public String apply(User user) {
   return capitalize(user.getFirstName());
  }

  private String capitalize(String firstName) {
   return Character.toUpperCase(firstName.charAt(0))     +firstName.substring(1);
  }
}

Firma ma użytkowników i bez zdradzania tego "w jakiej formie ich ma " pozwala wizytatorowi na manipulacje. W przykładzie powyżej wizytator zwróci listę imion wszystkich użytkowników z Pierwszą literą WIELKĄ (tak jakby ktoś zapomniał przy rejestracji.) Testowanie tego je proste bo to nie ma żadnego stanu ani zależności czyli nic mokować nie trza

@Test
public void shouldCapitalizeFirstName() {
//given
User user=new StandardUser("firstName", "lastName");

//when
String result = new CapitalizingFirstNameVisitor().apply(user);

//then
assertThat(result).isEqualTo("FirstName");
}

Pojawia się powtórzenie w kodzie

public class Category {

private List<Product> products;

public List<String> visitAll(Visitor visitor){
 List<String> resultList=new LinkedList<>();
  for (Product product: products) {
   String result=visitor.apply(product);
   resultList.add(result);
  }
  return resultList;
 }
}

Struktura jest podobna ale deklaracja typów w metodzie wizytatora będzie inna. Na początek postarajmy się użyć wspólnego interfejsu

public interface Visitor<A,B> {
 B apply(A input);
}

public class CapitalizingFirstNameVisitor implements Visitor<User,String>{

@Override
public String apply(User user) {
 return capitalize(user.getFirstName());
}

private String capitalize(String firstName) {
 return Character.toUpperCase(firstName.charAt(0)) +firstName.substring(1);
}
}

I mamy już jakąś reużywalność (jeśli takie słowo w ogóle jest w języku polskim)

public class Category {

private List<Product> products;

public List<String> visitAll(Visitor<Product, String> visitor){...}

}

public class Company {

private List<? extends User> users;

public List<String> visitAll(Visitor<User, String> visitor){...}

}

To tyle jeśli chodzi o interfejs ale cały czas jest problem z implementacją. Jeśli np. chcemy zamienić pierwszą literę nazwy produktu na WIELKĄ to kawałek kodu nadal się będzie powtarzać :

public class CapitalizingProductNameVisitor implements Visitor{

 @Override
 public String apply(Product input) {
  return capitalize(input.getName());
 }

 private String capitalize(String firstName) {
  return Character.toUpperCase(firstName.charAt(0)) +firstName.substring(1);
 }
}

Jeśli ktoś stracił wątek to powtarza się ta prywatna metoda zwiększająca pierwszą literę wyrazu (implementacje z netu skopiowałem)

Repeatability

I co teraz można zrobić? Popularne kroki to np. napisanie StringUtils - a jak. Inni mogą kombinować z wraperam RichString (bardziej obiektowo) albo bezstanowym FirstLetterKapitalizer (też bardziej obiektowo).

Ale pomyślmy teraz o bardzo ciekawym przypadku. Co jeśli mam teraz taką klaskę, która enkapsuluje kolekcję tytułów książek i chcę mieć wizytatora, który zwiększy pierwszą literę każdego tytułu.



public class CapitalizingFirstLetterVisitor implements Visitor<String,String>{

@Override
public String apply(String input) {
    return Character.toUpperCase(input.charAt(0))+input.substring(1);
   }
}

Czyli nie żadne Utilsy czy dziwne wrappery ale kolejny Wizytator. Jak teraz zrobić aby użyć tej funkcjonalności w pozostałych wizytatorach. Czas pomyślenia nad jakimś zunifikowanym sposobem kompozycji wizytatorów aby można było zrobić coś takiego :

public interface Visitor<A,B> {
B apply(A input);

<C> Visitor<A,C> andThen(Visitor<B,C> secondVisitor);
}

Zaczyna się robić coraz ciekawiej. Mamy wizytator który przekształca typ A na B , V1:A=>B i drugi , który zamienia B na C , V2:B=>C . Ponieważ pierwszy zwraca to co drugi przyjmuje na wejściu toteż można napisać coś takiego V3 = V1.andThen(V2) czyli V3 : A=>C.

Teraz mamy :

  • V1 - zwraca imię użytkownika User=>String
  • V2 - Zwiększa pierwszą litere wyrazu String=>String
  • V3 - Zwraca imię użytkownika z zamianą pierwszej litery na wielką User=>String
Podobnie można zrobić dla produktu z "reużyciem" V2 (nie mylić z niemiecką rakietą balistyczną).

Przypomina to znane wywołanie z powłoki popularnego systemu ps -ax | grep java , które jest możliwe gdyż pierwsza instrukcja nie jest w żaden sposób powiązana z kolejną (poza typem). Czyli mamy :

Atomowe operacje (high cohesion?)

public class ProductModule {

 public static final Visitor<String, String> capitalizeFirstLetter=new  GeneralVisitor<String, String>() {

   @Override
   public String apply(String input) {
    return Character.toUpperCase(input.charAt(0))+input.substring(1);
   }
 };

 public static final Visitor<Product, String> retrieveProductName=new  GeneralVisitor<Product, String>() {

   @Override
   public String apply(Product input) {
    return input.getName();
   }
 };
....

}

Linia produkcyjna (low coupling?)


public static final Visitor<Product, String> capitalizeProductName=retrieveProductName.andThen(capitalizeFirstLetter);

Jak to zaimplementować ?


public abstract class GeneralVisitor<A,B> implements Visitor<A, B> {

 @Override
 public <C> Visitor<A, C> andThen(final Visitor<B, C> secondVisitor) {
  return new GeneralVisitor<A, C>() {

     @Override
     public C apply(A input) {
        B firstResult = GeneralVisitor.this.apply(input);
        return secondVisitor.apply(firstResult);
     }
  };
 }
}

Po pierwsze to nie ma coś się bać tej konstrukcji gdyż jest to konstrukcja biblioteczna. Podobnie wiele osób skutecznie używa Listy w javię bez zbędnego interesowania się jak to tam jest zaimplementowane. A druga kwestia to GeneralVisitor.this.apply(input); jest sposobem na wywołanie this na klasie zewnętrznej.

V1 andThen V2 działa tak, ze najpierw jest wywołane V1 a potem V2. Można też w drugą stronę - V1.compose(V2) - najpierw V2 potem V1.


@Override
public <C> Visitor<C, B> compose(final Visitor<C, A>  firstVisitor){
  return new GeneralVisitor<C, B>() {

   @Override
   public B apply(C input) {
    A firstResult = firstVisitor.apply(input);
    return GeneralVisitor.this.apply(firstResult);
   }
  };
}

Grunt aby typy się zgadzały.

public class TextModule {
public static final Visitor capitalizeFirstLetter=new GeneralVisitor() {
   @Override
   public String apply(String input) {
    return Character.toUpperCase(input.charAt(0))+input.substring(1);
   }
 };

 public static final Visitor addPrefix=new   GeneralVisitor() {

  @Override
  public String apply(String input) {
   return "some prefix "+input;
  }
}; 

out.println(capitalizeFirstLetter.andThen(addPrefix).apply("input text"));
//some prefix Input tekst

out.println(capitalizeFirstLetter.compose(addPrefix).apply("input text"));
//Some prefix input tekst

Wstrzykiwanie parametrów

Co jeśli wezmę Wizytatora "addPrefix" z poprzedniego przykładu i będę chciał dodać możliwość ustawiania prefixu?


@Override
public static final TwoArgumentVisitor<String, String, String> addPrefix=new TwoArgumentVisitor<String,String,String>() {
  @Override
  public String apply(String prefix, String text) {
    return prefix+text;
  }
};

public static void main(String[] args) {
 out.println(addPrefix.apply("https://","www.wp.pl"));
 //  https://www.wp.pl
}

Idziemy dalej. Chcę mieć możliwość ustawienia jednego parametru ale tylko raz. Czyli coś jak konfiguracja. Wtedy jeden moduł może konfigurować protokół a inny użyje prekonfigurowanych wizytatorów do budowy URLa


@Override
Visitor<String, String> secureUrl=addPrefix.partiallyApply("https://");

Visitor<String, String> unsecureUrl=addPrefix.partiallyApply("http://");

Visitor<String, String> filetransferUrl=addPrefix.partiallyApply("ftp://");


public static void main(String[] args) {
out.println(secureUrl.apply("www.wp.pl"));
// -> https://www.wp.pl
out.println(unsecureUrl.apply("www.wp.pl"));
// -> http://www.wp.pl
out.println(filetransferUrl.apply("www.wp.pl"));
// -> ftp://www.wp.pl
}

I kodzik dla funkcji bibliotecznej :

public abstract class TwoArgumentVisitor<A,B,C> {

 public abstract C apply(A firstArgument,B secondArgument);

 public Function<B, C> partiallyApply(final A fixedArgument) {
  return new GeneralFunction<B, C>() {

   @Override
   public C apply(B variableArgument) {
    return TwoArgumentVisitor.this.apply(fixedArgument, variableArgument);
   }
  };
 }
 
}

Budowanie z cegiełek

Mając wspomniane wizytatory, możemy łatwo budować coraz to bardziej skomplikowaną funkcjonalność

Visitor<String, String> navigateUserToPurchase=new GeneralVisitor<String, String>() {

  @Override
  public String apply(String userName) {
   return "domain/purchase?name="+userName;
  }
};
   
public static final Visitor<User, String> secureUserNavigation
=getUserFirstName
.andThen(navigateUserToPurchase)
.andThen(secureUrl);
   
out.println(secureUserNavigation.apply(new StandardUser("Czesiek","Kowalski")));
// -> https://domain/purchase?name=Czesiek 

Prawdziwe nazwy

Jakby ktoś nie zgadł to Visitor => Function gdzie Function:A=>B

f andThen g → g(f(x)) ; f compose g → f(g(x))

public interface Function<A,B> {
   B apply(A input);

   <C> Function<A,C> andThen(Function<B,C> secondVisitor);

   <C> Function<C, B> compose(Function<C, A> secondVisitor);
}

Jeszcze jedno powtórzenie

List<? extends User> users=Arrays.asList(
 new StandardUser("roman","Cichocki"),
 new StandardUser("stefan","Zabłocki"));
 Company company=new Company(users);

List<String> names = company.visitAll(new CapitalizingFirstNameVisitor());

for (String name : names) {
 System.out.println(name);
}
   
List<Product> products=Arrays.asList(
  new Product("dietanabol"), 
  new Product("hyper protein 120%"));
  Category category=new Category(products);

  List<String> names = category.visitAll(new CapitalizingProductNameVisitor());

for (String name : names) {
  System.out.println(name);
}  

Co zastępujemy zwykłym :


public class FunctionalList<A> {

 private List<A> elements;

 public <B> List<B> map(Function<A, B> function){
  List<B> resultList=new LinkedList<>();
  for (A element : elements) {
   resultList.add(function.apply(element));
  }
  return resultList;
 }

 public void foreach(Function<A> function){
  for (A element : elements) {
   function.apply(element);
  }
 }
}   

Co nam daje Java 8

Można wywalić masę boilerplaejtu

FunctionalList products=
new FunctionalList<>(Arrays.asList(
 new Product("Rocket Fuel"), 
 new Product("Amino Juice"))
);

products.foreach(new VoidFunction() {
  @Override
  public void apply(Product input) {
    System.out.println(input.getName());
  }
}
);

I dostajemy

FunctionalList products=
new FunctionalList<>(Arrays.asList(
 new Product("Rocket Fuel"), 
 new Product("Amino Juice"))
);

products.foreach(
  input → out.println(input.getName())
);

Ciekawsze zastosowanie - Loan Pattern (Scala)

def withPrintWriter(file: File, 
op: PrintWriter => Unit) {
    val writer = new PrintWriter(file)
    try {
      op(writer)
    } finally {
      writer.close()
    }
  } 

withPrintWriter(
    new File("date.txt"),
    writer => writer.println(new java.util.Date))

withPrintWriter - funkcja biblioteczna i technicznie można pisać bezpieczny kod bez try/catch/finally (jawnie)

Enkapsulacja

Ponieważ mamy tutaj do czynienia z programowaniem deklaratywnym ("tu masz przepis i zrób jak ci wygodnie") to jest dużo miejsca na optymalizacje

public class ParallelFunctionalList<A> {

 private List<A> elements;

 public <B> List<B> map(Function<A, B> function){
  List<B> resultList=new LinkedList<>();
  for (A element : elements) {
   resultList.add(function.apply(element));
  }
  return resultList;
 }

 public void foreach(Function<A> function){
    //elements.split
  //use Fork-join on elements
 }

Zakońćzenie

  1. Czy używam tego w praktyce? - Tak, scala + FunctionalJava dla Javy 7
  2. Kto jest największym hejterem OOP? - Chyba ten pan : http://pl.wikipedia.org/wiki/Rich_Hickey
  3. Kto jest największym hejterem FP? - Wydaje mi się, ze wszelkiej maści analityce od UMLa
  4. Czy można używać OOP + FP? - Moim zdaniem tak i dlatego polecam Scalę
  5. Czy muzyka w filmie na początku jest tam umieszczona legalnie? - Według Youtuba nie i dlatego zablokował dźwięk dla odbiorców z Niemiec
  6. Dlaczego sam sobie odpowiadasz na pytania? - To zapewne początki Schizofrenii
  7. Myślisz, ze ktoś doczyta to do końca? - Nichuja
*      *      *

poniedziałek, 4 listopada 2013

Zdjęcia z mobilizacji

Zdjęcia z mobilizacji

Blogi

Na razie znalazłem jeden wpis :
http://nazargargol.com/2013-mobilization-3-conference-lodz/

Jak ktoś jeszcze ma coś na swoim blogu w tym temacie i chce się podzielić to niech się podzieli.

Scala na courserze

Jutro zaczyna się nowy kurs z udziałem scali :
https://www.coursera.org/course/reactive

*      *      *

niedziela, 20 października 2013

Warsjawa 2013 - Scala i AngularJs

Wstęp

<?php echo $generycznyWstępPochwalnyPoKonferencji ?>

Scalania - wydanie specjalne - Jacek Laskowski

Jacek ma tak rozwinięte zdolności prezentacyjne, że nawet jeśli jego kod nie kompiluje się z niewiadomego powodu to i tak jest w stanie zrobić z tego interesujący punkt programu :)

Generalnie z tego co zauważyłem aby chcieć się nauczyć czegoś nowego trzeba przekonać swój umysł do tego, iż to coś może się przydać i tutaj mamy dwa podejścia :

  • dużo teorii+jakieś ćwiczenia
  • ćwiczenia przeplatane teorią pomagającą je rozwiązać
Na całe szczęście scalania przyjęła drugą formę dzięki czemu jest ciekawie i mamy efekt "o k***a minęła już godzina" zamiast "o k***a minęło dopiero 5 minut". Jest minimum teorii i od razu zabieramy się do zadania. Czas jest ograniczony i całe szczęście - dzięki temu grupy się nie de synchronizują.

Później dyskusje o kodzie i jest git.

Pozostaje jeszcze jedno fundamentalne pytanie - Po co uczyć się Scali . Odpowiemy sobie na to za chwilę ale najpierw umieszczę obrazek aby przerwać monotonię ciągłości tekstu.

Po co uczyć się Scali.

Po pierwsze jest to technologia, która ma o wiele większe możliwości od Javy. Ten aspekt okaże się krytyczny gdy nadejdzie dzień ( a wieżę, że nadejdzie) gdy o konkurencyjności produktu będzie w dużej mierze decydowała technologia użyta do jego wytworzenia a nie minimalizacja ilości błędów w projektach popełniana przez ludzi którzy chcieliby sobie pozarządzać. Nie wiem jak ta sytuacja wygląda w skali całej Polski ale w Łodzi do niedawna było tak, że jak chciałeś sobie kupić mieszkanie+samochód na raty i do tego pojechać na jakieś wakacje to trzeba było uciekać na lepiej płatne pozycje gdzie twoim obowiązkiem było napierdalać jakieś szlaczki w powerpointach i udawać, że potencjalny sukces projektu to głównie twoja zasługa. Wydaje mi się, że trzeba chwilę poprogramować w Javie&Spółka aby odczuć jej ograniczenia - a jeśli robi się uskok ze ścieżki programistycznej po 3 latach aby zostać "JuniorBrandManager" to taki efekt dana osobę ominie. Osobiście subiektywnie odczuwam, że sytuacja się poprawia i zawód programisty zaczyna cieszyć się w naszym mieście coraz większym szacunkiem.

Scala jest trudniejsza od Javy co z jednej strony stanowi pewną przeszkodę w jej adaptacji bo jeśli odpowiednia ilość osób an rynku nie będzie znała tej technologii to firmy nie będą chciały robić przy jej pomocy projektów ( Dlatego kolejny plus dla inicjatyw typu scalania za szerzenie świadomości pośród społeczności). Z drugiej strony ta trudności nauki jest pochodną ogromnych możliwości Scali i stanowi pewien filtr, przez który mogą przejść jedynie osoby dysponujące określoną wiedzą. I może to co tutaj napiszę nie zabrzmi jakoś poprawnie politycznie ale właśnie ta trudność nauki może sprawić, że praca nie będzie uciekać dalej na wschód gdy zarobki w Polsce będą sukcesywnie rosnąć. A to dzięki temu ,że programiści tutaj w Polsce będą w stanie zagwarantować większą produktywność niż X razy tańsi programiści gdzieś tam na wschód.

I kolejny argument, o którym do niedawna nie miałem pojęcia. Scala to już nie jest jakiś tam projekt naukowy z uczelni ale produkt przemysłowy! Martin Odersky dostał kasę i założył firmę Typesafe, która wspiera rozwój Scali. Do tego w zarządzie zasiadł Rod Johnson - to ten, który stworzył Springa. Mając ogromny bagaż doświadczenia zapewne wie jak sprawić aby dana technologia osiągnęła sukces biznesowy. Wygłosił dosyć ciekawy wykład przy okazji ostatnich ScalaDays : http://parleys.com/play/51c1ffe7e4b0d38b54f46231/chapter0/about - kilku nerdom się nie spodobało ale cóż - prawda czasem boli.

AngularJs - Michał Ostruszka

Bardzo pouczający warsztat. Może w końcu uda nam się w firmie stworzyć jakieś porządne testy do javascriptu - na razie jest ciężkie selenium plus średnio wygodne testy Jasminy zagnieżdżone w htmla. Angular ładnie oddziela javascript od htmla i nie ma tego bólu. Do tego sam narzuca pewne poprawne praktyki jak dzielenie kodu na moduły. Na razie moja znajomość tematu jest zbyt mała abym napisał coś więcej ale już zaczęliśmy to cudowdrażać w naszym projektu. Ogólnie warsztat git.

Coś z innej beczki

Chłopaki rzucili ostatnią partię biletów na Mobilization3 - można się rejestrować tutaj : http://2013.mobilization.pl/registration/

Coś z zupełnie ale to zupełnie innej beczki

W zeszłym tygodniu pojawiła się wiadomość, iż naukowcy z jednego z uniwersytetów odkryli, że zarówno hipokamp jak i wątroba potrzebują białka zwanego "PPARalpha" do poprawnej pracy. Hipokamp potrzebuje go do tworzenia nowych "struktur pamięci" zaś wątroba do spalania tłuszczu. Im bardziej zatłuszczony jest organizm tym więcej tego białka potrzebuje wątroba - podprowadzając je hipokampowi - więcej info tutaj : http://www.livescience.com/40440-your-liver-may-be-eating-your-brain.html

Także wbrew mitom z holyłudu - narzucając na siebie dwudziesto-centymetrowy skafander tłuszczowy wcale nie stajemy się romantycznymi bohaterami z bujnym życiem wewnętrznym ale przeciętnymi ludźmi z upośledzoną pracą mózgu. Także wio na siłownie i nie opierdalać się!

niedziela, 6 października 2013

Obiektowe i funkcyjne obszary mózgu

Jeśli przyjmiemy dosyć ciekawe definicje programowania obiektwego i funkcynego podane w tej oto prezentacji :

czyli :
  • Programowanie obiektowe - obiekty jako podstawowe funkcje abstrakcji
  • Programowanie funkcyjne - funkcje jako podstawowe funkcje abstrakcji
to może okazać się, że różnica jest nie tylko w tym z jakich "klocków" (nie mylić z klockami lego albo wc) będzie zbudowany system ale również w tym jak będzie odbierał go nasz mózg.

Lingwistyka w służbie narodu

A to dlatego, iż kilka lat temu (zdaje się, że w 2010) dwójka hiszpańskich psychologów (z nazwiskami, które nikomu nic nie powiedzą) i Niemiecki neurolog (z nazwiskiem, które...) postanowiła poskanować mózgi ludzi uczących się rzeczowników oraz czasowników i zobaczyć co z tego wyjdzie.

Gdy ludzie leżeli sobie słodko w romantycznej komorze do skanów słyszeli takie zdania jak : Otworzyłem amelinium aby wsiąść do samochodu , Otworzyłem amelinium by przepuścić kobietę w ciąży - wtedy z kontekstu mozna wywnioskować, iż amelinum to coś ala drzwi.

Podobnie z czasownikami - Byłem głodny, więc farełałem puszkę z fasolą , Farełałem drzwi od samochodu - tutaj farełać oznacza "otworzyć"

Według badań przy nauce tych dwóch słów pracują u nas inne części móżgu. Rzeczowniki (czyli obiekty) - obszar mózgu odpowiedzialny za procesowanie wizualne , kategoryzowanie, rozpoznawanie twarzy (to ciekawe). Zaś za rozpoznawanie czasowników(Funkcji) odpowiedzialne były obszary "od gramatyki" i jakieś tam jeszcze.

Wnioski

Ponieważ to na razie ciekawostka także żadnych praktycznych wniosków na chwilę obecną nie ma. W artykule do którego link będzie (jeśli tylko nie zapomnę) na samym dole naukowcy deklarują, że podobno znaczenie rzeczowników łatwiej wyłapać z kontekstu. Być może dlatego wygodniej jest rysować kwadraty w uml jako symbole rzeczowników a nie czasowników? A może to nic nie znaczy?

Tak czy inaczej lingwistyka może być dosyć ciekawym kierunkiem dla lepszego zrozumienia zależności pomiędzy typami danych i przekształceniami w systemach.

A oto linki, o których nie zapomniałem :

poniedziałek, 30 września 2013

Jak wywołać funkcję "Eureka"

Jeśli założymy, że informatycy to pracownicy fizyczni wtedy faktycznie nagradzanie za ilość linii kodu ma sens - bo nagradzany jest fizyczny wysiłek mięśni zginacza palca środkowego i sąsiednich. Ale ponieważ (mam niesamowicie ogromną nadzieję!!!) większość populacji rozumie już, że to jest bzdura i informatyk/programista to pracownik o charakterze intelektualno-kreatywnym, którego praca polega na rozwiązywaniu problemów - toteż ma sens największy aby skupić się właśnie na tym - problemach (i rozwiązaniach).

Problemy (i rozwiązania)

Okazuje się, że problemy możemy rozwiązać na dwa sposoby :

  • Ewolucyjny/Analityczny - do rozwiązania dochodzimy przyrostowo. Mając elementy A,B i C tworzymy liniowo różne kombinacje aż na coś natrafimy. Przypomina to trochę próbę wcelowania po pijaku właściwym kluczem do zamka w drzwiach
  • Rewolucyjny/Kreatywny - mając elementy A,B i C nagle (ni z tego ni z owego) zauważamy pewną naturę rzeczy - element A można podzielić na D i E i zestawić z B tak, że powstanie nieoczekiwana kombinacja (słynny eksperyment ze świeczką)

I co z tego? Podział jak podział... A jednak okazuje się, że w dużej mierze wiadomo co tam się pod czaszką w momencie "Eureka" dzieje

(I tutaj małe ostrzeżenie - jeśli czytelnik wyznaje klasyczny tu i ówdzie pogląd, że programistę trzeba zajechać aby "zoptymalizować" jego produktywność to niech przestanie czytać i pójdzie pooglądać Kubę Wojewódzkiego czy coś w tym stylu bo to co napiszę poniżej nie przypasuje mu do światopoglądu :( )

Neurologia olśnienia

(zrodlo : http://openi.nlm.nih.gov/detailedresult.php?img=387268_pbio.0020097.g002&req=4

Bohaterem historyjki jest niejaki Mark Jung-Beeman - neurolog z ważnego uniwersytetu w USA, którego nazwa fajnie by brzmiała, dodała powagi tekstowi ale nikt i tak je nie zapamieta. Jako spec od prawej półkuli mózgowej pewnego dnia sam przeżył olśnienie (plus masa wiedzy i paredziesiąt lat doświadczenia) iż skomplikowana natura języka wymusza jego procesowanie przez obydwie półkulę a nie tylko lewą - zwaną analityczną.

Beeman zaprojektował eksperyment, który polegał na tym aby znaleźć związek pomiędzy grupą wyrazów. Zakładał, że dla prostej grupy algorytm rozwiązywania będzie miał charakter analityczny ale już dla niecodziennego zestawu mózg będzie musiał zastosować jakąś sztuczkę. (Np zestaw {droga,przystanek, pasażer} - dosyć prosto - autobus | ale już dla {książka,spodnie,oklaski} - tak łatwo związku znaleźć się nie da - mól - zwłaszcza przy ograniczonym czasie)

A że na szczęście technologia jest coraz lepsza to można wykonywać takie fajne foty mózgu(fMRI), z kolorowaniem fragmentów pracujących. Plan był taki, że ludzie będą rozwiązywali zagadki siiedząc w komorze do robienia skanów. Niestety fMRI ma kilka sekund opóźnienia przez co nie udawało się zarejestrować "Eureki". Wtedy Beeman skumał się z kolesiem zwanym John Kounios, który to eksperymentował z inną technologią badania mózgu - EEG. Ta technologia dawała natychmiastowy wynik ale bez informacji, który rejon mózgu działał.

Postanowili połączyć te dwie technologie a wynik widzimy na obrazku trzy akapity powyżej:

Eksperyment

Chwile przed olśnieniem wyglądają tak :
  1. Faza przygotowawcza - wysoka aktywność płata czołowego. Moc obliczeniowa przekazana jest na szukanie rozwiązania problemu. Zmysły wydają się być uciszone (a przynajmniej obszary mózgu odpowiedzialne za ich obsługę - umysł nie chce być rozpraszany)
  2. Faza szukania - początkowo skupienie jest utrzymane. Aktywna jest lewa półkula (ośrodek mowy) ale gdy przez kilka sekund nie udaje się nagle wykres EEG wykazuje duża aktywność fal gamma (25-100Hz). W teorii falę gamma w naszym mózgu towarzyszą powstawaniu nowych sieci neuronalnych. I Wułala - właśnie został rozbudowany nasz mózg i siedzimy tak zastanawiając się "dlaczego wcześniej na to nie wpadliśmy" - przecież to (teraz) takie oczywiste!

Co się Co się co się stało

Badacze zauważyli to co widać na obrazku - aktywność w prawej półkuli. W teorii prawa półkula lepiej łączy różne koncepcje ale robi to mniej dokładnie niż półkula lewa. Na początku mózg skupia się na problemie ale później musi przerwać tę uwagę aby dać działać prawej półkuli.

Jakieś dziwne umysły mogłyby powyższy akapić odczytać w sposób - "aha czyli należy rozpraszać programistów" Nie, ku*wa nieee. Poniższy filmik odpowie dokładniej na to pytanie:

A to dlatego, że zanim pojawi się krótka aktywność gamma scalająca sieci neuronowe - swoją obecność zaznacza inna mózgowa "fala". Mózg działa w częstotliwości alfa (8-12HZ) w stanie relaksu. Medytacja, trans, relaks, spacer do Żabki - to wtedy mózg jest w stanie skanować pamięć w celu znalezienia kreatywnego rozwiązania. Hen hen czasu temu czytałem, że przy tej częstotliwości najefektywniej zachodzi wymiana informacji pomiędzy półkulami jakkolwiek teraz nie chce mi się szukać badań.

Swoje trzy grosze dołożył tutaj niejaki Joy Bhattacharya (a psychologist at Goldsmiths, University of London - kolejna fajna nic nie znacząca nazwa uniwersytetu). W trakcie swoich badań zaobserwował na wykresie EEG wzrost natężenia fal alfa na 8 sekund przed "olśnieniem". Kilka fajnych cytatów z tych badań:

"unless subjects have sufficient alpha-wave activity they won’t be able to make use of hints the researchers give them."

To poniżej jest zajebiste!

"If you’re in an environment that forces you to produce and produce, and you feel very stressed, then you’re not going to have any insights."
"If you want to encourage insights, then you’vegot to also encourage people to relax.

Cholera znowu coś co stoi w sprzeczności ze szkołą zarządzania "optymalizacji użycia klawiatury". Czyżby jednak wyciskanie ludzi i szlifowanie dedlajnów mogło nie być najlepszym środkiem do zwiększenia produktywności w IT? Za każdym razem gdy znajduję takie badanie boję się, że gdzieś tam w krainie wyssanych z dupy harmnonogramów ginie gantowa wróżka

Ciekawy przypadek

Tak dla przypomnienia - istnieje jeszcze częstotliwość beta (16-20hz). W tym stanie mózg działa w trakcie "nie-relaksacji" i wyostrzonego skupienia. Jakkolwiek tutaj na ciekawy przypadek natrafił Kounios (to ten od EGG) w trakcie swoich badań. Otóż pewnego dnia uczestniczył w nich mistrz ZEN (to taka forma medytacji). Koleś nie był w stanie rozwiązać żadnych z puzzli - aż za nadto panował nad swoim umysłem w pełni skupiając się na problemie.

I nagle - w chwili pewnej - ZEN koleś zamienił się w prawdziwą maszynę do kreatywnego rozwiązywania zagadek. Generalnie tak zajebiście panował nad umysłem, że był w stanie skupić się na tym aby na niczym się nie skupiać. (To jest generalnie jedno z fajnych ćwiczeń w medytacji. Spróbujcie zamknąć oczy i nie myśleć o niczym - na samym początku można w tym stanie przesiedzieć maks kilka-kilkanaście sekund.

Do wspaniałych rzeczy jakie może dać medytacja w IT jeszcze kiedyś wrócimy.

Pracuje/niepracuje

Jestem na siłce i nagle do głowy przychodzi mi pewne rozwiązanie problemu z pracy. Najczęściej są to małe rzeczy związane designem komponentów/klas/funkcji w aplikacji ale czasami zdarzają się rzeczy relatywnie "przełomowe" jak np. ostatnio pomysł na wyciągnięcie części funkcjonalności do generowania raportów wewnętrznych do osobnej aplikacji co znacznie usprawniło rilisy (niby takie oczywiste a jednak przez ponad rok żaden mózg od pacyfiku poprzez stawy Jana w Łodzi o tym nie pomyślał). Początkowo myślałem, że to kwestia ukrwienia móżgu w trakcie ćwiczeń ale teraz widzę ogromny wpływ "stanu psychologicznego"

I teraz pytanie - jak to liczyć do czasu pracy? Rozwiązuje problemy z pracy to jestem w pracy? A jeśli siedzę przy klawiaturze i zastanawiam się czy zamknąłem drzwi od domu - to jest w pracy ale nie w pracy? I jak w kontekście tych rozważań ma się to zalecenie aby siedzieć 8 godzin przy klawiaturze? I czy czytniki przy drzwiach mają sens czy może raczej jakieś skanery mózgu?

Czy jeśli coś cokolwiek co napisałem powyżej ma sens to czy "optymalizacja czasu przy klawiaturze" driven development ma jakiś sen? Czy logowanie godzin i inne takie mają jakiś sens jeśli takie zbiory jak {"umysł","kreatywność","olśnienie","rozwiązanie"} {"liniowość","przewidywalność","plan","determinism"} lubią być zajebiście rozłączne?

Oczywiście cały czas gdzieś tam istnieje frakcja, według której jakiś zajebisty koleś w zajebiście brzmiącej roli wszystko wymyśli a małp.. znaczy programiści maja nie myśleć tylko robić. No cóż, był kiedyś taki odcinek przygód Tytusa gdzieś pewnej grupie ziomków wlali dosłownie olej do głowy - polecam lniany tłoczony na zimno - podobno ma dużo omega-3 .

Eureka i scala

Ostatnio mam relatywnie często olśnienia w trakcie rozkminy koncepcji ze scali. Covariance i Contravariance zczaiłem pomiędzy seriami na mięsień dwugłowy ramienia (zwany na dyskach osiedlowych "Bajcem"). Natomiast olśnienie odnośnie ostatniego zadania drugiego tygodnia kursu funkcyjnej scali (implementacja mapowania na symbolicznej reprezentacji zbiorów) przyszła z falą teścia po treningu nóg.

A no i kiedyś jak biegałem z ulotkami to nagle zaczaiłem jak powstaje drganie w układzie kondensator-cewka.

LINKI

niedziela, 15 września 2013

Jak stres w IT zabija kreatywność

Jak poruszyć anty-mainstreamowy temat i nie doprowadzić do jałowego trollowania?

Na przykład stwierdzenie "warto prowadzić zdrowy tryb życia" ma ogromny "potencjał strollowania" (np. "można żyć bez papierosów - tylko po co?" czy coś w tym stylu). Dużo trudniej trollować fakt - "mięśnie składają się z włókien białych i czerwonych" - chociaż może jakiś mistrz ciętej riposty i tutaj się wykaże.

Podobnie taka oto teza "stres w każdej postaci szkodzi produktywności w IT" może łatwo przerodzić się w trollo dyskusje ot chociażby poprzez stwierdzenie - "o nie nie, ja mam doświadczenie i jak raz przycisnąłem ludzi to produkt był w dwa tygodnie gotowy". No i zaczyna się problem ponieważ nasze subiektywne opinie i wspomnienia zazwyczaj mają mało wspólnego z rzeczywistością - i na ten temat są tysiące stron literatury naukowej.

Znacznie lepiej przenieść dyskusję na poziom bardziej ...mechaniczny.

Jak stres wyłącza neurogenezę

Bodziec

Najpierw pojawia się bodziec dla rozpoczęcia procesu - zagrożenie. Generalnie my - jako ludzie - mamy taki oficjalny "zbiór rzeczy stresowych" jak np. "to uczucie kiedy biegnie na ciebie coś dużego z 20 centymetrowymi kłami" czy też głośny dźwięk lub nagła utrata równowagi. Oczywiście każdy człowiek poprzez swoje niepowtarzalne życie tworzy wariację tego zbioru i tak np. hycel może się uodpornić na warczenie psa a ktoś inny nabędzie strachu przed zamkniętymi pomieszczeniami (czyli np. idziesz o dwunastej do sklepu i boisz się, że będzie zamknięty)

Są dwa bardzo interesujące bodźce korporacyjne do których powrócimy później.

Kortykotropina (ACTH)

O tym punkcie wspominam w zasadzie tylko dlatego, że słowo "Kortykotropina" zajebiście nadaje się do ćwiczenia wysławiania się. Sam mam wadę wymowy, więc mi pomaga - także wszyscy na trzy- cztery

  • Kortykotropina
  • Kortykotropina
  • Kortykotropina

Kortykotropina syntetyzowana przez przysadkę mózgową wali w nadnercza co zmusza je do produkcji hormonu stresu - kortyzolu (a nednercze to tutaj --> Nadnercze)

Tryb - "walcz lub uciekaj"

Kortyzol to taki globalny sygnał dla organizmu "Mamy kłopoty - koniec zabawy".

Kortyzol zatrzymuje "development organizmu". Mięśnie przechodzą w stan katabolizmu (rozpad), spowolnione zostaje działanie układu odpornościowego (nie czas na zwalczanie wirusów - za chwile coś może nam odrąbać głowę.

Bardzo ciekawe rzeczy dzieją się gdy kortyzol uderza w mózg - ciekawe zwłaszcza dla zawodów wymagających kreatywności

Zakręt zębaty i neurogeneza

Zakręt zębaty (Dentate_gyrus) to zajebisty kawałeczek mózgu. Do niedawna (przynajmniej relatywnego niedawna) uważano, że mózg rozwija się tylko w dzieciństwie i jeśli rodzicie spieprzą nam ten okres życia to już nie ma ratunku. Okazuje się, że proces tworzenia nowych neuronów,połączeń i struktur jest kontynuowany nawet w dorosłym mózgu a jedną z centralnych rol w tym procesie pełni właśnie zakręt zębaty.

"Zakręt zębaty" generuje nowe neurony i wspomaga tworzenie nowych struktur na potrzeby tworzenia nowych wspomnień związanych z eksploracją nowych środowisk czy też odnajdywaniem nowych zależności pomiędzy starymi koncepcjami - kreatywność? Brzmi jak kreatywność. A co z tym obszarem mózgu robi kortyzol? --- W Y Ł Ą C Z A !----

Tak oto doszliśmy do tego jak stres wyłącza kreatywność. Oczywiście nie mam swojego laboratorium i to co tutaj napisałem to moja własna interpretacja przeglądu literatury fachowej. Ale jeśli to prawda to powyższe dane rzucają nowe światło na psudo-techniki managerskie pod tytułem "wywrę na nich presję kłamiąc, że deadline jest dwa tygodnie wcześniej" (a słyszałem o takich). Oczywiście jest jeszcze jedno ale - czy programowanie to bardziej praca kreatywna czy mechaniczna?

Oczywiście, że kreatywna...

... a wcześniejsze pytanie było tylko retoryczne. Niestety nadal na rynku istnieją ludzie wierzący w industrialny podział na tych co myślą i na tych co robią. Właśnie taki totalny fail jak waterfall zakładał, że mądrzy ludzie zaprojektują a programiści "przeklepią". Cóż, jeśli jeszcze gdzieś jakiś beton w to wierzy to powyższe go nie przekona.

Natomiast jeśli ktoś uważa, że projekt IT to epickie zmagania z niezwykłą złożonością i że bez względu na metodykę i rolę w projekcie, każdy poprzez kontakt z innym wycinkiem tej złożoności jest w stanie użyć swojej kreatywnej mocy aby poprzez wartościowy feedback i pro aktywną postawę usprawnić stan projektu - wtedy witam w krainie mądrości i rozumu.

a i jeszcze jedno...

Oksytocyna

Oksytocyna to antagonista kortyzolu. To jest w sumie temat na osobny wpis ale tutaj wspomnę, że oksytocyna to tzw. "hormon więzi międzyludzkiej" - a nawet nie tylko międzyludzkiej. Dlatego właśnie gdy czujemy stres i ktoś okaże nam wsparcie to wtedy tak jakby czujemy się bezpieczniej. A jeśli komuś potrzeba bardziej naukowego przykładu - młode szczury oddzielone od matek w ciągu 48 godzin tracą dwa razy więcej komórek mózgowych w korze mózgu niż te nie oddzielone.

Korporacyjne źródła stresu

Dedlajn dedlajnem ale są dwie inne ciekawe kwestie, które mogą wpłynąć na nasz poziom stresu i naszą produktywność :

  1. Co ma wspólnego : wyprzedaż w MediaMarkt, ostatnie wolne miejsce w autobusie i dwie babcie, ostatni spadochron w spadającym samolocie i korporacyjny system bonusowy oparty o krzywą Gaussa? - są to ograniczone zasoby
  2. Czy jeśli macie znerwicowanego przełożonego, którego w kuchni mianowali odpowiednikiem męskiej części ciała i taki oto ktoś stoi wam za plecami to czujecie się bardziej czy mniej kreatywnie? W nasŧępnym odcinku(lub odcinkach) opowiemy sobie o teorii osobowości A i B - a także czy sama obecność przełożonego, lidera czy autorytetu może wzmocnić stres i wyłączyć kreatywność

A na koniec kilka linków oraz doskonale zagrany fragment filmu - gdzie możecie sobie zobaczyć jak płynnie zmienia się centrum "statusu i siły" poprzez zachowanie i jak wpływa ono na procesy osób uczestniczących w scence (procesy oczywiście udawane przez aktorów ale właśnie za to trzepią tyle kasy, że tak dobrze to udają)

niedziela, 11 sierpnia 2013

Covariance i Contravariance dla prostych ludzi jak ja

Temat jest bardzo ciekawy ale przy pierwszej styczności istnieje duże prawdopodobieństwo przepalenia zwojów mózgowych jeśli nie byłeś/byłaś nań wcześniej eksponowany. Warto jednak przyjrzeć się mu bliżej gdyż występuje kilku relatywnie nowych językach ale trudno napotkań nań w Javie - przez co znowu ludzie mogą pewnego dnia zostać zaskoczeni nowtym ficzerem Javy 13 podczas gdy cały świat na około będzie miał już to od dawna. Także nie ma co czekać.

W Javie relacje pomiędzy typami prostymi i typami wyższego rzędu możemy skonfigurować tylko w jeden sposób - brak jakiejkolwiek relacji - to się nazywa Invariance . Możliwe są jeszcze inne typy zależności

  • Covariance gdzie List[Object] jest faktycznie rodzicem List[String]
  • Contravariance gdzie List[Object] jest - uwaga !- dzieckiem List[String] co jest trochę na pierwszy rzut oka bez sensu ale w sumie bezsens wynika z napromieniowania mózgu imperatywną Java bo w przypadku funkcji covariance szybko staje się naturalne.

Oczywiście jeśli ktoś zarabia na kolejną ratę kredytu pisząc w Javie i mu z tym dobrze może wyrazić wątpliwość : "ale po co mi to? Ja nie chcę scali!"

Już nie tylko scala

Otóż sytuacja trochę zmieniła się od czasu gdy ten artykuł powstał w 2013 .Gdy go aktualizuję za oknem jest maj 2016 a świat ujrzała pierwsza oficjalna wersja języka Kotlin. Kotlin jest produktem JetBrains - firmy powszechniej kochanej i uwielbianej za ich IDE (to bez ironii - Intellij jest bardzo dobre). Ponieważ owa firma słucha developerów i dopasowuje się w ich gusta od kilkunastu lat to można śmiało stwierdzić, że wiedzą co robią.

No i jak tak spojrzymy na składnię Kotlin-a - Kod wprost z dokumentacji to naszym oczom ukaże się :

val a: Int = 10000
print(a === a) // Prints 'true'
val boxedA: Int? = a
val anotherBoxedA: Int? = a
print(boxedA === anotherBoxedA) // !!!Prints 'false'!!!
Ten kod tak w 90% wygląda jak Scala... Tak drogi czytelniku - firma, która od kilkunastu lat robi jedno z lepszych IDE dla programistów Javy i zna ten język an wylot. Z jakiegoś powodu postanowiła zerwać z dotychczasowa składnią Javy na rzecz składni "scalopodobnej".

Ale co ważne w kontekście tego artykułu to informacja, że i tam pojawia się jakaś forma contravariance i covariance. Może więc czas obok funkcji praktycznej zauważyć funkcję edukacyjna nowych języków? Niestety wygląda na to, że Java pomimo swej dojrzałości zostaje w tyle za innym językami i warto zadbać o swoją edukację "poza Javą".

A oto link do przykładu : https://kotlinlang.org/docs/reference/generics.html#declaration-site-variance

abstract class Source<out T> {
  abstract fun nextT(): T
}

abstract class Comparable<in T> {
  abstract fun compareTo(other: T): Int
}

Poniżej dla porównania kawałek .Net. Wygląda podobnie do tego kotlinowego kodu i znów pokazuje, że te koncepcje ogólnie nie są nowe. Nowe sa jedynie dla Javy.

public delegate TResult Func<in T, out TResult>(
    T arg
)

Przykłady obyczajowe

Generalnie aby nauka szła gładko warto sprząc przyswajaną wiedzę z wiedzą już posiadaną. A do tego jeśli owa posiadana wiedza ma charakter towarzysko - obyczajowy to powinno być i pożytecznie i zabawnie. Dlatego też tematem przewodnim w poniższych przykładach będzie wóda.

Ale o soooo chozzii...

W trakcie nauki programowania funkcyjnego tu i ówdzie napotyka się zestaw słówek: contrvariance,contravariance i invariance . W zasadzie to przy okazji lektury Javy też można na nie natrafić - najczęściej przy okazji generyków - ale ponieważ w Javie nie ma czegoś takiego jak declaration site variance dlatego też ów temat schodzi na poboczny tor.

Convariance i Contravariance są szczególnie ważne w kontekście funkcji, które wejście mają contravariant a wyjście covariant - oczywiście funkcje w większości języków bo jest jeden który tego tam nie ma i pozostawię czytelnikom do zgadnięcia który...

Generalnie w Javie można zadeklarować pewne zależności pomiędzy typami a listami jedynie przy deklaracji referencji do listy a nie listy samej w sobie.

List<String> strings=new LinkedList<>();
//List<Object> objects=strings; //compilation error

List<? extends Object> objectsAndChilds=strings;

Podobnego problemu nie ma Scala w przypadku listy "immutable".

val strings:List[java.lang.String]=List("1","2","3")
val objects:List[java.lang.Object]=strings

Jak i w kotlinie możemy to zrobić bezproblemowo

val list: List<String> =listOf("1","2","3")
val anys:List<Any> = list

Gdzież jest źródło tego oto zachowania?

Deklaracje

Deklaracja Listy w Scali i w Kotlinie mają obok generyka dodatkowe znaczki.

sealed abstract class List[+A] 
public interface List<out E> 

Własnie owe magiczne znaki sprawiają, że zachodzi odpowiednia relacja pomiędzy listą a przechowywanym wewnątrz jej typem. Warunek : Lista musi być "po angielsku immutable". Jeśli to był szok to co się stanie gdy zerkniemy do funkcji?

trait Function1[-T1,+R]

O ile Covariance (to z plusem) jeszcze jest jakoś intuicyjne o tyle Contravariance(to z minusem) już może czesać bańke. Dlatego też zilustrujemy mechanizm przykładem (obyczajowym)

Przyklad życiowy

Poniżej hierarchia klas, która posłuży nam do wytłumaczenia tematu. Domeną jest zestaw młodego chemika-smakosza :

class Alkohol
class Metanol extends Alkohol
class Etanol extends Alkohol
class Browar extends Etanol
class RozwodnionyBrowar extends Browar
class Wóda extends Etanol

Teraz jeszcze jakie haj order funkszyn w kontekście sklepu osiedlowego :

class SklepOsiedlowy{
 val browar=new Browar

 def realizujUsluge(usluga:Browar => String) = usluga(browar)
}

I nadchodzi teraz Clu wpisu na którym swego czasu zdzierałem sobie zwoje. Pamiętając, że cały czas obowiązuje zasada, iż do funkcji można przekazać albo deklarowany typ albo coś co z niego dziedziczy (jak w Javie) to które funkcje z poniższych można przekazać do "sklepu osiedlowego"?

val uslugaSpozywcza=(napój: Browar)=> "piję "+ napój //bramka nr 1
val kiepskaUslugaSpozywcza=(rozwodnionyNapój: RozwodnionyBrowar)=> "piję "+rozwodnionyNapój //bramka nr 2
val generycznaUslugaSpozywcza=(jakiśNapój: Alkohol) => "piję "+jakiśNapój //bramka nr 3

Pierwszy mindfuck przez jaki musiałem przebrnąć to "czucie" funkcji jako typu. Po latach siedzenia w Javie mój mózg cały czas próbuje widzieć je jako metody a nie dane same w sobie i cała koncepcję funkcji sprowadza do wywołania. Na szczęście znajomość javascriptu trochę tu pomaga ( ale i trochę przeszkadza). W każdym razie sklep osiedlowy ma metodę, która przyjmuje funkcję typu : TYP na wejściu Browar , TYP na wyjściu String. Na pewno do tego typu pasuje uslugaSpozywcza bo na wejściu ma Browar a na wyjściu String.

I właśnie tutaj pojawia się arcy ciekawe pytanie: która funkcja jest podtypem funkcji uslugaSpozywcza ? Paradoksalnie okazuje się, że podtypem jest... generycznaUslugaSpozywcza - tak to co przyjmuje "nadtyp" - jako funkcja staje się "podtypem".

Skąd ten potencjalny mindfuck? Być może w mózgu dzieje się coś takiego : jak RozwodnionyBrowar jest podtypem Browaru to zwoje kory szarej chcą aby funkcja, która przyjmuje RozwodnionyBrowar była tez podtypem funkcji, która przyjmuje Browar - ale jest odwrotnie! - dlatego pewnie nazywa się to CONTRAvariance (i ten minusik trait Function1[-T1,+R]).

Wytłumaczenie - podejście pierwsze

Wróćmy do kawałka kodu :

val browar=new Browar
def realizujUsluge(usluga:Browar => String) = usluga(browar)

A w szczególności tego fragmentu usluga(browar). Generalnie chodzi o to, żeby funkcja jakiej tutaj użyjemy mogła przyjąć TYP Browar.

  • val uslugaSpozywcza=(napój: Browar)=> "piję "+ napój - MOŻE
  • val generycznaUslugaSpozywcza=(jakiśNapój: Alkohol) => "piję "+jakiśNapój - MOŻE BO BROWAR TO ALKOHOL
  • val kiepskaUslugaSpozywcza=(rozwodnionyNapój: RozwodnionyBrowar)=> "piję "+rozwodnionyNapój - NIE MOŻE BO BROWAR TO NIEKONIECZNIE ROZWODNIONY BROWAR

Wytłumaczenie - podejście Drugie

Dla odmiany inna hierarchia

    class Kulturysta
    class Koksu extends Kulturysta
    class KoksuZMikrofonem extends Koksu

    val napierdalanie=(k: Kulturysta)=>"napierdalanie"
    val wywiady=(k:Koksu)=>"wywiady"
    val koksuSpiewaZgwiazdami=(k: KoksuZMikrofonem)=>"spiewanie"

    val telewizja = (fk:Koksu=>String)=>"dzisiaj w  telewizji" + fk(new Koksu)

    telewizja(wywiady)                                //> res1: String = dzisiaj w  telewizji wywiady
    telewizja(napierdalanie)                          //> res2: String = dzisiaj w  telewizji napierdalanie
    //telewizja(koksuSpiewaZgwiazdami) - to się nie kompiluje

Mamy tutaj standardowego koksa jako argument przekazywany do funkcji, która to funkcja (z racji tego, że sama jest typem) została przekazana do funkcji wyższego rzędu. Nasz standardowy koks może wziąć udział w wywiadach bo ta funkcja oczekuje właśnie koksa. Może wziąć udział w napierdalaniu (czyli ćwiczeniach), gdyż ta funkcja oczekuje dowolnego kulturysty czyli jest podtypem każdej funkcji, która przyjmuje koksa bo można ją zawsze przekazać w jej miejsce. Ostatnia funkcja oczekuje specyficznego koksa z mikrofonem i tutaj niestety kod się nie kompiluje.

A teraz to drugie z plusem

Teraz druga część - COVARIANCE. To jest bardziej intuicyjne bo tutaj typy idą niejako w tym samym kierunku co funkcje : trait Function1[-T1,+R]). Ponownie użyjemy znanej struktury typów

class Alkohol
class Metanol extends Alkohol
class Etanol extends Alkohol
class Browar extends Etanol
class RozwodnionyBrowar extends Browar
class Wóda extends Etanol

I do tego metodki :

val generycznaReceptaSpozywcza=()=>new Etanol
val receptaNaBrowar= ()=> new Browar
val receptaNAWódęZMety=() => new Metanol

class Wytwornia{
 def realizuje(recepta:() => Etanol) = recepta()
}

Mamy klasę wytwórnia, która spodziewa się bezparametrowej funkcji zwracającej Etanol. Czyli na bank do wywołania pasuje generycznaReceptaSpozywcza. No i dalej już powinno być jaśniej, że nie można tykać metody z Metanolem bo ludzie poumierają. Idzie taki Zdzisław do sklepu i zamiast produktu do konsumpcji spożywczej dostaje paliwo rakietowe (nie mylić z rocket fuel). Ale jak zamiast dowolnego Etanolu dostanie Browara to jest ok. Czyli tutaj funkcja, która jest podtypem również zwraca podtyp - to powinno być łatwiejsze do zrozumienia.

Post Scriptum o przykładzie

Pomimo, że przykład alkoholowy używa mainstrimowej analogii to jednocześnie pragnę przypomnieć, że alkohol w dużych dawkach jest niezdrowy.

Dalsza Lektura

Doskonałą lekturą uzupełniającą jest tenże link == o tutaj ==> Covariance_and_contravariance_(computer_science). I chociaż czasem ludzie podchodzą trochę nieufnie do artykułów na wikipedii to jednak informacje techniczne moim zdaniem są tam umieszczony w sposób obiektywny, zorganizowany i łatwy w nawigacji.