tag:blogger.com,1999:blog-50476320374949013722024-02-25T13:56:00.033+01:00Paweł Włodarski - ludzka twarz ITTematyka bloga zakreśla obszar technologii komputerowych z akcentem na centralną rolę jednostki ludzkiej jako napędu procesu wytwarzania oprogramowania (plus standardowe tematy egzystencjalno- informatyczne)Paweł Włodarskihttp://www.blogger.com/profile/04891037231290616803noreply@blogger.comBlogger162125tag:blogger.com,1999:blog-5047632037494901372.post-56844293860810792042019-03-07T11:46:00.000+01:002019-03-07T11:46:00.313+01:00Odmagicznianie<p class="akapit">
Patrząc na aplikację na jednym końcu jest framework (tu i ówdzie nazywany przez starych ludzi <b>zrębem</b>) a na drugim assembler, kod maszynowy, elektrony czy inne kwarki w zalezności od tego jak głęboko chcesz wchodzić.
Im wyższy poziom tym - w teorii - powinno się szybciej pracować, gdyż ukrywana przed nami jest skomplikowana drobnica, ale - w praktyce - i tak prędzej czy później dostaniesz plaskacza w twarz od warstw poniżej (tutaj można klasycznie zaliczkować do artykułu o "cieknących abstrakcjach" z 1413 roku)
</p>
<p>
No i miała miejsce taka konkretna sytuacja. Robię warsztaty z nowego API Kotlina na Springu. To API jest fajne bo tam nie ma żadnych adnotacji (dlaczego to jest fajne to jeszcze o tym w naszym artykule będzie) i wykorzystując wiele z bardziej zaawansowanych kotlinowych mechanizmów pozwala zbudować konfigurację beanów,restów itd tylko i wyłącznie przy pomocy czystego kodu.
</p>
<p>
Warsztaty były z Kotlina. To API springowe dosyć dobrze napisane to myślę sobie - będzie to dobra ilustracja mechanizmów. Jednakże po zanurkowaniu w głąb kodu kilku osobom poleciała para z mózgu i tam przy okazji smoltoków padła taka koncepcja, ze w sumie może lepiej było zostać na poziomie wywołań i nie wchodzić w szczegóły.
</p>
<p>
Otóż wydaje mi się, że jednak nie byłoby lepiej. I to nie tylko dlatego, że taka przygoda ma to samo w sobie wartość edukacyjną w kontekście nauki Kotlina. Jest jeszcze jeden aspekt całej sprawy...
</p>
<h1> #10yearsczelendż - JDD 2009 </h1>
<p>
Rok 2009 - czyli w świeci informatyki jakieś dwa wieki temu - był rokiem ciekawym. Wyobraź sobie, że świat jest w czymś czego młodzież IT rzucająca 10K na wejście jeszcze nie zna a co się nazywa "Kryzys Światowy".Java 6 jest szczytem nowoczesności. Youtube ma rozdzielczość 320p a zamiast fejsbuka jest nasza-klasa.
</p>
<p>
I właśnie wtedy miałem przyjemność uczestniczyć w konferencji JDD 2009 gdzie przyjechał pewien typ od JMS. No i tenże człowiek miał między innymiwykład o tym "jak NIE życ" czyli o antywzorcach w programowaniu. Lub coś takiego, coś w ten deseń. Było kilka ciekawych antywzorców ale nas interesuje ten jeden gdzie było coś o "magi" i pamiętam, że pokazał kawałek kodu z adnotacją @Transactional.
</p>
<pre>
@Transactional
public void metoda(){
..
}
</pre>
<p>
To był Spring <i>3.coś</i> i kontekst użycia magi polegał na tym, że ludzie wrzucali te adnotacje i mało kto wgłębiał się jak to działa. No i okazało się, ze w zależności od typu wyjątku jaki poleci - checked czy unchecked - działa to inaczej. Czasem będzie rollback a czasem nie (przynajmniej tak to działało A.D. 2009 )
</p>
<h1>Separacja i edukacja</h1>
<p>
Pomocne nam teraz będą dwa kawałki kodu.
</p>
<p>
Pierwszy przedstawia konfigurację RESTa adnotacjami. I widząc ten kawałek kodu w zasadzie trudno jest stwierdzić co się stanie. Trudno jest stwierdzić kiedy to się stanie.Trudno odpowiedzieć na pytanie czy jakiś wrapper będzie generowany w trakcie kompilacji, a może coś będzie czytać przez refleksję te adnotacje i jakaś bliżej nieokreślona logika pojawi się naokoło naszej klasy?
</p>
<p>
Dokładne przestudiowanie dokumentacji jest potrzebne - co samo w sobie nie musi być złe - ale to wymaga mocy skupienia aby zadość uczynić warunkowi <i>"dokładne"</i>. A jak życie pokazuje dokumentacja może mieć nieścisłości, może mieć braki i dziury. Być może jest jakiś specjalny plugin do IDE, który powiąże adnotacje z miejscem wywołania i jakoś zbadać ten kod - ale raz, że nie wnikałem czy w ogóle coś takiego istnieje - a dwa, że uzależnia nas to od kolejnej rzeczy, kolejnego narzędzia.
</p>
<pre class="kotlin" style="font-family:monospace;"><ol><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">@RestController</div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">@RequestMapping<span style="color: #009900;">(</span><span style="color: #0000ff;">"/foos"</span><span style="color: #009900;">)</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000000; font-weight: bold;">class</span> FooController <span style="color: #009900;">{</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> </div></li><li style="font-weight: bold; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> @Autowired</div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #000000; font-weight: bold;">private</span> IFooService service<span style="color: #339933;">;</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> </div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> @GetMapping</div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #000000; font-weight: bold;">public</span> List<span style="color: #339933;"><</span>Foo<span style="color: #339933;">></span> findAll<span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span></div></li><li style="font-weight: bold; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #000000; font-weight: bold;">return</span> service.<span style="color: #006633;">findAll</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #009900;">}</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> </div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> @GetMapping<span style="color: #009900;">(</span>value <span style="color: #339933;">=</span> <span style="color: #0000ff;">"/{id}"</span><span style="color: #009900;">)</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #000000; font-weight: bold;">public</span> Foo findOne<span style="color: #009900;">(</span>@PathVariable<span style="color: #009900;">(</span><span style="color: #0000ff;">"id"</span><span style="color: #009900;">)</span> <span style="color: #000066; font-weight: bold;">Long</span> id<span style="color: #009900;">)</span> <span style="color: #009900;">{</span></div></li><li style="font-weight: bold; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #000000; font-weight: bold;">return</span> RestPreconditions.<span style="color: #006633;">checkFound</span><span style="color: #009900;">(</span> service.<span style="color: #006633;">findOne</span><span style="color: #009900;">(</span> id <span style="color: #009900;">)</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #009900;">}</span></div></li></ol></pre>
<p>
Do tego dochodzi jeszcze jeden ważny aspekt czyli - <i>"kiedy tak naprawdę dowiem się, że coś zrobiłem źle i ile czasu zmarnuje aby rozpocząć naprawę buga"</i>. Kompilacja następuje (czasem dużo) wcześniej niż testy/odpalenie aplikacji - także jeśli <b>czas to pieniądz</b> to jest widoczna oszczędność pieniędzy. I znowu mogą pomóc jakieś pluginy do IDE tylko,że wiecie - naprawdę te pluginy <b>to rozwiązanie sztucznego problemu, który sami sobie zrobiliśmy...</b>
</p>
<p>
Teraz patrz na to:
</p>
<pre class="kotlin" style="font-family:monospace;"><ol><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000000; font-weight: bold;">fun</span> helloRouterFunction<span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #339933;">:</span> RouterFunction<span style="color: #339933;"><</span>ServerResponse<span style="color: #339933;">></span> <span style="color: #009900;">{</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #666666; font-style: italic;">//This one uses official kotlin DSL for building Routerfunction and Handlerfunctions</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #000000; font-weight: bold;">return</span> router <span style="color: #009900;">{</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> GET<span style="color: #009900;">(</span><span style="color: #0000ff;">"/hello"</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span> _ <span style="color: #339933;">-></span></div></li><li style="font-weight: bold; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #666666; font-style: italic;">//and below is HandlerFunction</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> ok<span style="color: #009900;">(</span><span style="color: #009900;">)</span>.<span style="color: #006633;">body</span><span style="color: #009900;">(</span>just<span style="color: #009900;">(</span><span style="color: #0000ff;">"Hello World!"</span><span style="color: #009900;">)</span>, <span style="color: #003399;">String</span><span style="color: #339933;">::</span><span style="color: #000000; font-weight: bold;">class</span>.<span style="color: #006633;">java</span><span style="color: #009900;">)</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #009900;">}</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #009900;">}</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009900;">}</span></div></li></ol></pre>
<p>
Ok, jest to jakaś konstrukcja, której działania muszę się domyśla. Dokumentacja może być a może jej nie być. A Może mam jakieś specyficzne scenariusze, których nie ma w dokumentacyjnych hello worldach? Tutaj mam opcję! To zwykły kod. Można pobrać źródła , <b>ctrl+b</b> i juz patrzę co to za <i>router</i>
</p>
<pre class="kotlin" style="font-family:monospace;"><ol><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000000; font-weight: bold;">fun</span> router<span style="color: #009900;">(</span>routes<span style="color: #339933;">:</span> RouterFunctionDsl.<span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #339933;">-></span> <span style="color: #000066; font-weight: bold;">Unit</span><span style="color: #009900;">)</span> <span style="color: #339933;">=</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> RouterFunctionDsl<span style="color: #009900;">(</span><span style="color: #009900;">)</span>.<span style="color: #006633;">apply</span><span style="color: #009900;">(</span>routes<span style="color: #009900;">)</span>.<span style="color: #006633;">router</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span></div></li></ol></pre>
<p>
Jest to prosta linijka kodu - prosta kiedy znasz kotlina, ale po to robię warsztaty - i jak już tego kotlina się umie czytać to to jest bardzo oczywiste co tutaj się dzieje. Jest taki builderek nazwany tutaj DSLem , do którego wpakujemy ustawienia routera. Na końcu jak to w builderach bywa jest wywołanie metody <b>build</b> , która tutaj nazywa się <b>router</b>
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj18irJT6QGLFlSa0ZOBVsY1TaRlwGAg4iNpejw2Dif0quXBXPfQ4WAgaOT__Z8ZR3LgJJjNTeRtkGUMkRM0dgGA5_ajRnwAhtig7MmYVnJJ35YwbwL4TeCNThZYjdWZKgcwZkk7gwuB7g/s1600/mem_zamiast_ryby_nakarmi__ci_.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj18irJT6QGLFlSa0ZOBVsY1TaRlwGAg4iNpejw2Dif0quXBXPfQ4WAgaOT__Z8ZR3LgJJjNTeRtkGUMkRM0dgGA5_ajRnwAhtig7MmYVnJJ35YwbwL4TeCNThZYjdWZKgcwZkk7gwuB7g/s400/mem_zamiast_ryby_nakarmi__ci_.png" width="400" height="363" data-original-width="600" data-original-height="544" /></a></div>
<p>
I teraz taka zagadka. Dlaczego mogę sobie napisać <b>GET</b> w środku <i>routera</i> ale już poniższe się nie kompiluje?
</p>
<pre class="kotlin" style="font-family:monospace;"><ol><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">GET<span style="color: #009900;">(</span><span style="color: #0000ff;">"/hello"</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span> _ <span style="color: #339933;">-></span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #666666; font-style: italic;">//and below is HandlerFunction</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #666666; font-style: italic;">// Handler function is explained in IntroSpring2</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #666666; font-style: italic;">//and Reactor api in IntroSpring2 and MonoDemo</span></div></li><li style="font-weight: bold; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> ok<span style="color: #009900;">(</span><span style="color: #009900;">)</span>.<span style="color: #006633;">body</span><span style="color: #009900;">(</span>just<span style="color: #009900;">(</span><span style="color: #0000ff;">"Hello World!"</span><span style="color: #009900;">)</span>, <span style="color: #003399;">String</span><span style="color: #339933;">::</span><span style="color: #000000; font-weight: bold;">class</span>.<span style="color: #006633;">java</span><span style="color: #009900;">)</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #009900;">}</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #000000; font-weight: bold;">return</span> router <span style="color: #009900;">{</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #666666; font-style: italic;">//for explanation how GET is build take a look at IntroSpring2</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #009900;">}</span></div></li></ol></pre>
<p>
By <b>odmagicznić</b> sytuację zwyczajnie włażę w implementację tej metody i widzę, ze jest to metoda instancji wcześniej widzianego buildera, która modyfikuje stan tejże instancji - NO RACZEJ ma to sens by wołać ja w kontekście jakiegoś obiektu, EJ HELOŁ!
</p>
<pre class="kotlin" style="font-family:monospace;"><ol><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #008000; font-style: italic; font-weight: bold;">/**</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #008000; font-style: italic; font-weight: bold;"> * Route to the given handler function if the given request predicate applies.</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #008000; font-style: italic; font-weight: bold;"> * @see RouterFunctions.route</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #008000; font-style: italic; font-weight: bold;"> */</span></div></li><li style="font-weight: bold; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #000000; font-weight: bold;">fun</span> GET<span style="color: #009900;">(</span>pattern<span style="color: #339933;">:</span> <span style="color: #003399;">String</span>, f<span style="color: #339933;">:</span> <span style="color: #009900;">(</span><span style="color: #003399;">ServerRequest</span><span style="color: #009900;">)</span> <span style="color: #339933;">-></span> Mono<span style="color: #339933;"><</span>ServerResponse<span style="color: #339933;">></span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> routes <span style="color: #339933;">+=</span> RouterFunctions.<span style="color: #006633;">route</span><span style="color: #009900;">(</span>RequestPredicates.<span style="color: #006633;">GET</span><span style="color: #009900;">(</span>pattern<span style="color: #009900;">)</span>, HandlerFunction <span style="color: #009900;">{</span> f<span style="color: #009900;">(</span>it<span style="color: #009900;">)</span> <span style="color: #009900;">}</span><span style="color: #009900;">)</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #009900;">}</span></div></li></ol></pre>
<h1>Wędka zamiast adnotacji</h1>
<p>
No i morał z tego taki, że im to wszystko, całe te mechanizmy są mniej przekombinowane tym naprawdę łatwiej rozkminić co się dzieje bo dokumentacji czasami jest jej jak na lekarstwo. Np. to Nowe API kotlinowe w springu to na jakimś blogu znalazłem opisane a dalej to sam już drążyłem i wynikiem sa materiały na gitbooku :
<p>
<a href="https://pawelwlodarski.gitbooks.io/kotlin-workshops/content/spring/intro.html"></a>
</p>
No i też te całe adnotacje interpretowane w runtime to trochę taki PHP napisany w Javie, macie dwa poziomy języka. To jest złe.
</p>
<h1> Warsztat na segfault university </h1>
<p>
Ten temat w formie 4-wymiarowego warsztatu poruszę na Segfault University w gdańsku w następnym tygodniu. Zapisywać można się chyba gdzieś tutaj : <a href="http://segfault.events/sites/gdansk2019/speakers/pawel-wlodarski/">http://segfault.events/sites/gdansk2019/speakers/pawel-wlodarski/</a>
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizGdGorVXtIOZ33PhKJucxTs4q4go0kk81_hkeLO1hSjIYAL228-LfXMR1Qe7iaLl48VdZF8qcLrwJYJR3jVBhojNQNzEexhidc2dvG-8NGNUrN8ziN0jWSjFQBh9x5jRlBH-2J7c8k4E/s1600/lublin2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizGdGorVXtIOZ33PhKJucxTs4q4go0kk81_hkeLO1hSjIYAL228-LfXMR1Qe7iaLl48VdZF8qcLrwJYJR3jVBhojNQNzEexhidc2dvG-8NGNUrN8ziN0jWSjFQBh9x5jRlBH-2J7c8k4E/s400/lublin2.jpg" width="400" height="267" data-original-width="1600" data-original-height="1067" /></a></div>Paweł Włodarskihttp://www.blogger.com/profile/04891037231290616803noreply@blogger.com0tag:blogger.com,1999:blog-5047632037494901372.post-23028503011734952442019-01-19T20:39:00.000+01:002019-01-19T20:39:35.003+01:00Kotlin plus Spring minus Adnotacje<p class="akapit">
Spring 5 dodał nowy - bardzo wygodny - sposób konfiguracji naszych przy użyciu prostych funkcji <i>STOP</i> Owo podejście nie wymaga stosowania adnotacji ani manipulacji bajtkodem <i>STOP</i> Co więcej Spring dostarcza natywne wsparcie dla Kotlina wykorzystując jego specyficzne mechanizmy, które znacznie upraszczają kod <i>STOP</i> A ponieważ nie jednego flejma o technologiach widziałem to we filozofie brnąć nie będę <i>STOP</i> A Tutaj jak ktoś chce są opisane problemy z adnotacjami <a href="https://blog.softwaremill.com/the-case-against-annotations-4b2fb170ed67">The case against annotations</a> <i>STOP</i>
</p>
<h2>Skoro o kodzie mowa</h2>
<p class="akapit">
Rozpoczynając prezentację - dla potrzeb naszego przykładu edukacyjnego stworzymy następująca kolekcję typów, która to kolekcja pozwoli nam zobrazować jak wygląda konfiguracja z użyciem Kotlinowego DSL-a. Jakies interfejsy, kilka 'binów' i działamy :
</p>
<pre class="kotlin" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">interface</span> I1
<span style="color: #000000; font-weight: bold;">interface</span> I2
<span style="color: #000000; font-weight: bold;">class</span> Bean1 <span style="color: #339933;">:</span> I1
<span style="color: #000000; font-weight: bold;">class</span> Bean2<span style="color: #009900;">(</span>dependency<span style="color: #339933;">:</span>I1<span style="color: #009900;">)</span> <span style="color: #339933;">:</span> I2
<span style="color: #000000; font-weight: bold;">class</span> Bean3<span style="color: #009900;">(</span>dependency<span style="color: #339933;">:</span>I2<span style="color: #009900;">)</span></pre>
<p>
Aby użyć DSLka wystarczy jeden import :
</p>
<b>import org.springframework.context.support.beans</b>
<p>
No i już możemy pracować z bardzo - w moim odczuciu - przyjemnym kodem. I w moim osobistym odczuciu to naprawdę jest dosyć czytelna konfiguracja, która jednocześnie jest silnie typowana, czyli kompilator pilnuje nam pleców ,wyłapuje wszelkie babole , troszczy się itd:
</p>
<pre class="kotlin" style="font-family:monospace;"><ol><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">beans <span style="color: #009900;">{</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> bean<span style="color: #339933;"><</span>Bean1<span style="color: #339933;">></span><span style="color: #009900;">(</span><span style="color: #009900;">)</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> bean<span style="color: #009900;">{</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #000000; font-weight: bold;">val</span> i1<span style="color: #339933;">:</span>I1<span style="color: #339933;">=</span>ref<span style="color: #339933;"><</span>Bean1<span style="color: #339933;">></span><span style="color: #009900;">(</span><span style="color: #009900;">)</span></div></li><li style="font-weight: bold; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> Bean2<span style="color: #009900;">(</span>i1<span style="color: #009900;">)</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #009900;">}</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> bean<span style="color: #009900;">(</span><span style="color: #0000ff;">"Bean3"</span><span style="color: #009900;">)</span><span style="color: #009900;">{</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #000000; font-weight: bold;">val</span> i2<span style="color: #339933;">:</span>I2<span style="color: #339933;">=</span>ref<span style="color: #339933;"><</span>Bean2<span style="color: #339933;">></span><span style="color: #009900;">(</span><span style="color: #009900;">)</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> Bean3<span style="color: #009900;">(</span>i2<span style="color: #009900;">)</span></div></li><li style="font-weight: bold; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #009900;">}</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009900;">}</span></div></li></ol></pre>
<p>Powyższy fragment jest standardowym kodem Kotlina - nie ma tam żadnej magii a jedynie wykorzystanie natywnych mechanizmów języka.
Deklarujemy nasze trzy <b>beany</b> pobierając zależności poprzez wywołanie metody. Wszystko jest kodem. Wszystko jest w jednym miejscu. Można to ogarnąć łatwo. Chaosu nie ma.
</p>
<p>A jeśli nie do końca jeszcze wiadomo to, by lepiej zrozumieć sytuację zerknijmy w głąb metod. Mamy tego <b>MR. beans</b> i wygląda to nawet przyjaźnie ale tenże argument init jakis taki dziwny. Jakieś nawiasy po kropce. Co... co się tutaj stanęło?</p>
<pre class="kotlin" style="font-family:monospace;"><ol><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000000; font-weight: bold;">fun</span> beans<span style="color: #009900;">(</span><span style="color: #000000; font-weight: bold;">init</span><span style="color: #339933;">:</span> BeanDefinitionDsl.<span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #339933;">-></span> <span style="color: #000066; font-weight: bold;">Unit</span><span style="color: #009900;">)</span><span style="color: #339933;">:</span> BeanDefinitionDsl <span style="color: #009900;">{</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #000000; font-weight: bold;">val</span> beans <span style="color: #339933;">=</span> BeanDefinitionDsl<span style="color: #009900;">(</span><span style="color: #009900;">)</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> beans.<span style="color: #000000; font-weight: bold;">init</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #000000; font-weight: bold;">return</span> beans</div></li><li style="font-weight: bold; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009900;">}</span></div></li></ol></pre>
<p>
Otóż cała zabawa z tym DSLem jest możliwa dzięki zapisowi <i>“init: BeanDefinitionDsl.() -> Unit”</i> , który definiuje BeanDefinitionDsl jako <b>odbiorcę</b> wywołań w lambdzie (z engielska 'receiver'). Czyli dla przykładu we fragmencie
</p>
<pre class="kotlin" style="font-family:monospace;"><ol><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">beans <span style="color: #009900;">{</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">bean<span style="color: #339933;"><</span>Bean1<span style="color: #339933;">></span><span style="color: #009900;">(</span><span style="color: #009900;">)</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> ...</div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009900;">}</span></div></li></ol></pre>
<p>
Mamy 'implicit this' (dokładnie tak!) i tak naprawdę, wywołujemy
</p>
<pre class="kotlin" style="font-family:monospace;"><ol><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">beans <span style="color: #009900;">{</span> dsl <span style="color: #339933;">-></span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> dsl.<span style="">bean</span><span style="color: #339933;"><</span>Bean1<span style="color: #339933;">></span><span style="color: #009900;">(</span><span style="color: #009900;">)</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> ...</div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009900;">}</span></div></li></ol></pre>
<p>
Teraz pojedynczy <b>'bean'</b>. Tutaj pojawiają się dziwne nowe słowa:
</p>
<pre class="kotlin" style="font-family:monospace;"><ol><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000000; font-weight: bold;">inline</span> <span style="color: #000000; font-weight: bold;">fun</span> <span style="color: #339933;"><</span><span style="color: #000000; font-weight: bold;">reified</span> T <span style="color: #339933;">:</span> Any<span style="color: #339933;">></span> bean<span style="color: #009900;">(</span>....<span style="color: #009900;">)</span><span style="color: #009900;">{</span>....<span style="color: #009900;">}</span></div></li></ol></pre>
<p>
W tej metodzie dzieje się trochę więcej. Generalnie para słów kluczowych <i>“inline”</i> i <i>“reified”</i> w sprytny sposób zachowa informacje o typie z generyka w 'Runtime', dzięki czemu możliwe będzie utworzenie nowej instancji klasy <b>Bean1</b> podanej w generyku. Podobna mechanika kryje się za metodą <i>“ref”</i>, która zwraca nam referencję do już zadeklarowanych beanów.
</p>
<pre class="kotlin" style="font-family:monospace;"><ol><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000000; font-weight: bold;">inline</span> <span style="color: #000000; font-weight: bold;">fun</span> <span style="color: #339933;"><</span><span style="color: #000000; font-weight: bold;">reified</span> T <span style="color: #339933;">:</span> Any<span style="color: #339933;">></span> ref<span style="color: #009900;">(</span>name<span style="color: #339933;">:</span> <span style="color: #003399;">String</span><span style="color: #339933;">?</span> <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">)</span> <span style="color: #339933;">:</span> T <span style="color: #339933;">=</span> </div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #000000; font-weight: bold;">when</span> <span style="color: #009900;">(</span>name<span style="color: #009900;">)</span> <span style="color: #009900;">{</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #000066; font-weight: bold;">null</span> <span style="color: #339933;">-></span> context.<span style="color: #006633;">getBean</span><span style="color: #009900;">(</span>T<span style="color: #339933;">::</span><span style="color: #000000; font-weight: bold;">class</span>.<span style="color: #006633;">java</span><span style="color: #009900;">)</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #339933;">-></span> context.<span style="color: #006633;">getBean</span><span style="color: #009900;">(</span>name, T<span style="color: #339933;">::</span><span style="color: #000000; font-weight: bold;">class</span>.<span style="color: #006633;">java</span><span style="color: #009900;">)</span></div></li><li style="font-weight: bold; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009900;">}</span></div></li></ol></pre>
<p>
Zauważ drogi czytelniku/czytelniczko iż zapis “T::class.java” robi coś niesamowitego i wyciąga klasę z generyka. Magia, po prostu magia….
</p>
<p>
Chociaż nie. Nie magia a nauka.
</p>
<h1>Inicjalizacja</h1>
<p class="akapit">
Caly mechanizm <i>"beans"</i> to tak naprawdę zwykły wzorzec <i>builder</i> i tak jak na klasycznym buiderze wołaliśmy “build()” lub coś podobnego na sam koniec by zapieczętować budowę - tak tutaj przekazujemy do budowy springowy kontekst. Trochę to wygląda na cykliczną zależność ale w zasadzie nie zauważyłem jeszcze z tym problemów.
</p>
<pre class="kotlin" style="font-family:monospace;"><ol><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000000; font-weight: bold;">val</span> ourInit<span style="color: #339933;">:</span> BeanDefinitionDsl <span style="color: #339933;">=</span>beans <span style="color: #009900;">{</span>...<span style="color: #009900;">}</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> GenericApplicationContext <span style="color: #009900;">{</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> ourInit.<span style="color: #006633;">initialize</span><span style="color: #009900;">(</span><span style="color: #000000; font-weight: bold;">this</span><span style="color: #009900;">)</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> refresh<span style="color: #009900;">(</span><span style="color: #009900;">)</span></div></li><li style="font-weight: bold; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009900;">}</span></div></li></ol></pre>
<p>
I kontekst springowy zainicjalizowany naszymi beanami. Żadnych adnotacji nie trzeba, żadnego CGLiba i majstrowania przy bajtkodzie też nie trzeba!!! Ale to nie koniec. Kotlin i Spring 5 dają nam jeszcze więcej udogodnień bo teraz <br/>
skupcie się weźta<br/>
wystawimy resta
</p>
<h1>konfiguracja REST - uważaj na przykłady Javy!</h1>
<p class="akapit">
Przede wszystkim czytając tutoriale do nowego mechanizmu - jak na przykład ten <a href="https://spring.io/blog/2016/09/22/new-in-spring-5-functional-web-framework">https://spring.io/blog/2016/09/22/new-in-spring-5-functional-web-framework </a> - uważaj na użytą składnie Javy, gdyż używając w identyczny sposób Kotlina możesz napotkać na pewne trudności.
Otóż API dla Javy zaleca użycie funkcji <i>“route”</i>, która jest zdefiniowana w sposób następujący
</p>
<pre class="java" style="font-family:monospace;"><ol><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #339933;"><</span>T <span style="color: #000000; font-weight: bold;">extends</span> ServerResponse<span style="color: #339933;">></span> RouterFunction<span style="color: #339933;"><</span>T<span style="color: #339933;">></span> route<span style="color: #009900;">(</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> RequestPredicate predicate, HandlerFunction<span style="color: #339933;"><</span>T<span style="color: #339933;">></span> handlerFunction<span style="color: #009900;">)</span> <span style="color: #009900;">{</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> </div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000000; font-weight: bold;">new</span> DefaultRouterFunction<span style="color: #339933;"><></span><span style="color: #009900;">(</span>predicate, handlerFunction<span style="color: #009900;">)</span><span style="color: #339933;">;</span></div></li><li style="font-weight: bold; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009900;">}</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> </div></li></ol></pre>
<p> Gdzie <i>"HandlerFunction"</i> to prosty interfejs funkcyjny: </p>
<pre class="java" style="font-family:monospace;"><ol><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">@FunctionalInterface</div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> HandlerFunction<span style="color: #339933;"><</span>T <span style="color: #000000; font-weight: bold;">extends</span> ServerResponse<span style="color: #339933;">></span> <span style="color: #009900;">{</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> Mono<span style="color: #339933;"><</span>T<span style="color: #339933;">></span> handle<span style="color: #009900;">(</span><span style="color: #003399;">ServerRequest</span> request<span style="color: #009900;">)</span><span style="color: #339933;">;</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009900;">}</span></div></li></ol></pre>
<p>Używając tego API możemy wygodnie wpisać sobie lambdę tam gdzie oczekiwany jest HandlerFunction a to dlatego, iż Java z automatu konwertuje ową lambdę na tzw. SAM czyli klasę abstrakcyjną/interfejs z jedną metodą. Dzięki temu możemy sobie napisać <b>route(GET(“/”),r->...)</b> . Niestety w Kotlinie przy konwersji lambdy na typ Javy jest potrzebna dodatkowa podpowiedź dla kompilatora: </p>
<pre class="java" style="font-family:monospace;"><ol><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #666666; font-style: italic;">//route(GET("/test"), { r -> ok().body(Mono.just("response")) }) <- to nie pyknie</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> </div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #666666; font-style: italic;">//poniżej podajemy podpowiedź, że ta lambda to HandlerFunction i działa</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">route<span style="color: #009900;">(</span>GET<span style="color: #009900;">(</span><span style="color: #0000ff;">"/test"</span><span style="color: #009900;">)</span>, HandlerFunction <span style="color: #009900;">{</span> r <span style="color: #339933;">-></span> ok<span style="color: #009900;">(</span><span style="color: #009900;">)</span>.<span style="color: #006633;">body</span><span style="color: #009900;">(</span>Mono.<span style="color: #006633;">just</span><span style="color: #009900;">(</span><span style="color: #0000ff;">"response"</span><span style="color: #009900;">)</span><span style="color: #009900;">)</span> <span style="color: #009900;">}</span><span style="color: #009900;">)</span></div></li></ol></pre>
<p>
Dlatego też warto używać dedykowany DSL -wiecie taki natywny ze springa a nie żadny na boku robiony - napisany specjalnie dla Kotlina. Konstrukcja tam użyta jest podobna do tego co widzieliśmy w poprzednim odcinku dla definicji Beanów - czyli dla przypomnienia:
</p>
<pre class="kotlin" style="font-family:monospace;"><ol><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000000; font-weight: bold;">fun</span> beans<span style="color: #009900;">(</span><span style="color: #000000; font-weight: bold;">init</span><span style="color: #339933;">:</span> BeanDefinitionDsl.<span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #339933;">-></span> <span style="color: #000066; font-weight: bold;">Unit</span><span style="color: #009900;">)</span><span style="color: #339933;">:</span> BeanDefinitionDsl <span style="color: #009900;">{</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #000000; font-weight: bold;">val</span> beans <span style="color: #339933;">=</span> BeanDefinitionDsl<span style="color: #009900;">(</span><span style="color: #009900;">)</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> beans.<span style="color: #000000; font-weight: bold;">init</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #000000; font-weight: bold;">return</span> beans</div></li><li style="font-weight: bold; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009900;">}</span></div></li></ol></pre>
<p>
W przypadku definiowania “routingu” wygląda to bardzo ale to bardzo podobnie :
</p>
<pre class="kotlin" style="font-family:monospace;"><ol><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000000; font-weight: bold;">fun</span> router<span style="color: #009900;">(</span>routes<span style="color: #339933;">:</span> RouterFunctionDsl.<span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #339933;">-></span> <span style="color: #000066; font-weight: bold;">Unit</span><span style="color: #009900;">)</span> <span style="color: #339933;">=</span> RouterFunctionDsl<span style="color: #009900;">(</span><span style="color: #009900;">)</span>.<span style="color: #006633;">apply</span><span style="color: #009900;">(</span>routes<span style="color: #009900;">)</span>.<span style="color: #006633;">router</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> </div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">router <span style="color: #009900;">{</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> GET<span style="color: #009900;">(</span><span style="color: #0000ff;">"/hello"</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span> _ <span style="color: #339933;">-></span></div></li><li style="font-weight: bold; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> ok<span style="color: #009900;">(</span><span style="color: #009900;">)</span>.<span style="color: #006633;">body</span><span style="color: #009900;">(</span>just<span style="color: #009900;">(</span><span style="color: #0000ff;">"Hello World!"</span><span style="color: #009900;">)</span>, <span style="color: #003399;">String</span><span style="color: #339933;">::</span><span style="color: #000000; font-weight: bold;">class</span>.<span style="color: #006633;">java</span><span style="color: #009900;">)</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #009900;">}</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009900;">}</span></div></li></ol></pre>
<p>
Jak możecie chyba zgadnąć GET to nic innego jak wywołanie metody na naszym DSLu i aby było jawne, jasne i klarowne co tam się dzieje to dzieję coś takiego :
</p>
<pre class="kotlin" style="font-family:monospace;"><ol><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">router <span style="color: #009900;">{</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #000000; font-weight: bold;">val</span> dsl<span style="color: #339933;">:</span>RouterFunctionDsl <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">this</span> <span style="color: #666666; font-style: italic;">//<- o tutaj cała magia</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> dsl.<span style="color: #006633;">GET</span><span style="color: #009900;">(</span><span style="color: #0000ff;">"/hello"</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span> _ <span style="color: #339933;">-></span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #666666; font-style: italic;">//and below is HandlerFunction</span></div></li><li style="font-weight: bold; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> ok<span style="color: #009900;">(</span><span style="color: #009900;">)</span>.<span style="color: #006633;">body</span><span style="color: #009900;">(</span>just<span style="color: #009900;">(</span><span style="color: #0000ff;">"Hello World!"</span><span style="color: #009900;">)</span>, <span style="color: #003399;">String</span><span style="color: #339933;">::</span><span style="color: #000000; font-weight: bold;">class</span>.<span style="color: #006633;">java</span><span style="color: #009900;">)</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> <span style="color: #009900;">}</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009900;">}</span> </div></li></ol></pre>
<p>
W powyższym przykładzie GET jest po prostu wygodnym opakowaniem na to API dla Javy, o którym mówiliśmy na samym początku :
</p>
<pre class="kotlin" style="font-family:monospace;"><ol><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #000000; font-weight: bold;">fun</span> GET<span style="color: #009900;">(</span>pattern<span style="color: #339933;">:</span> <span style="color: #003399;">String</span>, f<span style="color: #339933;">:</span> <span style="color: #009900;">(</span><span style="color: #003399;">ServerRequest</span><span style="color: #009900;">)</span> <span style="color: #339933;">-></span> Mono<span style="color: #339933;"><</span>ServerResponse<span style="color: #339933;">></span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> routes <span style="color: #339933;">+=</span> RouterFunctions.<span style="color: #006633;">route</span><span style="color: #009900;">(</span>RequestPredicates.<span style="color: #006633;">GET</span><span style="color: #009900;">(</span>pattern<span style="color: #009900;">)</span>, </div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> HandlerFunction <span style="color: #009900;">{</span> f<span style="color: #009900;">(</span>it<span style="color: #009900;">)</span> <span style="color: #009900;">}</span><span style="color: #009900;">)</span></div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #009900;">}</span></div></li><li style="font-weight: bold; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> </div></li><li style="font-weight: normal; vertical-align:top;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"> </div></li></ol></pre>
<p>
I problem “bojlerplejtu” rozwiązany.
</p>
<h2>Mono</h2>
<p>
Zwróć uwagę na sygnaturę funkcji przekazanej do Handlera :
</p>
<b>f: (ServerRequest) -> Mono<ServerResponse></b>
<p>
Czym jest to Mono i jak wpływa na przetwarzanie requestu? O tym w innym odcinku...
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_X7haN6lXoqSHpcoLoqsY5KkvbHtRgcxAwDVxO9T6Yau2GN9nGFiylNxLoOK6T5uqa93OnkMy_xnIv-MC_dY3jx-41wR_o-DNQJQ_khwJ7RBqFKB97nJ8TDDGpvwPgXK9VR8hhOwrUeA/s1600/wysokie38-sloncezagorami.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_X7haN6lXoqSHpcoLoqsY5KkvbHtRgcxAwDVxO9T6Yau2GN9nGFiylNxLoOK6T5uqa93OnkMy_xnIv-MC_dY3jx-41wR_o-DNQJQ_khwJ7RBqFKB97nJ8TDDGpvwPgXK9VR8hhOwrUeA/s320/wysokie38-sloncezagorami.jpg" width="320" height="213" data-original-width="1600" data-original-height="1067" /></a></div>Paweł Włodarskihttp://www.blogger.com/profile/04891037231290616803noreply@blogger.com0tag:blogger.com,1999:blog-5047632037494901372.post-88877824512884919492018-06-04T22:59:00.000+02:002018-06-04T22:59:11.525+02:00Domenowo ale bez alokacji<p class="akapit">
Ten artykuł miał być początkowo wzmianką o ciekawym - acz niszowym mechanizmie - który umożliwia stosowanie pattern matchingu dla prostych typów bez alokacji niepotrzebnych obiektów na stercie. Jednakże w trakcie pisania i zabawy z <b>javap -c ...</b> okazało się, że tak w sumie to ja mam niekompletne pojęcie co się w wielu miejscach wyplutego z programu scali bytekodu JVM dzieje. Stąd też będzie to bardziej ogólny wpis o tym co produkuje kompilator i kiedy płacimy - a kiedy nie - dodatkową alokacją pamięci.
</p>
<h1>"Name based extractors"</h1>
<p class="akapit">
Czasem dobrze zajrzeć do obcego kodu (ale tylko wtedy gdy pisał go ktoś faktycznie znający się na rzeczy) by odnaleźć warte przestudiowania konstrukcje. I taka konstrukcja pojawia się w <b>Akka typed</b>. Wertując bebechy Akki typowanej natrafimy na poniższe :
</p>
<pre style="background:#002240;color:#fff"><span style="color:#08f;font-style:italic"><span style="color:#e1efff">/**</span>
* INTERNAL API
* Represents optional values similar to `scala.Option`, but
* as a value class to avoid allocations.
*
* Note that it can be used in pattern matching without allocations
* because it has name based extractor using methods `isEmpty` and `get`.
* See https://hseeberger.wordpress.com/2013/10/04/name-based-extractors-in-scala-2-11/
<span style="color:#e1efff">*/</span></span>
<span style="color:#ffee80">private</span>[akka] <span style="color:#ffee80">final</span> <span style="color:#ff9d00">class</span> <span style="color:#fd0">OptionVal</span>[+<span style="color:#fd0">A</span> >: <span style="color:#fd0">Null</span>](<span style="color:#ff9d00">val</span> <span style="color:#fd0">x</span>: <span style="color:#fd0">A</span>) <span style="color:#ff9d00">extends</span> <span style="color:#80fcff;font-style:italic">AnyVal</span> {
</pre>
<p>
To jest bardzo interesujące. Zawsze wydawało mi się ,iż <b>AnyVal</b> i <b>PatternMatching</b> wzajemnie się wykluczają gdyż stoi jak wał w oficjalnej dokumentacji :
<div>
<a href="https://docs.scala-lang.org/overviews/core/value-classes.html">https://docs.scala-lang.org/overviews/core/value-classes.html</a>
</div>
<br/>
<div class="dygresja">
A value class is actually instantiated when:
<ol>
<li>a value class is treated as another type. </li>
<li>a value class is assigned to an array.</li>
<li><b>doing runtime type tests, such as pattern matching.</b></li>
</ol>
</div>
</p>
<p>
Wrócimy do tego przykładu ale najpierw krótka wycieczka po alokacji obiektów w scali by lepiej zrozumieć co się dzieje gdy do pracy ruszy kompilator. I tutaj na potrzeby edukacji załóżmy, że chcemy mieć taki domenowy typ dla Miesiąca. Będzie bardziej domenowo i biznesowo. Miesiąc jest podzbiorem <b>inta</b> gdzie kilka wartości ma sens a reszta już niekoniecznie.
</p>
<pre style="background:#002240;color:#fff"><span style="color:#ff9d00">class</span> <span style="color:#fd0">Month</span>(<span style="color:#ffee80">private</span> <span style="color:#ff9d00">val</span> <span style="color:#fd0">n</span>:<span style="color:#ffee80">Int</span>) <span style="color:#ff9d00">extends</span> <span style="color:#80fcff;font-style:italic">AnyVal</span>{
<span style="color:#ffee80">override</span> <span style="color:#ff9d00">def</span> <span style="color:#fd0">toString</span>: <span style="color:#ffee80">String</span> = s"Month($n)"
}
</pre>
<p>
W teorii rozszerzenie <b>AnyVal</b> powinno zapobiec alokacji nowego obiektu na stercie czym zajmie się kompilator zastępując nasz domenowy <b>Month</b> zwykłym intem w trakcie kompilacji. Niestety ta reguła ma wiele wyjątków i czasem alokacja następuje wbrew naszym oczekiwaniom. Zejdziemy teraz dużo niżej by lepiej zrozumieć kiedy coś takiego następuje..
</p>
<h2>Poligon </h2>
<p>
Naszym Poligonem laboratoryjnym będzie domenowy <b>Kalendarz</b>, który operuje na domenowym <b>Miesiącu</b> (wszystko takie domenowe)
</p>
<pre style="background:#002240;color:#fff"><span style="color:#ff9d00">class</span> <span style="color:#fd0">Calendar</span>{
<span style="color:#ff9d00">def</span> <span style="color:#fd0">somethingWithDate</span>(m:<span style="color:#fd0">Month</span>) = {
println(m)
}
}
</pre>
<p>
I po dekompilacji.
</p>
<pre style="background:#002240;color:#fff"><span style="color:#fd0">Compiled</span> from "Poligon.scala"
public <span style="color:#ff9d00">class</span> <span style="color:#fd0">jug.workshops.reactive.akka.typed.Calendar</span> {
public void somethingWithDate(int);
public jug.workshops.reactive.akka.typed.<span style="color:#fd0">Calendar</span>();
}
</pre>
<p>
Na pozór kod po dekompilacji wygląda ok, zamiast <b>Month</b> mamy <b>Int</b> i wydawać by się mogło, że wszystko idzie zgodnie z planem ale czeka nas niemiła niespodzianka...
</p>
<h2>Trochę mechaniki</h2>
<p>
Gdy zanurkujemy do asemblera to zobaczymy :
</p>
<pre style="background:#002240;color:#fff"> <span style="color:#fd0">Code</span>:
<span style="color:#ff628c">0</span>: getstatic #<span style="color:#ff628c">17</span> <span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span> Field scala/Predef$.MODULE$:Lscala/Predef$;</span>
<span style="color:#ff628c">3</span>: <span style="color:#ff9d00">new</span> <span style="color:#fd0">#19</span> <span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span> class jug/workshops/reactive/akka/typed/Month</span>
<span style="color:#ff628c">6</span>: dup
<span style="color:#ff628c">7</span>: iload_1
<span style="color:#ff628c">8</span>: invokespecial #<span style="color:#ff628c">22</span> <span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span> Method jug/workshops/reactive/akka/typed/Month."<init>":(I)V</span>
<span style="color:#ff628c">11</span>: invokevirtual #<span style="color:#ff628c">26</span> <span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span> Method scala/Predef$.println:(Ljava/lang/Object;)V</span>
<span style="color:#ff628c">14</span>: <span style="color:#ff9d00">return</span>
</pre>
<p>
Gdzie w linijce 3 pojawia się <b>new</b> czyli tworzenie nowego obiektu. Jest to zapewne Kochani moi polimorfizm w akcji gdzie <b>println</b> gdzie pod spodem musi być wywołane <b>toString</b> ale ze względu na dziedziczenie nie jest jasne z której klasy i tam cała ta maszyneria idzie w ruch. Bardzo łatwo pozbyć się alokacji usuwając polimorfizm ze sceny.
</p>
<pre style="background:#002240;color:#fff"><span style="color:#ff9d00">class</span> <span style="color:#fd0">Month</span>(<span style="color:#ffee80">private</span> <span style="color:#ff9d00">val</span> <span style="color:#fd0">n</span>:<span style="color:#ffee80">Int</span>) <span style="color:#ff9d00">extends</span> <span style="color:#80fcff;font-style:italic">AnyVal</span> {
<span style="color:#ff9d00">def</span> <span style="color:#fd0">display</span>: <span style="color:#ffee80">String</span> = s"Month : $n"
}
<span style="color:#ff9d00">class</span> <span style="color:#fd0">Calendar</span>{
<span style="color:#ff9d00">def</span> <span style="color:#fd0">somethingWithDate</span>(m:<span style="color:#fd0">Month</span>) = {
println(m.display)
}
}
public void somethingWithDate(int);
<span style="color:#fd0">Code</span>:
<span style="color:#ff628c">0</span>: getstatic #<span style="color:#ff628c">17</span> <span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span> Field scala/Predef$.MODULE$:Lscala/Predef$;</span>
<span style="color:#ff628c">3</span>: getstatic #<span style="color:#ff628c">22</span>
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span> Field jug/workshops/reactive/akka/typed/Month$.MODULE$:Ljug/workshops/reactive/akka/typed/Month$;</span>
<span style="color:#ff628c">6</span>: iload_1
<span style="color:#ff628c">7</span>: invokevirtual #<span style="color:#ff628c">26</span>
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span> Method jug/workshops/reactive/akka/typed/Month$.display$extension:(I)Ljava/lang/String;</span>
<span style="color:#ff628c">10</span>: invokevirtual #<span style="color:#ff628c">30</span>
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span> Method scala/Predef$.println:(Ljava/lang/Object;)V</span>
<span style="color:#ff628c">13</span>: <span style="color:#ff9d00">return</span>
</pre>
<p>
Po tej wycieczce po alokacjach wracamy do pattern matchingu.
</p>
<h2>Pattern Matching bez kosztu</h2>
<p>
Pattern matching bazuje na dekompozycji obiektów i metodzie <b>unapply</b>, która jest takim lustrzanym odbiciem kompozycji i metody apply. Kompilator tutaj dużo działa w tle bo gdy napiszemy poniższą linijkę.
</p>
<pre style="background:#002240;color:#fff"><span style="color:#ff9d00">case</span> <span style="color:#ff9d00">class</span> <span style="color:#fd0">Day</span>(v:<span style="color:#ffee80">Int</span>)
</pre>
<p>
No i każdy początkujący adept scali pewnie wie, że będzie z automatu wygenerowany comanion object, ktory ma 40000 metod a wśród nich <b>unapply</b> do pattern matchingu. Ten unapply ma tę wadę, że tak trochę niepotrzebnie za każdym razem Optiona tworzy który zaraz idzie do kosza.
</p>
<pre style="background:#002240;color:#fff">public <span style="color:#ffee80">final</span> <span style="color:#ff9d00">class</span> <span style="color:#fd0">jug.workshops.reactive.akka.typed.Day$</span> <span style="color:#ff9d00">extends</span> <span style="color:#80fcff;font-style:italic">...</span> {
...
public scala.<span style="color:#fd0">Option</span><<span style="color:#fd0">java</span>.lang.Object> unapply(jug.workshops.reactive.akka.typed.<span style="color:#fd0">Day</span>);
...
}
</pre>
<p>
<b>I tutaj pierwsza niespodzianka dla mnie bo okazuje się, że jednak ta metoda przy case class wcale nie jest używana!!! </b>
</p>
<p>
Według :
<div>
<a href="https://stackoverflow.com/questions/24227037/unapply-method-of-a-case-class-is-not-used-by-the-scala-compiler-to-do-pattern-m">https://stackoverflow.com/questions/24227037/unapply-method-of-a-case-class-is-not-used-by-the-scala-compiler-to-do-pattern-m</a>
</div>
</p>
<div class="dygresja">
However, when we get to pattern matching (§8.1), case classes have their own section on matching, §8.1.6, which specifies their behaviour in pattern matching based on the parameters to the constructor, without any reference to the already-generated unapply/unapplySeq:
</div>
<p>
Oraz:
<div>
<a href="https://stackoverflow.com/questions/8783226/scala-case-class-unapply-vs-a-manual-implementation-and-type-erasure">https://stackoverflow.com/questions/8783226/scala-case-class-unapply-vs-a-manual-implementation-and-type-erasure</a>
</div>
</p>
<div class="dygresja">
I can tell you that even though the compiler generates an unapply method for case classes, when it pattern matches on a case class it does not use that unapply method
</div>
<p>
No i faktycznie żadnego unapply w asemblerze nie widać. Dopiero gdy zmienimy <b>case class</b> na zwykłą klasę to <b>unapply</b> pójdzie w ruch z alokacją Optiona.
</p>
<pre style="background:#002240;color:#fff"><span style="color:#ff9d00">class</span> <span style="color:#fd0">Day</span>(<span style="color:#ff9d00">val</span> <span style="color:#fd0">v</span>:<span style="color:#ffee80">Int</span>)
<span style="color:#ff9d00">object</span> <span style="color:#fd0">Day</span>{
<span style="color:#ff9d00">def</span> <span style="color:#fd0">unapply</span>(<span style="color:#ccc">arg</span>: <span style="color:#fd0">Day</span>): <span style="color:#fd0">Option</span>[<span style="color:#ffee80">Int</span>] = <span style="color:#fd0">Some</span>(arg.v)
}
</pre>
I asembler :
<pre style="background:#002240;color:#fff"><span style="color:#ff628c">63</span>: invokevirtual #<span style="color:#ff628c">45</span>
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span> Method jug/workshops/reactive/akka/typed/Day$.unapply:(Ljug/workshops/reactive/akka/typed/Day;)Lscala/Option;</span>
public scala.<span style="color:#fd0">Option</span><<span style="color:#fd0">java</span>.lang.Object> unapply(jug.workshops.reactive.akka.typed.<span style="color:#fd0">Day</span>);
<span style="color:#fd0">Code</span>:
<span style="color:#ff628c">0</span>: <span style="color:#ff9d00">new</span> <span style="color:#fd0">#17</span> <span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span> class scala/Some</span>
<span style="color:#ff628c">3</span>: dup
<span style="color:#ff628c">4</span>: aload_1
<span style="color:#ff628c">5</span>: invokevirtual #<span style="color:#ff628c">23</span>
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span> Method jug/workshops/reactive/akka/typed/Day.v:()I</span>
<span style="color:#ff628c">8</span>: invokestatic #<span style="color:#ff628c">29</span>
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span> Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;</span>
<span style="color:#ff628c">11</span>: invokespecial #<span style="color:#ff628c">32</span>
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span> Method scala/Some."<init>":(Ljava/lang/Object;)V</span>
<span style="color:#ff628c">14</span>: areturn
</pre>
<h2>Ale po co tam option?</h2>
<p>
Odsuwając ideologie programowania w kont - z punktu widzenia pattern matchingu to option trochę tak z ch*ja jest. A to dlatego, że jeśli o sam Pattern Matching chodzi to my jako programiści tego Optiona nie tykamy, nie widzimy, nie wykorzystujemy - to je taka wewnętrzna rzecz - i w złym świecie programowania można to opykać bez alokacji na parze wartość/null - pewnie usuną z czatu monadowego ale garbage collector powinien chodzić trochę lepiej - co kto lubi i potrzebuje emocjonalnie w życiu.
</p>
<h2>Zastosowanie</h2>
<p>
Jak użycie tego wygląda w Akka (Acce) ? W ActorContextImpl (ku*wa lata uczenia młodzieży by nie dawała w nazwach Impl i ch** wszystko strzelił) znajdziemy
</p>
<pre style="background:#002240;color:#fff"> <span style="color:#ffee80">private</span> <span style="color:#ff9d00">var</span> <span style="color:#fd0">messageAdapterRef</span>: <span style="color:#fd0">OptionVal</span>[<span style="color:#fd0">ActorRef</span>[<span style="color:#fd0">Any</span>]] = <span style="color:#fd0">OptionVal</span>.<span style="color:#ff628c">None</span>
</pre>
<p>
I dalej mamy pattern matching
</p>
<pre style="background:#002240;color:#fff"><span style="color:#ff9d00">val</span> <span style="color:#fd0">ref</span> = messageAdapterRef <span style="color:#ff9d00">match</span> {
<span style="color:#ff9d00">case</span> <span style="color:#fd0">OptionVal</span>.<span style="color:#fd0">Some</span>(ref) ⇒ ref.asInstanceOf[<span style="color:#fd0">ActorRef</span>[<span style="color:#fd0">U</span>]]
<span style="color:#ff9d00">case</span> <span style="color:#fd0">OptionVal</span>.<span style="color:#ff628c">None</span> ⇒ ...
}
</pre>
<p>
Tak jak ja to osobiście rozumiem - działają w tym miejscu dwa extractory. Pierwszy bezpośrednio w <b>OptionVal</b>. Ale ale zaczynają dziać się rzeczy ciekawe bo żadnego unapply tam nie ma - znajdziemy dwie metody potrzebne do tego całego <b>"name based extraction"</b>.
</p>
<pre style="background:#002240;color:#fff"><span style="color:#ffee80">private</span>[akka] <span style="color:#ffee80">final</span> <span style="color:#ff9d00">class</span> <span style="color:#fd0">OptionVal</span>[+<span style="color:#fd0">A</span> >: <span style="color:#fd0">Null</span>](<span style="color:#ff9d00">val</span> <span style="color:#fd0">x</span>: <span style="color:#fd0">A</span>) <span style="color:#ff9d00">extends</span> <span style="color:#80fcff;font-style:italic">AnyVal</span> {
...
<span style="color:#ff9d00">def</span> <span style="color:#fd0">get</span>: <span style="color:#fd0">A</span> =
<span style="color:#ff9d00">if</span> (x == <span style="color:#ff628c">null</span>) <span style="color:#ff9d00">throw</span> <span style="color:#ff9d00">new</span> <span style="color:#fd0">NoSuchElementException</span>("OptionVal.None.get")
<span style="color:#ff9d00">else</span> x
<span style="color:#ff9d00">def</span> <span style="color:#fd0">isEmpty</span>: <span style="color:#ffee80">Boolean</span> = x == <span style="color:#ff628c">null</span>
...
}
</pre>
<p>
Wracamy do naszego laboratorium by sprawdzić co takiego dzieje się pod spodem. Na początek przypomnijmy co mamy :
</p>
<pre style="background:#002240;color:#fff"><span style="color:#ff9d00">class</span> <span style="color:#fd0">Month</span>(<span style="color:#ffee80">private</span> <span style="color:#ff9d00">val</span> <span style="color:#fd0">n</span>:<span style="color:#ffee80">Int</span>) <span style="color:#ff9d00">extends</span> <span style="color:#80fcff;font-style:italic">AnyVal</span> {
<span style="color:#ff9d00">def</span> <span style="color:#fd0">isEmpty</span>:<span style="color:#ffee80">Boolean</span> = n < <span style="color:#ff628c">0</span> || n > <span style="color:#ff628c">12</span>
<span style="color:#ff9d00">def</span> <span style="color:#fd0">get</span>:<span style="color:#ffee80">Int</span> = n
<span style="color:#ff9d00">def</span> <span style="color:#fd0">display</span>: <span style="color:#ffee80">String</span> = s"Month : $n"
}
<span style="color:#ff9d00">object</span> <span style="color:#fd0">Month</span>{
<span style="color:#ff9d00">def</span> <span style="color:#fd0">unapply</span>(<span style="color:#ccc">v</span>: <span style="color:#fd0">Int</span>) = <span style="color:#ff9d00">new</span> <span style="color:#fd0">Month</span>(v)
}
</pre>
<p>
Co umożliwi nam poniższe zabawy.
</p>
<pre style="background:#002240;color:#fff"> <span style="color:#ff9d00">val</span> <span style="color:#fd0">Month</span>(n) = <span style="color:#ff628c">2</span>
println(n)
<span style="color:#ff628c">1</span> <span style="color:#ff9d00">match</span> {
<span style="color:#ff9d00">case</span> <span style="color:#fd0">Month</span>(n) => println(n)
<span style="color:#ff9d00">case</span> _ => println("empty")
}
<span style="color:#ff628c">3</span> <span style="color:#ff9d00">match</span> {
<span style="color:#ff9d00">case</span> <span style="color:#fd0">Month</span>(n) => println(n)
<span style="color:#ff9d00">case</span> _ => println("empty")
}
</pre>
<p>
Fajnie jest ale teraz zmodyfikujmy nasze <b>unapply</b> by przyjmowało bezpośrednio obiekt domenowy, wtedy będzie bardziej biznesowo i domenowo.
</p>
<pre style="background:#002240;color:#fff"><span style="color:#ff9d00">object</span> <span style="color:#fd0">Month</span>{
<span style="color:#ff9d00">def</span> <span style="color:#fd0">unapply</span>(<span style="color:#ccc">v</span>: <span style="color:#fd0">Month</span>) : Month = v
}
</pre>
<p>
Co już nam daje znak, że Option jako taki z równania został wyłączony. Ale czy na pewno? Jest tylko jeden sposób by sprawdzić.
</p>
<p>
- kod wysokopoziomowy
</p>
<pre style="background:#002240;color:#fff"><span style="color:#ff9d00">def</span> <span style="color:#fd0">somethingWithDate</span>(m:<span style="color:#fd0">Month</span>) = m <span style="color:#ff9d00">match</span> {
<span style="color:#ff9d00">case</span> <span style="color:#fd0">Month</span>(n) <span style="color:#ff9d00">if</span> n <=<span style="color:#ff628c">6</span> => println("first half")
<span style="color:#ff9d00">case</span> <span style="color:#fd0">Month</span>(n) => println("second half")
<span style="color:#ff9d00">case</span> _ => println("error")
}
</pre>
<p>
kod (a właściwie kawałek) niskopoziomowy
</p>
<pre style="background:#002240;color:#fff"> public void somethingWithDate(int);
<span style="color:#fd0">Code</span>:
<span style="color:#ff628c">0</span>: iload_1
<span style="color:#ff628c">1</span>: istore_3
<span style="color:#ff628c">2</span>: getstatic #<span style="color:#ff628c">17</span>
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span> Field jug/workshops/reactive/akka/typed/Month$.MODULE$:Ljug/workshops/reactive/akka/typed/Month$;</span>
<span style="color:#ff628c">5</span>: iload_3
<span style="color:#ff628c">6</span>: invokevirtual #<span style="color:#ff628c">21</span>
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span> Method jug/workshops/reactive/akka/typed/Month$.unapply:(I)I</span>
<span style="color:#ff628c">9</span>: istore <span style="color:#ff628c">4</span>
<span style="color:#ff628c">11</span>: getstatic #<span style="color:#ff628c">17</span>
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span> Field jug/workshops/reactive/akka/typed/Month$.MODULE$:Ljug/workshops/reactive/akka/typed/Month$;</span>
<span style="color:#ff628c">14</span>: iload <span style="color:#ff628c">4</span>
<span style="color:#ff628c">16</span>: invokevirtual #<span style="color:#ff628c">25</span>
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span> Method jug/workshops/reactive/akka/typed/Month$.isEmpty$extension:(I)Z</span>
<span style="color:#ff628c">19</span>: ifne <span style="color:#ff628c">57</span>
<span style="color:#ff628c">22</span>: getstatic #<span style="color:#ff628c">17</span>
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span> Field jug/workshops/reactive/akka/typed/Month$.MODULE$:Ljug/workshops/reactive/akka/typed/Month$;</span>
<span style="color:#ff628c">25</span>: iload <span style="color:#ff628c">4</span>
<span style="color:#ff628c">27</span>: invokevirtual #<span style="color:#ff628c">28</span>
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span> Method jug/workshops/reactive/akka/typed/Month$.get$extension:(I)I</span>
<span style="color:#ff628c">30</span>: istore <span style="color:#ff628c">5</span>
<span style="color:#ff628c">32</span>: iload <span style="color:#ff628c">5</span>
<span style="color:#ff628c">34</span>: bipush <span style="color:#ff628c">6</span>
<span style="color:#ff628c">36</span>: if_icmpgt <span style="color:#ff628c">54</span>
<span style="color:#ff628c">39</span>: getstatic #<span style="color:#ff628c">33</span>
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span> Field scala/Predef$.MODULE$:Lscala/Predef$;</span>
<span style="color:#ff628c">42</span>: ldc #<span style="color:#ff628c">35</span> <span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span> String first half</span>
</pre>
<p>
I jak to przestudiujecie to nie powinniście tam nigdzie znaleźć żadnego <b>new</b> a jedynie wywołania statyczne.
</p>
<p>
I wydaje mi się, że to co jest w Acce idzie jeszcze dalej. Przypomnijmy kod :
</p>
<pre style="background:#002240;color:#fff"><span style="color:#ff9d00">val</span> <span style="color:#fd0">ref</span> = messageAdapterRef <span style="color:#ff9d00">match</span> {
<span style="color:#ff9d00">case</span> <span style="color:#fd0">OptionVal</span>.<span style="color:#fd0">Some</span>(ref) ⇒ ref.asInstanceOf[<span style="color:#fd0">ActorRef</span>[<span style="color:#fd0">U</span>]]
<span style="color:#ff9d00">case</span> <span style="color:#fd0">OptionVal</span>.<span style="color:#ff628c">None</span> ⇒
</pre>
<p>
I teraz jeśli chodzi o <b>None</b> to jest to zwykły obiekt z tym <b>isEmpty</b> oraz <b>get</b>.
</p>
<pre style="background:#002240;color:#fff"><span style="color:#ff9d00">val</span> <span style="color:#fd0">None</span> = <span style="color:#ff9d00">new</span> <span style="color:#fd0">OptionVal</span>[<span style="color:#fd0">Null</span>](<span style="color:#ff628c">null</span>)
</pre>
<p>
<b>I tutaj weź głęboki wdech</b> i przypomnij sobie nasz poprzedni przykład z miesiącem. Dla Pattern Matchingu istotne jest co będzie zwrócone z unapply - żeby to miało get i isEmpty - i tutaj wymijamy unapply i od razu podrzucamy taką instancję singletona.
</p>
<p>
A co z tym drugim Kejsem? Tutaj mamy ładne customowe unapply.
</p>
<pre style="background:#002240;color:#fff"> <span style="color:#ff9d00">object</span> <span style="color:#fd0">Some</span> {
<span style="color:#ff9d00">def</span> <span style="color:#fd0">apply</span>[<span style="color:#fd0">A</span> >: <span style="color:#fd0">Null</span>](<span style="color:#ccc">x</span>: <span style="color:#fd0">A</span>): <span style="color:#fd0">OptionVal</span>[<span style="color:#fd0">A</span>] = <span style="color:#ff9d00">new</span> <span style="color:#fd0">OptionVal</span>(x)
<span style="color:#ff9d00">def</span> <span style="color:#fd0">unapply</span>[<span style="color:#fd0">A</span> >: <span style="color:#fd0">Null</span>](<span style="color:#ccc">x</span>: <span style="color:#fd0">OptionVal</span>[<span style="color:#fd0">A</span>]): <span style="color:#fd0">OptionVal</span>[<span style="color:#fd0">A</span>] = x
}
</pre>
<h2>Po co to?</h2>
<p>
W moim odczuciu <b>AnyVal</b> to w pewnym stopniu udana próba implementacji mechanizmu przeniesienia typów prymitywnych do warstwy domenowej bez zbytniego cierpienia w runtime. Ponieważ koniec końców tam na dole zawsze będzie JVM to często czar pryska i trzeba instancję stworzyć, dlatego też zazwyczaj używałem AnyVal jako zabezpieczenia w sygnaturze. Tutaj pojawia się nowa ciekawa możliwość próby zaimplementowania takiego prostego i opartego na prymitywach ADT co widzieliśmy na przykładzie Akki gdzie działa taki Some/None jako nakładka na ActorRef i null.
</p>
<p>
Pojawiają się takie brzydkie słowa jak <b>var</b> czy <b>null</b> ale może to nie czas by się spuszczać nad programowaniem ideologicznym i pomyśleć, że ci ludzie oszczędzili tak ileś tam pamięci, którą musieli oszczędzić i poszli na piwo.
</p>
<h1>Podsumowanie</h1>
<p>
Także drodzy przyjaciele zachęcam do eksperymentów bo jak wspominałem na samym początku i dla mnie to była edukacja. Wrzućcie czasem kawałek kodu, odpalcie "javap -c" i zobaczcie co się tak naprawdę dzieje pod spodem. No a jak potrzebujecie inspiracji - to zerknijcie w jakiś kod pisany przez mądrych ludzi - najlepiej kod który zarabia jakieś pieniądze.
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnhm6wLWmeAoocrcm2H5hefM1uTRS3mPuyyI9UoOmkAYbFiQjIORDYOawj-7smEuIkZyU7mmu-FLX_AnFcRdEjpd2lCH24zbbItJ7W2GFzHmg8mRjNgtH87VJOd79b_RjPX0wTh9FP6Kg/s1600/2018-05-05+11.52.31+1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnhm6wLWmeAoocrcm2H5hefM1uTRS3mPuyyI9UoOmkAYbFiQjIORDYOawj-7smEuIkZyU7mmu-FLX_AnFcRdEjpd2lCH24zbbItJ7W2GFzHmg8mRjNgtH87VJOd79b_RjPX0wTh9FP6Kg/s400/2018-05-05+11.52.31+1.jpg" width="400" height="300" data-original-width="1600" data-original-height="1200" /></a></div>
Paweł Włodarskihttp://www.blogger.com/profile/04891037231290616803noreply@blogger.com0tag:blogger.com,1999:blog-5047632037494901372.post-40896572225348221322018-02-04T17:36:00.000+01:002018-02-04T17:36:03.419+01:00Kotlin + Akka Typed<h2> Ale po co?</h2>
<p>
Tak dla ćwiczeń.
</p>
<h2> No ale po co?</h2>
<p>
O ile w "świecie scali" ten język wydaje się być ściśle powiązany z Akka to jednak w świecie korporacji gdzie management wykształcony na industrialnych praktykach wciąż widzi dodatnią korelację pomiędzy headcountem a powodzeniem projektu - no i własnie tam coś ta scala się tak nie przyjmuje w tych korporacjach. Jest duży opór. A że korpo to hajs to Akka tez ma API Javowe. Ale jak ktoś pisał w scali to to API Javowe boli strasznie. I tutaj pojawia się Kotlin jako kandydat na "lepszą Javę" - i to co mam nadzieję zobaczymy w artykule - <b>Kod napisany w Kotlinie używającym API dla Javy w praktyce wygląda bardzo podobnie do scali używającej API dla Scali!</b>
</p>
<p>
No a do tego będzie okazja przećwiczyć akka typed bo trochę mnie wkurwia to receive w aktorach, które łyka co wpadnie.
</p>
<h2> Ale na pewno o to chodzi?</h2>
<p>
No dobra. Za Kotlina teraz dostaje się więcej lajków. Zbiór fanbojów akki pokrywa się ze zbiorem fanbojów scali w dużym topniu a Kotlin to teraz mobilki i może jacyś fanboje springa także suma tych zbiorów może da 100 000 lajków. Jak będzie 100 000 lajków pod tym postem powstanie część ósma.
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijauVGd7gpthDF6T4fsqLcMzSUmzRtVTSccERwYSAYvGgcHFbtNfC3IaU1-Hlk1YEgkyLiQ5TwykaESfjGfvWd9HK9_vw5p4-NVoTQfrj6OyW_CGfmCUfKNAJenLCLfgRNsLQTkZObI08/s1600/manufaktura.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijauVGd7gpthDF6T4fsqLcMzSUmzRtVTSccERwYSAYvGgcHFbtNfC3IaU1-Hlk1YEgkyLiQ5TwykaESfjGfvWd9HK9_vw5p4-NVoTQfrj6OyW_CGfmCUfKNAJenLCLfgRNsLQTkZObI08/s400/manufaktura.jpg" width="400" height="300" data-original-width="1600" data-original-height="1200" /></a></div>
<h1> Oddziczanie Javy Kotlinem </h1>
<h2>Przykład w Scali skopiowany z tutoriala </h2>
<p class="akapit">
Jako materiał użyjemy intro blog posta z blogu Akki do akka typed <a href="https://akka.io/blog/2017/05/05/typed-intro">https://akka.io/blog/2017/05/05/typed-intro</a>. Jest to ładne wprowadzenie gdzie mamy użyte dwa typy aktorów - jeden taki bardziej obiektowy ma sobie zmienną a drugi (chyba) bardziej funkcyjny generuje z zachowania nowe zachowanie.
</p>
<p>
Najpierw zobaczymy przyklejone kawałek Scali z dokumentacji a następnie analogiczny kawałek kotlina. Pod obiema próbkami kodu będzie opis/wyjaśnienie co właściwie trzeba było zrobić.
</p>
<pre style="background:#002240;color:#fff">
object <span style="color:#ffee80">Greeter1</span> {
sealed trait <span style="color:#ffee80">Command</span>
<span style="color:#ff9d00">case</span> object <span style="color:#ffee80">Greet</span> extends <span style="color:#ffee80">Command</span>
<span style="color:#ffee80">final</span> case <span style="color:#ffee80">class</span> <span style="color:#fd0">WhoToGreet</span>(who: String) <span style="color:#ffee80">extends</span> <span style="color:#80fcff;font-style:italic">Command</span>
val greeterBehavior: <span style="color:#80fcff;font-style:italic">Behavior</span>[<span style="color:#80fcff;font-style:italic">Command</span>] =
<span style="color:#80fcff;font-style:italic">Actor</span>.mutable[<span style="color:#80fcff;font-style:italic">Command</span>](ctx => new <span style="color:#80fcff;font-style:italic">Greeter1</span>)
}
class <span style="color:#80fcff;font-style:italic">Greeter1</span> extends <span style="color:#80fcff;font-style:italic">Actor</span>.<span style="color:#80fcff;font-style:italic">MutableBehavior</span>[<span style="color:#80fcff;font-style:italic">Greeter1</span>.<span style="color:#80fcff;font-style:italic">Command</span>] {
import <span style="color:#ffee80">Greeter1</span><span style="color:#ff9d00">.</span>_
<span style="color:#ffee80">private</span> var greeting <span style="color:#ff9d00">=</span> <span style="color:#3ad900">"</span>hello<span style="color:#3ad900">"</span>
override def onMessage<span style="color:#e1efff">(</span>msg<span style="color:#ff9d00">:</span> <span style="color:#ffee80">Command</span><span style="color:#e1efff">)</span><span style="color:#ff9d00">:</span> <span style="color:#ffee80">Behavior</span>[<span style="color:#ffee80">Command</span>] <span style="color:#ff9d00">=</span> {
msg match {
<span style="color:#ff9d00">case</span> WhoToGreet<span style="color:#e1efff">(</span>who<span style="color:#e1efff">)</span> <span style="color:#ff9d00">=</span><span style="color:#ff9d00">></span>
greeting <span style="color:#ff9d00">=</span> s<span style="color:#3ad900">"</span>hello, $who<span style="color:#3ad900">"</span>
<span style="color:#ff9d00">case</span> <span style="color:#ffee80">Greet</span> <span style="color:#ff9d00">=</span><span style="color:#ff9d00">></span>
println<span style="color:#e1efff">(</span>greeting<span style="color:#e1efff">)</span>
}
<span style="color:#ff80e1">this</span>
}
}
</pre>
<h2>Analogiczny przykład z Kotlina </h2>
<pre style="background:#002240;color:#fff"><span style="color:#ffee80">class</span> <span style="color:#fd0">Greeter1</span> : MutableBehaviorKT<Greeter1.Protocol.Command>() {
<span style="color:#ffee80">private</span> var greeting <span style="color:#ff9d00">=</span> <span style="color:#3ad900">"</span>hello<span style="color:#3ad900">"</span>
override fun onMessage<span style="color:#e1efff">(</span>msg<span style="color:#ff9d00">:</span> <span style="color:#ffee80">Command</span><span style="color:#e1efff">)</span><span style="color:#ff9d00">:</span> <span style="color:#ffee80">Behavior<<span style="color:#ffee80">Command</span>></span> {
when (msg) {
<span style="color:#ffee80">Command</span><span style="color:#ff9d00">.</span><span style="color:#ffee80">Greet</span> <span style="color:#ff9d00">-</span><span style="color:#ff9d00">></span> println<span style="color:#e1efff">(</span>greeting<span style="color:#e1efff">)</span>
is <span style="color:#ffee80">Command</span><span style="color:#ff9d00">.</span><span style="color:#ffee80">WhoToGreet</span> <span style="color:#ff9d00">-</span><span style="color:#ff9d00">></span> greeting <span style="color:#ff9d00">=</span> <span style="color:#3ad900">"</span>hello ${greeting}<span style="color:#3ad900">"</span>
}
<span style="color:#ff9d00">return</span> <span style="color:#ff80e1">this</span>
}
companion object <span style="color:#ffee80">Protocol</span> {
sealed <span style="color:#ffee80">class</span> <span style="color:#fd0">Command</span> {
object <span style="color:#ffee80">Greet</span> : <span style="color:#fd0">Command</span>()
data class <span style="color:#fd0">WhoToGreet</span>(<span style="color:#ccc">val</span> <span style="color:#ccc">who</span>: <span style="color:#ffee80">String</span>) : <span style="color:#fd0">Command</span>()
}
val greeterBehaviour<span style="color:#ff9d00">:</span> <span style="color:#ffee80">Behavior<<span style="color:#ffee80">Command</span>></span> <span style="color:#ff9d00">=</span> <span style="color:#ffee80">Actor</span>.mutable<<span style="color:#ffee80">Command</span>> { ctx -> <span style="color:#fd0">Greeter1</span>() }
<span style="color:#e1efff">}</span>
}
</pre>
<p class="akapit">
Ok jest jedna zaślepka <b>MutableBehaviorKT</b> ale to tylko taki mały adapter by zutylizować(kocham to słowo) Kotlinow <b>when</b> w miejsce Javowych builder - zara wkleję. Jednak najpierw skoncentrujmy się na tym jak podejść do modelowania komend/protokołu/interfejsu aktorów. W scali zazwyczaj komendy idą do <b>companion object</b> bądź do innego object jeśli interfejs obejmuje kilku aktorów. W Kotlinie także możemy stworzyć companion object jednak istnieją pewne ograniczenia ograniczające miejsce wystąpienia do ciała klasy. Jednym się spodoba innym nie.
</p>
<p>
W każdy razie zerknijmy na poniższe sytuacje.
</p>
<p>
DZIAŁA:
<pre style="background:#002240;color:#fff">companion object <span style="color:#ffee80">Protocol</span> {
sealed <span style="color:#ffee80">class</span> <span style="color:#fd0">Command</span> {
object <span style="color:#ffee80">Greet</span> : <span style="color:#fd0">Command</span>()
data class <span style="color:#fd0">WhoToGreet</span>(<span style="color:#ccc">val</span> <span style="color:#ccc">who</span>: <span style="color:#ffee80">String</span>) : <span style="color:#fd0">Command</span>()
}
val greeterBehaviour<span style="color:#ff9d00">:</span> <span style="color:#ffee80">Behavior<<span style="color:#ffee80">Command</span>></span> <span style="color:#ff9d00">=</span> <span style="color:#ffee80">Actor</span>.mutable<<span style="color:#ffee80">Command</span>> { ctx -> <span style="color:#fd0">Greeter1</span>() }
<span style="color:#e1efff">}</span>
</pre>
TEŻ DZIAŁA:
<pre style="background:#002240;color:#fff">companion object <span style="color:#ffee80">Protocol</span> {
val greeterBehaviour<span style="color:#ff9d00">:</span> <span style="color:#ffee80">Behavior<<span style="color:#ffee80">Command</span>></span> <span style="color:#ff9d00">=</span> <span style="color:#ffee80">Actor</span><span style="color:#ff9d00">.</span>mutable<span style="color:#ff9d00"><</span><span style="color:#ffee80">Command</span><span style="color:#ff9d00">></span> { ctx <span style="color:#ff9d00">-</span><span style="color:#ff9d00">></span> Greeter1<span style="color:#e1efff">(</span><span style="color:#e1efff">)</span> }
}
sealed <span style="color:#ffee80">class</span> <span style="color:#fd0">Command</span>
object Greet : Command()
data <span style="color:#ffee80">class</span> <span style="color:#fd0">WhoToGreet</span>(val who: String) : Command()
</pre>
NIE DZIAŁA:
<pre style="background:#002240;color:#fff">companion object <span style="color:#ffee80">Protocol</span> {
sealed <span style="color:#ffee80">class</span> <span style="color:#fd0">Command</span>
object Greet : Command()
data <span style="color:#ffee80">class</span> <span style="color:#fd0">WhoToGreet</span>(val who: String) : Command()
val greeterBehaviour: Behavior<Command> = Actor.mutable<Command> { ctx -> <span style="color:#fd0">Greeter1</span>() }
<span style="color:#e1efff">}</span>
</pre>
</p>
<p>
Nie rozmieniłem jeszcze dokładnie dlaczego ostatnie nie działa ale trzeba zaznaczyć, że ostatni przykład byłby najbardziej intuicyjny dla programisty scali dlatego tez od niego zaczynałem. Generalnie w Kotlinie mam odczucie, że Companion Object został bardziej stworzony z myślą o metodach niż jako taki "całościowy moduł" dlatego też typy danych lepiej grupować na poziomie pakietu.
</p>
<h2>Co to jest to MutableBehaviorKT ?</h2>
<p>
A to sobie taki adapterek zrobiłem by nie używać tych "niby-że-mamy-w-javie-pattern-matching" builderów
</p>
<pre style="background:#002240;color:#fff"><span style="color:#ffee80">abstract</span> <span style="color:#ffee80">class</span> <span style="color:#fd0">MutableBehaviorKT</span><T> : Actor.MutableBehavior<T>() {
<span style="color:#ffee80">abstract</span> fun <span style="color:#fd0">onMessage</span>(<span style="color:#ccc">msg</span>: <span style="color:#ffee80">T</span>): Behavior<span style="color:#ffee80"><<span style="color:#ffee80">T</span>></span>
override fun <span style="color:#fd0">createReceive</span>(): Actor.Receive<span style="color:#ffee80"><<span style="color:#ffee80">T</span>></span> = object : Actor.Receive<span style="color:#ffee80"><<span style="color:#ffee80">T</span>></span> {
override fun receiveMessage<span style="color:#e1efff">(</span>msg<span style="color:#ff9d00">:</span> <span style="color:#ffee80">T</span><span style="color:#e1efff">)</span><span style="color:#ff9d00">:</span> <span style="color:#ffee80">Behavior<<span style="color:#ffee80">T</span>></span> <span style="color:#ff9d00">=</span> onMessage<span style="color:#e1efff">(</span>msg<span style="color:#e1efff">)</span>
override fun receiveSignal<span style="color:#e1efff">(</span>msg<span style="color:#ff9d00">:</span> <span style="color:#ffee80">Signal</span><span style="color:#ff9d00">?</span><span style="color:#e1efff">)</span><span style="color:#ff9d00">:</span> <span style="color:#ffee80">Behavior<<span style="color:#ffee80">T</span>></span> <span style="color:#ff9d00">=</span> <span style="color:#ff80e1">this</span>@<span style="color:#ffee80">MutableBehaviorKT</span>
}
<span style="color:#e1efff">}</span>
</pre>
<p>
I od razu kilka słów wyjaśnienia. To "object : CośTam" to syntax na deklarację anonimowej klasy w Kotlinie. Tutaj nie używam żadnych builderów tylko deleguję receiveMessage do metody, która we właściwym aktorze zaimplementowana być powinna. Po co jest to receiveSignal jeszcze nie wiem.
</p>
<h2>Jeszcze raz porównując logikę Scala-ScalaAPI & Kotlin-JavaAPI+adapter </h2>
SCALA:
<pre style="background:#002240;color:#fff"> override def onMessage<span style="color:#e1efff">(</span>msg<span style="color:#ff9d00">:</span> <span style="color:#ffee80">Command</span><span style="color:#e1efff">)</span><span style="color:#ff9d00">:</span> <span style="color:#ffee80">Behavior</span>[<span style="color:#ffee80">Command</span>] <span style="color:#ff9d00">=</span> {
msg match {
<span style="color:#ff9d00">case</span> WhoToGreet<span style="color:#e1efff">(</span>who<span style="color:#e1efff">)</span> <span style="color:#ff9d00">=</span><span style="color:#ff9d00">></span>
greeting <span style="color:#ff9d00">=</span> s<span style="color:#3ad900">"</span>hello, $who<span style="color:#3ad900">"</span>
<span style="color:#ff9d00">case</span> <span style="color:#ffee80">Greet</span> <span style="color:#ff9d00">=</span><span style="color:#ff9d00">></span>
println<span style="color:#e1efff">(</span>greeting<span style="color:#e1efff">)</span>
}
<span style="color:#ff80e1">this</span>
}
</pre>
KOTLIN:
<pre>
<pre style="background:#002240;color:#fff"> override fun onMessage<span style="color:#e1efff">(</span>msg<span style="color:#ff9d00">:</span> <span style="color:#ffee80">Command</span><span style="color:#e1efff">)</span><span style="color:#ff9d00">:</span> <span style="color:#ffee80">Behavior<<span style="color:#ffee80">Command</span>></span> {
when (msg) {
<span style="color:#ffee80">Command</span><span style="color:#ff9d00">.</span><span style="color:#ffee80">Greet</span> <span style="color:#ff9d00">-</span><span style="color:#ff9d00">></span> println<span style="color:#e1efff">(</span>greeting<span style="color:#e1efff">)</span>
is <span style="color:#ffee80">Command</span><span style="color:#ff9d00">.</span><span style="color:#ffee80">WhoToGreet</span> <span style="color:#ff9d00">-</span><span style="color:#ff9d00">></span> greeting <span style="color:#ff9d00">=</span> <span style="color:#3ad900">"</span>hello ${greeting}<span style="color:#3ad900">"</span>
}
<span style="color:#ff9d00">return</span> <span style="color:#ff80e1">this</span>
}
</pre>
</pre>
<h1>Immutable Aktor Numer Dwa </h1>
SCALA CODE COPIED FROM TUTORIAL
<pre style="background:#002240;color:#fff">object <span style="color:#ffee80">Greeter2</span> {
sealed trait <span style="color:#ffee80">Command</span>
<span style="color:#ff9d00">case</span> object <span style="color:#ffee80">Greet</span> extends <span style="color:#ffee80">Command</span>
<span style="color:#ffee80">final</span> case <span style="color:#ffee80">class</span> <span style="color:#fd0">WhoToGreet</span>(who: String) <span style="color:#ffee80">extends</span> <span style="color:#80fcff;font-style:italic">Command</span>
val greeterBehavior: <span style="color:#80fcff;font-style:italic">Behavior</span>[<span style="color:#80fcff;font-style:italic">Command</span>] = greeterBehavior(currentGreeting = "hello")
private def greeterBehavior(currentGreeting: <span style="color:#80fcff;font-style:italic">String</span>): <span style="color:#80fcff;font-style:italic">Behavior</span>[<span style="color:#80fcff;font-style:italic">Command</span>] =
<span style="color:#80fcff;font-style:italic">Actor</span>.immutable[<span style="color:#80fcff;font-style:italic">Command</span>] { (ctx, msg) <span style="color:#ff9d00">=</span><span style="color:#ff9d00">></span>
msg match {
<span style="color:#ff9d00">case</span> WhoToGreet<span style="color:#e1efff">(</span>who<span style="color:#e1efff">)</span> <span style="color:#ff9d00">=</span><span style="color:#ff9d00">></span>
greeterBehavior<span style="color:#e1efff">(</span>s<span style="color:#3ad900">"</span>hello, $who<span style="color:#3ad900">"</span><span style="color:#e1efff">)</span>
<span style="color:#ff9d00">case</span> <span style="color:#ffee80">Greet</span> <span style="color:#ff9d00">=</span><span style="color:#ff9d00">></span>
println<span style="color:#e1efff">(</span>currentGreeting<span style="color:#e1efff">)</span>
<span style="color:#ffee80">Actor</span><span style="color:#ff9d00">.</span>same
}
<span style="color:#e1efff">}</span>
}
</pre>
KOTLIN ALTERNATIVE FOR JAVA API:
<pre style="background:#002240;color:#fff">sealed <span style="color:#ffee80">class</span> <span style="color:#fd0">CommandJava</span>
data <span style="color:#ffee80">class</span> <span style="color:#fd0">WhoToGreet</span>(val who: String) : CommandJava()
object Greet : CommandJava()
object Greeter2 {
val greeterBehavior<span style="color:#ff9d00">:</span> <span style="color:#ffee80">Behavior<<span style="color:#ffee80">CommandJava</span>></span> <span style="color:#ff9d00">=</span> <span style="color:#fd0">greeterBehaviour</span>(<span style="color:#ccc">currentGreeting</span> = "<span style="color:#ccc">hello</span>")
<span style="color:#ffee80">private</span> fun <span style="color:#fd0">greeterBehaviour</span>(<span style="color:#ccc">currentGreeting</span>: <span style="color:#ffee80">String</span>): Behavior<span style="color:#ffee80"><<span style="color:#ffee80">CommandJava</span>></span> =
Actor.immutable<span style="color:#ffee80"><<span style="color:#ffee80">CommandJava</span>></span> { _, msg <span style="color:#ff9d00">-</span><span style="color:#ff9d00">></span>
when (msg) {
<span style="color:#ffee80">Greet</span> <span style="color:#ff9d00">-</span><span style="color:#ff9d00">></span> {
println<span style="color:#e1efff">(</span>currentGreeting<span style="color:#e1efff">)</span>
<span style="color:#ffee80">Actor</span><span style="color:#ff9d00">.</span>same<span style="color:#e1efff">(</span><span style="color:#e1efff">)</span>
}
is <span style="color:#ffee80">WhoToGreet</span> <span style="color:#ff9d00">-</span><span style="color:#ff9d00">></span> greeterBehaviour<span style="color:#e1efff">(</span><span style="color:#3ad900">"</span>hello ${msg.who}<span style="color:#3ad900">"</span><span style="color:#e1efff">)</span>
}
}
<span style="color:#e1efff">}</span>
</pre>
<p>
Tutaj zdecydowałem się wynieść komendy poza object z powodów opisywanych w poprzedniej cześć. Dodatkowo w przypadku Kotlina pojawia się jeden zestaw klamerek więcej gdyż <b>when</b> w przypadku gdy za strzałka występuje więcej niż jedna instrykcja wymaga własnie zamknięcia ich w klamerki podczas gdy scalowe <b>match-case</b> po prostu zgarnia wszystko od strzałki do strzałki. Ale tak poza tym wygląda bardzo podobnie.
</p>
<h1> We to uruchom </h1>
<p>
Tutaj też dosyć "scalowo" to wygląda.
</p>
<pre style="background:#002240;color:#fff"> val root<span style="color:#ff9d00">:</span> <span style="color:#ffee80">Behavior<<span style="color:#ffee80">Nothing</span>></span> <span style="color:#ff9d00">=</span> <span style="color:#ffee80">Actor</span><span style="color:#ff9d00">.</span>deferred<span style="color:#ff9d00"><</span><span style="color:#ffee80">Nothing</span><span style="color:#ff9d00">></span> { ctx <span style="color:#ff9d00">-</span><span style="color:#ff9d00">></span>
val greeter<span style="color:#ff9d00">:</span> <span style="color:#ffee80">ActorRef<<span style="color:#ffee80">CommandJava</span>></span> <span style="color:#ff9d00">=</span> ctx<span style="color:#ff9d00">.</span>spawn<span style="color:#e1efff">(</span><span style="color:#ffee80">Greeter2</span><span style="color:#ff9d00">.</span>greeterBehavior<span style="color:#e1efff">,</span> <span style="color:#3ad900">"</span>greeter<span style="color:#3ad900">"</span><span style="color:#e1efff">)</span>
greeter send WhoToGreet<span style="color:#e1efff">(</span><span style="color:#3ad900">"</span>Java<span style="color:#3ad900">"</span><span style="color:#e1efff">)</span>
greeter send <span style="color:#ffee80">Greet</span>
<span style="color:#ffee80">Actor</span><span style="color:#ff9d00">.</span>empty<span style="color:#e1efff">(</span><span style="color:#e1efff">)</span>
}
<span style="color:#ffee80">ActorSystem</span><span style="color:#ff9d00">.</span>create<span style="color:#e1efff">(</span>root<span style="color:#e1efff">,</span> <span style="color:#3ad900">"</span>HelloWorld<span style="color:#3ad900">"</span><span style="color:#e1efff">)</span>
</pre>
<p>
Ale troszeczkę tutaj oszukuję. Generalnie w Scali wysłanie wiadomości do aktora wygląda tak : <i>actor ! msg</i> ale w Javie/Kotlinie nie można stworzyć takiej metody. Dodatkowo w Kotlinie jeśli chcemy wywołać metodę bez kropki i nawiasów to przy deklaracji trzeba to zaznaczyć operatorem <b>infix</b>. Oczywiście Javowe API tego nie ma i tam trzeba wołać klasycznie <i>actor.tell(msg)</i>.
</p>
<p>
No i ja wtedy wchodzę cały na biało (z extend method):
<pre style="background:#002240;color:#fff">infix fun <span style="color:#ff9d00"><</span><span style="color:#ffee80">T</span><span style="color:#ff9d00">></span> <span style="color:#ffee80">ActorRef<<span style="color:#ffee80">T</span>></span><span style="color:#ff9d00">.</span>send<span style="color:#e1efff">(</span>cmd<span style="color:#ff9d00">:</span><span style="color:#ffee80">T</span><span style="color:#e1efff">)</span> <span style="color:#ff9d00">=</span> <span style="color:#ff80e1">this</span><span style="color:#ff9d00">.</span>tell<span style="color:#e1efff">(</span>cmd<span style="color:#e1efff">)</span>
</pre>
</p>
<p>
I to działa! Wołanie Kotlinem Javowego API scalowej biblioteki zakończyło się pełnym powodzeniem przyjaciele!
</p>
<h1> Wołanie Scali z Kotlina </h1>
<p>
A pojedźmy z eksperymentem trochę dalej i obadajmy jak wyjdzie wołanie bezpośrednio API scalowego z kotlina.
</p>
<p>
Pierwszy przykład wygląda bardzo podobnie do odpowiednika ze Scali. Nie ma żadnego buildera tylko zwykła metodka onMessage i obyło się bez adapterów.
</p>
<pre style="background:#002240;color:#fff"><span style="color:#ffee80">class</span> <span style="color:#fd0">HelloScala1</span> : Actor.MutableBehavior<HelloScala1.Protocol.Command>() {
<span style="color:#ffee80">private</span> var greeting <span style="color:#ff9d00">=</span> <span style="color:#3ad900">"</span>hello<span style="color:#3ad900">"</span>
override fun onMessage<span style="color:#e1efff">(</span>msg<span style="color:#ff9d00">:</span> <span style="color:#ffee80">Command</span><span style="color:#e1efff">)</span><span style="color:#ff9d00">:</span> <span style="color:#ffee80">Behavior<<span style="color:#ffee80">Command</span>></span> {
when (msg) {
<span style="color:#ffee80">Command</span><span style="color:#ff9d00">.</span><span style="color:#ffee80">ScalaGreet</span> <span style="color:#ff9d00">-</span><span style="color:#ff9d00">></span> println<span style="color:#e1efff">(</span>greeting<span style="color:#e1efff">)</span>
is <span style="color:#ffee80">Command</span><span style="color:#ff9d00">.</span><span style="color:#ffee80">ScalaWhoToGreet</span> <span style="color:#ff9d00">-</span><span style="color:#ff9d00">></span> greeting <span style="color:#ff9d00">=</span> <span style="color:#3ad900">"</span>hello ${greeting}<span style="color:#3ad900">"</span>
}
<span style="color:#ff9d00">return</span> <span style="color:#ff80e1">this</span>
}
companion object <span style="color:#ffee80">Protocol</span> {
sealed <span style="color:#ffee80">class</span> <span style="color:#fd0">Command</span> {
object <span style="color:#ffee80">ScalaGreet</span> : <span style="color:#fd0">Command</span>()
data class <span style="color:#fd0">ScalaWhoToGreet</span>(<span style="color:#ccc">val</span> <span style="color:#ccc">who</span>: <span style="color:#ffee80">String</span>) : <span style="color:#fd0">Command</span>()
}
val greeterBehaviour<span style="color:#ff9d00">:</span> <span style="color:#ffee80">Behavior<<span style="color:#ffee80">Command</span>></span> <span style="color:#ff9d00">=</span> <span style="color:#ffee80">Actor</span>.mutable<<span style="color:#ffee80">Command</span>> { ctx -> <span style="color:#fd0">HelloScala1</span>() }
<span style="color:#e1efff">}</span>
}
</pre>
<h2>A teraz będzie coś fajnego</h2>
<p>
Ogólnie tutaj tez poszło gładko ale zerknijmy na jeden fragment :
</p>
<pre style="background:#002240;color:#fff"> <span style="color:#ffee80">Actor</span><span style="color:#ff9d00">.</span>immutable { _, msg <span style="color:#ff9d00">-</span><span style="color:#ff9d00">></span>
when (msg) {
is <span style="color:#ffee80">ScalaWhoToGreet</span> <span style="color:#ff9d00">-</span><span style="color:#ff9d00">></span>
greeterBehavior<span style="color:#e1efff">(</span><span style="color:#3ad900">"</span>hello, ${msg.who}<span style="color:#3ad900">"</span><span style="color:#e1efff">)</span>
<span style="color:#ffee80">ScalaGreet</span> <span style="color:#ff9d00">-</span><span style="color:#ff9d00">></span> {
println<span style="color:#e1efff">(</span>currentGreeting<span style="color:#e1efff">)</span>
<span style="color:#ffee80">Actor</span><span style="color:#ff9d00">.</span>same<span style="color:#ff9d00"><</span><span style="color:#ffee80">Command</span><span style="color:#ff9d00">></span>()
}
}
}
</pre>
<p>
Czy widzicie coś tutaj ciekawego? No kurde... Przecież to jest API Scalowe a kotlinowa funkcja weszła tam jak w masło. Mowa o tym : <i>" Actor.immutable[Command] { (ctx, msg) =>..."</i> , oto co moim zdaniem się dzieje.
Od Scali 2.12 Lambdy idą w natywny invokeDynamic toteż Kotlin pewnie widzi zwykłą lambdę z Javy8 - i nawet IDE podpowiada tam Function2. No i teraz poniewaz Kotlin ma filozofię "ma działać wygodnie z Java i chuj", więc lambdy w wywołaniach Javowego API są tłumaczone na SAM types i chyba tak to wyszło. Elegancko.
</p>
<h2>To we teraz to uruchom</h2>
<pre style="background:#002240;color:#fff"> val root <span style="color:#ff9d00">=</span> <span style="color:#ffee80">Actor</span><span style="color:#ff9d00">.</span>deferred<span style="color:#ff9d00"><</span><span style="color:#ffee80">Nothing</span><span style="color:#ff9d00">></span> { ctx <span style="color:#ff9d00">-</span><span style="color:#ff9d00">></span>
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span>scala default parameters not working in kotlin -> props</span>
val greeter<span style="color:#ff9d00">:</span> <span style="color:#ffee80">ActorRef<<span style="color:#ffee80">Command</span>></span> <span style="color:#ff9d00">=</span> ctx<span style="color:#ff9d00">.</span>spawn<span style="color:#e1efff">(</span><span style="color:#ffee80">HelloScala2</span><span style="color:#ff9d00">.</span>greeterBehavior<span style="color:#e1efff">,</span> <span style="color:#3ad900">"</span>greeter<span style="color:#3ad900">"</span><span style="color:#e1efff">,</span> <span style="color:#ffee80">Props</span><span style="color:#ff9d00">.</span>empty<span style="color:#e1efff">(</span><span style="color:#e1efff">)</span><span style="color:#e1efff">)</span>
greeter<span style="color:#ff9d00">.</span>tell<span style="color:#e1efff">(</span>ScalaWhoToGreet<span style="color:#e1efff">(</span><span style="color:#3ad900">"</span>ScalaExample<span style="color:#3ad900">"</span><span style="color:#e1efff">)</span><span style="color:#e1efff">)</span>
greeter send <span style="color:#ffee80">ScalaGreet</span>
<span style="color:#ffee80">Actor</span><span style="color:#ff9d00">.</span>empty<span style="color:#e1efff">(</span><span style="color:#e1efff">)</span>
}
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span> `ActorSystem$`.`MODULE$`.apply() //pure scala API with default parameters not recognised by Kotlin</span>
<span style="color:#ffee80">ActorSystem</span><span style="color:#ff9d00">.</span>create<span style="color:#e1efff">(</span>root<span style="color:#e1efff">,</span><span style="color:#3ad900">"</span>HelloWorld<span style="color:#3ad900">"</span><span style="color:#e1efff">)</span> <span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span> create is actually Java API</span>
</pre>
<p>
Tutja zaczęły się trochę schody bo Kotlin nie ma pojęcia o Scalowym cukrze składniowym także zapomnij o Object.apply i scalowych parametrach defaultowych. No i jak się uprzesz tykać konstrukcji nienaturalnych dla Javy to czeka cię coś w stylu : <i>"`ActorSystem$`.`MODULE$`.apply()"</i>. Można to "owrapować" kotlinowym API ale ogólnie - <b>aktor jest stworzony przez Scalowe API a ActorSystem przez Javowe i wszystko działa elegancko</b>.
</p>
<h1> Wnioski </h1>
<p>
Hejty na bok ale jak twórcy Akki dodali Javowe API by przyśpieszyć adaptację tej biblioteki w korpo to moim zdaniem dobrze mieć Kotlina gdzieś na radarze bo to się czuje, że Kotlin celuje w bycie lepszą Javą i to się może udać. Część druga wkrótce a cześć ósma jak będzie 100 000 lajków.
</p>
Paweł Włodarskihttp://www.blogger.com/profile/04891037231290616803noreply@blogger.com0tag:blogger.com,1999:blog-5047632037494901372.post-66908485211790262722018-01-21T18:14:00.000+01:002018-01-27T10:04:14.978+01:00Java9 Cleaner świetną ilustracją enkapsulacji<p class="akapit">
10 lat temu w <b>Effective java</b> mogliśmy przeczytać by nigdy nie używać <b>finalize</b>. Ja się zastosowałem i tylko raz niechcący w ferworze refaktoringu przezwałem jakąś metode na finalize i zaczęły dziać się śmieszne rzeczy. Latka minęły i świeżo na półeczki księgarni informatyka wyszło trzecie wydanie <b>Effective java</b> z apdejtem do <i>Java 9</i>. No i w tej najnowszej Javie (najnowszej jeszcze tylko 2 miesiące!) w rozdziale o finalize pojawia się nowy mechanizm <b>java.lang.ref.Cleaner</b>
</p>
<p>
Koniec końców Joshua Bloch napisał, że ten Cleaner tez zjebany ale ogólniej mniej i jest taki jeden kejs gdzie go bez strachu użyć można. No i tak się składa, że moim zdaniem ten przykład użycia jednocześnie niesie ze sobą
ogromną wartość edukacyjną jak właściwie enkapsulować stan w klasie. A do tego możemy sobie zobaczyć jak inne języki na JVM poradzą sobie ze standardową sytuacją w Javie.
</p>
<p>
Przez chwile miałem wątpliwości czy aby temat będzie dla ogółu interesujący ale potem sobie przypomniałem, że to mój blog i będę tutaj pisał co mi się chce.
</p>
<div style="text-align: center;">
<iframe width="560" height="315" src="https://www.youtube.com/embed/2I7vPbthvWo" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
</div>
<h1>Dobra Enkapsulacja</h1>
<p class="akapit">
Na poczatku wytniemy kawałeczki kodu by łatwiej było zauważyć wspomnianą enkapsulację i ogólnie pojęte <b>ukrywanie informacji</b>, które bardzo pomaga w utrzymaniu i rozbudowie systemu. Jeśli ktoś chce brzmieć bardziej Fancy to może używać terminu anglojęzycznego <a href="https://en.wikipedia.org/wiki/Information_hiding">https://en.wikipedia.org/wiki/Information_hiding</a>. Jeśli ktoś chce brzmieć bardziej biznesowo to może powiedzieć, że informejszyn hajding redukuje ołweral meintenance cost and reduces tajm to market for fiuczer rilises.
</p>
<p>
<pre style="background:#002240;color:#fff"><span style="color:#ffee80">public</span> <span style="color:#ffee80">class</span> <span style="color:#fd0">InstanceAroundResource</span> <span style="color:#ffee80">implements</span> <span style="color:#80fcff;font-style:italic">AutoCloseable</span>{
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span>We will delegeta cleaning to Cleaner from Java 9</span>
<span style="color:#ffee80">private</span> <span style="color:#ffee80">static</span> <span style="color:#ffee80">final</span> <span style="color:#ffee80">Cleaner</span> cleaner<span style="color:#ff9d00">=</span><span style="color:#ffee80">Cleaner</span><span style="color:#ff9d00">.</span>create<span style="color:#e1efff">(</span><span style="color:#e1efff">)</span><span style="color:#e1efff">;</span>
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span>This is definition of internal state, static -> so it has no ref to external instance</span>
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span>private - to better hide information</span>
<span style="color:#ffee80">private</span> <span style="color:#ffee80">static</span> <span style="color:#ffee80">class</span> <span style="color:#fd0">EncapsulatedResource</span> <span style="color:#ffee80">implements</span> <span style="color:#80fcff;font-style:italic">Runnable</span>{
(<span style="color:#ff9d00">.</span><span style="color:#ff9d00">.</span><span style="color:#ff9d00">.</span>)
<span style="color:#e1efff">}</span>
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span>no getters for those two fields, no strange hakiers annotations either</span>
<span style="color:#ffee80">private</span> <span style="color:#ffee80">final</span> <span style="color:#ffee80">EncapsulatedResource</span> state<span style="color:#e1efff">;</span>
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span>this triggers cleaning procedure</span>
<span style="color:#ffee80">private</span> <span style="color:#ffee80">final</span> <span style="color:#ffee80">Cleaner</span><span style="color:#ff9d00">.</span><span style="color:#ffee80">Cleanable</span> cleanable<span style="color:#e1efff">;</span>
<span style="color:#ffee80">public</span> <span style="color:#fd0">InstanceAroundResource</span>(<span style="color:#ffee80">String</span> <span style="color:#ccc">resourceId</span>) {
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span>notice that both instances are created inside constructor , no direct assignment, </span>
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span>no information how resourceId is escapes outside </span>
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span>compare this with stntaxt 'this.field = field' which is hiding information like in the sentence </span>
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span> "think about number seven but don't tell what the number is"</span>
<span style="color:#ff80e1">this</span><span style="color:#ff9d00">.</span>state <span style="color:#ff9d00">=</span> <span style="color:#ff9d00">new</span> <span style="color:#ffee80">EncapsulatedResource</span>(<span style="color:#3ad900">"</span>[opened :<span style="color:#3ad900">"</span><span style="color:#ff9d00">+</span>resourceId<span style="color:#ff9d00">+</span><span style="color:#3ad900">"</span>]<span style="color:#3ad900">"</span>)<span style="color:#e1efff">;</span>
<span style="color:#ff80e1">this</span><span style="color:#ff9d00">.</span>cleanable <span style="color:#ff9d00">=</span> cleaner<span style="color:#ff9d00">.</span>register<span style="color:#e1efff">(</span><span style="color:#ff80e1">this</span><span style="color:#e1efff">,</span> state<span style="color:#e1efff">)</span><span style="color:#e1efff">;</span>
}
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span> here we are connecting Cleaner with Autocloseable from Java7</span>
<span style="color:#ffee80">@Override</span>
<span style="color:#ffee80">public</span> <span style="color:#ffee80">void</span> <span style="color:#fd0">close</span>() <span style="color:#ffee80">throws</span> <span style="color:#ffee80">Exception</span> {
cleanable<span style="color:#ff9d00">.</span>clean<span style="color:#e1efff">(</span><span style="color:#e1efff">)</span><span style="color:#e1efff">;</span>
}
<span style="color:#e1efff">}</span>
</pre>
</p>
<p>
I teraz tak, po pierwsze primo od javy 9 mamy import do dyspozycji: <br/>
<pre style="background:#002240;color:#fff"><span style="color:#80ffbb">import</span> java.lang.ref.Cleaner;</pre>
<br/>
i idąc dalej :
<br/>
<ol>
<li>Zauważcie, że nic z tej klasy nie ucieka poza abstrakcyjnem <i>resourceId</i> przekazanym do konstruktora - to jest niejako kawałek publicznego interfejsu.</li>
<li>Drugim kawałkiem publicznego interfejsu jest - no własnie interfejs - <i>Autocloseable</i> , czyli obietnicę posiadania metody/zachowania <b>close</b> </li>
<li>Totalnie ukryliśmy przed użytkownikiem użycie Cleanera. Nie ma ani dziwnych ch** wie po co getterów setterów. </li>
<li>Jak Bloch przykazał pola są finalne - przynajmniej pod katem referencji wnętrze jest niezmienne.</li>
<li>Ukryliśmy przed światem zewnętrznym istnienie klasy <b>EncapsulatedResource</b> co daje nam pełne pole do refaktoringu tego kawałka kodu w przyszłości (i minimalizacji tajm to market)</li>
<li>Jeszcze raz podkreslmy, że parametry konstruktora również nie zdradzają za wiele o bebechach. </li>
<li>Sam Cleaner z tego co zrozumiałem jest lepszy od starej metody <b>finalize</b> pod tym katem, że delegując czyszczenie do Cleanera - który nasłuchuje (listenerek taki) - nie będzie problemu z wyjątkami przy sprzątaniu bo Cleaner ma pełną kontrolę nad tym watkiem/procedurą i ogarnia. Tak przynajmniej napisał autor i ja mu wierzę!</li>
</ol>
</p>
<p>
I cały kod <br/>
<pre style="background:#002240;color:#fff"><span style="color:#ff9d00">import</span> <span style="color:#ffee80">java.lang.ref.Cleaner</span>;
<span style="color:#ffee80">public</span> <span style="color:#ffee80">class</span> <span style="color:#fd0">InstanceAroundResource</span> <span style="color:#ffee80">implements</span> <span style="color:#80fcff;font-style:italic">AutoCloseable</span>{
<span style="color:#ffee80">private</span> <span style="color:#ffee80">static</span> <span style="color:#ffee80">final</span> <span style="color:#ffee80">Cleaner</span> cleaner<span style="color:#ff9d00">=</span><span style="color:#ffee80">Cleaner</span><span style="color:#ff9d00">.</span>create<span style="color:#e1efff">(</span><span style="color:#e1efff">)</span><span style="color:#e1efff">;</span>
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span>static to not have reference to external instance</span>
<span style="color:#ffee80">private</span> <span style="color:#ffee80">static</span> <span style="color:#ffee80">class</span> <span style="color:#fd0">EncapsulatedResource</span> <span style="color:#ffee80">implements</span> <span style="color:#80fcff;font-style:italic">Runnable</span>{
<span style="color:#ffee80">String</span> handleToSystemResource<span style="color:#e1efff">;</span> <span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span>don't need to be private because EncapsulatedResource is private</span>
<span style="color:#fd0">EncapsulatedResource</span>(<span style="color:#ffee80">String</span> <span style="color:#ccc">handleTosystemResource</span>) {
<span style="color:#ff80e1">this</span><span style="color:#ff9d00">.</span>handleToSystemResource <span style="color:#ff9d00">=</span> handleTosystemResource<span style="color:#e1efff">;</span>
}
<span style="color:#ffee80">@Override</span>
<span style="color:#ffee80">public</span> <span style="color:#ffee80">void</span> <span style="color:#fd0">run</span>() {
<span style="color:#ffee80">System</span><span style="color:#ff9d00">.</span>out<span style="color:#ff9d00">.</span>println<span style="color:#e1efff">(</span><span style="color:#3ad900">"</span>Closing system resource by cleaner :<span style="color:#3ad900">"</span><span style="color:#ff9d00">+</span>handleToSystemResource<span style="color:#e1efff">)</span><span style="color:#e1efff">;</span>
handleToSystemResource<span style="color:#ff9d00">=</span><span style="color:#3ad900">"</span>CLOSED<span style="color:#3ad900">"</span><span style="color:#e1efff">;</span>
}
<span style="color:#e1efff">}</span>
<span style="color:#ffee80">private</span> <span style="color:#ffee80">final</span> <span style="color:#ffee80">EncapsulatedResource</span> state<span style="color:#e1efff">;</span>
<span style="color:#ffee80">private</span> <span style="color:#ffee80">final</span> <span style="color:#ffee80">Cleaner</span><span style="color:#ff9d00">.</span><span style="color:#ffee80">Cleanable</span> cleanable<span style="color:#e1efff">;</span>
<span style="color:#ffee80">public</span> <span style="color:#fd0">InstanceAroundResource</span>(<span style="color:#ffee80">String</span> <span style="color:#ccc">resourceId</span>) {
<span style="color:#ff80e1">this</span><span style="color:#ff9d00">.</span>state <span style="color:#ff9d00">=</span> <span style="color:#ff9d00">new</span> <span style="color:#ffee80">EncapsulatedResource</span>(<span style="color:#3ad900">"</span>[opened :<span style="color:#3ad900">"</span><span style="color:#ff9d00">+</span>resourceId<span style="color:#ff9d00">+</span><span style="color:#3ad900">"</span>]<span style="color:#3ad900">"</span>)<span style="color:#e1efff">;</span>
<span style="color:#ff80e1">this</span><span style="color:#ff9d00">.</span>cleanable <span style="color:#ff9d00">=</span> cleaner<span style="color:#ff9d00">.</span>register<span style="color:#e1efff">(</span><span style="color:#ff80e1">this</span><span style="color:#e1efff">,</span> state<span style="color:#e1efff">)</span><span style="color:#e1efff">;</span>
}
<span style="color:#ffee80">@Override</span>
<span style="color:#ffee80">public</span> <span style="color:#ffee80">void</span> <span style="color:#fd0">close</span>() <span style="color:#ffee80">throws</span> <span style="color:#ffee80">Exception</span> {
<span style="color:#ffee80">System</span><span style="color:#ff9d00">.</span>out<span style="color:#ff9d00">.</span>println<span style="color:#e1efff">(</span><span style="color:#3ad900">"</span>First In Auto-Closable<span style="color:#3ad900">"</span><span style="color:#e1efff">)</span><span style="color:#e1efff">;</span>
cleanable<span style="color:#ff9d00">.</span>clean<span style="color:#e1efff">(</span><span style="color:#e1efff">)</span><span style="color:#e1efff">;</span>
}
<span style="color:#e1efff">}</span>
</pre>
</p>
<p>
Zerknijmy teraz na odpalenie tego : <br/>
<pre style="background:#002240;color:#fff"> <span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span>1</span>
<span style="color:#ff9d00">try</span>(<span style="color:#ffee80">InstanceAroundResource</span> r = <span style="color:#ff9d00">new</span> <span style="color:#ffee80">InstanceAroundResource</span>(<span style="color:#3ad900">"</span>BLOG-POST<span style="color:#3ad900">"</span>)){
<span style="color:#ffee80">System</span>.<span style="color:#ff9d00">out</span>.println(<span style="color:#3ad900">"</span>Using resource1<span style="color:#3ad900">"</span>);
}
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span>2</span>
<span style="color:#ff9d00">new</span> <span style="color:#ffee80">InstanceAroundResource</span>(<span style="color:#3ad900">"</span>UNHANDLED-RESOURCE<span style="color:#3ad900">"</span>);
<span style="color:#ffee80">System</span>.<span style="color:#ff9d00">out</span>.println(<span style="color:#3ad900">"</span>r2 left alone<span style="color:#3ad900">"</span>);
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span>System.gc();</span>
</pre>
</p>
<p>
sytuacja nr <b>1</b> prosta bo na końcu zostanie wykonane <b>close</b> i mamy
<pre>
Using resource1
First In Auto-Closable
Closing system resource by cleaner :[opened :BLOG-POST]
</pre>
Co do drugiej sytuacji to podobnie jak u autora książki także i u mnie backup nie zadziałał bez sztucznego wywołania <b> System.gc()</b>
<pre>
r2 left alone
Closing system resource by cleaner :[opened :UNHANDLED-RESOURCE]
</pre>
</p>
<h2> A Java 10 ? </h2>
<p>
W Javie 10 zadziała już poniższe : <br/>
<pre style="background:#002240;color:#fff"><span style="color:#ccc">jshell</span><span style="color:#ff9d00">></span> try(<span style="color:#ccc">var</span> <span style="color:#ccc">r</span>=<span style="color:#ccc">new</span> InstanceAroundResource(<span style="color:#3ad900">"</span>Java10<span style="color:#3ad900">"</span>)){
<span style="color:#ff9d00">...</span><span style="color:#ff9d00">></span> System.out.println(<span style="color:#3ad900">"</span>Doing something in java 10<span style="color:#3ad900">"</span>);
<span style="color:#ff9d00">...</span><span style="color:#ff9d00">></span> }
</pre>
<pre>
Doing something in java 10
First In Auto-Closable
Closing system resource by cleaner :[opened :Java10]
</pre>
</p>
<p>
Czyli już nie trzeba deklarować nowego <i>InstanceAroundResource</i> z zaznaczeniem iż jest typu <i>InstanceAroundResource</i>. Mniej czytania, inżynier może przeznaczyć moc operacyjną muzgu na redukcję tajm to market.
</p>
<h1>Inne Języki</h1>
<h2>Kotlin</h2>
<p>
Kotlin ma coś takiego : <br/>
<pre style="background:#002240;color:#fff">public inline fun <<span style="color:#fd0">T</span> : AutoCloseable?, R> <span style="color:#fd0">T</span>.use(<span style="color:#ccc">block</span>: (<span style="color:#fd0">T</span>) -> <span style="color:#fd0">R</span>): <span style="color:#fd0">R</span> {
<span style="color:#ff9d00">var</span> <span style="color:#fd0">exception</span>: <span style="color:#fd0">Throwable</span>? = <span style="color:#ff628c">null</span>
<span style="color:#ff9d00">try</span> {
<span style="color:#ff9d00">return</span> block(<span style="color:#ff80e1">this</span>)
} <span style="color:#ff9d00">catch</span> (<span style="color:#ccc">e</span>: <span style="color:#fd0">Throwable</span>) {
exception = e
<span style="color:#ff9d00">throw</span> e
} <span style="color:#ff9d00">finally</span> {
<span style="color:#ff80e1">this</span>.closeFinally(exception)
}
}
</pre>
</p>
<p>
Co oznacza, że mechanizmem "extends method" dorzuci metodę <b>use</b> do wszystkiego co rozszerza AutoCloseable. Także zadziała to i z naszym - napisanym w Javie - InstanceAroundResource. <br/>
<pre style="background:#002240;color:#fff"><span style="color:#ff9d00">val</span> <span style="color:#fd0">r</span>=<span style="color:#fd0">InstanceAroundResource</span>("KOTLIN-EXAMPLE")
r.use { <span style="color:#ccc">r</span>: <span style="color:#fd0">InstanceAroundResource</span> ->
println("Doing something in kotlin")
}
</pre>
I to w sumie w niektórych kręgach półświatka programistycznego można nazwać metodą/funkcją wyższego rzędu. Wynik będzie analogiczny z przykładem Javowym :
<pre>
Using resource1
First In Auto-Closable
Closing system resource by cleaner :[opened :BLOG-POST]
</pre>
</p>
<p>
No i analogie idzie dalej, jeśli chcemy by cleaner zadziałał jako backup trzeba ręcznie <b>gc</b> wywołać :
</p>
<pre style="background:#002240;color:#fff"><span style="color:#fd0">InstanceAroundResource</span>("UNHANDLED-IN-KOTLIN")
println("r2 left alone")
<span style="color:#fd0">System</span>.gc()
</pre>
<h4>A co z nullem</h4>
<p>
Ogarnianie nulli z javy to jeden z lepszych fiuczerów Kotlina, zerknijmy czy jebnie coś takiego :
<pre style="background:#002240;color:#fff"><span style="color:#ff9d00">val</span> <span style="color:#fd0">r3</span>:<span style="color:#fd0">InstanceAroundResource</span>? = <span style="color:#ff628c">null</span>
r3.use { <span style="color:#ccc">r</span>: <span style="color:#fd0">InstanceAroundResource?</span> -> println("jebnie?") } <span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span>nie jebnie</span>
</pre>
No i po pierwsze nie da się łatwo oszukać kompilatora, że null jest typu InstanceAroundResource (ten taki znak zapytania na końcu) a po drugie to nie jebnie.
Jak zerkniesz jeszcze raz na implementacje "use" to zobaczysz , ze w finally nie ma "close" a jest " this.closeFinally(exception)". I to wygląda mniej więcej tak :
<pre style="background:#002240;color:#fff">internal fun <span style="color:#fd0">AutoCloseable</span>?.closeFinally(<span style="color:#ccc">cause</span>: <span style="color:#fd0">Throwable?</span>) = when {
<span style="color:#ff80e1">this</span> == <span style="color:#ff628c">null</span> -> {}
cause == <span style="color:#ff628c">null</span> -> close()
<span style="color:#ff9d00">else</span> ->
<span style="color:#ff9d00">try</span> {
close()
} <span style="color:#ff9d00">catch</span> (<span style="color:#ccc">closeException</span>: <span style="color:#fd0">Throwable</span>) {
cause.addSuppressed(closeException)
}
}
</pre>
</p>
<p>
Czyli takie zamknięcie-otwarcie RISORSA nie jest rzeczą prostą. I całe szczęście, że Java i Kotlin mają gotowce na to w standardowej bibliotece. I tutaj też zwróć uwagę, że Java natywnie na poziomie języka a kotlin zaimplementowane przy pomocy bardziej abstrakcyjnego natywnego mechanizmu - "rozszerzalnych metod". Zaraz zobaczymy, ze to może iść jeszcze dalej.
</p>
<h2>Scala</h2>
<p class="akapit">
I teraz tak : wiem, że google jakoś segreguje wyniki wyszukiwania na podstawie ciasteczek i mogą być dla każdego unikalne ale jak wpisałem w googla własnie <i>"scala try with resources "</i> to kurcze same tutoriale wyskakują jak samemu napisać a nie byłem w stanie jakiejś natywnej konstrukcji odnaleźć.
</p>
<p>
jak ktoś zna to niech da namiar bo inaczej ryzykujemy w każdym projeckie "not inwented here" z pytaniem "a w której paczce mamy zaimplementowany loan-pattern, no wiesz ten try z javy?". Jest biblioteczka <a href="https://github.com/jsuereth/scala-arm">https://github.com/jsuereth/scala-arm</a> ale tez jakos nie jest dobrze na googlu spozycjonowana a znalazłem ją bo już o niej kiedyś słyszałem.
W każdym razie jak już biblioteczkę mamy to dalej kod wygląda bardzo podobnie:
<pre style="background:#002240;color:#fff"><span style="color:#ff9d00">val</span> <span style="color:#fd0">r</span>=<span style="color:#ff9d00">new</span> <span style="color:#fd0">InstanceAroundResource</span>("SCALA-EXAMPLE")
<span style="color:#ff9d00">val</span> <span style="color:#fd0">mr</span>: <span style="color:#fd0">ManagedResource</span>[<span style="color:#fd0">InstanceAroundResource</span>] = managed(r)
mr.foreach{r=>
println("Doing something in scala")
}
<span style="color:#ff9d00">new</span> <span style="color:#fd0">InstanceAroundResource</span>("UNHANDLED-IN-SCALA")
println("r2 left alone")
<span style="color:#fd0">System</span>.gc()
</pre>
<pre>
Doing something in scala
First In Auto-Closable
Closing system resource by cleaner :[opened :SCALA-EXAMPLE]
r2 left alone
Closing system resource by cleaner :[opened :UNHANDLED-IN-SCALA]
</pre>
</p>
<h4>Poziomy abstrakcji mechanizmów językowych</h4>
<p>
Obczajcie to :
<ul>
<li>Java ma <b>try-with-resources</b> </li>
<li>Kotlin ma <b>extension method</b> przy pomocy, którego można zaimplementować <b>try-with-resources</b> i <b>inne rozszerzenia</b></li>
<li>Scala ma <b>implicity</b> przy pomocy których można zaimplementować <b>extension method</b> i inne <b>meta-rozszerzenia</b> przy pomocy których można zaimplementować <b>try-with-resources</b> i <b>inne rozszerzenia</b> </li>
</ul>
No tylko, że im bardziej ogólny mechanizm tym trudniej go komuś wytłumaczyć i dłuższa edukacja - try-with-resources jest banalne w użyciu a teraz porównaj to z ogarnianiem implicit class i jakichś optymalizacji jak rozszerzanie AnyVal. Także coś za coś
</p>
<h2>Linki</h2>
<ul>
<li><a href="http://www.enyo.de/fw/notes/java-finalization-revisited.html">http://www.enyo.de/fw/notes/java-finalization-revisited.html</a></li>
<li><a href="https://docs.oracle.com/javase/9/docs/api/java/lang/ref/Cleaner.htm">https://docs.oracle.com/javase/9/docs/api/java/lang/ref/Cleaner.html</a></li>
<li><a href="https://stuartmarks.wordpress.com/2017/04/17/deprecation-of-object-finalize/">https://stuartmarks.wordpress.com/2017/04/17/deprecation-of-object-finalize/</a></li>
</ul>
Paweł Włodarskihttp://www.blogger.com/profile/04891037231290616803noreply@blogger.com0tag:blogger.com,1999:blog-5047632037494901372.post-54924891582833990092018-01-06T11:15:00.000+01:002018-01-06T11:15:25.015+01:00Nauka Mechanizmów Programowania<p class="akapit">
... a nie tylko konkretnych języków. Taki oto temat dzisiejszego wypracowania. Można by rzec, że mechanizmów starych ale subiektywnie nowych dla ludzi, którzy siedzą w Javie. Przed Javą 8 warto było uczyć się mechanizmów z innych języków na JVM by być przygotowanym na nadejście funkcji. Teraz może warto pochylić się nad innymi elementami, których w Javie nie uświadczysz (albo napotkasz w formie ubogiej) jak <i>'declaration site variance'</i> , wykrywanie typów czy modelowanie <i>'unii'</i> przy pomocy słówka <i>'sealed'</i>.
</p>
<p>
Narzędzie edukacyjne - by zmotywować uczestników - musi nosić jakieś znamiona przydatności na rynku lokalnym bo spotkania wokół Haskella czy bardziej zaawansowanego wykorzystania FP w Scali zainteresowały jedynie ograniczone grono. Scala jest fajna i bogata w przeróżne mechanizmy ale trudno zmotywować ludzi do jej nauki kiedy nie ma szans zrobić nań pieniądza. I tu pojawia się coś pomiędzy Scalą i Java czyli Kotlin.
</p>
<p>
Taka ma teoria, że ludzie z JetBrains pracując latami nad wsparciem scali nauczyli się dobrze, które ficzery łatwo wspierać w IDE a co lepiej usunąć. I tak w sumie jak ktoś przejdzie od Javy do Kotlina to z Kotlina dużo bliżej do Scali (jakby ktoś chciał). Język jest 'wystarczająco przyjemny' w porównaniu z Javą i ma wiele wygodnych mechanizmów, które występują w scali a do tego to już nie tylko Android ale różne narzędzia i inne Springi zaczynają go wspierać.
</p>
<p>
No to po kolei...
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgf3SiVPkfWyGJpWVR3kUgPZ17qYwueqQKXnVJYJtfhuKif_zWSYsmy3ZYps5-jT3m-1Q-ESGpcRSsqVxhyXiJtqbuMUGFfC_giVPV4vEvo4TCv7xE_A6AVV9fFG_uE46U9qWOJHNhpRzE/s1600/tory.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgf3SiVPkfWyGJpWVR3kUgPZ17qYwueqQKXnVJYJtfhuKif_zWSYsmy3ZYps5-jT3m-1Q-ESGpcRSsqVxhyXiJtqbuMUGFfC_giVPV4vEvo4TCv7xE_A6AVV9fFG_uE46U9qWOJHNhpRzE/s320/tory.jpg" width="320" height="180" data-original-width="1000" data-original-height="562" /></a></div>
<h1>Plan Nauki</h1>
<p class="akapit">
Na razie wbite są dwa meetupy
<ol>
<li><b>Wprowadzenie do FP i OOP</b> - <a href="https://www.meetup.com/Java-User-Group-Lodz/events/246218922/">https://www.meetup.com/Java-User-Group-Lodz/events/246218922/</a>. To wprowadzenie należy rozumieć jako poznanie składni aniżeli jakiejś abstrakcyjnej teorii. Jak Kotlin się kompiluje do Javy, jak rozmawia z Javą a przede wszystkim o ile mniej pracy trzeba w tym języku włożyć w zadeklarowanie prostej klasy czy funkcji. </li>
<li>
<b>System typów</b> - <a href="https://www.meetup.com/Java-User-Group-Lodz/events/246378280/">https://www.meetup.com/Java-User-Group-Lodz/events/246378280/</a> - Kolejna rzecz trochę podobna do Scali czyli <i>Niedziurawy</i> system typów z Any na górze i Nothing na dole - do tego dochodzą interesujące Unie Typu i Nulla , które w końcu mogą rozwiązać problem porozrzucanych nullpointerexceptionów po kodzie
</li>
</ol>
</p>
<p>
I co dalej :
<ul>
<li>Dużo ciekawszy mechanizm generyków, declaration site variance,covariance,contravariance i konsekwencje, o których pisałem rok temu : <a href="http://pawelwlodarski.blogspot.com/2017/01/kowariantne-konsekwencje.html">kowariantne konsekwencje</a> </li>
<li>
Kompozycja funkcji o niebo wygodniejsza ze względu na obecność prostych typów funkcji jak <b>Int -> Int</b> zamiast <b>Function<Int,Int></b>, currying i takie tam podobne
</li>
<li> Pattern matching, funkcje częściowe i całkowite i dlaczego to ważne. No i ADT czyli Algebraiczne typy Danych</li>
<li>Tutaj może wejdzie bardziej zaawansowane FP z bibliotekami <a href="https://github.com/MarioAriasC/funKTionale">https://github.com/MarioAriasC/funKTionale</a> oraz <a href="http://arrow-kt.io/">Kategory przemianowane na Arrow</a> </li>
<li>No i w międzyczasie może porobimy jakieś Code Retreat czy coding kata czy jakieś ćwiczenia w ten deseń </li>
</ul>
</p>
<p>
Także sytuacja będzie się rozwijać i jak ktoś jest zainteresowany niech śledzi meetupa.
</p>
<p>
W tym miejscu artykułów zazwyczaj występuje zakończenie także i tutaj nie może go zabraknąć.
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjV7PumXCvCYymw4U_MdLFxD2UVFtzENNuU0kUHYb-yEZWH7tYQRXFT0cm9Xm3a8IWM8Ld78FpL1hsp7zTYbvd0YUBOm0RTD3KPrqyctZG9jlZhhTRYMScewM7q9L2BQGgqbli8AOXt1Mg/s1600/2017-11-25+01.58.14+1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjV7PumXCvCYymw4U_MdLFxD2UVFtzENNuU0kUHYb-yEZWH7tYQRXFT0cm9Xm3a8IWM8Ld78FpL1hsp7zTYbvd0YUBOm0RTD3KPrqyctZG9jlZhhTRYMScewM7q9L2BQGgqbli8AOXt1Mg/s400/2017-11-25+01.58.14+1.jpg" width="400" height="300" data-original-width="1600" data-original-height="1200" /></a></div>Paweł Włodarskihttp://www.blogger.com/profile/04891037231290616803noreply@blogger.com0tag:blogger.com,1999:blog-5047632037494901372.post-26597678842977355202017-11-12T20:09:00.000+01:002017-11-12T20:09:03.567+01:00Functional Calisthenics z Kotlinem na GDCR 2017<p class="akapit">
Code Retreat - a zwłaszcza GLOBAL - to doskonała okazja do nauki programowania, zerwania z nieskutecznymi nawykami i odnalezienie nowych podejść do rozwiązywania problemów. A, że to jest to spotkanie cykliczne to akurat w tym miejscu wykorzystam starą metodę DRY i a TY będziesz dispatcherem/dispatcherką wywołania. Także wybierz sobie wstęp z jednego z poniższych artykułów.
<ol>
<li><a href="http://pawelwlodarski.blogspot.com/2013/12/coderetreat-2013-odz-i-wartosci.html">Motywacja do GDCR 2013</a> </li>
<li><a href="http://pawelwlodarski.blogspot.com/2013/12/coderetreat-2013-uwagi-i-wnioski.html">Wnioski po GDCR 2013</a> </li>
<li><a href="http://pawelwlodarski.blogspot.com/2014/10/coderetreat-2014-nowe-propozycje.html">Kilka przykładów użycia mechanizmów FP ze scali do Game of Life</a> </li>
<li><a href="http://pawelwlodarski.blogspot.com/2014/11/po-code-retreat-2014.html">Po GDCR 2014</a></li>
<li><a href="http://pawelwlodarski.blogspot.com/2015/11/code-retreat-2015-nie-boj-sie-nauki.html">przed GDCR 2015 - tutaj w ogóle jakiś Haskell jest :D</a> </li>
<li><a href="http://pawelwlodarski.blogspot.com/2015/11/funkcyjne-code-retreat.html">Po GDCR 2016 - przymiarki do funkcyjnego CR</a></li>
<li><a href="http://pawelwlodarski.blogspot.com/2016/11/wrazenia-po-code-retreat-2016-ktorego.html">Wrażenia po GDCR 2016, którego nie było i tym razem trochę lepszy Haskell</a></li>
</ol>
</p>
<p>
Skoro już trochę historii za nami to wróćmy na chwilkę do ograniczeń. Jednym z popularniejszych na CR jest ograniczenie zwane <b>object calisthenics</b>, które jest nakierowane na poprawienie umiejętności pisania poprawnego obiektowego kodu. I od razu musimy sobie wyjaśnić jedną rzecz - jeśli z jakiegoś powodu nie podoba ci się programowanie obiektowe to masz jak najbardziej prawo je krytykować ale najpierw musisz zrozumieć o co w tym wszystkim chodzi. Jeśli dzień za dniem rzeźbisz klasy, które nazywają się <b>ManagerCosTamImpl</b> albo <b>CosTamHelper</b> to nie masz problemu z programowaniem obiektowym ale zwyczajnie piszesz nad wyraz złozony kod proceduralny w języku, który wymusza by ten kod proceduralny był w klasach - stąd te kolosy po 8000 linijek.
</p>
<p>
A wracając do ograniczeń to object calisthenics mają np. takie ćwiczenie "jedna kropka na linie kodu" i to ma pomóc pisać kod, który lepiej enkapsuluje dane w klasach bo trudniej o tzw. train wreck <i>obj.get()A.get()B.setC(c)</i>. No i jako, że programowanie funkcyjne również zaczyna grać ważną role w twoim ulubionym języku to warto by podobne zasady wprowadzić dla FP.
</p>
<p>
W 2016 mieliśmy przerwę ale już w tym roku Code Retreat wraca na JUG Łódź. Spotkanie odbędzie się 18 listopada a zapisac można się tutaj -> <a href="https://www.meetup.com/Java-User-Group-Lodz/events/243444033/">Global Day of CR łódź Meetup</a>. W tym roku będzie także zapewniona opieka nad dziećmi także można wpaść z rodziną.
</p>
<p>
No i by do tematu nauki podejść całościowo i rozszerzyć ćwiczenia o FP to tym razem najprawdopodobniej kilka ćwiczeń będzie zainspirowanych nowym zestawem <b>functional calisthenics</b> -> <a href="https://codurance.com/2017/10/12/functional-calisthenics/">https://codurance.com/2017/10/12/functional-calisthenics/</a>
</p>
<p>
No to jedziemy z koksem i obczajamy te zasady. Tym razem użyjemy języka, który zdobywa coraz większą popularność na JVM, ma dobre wsparcie w IDE bo robi go firma, która sama robi IDE a do tego jest wciąż bezpiecznie ubogi tak, ze korporacje nie powinny nim sobie zrobić krzywdy - <b>mowa o Kotlinie</b>.
</p>
<br/>
<h1>Zasada 1 : Nazywaj wszystko i naucz się rozpoznawać wzorce w kodzie. </h1>
<p>
<i>"All functions need to be named. Which means that you shouldn't use lambdas or anonymous functions. Also, name all your variables as per standard clean code rules."</i>
</p>
<p>
Jeśli musisz dać czemuś nazwę to istnieje duża szansa, ze wiesz co ten fragment musi robić. No i teraz jeśli zamiast używać anonimowych funkcji zaczniesz je definiować i nazywać to może zauważysz szansę na parametryzacje i kompozycje. Ale aby to miało ręce i nogi najpierw musisz w ogóle zastosować podejście funkcyjne a tutaj moga pomóc bardziej fundamentalne ograniczenia jak np. brak zmiennych.
</p>
<p>
Co do implementacji to tutaj bardzo może się przydać nowy ficzer z kotlina 1.1 - aliasy typów.
</p>
<pre style="background:#002240;color:#fff"><span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span>aliases since Kotlin 1.1</span>
typealias <span style="color:#fd0">Cell</span> = <span style="color:#ffee80">Boolean</span>
typealias <span style="color:#fd0">Neighbours</span> = <span style="color:#ffee80">Int</span>
<span style="color:#ff9d00">val</span> <span style="color:#fd0">LIVE_CELL</span>:<span style="color:#fd0">Cell</span> = <span style="color:#ff628c">true</span>
<span style="color:#ff9d00">val</span> <span style="color:#fd0">DEAD_CELL</span>:<span style="color:#fd0">Cell</span> = <span style="color:#ff628c">false</span>
fun cellEvolution(c:<span style="color:#fd0">Cell</span>,n:<span style="color:#fd0">Neighbours</span>): <span style="color:#fd0">Cell</span> =
when(c){
<span style="color:#fd0">LIVE_CELL</span> -> <span style="color:#ff9d00">if</span>(n==<span style="color:#ff628c">2</span> || n==<span style="color:#ff628c">3</span>) <span style="color:#fd0">LIVE_CELL</span> <span style="color:#ff9d00">else</span> <span style="color:#fd0">DEAD_CELL</span>
<span style="color:#fd0">DEAD_CELL</span> -> <span style="color:#ff9d00">if</span>(n==<span style="color:#ff628c">3</span>) <span style="color:#fd0">LIVE_CELL</span> <span style="color:#ff9d00">else</span> <span style="color:#fd0">DEAD_CELL</span>
}
</pre>
<p>
Powyżej pierwsza próba, w trakcie której próbowałem zadeklarować dwie stałe okreslające stan komórki <i>DEAD</i> oraz <i>LIVE</i> jakkolwiek kompilator (a przynajmniej plugin do Intellij) nie był w stanie wykryć iż wszystkie warunki w wywołaniu <i>when</i> zostały ogarnięte. Dlatego tez powstało drugie podejście - <b>sealed class</b>
<pre style="background:#002240;color:#fff"><span style="color:#ffee80">sealed</span> <span style="color:#ff9d00">class</span> <span style="color:#fd0">Cell</span>
<span style="color:#ff9d00">object</span> <span style="color:#fd0">LiveCell</span> :<span style="color:#fd0">Cell</span>()
<span style="color:#ff9d00">object</span> <span style="color:#fd0">DeadCell</span> :<span style="color:#fd0">Cell</span>()
fun cellEvolution(c:<span style="color:#fd0">Cell</span>,n:<span style="color:#fd0">Neighbours</span>): <span style="color:#fd0">Cell</span> =
when(c){
<span style="color:#fd0">LiveCell</span> -> <span style="color:#ff9d00">if</span>(n==<span style="color:#ff628c">2</span> || n==<span style="color:#ff628c">3</span>) <span style="color:#fd0">LiveCell</span> <span style="color:#ff9d00">else</span> <span style="color:#fd0">DeadCell</span>
<span style="color:#fd0">DeadCell</span> -> <span style="color:#ff9d00">if</span>(n==<span style="color:#ff628c">3</span>) <span style="color:#fd0">LiveCell</span> <span style="color:#ff9d00">else</span> <span style="color:#fd0">DeadCell</span>
}
</pre>
</p>
<br/>
<h1>Zasada 2 : Brak zmiennego stanu. </h1>
<p>
Dosłownie : "You shouldn't use any variable of any type that can mutate."
</p>
<p>
Najważniejsze w tym ćwiczeniu jest "zablokowanie" uczestnikom drogi w kierunku (nawet i poprawnego) programowania obiektowego gdyż w tym wypadku nie można owinąć zmiennego stanu instancją obiektu.
</p>
<pre style="background:#002240;color:#fff"><span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span>THIS IS FORBIDDEN</span>
<span style="color:#ff9d00">class</span> <span style="color:#fd0">MutableCell</span>(<span style="color:#ffee80">private</span> <span style="color:#ff9d00">var</span> <span style="color:#fd0">state</span>:<span style="color:#ffee80">Boolean</span>){
fun evolve(n:<span style="color:#fd0">Neighbours</span>){
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span>set new state here</span>
}
}
</pre>
<p>
Pewne trudności moga sie pojawić kiedy będziemy chcieli zmienić stan planszy - no ale przecież zmiany nie są dozwolone!. Kotlin dosyć ładnie oddziela api służące do deklarowania i używania niemutowalnych kolekcji od mutowalnych odpowiedników. Aby transformować niemutowalne listy tworząc <b>nowe niezależne</b> wersje używamy funkcyjny wyższego rzędu jak <i>map</i> czy <i>filter</i> obecnych teraz nawet w Javie.
</p>
<pre style="background:#002240;color:#fff">typealias <span style="color:#fd0">Coordinates</span>=<span style="color:#fd0">Pair</span><<span style="color:#fd0">Int</span>,Int>
typealias <span style="color:#fd0">CellPosition</span>=<span style="color:#fd0">Pair</span><<span style="color:#fd0">Coordinates</span>,Cell>
typealias <span style="color:#fd0">Board</span> = kotlin.collections.<span style="color:#fd0">List</span><<span style="color:#fd0">CellPosition</span>>
<span style="color:#ff9d00">val</span> <span style="color:#fd0">nextRound</span> : (<span style="color:#fd0">Board</span>) -> <span style="color:#fd0">Board</span> = {board ->
board.map { ??? }
}
</pre>
<p>
No i zobacz czytelniku/czytelniczko jakim wygodnym pomysłem są aliasy w przykładzie powyżej.
</p>
<h1>Zasada 3 : Każdy argument na wejściu zwraca wynik </h1>
<p>
<i>"There can not be an if without an else. Switches and pattern matching should always have all paths considered"</i>
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1cmo0uyOoraHxCgHLDv13GbnqTGxXT5iiiF-7NLlKDsyvWeQ_ape8Rb2UlH0Sv5YhNvz8Y0SnV_n_VTesP7epE-Cq20Tvwd1mO6y5nYV-nPkf7S1jbNXjYDw66G5WLTMxgwyPmSX81dM/s1600/partialfunction.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1cmo0uyOoraHxCgHLDv13GbnqTGxXT5iiiF-7NLlKDsyvWeQ_ape8Rb2UlH0Sv5YhNvz8Y0SnV_n_VTesP7epE-Cq20Tvwd1mO6y5nYV-nPkf7S1jbNXjYDw66G5WLTMxgwyPmSX81dM/s400/partialfunction.png" width="400" height="158" data-original-width="860" data-original-height="340" /></a></div>
<p>
To jest dosyć ciekawa zasada bo dobrze oddaje naturę code retreat. Tak więc mamy proste założenie, którego uczestnicy mają się trzymać i obserwować wyniki. Jest to na początku znacznie prostsze aniżeli wchodzenie w rozważania teoretyczne o funkcjach częściowych. Każdy argument musi generować konkretny wynik - <b>bez wyjątków - dosłownie!</b>
</p>
<h1>Zasada 4 : Nie używaj zmiennych tymczasowych </h1>
<h1>Zasada 5 : Expressions, not statements </h1>
<p>
Te dwie zasady postanowiłem połączyć bo w moim odczuciu dotyczą podobnego tematu. Dodatkowo druga zostawiam po engliszu by nie popełnić błędów w tłumaczeniu.
</p>
<p>
<i>"There shouldn't be any variable declared in the body of a function."</i> oraz <i>"All lines should be expressions. That's it, all lines should return a value."</i>
</p>
<p>
Tutaj języki takie jak Kotlin czy Scala mogą pomóc bardzo, bardzo, bardzo bo tam wszystko zdaje się coś zwracać! A szczególnie if jest wygodny jak coś zwraca. W Javie zazwyczaj trzeba coś tam manipulować po bokach.
</p>
<pre style="background:#002240;color:#fff">fun badEvolve(cell:<span style="color:#fd0">Cell</span>,neighbours:<span style="color:#ffee80">Int</span>):<span style="color:#fd0">Cell</span>{
<span style="color:#ff9d00">var</span> <span style="color:#fd0">newCell</span>:<span style="color:#fd0">Cell</span>?=<span style="color:#ff628c">null</span> <span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span>val newCell:Cell would also work here but var shows problem better</span>
<span style="color:#ff9d00">if</span>(cell==<span style="color:#fd0">LiveCell</span> && neighbours in (<span style="color:#ff628c">2</span>..<span style="color:#ff628c">3</span>)) {
newCell = <span style="color:#fd0">LiveCell</span>
}
<span style="color:#ff9d00">else</span> <span style="color:#ff9d00">if</span>(cell==<span style="color:#fd0">LiveCell</span>) {
newCell = <span style="color:#fd0">DeadCell</span>
}
<span style="color:#ff9d00">else</span> <span style="color:#ff9d00">if</span>(cell==<span style="color:#fd0">DeadCell</span> && neighbours==<span style="color:#ff628c">3</span>) {
newCell=<span style="color:#fd0">LiveCell</span>
}
<span style="color:#ff9d00">else</span> {
newCell=<span style="color:#fd0">DeadCell</span>
}
<span style="color:#ff9d00">return</span> newCell
}
</pre>
<p>
W Javie często deklarowane są zmienne tymczasowe (pamiętacie te czasy gdy 90% zmiennych w waszym godzinie nazywało się <b>temp</b>?) tylko po to by coś w nich na chwilę przypisać i od razu dać return. Wyjście? Niech if coś zwraca i niech to będzie wynik metody. No i w Kotlinie to dzieje sie naturalnie. W Javie niby jest tzw. "ternary operator" ale on chyba dlatego nazywa się ternary bo nie ma "if-else". Trochę peszek.
</p>
<pre style="background:#002240;color:#fff">fun betterEvolve(cell:<span style="color:#fd0">Cell</span>,neighbours:<span style="color:#ffee80">Int</span>):<span style="color:#fd0">Cell</span>{
<span style="color:#ff9d00">return</span> <span style="color:#ff9d00">if</span>(cell==<span style="color:#fd0">LiveCell</span> && neighbours in (<span style="color:#ff628c">2</span>..<span style="color:#ff628c">3</span>)) <span style="color:#fd0">LiveCell</span>
<span style="color:#ff9d00">else</span> <span style="color:#ff9d00">if</span>(cell==<span style="color:#fd0">LiveCell</span>) <span style="color:#fd0">DeadCell</span>
<span style="color:#ff9d00">else</span> <span style="color:#ff9d00">if</span>(cell==<span style="color:#fd0">DeadCell</span> && neighbours==<span style="color:#ff628c">3</span>) <span style="color:#fd0">LiveCell</span>
<span style="color:#ff9d00">else</span> <span style="color:#fd0">DeadCell</span>
}
</pre>
<p>
No i teraz najlepsze. Ponieważ jest to jedyna instrukcja funkcji to możemy wyrażenie uprościć jeszcze bardziej.
</p>
<pre style="background:#002240;color:#fff">fun bestEvolve(cell:<span style="color:#fd0">Cell</span>,neighbours:<span style="color:#ffee80">Int</span>):<span style="color:#fd0">Cell</span> =
<span style="color:#ff9d00">if</span>(cell==<span style="color:#fd0">LiveCell</span> && neighbours in (<span style="color:#ff628c">2</span>..<span style="color:#ff628c">3</span>)) <span style="color:#fd0">LiveCell</span>
<span style="color:#ff9d00">else</span> <span style="color:#ff9d00">if</span>(cell==<span style="color:#fd0">LiveCell</span>) <span style="color:#fd0">DeadCell</span>
<span style="color:#ff9d00">else</span> <span style="color:#ff9d00">if</span>(cell==<span style="color:#fd0">DeadCell</span> && neighbours==<span style="color:#ff628c">3</span>) <span style="color:#fd0">LiveCell</span>
<span style="color:#ff9d00">else</span> <span style="color:#fd0">DeadCell</span>
</pre>
<h1>Zasada 6 : Brak jawnej rekurencji </h1>
<p>
Przyznam, że tego punktu do nie rozumiem a to z faktu, że autorzy odnoszą się do jakichś konstrukcji z Clojure. Coś tam kiedyś czytałem o "loop/recur" ale nie będę udawał, że pamiętam. Tak czy inaczej w tym punkcie znajdziemy poradę by tę "jawną rekurencję" zastąpić map/reduce . No to tak będziemy starali się zrobić.
</p>
<h1>Zasada 7 : Generyczne bloki </h1>
<p>
<i>"Try to use a much as possible generic types for your functions, outside of the boundaries of your application"</i>
</p>
<p>
To jets dosyć interesujący i abstrakcyjny sam w sobie punk. Z jednej strony ile razy deklarowałeś listę kiedy kiedy Collecion lub Iterable w zupełności wystarczało? Z tym ograniczeniem będziesz musiał dokładnie uzasadnić czy typ, którego używasz nie jest zbyt konkretny co może związać ci ręce przy dalszych zmianach. Dodatkowo w Kotlinie ze względu na wykrywanie typów musisz się zastanowić czy pozostawić prace kompilatorowi, który pewnie znajdzie najbardziej konkretny typ czy też może zadecydować świadomie samemu.
</p>
<p>
Możesz zastosować podobne podejście do funkcji ale tutaj idzie to trochę w inną stronę. Czy obecna implementacja dla danego typu nie jest zbyt "wąska"? Klasycznym przykładem jest tutaj <b>reduce</b> które jest generalizacją dodawania, mnożenia i czego tam sobie zażyczymy.
</p>
<pre style="background:#002240;color:#fff">fun add(list:<span style="color:#fd0">List</span><<span style="color:#fd0">Int</span>>) : <span style="color:#ffee80">Int</span> =<span style="color:#ff9d00">if</span>(list.isEmpty()) <span style="color:#ff628c">0</span> <span style="color:#ff9d00">else</span> list[<span style="color:#ff628c">0</span>] + add(list.drop(<span style="color:#ff628c">1</span>))
fun multiply(list:<span style="color:#fd0">List</span><<span style="color:#fd0">Int</span>>) : <span style="color:#ffee80">Int</span> =<span style="color:#ff9d00">if</span>(list.isEmpty()) <span style="color:#ff628c">1</span> <span style="color:#ff9d00">else</span> list[<span style="color:#ff628c">0</span>] * multiply(list.drop(<span style="color:#ff628c">1</span>))
fun <<span style="color:#fd0">A</span>> genericReduce(l:<span style="color:#fd0">List</span><<span style="color:#fd0">A</span>>,neutral:<span style="color:#fd0">A</span>,reduction:(<span style="color:#fd0">A</span>,<span style="color:#fd0">A</span>)-><span style="color:#fd0">A</span>):<span style="color:#fd0">A</span> =
<span style="color:#ff9d00">if</span>(l.isEmpty()) neutral <span style="color:#ff9d00">else</span> reduction(l[<span style="color:#ff628c">0</span>], genericReduce(l.drop(<span style="color:#ff628c">1</span>),neutral,reduction))
</pre>
<p>
I zgodnie z oczekiwaniami
</p>
<pre style="background:#002240;color:#fff">println(add(listOf(<span style="color:#ff628c">1</span>,<span style="color:#ff628c">2</span>,<span style="color:#ff628c">3</span>,<span style="color:#ff628c">4</span>,<span style="color:#ff628c">5</span>)))
println(multiply(listOf(<span style="color:#ff628c">1</span>,<span style="color:#ff628c">2</span>,<span style="color:#ff628c">3</span>,<span style="color:#ff628c">4</span>,<span style="color:#ff628c">5</span>)))
println(genericReduce(listOf(<span style="color:#ff628c">1</span>,<span style="color:#ff628c">2</span>,<span style="color:#ff628c">3</span>,<span style="color:#ff628c">4</span>,<span style="color:#ff628c">5</span>),<span style="color:#ff628c">0</span>,{a,b->a+b}))
println(genericReduce(listOf(<span style="color:#ff628c">1</span>,<span style="color:#ff628c">2</span>,<span style="color:#ff628c">3</span>,<span style="color:#ff628c">4</span>,<span style="color:#ff628c">5</span>),<span style="color:#ff628c">1</span>,{a,b->a*b}))
</pre>
<h1>Zasada 8 : Efekty uboczne tylko na granicy systemu </h1>
<p>
<i>"Side effects should only appear on the boundaries of your application. The guts of your application should have no side effects." </i>
</p>
<p>
Tutaj po pierwsze musisz używać funkcji, które nie zmieniają żadnego stanu poza nimi żadnego <b>println</b> czy też modyfikowania mutowalnej tablicy zdefiniowanej poza funkcją. To ograniczenie może być jeszcze bardziej interesujące gdy założysz, że efekty na granicy systemu musza być reprezentowane przy pomocy odpowiednich typów.
</p>
<p>
W takich wypadkach możesz skorzystać z typu <b>Optional</b> dodanego do Javy8
</p>
<pre style="background:#002240;color:#fff">typealias <span style="color:#fd0">Coordinates</span>=<span style="color:#fd0">Pair</span><<span style="color:#fd0">Int</span>,Int>
typealias <span style="color:#fd0">CellPosition</span>=<span style="color:#fd0">Pair</span><<span style="color:#fd0">Coordinates</span>,Cell>
typealias <span style="color:#fd0">Board</span> = kotlin.collections.<span style="color:#fd0">List</span><<span style="color:#fd0">CellPosition</span>>
<span style="color:#ff9d00">val</span> <span style="color:#fd0">initializeBoard</span>:(<span style="color:#fd0">Coordinates</span>) -> <span style="color:#fd0">Board</span> = ...
<span style="color:#ff9d00">val</span> <span style="color:#fd0">nextTurn</span>: (<span style="color:#fd0">Board</span>) -> <span style="color:#fd0">Board</span> = ...
fun readInput():<span style="color:#fd0">Optional</span><<span style="color:#fd0">Coordinates</span>> = ...
fun display(b:<span style="color:#fd0">Board</span>):<span style="color:#ffee80">Unit</span> = ...
readInput().map(initializeBoard).map(nextTurn).ifPresent(::display)
</pre>
<p>
W przykładzie powyżej możesz zobaczyć, że Kotlin całkiem wygodnie integruje Jawowe klasy. Optional służy tam do zasygnalizowania efektu ubocznego związanego z wprowadzaniem danych ze świata zewnętrznego - który jakby nie patrzyć jest trochę uboczny.
</p>
<p>
Bardziej zaawansowani uczestnicy mogą zechcieć skorzystać z również bardziej zaawansowanej biblioteki <a href="http://kategory.io/">http://kategory.io/</a> i użyć IO Monad do wypisywania tekstu na konsolę <a href="http://kategory.io/docs/effects/io/">http://kategory.io/docs/effects/io/</a> .
</p>
<h1>Zasada 9 : Nieskończone strumienie danych </h1>
<p>
<i>W skrócie - nie możesz używać tablic ani kolekcji. Tam gdzie użyłbyś standardowej kolekcji musisz użyć strumieni/ nieskończonej sekwencji </i>
</p>
<p>
Programowanie Funkcyjne kładzie ogromny nacisk na operowanie na wartościach bez mutowania stanu. Jeśli nie zmieniamy stanu i wartości są stałe to czy ważne jest kiedy operacje będą miały miejsce (stąd FP ułatwia operacje wielowątkowe)? No nie ma w związku z czym możemy pracować na tzw. leniwych kolekcjach które są niejako "opisane" ale nie istnieją puki nie trzeba.
</p>
<p>
Przykładowymi kandydatami do "strumieniowania" w grze życie są komórki - na z definicji nieskończonej planszy. Również gra sama w sobie jest nieskończoną kolekcją tur.
</p>
<pre style="background:#002240;color:#fff"><span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span>here we are playing 10 turns</span>
<span style="color:#ff9d00">val</span> <span style="color:#fd0">init</span>:<span style="color:#fd0">Board</span> = initializeBoard()
generateSequence(init,nextTurn).take(<span style="color:#ff628c">10</span>).forEach(::display)
</pre>
<p>
Ale zamiast 10 tur możemy chcieć grać do momentu kiedy na planszy mamy jakiekolwiek żywe komórki. Aby było bardziej interesująco przeskoczmy na chwile do Javy. Pierwszą rzeczą jaką chcemy sprawdzić to czy da się wykorzystać kod, ktory napisaliśmy w Kotlinie.
</p>
<pre style="background:#002240;color:#fff"><span style="color:#fd0">List</span><<span style="color:#fd0">Pair</span><<span style="color:#fd0">Pair</span><<span style="color:#fd0">Integer</span>, Integer>, Cell>> board = <span style="color:#fd0">Life1Kt</span>.initializeBoard();
</pre>
<p>
Technicznie jest to możliwe ale praktycznie raczej nikomu nie będzie się chciało babrać z tak rozbudowanymi typami generycznymi. No dobrze to spróbujmy od początku :
</p>
<pre style="background:#002240;color:#fff"><span style="color:#fd0">Board</span> init= ...;
<span style="color:#fd0">Predicate</span><<span style="color:#fd0">Board</span>> hasLiveCells = ...;
<span style="color:#fd0">UnaryOperator</span><<span style="color:#fd0">Board</span>> nextTurn = ...;
<span style="color:#fd0">Consumer</span><<span style="color:#fd0">Board</span>> display=...;
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span>below iterate version possible from Java9</span>
<span style="color:#fd0">Stream</span>.iterate(init,hasLiveCells,nextTurn).forEach(display);
<span style="color:#08f;font-style:italic"><span style="color:#e1efff">//</span>take while possible from Java9</span>
<span style="color:#fd0">Stream</span>.iterate(init,nextTurn).takeWhile(hasLiveCells).forEach(display);
</pre>
<h1>Zasada 10 : Tylko funkcje jedno parometrowe </h1>
<p>
<i> "Each function should have a single parameter." </i>
</p>
<p>
Według mnie to najważniejsze ograniczenie by dobrze zrozumieć siłę kompozycji funkcji. Gdy przekazujesz do metody całą paczkę parametrów możesz ją postrzegać jako wielki monolit. Lecz kiedy przesłanie kolejnych parametrów określa tak naprawdę innego rodzaju funkcje - wtedy musisz się zastanowić co z czego tworzysz. Dla przykładu funkcję <b>findNeighbours</b> możesz zaimplementować na dwa sposoby.
</p>
<pre style="background:#002240;color:#fff"><span style="color:#ccc">findNeighbours</span> : (<span style="color:#fd0">Coordinates</span>) -> (<span style="color:#fd0">Board</span>) -> <span style="color:#fd0">Neighbours</span> = ...
</pre>
<p>
Czy widzisz różnicę? Czy lepiej mieć funkcje, która znajdzie sąsiadów dla przekazanych koordynat na z góry określonej planszy czy może wygodniej jest przekazywać planszę dla wcześniej orkeślonych koordynat?
</p>
<p>
Co do samego Kotlina to nie ma on tak wygodnego wsparcia dla <b>curryingu</b> jak scala (currying to własnie to, że przekazujesz parametr po parametrze) ale jak się trochę ogarnie składnie to też daje radę
</p>
<pre style="background:#002240;color:#fff"><span style="color:#ff9d00">val</span> <span style="color:#fd0">evolve</span> : (<span style="color:#fd0">Neighbours</span>) -> (<span style="color:#fd0">Cell</span>) -> <span style="color:#fd0">Cell</span> = {ns->{c->c}}
</pre>
<p>
Ewentualnie produkuj funkcję z metody
</p>
<pre style="background:#002240;color:#fff">fun evolve2(ns:<span style="color:#fd0">Neighbours</span>) : (<span style="color:#fd0">Cell</span>) -> <span style="color:#fd0">Cell</span> = {c -> c}
</pre>
<h1>Zasada X : Żadnych nulli </h1>
<p>
Ta zasada co prawda nie pojawia się w oryginalnym zestawie ale w programowaniu funkcyjnym null jest ... bez sensu. Kotlin ma ciekawe patenty na poziomie języka do radzenia sobie z nullami . Jeśli nie chcesz w nie wchodzić wtedy cóż, zawsze zostaje prawilne podejście z opakowywaniem każdego nullowego api jak <i>map.get</i> w Optional.
</p>
<h1>Podsumowanie</h1>
<p>
Podobnie jak chodząc na siłownię powtarzasz pewne ćwiczenia tak samo tutaj powtarzając cwiczenia nabierasz informatycznej siły. I analogicznie samo czytanie o ćwiczeniach niewiele ci da. Jeśli chcesz zwiększyć siłę programowania funkcyjnego ćwicz,ćwicz,ćwicz,ćwicz,ćwicz,ćwicz,ćwicz,ćwicz,ćwicz,ćwicz,ćwicz,ćwicz. Poszukaj spotkania code retreat w twojej okolicy lub podobnych warsztatów i nie opierdalaj się!
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEip13DMiendpElwCXbr0hc8kki3MBzX4Ki7nKGp8mR_qgWEDnUYlcuDu0nlLQQhqzWuU8rjNIERy3CDmp2RyTu4e-xd5-3TSLABSCg-f2_xdmjPl6NeJWMo0-zLoGNSq49qKXSvyF8iwic/s1600/zamek.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEip13DMiendpElwCXbr0hc8kki3MBzX4Ki7nKGp8mR_qgWEDnUYlcuDu0nlLQQhqzWuU8rjNIERy3CDmp2RyTu4e-xd5-3TSLABSCg-f2_xdmjPl6NeJWMo0-zLoGNSq49qKXSvyF8iwic/s400/zamek.jpg" width="400" height="300" data-original-width="1600" data-original-height="1200" /></a></div>Paweł Włodarskihttp://www.blogger.com/profile/04891037231290616803noreply@blogger.com0tag:blogger.com,1999:blog-5047632037494901372.post-12678933560540852072017-10-15T19:36:00.000+02:002017-10-15T19:36:53.190+02:00Fajny nowy acz niepozorny operator z Javy 9 <p>
I nie chodzi o moduły a o nową ciekawą metodę <b>Optional</b>, która zwię się <b>or</b> i jest dostępna od Javy 9.
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiCaaPWlPA0_F-FFyxmGrIs0HDCl95mPx9l-3tHVO6_BjdwasGyp3mGT8MUkxY2tKwFJKcop56xv2mC_iFPgvWcDdbsHtcjkWqtFutpf6hrHdG6TVy3V822ZT87ac0UNxx_YM9cIAhwvw/s1600/or.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiCaaPWlPA0_F-FFyxmGrIs0HDCl95mPx9l-3tHVO6_BjdwasGyp3mGT8MUkxY2tKwFJKcop56xv2mC_iFPgvWcDdbsHtcjkWqtFutpf6hrHdG6TVy3V822ZT87ac0UNxx_YM9cIAhwvw/s640/or.jpg" width="640" height="288" data-original-width="740" data-original-height="333" /></a></div>
<p>
To skoro small talk mamy za sobą to dlaczego ona taka fajna?
</p>
<h1> Unia opcjonalnych typów w dynamicznych strukturach</h1>
<p class="akapit">
Taka sytuacja. Masz jakiś kanał komunikacji i otrzymujesz przez ten kanał opcjonalną wartość jakiegoś typu. I teraz ten typ którego wartość jest opcjonalna może przyjąć jedną z na przykład 4 elementowego zbioru wartości gdzie każdy element może mieć różną liczbę różnych atrybutów. Na rysunku duże kółko to symbolika typu abstrakcyjnego a małe kółka to podtypy - i technicznie wszystko jest tak opcjonalne, że ani nie wiadomo czy jakaś wartość będzie przekazana a jeśli będzie to jaka to wartość będzie?
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicEgX1WJ8qJGFp5nL8NZEKcBfMC1ZsZSsZmTJdRncViKLmK82kx4JJXXBFAey2jwET76Hq0hMbX1JK2SB5PHLugM4MxrugLNqOCB-SrNzxiH8UDXLhW1vBh4Vd6WjVQWE3II5YfH9vvH8/s1600/unionpicture.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicEgX1WJ8qJGFp5nL8NZEKcBfMC1ZsZSsZmTJdRncViKLmK82kx4JJXXBFAey2jwET76Hq0hMbX1JK2SB5PHLugM4MxrugLNqOCB-SrNzxiH8UDXLhW1vBh4Vd6WjVQWE3II5YfH9vvH8/s640/unionpicture.png" width="640" height="395" data-original-width="470" data-original-height="290" /></a></div>
</p>
<p>
Gdy już mało mówiący opis abstrakcyjny mamy za sobą teraz będzie trochę konkretów w stylu retro.
</p>
<h1> Retro przykład </h1>
<p>
Żeby nie było, że tylko nowe nowe nowe to zerknijmy zatem na przykład pamiętający czasy monitorów monochromatycznych
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiP_2XShb4vglyXkULSihULgPdesHVjXvOkl_XnfgzCiVMSujgGq3i6xOgnaxGagmnhleRdZ9VXDQyt-CruMPPlJ4XHhklLus7-7JtJJUIVTOXwu_5TDV_a-lmB21jC3Vn_a6jNqqtdAMw/s1600/findingneverland2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiP_2XShb4vglyXkULSihULgPdesHVjXvOkl_XnfgzCiVMSujgGq3i6xOgnaxGagmnhleRdZ9VXDQyt-CruMPPlJ4XHhklLus7-7JtJJUIVTOXwu_5TDV_a-lmB21jC3Vn_a6jNqqtdAMw/s400/findingneverland2.jpg" width="283" height="400" data-original-width="501" data-original-height="708" /></a></div>
</p>
<p>
Poniżej kawałek jakiejś tam definicji jednego z elementów w jakiejś tam specyfikacji. Nieważne. Ważny jest ten <b>choice</b> który sprawia, że tam w tym typie może być w sumie cokolwiek.
</p>
<pre style="background:#fff;color:#3b3b3b"> Schema Definition
<span style="color:#7a7a7a"><<span style="color:#016cff">element</span> <span style="color:#963dff">name</span>=<span style="color:#666">"X509Data"</span> <span style="color:#963dff">type</span>=<span style="color:#666">"ds:X509DataType"</span>/></span>
<span style="color:#7a7a7a"><<span style="color:#016cff">complexType</span> <span style="color:#963dff">name</span>=<span style="color:#666">"X509DataType"</span>></span>
<span style="color:#7a7a7a"><<span style="color:#016cff">sequence</span> <span style="color:#963dff">maxOccurs</span>=<span style="color:#666">"unbounded"</span>></span>
<span style="color:#7a7a7a"><<span style="color:#016cff">choice</span>></span>
<span style="color:#7a7a7a"><<span style="color:#016cff">element</span> <span style="color:#963dff">name</span>=<span style="color:#666">"X509IssuerSerial"</span> <span style="color:#963dff">type</span>=<span style="color:#666">"ds:X509IssuerSerialType"</span>/></span>
<span style="color:#7a7a7a"><<span style="color:#016cff">element</span> <span style="color:#963dff">name</span>=<span style="color:#666">"X509SKI"</span> <span style="color:#963dff">type</span>=<span style="color:#666">"base64Binary"</span>/></span>
<span style="color:#7a7a7a"><<span style="color:#016cff">element</span> <span style="color:#963dff">name</span>=<span style="color:#666">"X509SubjectName"</span> <span style="color:#963dff">type</span>=<span style="color:#666">"string"</span>/></span>
<span style="color:#7a7a7a"><<span style="color:#016cff">element</span> <span style="color:#963dff">name</span>=<span style="color:#666">"X509Certificate"</span> <span style="color:#963dff">type</span>=<span style="color:#666">"base64Binary"</span>/></span>
<span style="color:#7a7a7a"><<span style="color:#016cff">element</span> <span style="color:#963dff">name</span>=<span style="color:#666">"X509CRL"</span> <span style="color:#963dff">type</span>=<span style="color:#666">"base64Binary"</span>/></span>
<span style="color:#7a7a7a"><<span style="color:#016cff">any</span> <span style="color:#963dff">namespace</span>=<span style="color:#666">"##other"</span> <span style="color:#963dff">processContents</span>=<span style="color:#666">"lax"</span>/></span>
<span style="color:#7a7a7a"></<span style="color:#016cff">choice</span>></span>
<span style="color:#7a7a7a"></<span style="color:#016cff">sequence</span>></span>
<span style="color:#7a7a7a"></<span style="color:#016cff">complexType</span>></span>
<span style="color:#7a7a7a"><<span style="color:#016cff">complexType</span> <span style="color:#963dff">name</span>=<span style="color:#666">"X509IssuerSerialType"</span>></span>
<span style="color:#7a7a7a"><<span style="color:#016cff">sequence</span>></span>
<span style="color:#7a7a7a"><<span style="color:#016cff">element</span> <span style="color:#963dff">name</span>=<span style="color:#666">"X509IssuerName"</span> <span style="color:#963dff">type</span>=<span style="color:#666">"string"</span>/></span>
<span style="color:#7a7a7a"><<span style="color:#016cff">element</span> <span style="color:#963dff">name</span>=<span style="color:#666">"X509SerialNumber"</span> <span style="color:#963dff">type</span>=<span style="color:#666">"integer"</span>/></span>
<span style="color:#7a7a7a"></<span style="color:#016cff">sequence</span>></span>
<span style="color:#7a7a7a"></<span style="color:#016cff">complexType</span>></span>
</pre>
<p style="font-size:12px">
Żródło : <a href="https://www.w3.org/TR/xmldsig-core/">https://www.w3.org/TR/xmldsig-core/</a> <--- jakiś tam losowy standard sprzed 10 lat wybrany losowo na potrzeby artykułu.
</p>
<p>
No i są takie patenty w stylu JAX-WS, które to przewalą na kod javowy bardzo często mający więcej nulli niż rzeczywistych wartości. Ponieważ artykuł nie jest o xmlach i klasach javy wypełnionych po brzegi annotacjami to zrobimy wygodny skok/uproszczenie i dla potrzeb edukacyjnych "ekstrakcję" zasymilujemy na zwykłej takiej javowej mapie.
</p>
<h1>Bezpieczny i silnie typowany kod Javy 9</h1>
<p>
Także oto wspomniana mapka na potrzeby edukacyjne :
</p>
<pre style="background:#fff;color:#000">Map<String, String> m1 <span style="color:#0100b6;font-weight:700">=</span> Map<span style="color:#0100b6;font-weight:700">.</span>of(<span style="color:#d80800">"X509SKI"</span>, <span style="color:#d80800">"dupa"</span>);
</pre>
<p>
No i teraz najważniejsze. Chcemy wydobyć ten element kiedy tak naprawdę nie wiemy czy on tam jest, robimy to tak :
</p>
<pre style="background:#fff;color:#000"> <span style="color:#ff5600">Optional<<span style="color:#ff5600">X509Data</span>></span> result <span style="color:#ff5600">=</span> <span style="color:#ff5600">Optional</span>
.ofNullable(m1<span style="color:#ff5600">.</span>get(<span style="color:#00a33f">"X509SKI"</span>))<span style="color:#ff5600">.</span>map(<span style="color:#ff5600">X509Data</span><span style="color:#ff5600">.</span>X509SKI<span style="color:#ff5600">:</span><span style="color:#ff5600">:</span><span style="color:#ff5600">new</span>)
</pre>
<p>
No i fajnie ale to nie jedyna opcja w tej opcji - przecież możemy mieć <i>"X509CLR"</i> i teraz własnie wchodzi <b>or</b>
</p>
<pre style="background:#fff;color:#000"> <span style="color:#ff5600">Optional<<span style="color:#ff5600">X509Data</span>></span> result <span style="color:#ff5600">=</span> <span style="color:#ff5600">Optional</span>
.ofNullable(m1<span style="color:#ff5600">.</span>get(<span style="color:#00a33f">"X509SKI"</span>))<span style="color:#ff5600">.</span><span style="color:#ff5600"><</span><span style="color:#ff5600">X509Data</span><span style="color:#ff5600">></span>map(<span style="color:#ff5600">X509Data</span><span style="color:#ff5600">.</span>X509SKI<span style="color:#ff5600">:</span><span style="color:#ff5600">:</span><span style="color:#ff5600">new</span>)
.or(
() <span style="color:#ff5600">-</span><span style="color:#ff5600">></span> <span style="color:#ff5600">Optional</span><span style="color:#ff5600">.</span>ofNullable(m1<span style="color:#ff5600">.</span>get(<span style="color:#00a33f">"X509CLR"</span>))<span style="color:#ff5600">.</span>map(<span style="color:#ff5600">X509Data</span><span style="color:#ff5600">.</span>X509CLR<span style="color:#ff5600">:</span><span style="color:#ff5600">:</span><span style="color:#ff5600">new</span>)
)
</pre>
<p>
<ul>
<li>Obserwacja nr1 : Java nie ma czegoś takiego jak "pass by name" w skutek czego trzeba to zasymulować przekazaniem <i>Supplier</i> stąd to "()->" na początku</li>
<li>Obserwacja nr2 : zauważcie to <b>.<X509Data>map</b> : jeszcze nie pokazałem jak te typy sa modelowane ale generalnie X509Data to nad-typ i niestety wykrywanie typów w Javie kuleje jeszcze na tyle, że trzeba mu tutaj pomóc i powiedzieć żeby trzymał się typu bazowego. </li>
</ul>
</p>
<p>
No i ostatecznie mamy :
</p>
<pre style="background:#fff;color:#000"><span style="color:#ff5600">Optional<<span style="color:#ff5600">X509Data</span>></span> result <span style="color:#ff5600">=</span> <span style="color:#ff5600">Optional</span>
.ofNullable(m1<span style="color:#ff5600">.</span>get(<span style="color:#00a33f">"X509SKI"</span>))<span style="color:#ff5600">.</span><span style="color:#ff5600"><</span><span style="color:#ff5600">X509Data</span><span style="color:#ff5600">></span>map(<span style="color:#ff5600">X509Data</span><span style="color:#ff5600">.</span>X509SKI<span style="color:#ff5600">:</span><span style="color:#ff5600">:</span><span style="color:#ff5600">new</span>)
.or(
() <span style="color:#ff5600">-</span><span style="color:#ff5600">></span> <span style="color:#ff5600">Optional</span><span style="color:#ff5600">.</span>ofNullable(m1<span style="color:#ff5600">.</span>get(<span style="color:#00a33f">"X509CLR"</span>))<span style="color:#ff5600">.</span>map(<span style="color:#ff5600">X509Data</span><span style="color:#ff5600">.</span>X509CLR<span style="color:#ff5600">:</span><span style="color:#ff5600">:</span><span style="color:#ff5600">new</span>)
)<span style="color:#ff5600">.</span>or(
() <span style="color:#ff5600">-</span><span style="color:#ff5600">></span> <span style="color:#ff5600">Optional</span><span style="color:#ff5600">.</span>ofNullable(m1<span style="color:#ff5600">.</span>get(<span style="color:#00a33f">"X509IssuerSerial"</span>))
.map(data <span style="color:#ff5600">-</span><span style="color:#ff5600">></span> <span style="color:#ff5600">new</span> <span style="color:#ff5600">X509Data</span>.<span style="color:#ff5600">X509IssuerSerial</span>(data, 69))
);
</pre>
<h2>Closed Algebraic Data Type</h2>
<p>
Wróćmy teraz do modelu danych. Mamy pewien abstrakcyjny typ z określonymi jego realizacjami X509SKI, X509CosTamInnego itd. Inne języki niż Java wspierają taki typ przy pomocy konstrukcji, która z jednej strony nie jest finalna w nad-klasie a z drugiej pozwala jedynie na zadeklarowanie jasno określonej listy pod typów. (więcej na ten temat : <a href="http://pawelwlodarski.blogspot.com/2017/02/closedclosed-principle.html">http://pawelwlodarski.blogspot.com/2017/02/closedclosed-principle.html</a>) . W javie okazuję się jest też pewien "sposób" na takie rozwiązanie. Pod spodem zobacyzmy ograniczoną listę klasy wewnętrznych i klasę zewnętrzna z prywatnym konstruktorem -> czyli nic poza ta klasą nie stworzy nowej podklasy bo nie ma dostępu do konstruktora nadklasy - w teorii tak to własnie powinno działać.
</p>
<pre style="background:#fff;color:#000"><span style="color:#919191">//Java sealed type dla ubogich</span>
<span style="color:#ff5600">class</span> <span style="color:#21439c">X509Data</span> {
<span style="color:#ff5600">private</span> <span style="color:#21439c">X509Data</span>() {
}
<span style="color:#ff5600">final</span> <span style="color:#ff5600">static</span> <span style="color:#ff5600">class</span> <span style="color:#21439c">X509SKI</span> <span style="color:#ff5600">extends</span> X509Data {
<span style="color:#ff5600">final</span> <span style="color:#ff5600">String</span> value;
X509SKI(<span style="color:#ff5600">String</span> value) {
this<span style="color:#ff5600">.</span>value <span style="color:#ff5600">=</span> value;
}
}
<span style="color:#ff5600">final</span> <span style="color:#ff5600">static</span> <span style="color:#ff5600">class</span> <span style="color:#21439c">X509CLR</span> <span style="color:#ff5600">extends</span> X509Data {
<span style="color:#ff5600">final</span> <span style="color:#ff5600">String</span> value;
X509CLR(<span style="color:#ff5600">String</span> value) {
this<span style="color:#ff5600">.</span>value <span style="color:#ff5600">=</span> value;
}
}
<span style="color:#ff5600">final</span> <span style="color:#ff5600">static</span> <span style="color:#ff5600">class</span> <span style="color:#21439c">X509IssuerSerial</span> <span style="color:#ff5600">extends</span> X509Data {
<span style="color:#ff5600">final</span> <span style="color:#ff5600">String</span> name;
<span style="color:#ff5600">final</span> <span style="color:#ff5600">Integer</span> number;
<span style="color:#21439c">X509IssuerSerial</span>(<span style="color:#ff5600">String</span> name, <span style="color:#ff5600">Integer</span> number) {
this<span style="color:#ff5600">.</span>name <span style="color:#ff5600">=</span> name;
this<span style="color:#ff5600">.</span>number <span style="color:#ff5600">=</span> number;
}
}
}
</pre>
<h2>Wygodniej w Kotlinie</h2>
<p>
Ogólnie fajnie, że java się rozwija i stara się nadganiać ale niektóre rzeczy wciąż wyglądają jak wiadro z gównem. Toteż uwagę mą przykuwa coraz popularniejszy Kotlin, który pod kontem ekspresji jest dla mnie gdzieś pomiędzy Javą a Scalą - i co dobre wydaje się być jeszcze przed granicą gdzie nie udostępnia potężnych ale i niebezpiecznych mechanizmów, którymi dzieci w korporacjach robią sobie krzywdę. A co najważniejsze dla naszego przykładu - ma natywne wsparcie dla rekordów danych oraz typów algebraicznych
</p>
<pre style="background:#042029;color:#839496">sealed <span style="color:#a57800">class</span> <span style="color:#268bd2">X509Data</span>
data <span style="color:#a57800">class</span> <span style="color:#268bd2">X509SKI</span>(val value:String):X509Data()
data <span style="color:#a57800">class</span> <span style="color:#268bd2">X509CLR</span>(val value:String):X509Data()
data <span style="color:#a57800">class</span> <span style="color:#268bd2">X509IssuerSerial</span>(val name:String,val number:Int):X509Data()
</pre>
<p>
I mając rozwiązanie na największy ból obecnej javy czyli definicje małych klas rozjebane na dwa ekrany możemy przejść do naszego głównego przykładu
</p>
<pre style="background:#042029;color:#839496">val m1<span style="color:#859900">=</span>mapOf(<span style="color:#269186"><span style="color:#c60000">"</span>X509CLR<span style="color:#c60000">"</span></span> to <span style="color:#269186"><span style="color:#c60000">"</span>dupa<span style="color:#c60000">"</span></span>)
val result<span style="color:#859900">:</span><span style="color:#738a05">Optional<<span style="color:#738a05">X509Data</span>></span> <span style="color:#859900">=</span> <span style="color:#738a05">Optional</span>
.ofNullable(m1[<span style="color:#269186"><span style="color:#c60000">"</span>X509SKI<span style="color:#c60000">"</span></span>])<span style="color:#859900">.</span>map<span style="color:#859900"><</span><span style="color:#738a05">X509Data</span><span style="color:#859900">></span>(<span style="color:#859900">:</span><span style="color:#859900">:</span><span style="color:#cb4b16">X509SKI</span>)
.or{ <span style="color:#738a05">Optional</span><span style="color:#859900">.</span>ofNullable(m1[<span style="color:#269186"><span style="color:#c60000">"</span>X509CLR<span style="color:#c60000">"</span></span>])<span style="color:#859900">.</span>map(<span style="color:#859900">:</span><span style="color:#859900">:</span><span style="color:#cb4b16">X509CLR</span>)}
.or{ <span style="color:#738a05">Optional</span><span style="color:#859900">.</span>ofNullable(m1[<span style="color:#269186"><span style="color:#c60000">"</span>X509IssuerSerial<span style="color:#c60000">"</span></span>])<span style="color:#859900">.</span>map { data <span style="color:#859900">-</span><span style="color:#859900">></span> X509IssuerSerial(data,<span style="color:#d33682">69</span>) } }
</pre>
<p>
Okazuje się, że Kotlin bardzo dobrze radzi sobie z konwersją pomiędzy swoimi lambdami a <i>Javowymi SAM types</i>. Trzeba tylko przywyknąć do tych klamerek takich i będzie ok.
</p>
<div class="dygresja">
<h2>Edukacyjna rola Scali</h2>
Operator <b>Optional.or</b>, który jest nowością w Javie 9 był od dawna dostępny w scali jako <b>Option.orElse</b>. Poniżej jego definicja z charakterystyczną strzałką "=>" przed argumentem. Ten zapis oznacza "call by name" czyli argument jest zwyczajnie ewaluowany leniwie. Ponieważ w Javie nie ma czegoś takiego to zwyczajnie trzeba było się tam spodziewać <i>Supplier</i>. No i tak znając jeden język można z marszu przejść do używania "nowinek" w innym języku.
<pre style="color:#3b3b3b"> @inline <span style="color:#ff5600">final</span> <span style="color:#069;font-weight:700">def</span> <span style="color:#21439c">orElse</span>[B >: A](<span style="color:#0053ff;font-weight:700">alternative</span>: => Option[B]): Option[B] =
<span style="color:#069;font-weight:700">if</span> (isEmpty) alternative <span style="color:#069;font-weight:700">else</span> <span style="color:#0053ff;font-weight:700">this</span>
</pre>
</div>
<h1>Podsumowanie</h1>
<p>
Dzisiaj połączyliśmy technologię w miarę nowoczesną - Java 9 - która mimo wszystko trochę jest w plecy za resztą świata - z przykładem technologii tak starej, że pewnie wasz dziadek używał kiedy w dyliżansie przemierzał dziki zachód. To co chciałbym byście wynieśli to jednak ilustracja zastosowania operatora <b>na poziomie typów Optional</b>. Bo to już nie takie pseudo "ifowanie" w stylu
<pre>
Zaczytałem se jakiegoś syfa
użyje ifPresent czy getOrElse
i z Optionala mam kurwa zwykłego IFa
</pre>
To co pojawia się w przypadku <b>Optional.or</b> to - <i>algebra</i> - tak samo jak <i>algebra boolea</i> dla true|false . Java zmierza w dobrym kierunku (byleby jakiemu geniuszowi nie przyszło do głowy jebnąć na Optional jakiejś annotacji @orrable która w runtime obrzyga całe typesafety, nie , prosze nie, nie , poprostu nie)
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvYoogSIkwPH3vsFQBEHNnqjzUu7UzPBGpZpxJd0unHKDikpzoQndHpYuoCe0tt1v3tTYGVnw3jaHwP0CMrUq9F4reijz9pByW5TAb3aUE8zuznB2QeR0fMPxR8AGkPni39H5i8KX3C18/s1600/IMG_20170814_194549_945.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvYoogSIkwPH3vsFQBEHNnqjzUu7UzPBGpZpxJd0unHKDikpzoQndHpYuoCe0tt1v3tTYGVnw3jaHwP0CMrUq9F4reijz9pByW5TAb3aUE8zuznB2QeR0fMPxR8AGkPni39H5i8KX3C18/s400/IMG_20170814_194549_945.jpg" width="400" height="400" data-original-width="1600" data-original-height="1600" /></a></div>Paweł Włodarskihttp://www.blogger.com/profile/04891037231290616803noreply@blogger.com1tag:blogger.com,1999:blog-5047632037494901372.post-35410398989282796892017-09-25T08:28:00.000+02:002017-09-25T19:28:31.421+02:00Patronat medialny nad Konferencją ByteMyCode<p akapit="">
Na początek zgodnie z poradami książki* o marketingu internetowym, która kupiłem w 2009 roku w ksiągarni** elektronika - i w tej książce było napisane
by od razu walnąć główny link odpowiednim akcentem
</p>
<div style="font-size:15px; font-style: italic;">
*wytłumaczenie dla młodzieży - książka to taki rodzaj tabletu, który nie pobiera prądu ale nie ma możliwości customizowania wyświetlanej treści </br>
** księgarnia - taki sklep firmowy z książkami jak analogiczny iSpot ale różni się tym, że pracownicy mogą chodzić we własnych ubraniach </br>
</div>
<p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAl7hDZ0YrSjLlQhffoLSQOXhFi0eoPYJ821CfSofRoJgXb0OWf7k8imrmKKEktBJv56t42xIVQ66V8GWQws3MSwbYrHraPzF9fRHi7eSZ2PmX8dND0fxK9-qa0xARPjuFgIA46wKLS44/s1600/hot.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAl7hDZ0YrSjLlQhffoLSQOXhFi0eoPYJ821CfSofRoJgXb0OWf7k8imrmKKEktBJv56t42xIVQ66V8GWQws3MSwbYrHraPzF9fRHi7eSZ2PmX8dND0fxK9-qa0xARPjuFgIA46wKLS44/s1600/hot.gif" data-original-width="55" data-original-height="27" /></a></div>
</p>
<p>
<b>=============></b> <a href="https://bytemycode.pl/" style="font-size:30px;">!!!!!Konferencja Byte My Code Kliknij Tutaj!!!!!</a> <b><===========</b>
</p>
<p style="font-size:20px;font-weight:bold; text-align: center;">
Występują Java Czempioni:
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9nUdnIC3FT9HSJ-ed6NCHBN_XsS_G_2_1JZWbJYTaFm81XvnQMWvgdMgGdAMEL-9_NKriKWsZOnh65D29hzpDfuCE6fRM5h04hVYlFu2uzK7EVMXM1-waGcnECi5rBdOuuIvi7dwDjZA/s1600/joshlong.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9nUdnIC3FT9HSJ-ed6NCHBN_XsS_G_2_1JZWbJYTaFm81XvnQMWvgdMgGdAMEL-9_NKriKWsZOnh65D29hzpDfuCE6fRM5h04hVYlFu2uzK7EVMXM1-waGcnECi5rBdOuuIvi7dwDjZA/s400/joshlong.gif" width="400" height="400" data-original-width="512" data-original-height="512" /></a></div>
<p style="font-size:20px;font-weight:bold; text-align: center;">
Oraz:
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivfAPoCguWxWX7ILeT8skvFrvR2eqGRf4mYDg1EYVoBKGmoRLmJEPKOoTCekqoraJEA0UqhLEKzWKf3Q0LHM5eH40i_DSKWR1eHTAqZFu2vLnGxUhyOq4i5t057F4Hn30B_Lgg4bConR8/s1600/kirkpepperdine.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivfAPoCguWxWX7ILeT8skvFrvR2eqGRf4mYDg1EYVoBKGmoRLmJEPKOoTCekqoraJEA0UqhLEKzWKf3Q0LHM5eH40i_DSKWR1eHTAqZFu2vLnGxUhyOq4i5t057F4Hn30B_Lgg4bConR8/s400/kirkpepperdine.gif" width="400" height="400" data-original-width="512" data-original-height="512" /></a></div>
<p style="font-size:20px;font-weight:bold; text-align: center;">
I wiele innych atrakcji!!
</p>
<p>
<b>=============></b> <a href="https://bytemycode.pl/" style="font-size:30px;">!!!!!Konferencja Byte My Code Kliknij Tutaj!!!!!</a> <b><===========</b>
</p>
<p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAl7hDZ0YrSjLlQhffoLSQOXhFi0eoPYJ821CfSofRoJgXb0OWf7k8imrmKKEktBJv56t42xIVQ66V8GWQws3MSwbYrHraPzF9fRHi7eSZ2PmX8dND0fxK9-qa0xARPjuFgIA46wKLS44/s1600/hot.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAl7hDZ0YrSjLlQhffoLSQOXhFi0eoPYJ821CfSofRoJgXb0OWf7k8imrmKKEktBJv56t42xIVQ66V8GWQws3MSwbYrHraPzF9fRHi7eSZ2PmX8dND0fxK9-qa0xARPjuFgIA46wKLS44/s1600/hot.gif" data-original-width="55" data-original-height="27" /></a></div>
</p>
<p>
Ok skoro część marketingową mamy za sobą. To krótkie wyjaśnienie o co chodzi. Otóż okazało się, że tego bloga czytają nie tylko ruskie boty ale także gdzieś jakaś żywa tkanka jest tą treścią zainteresowana. No i zgłosiła się miła pani czy bym nie objął nad konferencją patronatu --> to obejmuję i jeszcze raz link <a href="https://bytemycode.pl/"">https://bytemycode.pl/"</a>
</p>
<p>
Jest to o tyle miłe, że w zasadzie ten blog to dla mnie generator wielu problemów. Dlaczego? Nie znajdziesz tutaj zbyt wielu tutoriali a raczej próbę zmuszenia ludzi do refleksji. Aby zmusić ludzi do refleksji trzeba zaburzyć ich porządek świata. Aby zaburzyć ich porządek świata trzeba zaburzyć ich widzenie siebie. A to w skrócie oznacza, że np. by wymusić na kimś z wieloletnim doświadczeniem w javie proces samo-refleksji trzeba mu wytłumaczyć, ze fakt iż zna zestaw annotacji z hibernate nie robi z niego programisty. No i teraz pytanie retoryczne czy owy proces sprzyja lajkom czy hejtom? Dlatego też jest to naprawdę miłe gdy ktoś jednak docenia ten wysiłek, chce czytać tę treść i zależy mu by tutaj coś się pojawiło.
</p>
<p>
Są dwie wejściówki do rozlosowania. Aby wziąć udział w losowaniu w komentarzach poniżej napiszcie proszę tak w kilku zdaniach dlaczego lubicie czytać tego bloga. Najlepsze dwie wypowiedzi otrzymają wejściówki.
..</br>
..</br>
..</br>
oczywiście kurwa żartuje, będzie losowanie standardowo na meetupie ---> <a href="https://www.meetup.com/Java-User-Group-Lodz/events/243630569/">LOSOWANIE</a>
</p>
<h1>WPIS NA FACEBOOKA PL:</h1>
<p>
Na koniec aby pokazać moją niezależność jako autora tego bloga wkleję tutaj notatkę przeznaczoną na fejsa
<div class="dygresja">
Spotkanie z #JavaChampions: Wrocław, 7 października! UBS Polska zaprasza na pierwszą edycję konferencji Byte My Code, podczas której spotkacie <b>#JavaChampions</b>: <b>Josha Long</b> oraz <b>Kirka Pepperdine</b>, jak również wyśmienitych specjalistów <b>#Java</b>: <b>Łukasza Szydło</b>, <b>Sebastiana Malaca</b>, <b>Michała Kordasa</b> i <b>innych</b>.
Wszystkich prelegentów oraz szczegółowe informacje znajdziecie na: <a href="https://bytemycode.pl">https://bytemycode.pl</a>
Nie czekajcie z rezerwacją biletu - na spotkanie z #<b>JavaChampions</b> przewidziano podczas pierwszej edycji tylko 250 biletów!
First come, first served!
</div>
</p>
<p>
I jeszcze zdjęcie gór.
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2PnGh1933XHhyphenhyphenMCsxy8_rHyXeFIcFht03xrOHT2NIgVsCVj812eTkJCgyKV4Y-yfQ-BSYiBSXLFwwmPJ0EoTlshR5isMNPjn31I-xgiXDGtdkZKbkevDHlX6me5j9OP01s6jpI1IwUik/s1600/schodzac_na_konczysty.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2PnGh1933XHhyphenhyphenMCsxy8_rHyXeFIcFht03xrOHT2NIgVsCVj812eTkJCgyKV4Y-yfQ-BSYiBSXLFwwmPJ0EoTlshR5isMNPjn31I-xgiXDGtdkZKbkevDHlX6me5j9OP01s6jpI1IwUik/s640/schodzac_na_konczysty.jpg" width="640" height="434" data-original-width="1080" data-original-height="733" /></a></div>Paweł Włodarskihttp://www.blogger.com/profile/04891037231290616803noreply@blogger.com0tag:blogger.com,1999:blog-5047632037494901372.post-87876971105195010462017-06-29T21:40:00.000+02:002017-06-30T21:14:32.254+02:00Na granicy systemu<p class="akapit">
Nie wiadomo czy to miejska legenda czy przypadek prawdziwy ale podobno w Indiach mają taką sztuczkę na łapanie małp : wsadzają banan w butelkę a butelkę zakopują. Teraz małpka wyciąga łapkę, łapie banan zaciskając paluszki i już łapka tam zostaje. Małpka banana nie puści i będzie tak czekała zaklinowana aż kłusownicy po nią przyjdą.
</p>
<p>
Przykład jest tak absurdalny, że doczekał się znaczenia metaforycznego kiedy to ludzie chwytają tak swoje myśli, które to wiążą ich w mentalnych klatkach. I ludzie ci tak będą czekać w tej klatce a myśli nie puszczą. Jaki to ma związek z dzisiejszym artykułem. W zasadzie żaden ale to fajna anegdota a zawsze te pierwsze akapity są najtrudniejsze.
</p>
<h1> Granice Systemu </h1>
<p>
Dzisiejszy artykuł sponsorują dwie funkcje :
<ul>
<li><i>toHex : String => Hex </i></li>
<li><i>createUser : Json => User</i> </li>
</ul>
Obie w założeniu działają na granicy systemu czyli zupełnie niekontrolowany 'input' zamieniają w typ domenowy. Coś jak na rysunku<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLOte0r4t2nYHKmLvYARFv69u1S2TWUEGO3C8NbfiruLesIGsTxJ58YbDRyVWjxYb-dDavwDGVutcgUMPAPYyl0wjMt267jhpZHwT3Jw_FRPiO2TaAZOQdUpDyrOICLREDdlgSiaIpMTE/s1600/systembasics.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLOte0r4t2nYHKmLvYARFv69u1S2TWUEGO3C8NbfiruLesIGsTxJ58YbDRyVWjxYb-dDavwDGVutcgUMPAPYyl0wjMt267jhpZHwT3Jw_FRPiO2TaAZOQdUpDyrOICLREDdlgSiaIpMTE/s400/systembasics.png" width="400" height="333" data-original-width="446" data-original-height="371" /></a></div>
</p>
<p>
<i>Hex</i> i <i>User</i>... z pozoru mają ze sobą niewiele wspólnego - tak jak i obydwie funkcje <i>toHex</i> oraz <i>createUser</i>. Ale jest pewna wspólna rzecz, jedna niespodziewana i siejąca spustoszenie w systemach IT rzecz. Nawet bez zaglądania do ich definicji można z dużym prawdopodobieństwem rzecz - obydwie te funkcje kłamią!
</p>
<h2> Program jako funkcja całkowita</h2>
<p>
Ten akapit będzie streszczeniem innego artykułu : <a href="http://pawelwlodarski.blogspot.com/2016/08/program-jako-funkcja-cakowita-czyli.html">Program jako funkcja całkowita</a> i generalnie chodzi o to, że bug w systemie jest wtedy jak myślimy że nasz <b>program-funkcja</b> jest zdefiniowany dla konkretnych danych wyjściowych a nie jest :( . Na przykład nasz program to aplikacja webowa przetwarzająca <i>request</i> w <i>response</i> czyli <b>Request=>Response</b> no i dla requestu z sqlinjection zachowanie poprawne nie było zdefiniowane - czyli na przykład wyświetlenie błędu - i całość zakończyła się katastrofą.
</p>
<p>
No i teraz jak mamy "miniprogram" <b>Json => User</b> to o ile dla każdego błędnego jsona nie zwracamy użytkownika <i>Roman</i> to to nie może działać!!!
</p>
<div class="dygresja">
<h2>Null object (czy coś takiego) </h2>
Kiedyś pamiętam był na tapecie taki koncept by nie zwracać z funkcji nuli tylko na przykład puste listy ,puste tablice, puste mapy, puste... puste k**wa cokolwiek. Potem pamiętam serię artykułów, że ludzie trochę zaczęli przekombinowywać i zwracać "puste" obiekty nie tylko gdy brakowało danych w bazie czy coś w ten deseń ale gdy np. wystąpił błąd. Jest to zamiatanie problemu pod dywan. Bardzo złe. Bardzo niedobre. Co możemy zwrócić jak jest zły JSON? No jeśli to nie jest na chama robiony CRUD to latający obiekt z "wrong variance" czy jak to się mówi po angielsku - spowoduje tylko kłopoty
</div>
<p>
Podobnie dla HEX -> "FFAA00" to dobry hex , "DUPA" to zły hex (acz trywialna implementacja String.getBytes obydwa zamieni w poprawny typ z poprawnymi pojedynczymi wartościami ale złym znaczeniem!!!) . I teraz weźmy dwie szkoły. Po pierwsze możemy rozszerzyć rezultat funkcji <b>String => Option[Hex]</b> czy <b> JSON => Option[User] </b>
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKJoIMV_JBFTrZxrev6Qm3qXSbxw70YqWaCx1WJukMjMQiUAVhHZwhEjFNVOqw5CEPf59wugWo3buJNq_OSOMRdpK8maV8bZ_FZTpiPLMVoiln8A48uLi2lQA6YAmo07nbZf-9f8iD1NM/s1600/fulldomain.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKJoIMV_JBFTrZxrev6Qm3qXSbxw70YqWaCx1WJukMjMQiUAVhHZwhEjFNVOqw5CEPf59wugWo3buJNq_OSOMRdpK8maV8bZ_FZTpiPLMVoiln8A48uLi2lQA6YAmo07nbZf-9f8iD1NM/s640/fulldomain.png" width="640" height="228" data-original-width="785" data-original-height="280" /></a></div>
<p>
Druga szkoła to dobrze znane nam wyjątki. Tutaj sztuczka polega na tym, że blok <b>try-catch</b> niejako ogranicza <b>dziedzine funkcji</b> ale w trochę nieintuicyjny sposób bo albo działamy na poprawnym zbiorze wartości i dostaniemy poprawny rezultat albo działamy na niepoprawnym zbiorze i ... zakrzywiamy czasoprzestrzeń lądując <i>"kiedyś"</i> i <i>"gdzieś"</i>.
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggQprtF9APpLZKyBcxgq0ZME7L94PbJ7cBlJc9W9jFJXx4Vg-3-i_tbh9GUAGbwB0KtpZXSvjkqg13pqp6URI1cZAzT6JnzcWUjxWmIHKEDZ_s91vHdG-nSCQGP_m0M2mwbdtsD2-rvvw/s1600/trycatch.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggQprtF9APpLZKyBcxgq0ZME7L94PbJ7cBlJc9W9jFJXx4Vg-3-i_tbh9GUAGbwB0KtpZXSvjkqg13pqp6URI1cZAzT6JnzcWUjxWmIHKEDZ_s91vHdG-nSCQGP_m0M2mwbdtsD2-rvvw/s640/trycatch.png" width="640" height="322" data-original-width="785" data-original-height="395" /></a></div>
<div class="dygresja">
<h2>Problem z null </h2>
Na nulla możemy także spojrzeć z perspektywy funkcji częściowej i całkowitej. Otóż jeśli np. mam funkcje <i>String => Option[Hex]</i> i jest ona całkowita ze względu na <i>każdy element zbioru String</i> to można szybko zamienić ją na częściową wprowadzając null gdyż wtedy domena zamienia się na "każdy element zbioru string <b>i do tego null</b>" czyli aby znowu uzyskać funkcję całkowita potrzebujemy dodać dedykowaną obsługę nulla.
</div>
<h2> Czas ma znaczenie </h2>
<p>
Znak zapytania na ostatnim diagramie to bardzo często jakiś tam <i>ErrorHandlingController</i>. To jedno ale druga sprawa to, że nie za bardzo mamy czas pomyśleć bo <b>to dzieje się teraz!!</b> . Skok w try następuje od razu. W przypadku szkoły pierwszej wspomnianej wcześniej mamy pewien typ. Ten typ mamy tu i teraz i możemy się chwile zastanowić - on nie ucieknie. Innymi słowami <i>try-catch</i> to wykonanie instrukcji a <i>Option[User]</i> czy <i>Option[Hex]</i> to obliczenia w toku. Co więcej obliczenia, które nawet nie muszą być jeszcze wykonane jeśli mamy leniwy język!
</p>
<p>
No i mając ten <i>Option</i> mogę stworzyć jego dalsze przetwarzania przy pomocy dostępnych kompozycji jak <b>option.orElse(otherOption)</b> . Przy skokach w try oczywiście też mogę dać obsługę wyjątków ale zazwyczaj nie wynika taka operacja z typów co dla <i>RuntimeException</i> zwiększa ryzyko, że o tym zapomnimy faktycznie o obsłudze. No i oczywiście sam skok to nie jest jakaś zwracana wartość tylko no... "skok" także nie można tego za bardzo komponować co może zakończyć się tuzinem zagnieżdżonych klamerek przy bardziej wyszukanej obsłudze.
</p>
<h2> Szkoła dwa_i_pół</h2>
<p>
W GO popularne jest inne podejście. Często funkcja zwraca potencjalny rezultat i potencjalny błąd przez co jest całkowita.
<!-- HTML generated using hilite.me --><div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;"><pre style="margin: 0; line-height: 125%"><span style="color: #008800; font-weight: bold">func</span> aleBezpieczneDzielenie(a, b <span style="color: #333399; font-weight: bold">float64</span>) (<span style="color: #333399; font-weight: bold">float64</span>, <span style="color: #333399; font-weight: bold">error</span>) {
<span style="color: #008800; font-weight: bold">if</span> b <span style="color: #333333">==</span> <span style="color: #6600EE; font-weight: bold">0.0</span> {
<span style="color: #008800; font-weight: bold">return</span> <span style="color: #6600EE; font-weight: bold">0.0</span>,errors.New(<span style="background-color: #fff0f0">"oj neidobrze"</span>)
} <span style="color: #008800; font-weight: bold">else</span> {
<span style="color: #008800; font-weight: bold">return</span> a<span style="color: #333333">/</span>b , <span style="color: #008800; font-weight: bold">nil</span>
}
}
</pre></div>
Problem z tym przykładem jest taki, że pomimo, iż potencjalne - to jednocześnie wartość i błąd musza być konkretne stad mimo wszystko zwracane jest <i>0.0</i> co jest dziwne - no i w sumie to ode mnie zależy czy błąd sprawdzę czy nie także nadal może się popsuć. Oczywiście nie znam tak dobrze jeszcze tego języka i być może jakaś opcja jeszcze gdzieś tam inna istnieje by to inaczej obsłużyć.
</p>
<h2>Szkoła trzecia - siła typów</h2>
<p class="akapit">
Zaczęliśmy od <b>A=>B</b> by dojść do teoretycznie bezpieczniejszego <b>A=>Option[B]</b> czyli bezpiecznie przyjąć dane z zewnątrz systemu
<ul>
<li>intoSystem: String => Option[Hex] </li>
<li>intosystem: JSON => Option[User] </li>
</ul>
</p>
<p>
Ale co gdy mimo wszystko chcemy zachować funkcję <b>String => Hex</b> ? Cóż wtedy, wtedy cóż? Być może to jakaś funkcja biblioteczna a może po prostu nam pasuje tak jak jest?
Zawsze można to zrobić to podejściem ze szkoły pierwszej czyli coś w stylu <b>lift : (A=>B) => (A=>Option[B])</b> ale można też rozwiazac problem od drugiej strony ograniczając dziedzinę do tylko prawilnych User-JSONów lub Hex-Stringów!
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJaztqHuQTvMIeHMCUqbAw4ycQq-UIV9NvX-AG1PZMl9myvNxdqMfgeI5YNgZeewvprWLcrAgWeLZQKOrf8mMkvOoxAUhd82bt1qWxc26jLuW4kANUUQY4dOaCDUAakCdEebi-SAlzj0g/s1600/safecontext.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJaztqHuQTvMIeHMCUqbAw4ycQq-UIV9NvX-AG1PZMl9myvNxdqMfgeI5YNgZeewvprWLcrAgWeLZQKOrf8mMkvOoxAUhd82bt1qWxc26jLuW4kANUUQY4dOaCDUAakCdEebi-SAlzj0g/s640/safecontext.png" width="640" height="157" data-original-width="1145" data-original-height="280" /></a></div>
<p>
Lub na jeszcze innym rysunku zobaczymy porównanie rozwiązania błędnego z funkcją częściową, funkcję całkowitą poprzez rozbudowanie domeny wyniku, oraz funkcję całkowitą poprzez ograniczenie domeny wejścia do bezpiecznego typu
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgui-dKsbF3rHsM1uTLhmdRJL1JBYWjIf9-iSZ344dBj5eQKOabCCXKf5iB8Vtr3ZJPfebIPk9BwHEFeAtLhzHiy9oMDc5OlzcMJCoOH8UYMqGwkeBeuR9uO2F9O7MCHD65AHaIwyiJkhE/s1600/porownanie.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgui-dKsbF3rHsM1uTLhmdRJL1JBYWjIf9-iSZ344dBj5eQKOabCCXKf5iB8Vtr3ZJPfebIPk9BwHEFeAtLhzHiy9oMDc5OlzcMJCoOH8UYMqGwkeBeuR9uO2F9O7MCHD65AHaIwyiJkhE/s640/porownanie.png" width="640" height="543" data-original-width="613" data-original-height="520" /></a></div>
<p>
W kodzie by to wyglądało mniej więcej tak:
<!-- HTML generated using hilite.me --><div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;"><pre style="margin: 0; line-height: 125%"><span style="color: #008800; font-weight: bold">val</span> validate<span style="color: #008800; font-weight: bold">:</span> <span style="color: #333399; font-weight: bold">String</span> <span style="color: #333333">=></span> <span style="color: #BB0066; font-weight: bold">Option</span><span style="color: #333333">[</span><span style="color: #333399; font-weight: bold">SafeHexString</span><span style="color: #333333">]</span> <span style="color: #008800; font-weight: bold">=</span> <span style="color: #333333">...</span>
<span style="color: #008800; font-weight: bold">val</span> toHex <span style="color: #008800; font-weight: bold">:</span> <span style="color: #333399; font-weight: bold">SafeHexString</span> <span style="color: #333333">=></span> <span style="color: #BB0066; font-weight: bold">Hex</span>
validate<span style="color: #333333">(</span>input<span style="color: #333333">).</span>map<span style="color: #333333">(</span>toHex<span style="color: #333333">)</span>
</pre></div>
</p>
<h2> Podsumowanie </h2>
<p>
Artykuł zaczęliśmy od śmiesznej anegdoty o małpce złapanej w butelkę (po która przyjdą kłusownicy - czyli może nie tak śmiesznej). Miało to nie być związane z samym artykułem ale jednak będzie. Metafora banana i trzymania się kurczowo nawyków. Gdy <b>Optional</b> pojawił się w Javie wielu programistów, z którymi miałem styczność traktował go jako takiego "wrapper na nulla". "Wrapper na nulla" należy do domeny Javy, być może dobrze czasem wznieść się na bardziej abstrakcyjny poziom by zobaczyć inną istotę używanych konstrukcji. Jeśli komuś nie pasuje metafora z małpką która będzie zjedzona w Indiach to inna opowieść to "Brzydkie Kaczątko" ale trzeba by ją trochę nagiąć by kaczątko stało się monadą niewykorzystanego potencjału.
</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQo7DYMT6qZaB5LFzUylL_arjYkjx6gUh7HFTS5cFcWOBFgQ96Ryvsoe7gUJG8tnN2gk1QmZRA2abbYUgfNn8RTi0Q04EKZj1OvGbSz9PLcU5PSQlhCQEMUlLBaREC5Xvev3rpeFfFoVg/s1600/20170624_161020.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQo7DYMT6qZaB5LFzUylL_arjYkjx6gUh7HFTS5cFcWOBFgQ96Ryvsoe7gUJG8tnN2gk1QmZRA2abbYUgfNn8RTi0Q04EKZj1OvGbSz9PLcU5PSQlhCQEMUlLBaREC5Xvev3rpeFfFoVg/s640/20170624_161020.jpg" width="640" height="360" data-original-width="1600" data-original-height="900" /></a></div>
Paweł Włodarskihttp://www.blogger.com/profile/04891037231290616803noreply@blogger.com8tag:blogger.com,1999:blog-5047632037494901372.post-24063140809492475262017-06-04T18:14:00.001+02:002017-06-04T22:13:23.515+02:00Rozszczepienie obiektu<p class="akapit">
Jest takie pojęcie - "myślenie lateralne" - stworzone przez E. De Bono, który jest takim specem od ogólnej nauki i przyswajania wiedzy.
W tejże książce znajdują się (takie fajne) rysunkowe przykłady graficznego tworzenia jakiegoś rozwiązania gdy dysponujemy ściśle określonym kształtem figur.
Zabity na pałę kształt figury symbolizuje sztywne przekonanie a problemy zbudowania rozwiązania symbolizują problemy szablonowego
podejścia do rozwiązania problemu gdy mamy tylko sztywne przekonania.
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTQETV2FxZOFXVNqgiElduev7zzz0-Aj3fXH-cTR1v9HL6X3pUF4OsbOtYLYRHyD0sCSewZpTAP4G8yD_tQYrwZngGDF3f4dFbT8_yEgny-q7N0GbiIAHvljUL2qbG7LdSaw44ICRJUe8/s1600/beton.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTQETV2FxZOFXVNqgiElduev7zzz0-Aj3fXH-cTR1v9HL6X3pUF4OsbOtYLYRHyD0sCSewZpTAP4G8yD_tQYrwZngGDF3f4dFbT8_yEgny-q7N0GbiIAHvljUL2qbG7LdSaw44ICRJUe8/s400/beton.jpg" width="400" height="225" data-original-width="1600" data-original-height="900" /></a></div>
</p>
<p>
Na kolejnych stronach sztywne kształty są rozbijane na nowe i w końcu budujemy rozwiązanie z nowych przekonań. Jak to ma się do programowwania?
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCqpnjLd4I_4eFy3I0QB_QkYCDj10_LG29lQ0xR9QIC6LhFuWYcy5IiON_DkQ3ERfIL6J0KqQF2irHdEwZFjTFtiS6kwCLUZCbTHISLUp1fWJNHCWiLXRn26R8y0YV9clT2cu9TYTdX58/s1600/nowe+ksztalty.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCqpnjLd4I_4eFy3I0QB_QkYCDj10_LG29lQ0xR9QIC6LhFuWYcy5IiON_DkQ3ERfIL6J0KqQF2irHdEwZFjTFtiS6kwCLUZCbTHISLUp1fWJNHCWiLXRn26R8y0YV9clT2cu9TYTdX58/s400/nowe+ksztalty.jpg" width="400" height="225" data-original-width="1600" data-original-height="900" /></a></div>
<p>
Jest takie powiedzenie <i>"jak programujesz młotkiem to wszystko wygląda jak gwoździe"</i> . Osobiście na tym blogu w ostatnich latach staram
się to stwierdzenie odnosić do Javy - z prostego powodu. Sam kiedyś myślałem, że "programowanie" zamyka się w segregacji interfejsów
by było bardziej "domenowo", dorzuceniu stosu annotacji by framework przyjął nasz kod i podregulowaniu JVM by było szybciej.
</p>
<p>
Dlatego też polecam by każdy podszedł do nauki kolejnego języka (nawet bez szybkiej perspektywy zastosowania go w praktyce), który zmusi go do wypróbowania zupełnie nowych podejść i sprawi, że sztywne kształty zostaną rozbite i nowa kompozycja rozwiązania stanie się realna.
</p>
<h1>Rozszczepienie obiektu</h1>
<p>
Mamy klasy, które mają pola - pola ustawiamy seterami lub konstruktorem a pobieramy getterami. Inne nazewnictwo tego mechanizmu to "mutatory" i "akcesory" (czy "accessory").
getter są połączone z daną instancją obiektu ... ale czy muszą?
</p>
<p>
Obiekty w javie to (chyba) częściej będą jakieś bezstanowe kontrolery/repozytoria lub zwykłe DTO/rekordy danych (pole+getter) aniżeli jakaś wyrafinowana enkapsulacja
zmiennego/mutowalnego stanu. Wynikać to poniekąd może z faktu, że dane i tak trzeba zapisać w bazie toteż "życie" takiego obiektu jest bardzo krótkie. Jeden z niewielu przykładów
gdzie z mojego doświadczenia takie prawo nie obowiązywało to akka-persistance gdzie aktor może kumulować prywatny stan mając zabezpieczenie w postaci "event journala" - nie wykluczone, że podobna sytuacja występuje w domenach i narzędziach, z którymi przyjemności nie miałem pracować ale chyba w CRUDach produkowanych w Łódzkich szwalniach raczej przeważa model "wyciąg z bazy, zmien i wciśnij na powrót".
</p>
<p>
I taka "obiektowa" reprezentacja rekordu danych np "User" nam do dalszych rozważań spokojnie wystarczy.
</p>
<p>
No bo teraz zobaczmy taką konstrukcję.
<pre style="background:#f9f9f9;color:#080808"><span style="color:#794938">class</span> <span style="color:#bf4f24">Street</span>(name:<span style="color:#a71d5d;font-style:italic">String</span>)
<span style="color:#794938">class</span> <span style="color:#bf4f24">Address</span>(s:<span style="color:#bf4f24">Street</span>,city:<span style="color:#a71d5d;font-style:italic">String</span>)
<span style="color:#794938">class</span> <span style="color:#bf4f24">User</span>(name:<span style="color:#a71d5d;font-style:italic">String</span>, address:<span style="color:#bf4f24">Address</span>)
</pre>
Mając cały czas ten pierwotny sztywny kształt "getter w instancji" próbując dostać się do nazwy ulicy otrzymamy .
<pre style="background:#f9f9f9;color:#080808">street.getName
address.getStreet.getName
user.getAddress.getStreet.getName
</pre>
</p>
<p>
Wiele osób sie skręci na ten widok bo tyle kropek w jednej linii uważane jest (poniekąd prawidłowo) za antywzorzec i nazwane "train wreck". Oburzenie jednocześnie byłoby i nie byłoby uzasadnione. Otóż spierdolina niewątpliwie może się pojawić gdy np. w obiekcie mamy listę produktów i staramy się pobrać najdroższy z nich
</p>
<p>
Można to zrobić źle
<pre style="background:#f9f9f9;color:#080808"><span style="color:#794938">class</span> <span style="color:#bf4f24">Klasa</span>{
<span style="color:#a71d5d;font-style:italic">private</span> <span style="color:#bf4f24">List</span><<span style="color:#bf4f24">Product</span>> products = ...
getProducts...
}
klasa.getProducts.sort(desc).takeFirst
</pre>
</p>
<p>
lub trochę lepiej :
<pre style="background:#f9f9f9;color:#080808"><span style="color:#794938">class</span> <span style="color:#bf4f24">Klasa</span>{
<span style="color:#a71d5d;font-style:italic">private</span> <span style="color:#bf4f24">List</span><<span style="color:#bf4f24">Product</span>> products = ...
findMostExpensive = products.sort(desc).takeFirst
}
klasa.findMostExpensive
</pre>
</p>
<p>
I to dla mnie wydawało się jasne i oczywiste gdy byłem w epoce javy ale nic nie stoi na przeszkodzie by cały czas mieć enkapsulację danych a wynieść metodę do innego obiektu, który może działa w zakresie prywatnym danej instancji. Brzmi trochę dziwnie ale np. scala umożliwia taką konstrukcje przy pomocy <b>companion object</b>
<pre style="background:#f9f9f9;color:#080808"><span style="color:#794938">class</span> <span style="color:#bf4f24">Klasa</span>{
<span style="color:#a71d5d;font-style:italic">private</span> <span style="color:#bf4f24">List</span><<span style="color:#bf4f24">Product</span>> products = ...
}
<span style="color:#794938">object</span> <span style="color:#bf4f24">Klasa</span>{
<span style="color:#794938">def</span> <span style="color:#bf4f24">findMostExpensive</span>(instance:<span style="color:#bf4f24">Klasa</span>) = instance.products.sort(desc).takeFirst
}
<span style="color:#5a525f;font-style:italic">//in a different package</span>
<span style="color:#794938">import</span> <span style="color:#234a97">Klasa.</span><span style="color:#234a97">_</span>
<span style="color:#234a97">val </span><span style="color:#234a97">k=new </span><span style="color:#234a97">Klasa</span>
<span style="color:#234a97">findMostExpensive(k)</span>
</pre>
i to może zadziałać tylko jeśli na liście będą metody, które sobie wymyśliłem. A jeśli mamy jakieś "superSpecjalistyczneBiznesoweSortowanie" ?
Wtedy można wywołać ją "explicit"
<pre style="background:#f9f9f9;color:#080808">superSpecjalistyczneBiznesoweSortowanie(instance.products).takeFirst
</pre>
Ale jeśli spojrzeć na superSpecjalistyczneBiznesoweSortowanie nie jak na metodę a jak na funkcję "List[Products] => List[Products]" wtedy może mieć miejsce zgrabna kompozycja
<pre style="background:#f9f9f9;color:#080808"><span style="color:#794938">val</span> <span style="color:#bf4f24">findMostExpensive</span> : <span style="color:#bf4f24">Klasa</span> => <span style="color:#bf4f24">Product</span> =
getProducts andThen superSpecjalistyczneBiznesoweSortowanie andThen getFirst
</pre>
<p/>
<p>
Czym jest <i>getProducts?</i> To getter w postaci funkcji, która przyjmuje daną instancje. Normalnie jak mamy "getCos" w klasie to tak "na pierwszy rzut oka" nie ma parametrów ale na rzut oka drugi w bajtkodzie będzie przekazany parametr "this" czyli mamy taki "coupling" gettera do danej konkretnej instancji. Możemy zrobić "decoupling" oraz odpowiednio sterować zakresem dostępu by getter wyciągał bebech w określonych miejscach.
</p>
<p>
ok, rozbijając pierwotny kształt dochodzimy do trochę innego sposobu budowania rozwiązania -> podążajmy dalej tym tropem
</p>
<h1> Optyka</h1>
<p>
Jeśli już mamy getName, getStreet i getAddress wtedy bez problemu możemy całość skomponować w jednego gettera
<pre style="background:#f9f9f9;color:#080808"><span style="color:#794938">val</span> <span style="color:#bf4f24">getStreetName</span> : <span style="color:#bf4f24">User</span> => <span style="color:#a71d5d;font-style:italic">String</span> = getAddress andThen getStreet andThen getName
</pre>
no fajnie ale co nam to daje? Jest to klasyczny przyklad user, ktory ma adres. Firma może mieć adres i zakup moze miec adres. no i można getter "reużyć" w kompozycji.
<pre style="background:#f9f9f9;color:#080808"><span style="color:#794938">val</span> <span style="color:#bf4f24">getStreet</span> : <span style="color:#bf4f24">Address</span> => <span style="color:#a71d5d;font-style:italic">String</span> = getStreet andThen getName
<span style="color:#794938">val</span> <span style="color:#bf4f24">companyStreet</span>: <span style="color:#bf4f24">Company</span> => <span style="color:#a71d5d;font-style:italic">String</span> = companyAddress andThen getStreet
<span style="color:#794938">val</span> <span style="color:#bf4f24">purchaseStreet</span>: <span style="color:#bf4f24">Purchase</span> => <span style="color:#a71d5d;font-style:italic">String</span> = purchaseAddress andThen getStreet
</pre>
No i jest rejuse poprzez ładną kompozycję. A to dopiero gettery. Magia zaczyna się gdy poskładamy tak sobie settery i może skromna wizualizacja poniżej.
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiA4JNc8CGIfPyMZLOXt9bInCjYEICyNig_vPWgAarSy5V-If3J8fYpQN7RqvErmAcJQd2Fy4bSVy0anE5nA32ElExtSaQ3okiPYPXKyzLr4EK4GRQ1v34UTjRCZppColvyJEWbZPfs4qg/s1600/lenses.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiA4JNc8CGIfPyMZLOXt9bInCjYEICyNig_vPWgAarSy5V-If3J8fYpQN7RqvErmAcJQd2Fy4bSVy0anE5nA32ElExtSaQ3okiPYPXKyzLr4EK4GRQ1v34UTjRCZppColvyJEWbZPfs4qg/s400/lenses.png" width="351" height="400" data-original-width="570" data-original-height="650" /></a></div>
<p>
Wspomniany mechanizm nie został odkryty tu i teraz. To jest popularne podejście FP zwane <b>Lens</b> i realizowany przez biblioteki Monocle(<a href="https://github.com/julien-truffaut/Monocle">https://github.com/julien-truffaut/Monocle</a>) lub rodzime Quicklens(<a href="https://github.com/adamw/quicklens">https://github.com/adamw/quicklens</a>).
A monocle dlatego, że lens jest częścią ogólniejszego mechanizmu zwanego <b>optics</b> i jest tam kilka innych ciekawych rzeczy.
</p>
<h2>Iso</h2>
<p>
Co jeśli w jednym kontekście numer ulicy to String ale gdzie indziej operujemy "bardziej domenowym" StreetNumber. Można łatwo dokomponować do gettera/settera konwersję "w tę i na zad".
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8skj2DoF9gijI84Qw5g6jwB5zt47d3yIebl4TqLpOrAk2fp6HRD-GIiT655o5Q7-tiZzr0Ch1wH9HJ06vaiAItwaYdxVlw5cCSV9GAA2kPyvWBocN6ksXdBUkfaPsIRcnVlragLi4Vas/s1600/iso.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8skj2DoF9gijI84Qw5g6jwB5zt47d3yIebl4TqLpOrAk2fp6HRD-GIiT655o5Q7-tiZzr0Ch1wH9HJ06vaiAItwaYdxVlw5cCSV9GAA2kPyvWBocN6ksXdBUkfaPsIRcnVlragLi4Vas/s400/iso.png" width="400" height="184" data-original-width="730" data-original-height="335" /></a></div>
<h2>Optional</h2>
<p>
Nulle to chuje. Kosztują wiele błędów, czasu i pieniędzy. Dlatego brak wartości należy modelować przy pomocy Option/Optional/Maybe . No i możemy Optional wkomponować w nasze gettery tak, że dalsze soczewki będa komponowane w kontekście potencjalnego braku wartości i na koniec dostajemy np. <i>Option[StreetNumber] </i>
</p>
<h2>List</h2>
<p>
Jeśli Option to zero lub jeden element - tak lista to zero lub n elementów. No i teraz taka opcja. Powiedzmy, że mamy jebany javowy moloch wygenerowany z SOAP.
<pre>
getUser composeTraversal getPurchases.map(_.price) composeFold reduce // to pseudokod
</pre>
I to może nam dać szybki raport o sumie zakupów
</p>
<h2>Functor</h2>
<p>
No to jak jest Option i jest List to pewnie będzie i generalizacja w postaci funktora. I np. w monocle mamy:
<pre style="background:#f9f9f9;color:#080808"><span style="color:#5a525f;font-style:italic"> /** modify polymorphically the target of a [[PLens]] using Functor function */</span>
<span style="color:#794938">def</span> <span style="color:#bf4f24">modifyF</span>[<span style="color:#bf4f24">F</span>[_]: <span style="color:#bf4f24">Functor</span>](<span style="color:#234a97">f</span>: <span style="color:#bf4f24">A</span> => <span style="color:#bf4f24">F</span>[<span style="color:#bf4f24">B</span>])(<span style="color:#234a97">s</span>: <span style="color:#bf4f24">S</span>): <span style="color:#bf4f24">F</span>[<span style="color:#bf4f24">T</span>]
</pre>
</p>
<h2>Pryzmat </h2>
<p>
Ta koncepcja raczej będzie opcja w świecie JAvy. Pryzmat jest w stanie rozszczepić abstrakcyjny typ ADT do konkretnego podtypu. Klasycznym przykladem jest
<pre style="background:#f9f9f9;color:#080808"><span style="color:#a71d5d;font-style:italic">sealed</span> <span style="color:#794938">trait</span> <span style="color:#bf4f24">Json</span>
<span style="color:#794938">case</span> <span style="color:#794938">class</span> <span style="color:#bf4f24">JStr</span>(s:<span style="color:#a71d5d;font-style:italic">String</span>) <span style="color:#794938">extends</span> <span style="color:#bf4f24">Json</span>
<span style="color:#794938">case</span> <span style="color:#794938">class</span> <span style="color:#bf4f24">JNum</span>(i:<span style="color:#a71d5d;font-style:italic">Int</span>) <span style="color:#794938">extends</span> <span style="color:#bf4f24">Json</span>
<span style="color:#5a525f;font-style:italic">//i to tutaj skopiowane prost z dokumentacji</span>
<span style="color:#794938">val</span> <span style="color:#bf4f24">jStr</span> = <span style="color:#bf4f24">Prism</span>[<span style="color:#bf4f24">Json</span>, <span style="color:#a71d5d;font-style:italic">String</span>]{
<span style="color:#794938">case</span> <span style="color:#bf4f24">JStr</span>(v) => <span style="color:#bf4f24">Some</span>(v)
<span style="color:#794938">case</span> _ => <span style="color:#811f24;font-weight:700">None</span>
}(<span style="color:#bf4f24">JStr</span>)
</pre>
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8caMCwpmHQs84NVn7pwEYkp-7oaMK-CLKcNP_v9RXiqo13zew2-nEBPst-v_lUvIJCi4DihAm8BQXVMMGeN95wnaqxF02GcZKXVB55n9w7Urh6L7r7bQhzQwssjzYfXfMtVwzqgghjBg/s1600/prism.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8caMCwpmHQs84NVn7pwEYkp-7oaMK-CLKcNP_v9RXiqo13zew2-nEBPst-v_lUvIJCi4DihAm8BQXVMMGeN95wnaqxF02GcZKXVB55n9w7Urh6L7r7bQhzQwssjzYfXfMtVwzqgghjBg/s400/prism.png" width="387" height="400" data-original-width="498" data-original-height="515" /></a></div>
<h1>Warsztaty</h1>
<p>
Temat poruszony w tym artykule został zainspirowany książką "[TYTUL]" która stanowi kręgosłup nowego cyklu warsztatów na łódzkim JUGu (JUG - Just User Group) "Modelowanie Domeny z FP". Pierwsze spotkanie już się odbyło i kilkanaście osób na tak wyspecjalizowany temat interpretuję jako zainteresowanie duże.
</p>
<p>
Na <div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgp9ROOaXmrs6BWfPPJqYxOhPjQgoYpcQiOXiuaV6p4l4M8OvW-AY5BZH93qAHRGt6jct1XjkbUTqP9zHG-yMSPFzzEmoHZBwXMeMVsNsPfR4bLMUqSlK6aG4RrEKIxCbekQXG3931ZwfQ/s1600/20170510_182240.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgp9ROOaXmrs6BWfPPJqYxOhPjQgoYpcQiOXiuaV6p4l4M8OvW-AY5BZH93qAHRGt6jct1XjkbUTqP9zHG-yMSPFzzEmoHZBwXMeMVsNsPfR4bLMUqSlK6aG4RrEKIxCbekQXG3931ZwfQ/s400/20170510_182240.jpg" width="400" height="225" data-original-width="1600" data-original-height="900" /></a></div>pierwszym spotkaniu uczyliśmy się jak wykorzystać monady do modelowania efektów (tak padło słowo monada i nie rozumiem tego podniecenia tu i tam - "nie wypowiem słowa na M"- po to kurwa ma ta konstrukcja nazwę by jej używać) oraz jak komponować operacje biznesowe będące czystymi funkcjami z efektami. Kolejna część po wakacjach bo jak jest lato i 30 stopni to nikomu się nie chce przychodzić i jest dla mnie strasznie frustrujące jak zapisuje się 30 osób a przychodzi 5. Także wrzesień - manipulacja złożonymi typami przy pomocy "optyki" a później pewnie użycie Monad Reader jako repozytoriów.
</p>
<p>
No a artykuł był o tym by zburzyć dogmaty na których zbudowane są nasze przekonania - w tym przypadku przekonanie, że zawsze getter musi być związany z dana instancją - a jak już to się stanie to możemy budować rozwiązania z nowych "kształtów"
</p>
<h1>Post SKRYPTum </h1>
<p>
I tutaj jeszcze link z mojej próby podejścia do tego tematu dwa lata temu : <a href="http://pawelwlodarski.blogspot.com/2015/08/soczewkiobiektywylenses.html">http://pawelwlodarski.blogspot.com/2015/08/soczewkiobiektywylenses.html</a>
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_UrVhhXSPQtaH4RH_UMpJKLY6n4Cajp2rsN0hyphenhyphenG_UVPar5-HNG1SjRN5JsTZxg28B14onDEvQsvikNfkxM5qKWO-RFfqTHq917Kbbl9MJUbfvKyg58uLXbcL8DdZQZ6J3l4hJ2B8RrgM/s1600/20170603_155709.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_UrVhhXSPQtaH4RH_UMpJKLY6n4Cajp2rsN0hyphenhyphenG_UVPar5-HNG1SjRN5JsTZxg28B14onDEvQsvikNfkxM5qKWO-RFfqTHq917Kbbl9MJUbfvKyg58uLXbcL8DdZQZ6J3l4hJ2B8RrgM/s640/20170603_155709.jpg" width="640" height="360" data-original-width="1600" data-original-height="900" /></a></div>
Paweł Włodarskihttp://www.blogger.com/profile/04891037231290616803noreply@blogger.com0tag:blogger.com,1999:blog-5047632037494901372.post-714791224787265722017-05-07T18:55:00.000+02:002017-05-07T18:55:06.435+02:00Jak w Javie można podkradać fajki czyli private nie takie prywatne<p class="akapit">
We wstępie do takiej jednej książki autorstwa Roberta Cialdiniego o obronie przed manipulacją jest przykład pewnego Indora (nie chodzi o popularne na siłowniach "<i>Indor</i> Cycling" ale o zwykłego żywego ptoka) i tamże naukowcy podrzucili temu prawdziwemu Indorowi sztucznego Indora, a w zasadzie nie indora tylko coś co wydawało <i>indorowate dziwięki</i> i to wystarczyło aby prawdziwy indor zaczął traktować odtwarzacz kasetowy jako swoje własne indorze piskle.
</p>
<p class="akapit">
Innymi popularnymi przykładami <i>bezrefleksyjnego zachowania bodziec-reakcja</i> w świecie przyrody będzie oczywiście czerwona płachta na byka, wydzielanie śliny po usłyszeniu dzwonka przez psa Pawłowa oraz oburzenie niektórych programistów Java gdy przed polami w klasie nie pojawia się słowo <b>private</b>.
</p>
<h2> Pola (Niepotrzebnie)Prywatne</h2>
<p class="akapit">
Jak kończy się bardzo często w praktyce dodawanie modyfikatora <i>private</i> do pól? Gdy chcemy stworzyć po prostu reprezentacje danych a język, w którym programujemy ma tylko klasy - wtedy tworzymy klasę, która ma być po prostu danymi - dodajemy pola i generujemy getter/settery.
</p>
<p>
Ewentualnie jeśli jesteśmy w tej branży odpowiednio długo to jednak nie dodajemy setterów. Można poczytać choćby w już 10 letniej <i>Effective Java</i> o zaletach (z angielska) "klas niemutowalnych" i stworzyć konstruktor, który będzie dbał o to by w naszym obiekcie nie pojawiły się śmieci w stylu sto-dwudziesty-ósmy dzień tygodnia, dajemy <b>final</b> przed polami i jest elegancko. A jak już jest obiekt i uda nam się uniknąć jałowej dyskusji czy to ma być <i>rich/fat/poor/flat/anemic</i> bo potrzebujesz rekord danych - a twój język zarówno technologicznie jak i ideologicznie nie dopuszcza możliwości stworzenia czegoś takiego - wtedy trzeba na końcu nazwy dodać "DTO" i następąpi kolejny cykl <i>bodziec-reakcja</i> gdzie na niektórych ludzi zadziała to jak mellissa i przestaną ci podsyłać posty Martina Fowlera z przed 15 lat.
</p>
<p>
Jak już mamy poprawnie stworzony obiekt (pamiętaj pamiętaj pamiętaj : "Data Transfer Object" a nie żaden "Record" - Wszystko jest obiektem a Record to takie nieobiektowe) wtedy trzeba dać możliwość dostępu do danych. No i jest jakaś teoria za geterami, która nazywa je (z angielska) "Akcesorami" i daje jakieś tam uzasadnienie że coś tam można prywatnie zmieniać w implementacji klasy bez zmiany jej interfejsu. O i tutaj zaraz na prawo jest taki post gdzie na obrazku w nagłówku jakaś ładna pani czyta wsadowy plik DOSa -> <a href="https://www.thoughtco.com/accessors-and-mutators-2034335">Accessors and Mutators</a>. No i jak to w tego typu postach mamy trochę z dupy naciąganą sytuacje gdzie w <strike>Rekordzie</strike> obiekcie <i>Person</i> trzeba było zmienić sposób w jaki przechowuje się middle name ze Stringa na Tablice. No niezwykle praktyczny przykład.
</p>
<p>
Oczywiście może pojawić się krytyka, że przecież muszą być gettery bo pola sa prywatne a przecież musza być prywatne bo jak nie będą to każdy tam wepchnie byle syf. Nie nie muszą. Mamy coś takiego jak juz wspomniane <b>final</b> i jak pole jest final to ustawiasz sobie raz to pole <i>public final String name</i> w konstruktorze. Na pewno się to nie uda gdy utrzymujemy projekt z przed 150 lat gdzie standard JSP wręcz wymusza by dostęp do danych był przez "getCosTam". To się nazywa konwencja i taką sobie przyjęli - być może inne <strike>Zręby</strike> frameworki też wymuszają taką konwencję. Cóż jak chcesz ich używać to nie masz wyjścia ale takie uzasadnienie "bo framework wymaga" ma niewiele wspólnego z perspektywą projektowania/modelowania systemu.
</p>
<p>
Apropo frameworków to możemy czasem wpaść na pomysł, że w sumie chcemy gdzieś zapisywać dane a później np. chcemy wyświetlić listę "Personów" na jednej ze stron naszego CRUDa. No i jest ten fajny framework, który mi wyciąga dane z bazy i pakuje do klas i w ogóle. I wystarczy tylko dać annotacje tu i tam. A no i trzeba dodać bezparametrowy konstruktor -> no bo frejmłork stworzy sobie pustą klasę i bedzie tam wpychał dane jak mu wygodnie, być może przez refleksję będzie je wpychał, być może z totalnym wyjebaniem na takie słówka jak <i>private</i>. No i wtedy nie ma wyjścia - jak masz konstruktor bezparametrowy to już pola nie mogą być final i musza być private. Chyba nie ma wyjścia --> <a href="http://stackoverflow.com/questions/32082633/jpa-implementation-that-doesnt-require-no-arg-constructor">z tej sytuacji bo taki standard jest.</a> No cóż.
<pre>
¯\_(ツ)_/¯
</pre>
</p>
<h2> Pola (potrzebnie)Prywatne</h2>
<p class="akapit">
Kiedy tworzenie pola prywatnego ma sens? Zawsze kiedy masz stan, który musisz zmieniać. To czy musisz mieć ten stan i czy to dobrze czy nie dobrze, że go zmieniasz to już inna historia. Obiekt może przechowywać stan, który na skutek interakcji z resztą systemu może ulegać zmianie i zależy ci aby przede wszystkim uniemożliwić te zmiany z zewnątrz. Z racji wydajnościowych lub innych ważnych powodów możesz chcieć operować efektywnymi acz umożliwiającymi machloje strukturami danych i a na zewnątrz chcesz operować bezpiecznymi niezmiennymi strukturami. I tutaj na przykład obiekt może manipulować tablicą bajtów czy StringBuilderem a z zewnątrz będzie można dane tylko jak string odczytywać. Plus jak sobie włączymy 2,3,4 wątek to bardzo bardzo nam powinno zależeć aby stan zmieniać tylko z jednego zabezpieczonego miejsca.
</p>
<p>
No i dla przypomnienia raz jeszcze. Jak sobie napiszesz klasę Person i tam jest getName, które zwraca prywatne pole typu String to nic nie ukrywasz - taka sztuka dla sztuki ten geter, a jak jeszcze masz seter bo jakiś framework tego chce to ani nie ma żadnego ukrywania ani żadnej kontroli. Cześtym argumentem pojawiającym się tutaj jest - "bo jak mam settera to walidację sobie mogę zrobić" - spójrz w lustro , spójrz sobie w oczy w tym lustrze i odpowiedz sam przed sobą ile razy twoja interakcja z setterem to było coś więcej niż IDE->GENERUJ.
</p>
<p>
W każdy razie po tym wstępie (tak to był wstęp, długi ale wstęp) przejdziemy do zasadniczej części artykułu. Jeśli już masz taki uzasadniony prywatny stan - to niespodzianka - on wcale taki prywatny w tej Javie nie jest.
</p>
<h1> Pola (Nawet nie wiesz, że nie)Prywatne</h1>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCtql6s1wWGCi4cT4mcXwYrsGjsK6t-Pf7nv0NLb7SbBkLBtvgDh8ArsuH_Bgt__j6zeGOaWsACx87_tOwrRbvp5a8wMzTAj_0-Z8TtiOSRCA7mfRs0dpHUu04LtCpqxph7tuNC8HAjHI/s1600/kieszonkowcy.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCtql6s1wWGCi4cT4mcXwYrsGjsK6t-Pf7nv0NLb7SbBkLBtvgDh8ArsuH_Bgt__j6zeGOaWsACx87_tOwrRbvp5a8wMzTAj_0-Z8TtiOSRCA7mfRs0dpHUu04LtCpqxph7tuNC8HAjHI/s320/kieszonkowcy.jpg" width="320" height="279" /></a></div>
<p>
Obiektem - a w zasadzie dwoma obiektami - naszych badań będą dwie instancje klasy <i>Osoba</i>. Klasa ta prezentuje koncept biednego człowieka relaksującego się przy pomocy używek.
</p>
<pre style="background:#f9f9f9;color:#080808"><span style="color:#a71d5d;font-style:italic">class</span> <span style="color:#bf4f24">Osoba</span>{
<span style="color:#a71d5d;font-style:italic">private</span> <span style="color:#a71d5d;font-style:italic">int</span> fajki;
<span style="color:#a71d5d;font-style:italic">public</span> <span style="color:#a71d5d;font-style:italic">final</span> <span style="color:#a71d5d;font-style:italic">String</span> name;
<span style="color:#a71d5d;font-style:italic">public</span> <span style="color:#bf4f24">Osoba</span>(<span style="color:#a71d5d;font-style:italic">int</span> <span style="color:#234a97">fajki</span>, <span style="color:#a71d5d;font-style:italic">String</span> <span style="color:#234a97">name</span>) {
<span style="color:#234a97">this</span><span style="color:#794938">.</span>fajki <span style="color:#794938">=</span> fajki;
<span style="color:#234a97">this</span><span style="color:#794938">.</span>name <span style="color:#794938">=</span> name;
}
<span style="color:#a71d5d;font-style:italic">public</span> <span style="color:#a71d5d;font-style:italic">String</span> <span style="color:#bf4f24">relax</span>(){
<span style="color:#794938">if</span>(fajki<span style="color:#794938">==</span><span style="color:#811f24;font-weight:700">0</span>)
<span style="color:#794938">return</span> name <span style="color:#794938">+</span> <span style="color:#0b6125">": o kurde gdzie moje fajki!"</span>;
<span style="color:#794938">else</span>{
fajki<span style="color:#794938">=</span>fajki<span style="color:#794938">-</span><span style="color:#811f24;font-weight:700">1</span>;
<span style="color:#794938">return</span> name <span style="color:#794938">+</span> <span style="color:#0b6125">": zostało mi "</span><span style="color:#794938">+</span>fajki<span style="color:#794938">+</span><span style="color:#0b6125">" fajek"</span>;
}
}
<span style="color:#a71d5d;font-style:italic">void</span> <span style="color:#bf4f24">podpierdolFajki</span>(<span style="color:#a71d5d;font-style:italic">Osoba</span> <span style="color:#234a97">ktosInny</span>){
<span style="color:#234a97">this</span><span style="color:#794938">.</span>fajki<span style="color:#794938">=</span>ktosInny<span style="color:#794938">.</span>fajki;
ktosInny<span style="color:#794938">.</span>fajki<span style="color:#794938">=</span><span style="color:#811f24;font-weight:700">0</span>;
}
}
</pre>
<div class="dygresja">
Palenie szkodzi zdrowiu. Poniższy przykład służy tylko edukacji bo prościej sobie wyobrazić, że ktoś podprowadzi fajki a nie witaminę B6.
</div>
<p>
I co my tam mamy? Jest publiczne pole <i>name</i> czyli już będzie (David) lincz na forach javowywch. Ale jest też prywatne pole fajki i nie ma metody <i>getFajki</i>. Nie powinno nikogo interesować jak ktoś chce sobie puścić dymka. No i w zależności od stanu prywatnego fajek w kieszeni tenże relaks się uda albo nie uda.
</p>
<p>
Mamy także i jeszcze jedną niepokojąca metodę. Metoda ta ma zakres <b>pakietowy</b> (o czym wielu zapomina, że taki jest bo jest niewidzialny) czyli możemy założyć, że to metoda prywatna dla danej paczki co jest także dosyć wygodne by podzielić logike na kilka klas w pakiecie bez pokazywania ich na świat.
</p>
<p>
No i w tej metodzie tak trochę wygląda jakby jedna instancja mogła zmienić stan w innej. czy to się kompiluje? Niestety albo stety tak
</p>
<pre style="background:#f9f9f9;color:#080808"><span style="color:#a71d5d;font-style:italic">Osoba</span> stefan=<span style="color:#794938">new</span> <span style="color:#a71d5d;font-style:italic">Osoba</span>(<span style="color:#811f24;font-weight:700">0</span>, <span style="color:#0b6125">"Stefan"</span>);
<span style="color:#a71d5d;font-style:italic">Osoba</span> babkaStefana=<span style="color:#794938">new</span> <span style="color:#a71d5d;font-style:italic">Osoba</span>(<span style="color:#811f24;font-weight:700">10</span>, <span style="color:#0b6125">"Babka Stefana"</span>);
stefan.podpierdolFajki(babkaStefana);
<span style="color:#a71d5d;font-style:italic">System</span>.<span style="color:#794938">out</span>.println(stefan.relax());
<span style="color:#a71d5d;font-style:italic">System</span>.<span style="color:#794938">out</span>.println(babkaStefana.relax());
</pre>
<div>
I chociaż Stefan nie ma fajek to jednak w wyniku szfindlu i kompilacji.
</div>
<pre>
Stefan: zostało mi 9 fajek
Babka Stefana: o kurde gdzie moje fajki!
</pre>
<div>
Dlaczego tak się stało? Otóż <b>private</b> w Javie nie jest dla obiektów ale dla klas! Dlatego też dwie instancje tego samego obiektu mogą sobie te prywatne pola czytać. Może to się przydać przy tzw "konstruktorach kopiujących" kiedy tworzymy nowy obiekt na podstawie starego. No i oczywiście coś takiego nie przeszkadza kiedy mamy udawane-obiekto-dane gdzie można sobie ustawić cokolwiek skądkolwiek przy pomocy settera.
</div>
<p>
Kiedy takie podkradanie danych przez instancje tej samej klasy zaczyna być zauważalne? Kiedy w deklaracji klasy pojawia się generyk oraz zależność pomiędzy klasą a typem generyka jest <i>Covariant</i> (więcej może tu : <a href="http://pawelwlodarski.blogspot.com/2017/01/kowariantne-konsekwencje.html">kowariantne-konsekwencje.html"</a>)
</p>
<h2>Pola (Naprawdę)Prywatne </h2>
Do eksperymentu wystarczy nam taka deklaracja :
<pre style="background:#f9f9f9;color:#080808"><span style="color:#794938">class</span> <span style="color:#bf4f24">Opakowanie</span>[+<span style="color:#bf4f24">A</span>](<span style="color:#a71d5d;font-style:italic">private</span> <span style="color:#794938">var</span> <span style="color:#bf4f24">mutable</span>:<span style="color:#bf4f24">ListBuffer</span>[<span style="color:#bf4f24">A</span>])
</pre>
No i co sie teraz stanie gdy będziemy tworzyć instancję?
<pre style="background:#f9f9f9;color:#080808"><span style="color:#794938">val</span> <span style="color:#bf4f24">o</span>=<span style="color:#794938">new</span> <span style="color:#bf4f24">Opakowanie</span>[<span style="color:#a71d5d;font-style:italic">String</span>](<span style="color:#bf4f24">ListBuffer</span>[<span style="color:#a71d5d;font-style:italic">String</span>]())
</pre>
Błąd !
<pre>
Error:(14, 34) covariant type A occurs in invariant position in type => scala.collection.mutable.ListBuffer[A] of variable mutable
class Opakowanie[+A](private var mutable:ListBuffer[A])
</pre>
<p>
o so chozi? Otóż z racji, że Opakowanie[String] jest podtypem Opakowania[Object] możliwe jest szachrajstwo gdzie Opakowanie[Int] podszywając się za Opakowanie[Object] podrzuci Inta do Listy Stringów - a tego nie chcemy. Nie chcemy usuwac tego <b>+A</b> bo chcemy miec <i>relację Covariant</i> - co zrobić? Otóż rozwiązaniem jest <b>prywatny zakres instancji</b>
</p>
<pre style="background:#f9f9f9;color:#080808"><span style="color:#794938">class</span> <span style="color:#bf4f24">Opakowanie</span>[+<span style="color:#bf4f24">A</span>](<span style="color:#a71d5d;font-style:italic">private</span>[<span style="color:#234a97">this</span>] <span style="color:#794938">var</span> <span style="color:#bf4f24">mutable</span>:<span style="color:#bf4f24">ListBuffer</span>[<span style="color:#bf4f24">A</span>])
</pre>
Jest coś takiego w Scali - Zakres prywatny Instancji .No i teraz żodyn tu int anie podrzuci Żodyn!!!
<h1> Podsumowanie </h1>
<p>
O czym dokładnie był ten artykuł? Na poziomie mechanicznym o tym, że niektóre mechanizmy języków nie zawsze działają tak jak nam się wydaje. Na poziomie ideologicznym był to apel by jednak do pewnych rzeczy nie podchodzić jak maszynka bo przemysł nas zaprogramował by lubić annotacje i "Beany". Czasem warto zajrzeć jak coś działa w innych językach a już na pewno uważać z używaniem cytatów Fowlera czy Unkla Boba jako argumentów - każdy przez to przechodzi i ja też przechodziłem - to, że konsultant, który oferuje swoje usługi płatnie wydał kilkanaście lat temu opinie jeszcze nie jest argumentem
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZCq9S_XwQpG309ECKJPIFiC3DIXuDC8ZJtzCkIX26p_-b9PAbu6NSwQewHOn3O16MkpQapCJG1M7ZByu2n9tHB8vxMo-vJnsBhyggCXA6IjLt1V8F8A1x7DO5aDkh2uOmUHEvvo8z6nY/s1600/gora2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZCq9S_XwQpG309ECKJPIFiC3DIXuDC8ZJtzCkIX26p_-b9PAbu6NSwQewHOn3O16MkpQapCJG1M7ZByu2n9tHB8vxMo-vJnsBhyggCXA6IjLt1V8F8A1x7DO5aDkh2uOmUHEvvo8z6nY/s400/gora2.jpg" width="400" height="400" /></a></div>Paweł Włodarskihttp://www.blogger.com/profile/04891037231290616803noreply@blogger.com0tag:blogger.com,1999:blog-5047632037494901372.post-78139941760978309992017-04-17T17:53:00.000+02:002017-04-17T17:53:38.154+02:00Nauka Modelowania Domeny z Programowaniem Funkcyjnym<h1>Co będzie</h1>
<p>
<ul>
<li>
Będzie warsztat FP + modelowanie domeny-> <a href="https://www.meetup.com/Java-User-Group-Lodz/events/239271453/">Modelowanie Domeny z FP - część 1 - Oddzielenie biznesu od efektów ubocznych</a>. Najprawdopodobniej 10 maja ale wiele rzeczy się dzieje to i termin może się przesunąć.
</li>
<li>na podstawie książki
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihxjrCjjql1xojTQIlhgumEdMgZ5W5WFBK2zJxiGBDnGEIgdZdwLfDodXXn660u5WhsE4zoiwThMjNTfIAq407IULrYoHVzGYlbWaLMJsYiDW524_cZmgqOf7UCNVM4wI_JsyZbzLSlEY/s1600/Cover.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihxjrCjjql1xojTQIlhgumEdMgZ5W5WFBK2zJxiGBDnGEIgdZdwLfDodXXn660u5WhsE4zoiwThMjNTfIAq407IULrYoHVzGYlbWaLMJsYiDW524_cZmgqOf7UCNVM4wI_JsyZbzLSlEY/s400/Cover.jpg" width="319" height="400" /></a></div>
</li>
<li>
w Scali
</li>
<li>
przykłady praktyczne z wykorzystaniem czasem zaawansowanego FP
</li>
<li>
nie będzie hajbernejta ani żadnych frameworków (nazywanych przez ludzi pozbawionych praktyki programistycznej "zrębami"), które gloryfikują kod gdzie jest więcej annotacji niż samego kodu -> czyli czegoś w stylu :
<pre>
@ManyToMany
@JoinTable(
name="EMP_PROJ",
joinColumns=@JoinColumn(name="EMP_ID", referencedColumnName="ID"),
inverseJoinColumns=@JoinColumn(name="PROJ_ID", referencedColumnName="ID"))
@WhatDoYouMeanByLearnSQL?
@FuckThoseRelationsOOPUberAlles
@IJustWantToHaveAListAndCallGetterOnIt
@IDontCare
@PleaseDontForceMeToThink
@MagicalAnnotationToMakeAllProblemsDissapear
@AndAlsoPleaseHandleTransactionsForMe
private List<Project> projects;
</pre>
(co w moich oczach przypomina bardziej średniowieczną alchemię gdzie dąży się do takiego dobrania składników by zamienić metal w złoto - w tym przypadku zamienić zwykłą deklarację listy w jakiś twór, który spełni niebanalne wymagania domenowe)
</li>
</ul>
</p>
<h2>A dokładniej</h2>
<p>
Traktujac ksiązkę jako kręgosłup nauki pojawia się następujący plan:
<ol>
<li>Tworzenie danych/aggregatów i oddzielenie operacji domenowych od operacji na efektach infrastruktory - Option,Try,Future,Validation -> i jak map i flatMap pomagają utworzyć przepływ danych </li>
<li>Lenses i kompozycja przekształceń na agregacie danych </li>
<li>Kompozycja operacji na repozytorium przy pomocy Monad Readera </li>
<li>Type classes i monoid - to da wiedzę jak uzyskąć znacznie lepszą kompozycję poprzez definicję symbolicznych operacji dla danego typu </li>
<li>Funktor,Applicative i Monady - jeszcze wiecej wiedzy jak uzyskać lepszą kompozycje funkcji biznesowych poprzez separację efektów ubocznych systemu. Tutja moga sie pojawiać zastosowania dla bardziej specjalistycznych typów jak StateMonad
</li>
<li>
No i jedziemy dalej z coraz silniejsza kompozycją - tutja będzie tzw. “Kleisli arrow” , która to konstrukcja pozwala komponować typy jak M[A] => M[B] prz pomocy funkcji z efektami A=>M[B]
</li>
<li>
Wykrywanie naruszeń zasad biznesowych w trakcie kompilacji - typy Fantomowe
</li>
<li>Modularyzacja/Bounded Context przy pomocy FreeMonad </li>
</ol>
</p>
<p>
Plan można zmieniać wedle upodobań. Formuła to zapewne dwie części z ćwiczeniami. Część pierwsze zajmie się bardziej mechanika używanych konstrukcji FP a druga bardziej zastosowaniem domenowym.
No i formułę tez oczywiście można zmienić wedle upodobań. Także (najprawdopodobniej) 10 maja zapraszam kto chętny : <a href="https://www.meetup.com/Java-User-Group-Lodz/events/239271453/">Modelowanie Domeny z FP - część 1 - Oddzielenie biznesu od efektów ubocznych</a>
</p>
Paweł Włodarskihttp://www.blogger.com/profile/04891037231290616803noreply@blogger.com2tag:blogger.com,1999:blog-5047632037494901372.post-77816299717169326292017-02-26T19:16:00.000+01:002017-02-26T19:16:32.202+01:00Closed/Closed Principle
<div class="cytat" style="margin: 20px; font-size: 1.2em">
(...)The short way of saying this is, OpenClosedPrinciple cannot work well without a good crystal ball. It is sort of like saying, "Stocks are easy, all you have to do is pick the right stock and you can be rich." It's a "tease" principle without teeth(...)
</div>
<h1>Wstęp</h1>
<p class="akapit">
Jest kilka zasad w programowaniu, których się po prostu "nie rusza". Nie podważa, nie analizuje, nie szuka alternatyw.A jeśli tylko spróbujesz to zostaniesz wykluczony z kręgu towarzyskiego "programistów, którzy rozumieją jak się robi dobre programy". I teraz spróbuj nie dostać kamieniem gdy wejdziesz z opinią, że open/close principle (po naszemu "ino otworte na rozszerzonie ać z domykiem na modyfikacjom!") może w niektórych miejscach przynieść więcej szkody niż pożytku.
</p>
<p>
Co jakiś czas można się nadziać na artykuł o zasadzie otwarte/zamknięte gdzie logika argumentacji trochę przebiega jak w przykładzie "a teraz pokaże wam, że opony zimowe są lepsze od letnich. Na potrzeby artykułu załóżmy, że wszędzie leży śnieg". Czyli "o tutaj mam taki problem, który dobrze rozwiązuje dziedziczenie w javie. Dla potrzeb dyskusji przyjmijmy, że każdy problem tak wygląda".
Mam nadzieję, że w tym artykule uda nam się zobaczyć, że rzeczywistość jest bardziej "różnorodna".
</p>
<p>
Ale zaczniemy od tego, że zazwyczaj przy okazji takich "praw" programowania gdzieś tam w tle pojawia się temat <b>zmiany</b> logiki/wymagań/funkcjonalności. I, że na zmianę trzeba się przygotować. Przygotowanie się na zmianę w miejscu gdzie ona nigdy nie nadejdzie może nas tak naprawdę sporo kosztować i wtedy zastosowanie "o/c" staje się zwykłym antywzorcem - a powiązany kawałek kodu zwykłą fuszerką. No ale jak to zmiana nie nadejdzie? Przecież w chaotycznie prowadzonym projekcie IT zmienia się wszystko! Nie. Nawet w tysiącach maksymalnie totalnie chujowo prowadzonych projektach jest kawałek logiki, który nigdy się nie zmienił i pewnie nie zmieni nigdy - i to od niego zaczniemy dalsze rozważania.
</p>
<h1>170 lat bez zmiany</h1>
<p>
(Albo 680 łokresów kwartalnych bez Rekłestu dla czendża w tejże logice)
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAhdlVN6b5ck5k32W3GfhAvEugjfV421Rd1Sj-X2c6v97EUIrCfwqq844i0pahUHxqmF_30sgPmxbP3fWJNdB0jBIq1LFa5EEeyy85JbwLer-5x_5vnX7Eu26J0zle9KECWGDW8IWwv00/s1600/truefalse.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAhdlVN6b5ck5k32W3GfhAvEugjfV421Rd1Sj-X2c6v97EUIrCfwqq844i0pahUHxqmF_30sgPmxbP3fWJNdB0jBIq1LFa5EEeyy85JbwLer-5x_5vnX7Eu26J0zle9KECWGDW8IWwv00/s400/truefalse.jpg" width="400" height="229" /></a></div>
<p>
Jeśli wierzyć internetowi (a dlaczego by nie wierzyć) Algebra Boola <i> was introduced by George Boole in his first book The Mathematical Analysis of Logic (1847)</i>. Czyli dawno. Bardzo. I nic się nie zmieniło.
</p>
<p>
Wyobraźmy sobie teraz na chwilę, że nie ma algebry Boolea (bóla). Ni ma. Ni ma <b>true</b>. Ni ma <b>false</b>. I w tym świecie ktoś rzuca speckę by taki typ zrobić. Potencjalnie można stworzyć popularną javową konstrukcję z "interfejsem, implementacjami , polimorfizm i w ogóle"
</p>
<pre style="background:#f9f9f9;color:#080808"><span style="color:#a71d5d;font-style:italic">interface</span> <span style="color:#bf4f24">Bool</span>{
<span style="color:#a71d5d;font-style:italic">Bool</span> <span style="color:#bf4f24">or</span>(<span style="color:#a71d5d;font-style:italic">Bool</span> <span style="color:#234a97">o</span>);
<span style="color:#a71d5d;font-style:italic">Bool</span> <span style="color:#bf4f24">and</span>(<span style="color:#a71d5d;font-style:italic">Bool</span> <span style="color:#234a97">o</span>);
}
<span style="color:#a71d5d;font-style:italic">class</span> <span style="color:#bf4f24">True</span> <span style="color:#a71d5d;font-style:italic">implements</span> <span style="color:#bf4f24">Bool</span>{
<span style="color:#a71d5d;font-style:italic">@Override</span>
<span style="color:#a71d5d;font-style:italic">public</span> <span style="color:#a71d5d;font-style:italic">Bool</span> <span style="color:#bf4f24">or</span>(<span style="color:#a71d5d;font-style:italic">Bool</span> <span style="color:#234a97">o</span>) {
<span style="color:#794938">return</span> <span style="color:#794938">new</span> <span style="color:#a71d5d;font-style:italic">True</span>();
}
<span style="color:#a71d5d;font-style:italic">@Override</span>
<span style="color:#a71d5d;font-style:italic">public</span> <span style="color:#a71d5d;font-style:italic">Bool</span> <span style="color:#bf4f24">and</span>(<span style="color:#a71d5d;font-style:italic">Bool</span> <span style="color:#234a97">o</span>) {
<span style="color:#794938">return</span> o;
}
}
<span style="color:#a71d5d;font-style:italic">class</span> <span style="color:#bf4f24">False</span> <span style="color:#a71d5d;font-style:italic">implements</span> <span style="color:#bf4f24">Bool</span>{
<span style="color:#a71d5d;font-style:italic">@Override</span>
<span style="color:#a71d5d;font-style:italic">public</span> <span style="color:#a71d5d;font-style:italic">Bool</span> <span style="color:#bf4f24">or</span>(<span style="color:#a71d5d;font-style:italic">Bool</span> <span style="color:#234a97">o</span>) {
<span style="color:#794938">return</span> o;
}
<span style="color:#a71d5d;font-style:italic">@Override</span>
<span style="color:#a71d5d;font-style:italic">public</span> <span style="color:#a71d5d;font-style:italic">Bool</span> <span style="color:#bf4f24">and</span>(<span style="color:#a71d5d;font-style:italic">Bool</span> <span style="color:#234a97">o</span>) {
<span style="color:#794938">return</span> <span style="color:#794938">new</span> <span style="color:#a71d5d;font-style:italic">False</span>();
}
}
</pre>
<p>
I chociaż technicznie taka implementacja powinna działać to jest ona bez sensu. Z bardzo prostego powodu. Chociaż dodanie nowego typu jest możliwe od strony mechaniki języka to od strony funkcjonalności to nie ma szans zadziałać. No bo jak byśmy dodali typ <b>AlmostFalse implements Bool</b> to teraz jak ma zmienić się zachowanie metod <i>and</i> i <i>or</i>?
</p>
<p>
Ponieważ typ jako taki <br/>
jest częścią API <br/>
to dając nowy</br>
czeka nas zawrót głowy</br>
</p>
<p>
W skrócie nie będzie działać. Dlatego tez <b>if</b> w javie od 20 wygląda tak samo. Jest albo <i>true</i> albo <i>false</i>. Nie ma nic innego i nie ma w planach niczego innego.
If - i wszystko co bazuje na boolean jako boolean - jest zamknięte na rozbudowę i zamknięte na rozszerzanie. I całe szczęście. Inaczej mało co by działało i reaktory by wybuchały.
</p>
<p>
W jednym z popularniejszych przykładów Open/Closed jest chyba ten gdzie dodaje się nowe figury geometryczne i tak mając interfejs "Figura" (Katarzyna) z metodą pole , mamy trójkąt i możemy sobie dodać kółko. Przykład jest wygodny i ma tę właściwość, że typy nie oddziałują same ze sobą czyli nie ma na tej płaszczyźnie pomiędzy nimi <b>relacji</b>. Relacji w rozumieniu abstrakcyjnym. I właśnie wokół tego słowa i ogólnie pojętej abstrakcji na chwile przejdziemy do mniej praktycznych rozważań.
</p>
<h1>Nazwy</h1>
<p>
Jak tam wyżej wspominaliśmy Boole'a" to tam był jeszcze chyba mianownik "kto?co? -> Algebra" . Algebra jest słowem niezwykle abstrakcyjnym i chyba nie atrakcyjnym dla szerokiej masy ludzi, którzy mówiąc "w życiu trzeba spróbować wszystkiego" mają zazwyczaj na myśli narkotyki i skoki z samolotu a nie zrozumienie Analizy Matematycznej (czy jakoś tak szedł ten dowcip).
</p>
<p>
Dlatego zamiast o abstrakcyjnych pojęciach matematycznych ruszymy łatwiejszą drogą, wkleję zdjęcie czaszki i porozmawiamy o grze.
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSMvKAjudcdMh-26UYywMu12D5LzOUE6ZH6Octp_CBrVSCvD0gYjzQ3wuddJwHqiYaqrUtaOIocRCI1H5a61Tr3dEO1gw8y3Dy73GAWkJVtpPlXGO43qN4d_AlhdfgGFOReAMnyn0g-R0/s1600/Planescape-Torment-Morte.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSMvKAjudcdMh-26UYywMu12D5LzOUE6ZH6Octp_CBrVSCvD0gYjzQ3wuddJwHqiYaqrUtaOIocRCI1H5a61Tr3dEO1gw8y3Dy73GAWkJVtpPlXGO43qN4d_AlhdfgGFOReAMnyn0g-R0/s400/Planescape-Torment-Morte.jpg" width="400" height="357" /></a></div>
<p>
Gra ciekawa, wydana ze 20 lat temu o tytule "Planescape torment" - główny bohater nie dość, że nie żyje to nie ma imienia i to właśnie temat "znaczenia imienia/nazwy" jest tam jednym z głównych wątków. Z tego co pamiętam w pewnym momencie spotykało się typka co to przeklinał dzień kiedy odzyskał imię bo od tego dnia właśnie jego wrogowie mogli rzucać w niego klątwami czy coś w tym stylu.
</p>
<p>
Podobnie możemy podejść do kwestii nazewnictwa przy rozważaniu praw programowania. Być może lepiej zahaczać o pewne pojęcia bez definiowania konkretnej nazwy. Ominiemy w ten sposób pole minowe nafaszerowane subtelnymi niuansami znaczeniowymi i unikniemy jałowych dyskusji w stylu "czy Try to Monada" i takie tam.
</p>
<h1>ADT po raz pierwszy</h1>
<p class="akapit">
Jak już pojawia się słowo Algebra niedaleko padają od jabłoni <i>Algebraiczne Typy Danych</i> i - czego się spodziewaliśmy - tuzin różnych definicji. Można sobie o tym poczytać na wikipedi <a href="https://en.wikipedia.org/wiki/Algebraic_data_type">https://en.wikipedia.org/wiki/Algebraic_data_type</a> . Sam również kiedyś próbowałem to opisać w sposób prawidłowy i zabawny tutaj ->
<a href="http://pawelwlodarski.blogspot.com/2016/05/typy-danych-ale-algebraiczne.html">http://pawelwlodarski.blogspot.com/2016/05/typy-danych-ale-algebraiczne.html</a>. Nie wiem czy udało mi się jedno albo drugie.
</p>
<p>
Skacząc dalej po linkach ciekawe zdanie jest umieszczone na haskellowej wiki : <a href="https://wiki.haskell.org/Algebraic_data_type">https://wiki.haskell.org/Algebraic_data_type</a>
</p>
<div class="cytat" style="font-weight:bold">
This is a type where we specify the shape of each of the elements(...)
</div>
<p>
Czyli rozumiejąc tak jak jest mi na tę chwilę wygodnie będzie to typ, gdzie wszystkie elementy są jasno określone. Czyli dla typu Boolean jasno określone są True i False. Tylko, że znowu może to znaczy to a może coś innego. Jaki jest rozpierdziel z definicjami doczytamy w dalszych akapitach zacytowanej strony.
</p>
<div class="cytat">
Algebraic Data Type is not to be confused with *Abstract* Data Type, which (ironically) is its opposite, in some sense. The initialism "ADT" usually means *Abstract* Data Type, but GADT usually means Generalized *Algebraic* Data Type.
</div>
Także tego...
<h1>ADT po raz drugi (i PDT)</h1>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwomFKOZXssYqEaGuayjVGVePoD9eNQXV5GEJefzovP_5DU8dUnVde9gEXja0qzSJMCly6Kbkw_tGDM4_SUx-OVuhH7DbFdI1s5WeioyxFURjfwgTr9XMWaWLoNMxJYLjtNjYYflQhu28/s1600/oopvsadt.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwomFKOZXssYqEaGuayjVGVePoD9eNQXV5GEJefzovP_5DU8dUnVde9gEXja0qzSJMCly6Kbkw_tGDM4_SUx-OVuhH7DbFdI1s5WeioyxFURjfwgTr9XMWaWLoNMxJYLjtNjYYflQhu28/s400/oopvsadt.jpg" width="400" height="166" /></a></div>
Link do opracowania : <a href="Object-Oriented Programming Versus Abstract Data Types">https://www.cs.utexas.edu/users/wcook/papers/OOPvsADT/CookOOPvsADT90.pdf</a>
<p>
Wspomniana tutaj praca zestawia ze sobą reprezentacje typów programowania obiektowego zwaną dalej <b>PDT - Procedural Data Types</b> z innym <b>ADT - Abstract Data Types</b>. Przyswajania informacji wcale nie ułatwia fakt, że cytowana w poprzednim punkcie wiki Haskella twierdzi, że Abstract Data Types to coś przeciwnego do Algebraic Data Types a autorzy tego opracowania twierdzą, że jest "complementary" do programowania obiektowego.
</p>
<p>
Praca ma stron 20 dlatego wybierzemy sobie z niej jeden interesujący aspekt odnośnie dwóch różnych podejść do modelowania danych.
</p>
<div class="cytat">
ADTs are organized around the observations. Each observation is implemented as an operation
upon a concrete representation derived from the constructors. The constructors are also implemented
as operations that create values in the representation type. The representation is shared among the
operations, but hidden from clients of the ADT.
<br/><br/>
PDA is organized around the constructors of the data abstraction. The observations become the
attributes, or methods, of the procedural data values. Thus a procedural data value is simply defined by
the combination of all possible observations upon it.
</div>
<p>
Definicje znowu sa bardzo abstrakcyjne ale na szczęście w artykule mamy przykłady konkretnych deklaracji listy zarówno w zgodzie z PDT jak i ADT. Lista koncepcyjnie jako lista będzie też czymś co może zaskoczyć programistów "tylko javy" bo będzie ona reprezentowana jako dwa pod typy "ELEMENT_LISTY" oraz "KONIEC_LISTY"
</p>
<h3>PDT</h3>
<pre style="background:#f9f9f9;color:#080808"><span style="color:#811f24;font-weight:700">Nil</span> <span style="color:#794938">=</span> recursive self <span style="color:#794938">=</span> record
<span style="color:#693a17">null</span><span style="color:#794938">?</span> <span style="color:#794938">=</span> true
<span style="color:#693a17">head</span> <span style="color:#794938">=</span> <span style="color:#693a17">error</span>;
<span style="color:#693a17">tail</span> <span style="color:#794938">=</span> <span style="color:#693a17">error</span>;
cons <span style="color:#794938">=</span> fun(y) <span style="color:#811f24;font-weight:700">Cell</span>(y<span style="color:#794938">,</span> self);
equal <span style="color:#794938">=</span> fun(m) m<span style="color:#794938">.</span><span style="color:#693a17">null</span><span style="color:#794938">?</span>
end
<span style="color:#811f24;font-weight:700">Cell</span>(x<span style="color:#794938">,</span> l) <span style="color:#794938">=</span> recursive self <span style="color:#794938">=</span> record
<span style="color:#693a17">null</span><span style="color:#794938">?</span> <span style="color:#794938">=</span> false
<span style="color:#693a17">head</span> <span style="color:#794938">=</span> x;
<span style="color:#693a17">tail</span> <span style="color:#794938">=</span> l;
cons <span style="color:#794938">=</span> fun(y) <span style="color:#811f24;font-weight:700">Cell</span>(y<span style="color:#794938">,</span> self);
equal <span style="color:#794938">=</span> fun(m) (<span style="color:#693a17">not</span> m<span style="color:#794938">.</span><span style="color:#693a17">null</span><span style="color:#794938">?</span>)
<span style="color:#693a17">and</span> (x <span style="color:#794938">=</span> m<span style="color:#794938">.</span><span style="color:#693a17">head</span>)
<span style="color:#693a17">and</span> l<span style="color:#794938">.</span>equal(m<span style="color:#794938">.</span><span style="color:#693a17">tail</span>)
end
</pre>
<p>
Nie mogłem namierzyć info czy to jakiś konkret język czy taki edukacyjny pseudokod ale nie ma to znaczenia bo PDF i tak go nie skompiluje. Ten kawałek tutaj przypomina podejście "polimorfizm ala Java" ino trzeba tam jakiś <i>interface List</i> dodać. Mamy pod-typy i każdy po swojemu przeciąża metodę. Czyli tak jak napisaliśmy wcześniej : "Thus a procedural data value is simply defined by
the combination of all possible observations upon it."
A teraz zobaczmy to samo inaczej
</p>
<h3>ADT</h3>
<pre style="background:#f9f9f9;color:#080808">adt <span style="color:#811f24;font-weight:700">IntList</span>
representation
list <span style="color:#794938">=</span> <span style="color:#811f24;font-weight:700">NIL</span> <span style="color:#794938">|</span> <span style="color:#811f24;font-weight:700">CELL</span> <span style="color:#794938">of</span> integer * list
operations
nil <span style="color:#794938">=</span> <span style="color:#811f24;font-weight:700">NIL</span>
adjoin(x <span style="color:#794938">:</span> integer<span style="color:#794938">,</span> l <span style="color:#794938">:</span> list) <span style="color:#794938">=</span>
<span style="color:#811f24;font-weight:700">CELL</span>(x<span style="color:#794938">,</span> l)
<span style="color:#693a17">null</span><span style="color:#794938">?</span>(l <span style="color:#794938">:</span> list) <span style="color:#794938">=</span> <span style="color:#794938">case</span> l <span style="color:#794938">of</span>
<span style="color:#811f24;font-weight:700">NIL</span> ⇒ true
<span style="color:#811f24;font-weight:700">CELL</span>(x<span style="color:#794938">,</span> l) ⇒ false
<span style="color:#693a17">head</span>(l <span style="color:#794938">:</span> list) <span style="color:#794938">=</span> <span style="color:#794938">case</span> l <span style="color:#794938">of</span>
<span style="color:#811f24;font-weight:700">NIL</span> ⇒ <span style="color:#693a17">error</span>
<span style="color:#811f24;font-weight:700">CELL</span>(x<span style="color:#794938">,</span> l ) ⇒ x
<span style="color:#693a17">tail</span>(l <span style="color:#794938">:</span> list) <span style="color:#794938">=</span> <span style="color:#794938">case</span> l <span style="color:#794938">of</span>
<span style="color:#811f24;font-weight:700">NIL</span> ⇒ <span style="color:#693a17">error</span>
<span style="color:#811f24;font-weight:700">CELL</span>(x<span style="color:#794938">,</span> l ) ⇒ l
equal(l <span style="color:#794938">:</span> list<span style="color:#794938">,</span> m <span style="color:#794938">:</span> list) <span style="color:#794938">=</span> <span style="color:#794938">case</span> l <span style="color:#794938">of</span>
<span style="color:#811f24;font-weight:700">NIL</span> ⇒ <span style="color:#693a17">null</span><span style="color:#794938">?</span>(m)
<span style="color:#811f24;font-weight:700">CELL</span>(x<span style="color:#794938">,</span> l ) ⇒ <span style="color:#693a17">not</span> <span style="color:#693a17">null</span><span style="color:#794938">?</span>(m)
<span style="color:#693a17">and</span> x <span style="color:#794938">=</span> <span style="color:#693a17">head</span>(m)
<span style="color:#693a17">and</span> equal(l <span style="color:#794938">,</span> <span style="color:#693a17">tail</span>(m))
</pre>
<p>
Tym razem bardziej to przypomina prosty zestaw typów z jasno zdefiniowanym zbiorem operacji, który można nań wykonać.Zwróć uwagę, że każda z operacji jest w pełni świadoma jakiego typu dane może dostać i stosuje nań standardowy <b>pattern matching</b>. Czyli tak jak napisalismy wcześniej : "Each observation is implemented as an operation
upon a concrete representation derived from the constructors(...)The representation is shared among the
operations, but hidden from clients of the ADT."
</p>
<h1>Praktycznie</h1>
<p>
Po tej teoretycznej wycieczce po abstrakcjach i ciekawych artykułach skupimy się na słowie, które już wcześniej padło odnośnie ADT i PDT a daje nadzieje na "win-win" czyli <b>complementary</b> - znaczy, że uzupełniający się. Będę starał się pokazać, że to nie jest żadne <b>vs</b> ale, że nasze standardowe podejście javowe może łatwo współpracować z czymś co łamie dobitnie zasadę open/closed.
</p>
<p>
Na początek zacznijmy ze standardową sytuacją, gdzie faktycznie chcemy dać sobie furtkę do rozszerzania danej logiki przez dodanie kolejnych implementacji "Biznesowej Walidacji". Będzie to mechanizm w zgodzie z O/C principle.
</p>
<pre style="background:#f9f9f9;color:#080808"><span style="color:#794938">object</span> <span style="color:#bf4f24">BusinessLogic</span>{
<span style="color:#794938">trait</span> <span style="color:#bf4f24">BusinessData</span>
<span style="color:#794938">trait</span> <span style="color:#bf4f24">BusinessValidationPDT</span>{
<span style="color:#794938">def</span> <span style="color:#bf4f24">isValid</span>(bd:<span style="color:#bf4f24">BusinessData</span>):<span style="color:#a71d5d;font-style:italic">Boolean</span>
}
<span style="color:#794938">def</span> <span style="color:#bf4f24">validateProcess</span>(data:<span style="color:#bf4f24">BusinessData</span>,checks:<span style="color:#bf4f24">Iterable</span>[<span style="color:#bf4f24">BusinessValidationPDT</span>]):<span style="color:#a71d5d;font-style:italic">Boolean</span> =
checks.forall(check => check.isValid(data))
}
</pre>
<p>
Czyli tak jak z tymi figurami w oryginalnym przykładzie tak i tutaj mogę sobie dorzucić kolejną implementację. Mamy w tej sytuacji także druga rodzinę typów totalnie zamkniętych na wszelkie rozszerzania czyli już wcześniej wspomniany boolean. Teraz aby to rozróżnienie bardziej unaocznić zastąpmy boolean własnym typem, który po za tym, że coś się zepsuło niesie informacje co się zepsuło.
</p>
<pre style="background:#f9f9f9;color:#080808"><span style="color:#794938">object</span> <span style="color:#bf4f24">CheckADT</span>{
<span style="color:#a71d5d;font-style:italic">sealed</span> <span style="color:#794938">trait</span> <span style="color:#bf4f24">CheckResult</span>
<span style="color:#a71d5d;font-style:italic">final</span> <span style="color:#794938">case</span> <span style="color:#794938">object</span> <span style="color:#bf4f24">CheckOK</span> <span style="color:#794938">extends</span> <span style="color:#bf4f24">CheckResult</span>
<span style="color:#a71d5d;font-style:italic">final</span> <span style="color:#794938">case</span> <span style="color:#794938">class</span> <span style="color:#bf4f24">CheckFailure</span>(info:<span style="color:#bf4f24">List</span>[<span style="color:#bf4f24">Throwable</span>]) <span style="color:#794938">extends</span> <span style="color:#bf4f24">CheckResult</span>
<span style="color:#794938">def</span> <span style="color:#bf4f24">combine</span>[<span style="color:#bf4f24">A</span>](checks:<span style="color:#bf4f24">Iterable</span>[<span style="color:#bf4f24">CheckResult</span>]):<span style="color:#bf4f24">CheckResult</span> = checks.foldLeft[<span style="color:#bf4f24">CheckResult</span>](<span style="color:#bf4f24">CheckOK</span>){
<span style="color:#794938">case</span> (<span style="color:#bf4f24">CheckOK</span>,<span style="color:#bf4f24">CheckOK</span>) => <span style="color:#bf4f24">CheckOK</span>
<span style="color:#794938">case</span> (<span style="color:#bf4f24">CheckOK</span>,<span style="color:#234a97">f</span> : <span style="color:#bf4f24">CheckFailure</span>) => f
<span style="color:#794938">case</span> (<span style="color:#234a97">f</span> : <span style="color:#bf4f24">CheckFailure</span>, <span style="color:#bf4f24">CheckOK</span>) => f
<span style="color:#794938">case</span> (<span style="color:#bf4f24">CheckFailure</span>(info1),<span style="color:#bf4f24">CheckFailure</span>(info2)) => <span style="color:#bf4f24">CheckFailure</span>(info1 ++ info2)
}
}
</pre>
<p>
Tym razem przy definicji traitu mamy slówko <b>sealed</b> czyli nie możemy dodawać nowych rozszerzeń poza plikiem gdzie ów trait jest zdefiniowany. Oznacza to w praktyce, że mamy dwa możliwe podtypy CheckResult i nic więcej. Teraz pytanie czy to ADT i jeśli ADT to Abstract czy Algebraic? Z punktu praktycznego nie ma to żadnego znaczenia i możemy go również nazwać "Andrzeja Dom Tonie" czy coś takiego. To co nas najbardziej interesuje to, że mamy jasno zdefiniowaną operacje na jasno zdefiniowanym zestawie typów : <b>combine</b>.
</p>
<p>
W zasadzie nic nie stoi na przeszkodzie by dodac kolejne operacje tak jak do boolean można dodac <b>xora</b> czy inne takie. Czyli cały czas pod pewnym aspektami jesteśmy przygotowani na rozbudowę ale nie kurwa tak, że fanatycznie wszystko polimorfizm i abstrakcje i polimorfizm i abstrakcje. Co więcej jest to ten moment kiedy można użyć <b>Property Based Testing</b>. Zazwyczaj przy okazji jakiejś prezentacji czy warsztatów ze <b>ScalaCheck</b> pada pytanie "no ale jak mam na przykład taką klasę <i>User</i> to jak do tego użyć PBT?". Źle zadane pytanie. Jak masz ADT i operacje na nich operujące wtedy możesz użyć PDT. (masa masa skrótów trzyliterowych, dobre na prezentacje marketingową, jeszcze tylko jakieś zdjęcia ludzi w garniakach ze stocka).
</p>
<pre style="background:#f9f9f9;color:#080808"><span style="color:#794938">object</span> <span style="color:#bf4f24">prop</span> <span style="color:#794938">extends</span> <span style="color:#bf4f24">Properties</span>(<span style="color:#0b6125">"CheckResult"</span>){
<span style="color:#794938">val</span> <span style="color:#bf4f24">gen</span>:<span style="color:#bf4f24">Gen</span>[<span style="color:#bf4f24">List</span>[<span style="color:#bf4f24">CheckResult</span>]] = ???
property(<span style="color:#0b6125">"combine"</span>) =forAll(gen){checks=>
<span style="color:#794938">val</span> <span style="color:#bf4f24">initialErrors</span>=checks.collect{<span style="color:#794938">case</span> <span style="color:#bf4f24">CheckFailure</span>(infos) => infos.length}.reduce(_+_)
<span style="color:#794938">val</span> <span style="color:#bf4f24">reducedErrors</span>=<span style="color:#bf4f24">CheckADT</span>.combine(checks) <span style="color:#794938">match</span> {
<span style="color:#794938">case</span> <span style="color:#bf4f24">CheckOK</span> => <span style="color:#811f24;font-weight:700">0</span>
<span style="color:#794938">case</span> <span style="color:#bf4f24">CheckFailure</span>(infos) => infos.length
}
initialErrors == reducedErrors
}
}
</pre>
<p>
Czyli kolejna zaleta NIEstosowania o/c principle -> otwiera się przed nami potężny paradygmat testowania kodu jako zestawu twierdzeń.
</p>
<p>
No i na koniec jak to zastosować :
</p>
<pre style="background:#f9f9f9;color:#080808"><span style="color:#794938">object</span> <span style="color:#bf4f24">BusinessLogic2</span>{
<span style="color:#794938">trait</span> <span style="color:#bf4f24">BusinessData</span>
<span style="color:#794938">trait</span> <span style="color:#bf4f24">BusinessValidationPDT</span>{
<span style="color:#794938">def</span> <span style="color:#bf4f24">isValid</span>(bd:<span style="color:#bf4f24">BusinessData</span>):<span style="color:#bf4f24">CheckResult</span>
}
<span style="color:#794938">def</span> <span style="color:#bf4f24">validateProcess</span>(data:<span style="color:#bf4f24">BusinessData</span>,checks:<span style="color:#bf4f24">Iterable</span>[<span style="color:#bf4f24">BusinessValidationPDT</span>]):<span style="color:#bf4f24">CheckResult</span> =
<span style="color:#bf4f24">CheckADT</span>.combine(checks.map(_.isValid(data)))
}
</pre>
<p>
Na razie chyba najlepsza publikacją omawiająca praktyczne podejście do tego co tutaj opisałem znalazłem w:
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikQQ0f0ug-b8GJee4E3HM2BAQ_YSQENzP3M7DoZv99jliCPFuVUO_yojZTGE5d6M6QJ7GaTPSDrJ3Cks2RMpJ3a2D_wzpbNtAY82wrBguhKkFiwqKh8N3tF_f9QuIiBIXTQIWc8E0B_AQ/s1600/functionaldomainmodeling.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikQQ0f0ug-b8GJee4E3HM2BAQ_YSQENzP3M7DoZv99jliCPFuVUO_yojZTGE5d6M6QJ7GaTPSDrJ3Cks2RMpJ3a2D_wzpbNtAY82wrBguhKkFiwqKh8N3tF_f9QuIiBIXTQIWc8E0B_AQ/s400/functionaldomainmodeling.jpg" width="319" height="400" /></a></div>
</p>
<p>
I jeszcze link do ciekawej prezentacji, żeby nie było że nikt inny nie jedzie po SOLID :
<a href="https://speakerdeck.com/tastapod/why-every-element-of-solid-is-wrong">why-every-element-of-solid-is-wrong</a>
</p>
<h1>Podsumowanie</h1>
<p>
Wyobraź sobie, że to działa tak:
<ol>
<li> Najpierw w ogóle nie wiesz, że jest open/close principle...</li>
<li> Potem wiesz, że jest i tego powyżej uważasz za niekompetentnego programistę ale jeszcze nie wiesz, że jest kolejne stadium kiedy to...</li>
<li> Rozumiesz, że open/close nie jest prawem programowania a jedynie zbiorem wygodnych uproszczeń w komunikacji i nauce</li>
</ol>
No i teoretycznie teraz wchodząc na poziom drugi myślisz, ze to ostatni poziom i nie odróżniasz tych co jeszcze nie ogarnęli o/c (czy innej prostej zasady) od tych którzy wiedzą, że to już nie działa. Oczywiście to może iść dalej bo skąd wiadomo czy nie ma czwartego poziomu gdzie jednak w jakimś kontekście to działa, a potem piątego który ponownie całą koncepcje odrzuca... Także słowo na koniec to : taki system informatyczny to inżynieria wielu zmiennych a nie zestaw prostych zasad gdzie każdy problem da się rozwiązań skończonym zestawem annotacji i hajbernejtem. Cały czas szukaj nowych źródeł wiedzy i podważaj to co już wiesz.
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifJ0MKkamwPG4FYwI3DCEocBfd5bGr9zkut9o2Bmt18_Cd2tpRxeGmoVdjEYjU-ZPmvc4YO0t8Vyjarz25FvfPv6FbsS_r5CVgQK4VxJhcdn8fngdBMxGDhPh3oY1xO8JAGJZOkcsDEHs/s1600/polanastoly.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifJ0MKkamwPG4FYwI3DCEocBfd5bGr9zkut9o2Bmt18_Cd2tpRxeGmoVdjEYjU-ZPmvc4YO0t8Vyjarz25FvfPv6FbsS_r5CVgQK4VxJhcdn8fngdBMxGDhPh3oY1xO8JAGJZOkcsDEHs/s640/polanastoly.jpg" width="640" height="360" /></a></div>
Paweł Włodarskihttp://www.blogger.com/profile/04891037231290616803noreply@blogger.com0tag:blogger.com,1999:blog-5047632037494901372.post-15498866980808430572017-01-29T23:00:00.000+01:002017-01-29T23:00:15.323+01:00Kowariantne Konsekwencje<p class="akapit">
Mroźnym popołudniem standardowego dnia pracy wiedzeni drzemiącą w nas naturą podróżnika możemy wylądować gdzieś w pośród deklaracji metod bibliotecznych, które w javie8 wielce prawdopodobne będa przyjmować funkcje. I wtedy to naszym oczom może ukazać się coś takiego :
</p>
<pre style="background:#f9f9f9;color:#080808"><span style="color:#a71d5d;font-style:italic">Function<? super <span style="color:#a71d5d;font-style:italic">V</span>, ? extends <span style="color:#a71d5d;font-style:italic">T</span>></span> declarationName
</pre>
<p class="akapit">
I tak w zasadzie to podobne rzeczy będą się ukazywać nam co chwilę... coraz częściej... w zasadzie w przypadku funkcji inna deklaracja(bez tego super i extends) nie ma sensu. Omówimy sobie skąd się to wzięło, dlaczego tak zostało, czemu inne deklaracje nie mają sensu i dlaczego pomimo, że to jedyna deklaracja z sensem to trzeba z palca zawsze to extends i super dodawać oraz, że istnieje alternatywa którą (znowu) ma w zasadzie wiele języków a nie ma java.
</p>
<h1>Problemy z typem typu</h1>
<p class="akapit">
Dawno dawno temu wszystko w Javie było faktycznie obiektem. Nawet jak nie chciałeś. Jeśli mieliśmy Listę to mieliśmy listę obiektów. Były to czasy gdy monitory CRT wypalały oczy a aplikacja startowała 15 minut po to by zaraz po starcie rzucić wyjątek <i>"class case exception"</i> - no bo trzeba było zgadywać co za typ kryje się za obiektem. Nie było generyków.
</p>
<p class="akapit">
Gdy generyki w końcu zawitały do Javy5 te problemy stały się znikome ale fani zbyt uproszczonych rozwiązań dostali nowe tematy do hejtowania bo oto pojawiły się pewne zachowania z punktu widzenia bazującego na "wszystko jest obiektem" - trochę nieintuicyjne.
</p>
<p class="akapit">
No bo mamy takie coś, że -> String jest Obiektem -> mamy listę stringów -> List<String> -> lista stringów jest obiektem ale czy stringi w liście są na tyle obiektami, że to także lista obiektów?
Okazuje się, że w tym miejscu model się załamuje - bo nie jest!
</p>
Gdyby była to dałoby się zrobić coś takiego
<pre style="background:#f9f9f9;color:#080808"><span style="color:#a71d5d;font-style:italic">List<<span style="color:#a71d5d;font-style:italic">String</span>></span> stringi<span style="color:#794938">=</span><span style="color:#794938">new</span> <span style="color:#a71d5d;font-style:italic">LinkedList<></span>();
<span style="color:#a71d5d;font-style:italic">List<<span style="color:#a71d5d;font-style:italic">Object</span>></span> objjjekty <span style="color:#794938">=</span> stringi;
objjjekty<span style="color:#794938">.</span>add(<span style="color:#811f24;font-weight:700">1</span>); <span style="color:#5a525f;font-style:italic">//kupa</span>
</pre>
<p class="akapit">
A ponieważ doprowadziłoby to do eksplozji to takie niecne programowanie jest zabronione. No ale jeśli dobrze nam z oczu patrzy i obiecamy, że nie będziemy tam nic wkładać to kompilator może nam pójść na pewne ustępstwo :
</p>
<pre style="background:#f9f9f9;color:#080808"><span style="color:#a71d5d;font-style:italic">List<? extends <span style="color:#a71d5d;font-style:italic">Object</span>></span> probaDruga<span style="color:#794938">=</span>stringi;
</pre>
I jest teraz zabezpieczenie w postaci dziwnego typu co wystarczy by nas powstrzymać przed wrzucaniem tam śmieci
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI0GeLtaqfTNrDyJ2BJ1FNu1tbjjibs-KcNrRMk3xKIdH3st8qTwcg3PDJrq_owwmu5skhonlSi1wJyfZuD6khQym8WvhWfWfzbDnMfvQA6jFQb6icfMNZJD2EqrQifXOGUDXbdMOsGlo/s1600/idea.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI0GeLtaqfTNrDyJ2BJ1FNu1tbjjibs-KcNrRMk3xKIdH3st8qTwcg3PDJrq_owwmu5skhonlSi1wJyfZuD6khQym8WvhWfWfzbDnMfvQA6jFQb6icfMNZJD2EqrQifXOGUDXbdMOsGlo/s640/idea.jpg" width="640" height="93" /></a></div>
<p class="akapit">
Czy można było inaczej to zrobić? Można było, co zobaczymy później ale patrząc na ten kawałek kodu z listą wydaje się, że mechanizm jest w porządku, nieprzekombnowany i ratuje nas przed ClassCastEx.
To był rok 2004. Mija kolejnych 10 lat. Cała dekada. Wychodzi Java8 a w niej Funkcje . I to właśnie ten nowy mechanizm pokaże słabe strony wyborów z przeszłości...
</p>
<h1>Use Site Variance</h1>
<p class="akapit">
Jeśli wejdziesz w definicję <b>java.util.function.Function</b> to zobaczysz do czego te zabawy z generykami doprowadziły
</p>
<pre style="background:#f9f9f9;color:#080808"> <span style="color:#794938">default</span> <span style="color:#794938"><</span><span style="color:#a71d5d;font-style:italic">V</span><span style="color:#794938">></span> <span style="color:#a71d5d;font-style:italic">Function<<span style="color:#a71d5d;font-style:italic">V</span>, <span style="color:#a71d5d;font-style:italic">R</span>></span> compose(<span style="color:#a71d5d;font-style:italic">Function<? super <span style="color:#a71d5d;font-style:italic">V</span>, ? extends <span style="color:#a71d5d;font-style:italic">T</span>></span> before) {
<span style="color:#a71d5d;font-style:italic">Objects</span><span style="color:#794938">.</span>requireNonNull(before);
<span style="color:#794938">return</span> (<span style="color:#a71d5d;font-style:italic">V</span> v) <span style="color:#794938">-</span><span style="color:#794938">></span> apply(before<span style="color:#794938">.</span>apply(v));
}
</pre>
<p>
Pytania czy te <i>"extends"</i> i <i>"super"</i> musza tam być? To co teraz zrobię być może ma jakąś nazwę w nauce o wnioskowaniu (a może nie) ale generalnie one tam być muszą bo... nie ma żadnych argumentów za tym aby w przypadku funkcji ich tam nie było! (ewentualnie ktoś może mnie tutaj do-edukować).
</p>
<h2>Extends</h2>
<p>
Jaka jest różnica pomiędzy dwoma poniższymi funkcjami bibliotecznymi? (taka funkcja "map" dla ubogich)
</p>
<pre style="background:#f9f9f9;color:#080808"> <span style="color:#a71d5d;font-style:italic">public</span> <span style="color:#a71d5d;font-style:italic">static</span> <span style="color:#794938"><</span><span style="color:#a71d5d;font-style:italic">A</span>,<span style="color:#a71d5d;font-style:italic">B</span><span style="color:#794938">></span> <span style="color:#a71d5d;font-style:italic">Collection<<span style="color:#a71d5d;font-style:italic">B</span>></span> libraryMethod(<span style="color:#a71d5d;font-style:italic">Collection<<span style="color:#a71d5d;font-style:italic">A</span>></span> c, <span style="color:#a71d5d;font-style:italic">Function<<span style="color:#a71d5d;font-style:italic">A</span>,<span style="color:#a71d5d;font-style:italic">B</span>></span> f){
<span style="color:#a71d5d;font-style:italic">List<<span style="color:#a71d5d;font-style:italic">B</span>></span> l <span style="color:#794938">=</span><span style="color:#794938">new</span> <span style="color:#a71d5d;font-style:italic">ArrayList<></span>();
<span style="color:#794938">for</span>(<span style="color:#a71d5d;font-style:italic">A</span> a<span style="color:#794938">:</span> c){
l<span style="color:#794938">.</span>add(f<span style="color:#794938">.</span>apply(a));
}
<span style="color:#794938">return</span> l;
}
<span style="color:#a71d5d;font-style:italic">public</span> <span style="color:#a71d5d;font-style:italic">static</span> <span style="color:#794938"><</span><span style="color:#a71d5d;font-style:italic">A</span>,<span style="color:#a71d5d;font-style:italic">B</span><span style="color:#794938">></span> <span style="color:#a71d5d;font-style:italic">Collection<<span style="color:#a71d5d;font-style:italic">B</span>></span> libraryMethod2(<span style="color:#a71d5d;font-style:italic">Collection<<span style="color:#a71d5d;font-style:italic">A</span>></span> c, <span style="color:#a71d5d;font-style:italic">Function<? super <span style="color:#a71d5d;font-style:italic">A</span>,? extends <span style="color:#a71d5d;font-style:italic">B</span>></span> f){
<span style="color:#a71d5d;font-style:italic">List<<span style="color:#a71d5d;font-style:italic">B</span>></span> l <span style="color:#794938">=</span><span style="color:#794938">new</span> <span style="color:#a71d5d;font-style:italic">ArrayList<></span>();
<span style="color:#794938">for</span>(<span style="color:#a71d5d;font-style:italic">A</span> a<span style="color:#794938">:</span> c){
l<span style="color:#794938">.</span>add(f<span style="color:#794938">.</span>apply(a));
}
<span style="color:#794938">return</span> l;
}
</pre>
<p>
Różnica pojawi się w wywołaniu bo mając klasę
</p>
<pre style="background:#f9f9f9;color:#080808"><span style="color:#a71d5d;font-style:italic">class</span> <span style="color:#bf4f24">User</span>{
<span style="color:#a71d5d;font-style:italic">private</span> <span style="color:#a71d5d;font-style:italic">String</span> name;
<span style="color:#a71d5d;font-style:italic">private</span> <span style="color:#a71d5d;font-style:italic">Integer</span> age;
<span style="color:#a71d5d;font-style:italic">public</span> <span style="color:#bf4f24">User</span>(<span style="color:#a71d5d;font-style:italic">String</span> <span style="color:#234a97">name</span>, <span style="color:#a71d5d;font-style:italic">Integer</span> <span style="color:#234a97">age</span>) {
<span style="color:#234a97">this</span><span style="color:#794938">.</span>name <span style="color:#794938">=</span> name;
<span style="color:#234a97">this</span><span style="color:#794938">.</span>age <span style="color:#794938">=</span> age;
}
<span style="color:#a71d5d;font-style:italic">public</span> <span style="color:#a71d5d;font-style:italic">String</span> <span style="color:#bf4f24">getName</span>() {
<span style="color:#794938">return</span> name;
}
<span style="color:#a71d5d;font-style:italic">public</span> <span style="color:#a71d5d;font-style:italic">Integer</span> <span style="color:#bf4f24">getAge</span>() {
<span style="color:#794938">return</span> age;
}
}
</pre>
<p>
Chciałbym teraz wykonać poniższe przekształcenie:
</p>
<pre style="background:#f9f9f9;color:#080808"><span style="color:#a71d5d;font-style:italic">Collection<<span style="color:#a71d5d;font-style:italic">User</span>></span> users<span style="color:#794938">=</span><span style="color:#794938">new</span> <span style="color:#a71d5d;font-style:italic">LinkedList<></span>();
<span style="color:#a71d5d;font-style:italic">Function<<span style="color:#a71d5d;font-style:italic">User</span>,<span style="color:#a71d5d;font-style:italic">String</span>></span> display<span style="color:#794938">=</span>o<span style="color:#794938">-</span><span style="color:#794938">></span>o<span style="color:#794938">.</span>toString();
<span style="color:#a71d5d;font-style:italic">Collection<<span style="color:#a71d5d;font-style:italic">Object</span>></span> res1<span style="color:#794938">=</span>libraryMethod(users,display); <span style="color:#5a525f;font-style:italic">// error</span>
<span style="color:#a71d5d;font-style:italic">Collection<<span style="color:#a71d5d;font-style:italic">Object</span>></span> res2<span style="color:#794938">=</span>libraryMethod2(users,display);
</pre>
<p>
Ale nie można go wykonać :( Wiem, że w tych akapitach zbytnio się nie rozpisałem ale próbki kodu chyba lepiej pokazują o co chodzi. Bez dodatkowego wysiłku i dodatkowych deklaracji wprowadzamy niczym nie uzasadnione ograniczenie. Nie ma naprawdę żadnego argumentu za ograniczeniem przyjmowanych funkcja do stricte typów biorących udział w równaniu gdyż nic przez to nie zyskujemy a tracimy wszystkie przypadki wywołania gdy typy nie zgadzają się "jeden do jednego". I w zasadzie tak będzie wszędzie - w sensie każdej funkcji bibliotecznej. Nie potrafię znaleźć kontr-przykładu.
</p>
<h2>Super</h2>
<p>
Z tym super na początku sprawa jest trudniejsza bo to szalenie nieintuicyjne co tu się dzieje. Starałem się to kiedyś wytłumaczyć tutaj -> <a href="http://pawelwlodarski.blogspot.com/2013/08/covariance-i-contravariance-dla.html">http://pawelwlodarski.blogspot.com/2013/08/covariance-i-contravariance-dla.html</a>. Tutaj spróbujmy taki prosty przykład. Niech User ma podklasę jakaś taką specjalną :
</p>
<pre style="background:#f9f9f9;color:#080808"><span style="color:#a71d5d;font-style:italic">class</span> <span style="color:#bf4f24">SpecialUser</span> <span style="color:#a71d5d;font-style:italic">extends</span> <span style="color:#bf4f24">User</span>{
<span style="color:#a71d5d;font-style:italic">private</span> <span style="color:#a71d5d;font-style:italic">String</span> somethingSpecial;
<span style="color:#a71d5d;font-style:italic">public</span> <span style="color:#bf4f24">SpecialUser</span>(<span style="color:#a71d5d;font-style:italic">String</span> <span style="color:#234a97">name</span>, <span style="color:#a71d5d;font-style:italic">Integer</span> <span style="color:#234a97">age</span>, <span style="color:#a71d5d;font-style:italic">String</span> <span style="color:#234a97">somethingSpecial</span>) {
<span style="color:#234a97">super</span>(name, age);
<span style="color:#234a97">this</span><span style="color:#794938">.</span>somethingSpecial <span style="color:#794938">=</span> somethingSpecial;
}
}
</pre>
<p>
Mamy znowu inna funkcję biblioteczną, która tym razem filtruje nasze obiekty :
</p>
<pre style="background:#f9f9f9;color:#080808"> <span style="color:#a71d5d;font-style:italic">public</span> <span style="color:#a71d5d;font-style:italic">static</span> <span style="color:#794938"><</span><span style="color:#a71d5d;font-style:italic">A</span><span style="color:#794938">></span> <span style="color:#a71d5d;font-style:italic">Collection<<span style="color:#a71d5d;font-style:italic">A</span>></span> filter1(<span style="color:#a71d5d;font-style:italic">Collection<<span style="color:#a71d5d;font-style:italic">A</span>></span> c, <span style="color:#a71d5d;font-style:italic">Function<<span style="color:#a71d5d;font-style:italic">A</span>,<span style="color:#a71d5d;font-style:italic">Boolean</span>></span> f){
<span style="color:#a71d5d;font-style:italic">List<<span style="color:#a71d5d;font-style:italic">A</span>></span> l <span style="color:#794938">=</span><span style="color:#794938">new</span> <span style="color:#a71d5d;font-style:italic">ArrayList<></span>();
<span style="color:#794938">for</span>(<span style="color:#a71d5d;font-style:italic">A</span> a<span style="color:#794938">:</span> c){
<span style="color:#794938">if</span>(f<span style="color:#794938">.</span>apply(a)) l<span style="color:#794938">.</span>add(a);
}
<span style="color:#794938">return</span> l;
}
<span style="color:#a71d5d;font-style:italic">public</span> <span style="color:#a71d5d;font-style:italic">static</span> <span style="color:#794938"><</span><span style="color:#a71d5d;font-style:italic">A</span><span style="color:#794938">></span> <span style="color:#a71d5d;font-style:italic">Collection<<span style="color:#a71d5d;font-style:italic">A</span>></span> filter2(<span style="color:#a71d5d;font-style:italic">Collection<<span style="color:#a71d5d;font-style:italic">A</span>></span> c, <span style="color:#a71d5d;font-style:italic">Function<? super <span style="color:#a71d5d;font-style:italic">A</span>,<span style="color:#a71d5d;font-style:italic">Boolean</span>></span> f){
<span style="color:#a71d5d;font-style:italic">List<<span style="color:#a71d5d;font-style:italic">A</span>></span> l <span style="color:#794938">=</span><span style="color:#794938">new</span> <span style="color:#a71d5d;font-style:italic">ArrayList<></span>();
<span style="color:#794938">for</span>(<span style="color:#a71d5d;font-style:italic">A</span> a<span style="color:#794938">:</span> c){
<span style="color:#794938">if</span>(f<span style="color:#794938">.</span>apply(a)) l<span style="color:#794938">.</span>add(a);
}
<span style="color:#794938">return</span> l;
}
</pre>
<p>
I znowu nie ma żadnego powodu by nie pozwolić tej metodzie przyjmować funkcje, które działają na podtypach bo przecież jest to całe <b>is-A</b> zapewnione - w sensie, że w podtypie na pewno znajdą się te metody których wymaga metoda działająca na rodzicu i całość się skompiluje.
</p>
<pre style="background:#f9f9f9;color:#080808"><span style="color:#a71d5d;font-style:italic">Function<<span style="color:#a71d5d;font-style:italic">User</span>,<span style="color:#a71d5d;font-style:italic">Boolean</span>></span> isAdult<span style="color:#794938">=</span>user<span style="color:#794938">-</span><span style="color:#794938">></span>user<span style="color:#794938">.</span>getAge()<span style="color:#794938">>=</span> <span style="color:#811f24;font-weight:700">18</span>;
<span style="color:#a71d5d;font-style:italic">Collection<<span style="color:#a71d5d;font-style:italic">SpecialUser</span>></span> specialUsers<span style="color:#794938">=</span><span style="color:#794938">new</span> <span style="color:#a71d5d;font-style:italic">LinkedList<></span>();
<span style="color:#5a525f;font-style:italic">// filter1(specialUsers,isAdult); //error</span>
filter2(specialUsers,isAdult);
</pre>
<p>
No i oczywiście jak zajrzysz w implementacje <b>java.util.stream.Stream</b> to i tam też <i>map</i> oraz <i>filter</i> również mają te super i extends -> bo zwyczajnie inna deklaracja nie ma sensu! Ale skoro nie ma sensu to czy dałoby się zrobić to jakoś inaczej by tyle tego nie pisać i by uprościć typy? Oczywiście, gdyż to już jest, to już jest, jest już to </br>
zdrowo i wesoło</br>
we wszystkich językach w koło
</p>
<h1>Declaration-Site Variance </h1>
<p>
Otóż w językach innych możemy zamiast pisać po tysiąc razy to "extends" zwyczajnie napisać jeden raz przy deklaracji, domyślnie zawsze będzie "extends", że to jest po prostu natura danej konstrukcji.
</p>
C#
<pre style="background:#f9f9f9;color:#080808"><span style="color:#a71d5d;font-style:italic">interface</span> <span style="color:#bf4f24">IProducer</span><out T> <span style="color:#5a525f;font-style:italic">// Covariant</span>
{
<span style="color:#a71d5d;font-style:italic">T</span> <span style="color:#bf4f24">produce</span>();
}
<span style="color:#a71d5d;font-style:italic">interface</span> <span style="color:#bf4f24">IConsumer</span><in T> <span style="color:#5a525f;font-style:italic">// Contravariant</span>
{
<span style="color:#a71d5d;font-style:italic">void</span> <span style="color:#bf4f24">consume</span>(<span style="color:#a71d5d;font-style:italic">T</span> <span style="color:#234a97">t</span>);
}
</pre>
Kotlin
<pre style="background:#f9f9f9;color:#080808"><span style="color:#a71d5d;font-style:italic">abstract</span> <span style="color:#a71d5d;font-style:italic">class</span> <span style="color:#bf4f24">Source</span><out T> {
<span style="color:#a71d5d;font-style:italic">abstract</span> fun <span style="color:#bf4f24">nextT</span>(): T
}
</pre>
Scala
<pre style="background:#f9f9f9;color:#080808">trait <span style="color:#a71d5d;font-style:italic">Function1</span>[<span style="color:#794938">-</span><span style="color:#811f24;font-weight:700">T1</span>,<span style="color:#794938">+</span><span style="color:#a71d5d;font-style:italic">R</span>] extends <span style="color:#a71d5d;font-style:italic">AnyRef</span>
</pre>
<h2>To dlaczego nie tak?</h2>
<p>
Dlaczego w javie jest to zrobione ala "use-site variance?" . Najprawdopodobniej gdy ten mechanizm powstawał wydawał się doskonałym pomysłem bo java miała jedynie mutowalne kolekcje do których ta maszynka wystarczała. Przypomnijmy - były to lata 2002-2005 -> IE miało 90% udziałów w rynku, ratunku dla branży widziano w tonach xmli a o funkcjach nikt nie myślał. No i w Javie musi być kompatybilność wstecz to jak już zrobili to tak zostało... Jeśli ktoś szuka przykładu długu technicznego to wydaje mi się, że tutaj właśnie go znaleźliśmy.
</p>
<p>
O nielicznych zaletach i licznej krytyce "Use-Site variance" przeczytacie tutaj -> <a href="https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)#Comparing_declaration-site_and_use-site_annotations">https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)#Comparing_declaration-site_and_use-site_annotations</a>. Generalnie jeśli chodzi o funkcje to przewaga "declaration-site variance" wydaje mi się bezdyskusyjna. Bardziej problematyczne są kolekcje. O ile chyba Kotlin ma obydwa typy podejść o tyle np. (znowu z tego co mi wiadomo) scala zrezygnowała z "use-site" na jakimś tam początkowym etapie rozwoju gdyż niewiele to dawało a utrudniało mocno koncepcję auto wykrywania typów dzięki któremu programy w scali mają tone mniej tekstu niż to co reprezentuje sobą java. Zaś co do samych kolekcji należałoby przenieść dyskusje na zupełnie inną płaszczyznę zatytułowaną "algorytmy z wykorzystaniem kolekcji niezmiennych" a tu już jesteśmy o krok od FP vs OOP co może nas doprowadzić do ogólnego wniosku, że problemy z generykami w Javie są pochodną wybranego paradygmatu programowania.
</p>
<h2>Pocieszenie </h2>
<p>
Jeśli pracujesz w dobrym ogromnym korpo gdzie kastą rządząca są ludzie biegający z plikiem exceli pod pachą (tzw. "jego EXCELencja") to nie masz się czym martwić bo i tak javy8 pewnie nie zobaczysz przez następne 10 lat. Także głowa do góry!
</p>
<h2>linki</h2>
<ul>
<li> <a href="https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)">https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)</a></li>
<li><a href="https://kotlinlang.org/docs/reference/generics.html#declaration-site-variance">https://kotlinlang.org/docs/reference/generics.html#declaration-site-variance</a> </li>
<li><a href="https://schneide.wordpress.com/2015/05/11/declaration-site-and-use-site-variance-explained/">https://schneide.wordpress.com/2015/05/11/declaration-site-and-use-site-variance-explained/</a>
<li><a href="https://medium.com/byte-code/variance-in-java-and-scala-63af925d21dc#.lleehih3p">https://medium.com/byte-code/variance-in-java-and-scala-63af925d21dc#.lleehih3p</a> </li>
</ul>
<br/>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjY3WXpjiNVv4-qIldTwmi97zIvkSXE4R6hIsvH2WNGmcQZgQQE3gTvbCgUpLnDBpgekIXgmYh0Hptlum71Ksjhoqxh0aediHuwaYZdq7PeRpO_YKTfZg85gAnCd451DxUhpWnLxdf7IlE/s1600/20160612_111717.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjY3WXpjiNVv4-qIldTwmi97zIvkSXE4R6hIsvH2WNGmcQZgQQE3gTvbCgUpLnDBpgekIXgmYh0Hptlum71Ksjhoqxh0aediHuwaYZdq7PeRpO_YKTfZg85gAnCd451DxUhpWnLxdf7IlE/s640/20160612_111717.jpg" width="640" height="360" /></a></div>Paweł Włodarskihttp://www.blogger.com/profile/04891037231290616803noreply@blogger.com2tag:blogger.com,1999:blog-5047632037494901372.post-84059355995936770472016-12-18T22:56:00.000+01:002016-12-18T22:56:23.557+01:00Sprawność ITSilnika<p class="akapit" >
Za wikipedią : <a href="https://pl.wikipedia.org/wiki/Sprawno%C5%9B%C4%87">https://pl.wikipedia.org/wiki/Sprawno%C5%9B%C4%87</a>
</p>
<p class="cytat" style="padding:5px">
<b>Sprawność</b> – skalarna bezwymiarowa wielkość fizyczna określająca w jakim stopniu urządzenie, organizm lub proces przekształca energię występującą w jednej postaci w energię w innej postaci, stosunek wartości wielkości wydawanej przez układ do wartości tej samej wielkości dostarczanej do tego samego układ.
</p>
<p>
Mamy na przykład sprawność silnika cieplnego, do tego z technikum pamiętam, że generator prądu też miał sprawność, a no i w zasadzie wszystko co zamienia jeden rodzaj energii na inny ma sprawność. Zamiana energii programisty w implementację ficzerów też ma swoją sprawność. Zerkniemy trochę na tę sprawność. Trochę na serio ale bardziej nie na poważnie. Bo tak na poważnie to się nie da.
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikLKzUzoDU82fXNjQj2CMmgk9Ive6sylhxmIVMwgZKMOXG8_WtMpaFmeNE6MjLB4h7PDd7kYCoCypku3nLdNK93W5fdLJiVSy_EDVADuFNzkWIn5y-1DBauWRL042lYuRkneRnY4cnb5o/s1600/Heat-engine.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikLKzUzoDU82fXNjQj2CMmgk9Ive6sylhxmIVMwgZKMOXG8_WtMpaFmeNE6MjLB4h7PDd7kYCoCypku3nLdNK93W5fdLJiVSy_EDVADuFNzkWIn5y-1DBauWRL042lYuRkneRnY4cnb5o/s320/Heat-engine.png" width="238" height="320" /></a></div>
<h2>mała uwaga</h2>
<p class="akapit">
Jeśli pojawia się słowo "sprawność" to najpierw ostrzeżenie. Niestety branża IT przepełniona jest masą folkloru i samozwańczych metodyk wytwarzania końcowego produktu co owocowało tym, że "sprawność pracy" w przeszłości była określana na podstawie chybionych porównań pomiędzy skrajnie różnymi formami pracy. I tak ludzie, którzy nie za bardzo znali się na wytwarzaniu oprogramowania ale regularnie prasowali swoje koszule określili, że miernikiem sprawności pracy jest ilość wytwarzanych linijek kodu bo przecież jak produkujemy śrubki to im więcej normy ktoś wyrobi to chyba lepiej tak?
</p>
<p>
To co mam nadzieję zobaczymy poniżej powinno nas przekonać, że jest odwrotnie. Im mniej linii kodu tym lepiej. (z założeniem odpowiedniej czytelności co też trudno zdefiniować bo czasem brak czytelności kodu to nie właściwość kodu ale właściwość niesatysfakcjonującego poziomu wiedzy osoby ten kod czytającej ) . A w zasadzie jak ktoś ma ten współczynnik ujemny czyli np <i>-100</i> oznacza usunięcie 100 lii kodu i uzyska oczekiwany efekt - to ten ktoś powinien dostać kurde bonus. Każda linia kodu to potencjalne bugi a tu linie kodu poznikały a ficzery są! W zasadzie jeśli programista jest w stanie przyjść do pracy i zrobić ficzera zgodnie z założeniami jakości kodu w 30 minut to powinien iść do domu bo każda minuta obecności programisty przy komputerze zwiększa prawdopodobieństwo pojawienia się bugów.
</p>
<p>
Na koniec obligatoryjne wspomnienie klasyki : <a href="https://en.wikipedia.org/wiki/The_Mythical_Man-Month">https://en.wikipedia.org/wiki/The_Mythical_Man-Month</a> by przypomnieć, że już od 40 lat niektórzy śmieją się z tworzenia programowania przy pomocy "metodyki ludzkiej fali", o i teraz można przejść do rzeczy prostszych czyli języków programowania.
</p>
<h2>Sprawność programowania</h2>
<p>
Jest taki dowcip, że programowanie to konwersja kawy do linii kodu (taki śmieszny śmieszny dowcip). Można to uogólnić na wymianę energii psycho-fizycznej programisty w uporządkowany zestaw cybernetycznych operacji na abstrakcyjnych formach informacji, które to można dla uproszczenia nazwać <i>"ficzerami produktu, które przynoszą hajs"</i>.
</p>
<p>
I tak np. dla uproszczenia rozważmy formę zminimalizowaną tych ficzerów - niech "ficzer" na początku będzie reprezentowany przez minimalną logikę inkrementująca inta. Mamy tu przykład Javy 7 i Javy 8 także zostajemy w mainstreamie.
<pre style="background:#f9f9f9;color:#080808"><span style="color:#5a525f;font-style:italic">//Java7</span>
<span style="color:#a71d5d;font-style:italic">Function<<span style="color:#a71d5d;font-style:italic">Integer</span>,<span style="color:#a71d5d;font-style:italic">Integer</span>></span> inkrementuj7<span style="color:#794938">=</span><span style="color:#794938">new</span> <span style="color:#a71d5d;font-style:italic">Function<<span style="color:#a71d5d;font-style:italic">Integer</span>, <span style="color:#a71d5d;font-style:italic">Integer</span>></span>() {
<span style="color:#a71d5d;font-style:italic">@Override</span>
<span style="color:#a71d5d;font-style:italic">public</span> <span style="color:#a71d5d;font-style:italic">Integer</span> <span style="color:#bf4f24">apply</span>(<span style="color:#a71d5d;font-style:italic">Integer</span> <span style="color:#234a97">integer</span>) {
<span style="color:#794938">return</span> integer<span style="color:#794938">+</span><span style="color:#811f24;font-weight:700">1</span>;
}
};
<span style="color:#5a525f;font-style:italic">//Java8</span>
<span style="color:#a71d5d;font-style:italic">Function<<span style="color:#a71d5d;font-style:italic">Integer</span>,<span style="color:#a71d5d;font-style:italic">Integer</span>></span> inkrementuj8 <span style="color:#794938">=</span> i <span style="color:#794938">-</span><span style="color:#794938">></span> i<span style="color:#794938">+</span><span style="color:#811f24;font-weight:700">1</span>;
</pre>
W pierwszym przypadku potrzeba więcej ruchów palcami, spalenia większej ilości kalorii i większej aktywności pomiędzy neuronami by wyprodukować rezultat dokładnie taki sam jak jedno-linijkowiec poniżej.
</p>
<p>
Teraz zerknijmy na bardziej rozbudowany przykład - funkcja <b>map</b>, która robi podobne manipulacje jak analogiczna metoda na Stream'ach - zmienia każdy z elementów według podanej funkcji prostej <i>'f'</i> -> stąd zagnieżdżone wewnętrzne <i>Function</i> w typie.
<pre style="background:#f9f9f9;color:#080808"><span style="color:#a71d5d;font-style:italic">Function<<span style="color:#a71d5d;font-style:italic">List<<span style="color:#a71d5d;font-style:italic">Integer</span>></span>,<span style="color:#a71d5d;font-style:italic">Function<<span style="color:#a71d5d;font-style:italic">Function<<span style="color:#a71d5d;font-style:italic">Integer</span>,<span style="color:#a71d5d;font-style:italic">Integer</span>></span>,<span style="color:#a71d5d;font-style:italic">List<<span style="color:#a71d5d;font-style:italic">Integer</span>></span>></span>></span> map <span style="color:#794938">=</span> input <span style="color:#794938">-</span><span style="color:#794938">></span> f <span style="color:#794938">-</span><span style="color:#794938">></span> .<span style="color:#794938">.</span><span style="color:#794938">.</span>;
</pre>
</p>
<p>
Typ jest dosyć zakręcony a to w zasadzie jedna z najprostszych sygnatur funkcji wyższego rzędu jakie można spotkać. Zobaczmy co możemy uzyskać po wprowadzeniu łatwiejszej notacji typów. Tym razem scala :
<pre style="background:#f9f9f9;color:#080808"><span style="color:#794938">val</span> <span style="color:#bf4f24">mapFull</span>: <span style="color:#bf4f24">Function</span>[<span style="color:#bf4f24">List</span>[<span style="color:#bf4f24">Integer</span>],<span style="color:#bf4f24">Function</span>[<span style="color:#bf4f24">Function</span>[<span style="color:#a71d5d;font-style:italic">Int</span>,<span style="color:#a71d5d;font-style:italic">Int</span>],<span style="color:#bf4f24">List</span>[<span style="color:#bf4f24">Integer</span>]]] = input => f => ???
<span style="color:#794938">val</span> <span style="color:#bf4f24">map</span> : <span style="color:#bf4f24">List</span>[<span style="color:#bf4f24">Integer</span>] => (<span style="color:#a71d5d;font-style:italic">Int</span>=><span style="color:#a71d5d;font-style:italic">Int</span>) => <span style="color:#bf4f24">List</span>[<span style="color:#bf4f24">Integer</span>] = input => f => ???
</pre>
Chociaż na początku wydaje się, że różnica to tylko kilka centymetrów to jednak z punktu widzenia programisty różnica w poświęconej energii na kodowanie/dekodowanie typu rozszerzonego jest odczuwalna. Przynajmniej ja ja odczułem. Może drogi czytelniku/czytelniczko przeprowadzić swój własny eksperyment i spróbować popisać samemu/samej te typy.
</p>
<p>
Ciekawą rzeczą jest tutaj także <b>koszt dekompresji</b> rozwiązania do mózgu programisty i subiektywna ocena tego kosztu wynikająca czasem z braku odpowiedniego doświadczenia. Na przykład :
<pre style="background:#f9f9f9;color:#080808">map(<span style="color:#bf4f24">List</span>(<span style="color:#811f24;font-weight:700">1</span>,<span style="color:#811f24;font-weight:700">2</span>,<span style="color:#811f24;font-weight:700">3</span>))(e=>e+<span style="color:#811f24;font-weight:700">1</span>)
map(<span style="color:#bf4f24">List</span>(<span style="color:#811f24;font-weight:700">1</span>,<span style="color:#811f24;font-weight:700">2</span>,<span style="color:#811f24;font-weight:700">3</span>))(_+<span style="color:#811f24;font-weight:700">1</span>)
</pre>
Ten podkreślnik .W scali możemy zastosować taki "plejsholder" zamiast powtarzać wystąpienie argumentu. Dla mnie osobiście jest to trochę czytelniejsze (to z podkreślnikiem) natomiast pamiętam na początku, że nie zawsze było dlatego potrzebny jest pewien czas ekspozycji na dane rozwiązanie by subiektywnie było zakwalifikowane do indywidualnego worka "(według mnie) obiektywnie czytelne"
</p>
<h2>Dane</h2>
<p class="akapit">
Podobnie jak z operacjami na informacjach tak samo można podejść do kosztów energetycznych tworzenia samych informacji. Jaki wqysiłek mierzony w ruchach palcami (a przypomnijmy, że jakieś tam zapalenie nadgarstków to zawodowa choroba programistów) należy ponieść by zdefiniować dane?
</p>
Java
<pre style="background:#f9f9f9;color:#080808"><span style="color:#a71d5d;font-style:italic">class</span> <span style="color:#bf4f24">User</span>{
<span style="color:#a71d5d;font-style:italic">private</span> <span style="color:#a71d5d;font-style:italic">Long</span> id;
<span style="color:#a71d5d;font-style:italic">private</span> <span style="color:#a71d5d;font-style:italic">String</span> name;
<span style="color:#a71d5d;font-style:italic">public</span> <span style="color:#bf4f24">User</span>(<span style="color:#a71d5d;font-style:italic">Long</span> <span style="color:#234a97">id</span>, <span style="color:#a71d5d;font-style:italic">String</span> <span style="color:#234a97">name</span>) {
<span style="color:#234a97">this</span><span style="color:#794938">.</span>id <span style="color:#794938">=</span> id;
<span style="color:#234a97">this</span><span style="color:#794938">.</span>name <span style="color:#794938">=</span> name;
}
<span style="color:#a71d5d;font-style:italic">public</span> <span style="color:#a71d5d;font-style:italic">Long</span> <span style="color:#bf4f24">getId</span>() {
<span style="color:#794938">return</span> id;
}
<span style="color:#a71d5d;font-style:italic">public</span> <span style="color:#a71d5d;font-style:italic">String</span> <span style="color:#bf4f24">getName</span>() {
<span style="color:#794938">return</span> name;
}
}
</pre>
Kotlin i Scala
<pre style="background:#f9f9f9;color:#080808"><span style="color:#5a525f;font-style:italic">//Kotlin zwykła klasa</span>
<span style="color:#a71d5d;font-style:italic">class</span> <span style="color:#bf4f24">User</span>(val id:Int,val name:String)
<span style="color:#5a525f;font-style:italic">//Kotlin klasa z equalsami,hashcodami i innymi takimi</span>
data <span style="color:#a71d5d;font-style:italic">class</span> <span style="color:#bf4f24">User</span>(val id:Int,val name:String)
<span style="color:#5a525f;font-style:italic">//scala zwykła klasa</span>
<span style="color:#a71d5d;font-style:italic">class</span> <span style="color:#bf4f24">User</span>(val id:Int,val name:String)
<span style="color:#5a525f;font-style:italic">//scala - klasa z całym dobrodziejstwem inwetnarza hasz kody,equalsy i pattern matching</span>
case <span style="color:#a71d5d;font-style:italic">class</span> <span style="color:#bf4f24">User</span>(id:Int,name:String)
</pre>
<p>
Oczywiści w 2016 roku nie trzeba każdej literki pisać z osobna bo IDE dużo samo pogeneruje jednakże już w trakcie analizy - nawet mając do czynienia ze znajomymi wzorcami gettery/gettery/gettery - trzeba to gdzieś w pamięci operacyjnej zmagazynować i chyba wtedy zdaje się sód albo jakiś inny pierwiastek jest używany do zmiany potencjału na aksonach (końcówki neuronów) i później jakieś odpadki wyładowań elektrycznych, które po tych wymianach danych pozostały pomiędzy neuronami, muszą być w trakcie snu usunięte.
</p>
<p>
W javie jest jeszcze ten Lombok. Nie znam produktu jako takiego ale skoro ludzie chcą go używać to strzelam, że ilość mechanicznego kodu, który inaczej musieliby napisać ręcznie jest dla nich bolesna. Coś tam słyszałem, że w Javie 10 może jakas lepsza składnia będzie. Jak będzie to będzie.
</p>
<h2>Bonus : bezpieczne granice</h2>
<p>
Ponieważ pojawiła się Scala to być może pojawią sie opinie, że trudny język, że tak dalej i tak dalej... Generalnie o ile przy przejmowaniu kodu z dalekich krain trzeba mieć się na baczności o tyle samemu kontrolując granice można naprawdę traktować scalę jak wygodniejszą jave. I chociaż w środowisku scalowym często sformułowanie "używać scalę jako lepszą javę" często jest używane trochę z negatywnym zabarwieniem, że ktoś niby nie stosuje/rozumie technik niedostępnych w javie (wolne monady 147 poziomu) - o tyle jeśli ktoś zdecyduje się przejść z javy do scali to to jednak od czegoś trzeba zacząć. Można zacząć od prostych rzeczy zgodnie z powiedzeniem "lepszy rydz niż nic".
</p>
<p>
Pomimo, że scala kojarzy się (przynajmniej mnie) z popularyzacją podejścia funkcyjnego to - być może nie jest wiedza powszechna - ale <b>ale Scala jest bardziej obiektowa niż Java</b>. Bo jak to większość czytanek wspomina - w Javie wszystko jest obiektem.... no może poza klasą która ma same metody statyczne,... no i może poza int... i w sumie też nie long. No i boolean to też nie obiekt.
</p>
<p>
Weźmy taki standardowy przykład z abstrakcją za interfejsem i fabryką implementacji realizujących tę abstrakcję - możemy to strzelić w scali w kilku linijkach
</p>
<pre style="background:#f9f9f9;color:#080808">trait <span style="color:#a71d5d;font-style:italic">Abstraction</span>{
def abstractProcess(s<span style="color:#794938">:</span><span style="color:#a71d5d;font-style:italic">String</span>)<span style="color:#794938">:</span><span style="color:#a71d5d;font-style:italic">String</span>
}
<span style="color:#a71d5d;font-style:italic">class</span> <span style="color:#bf4f24">ConcreteImplementationDupa</span> <span style="color:#a71d5d;font-style:italic">extends</span> <span style="color:#bf4f24">Abstraction</span>{
override def <span style="color:#bf4f24">abstractProcess</span>(<span style="color:#234a97">s</span>: <span style="color:#a71d5d;font-style:italic">String</span>): String = s+"dupa"
}
object <span style="color:#a71d5d;font-style:italic">SurpriseFactoryPattern</span>{
def create()<span style="color:#794938">:</span><span style="color:#a71d5d;font-style:italic">Abstraction</span> <span style="color:#794938">=</span> <span style="color:#794938">new</span> ConcreteImplementationDupa
}
</pre>
<p>
I co najważniejsze - jeśli będziemy trzymać się koncepcji, które dla javy 8 nie są czymś obcym to pod spodem dostaniem byte code, który też nie powinien zawierać niespodzianek.
I tak trait z abstrakcyjnymi metodami kończy jako zwykły interfejs
<pre style="background:#f9f9f9;color:#080808"><span style="color:#a71d5d;font-style:italic">public</span> <span style="color:#a71d5d;font-style:italic">interface</span> <span style="color:#bf4f24">jug</span>.lodz.workshops.Abstraction {
<span style="color:#a71d5d;font-style:italic">public</span> <span style="color:#a71d5d;font-style:italic">abstract</span> <span style="color:#a71d5d;font-style:italic">java.lang<span style="color:#794938">.</span>String</span> <span style="color:#bf4f24">abstractProcess</span>(<span style="color:#a71d5d;font-style:italic">java.lang<span style="color:#794938">.</span>String</span>);
}
</pre>
A klasa to zwykła klasa
<pre style="background:#f9f9f9;color:#080808"><span style="color:#a71d5d;font-style:italic">public</span> <span style="color:#a71d5d;font-style:italic">class</span> <span style="color:#bf4f24">jug</span>.lodz.workshops.ConcreteImplementationDupa <span style="color:#a71d5d;font-style:italic">implements</span> <span style="color:#bf4f24">jug.lodz.workshops<span style="color:#794938">.</span>Abstraction</span> {
<span style="color:#a71d5d;font-style:italic">public</span> <span style="color:#a71d5d;font-style:italic">java.lang<span style="color:#794938">.</span>String</span> <span style="color:#bf4f24">abstractProcess</span>(<span style="color:#a71d5d;font-style:italic">java.lang<span style="color:#794938">.</span>String</span>);
<span style="color:#a71d5d;font-style:italic">public</span> jug.lodz.workshops.<span style="color:#bf4f24">ConcreteImplementationDupa</span>();
}
</pre>
Fabryka jako, że stanowi koncept dla javy8 obcy czyli <i>singleton na poziomie języka</i> - jest odwzorowany przy pomocy dwóch klas <i>SurpriseFactoryPattern.class</i> i <i>SurpriseFactoryPattern$.class</i> - czyli jedna jedyna instancja i dostęp do tejże instancji poprzez statyczne metody - w javie jako javie inaczej chyba się nie da
</p>
<p>
Również jesli chodzi o sygnatury funkcji process kompilacji jest przewidywalny i a na poziomie kodu mamy bardzo czytelne aliasy typów funkcji :
<pre style="background:#f9f9f9;color:#080808"> <span style="color:#794938">val</span> <span style="color:#bf4f24">map</span>: <span style="color:#bf4f24">List</span>[<span style="color:#a71d5d;font-style:italic">String</span>] => (<span style="color:#a71d5d;font-style:italic">String</span>=><span style="color:#a71d5d;font-style:italic">String</span>) => <span style="color:#bf4f24">List</span>[<span style="color:#a71d5d;font-style:italic">String</span>] = input => f => input.map(f)
</pre>
Są one przez kompilator zamieniane w znajome dla javy8 <a href="http://stackoverflow.com/questions/17913409/what-is-a-sam-type-in-java">SAM type</a>
<pre style="background:#f9f9f9;color:#080808"><span style="color:#a71d5d;font-style:italic">public</span> <span style="color:#a71d5d;font-style:italic">static</span> <span style="color:#a71d5d;font-style:italic">scala.Function1<<span style="color:#a71d5d;font-style:italic">scala.collection.immutable.List<<span style="color:#a71d5d;font-style:italic">java.lang<span style="color:#794938">.</span>String</span>></span>,
<span style="color:#a71d5d;font-style:italic">scala.Function1<<span style="color:#a71d5d;font-style:italic">scala.Function1<<span style="color:#a71d5d;font-style:italic">java.lang<span style="color:#794938">.</span>String</span>, <span style="color:#a71d5d;font-style:italic">java.lang<span style="color:#794938">.</span>String</span>></span>,
<span style="color:#a71d5d;font-style:italic">scala.collection.immutable.List<<span style="color:#a71d5d;font-style:italic">java.lang<span style="color:#794938">.</span>String</span>></span>></span>></span> map();
</pre>
</p>
<h2>Zakończenie</h2>
<p>
Na zajęciach z polskiego zawsze była taka teoria, że artykuł ma początek, środek i zakończenie. Gdzie zakończenie to wstęp tylko innymi słowami. Zamiast się tutaj produkować przeczytajcie sobie raz jeszcze wstęp ale co drugie słowo to wyjdzie coś oryginalnego z tym samym przesłaniem i tyle na dzisiaj starczy.
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixr-yCqspvGFBMa2trS_mN_ze_PZkutaks_Dzy9x7qN22ZlkGT-kszR2U6w4lVf9767K4RBSrJlCq8EhcbzWbRHAFmRev_pN6xE-Srfx4H5HadkatSnMbytKGgoi7LtMWzTpupDRDDGcI/s1600/SDC11475.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixr-yCqspvGFBMa2trS_mN_ze_PZkutaks_Dzy9x7qN22ZlkGT-kszR2U6w4lVf9767K4RBSrJlCq8EhcbzWbRHAFmRev_pN6xE-Srfx4H5HadkatSnMbytKGgoi7LtMWzTpupDRDDGcI/s400/SDC11475.JPG" width="400" height="300" /></a></div>Paweł Włodarskihttp://www.blogger.com/profile/04891037231290616803noreply@blogger.com0tag:blogger.com,1999:blog-5047632037494901372.post-53610873704529932622016-11-21T20:52:00.000+01:002016-11-21T21:13:33.396+01:00Bezpieczny numerek<h3>Wyobrażenie </h3>
<p class="akapit">
Za każdym razem gdy spróbujemy wyjść poza najbardziej mainstreamowy język programowania na ziemi musi pojawić się pytanie <i>ale po co</i>. W Javie jest wszystko, frameworki, serwery, narzędzia, są obiekty - a wszystko jest obiektem to chyba jest wszystko?
</p>
<p class="akapit">
W tym momencie pojawi się teza. Teza może wynikać z teorii lub obserwacji i ta tutaj wynika właśnie z szeregu obserwacji. Obserwacji, że w 2016 - czyli dwa lata po tym jak Java oficjalnie dostała w podarunku lambdy - wielu programistów javy z kilkuletnim doświadczeniem , a których miale okazję obserwować, miało pewien kłopot w operowaniu tymi "strzałkami". I nie jest to dyskusja typu "bo ja umiem a wy nie" ale raczej czy możne pewne zjawiska ubiec aby być lepiej przygotowanym gdy już nastąpią.
</p>
<p>
I tak na przykład jeśli planowałbym ogarniać strzałki od pierwszego dnia ich wprowadzenia - czyli któryś tam marzec 2014 - wtedy nie mogę ograniczyć się jedynie do javy bo nie nauczę się mechanizmu, który w tym języku jeszcze przed ta datą nie istnieje... (podobnie w 2004 gdy wyszła java5 z generykami świat javy musiał zaznajomić się z teorią, która wcześniej w nim nie istniała czyli nie możesz przygotować się do rozwoju javy ograniczając się jedynie do javy!)
</p>
<p>
I tak na przykład widziałem jak doświadczeni programiści C# szybciej łapali Scalę aniżeli ci doświadczeni w Javie7lubmniej. Być może nawet w marcu 2014 taki "uśredniony" programista C# lepiej odnalazłby się w Javie8 aniżeli jego javowy odpowiednik. Do tego kolejną zaleta poszerzenia pola widzenia jest to, że znajomość realizacji tego samego mechanizmu w dwóch lub więcej językach ułatwia zrozumienie abstrakcji, która za tym mechanizmem stoi.
</p>
<p>
No ale co było to było a za chwilę Java8 będzie miała trzecią rocznicę, lambdy - podobnie jak wcześniej generyki - z roku na rok będą stawać się integralną częścią języka, lada chwila ma być wydana książka <i>"Functional Programming in Java"</i> i istnieją już także wygodne biblioteki "lambdowe" jak Javaslang. W Javie 9 i 10 są zapowiadane pewne udogodnienia (<a href="https://en.wikipedia.org/wiki/Project_Valhalla_(Java_language)">Project_Valhalla</a>) ale na horyzoncie nie widać kolejnej wielkiej rewolucji.
</p>
<p>
Ale czy na pewno...? (tak z akcentem na 'NA PEwno', i do tego przydałby się jakiś podkład muzyczny - może jakiś wczesny scooter?)
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVggs1iZmG6Vns8AMdxiRUg93eHSPxs99gKSTZ1Ccz63citsaG7Cj1siB_xBvUb7sTEjfkvXNluo5xbgvOBPtOFi4rqUez6nznRSjGVn85hFKWAQtdtp57e2k4KIwG5j67PhOBPTM2FgI/s1600/SDC10406.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVggs1iZmG6Vns8AMdxiRUg93eHSPxs99gKSTZ1Ccz63citsaG7Cj1siB_xBvUb7sTEjfkvXNluo5xbgvOBPtOFi4rqUez6nznRSjGVn85hFKWAQtdtp57e2k4KIwG5j67PhOBPTM2FgI/s320/SDC10406.JPG" width="320" height="240" /></a></div>
<h2>Idzie nowe</h2>
<p>
<a href="https://www.cs.purdue.edu/homes/rompf/papers/amin-wf16.pdf">The Essence of Dependent Object Types</a> - to tytuł pracy - takiej naukowej - na którą można natrafić o tu --> <a href="http://dotty.epfl.ch/#why-dotty">http://dotty.epfl.ch/#why-dotty</a> a "TU" to strona platformy <i>dotty</i>, która (chyba) ma zdefiniować jak będzie wyglądała <i>Scala 3.0</i>. Jeśli wierzyć autorom mamy do czynienia z zupełnie nowym potężnym podejściem do typów w językach prorgamowania. Niestety z dokumentu za wiele nie rozumiem a samo dotty jest work in progress.
</p>
<p>
Ale gdy tak siedzę nieco zagubiony nagle, tak znienacka wyłania się język, który w kwestii edukacji może być dla "Typów Zależnych" tym samym czym Haskell dla "Programowania Funkcyjnego " - mowa o <a href="http://www.idris-lang.org/">Idris</a>. Co ciekawe ten język jest w istocie napisany "na" Haskellu i ma bardzo podobną składnię także w tym przypadku dla mających jakieś pojęcie o Haskellu łatwiej jest zacząć. Tyle gadaniny - zerknijmy trochę pod pokrywkę.
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjE2cIMNyvCjqzJPh7G_csT8yv-Trs_1QLr9JF5-PawwjZezSHcylcxh2_7aKJ0cMlylZ_gw4WNOPojWjygtNUnOXbWva5wh6KFzXU2f46gXwnqIpNQaoILu63zoX6jG-X2ITmhrYFB_IM/s1600/idris.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjE2cIMNyvCjqzJPh7G_csT8yv-Trs_1QLr9JF5-PawwjZezSHcylcxh2_7aKJ0cMlylZ_gw4WNOPojWjygtNUnOXbWva5wh6KFzXU2f46gXwnqIpNQaoILu63zoX6jG-X2ITmhrYFB_IM/s400/idris.jpg" width="400" height="203" /></a></div>
<h2>Typ Typu</h2>
<p class="akapit">
Cały bajer z typami zależnymi polega na tym, że typ może mieć typ, który może mieć typ itd. Nie będę tutaj grał fachury bo sam hoduje sobie neurony by ogarnąć ten temat ale nawet na najprostszych przykładach widać jak obiecujący jest to mechanizm.
</p>
<p>
Pierwsza rzecz do której musimy się przyzwyczaić to ta rekurencyjna koncepcja pojęcia typu. Jeśli znowu wrócimy do Javy to przed javą 5 lista to była sucha konstrukcja. Od javy 1.5 możemy już np. mówić, że Lista ma typ String czyli :
<!-- HTML generated using hilite.me --><div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;"><pre style="margin: 0; line-height: 125%">List<span style="color: #333333"><</span>String<span style="color: #333333">></span>
</pre></div>
A teraz... jeśli to pójdzie dalej to ta lista stringów też może mieć typ - dokładnie tak - typ typu - np. <i>List typu String</i> o typie <i>długość cztery</i>
<!-- HTML generated using hilite.me --><div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;"><pre style="margin: 0; line-height: 125%">List<span style="color: #333333"><</span>String<span style="color: #333333">><</span><span style="color: #0000DD; font-weight: bold">4</span><span style="color: #333333">></span>
</pre></div>
Oczywiście w Javie nie ma czegoś takiego ale czas na Idris gdzie taka sytuacja to stan naturalny :
<pre style="background:#eee;color:#000">fourElements <span style="color:#00f;font-weight:700">:</span> <span style="color:#c5060b;font-weight:700">Vect</span> <span style="color:#0000cd">4</span> <span style="color:#c5060b;font-weight:700">String</span>
fourElements <span style="color:#00f;font-weight:700">=</span> [<span style="color:#036a07">"pierwszy"</span>,<span style="color:#036a07">"drugi"</span>,<span style="color:#036a07">"trzeci"</span>,<span style="color:#036a07">"czwarty"</span>]
</pre>
Gdybym się pomylił i dał inną ilość elementów to to się nawet nie skompiluje!
<pre style="background:#eee;color:#000">fourElements <span style="color:#00f;font-weight:700">=</span> [<span style="color:#036a07">"pierwszy"</span>,<span style="color:#036a07">"drugi"</span>,<span style="color:#036a07">"trzeci"</span>]
</pre>
</p>
<p>
No i teraz pierwsze miejsce gdzie ta konstrukcja może sie przydać. Zerknijmy na poznaną już Java8 metoda Stream.map , zmieniająca każdy element według instrukcji podanej w postaci funkcji <i>a->b</i>. W takim javowym pseudokodzie to będzie coś takiego :
<!-- HTML generated using hilite.me --><div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;"><pre style="margin: 0; line-height: 125%"><span style="color: #333399; font-weight: bold">List</span><span style="color: #333333"><</span><span style="color: #333399; font-weight: bold">B</span><span style="color: #333333">></span> result<span style="color: #000000; font-weight: bold">=</span> <span style="color: #333399; font-weight: bold">List</span><span style="color: #333333"><</span><span style="color: #333399; font-weight: bold">A</span><span style="color: #333333">>.</span>stream<span style="color: #333333">.</span>map(fab)<span style="color: #333333">.</span>collect(toList);
</pre></div>
Problem polega na tym, że mając zabezpieczenie tylko tymi typami <i>a->b</i> bardzo łatwo popełnić błąd. Co gdy zawsze będę zwracać pustą listę? I tak się skompiluje. Podobnie jak analogiczny przykład z Idris z użyciem typu List, która nie ma zależnego typu długości
<pre style="background:#eee;color:#000">customStandardMap <span style="color:#00f;font-weight:700">:</span> (a<span style="color:#00f;font-weight:700">-></span>b) <span style="color:#00f;font-weight:700">-></span> <span style="color:#c5060b;font-weight:700">List</span> a <span style="color:#00f;font-weight:700">-></span> <span style="color:#c5060b;font-weight:700">List</span> b
customStandardMap f <span style="color:#585cf6;font-weight:700">[]</span> <span style="color:#00f;font-weight:700">=</span> <span style="color:#585cf6;font-weight:700">[]</span>
customStandardMap f (x <span style="color:#00f;font-weight:700">::</span> xs) <span style="color:#00f;font-weight:700">=</span> <span style="color:#585cf6;font-weight:700">[]</span>
</pre>
Natomiast gdy przerzucimy się na typ <b>Vect</b>, którego typ ma swój typ dostaniemy taką oto sygnaturę :
<pre style="background:#eee;color:#000">customMap <span style="color:#00f;font-weight:700">:</span> (a <span style="color:#00f;font-weight:700">-></span> b ) <span style="color:#00f;font-weight:700">-></span> <span style="color:#c5060b;font-weight:700">Vect</span> n a <span style="color:#00f;font-weight:700">-></span> <span style="color:#c5060b;font-weight:700">Vect</span> n b
</pre>
<b>n</b> to długość kolekcji i przy tak zapisanej funkcji nie ma wyjścia, kolekcja zwracana musi mieć taką samą długość jak ta podana!
<pre style="background:#eee;color:#000"><span style="color:#06f;font-style:italic">-- this will not compile!!!</span>
customMap f <span style="color:#585cf6;font-weight:700">[]</span> <span style="color:#00f;font-weight:700">=</span> <span style="color:#585cf6;font-weight:700">[]</span>
customMap f (x <span style="color:#00f;font-weight:700">::</span> xs) <span style="color:#00f;font-weight:700">=</span> <span style="color:#585cf6;font-weight:700">[]</span>
</pre>
</p>
<h2>Czas na numerek</h2>
<p>
Teraz coś z zupełnie innej beczki. Czy można wartość dowolnej liczby naturalnej (jedne, milion,pierdzyliard) zaprezentować przy pomocy jedynie dwóch typów?
</p>
<p>
Jeśli ktoś spróbował w życiu Scali wie, że tam Lista to nie tyle "kolekcja N elementów" ale po prostu : "element z przodu i (być może) reszta listy". Lista tam jest tzw. <a href="http://pawelwlodarski.blogspot.com/2016/05/typy-danych-ale-algebraiczne.html">typem algebraicznym</a> czyli ściśle ograniczoną rodziną możliwych typów z jasno zdefiniowanymi nań operacjami.
A w praktyce Lista to albo ... "Lista" albo "Koniec listy" co pozwala nam wygodnie używać tej konstrukcji rekurencyjnie
<pre style="background:#eee;color:#000">safeListIteration<span style="color:#00f;font-weight:700">:</span> <span style="color:#c5060b;font-weight:700">List</span> <span style="color:#c5060b;font-weight:700">Integer</span> <span style="color:#00f;font-weight:700">-></span> <span style="color:#c5060b;font-weight:700">String</span>
safeListIteration <span style="color:#585cf6;font-weight:700">[]</span> <span style="color:#00f;font-weight:700">=</span> <span style="color:#036a07">""</span>
safeListIteration (x <span style="color:#00f;font-weight:700">::</span> xs) <span style="color:#00f;font-weight:700">=</span> <span style="color:#3c4c72;font-weight:700">show</span> x <span style="color:#00f;font-weight:700">++</span><span style="color:#036a07">":"</span><span style="color:#00f;font-weight:700">++</span> safeListIteration xs
</pre>
</p>
<p>
No i teraz jeśli zadziałało dla listy to możemy sobie wyobrazić Kolejne liczby naturalne jako taką listę z końcem ogonka na zerze. I w ten oto sposób dostaniemy bardzo bliźniaczy kod
</p>
<pre style="background:#eee;color:#000">safeNumberIteration <span style="color:#00f;font-weight:700">:</span> <span style="color:#c5060b;font-weight:700">Nat</span> <span style="color:#00f;font-weight:700">-></span> <span style="color:#c5060b;font-weight:700">String</span>
safeNumberIteration <span style="color:#c5060b;font-weight:700">Z</span> <span style="color:#00f;font-weight:700">=</span> <span style="color:#036a07">""</span>
safeNumberIteration (<span style="color:#c5060b;font-weight:700">S</span> k) <span style="color:#00f;font-weight:700">=</span> <span style="color:#3c4c72;font-weight:700">show</span> k <span style="color:#00f;font-weight:700">++</span><span style="color:#036a07">":"</span><span style="color:#00f;font-weight:700">++</span> safeNumberIteration k
</pre>
<p>
Jest to trochę taki mindfuck - dowolna liczba naturalna to : <b>albo zero albo następca innej liczby naturalnej</b>. No i teraz jak tę definicję scalimy z typami zależnymi dostajemy kolejne możliwości zabezpieczenia poprawności programu na etapie kompilacji.
</p>
<pre style="background:#eee;color:#000">append <span style="color:#00f;font-weight:700">:</span> <span style="color:#c5060b;font-weight:700">String</span> <span style="color:#00f;font-weight:700">-></span> <span style="color:#c5060b;font-weight:700">Vect</span> n <span style="color:#c5060b;font-weight:700">String</span> <span style="color:#00f;font-weight:700">-></span> <span style="color:#c5060b;font-weight:700">Vect</span> (<span style="color:#c5060b;font-weight:700">S</span> n) <span style="color:#c5060b;font-weight:700">String</span>
append x <span style="color:#585cf6;font-weight:700">[]</span> <span style="color:#00f;font-weight:700">=</span> [x]
append x xs <span style="color:#00f;font-weight:700">=</span> x <span style="color:#00f;font-weight:700">::</span> xs
</pre>
<p>
Czyli jeśli dodamy element do kolekcji to nie ma ku**a innego wyjścia jak tylko musimy otrzymać kolekcję gdzie długość to kolejna liczba naturalna względem długości kolekcji pierwotnej (być może trzeba to zdanie przeczytać sobie raz jeszcze)
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_peM5w8tf7RiocOGnzzEHumoS6Jmhy8qPsC1Q_vmQtT1-Q_DD6WhwXQB2eFWnfO-SRmw22aYbkwr4gqcgR0fcXjFVfLLCXAPt1ioyk3aD4peh5KNLglaaIwba52_Pzl3iCv0QUplywpg/s1600/lanuchy.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_peM5w8tf7RiocOGnzzEHumoS6Jmhy8qPsC1Q_vmQtT1-Q_DD6WhwXQB2eFWnfO-SRmw22aYbkwr4gqcgR0fcXjFVfLLCXAPt1ioyk3aD4peh5KNLglaaIwba52_Pzl3iCv0QUplywpg/s400/lanuchy.jpg" width="400" height="225" /></a></div>
<h2>Program zabezpieczony </h2>
<p>
A teraz taka sytuacja. Jak w Javie byśmy się zabezpieczyli przed np. podaniem indexu przekraczającego długość kolekcji? Albo jak się zabezpieczyć przed podaniem 369 w miejsce gdzie jest spodziewany dzień miesiąca? A jak już się zastanawiasz i widzisz te ify sprawdzające poprawność wartości w rantajmie - to kolejne pytanie - jak to zrobić w trakcie kompilacji?
</p>
<p>
Weźmy na to ten kalendarz i tylko trzy pierwsze miesiące by było mniej pisania
</p>
<pre style="background:#eee;color:#000">nToMonth <span style="color:#00f;font-weight:700">:</span> <span style="color:#c5060b;font-weight:700">Fin</span> <span style="color:#0000cd">3</span> <span style="color:#00f;font-weight:700">-></span> <span style="color:#c5060b;font-weight:700">Month</span>
nToMonth i <span style="color:#00f;font-weight:700">=</span> <span style="color:#00f;font-weight:700">case</span> finToInteger i <span style="color:#00f;font-weight:700">of</span>
<span style="color:#0000cd">0</span> <span style="color:#00f;font-weight:700">=></span> <span style="color:#c5060b;font-weight:700">January</span>
<span style="color:#0000cd">1</span> <span style="color:#00f;font-weight:700">=></span> <span style="color:#c5060b;font-weight:700">February</span>
<span style="color:#0000cd">2</span> <span style="color:#00f;font-weight:700">=></span> <span style="color:#c5060b;font-weight:700">March</span>
</pre>
<p>
Ok co ja pacze? Co to jets ten <i>Fin 3</i>? Otóż jest to zabezpieczenie na poziomie typów - czyli i kompilacji, takie że tam jako argument tejże metody otrzymamy wartość skończoną z zakresu 0-2.
Jeszcze raz - TYPÓW - T-Y-P-Ó-W - Typów - types - типы. Jeśli to się skompiluje to znaczy, że działa! Jeszcze raz - jak to się skompiluje to znaczy, ze działa! </p>
<p>
No ok ale skąd ten Fin się ma wziąć?. Trzeba pomyśleć o tym w szerszym kontekście. Ta funkcja jest taka czysto biznesowa a funkcja "sito" odpowiedzialna za komunikację z nieprzewidywalnym światem zewnętrznym będzie gdzieś indziej.
</p>
<pre style="background:#eee;color:#000">firstQuarterMonth <span style="color:#00f;font-weight:700">:</span> <span style="color:#c5060b;font-weight:700">Integer</span> <span style="color:#00f;font-weight:700">-></span> <span style="color:#c5060b;font-weight:700">Maybe</span> <span style="color:#c5060b;font-weight:700">Month</span>
firstQuarterMonth i <span style="color:#00f;font-weight:700">=</span> <span style="color:#00f;font-weight:700">case</span> integerToFin i <span style="color:#0000cd">3</span> <span style="color:#00f;font-weight:700">of</span>
<span style="color:#06960e;font-weight:700">Nothing</span> <span style="color:#00f;font-weight:700">=></span> <span style="color:#06960e;font-weight:700">Nothing</span>
<span style="color:#06960e;font-weight:700">Just</span> n <span style="color:#00f;font-weight:700">=></span> <span style="color:#06960e;font-weight:700">Just</span> (nToMonth n)
</pre>
<p>
I teraz ładnie ogarniamy każdą możliwą kombinację wejścia czyli nasz program jako program działa zawsze poprawnie, pomimo iż w trakcie kompilacji nie wiemy co przyjdzie w runtime.
</p>
<pre>
*poligon> firstQuarterMonth 0
Just January : Maybe Month
*poligon> firstQuarterMonth 1
Just February : Maybe Month
*poligon> firstQuarterMonth 2
Just March : Maybe Month
*poligon> firstQuarterMonth 3
Nothing : Maybe Month
</pre>
<p>
Czaisz o co chodzi? Poprawność programu wynika z tego, że zwraca zdefiniowaną odpowiedź na każda możliwa kombinacje wejściową!
</p>
<div class="dygresja">
<h2>Ale czy na pewno?</h2>
Oczywiście, że nie bo użyłem tam hamskiego brute forca, żeby na siłę zamienić Fin z powrotem w integer, którego użyłem później w pattern matchingu. Dlaczego tak zrobiłem?
Wynika to z prostej przyczyny : inaczej nie umiem. Nauka jest w trakcie trwania i na pewno za kilka miesięcy spojrzę na swój kod w Idris z dzisiaj i być może się porzygam ale to co fajnego wyszło w tym przykładzie, to że tak naprawdę to język zauważył, że odpierdalam a nie ja sam. Idris jest w stanie przeanalizować typy od początku do końca i sprawdzić czy funkcja jest całkowita czyli nei wystąpi jakaś nieprzewidziana kombinacja parametrów wejściowych, która zrobi nam kuku.
<pre>
*poligon> :total firstQuarterMonth
Main.firstQuarterMonth is possibly not total due to:
Main.nToMonth, which is possibly not total due to:
Main.case block in nToMonth at poligon.idr:59:19, which is not total as there are missing cases
</pre>
Linia 59 to jest dokładnie ta linia z tym brute forcem. Żeby być w stanie zrobić taką analizę programu to jest siła!!!
Jeśli to nie wywróci świata IT do góry nogami w przeciągu następnej dekady...
</div>
<br/><br/><br/>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_G6-sDw3OaCL-yI5gHzvESOHnuF4MkwuxTUEPz3m4Xx_n6gDcplSFnz8PQ9sa431MOZbtniu7eDi4siePJRsoibepZibmoXSseBRVj9vTSTjOr-UpMm8B3Zf0Gy-m81NKmBmEWWtytcM/s1600/drabinka.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_G6-sDw3OaCL-yI5gHzvESOHnuF4MkwuxTUEPz3m4Xx_n6gDcplSFnz8PQ9sa431MOZbtniu7eDi4siePJRsoibepZibmoXSseBRVj9vTSTjOr-UpMm8B3Zf0Gy-m81NKmBmEWWtytcM/s400/drabinka.jpg" width="400" height="225" /></a></div>Paweł Włodarskihttp://www.blogger.com/profile/04891037231290616803noreply@blogger.com3tag:blogger.com,1999:blog-5047632037494901372.post-53594030696590841022016-11-02T20:16:00.000+01:002016-11-02T20:16:28.664+01:00Wrażenia po Code retreat 2016 którego nie było<p class="akapit">
W tym roku data <a href="http://globalday.coderetreat.org/">Global Day of Code Retreat</a> niestety pokryła się z Mobilizacją dlatego my jako JUG Lodz tegoż wydarzenia nie organizowaliśmy nic mi nie wiadomo by ktoś inny podjął się tego zadania także w Łodzi ćwiczenia tej jesieni chyba się nie odbyły. Cóż - Zobaczymy czy daty za rok dopasują. Ale pomimo braku połączenia video z Koluszkami Górnymi czy innymi miastami wokół globu (oraz brakiem standardowego browara po zajęciach) można samemu przeprowadzić ćwiczenie i wyciągnąć jakąś naukę ze zdarzenia, które się technicznie nie odbyło.
</p>
<div>
Zasadniczo główną przeszkodą na drodze nauki jesteśmy my sami wyposażeni w bogatą kolekcję błędów poznawczych jak chociażby efekt aureoli, którą sami sobie nakładamy gdy myślimy, że doskonała znajomość jiry i kilkuletnie doświadczenie w odpalaniu tomcata automatycznie oznacza, że ogólnie "umiemy IT bardzo dobrze". <i>"Pisanie kodu, o możliwie niskiej złożoności w wymiarze czasu i przestrzeni"</i> to umiejętność niezależna od znajomości adnotacji w springu, doświadczeniu w konfiguracji mavena czy latach doświadczenia w przekonywaniu, że ten rysunek z 5 kwadratami to kompletny projekt systemu. Także jako umiejętność niezależną należy ją ćwiczyć niezależnie.
</div>
<div>
Więcej o takich sprawach produkowałem się rok temu : <a href="http://pawelwlodarski.blogspot.com/2015/11/code-retreat-2015-nie-boj-sie-nauki.html">CodeRetreat 2015 i nauka</a> są obrazki z cyklem Kolba (nie mylić z uderzeniem kolbą w skroń, która to może przynieść efekt odwrotny do zamierzonego) jest i teoria atrybucji także można sobie poczytać.
</div>
<h1>Ograniczenia i przyzwyczajenia</h1>
<p class="akapit">
Im dłużej pracujemy w pewien sposób tym bardziej ten sposób dopracowaliśmy do "lokalnej perfekcji" nawet jeśli to jedynie mało wydajne "maksimum lokalne" produktywności. Gdy próbujemy wyjść ze starego sposobu to opuszczamy to maksimum lokalne i nawet jeśli za rogiem czai się potężna "górka efektywności" (ku*wa chyba pójdę w kołczing) to w pierwszym momencie i tak będzie nam szło gorzej.
</p>
<p class="akapit">
Stąd też pomysł aby nałożyć sztuczne ograniczenia w trakcie pisania programu, tak abyśmy byli zmuszeni wyjść poza znane nam mechanizmy (ej naprawdę nazwać to "poza cyfrową strefe komfortu", kupić trochę pączków i jeździć po Polsce ze szkoleniami). Oczywiście ograniczenia musza być dobrane w sposób sensowny aby kierować nas w dobra stronę - a skąd wiemy, która jest dobra? CodeRetreat ma pewne gotowe schematy sesji, które czerpią inspirację z doświadczenia ludzie mających ogromne doświadczenie praktyczne. A Skąd wiadomo, że oni mają dobre doświadczenie praktyczne? Tego nie wiadomo nigdy ale taką wskazówką jest podejście tych ludzi do tematu nauki, kiedy to twierdzą iż rozumieją, że w trakcie edukacji trzeba cały czas powracać do etapu początkującego (taka skromność edukacyjna).
</p>
<p class="akapit">
Mainstreamowy CodeRetreat jest raczej nakierowany na Javę i dobre praktyki programowania obiektowego - czy można to podejście wykorzystać do nauki programowania funkcyjnego? Może ograniczenie "tylko funkcje", "żadnych przypisań", "nie zmieniaj stanu", "żadnych efektów ubocznych"? No w sumie z myślą o takiej sesji, zostało przygotowane specjalne narzędzie edukacyjne - nazywa się onoHaskell...
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4pL6TkjRUWLo0Jp7eInYSxlyTAjCxIgs8KG5P4HCuY5gDbRbG8NjgYWY9AZCfpx21hZZYzRoFCJQ81mHSQfsrmqNMQZR4YdvDineBzfc12v8k-hQvfqOjEJYUnmTEKHSMZtm3KT0ocgM/s1600/Game_of_life_animated_glider.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4pL6TkjRUWLo0Jp7eInYSxlyTAjCxIgs8KG5P4HCuY5gDbRbG8NjgYWY9AZCfpx21hZZYzRoFCJQ81mHSQfsrmqNMQZR4YdvDineBzfc12v8k-hQvfqOjEJYUnmTEKHSMZtm3KT0ocgM/s320/Game_of_life_animated_glider.gif" width="320" height="320" /></a></div>
<h1> Kod </h1>
<p class="akapit">
Znam (niestety) wiele opinii i podejść do Haskella - "tego się nie używa to po co się uczyć". A może języka warto się nauczyć dla ... samej nauki? (chociaż tutaj pewnie fani Haskella powiedzą, że w praktyce tu czy tam się go używa). W Haskellu programowaniu funkcyjne jest "natywne" i przez to nauka tego podejścia idzie tam naturalnie i duzo łatwiej niż w Scali czy Javie. No jak na przykład w książce <a href="https://www.manning.com/books/functional-programming-in-java">"Functional Programming in Java"</a> jest cały rozdział o tym jak w Javie zasymulować <i>tail recursion</i>, które w Haskellu (a nawet w Scali) po prostu "jest" - to istnieje duże prawdopodobieństwo, że standardowy programista Javy zawróci z tej ścieżki traktując funkcje w Java8 jako taki kosmetyczny dodatek do kolekcji. (to trochę tka jakby naukę programowania zaczynać od lutowania rezystorów do płytki - "Lekcja 3 - nakładamy kalafonię")
</p>
<p>
Zasady gry <b>Game Of Life</b>, którą to implementuje się na code retreat - opisane są tutaj : <a href="https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life">https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life</a>. Jak jest tyle a tyle komórek a nasza jest żywa to przezywa albo umiera. I podobnie gdy jest martwa. Czyli dosyć ciekawy zestaw wymagań gdzie występuje stan zarówno wewnątrz komórki jak i poza nią.
</p>
<p>
No to spróbujmy Haskella i zobaczmy najciekawsze fragmenty, które udało się wygenerować. Na początek w naszym kodzie - komórka. Gra życie polega na ewolucji komórek w kolejnych pokoleniach. Często ludzie słysząc, że komórka ma dwa stany myślą <b>boolean</b>. A Komórka to Komórka. Więc prezentujmy Komórkę jako komórkę.
</p>
<pre style="background:#f9f9f9;color:#080808"><span style="color:#794938">data</span> <span style="color:#811f24;font-weight:700">Cell</span> <span style="color:#794938">=</span> <span style="color:#811f24;font-weight:700">Live</span> <span style="color:#794938">|</span> <span style="color:#811f24;font-weight:700">Dead</span> <span style="color:#794938">deriving</span> (<span style="color:#bf4f24">Show</span>,<span style="color:#bf4f24">Eq</span>)
</pre>
<div>
Kolejna rzecz, która jest jasno zdefiniowana w wymaganiach gry to zasady ewolucji komórki w zależności od sąsiadów. Widzimy więc, że komórka jest mocno zależna od stanu zewnętrznego. Trzeba jakoś przekazać tę informację i zazwyczaj tutaj pojawia się jakiś if no bo jest kilka warunków ewolucji komórki. Okazuje się, że mając mechanizmy niespotykane w Javie można te zasady w sposób bardzo czytelny napisać bez użycia ifa - oto mamy pattern matching
</div>
<pre style="background:#eee;color:#3b3b3b"><span style="color:#21439c">next</span> <span style="color:#069;font-weight:700">::</span> <span style="color:#ff5600">Cell</span> <span style="color:#069;font-weight:700">-></span> <span style="color:#a535ae">Int</span> <span style="color:#069;font-weight:700">-></span> <span style="color:#ff5600">Cell</span>
next Dead <span style="color:#a8017e">3</span> <span style="color:#069;font-weight:700">=</span> Live
next Dead _ <span style="color:#069;font-weight:700">=</span> Dead
next Live <span style="color:#a8017e">2</span> <span style="color:#069;font-weight:700">=</span> Live
next Live <span style="color:#a8017e">3</span> <span style="color:#069;font-weight:700">=</span> Live
next Live _ <span style="color:#069;font-weight:700">=</span> Dead
</pre>
<div>
Następnie przechodzimy do definicji planszy. Generalnie pisząc raz za razem game of life dochodzimy do momentu gdzie w zasadzie liczą się tylko miejsca z żywymi komórkami i możemy łatwo zasymulować nieskończoną przestrzeń przy pomocy mapy. Nie musimy także tworzyć osobnego typu na współrzędne gdyż haskella dostarcza nam wygodne aliasy. W tym przypadku zastosowanie aliasu pomaga łatwo dołożyć na przykład trzeci wymiar gdyż współrzędne działają jedynie jako "klucz" i kawałki kodu świadome ilości wymiarów są ograniczone i łatwe do ogarnięcia.
</div>
<pre style="background:#eee;color:#3b3b3b"><span style="color:#069;font-weight:700">type</span> Coordinates <span style="color:#069;font-weight:700">=</span> (Int,Int)
<span style="color:#069;font-weight:700">type</span> Board <span style="color:#069;font-weight:700">=</span> M<span style="color:#069;font-weight:700">.</span>Map Coordinates Cell
<span style="color:#21439c">initial</span><span style="color:#069;font-weight:700">::</span> [<span style="color:#ff5600">Coordinates</span>]
initial <span style="color:#069;font-weight:700">=</span> [(<span style="color:#a8017e">0</span>,<span style="color:#a8017e">0</span>),(<span style="color:#a8017e">0</span>,<span style="color:#a8017e">1</span>),(<span style="color:#a8017e">1</span>,<span style="color:#a8017e">1</span>),(<span style="color:#a8017e">2</span>,<span style="color:#a8017e">1</span>)]
<span style="color:#21439c">initialBoard</span> <span style="color:#069;font-weight:700">::</span><span style="color:#ff5600">M</span>.<span style="color:#ff5600">Map</span> <span style="color:#ff5600">Coordinates</span> <span style="color:#ff5600">Cell</span>
initialBoard <span style="color:#069;font-weight:700">=</span> M<span style="color:#069;font-weight:700">.</span>fromList <span style="color:#069;font-weight:700">$</span> <span style="color:#45ae34;font-weight:700">map</span> (<span style="color:#069;font-weight:700">\</span>c<span style="color:#069;font-weight:700">-></span>(c,Live)) initial
</pre>
<h3>Tu macz comprehenszyn </h3>
<div>
W jaki sposób znaleźć współrzędne wszystkich sąsiadów? Szukamy iloczynu kartezjańskiego sasiadów w osi x z sąsiadami w osi y. W Javie można to zrobić dwoma zagnieżdżonymi forami - no chyba, że akurat jest ograniczenie "bez zagnieżdżeń" - wtedy robi się na przykład klasy Range, Surroundings i jakiś Carthesian (Function,Service co tam chceta). A w Haskellu ?
</div>
<pre style="background:#eee;color:#3b3b3b">neighbours:: <span style="color:#0053ff;font-weight:700">Coordinates</span> <span style="color:#069;font-weight:700">-</span><span style="color:#069;font-weight:700">></span> [<span style="color:#0053ff;font-weight:700">Coordinates</span>]
<span style="color:#21439c">neighbours</span> (x,y) <span style="color:#069;font-weight:700">=</span> [(xn,yn) |xn <span style="color:#069;font-weight:700"><-</span> [x<span style="color:#069;font-weight:700">-</span><span style="color:#a8017e">1</span>..x<span style="color:#069;font-weight:700">+</span><span style="color:#a8017e">1</span>],yn<span style="color:#069;font-weight:700"><-</span>[y<span style="color:#069;font-weight:700">-</span><span style="color:#a8017e">1</span>..y<span style="color:#069;font-weight:700">+</span><span style="color:#a8017e">1</span>], (xn,yn)<span style="color:#069;font-weight:700">/=</span>(x,y) ]
</pre>
<div>
No proszę tylko jedna linijka! Ale to oszukiwanie bo tam są poukrywane monady... W każdym razie podobnie możemy policzyć żywych sąsiadów
</div>
<pre style="background:#eee;color:#3b3b3b"><span style="color:#21439c">liveNeighbours</span> <span style="color:#069;font-weight:700">::</span> <span style="color:#ff5600">Coordinates</span> <span style="color:#069;font-weight:700">-></span> <span style="color:#ff5600">Board</span> <span style="color:#069;font-weight:700">-></span> <span style="color:#a535ae">Int</span>
liveNeighbours c board <span style="color:#069;font-weight:700">=</span> <span style="color:#45ae34;font-weight:700">sum</span> [<span style="color:#a8017e">1</span> <span style="color:#069;font-weight:700">|</span> coord <span style="color:#069;font-weight:700"><-</span> neighbours c,M<span style="color:#069;font-weight:700">.</span>member coord board]
</pre>
<div>
Ponieważ zyskujemy tutaj dodatkowy wymiar kompozycji pod nazwą <b>currying</b> czyli innymi słowy możemy niezależnie zaaplikować <i>Board</i> i <i>Coordinate</i>, więc powstaje pytanie czy obecna kolejność jest właściwa : <b>Coordinates -> Board -> Int</b> czy może powinno być na odwrót czyli <b> Board-> Coordinates -> Int</b>? O tym, że problem nie jest banalny starłem się napisać tutaj : <a href="http://pawelwlodarski.blogspot.com/2016/03/o-rany-odwrotna-kolejnosc-danych.html">http://pawelwlodarski.blogspot.com/2016/03/o-rany-odwrotna-kolejnosc-danych.html</a> natomiast w tymże ćwiczeniu odpowiedzi nie znam. W tej formie w jakiej jest kod kolejność wydaje się nie mieć znaczenia bo funkcja i tak ani nie weźmie udziału w kompozycji ani nie będzie niezależnie aplikować argumentów.
</div>
<h3>Końcówka</h3>
<p>
Końcówkę umieszczam w zasadzie tylko aby za rok zrobić porównanie. Generalnie metody wydają się krótkie ale jest to złudne gdyż te kilka linijek w Javie7 zajęłoby linijek kilkadziesiąt. Logika jest dosyć "skompaktowana" i wymaga od umysłu programisty odpowiedniej mocy obliczeniowej na rozpakowanie.
</p>
<p>
<pre style="background:#eee;color:#3b3b3b"><span style="color:#21439c">potentialCells</span> <span style="color:#069;font-weight:700">::</span> [<span style="color:#ff5600">Coordinates</span>] <span style="color:#069;font-weight:700">-></span> [<span style="color:#ff5600">Coordinates</span>]
potentialCells cs <span style="color:#069;font-weight:700">=</span> [(xn,yn) <span style="color:#069;font-weight:700">|</span> c<span style="color:#069;font-weight:700"><-</span>cs,(xn,yn)<span style="color:#069;font-weight:700"><-</span>neighbours c, xn<span style="color:#069;font-weight:700">>=</span><span style="color:#a8017e">0</span> , yn<span style="color:#069;font-weight:700">>=</span><span style="color:#a8017e">0</span>]
<span style="color:#21439c">nextStep</span> <span style="color:#069;font-weight:700">::</span> <span style="color:#ff5600">Board</span> <span style="color:#069;font-weight:700">-></span> <span style="color:#ff5600">Board</span>
nextStep board <span style="color:#069;font-weight:700">=</span>M<span style="color:#069;font-weight:700">.</span><span style="color:#45ae34;font-weight:700">filter</span> ( <span style="color:#069;font-weight:700">==</span> Live) <span style="color:#069;font-weight:700">$</span> M<span style="color:#069;font-weight:700">.</span>fromList <span style="color:#069;font-weight:700">$</span> <span style="color:#45ae34;font-weight:700">map</span> mapCell newCells
<span style="color:#069;font-weight:700">where</span>
newCells <span style="color:#069;font-weight:700">=</span> potentialCells <span style="color:#069;font-weight:700">$</span> M<span style="color:#069;font-weight:700">.</span>keys board
mapCell cord <span style="color:#069;font-weight:700">=</span>(cord, next (M<span style="color:#069;font-weight:700">.</span>findWithDefault Dead cord board) (liveNeighbours cord board))
</pre>
</p>
<div>
Odpalenie też w sumie wykorzysta kilka ciekawych mechanizmów :
</div>
<pre style="background:#eee;color:#3b3b3b"><span style="color:#45ae34;font-weight:700">map</span> (<span style="color:#45ae34;font-weight:700">map</span> <span style="color:#45ae34;font-weight:700">fst</span> <span style="color:#069;font-weight:700">.</span> Data<span style="color:#069;font-weight:700">.</span>Map<span style="color:#069;font-weight:700">.</span>toList) <span style="color:#069;font-weight:700">$</span> <span style="color:#45ae34;font-weight:700">take</span> <span style="color:#a8017e">5</span> <span style="color:#069;font-weight:700">$</span> <span style="color:#45ae34;font-weight:700">iterate</span> nextStep initialBoard
<span style="color:#af82d4">-- [[(0,0),(0,1),(1,1),(2,1)],[(0,0),(0,1),(1,1),(1,2)],[(0,0),(0,1),(0,2),(1,0),(1,1),(1,2)],
[(0,0),(0,2),(1,0),(1,2),(2,1)],[(1,0),(1,2),(2,1)]]</span>
</pre>
<div>
W wyniku dostajemy kolejne fazy gry i chyba są nawet poprawne - niestety jeszcze nie ogarnąłem tematu testów jednostkowych w Haskellu także dowód jest empiryczny. Podejście było dosyć restrykcyjne z punktu widzenia Obiektówki bo nie mamy żadnego zmiennego stanu. Natomiast widać cały czas pewne oznaki takiego trochę proceduralnego programowania gdzie kawałki kodu niejako nie komponują się a jedynie następują jeden po drugim.
</div>
<div>
Także by zabawy było więcej, czas dorzucić jakieś ograniczenia w ramach już istniejących ograniczeń.
</div>
<h1>Ograniczenia</h1>
<div>
Pojawiają się pewne rzeczy, które potencjalnie nadają się na ograniczenia
<ul>
<li> <b>maks jeden $ w linii</b> - generalnie każdy kolejny <i>'$'</i> można traktować jako kolejną linie kodu tyle że... w poziomie.</li>
<li> <b>brak zagnieżdzonych nawiasów "))"</b> - kolejny sposób na wywołanie instrukcji w instrukcji</li>
<li> <b>brak where,let i list comprehension </b> - tak by nie zamykać logiki w lokalnych aliasach</li>
</ul>
</div>
<div>
Kod zaczyna się podobnie, w sensie operacje na komórkach sa jasno określone przy pomocy pattern matchingu. Ciekawie zaczyna robić się przy określaniu współrzędnych. Na początek prosty jednowymiarowy generator sąsiadów z uwzględnieniem krawędzi planszy co być może jest niepotrzebne bo przecież poruszamy się po planszy nieskończonej.
</div>
<pre style="background:#eee;color:#3b3b3b"><span style="color:#21439c">surrounding</span> <span style="color:#069;font-weight:700">::</span> <span style="color:#a535ae">Int</span> <span style="color:#069;font-weight:700">-></span> [<span style="color:#a535ae">Int</span>]
surrounding i <span style="color:#069;font-weight:700">=</span> <span style="color:#45ae34;font-weight:700">filter</span> (<span style="color:#069;font-weight:700">>=</span><span style="color:#a8017e">0</span>) [i<span style="color:#069;font-weight:700">-</span><span style="color:#a8017e">1</span>,i,i<span style="color:#069;font-weight:700">+</span><span style="color:#a8017e">1</span>]
</pre>
<div>
I teraz zaczyna się robić naprawdę ciekawie bo aby zdefiniować współrzędne sąsiadów potrzebne jest połączenie "każdy-z-każdym". Tyle, że bez comprehension i zagnieżdżonych funkcji. Jak to zrobić?
</div>
<div>
wchodzimy na hoogle (<a href="https://www.haskell.org/hoogle/">https://www.haskell.org/hoogle/</a>) i szukamy czegoś co połączy nam dwie listy w listę tupli, które są u nas współrzędnymi. <b>[a]->[a]->[(a,a)]</b>. Znajdujemy funkcję <i>zip</i> i jakieś inne funkcje specjalizowane. Ponieważ mamy REPLa (od wersji 9 w końcu ma być repl w Javie!) możemy sobie szybko zrobić test
</div>
<pre>
zip [1,2] [3,4]
>> [(1,3),(2,4)]
</pre>
<div>
To nie to o co nam chodziło. Spróbujmy poszerzyć poszukiwania. Może znajdziemy coś co łączy dwie listy dając nam do dyspozycji mechanizm połączenia ich w wygodny dla nas sposób <b>(a->b->c)->[a]->[b]->[c]</b> . I tu pojawi się coś ciekawego na miejscu drugim :
<ol>
<li>zipWith :: (a -> b -> c) -> [a] -> [b] -> [c] </li>
<li>liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c </li>
</ol>
</div>
Applicative w tej sygnaturze to w wolnym tłumaczeniu "Klasa Typu", która znowu w wolnym wytłumaczenia trochę po javowemu mówi, że przekazany typ musi spełniać określony interfejs. Czy lista go spełnia?
<pre>
:info []
data [] a = [] | a : [a] -- Defined in ‘GHC.Types’
instance Eq a => Eq [a] -- Defined in ‘GHC.Classes’
instance Monad [] -- Defined in ‘GHC.Base’
instance Functor [] -- Defined in ‘GHC.Base’
instance Ord a => Ord [a] -- Defined in ‘GHC.Classes’
instance Read a => Read [a] -- Defined in ‘GHC.Read’
instance Show a => Show [a] -- Defined in ‘GHC.Show’
instance Applicative [] -- Defined in ‘GHC.Base’ `` <- spełnia!spełnia! ojjjj spełnia!
...
</pre>
Ale skąd weźmiemy funkcję? To jest dosyć ciekawa perspektywa poznawcza. Struktura z która pracujemy w zasadzie... jest funkcją
<pre>
:t (,)
>> (,) :: a -> b -> (a, b)
</pre>
i eksperyment :
<pre>
Control.Applicative.liftA2 (,) [1,2] [3,4]
>> [(1,3),(1,4),(2,3),(2,4)]
Control.Applicative.liftA2 (,) [0,1,2] [1,2]
>> [(0,1),(0,2),(1,1),(1,2),(2,1),(2,2)]
</pre>
<div class="dygresja">
Ćwiczenie można kontynuować bez wnikania w to co to jest faktycznie to <i>Applicative</i>. Temat jest gruby i w dużym skrócie można napisać, że Applicative umożliwia zastosowanie prostej funkcji <i>a->b->c</i> czyli u nas <i>a->b->(a,b)</i> na poziomie złozonychefektów. Tylko jakich efektów i w jakim sensie złożonych? Czego efektem jest lista? Jeśli założymy, że funkcja może mieć tylko jeden wynik to zwrócenie listy, która jest "wieloma wynikami", oznacza brak determinizmu. No bo jeśli mamy funkcję <i>MONETA->STRONA</i> i wyniku dostajemy [ORZEL,RESZKA] to po dwóch wywołaniach mamy [ORZEL,RESZKA] i [ORZEL,RESZKA] i łącząc ze sobą dwa niedeterministyczne wyniki otrzymujemy wszystkie możliwe kombinacje - co też zobaczyliśmy na przykładzie szukanie sąsiadów.
<div>
Więcej tutaj : <a href="http://pawelwlodarski.blogspot.com/2016/04/lista-nieoczywista.html">http://pawelwlodarski.blogspot.com/2016/04/lista-nieoczywista.html</a>
</div>
</div>
<p>
I to w zasadzie tyle.<br/>
Tyle?!? Ale przecież nieskończone!!! <br/>
Nie musi być skończone a nawet nie powinno dlatego sesje na code retreat trwają 45 minut i nie zakładają, że ktoś skończy. I aby nie przywiązywać się do jednego rozwiązania kasujemy kod po sesji i to też własnie robię.
</p>
<h3>Podsumowanie</h3>
<p class="akapit">
W ferworze implementacji wyszło mi coś takiego <b>map (\(coord,cell)->(coord,next cell))</b> na co haskell-ide zareagowała "po co się meczysz z czymś takim zamiast użyć <b>Control.Arrow.second</b>"
</p>
<pre>
:t Control.Arrow.second
Control.Arrow.second :: Arrow a => a b c -> a (d, b) (d, c)
</pre>
<div>
Jak już myślałem, że zaczynam ogarniać te monady to teraz zerkłem se na to i : <i>"Arrows, like monads, express computations that happen within a context. However, they are a more general abstraction than monads, and thus allow for contexts beyond what the Monad class makes possible"</i>. Także ten tego... nauka nie kończy się nigdy...
</div>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDuWEZqddiZNxZRYUf8iyz-vnawwTJlAhHXkgo5kLKepKrUKxKugeHMUlY5oQOONRzFsLbZmulq1lEvwReD-31BfUUnzdF9_zwAKqc-t5WGiolIpJ8jsnpvymQegGHhfTbGCZBjt50TEA/s1600/20160716_152644.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDuWEZqddiZNxZRYUf8iyz-vnawwTJlAhHXkgo5kLKepKrUKxKugeHMUlY5oQOONRzFsLbZmulq1lEvwReD-31BfUUnzdF9_zwAKqc-t5WGiolIpJ8jsnpvymQegGHhfTbGCZBjt50TEA/s400/20160716_152644.jpg" width="225" height="400" /></a></div>
Paweł Włodarskihttp://www.blogger.com/profile/04891037231290616803noreply@blogger.com0tag:blogger.com,1999:blog-5047632037494901372.post-30289274760882882622016-10-03T21:09:00.000+02:002016-10-03T21:09:08.051+02:00Na tej pętli nie zawiśniesz<p class="akapit">
To jest taki trochę ciąg dalszy poprzedniego odcinka <a href="http://pawelwlodarski.blogspot.com/2016/09/currying-spotyka-dziedziczenie.html">Kompozycja Funkcyjna w języku w którym lista dziedziczy po funkcji</a>, który to odcinek był inspirowany dokumentem <a href="https://www.cs.kent.ac.uk/people/staff/dat/miranda/whyfp90.pdf">Why Functional Programming Matters</a>.
</p>
<p>
O ile poprzednia część była o prostej kompozycji i funkcjach wyższego rzędu o tyle dalsza część wchodzi w zupełnie nowy wymiar komponowania programów dodając kontrolę nad wymiarem czasu. No bo to jest trochę taki mindfuck kiedy do tego "co jest" jako konstrukcja kodu dodajemy wymiar "kiedy i czym to jest" - wymiar który również można parametryzować. Ale najpierw ogólnie o kompozycja na rysunku.
</p>
<p>
Kompozycja jest tak naprawdę udana kiedy bierzemy dwie części i łączymy je bez dodatkowego "klejo-kodu"
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibv5auyQgK74_G4vAUy-vGJFMVm-Rof26GptDdPJE6rzGCFzTQI_cTV0SnpC3ajjniTreYxe-XbTqj7hyEBIrcBWXUHibGTmrxnfokTGZwc3knkuUDurPG1S7OyNSAzhZyzhOT7GQjG1M/s1600/composition.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibv5auyQgK74_G4vAUy-vGJFMVm-Rof26GptDdPJE6rzGCFzTQI_cTV0SnpC3ajjniTreYxe-XbTqj7hyEBIrcBWXUHibGTmrxnfokTGZwc3knkuUDurPG1S7OyNSAzhZyzhOT7GQjG1M/s400/composition.jpg" width="400" height="251" /></a></div>
<p>
A tak mniej abstrakcyjnie. Na poniższym rysunku nakrętka doskonale komponuje się z butelką i tworzy nową funkcjonalność "zamknięta butelka".
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuL-uQGskmEcNGZUHnPbbBbq6K_JfHdk4JcCd07yFzmuQCUISQy6VPiPbUECAOTsqMtB6Ge8CDh0bGMmzxDOuwZDfOcTHJd7PvAbiBWJlXRVByWUg1bb49LPaLNX6qppj-KADLFzWaGk4/s1600/but1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuL-uQGskmEcNGZUHnPbbBbq6K_JfHdk4JcCd07yFzmuQCUISQy6VPiPbUECAOTsqMtB6Ge8CDh0bGMmzxDOuwZDfOcTHJd7PvAbiBWJlXRVByWUg1bb49LPaLNX6qppj-KADLFzWaGk4/s320/but1.jpg" width="320" height="180" /></a></div>
<p>
Następnie spróbujmy uzyskać zamkniętą butelkę poprzez kompozycje butelki i mapy <i>Jury Krakowsko-Częstochowskiej</i> (Część północna).
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisHovrsKLYtmZowu92OEmbKSEQQxpwVXIBaVlKlHa84eQKofzboywKomsPx2mMc6Mtp4Zp-n2yeI2NyJg2y6JQrvX9kXhMFZxcEni-pq4Z0iRH3MRw5N_qhlGAsz5Qg6T-juGjklkW11Y/s1600/but2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisHovrsKLYtmZowu92OEmbKSEQQxpwVXIBaVlKlHa84eQKofzboywKomsPx2mMc6Mtp4Zp-n2yeI2NyJg2y6JQrvX9kXhMFZxcEni-pq4Z0iRH3MRw5N_qhlGAsz5Qg6T-juGjklkW11Y/s320/but2.jpg" width="320" height="180" /></a></div>
<p>
Pomimo iż, dobry konsultant może się wykłócić, że tak otrzymany produkt spełnia wymagania user story <i>"as a Stefan I want to zabrać ze sobą za sklep 1 litr bimbru so that straż miejska mnie nie spisze "</i> i wszelkie "rozlania płynu" wynikają z błędnego użycia interfejsu przez użytkownika - to jednak my - inżynierowie - wiemy w głębi duszy, że kompozycja jest nieudana
</p>
<p>
Bardzo często w takich przypadkach wywala się masę hajsu na jakiś zewnętrzny frejmłork obiecujący mimo wszystko przymocowanie mapy do butelki w sposób trwały za 100 trylionów rubli per sprint
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyxdmaTJ3bDYUKZ1W6iS3fR13ImBHgy2to3QidvWOVDT5ALDRLr-kQyhR8l8MOavTbAugbVaLGAiLdDzD6dB-N8xo6CQ_1mOUKJzSurWFHgzL4DMPI7asiUF2SmH_0eJyOrD1iSZVJGE0/s1600/but3.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyxdmaTJ3bDYUKZ1W6iS3fR13ImBHgy2to3QidvWOVDT5ALDRLr-kQyhR8l8MOavTbAugbVaLGAiLdDzD6dB-N8xo6CQ_1mOUKJzSurWFHgzL4DMPI7asiUF2SmH_0eJyOrD1iSZVJGE0/s320/but3.jpg" width="320" height="180" /></a></div>
(Odkręcanie zrobi się później w ramach utrzymania - a w przyszłości bez kleju już się nie obędzie także "vendor lock in")
<h2> Czas </h2>
<p class="akapit">
No i teraz ten mindfuck. Generalnie kawałki kodu widzimy tu i teraz i myśląc o kompozycji myślimy o "kompozycji tu i teraz" w "formie zdefiniowanej tu i teraz". Idąc jeden poziom abstrakcji wyżej można wyobrazić sobie kompozycję w kontekście czasu - "skomponuj jeden fragment kodu, który kiedyś będzie działał i dopiero wtedy będzie wiadomo jak wygląda - z drugim kawałkiem kodu, który też w pewnym momencie czasu będzie pasował do kompozycji".
</p>
<p>
Mi zbudowanie intuicji wokół tej koncepcji zajęło dużo czasu i zauważyłem, że atakowanie tego tematu z różnych kierunków buduje ciekawe perspektywy pojęciowe, które pomagają zbudować swoiste "przyczółki zrozumienia". Także od ostrej abstrakcji przejdźmy teraz do zwykłych konkretów.
</p>
<h1>Pętla</h1>
<p>
Jest sobie taka zwykła pętla.
</p>
<pre style="background:#eee;color:#3b3b3b"><span style="color:#069;font-weight:700">var</span> i = <span style="color:#a8017e">0</span>
<span style="color:#069;font-weight:700">while</span>(i < <span style="color:#a8017e">100</span>){
println(i)
i=i+<span style="color:#a8017e">1</span>
}
</pre>
<p>
Co można zrobić z taką zwykłą pętlą? Rozwiązuje ona doskonale pewien niszowy problem pod tytułem "wypisz 100 liczb na konsolę" ale średnio komponuje się z czymkolwiek.
Na początek może spróbujmy dokodować możliwość kompozycji ze zwykłą liczbą całkowitą.
</p>
<pre style="background:#eee;color:#3b3b3b"><span style="color:#069;font-weight:700">def</span> <span style="color:#21439c">kompozycja</span>(limit:<span style="color:#ff5600">Int</span>)={
<span style="color:#069;font-weight:700">var</span> i = <span style="color:#a8017e">0</span>
<span style="color:#069;font-weight:700">while</span>(i < limit){
println(i)
i=i+<span style="color:#a8017e">1</span>
}
}
kompozycja(<span style="color:#a8017e">10</span>)
</pre>
<p>
Możemy iść dalej i dorobić gwint do wkręcania czynności jaka ma być wykonana wewnątrz pętli. (Kto był w technikum ten wie jak fajnie się gwintuje gwintownikiem ręcznym przez 5 godzin). I teraz można to zrobić o tak :
</p>
<pre style="background:#eee;color:#3b3b3b"><span style="color:#069;font-weight:700">trait</span> BusinessGwintownikStrategy{
<span style="color:#069;font-weight:700">def</span> <span style="color:#21439c">dziaaaaaaaaa</span>łaj(input:<span style="color:#ff5600">Int</span>):<span style="color:#ff5600">Unit</span>
}
<span style="color:#069;font-weight:700">object</span> WypisywaczProfessionalStrategy <span style="color:#069;font-weight:700">extends</span> BusinessGwintownikStrategy{
<span style="color:#ff5600">override</span> <span style="color:#069;font-weight:700">def</span> <span style="color:#21439c">dziaaaaaaaaa</span>łaj(<span style="color:#0053ff;font-weight:700">input</span>: Int): <span style="color:#ff5600">Unit</span> = println(s<span style="color:#666">"STRATEGY $input"</span>)
}
<span style="color:#069;font-weight:700">def</span> <span style="color:#21439c">kompozycja</span>(limit:<span style="color:#ff5600">Int</span>,<span style="color:#0053ff;font-weight:700">strategy</span> : BusinessGwintownikStrategy)={
<span style="color:#069;font-weight:700">var</span> i = <span style="color:#a8017e">0</span>
<span style="color:#069;font-weight:700">while</span>(i < limit){
strategy.dziaaaaaaaaałaj(i)
i=i+<span style="color:#a8017e">1</span>
}
}
kompozycja(<span style="color:#a8017e">10</span>,WypisywaczProfessionalStrategy)
</pre>
<p>
Tylko na ch*j? W tej całej strategi nie ma nawet jakiegokolwiek stanu także po co się męczyć z jakimś pseudo obiektowym rękodziełem kiedy mamy uniwersalny standard śrubek w formie A=>B? (Chociaż UMLe zawsze można za dodatkowy hajs ojebać. No i do tego fajnie wyglądają w powerpointach)
</p>
<p>
<b>I to jest dosyć istotny moment</b>, że nawet go wyboldowałem. Bo teraz tak. Jak macie np. kompa to on ma interfejs USB. I są pendraivy na USB, klawiatury na USB, lampki na USB i podobno nawet takie "urządzenia peryferyjne" dla zdalnych par (if you know what i mean). Mamy do czynienia z ogólnoświatowym standardem dzięki czemu lampka na usb wyprodukowana w Chinach komponuje się z komputerem wyprodukowanym na tajwanie.
</p>
<p>
Gdyby każdy wyprodukowany komp dorzucał swój interfejs "Strategia" to nie byłaby to "Strategia" tylko "Tragedia". Dlatego warto użyć universalnego portu w postaci funkcji , która jest zdefiniowana w bibliotece standardowej i jest U-N-I-V-E-R-S-A-L-N-A (później jak ktoś bardzo chce może sobie ograniczyć dostęp ze względu na typy - dajemy wybór)
</p>
<pre style="background:#eee;color:#3b3b3b"><span style="color:#069;font-weight:700">val</span> wypisywacz : <span style="color:#ff5600">Int</span> => <span style="color:#ff5600">Unit</span> = i => println(s<span style="color:#666">"FUNKCYJA $i"</span> )
<span style="color:#069;font-weight:700">def</span> <span style="color:#21439c">kompozycja</span>(limit:<span style="color:#ff5600">Int</span>,<span style="color:#0053ff;font-weight:700">strategy</span> : Int => <span style="color:#ff5600">Unit</span>)={
<span style="color:#069;font-weight:700">var</span> i = <span style="color:#a8017e">0</span>
<span style="color:#069;font-weight:700">while</span>(i < limit){
strategy(i)
i=i+<span style="color:#a8017e">1</span>
}
}
kompozycja(<span style="color:#a8017e">10</span>,wypisywacz)
</pre>
<h2>Gdzie ten czas?</h2>
<p class="akapit">
No dobra to nadszedł czas na "czas". W tej chwili mamy dwa sposoby kompozycji <i>(INT, INT => UNIT)</i> z tymże w takiej formie musimy materializować je w czasie w tym samym momencie (tak wiem, że w scali można robić częściową aplikację parametrów w zwykłych metodach bo w scali można "wszystko" ale dla wygody wyprowadzanego wywodu nie mąćmy).
</p>
<p>
Aby odseparować te dwie rzeczy w czasie wykorzystajmy mechanizm wspomniany w pierwszej części <i>"Why Functional Programming Matters"</i> czyli Currying.
</p>
<pre style="background:#eee;color:#3b3b3b"><span style="color:#069;font-weight:700">def</span> <span style="color:#21439c">kompozycja</span>(limit:<span style="color:#ff5600">Int</span>)(<span style="color:#0053ff;font-weight:700">strategy</span> : Int => <span style="color:#ff5600">Unit</span>):<span style="color:#ff5600">Unit</span>={
<span style="color:#069;font-weight:700">var</span> i = <span style="color:#a8017e">0</span>
<span style="color:#069;font-weight:700">while</span>(i < limit){
strategy(i)
i=i+<span style="color:#a8017e">1</span>
}
}
<span style="color:#069;font-weight:700">val</span> kompozycjaWToku: (<span style="color:#ff5600">Int</span> => <span style="color:#ff5600">Unit</span>) => <span style="color:#ff5600">Unit</span> = kompozycja(<span style="color:#a8017e">10</span>) _
println(<span style="color:#666">"cos sobie wypisze dla zabicia czasu"</span>)
kompozycjaWToku(wypisywacz)
</pre>
<p>
Ba! możemy pójść nawet o krok dalej i nie wykonywać programu w tym samym czasie co ustalenie ostatniej kompozycji.
</p>
<pre style="background:#eee;color:#3b3b3b"><span style="color:#af82d4">//Metoda zwraca teraz typ () => Unit - nowy alias 'Program'</span>
<span style="color:#069;font-weight:700">type</span> <span style="color:#21439c">Program</span> = () => <span style="color:#ff5600">Unit</span>
<span style="color:#069;font-weight:700">def</span> <span style="color:#21439c">kompozycja</span>(limit:<span style="color:#ff5600">Int</span>)(<span style="color:#0053ff;font-weight:700">strategy</span> : Int => <span style="color:#ff5600">Unit</span>):Program=()=>{
<span style="color:#069;font-weight:700">var</span> i = <span style="color:#a8017e">0</span>
<span style="color:#069;font-weight:700">while</span>(i < limit){
strategy(i)
i=i+<span style="color:#a8017e">1</span>
}
}
<span style="color:#069;font-weight:700">val</span> kompozycjaWToku: (<span style="color:#ff5600">Int</span> => <span style="color:#ff5600">Unit</span>) => Program = kompozycja(<span style="color:#a8017e">10</span>) _
println(<span style="color:#666">"kompozycja w trakcie..."</span>)
<span style="color:#069;font-weight:700">val</span> blueprint: Program =kompozycjaWToku(wypisywacz)
println(<span style="color:#666">"Jakiś czas później..."</span>)
blueprint()
</pre>
<h2>Iteracja</h2>
<p class="akapit">
Analogicznie do funkcji, która określa "co robić" możemy dodać dodatkową kompozycję "jak iterować."
</p>
<pre style="background:#eee;color:#3b3b3b"><span style="color:#069;font-weight:700">val</span> coDrugi: <span style="color:#ff5600">Int</span> => <span style="color:#ff5600">Int</span> = _ + <span style="color:#a8017e">2</span>
<span style="color:#069;font-weight:700">type</span> <span style="color:#21439c">Program</span> = () => <span style="color:#ff5600">Unit</span>
<span style="color:#069;font-weight:700">def</span> <span style="color:#21439c">kompozycja</span>(iterator:<span style="color:#ff5600">Int</span>=><span style="color:#ff5600">Int</span>)(<span style="color:#0053ff;font-weight:700">strategy</span> : Int => <span style="color:#ff5600">Unit</span>)(limit:<span style="color:#ff5600">Int</span>):Program=()=>{
<span style="color:#069;font-weight:700">var</span> i = <span style="color:#a8017e">0</span>
<span style="color:#069;font-weight:700">while</span>(i < limit){
strategy(i)
i=iterator(i)
}
}
<span style="color:#069;font-weight:700">val</span> iterujCoDrugi: (<span style="color:#ff5600">Int</span> => <span style="color:#ff5600">Unit</span>) => (<span style="color:#ff5600">Int</span>) => Program = kompozycja(coDrugi) _
<span style="color:#069;font-weight:700">val</span> wypisuj: <span style="color:#ff5600">Int</span> => Program =iterujCoDrugi(wypisywacz)
<span style="color:#069;font-weight:700">val</span> doDziesieciu : Program= wypisuj(<span style="color:#a8017e">10</span>)
println(<span style="color:#666">"Jakiś czas później..."</span>)
doDziesieciu()
</pre>
<p>
Nie ma róży bez kolców. To co źle tutaj działa to połączenie sposobu generowania elementów z licznikiem pętli. Na pytanie "po co byśmy chcieli to robić" odpowiemy kolejnym przykładem z artykułu <i>Why Functional Programming matters</i> a mianowicie iteracyjnym algorytmem na obliczenia pierwiastka kwadratowego
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZcKh9TLABmK9raEsLDdGnS0RapnJ32JzlMXkcZVNwqUDljnbGy6UygE-n7QOMM7IsP1G6yXlmcQltbRi6upmbIlGxu0vEE0YEatR4AZN-nmMwVQG3qfP4F4eaCjPustZnrngSdx5hxRw/s1600/root.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZcKh9TLABmK9raEsLDdGnS0RapnJ32JzlMXkcZVNwqUDljnbGy6UygE-n7QOMM7IsP1G6yXlmcQltbRi6upmbIlGxu0vEE0YEatR4AZN-nmMwVQG3qfP4F4eaCjPustZnrngSdx5hxRw/s640/root.jpg" width="640" height="195" /></a></div>
<p>
Czyli generalnie chciałbym aby pętla sobie chodziła - nawet i w nieskończoność - a ja niezależnie od niej co iterację chcę generować kolejne stadium rozwiązania.
</p>
<h2>Pętla tylko koncepcyjna</h2>
<p>Można wytwarzać kolejne przybliżenia rozwiązania naszą pętlą ale zaczyna powstawać coś strasznego - metoda z tysiącem parametrów. A do tego utrudnione jest użycie zwykłych funkcji bo one w scali nie mogą mieć generyków</p>
<pre style="background:#eee;color:#3b3b3b"><span style="color:#069;font-weight:700">val</span> wypisywacz : <span style="color:#ff5600">Int</span> => <span style="color:#ff5600">Unit</span> = i => println(s<span style="color:#666">"FUNKCYJA $i"</span>)
<span style="color:#069;font-weight:700">val</span> coDrugi: <span style="color:#ff5600">Int</span> => <span style="color:#ff5600">Int</span> = _ + <span style="color:#a8017e">2</span>
<span style="color:#069;font-weight:700">val</span> nextRoot : <span style="color:#ff5600">Double</span>=><span style="color:#ff5600">Double</span>=><span style="color:#ff5600">Double</span> = n => ai => (ai+n/ai)/<span style="color:#a8017e">2</span>
<span style="color:#069;font-weight:700">def</span> <span style="color:#21439c">generycznyWypisywacz</span>[A] :A=><span style="color:#ff5600">Unit</span> =e => println(s<span style="color:#666">"e : $e"</span>)
<span style="color:#069;font-weight:700">type</span> <span style="color:#21439c">Program</span> = () => <span style="color:#ff5600">Unit</span>
<span style="color:#069;font-weight:700">def</span> <span style="color:#21439c">kompozycja</span>[A](start:A)(iterator:A=>A)(<span style="color:#0053ff;font-weight:700">strategy</span> : A => <span style="color:#ff5600">Unit</span>)(limit:<span style="color:#ff5600">Int</span>):Program=()=>{
<span style="color:#069;font-weight:700">var</span> i = <span style="color:#a8017e">0</span>
<span style="color:#069;font-weight:700">var</span> e=start
<span style="color:#069;font-weight:700">while</span>(i < limit){
strategy(e)
e=iterator(e)
i=i+<span style="color:#a8017e">1</span>
}
}
<span style="color:#af82d4">//kompozycja(0.0)(nextRoot(2))(wypisywacz)(10) // zwykly wypisywacz nie dziala</span>
<span style="color:#069;font-weight:700">val</span> program=kompozycja(<span style="color:#a8017e">1.0</span>)(nextRoot(<span style="color:#a8017e">2</span>))(generycznyWypisywacz)(<span style="color:#a8017e">10</span>)
program()
</pre>
<p>
Ale co gorsza po odpaleniu programu nie mamy żadnego wpływu na wynik naszej operacji. Zwróć uwagę na kilka ostatnich elementów. :
</p>
<pre>
e : 1.0
e : 1.5
e : 1.4166666666666665
e : 1.4142156862745097
e : 1.4142135623746899
e : 1.414213562373095
e : 1.414213562373095
e : 1.414213562373095
e : 1.414213562373095
e : 1.414213562373095
</pre>
<p>
I teraz fajnie, że robimy sobie takie wstrzykiwanie zależności i parametrów ale my wcale nie potrzebowaliśmy 10 elementów bo z tego co widać 5 by wystarczyło. Ale to jest informacja, która będzie
dostępna dopiero w trakcie wykonania. Czyli chociaż nasze budowanie programu jest takie trochę <i>lazy</i> to nijak nie umiemy tego wykorzystać w trakcie odpalania programu.
</p>
<p>
Oczywiście moglibyśmy dodać kolejny parametr w postaci funkcji A=>Boolean, który by określał warunek w pętli while ale specjalnie już trochę przekombinowałem. Nosz kurde mamy 4 parametry w metodzie - zaraz się z tego zrobi <b>WinAPI</b>.
</p>
<p>
Aby rozwiązać ten problem musimy totalnie zanihilować fizyczną reprezentację pętli i zachować ją jedynie w formie <b>"koncepcji"</b>, która będzie materializowana w miarę potrzeb w trakcie wykonywania się programu.
</p>
<h2>Leniwość i Materializacja</h2>
<p>
Tutaj trochę robi się obiektowo bo tworzymy klase - ale to <b>case klasa</b> czyli taka <b>klasa-dana</b> ale nie jak w piosence <i>oj dana dana</i> tylko dana jako dana... w każdym razie "koncepcyjna pętla, która można iterować bez końca" wygląda tak
</p>
<pre style="background:#eee;color:#3b3b3b"><span style="color:#069;font-weight:700">case</span> <span style="color:#069;font-weight:700">class</span> Loop[A](e:A,next:()=>Loop[A])
<span style="color:#069;font-weight:700">def</span> <span style="color:#21439c">petlaKoncepcyjna</span>[A](start:A)(iterator:A=>A): Loop[A] = {
<span style="color:#069;font-weight:700">val</span> e2=iterator(start)
Loop(e2,()=>petlaKoncepcyjna(e2)(iterator))
}
<span style="color:#069;font-weight:700">val</span> Loop(e,next)=petlaKoncepcyjna(<span style="color:#a8017e">1.0</span>)(nextRoot(<span style="color:#a8017e">2</span>))
<span style="color:#069;font-weight:700">val</span> Loop(e2,next2) = next()
<span style="color:#069;font-weight:700">val</span> Loop(e3,next3) = next2()
<span style="color:#069;font-weight:700">val</span> Loop(e4,next4) = next3()
println(s<span style="color:#666">"elements : $e,$e2,$e3,$e4"</span>)
</pre>
I wynik :
<pre>
elements : 1.5,1.4166666666666665,1.4142156862745097,1.4142135623746899
</pre>
<p>
Nie ma co się na razie przerażać tym, że jedziemy po niej ręcznie. Co się robi na pałę da się zautomatyzować (dlatego większość programistów CRUDa kiedyś straci prace - just saying)
</p>
<p>
Co można zrobić dalej? Udajmy się po inspirację do języka czysto funkcyjnego...
</p>
<h2>Bez Klas</h2>
<p>
Haskellowo - amatorska implementacja tego co do tej pory zrobiliśmy wygląda mniej więcej tak :
</p>
<pre style="background:#eee;color:#3b3b3b"><span style="color:#069;font-weight:700">data</span> Loop a <span style="color:#069;font-weight:700">=</span> Loop a (Loop a)
<span style="color:#21439c">petlaKoncepcyjna</span> <span style="color:#069;font-weight:700">::</span> <span style="color:#0053ff;font-weight:700">a</span> <span style="color:#069;font-weight:700">-></span> (<span style="color:#0053ff;font-weight:700">a</span><span style="color:#069;font-weight:700">-></span><span style="color:#0053ff;font-weight:700">a</span>) <span style="color:#069;font-weight:700">-></span> <span style="color:#ff5600">Loop</span> <span style="color:#0053ff;font-weight:700">a</span>
petlaKoncepcyjna start iter <span style="color:#069;font-weight:700">=</span> Loop e (petlaKoncepcyjna e iter)
<span style="color:#069;font-weight:700">where</span> e <span style="color:#069;font-weight:700">=</span> iter start
<span style="color:#21439c">root</span> <span style="color:#069;font-weight:700">::</span> <span style="color:#a535ae">Double</span> <span style="color:#069;font-weight:700">-></span> <span style="color:#a535ae">Double</span> <span style="color:#069;font-weight:700">-></span><span style="color:#a535ae">Double</span>
root n ai <span style="color:#069;font-weight:700">=</span> (ai<span style="color:#069;font-weight:700">+</span>n<span style="color:#069;font-weight:700">/</span>ai)<span style="color:#069;font-weight:700">/</span><span style="color:#a8017e">2</span>
element (Loop a _) <span style="color:#069;font-weight:700">=</span> a
loop (Loop _ next) <span style="color:#069;font-weight:700">=</span> next
</pre>
<p>
Co daje nam ponownie możliwość manualnej iteracji po pętli.
</p>
<pre>
*Learn> let s1=petlaKoncepcyjna 1.0 (root 2)
*Learn> element s1
1.5
*Learn> let s2= loop s1
*Learn> element s2
1.4166666666666665
*Learn> let s3= loop s2
*Learn> let s4= loop s3
*Learn> let s5= loop s4
*Learn> map element [s1,s2,s3,s4,s5]
[1.5,1.4166666666666665,1.4142156862745097,1.4142135623746899,1.414213562373095]
</pre>
<p>
Tyle, że nie ma co wyważać otwartych drzwi bo w Haskellu mamy już na to gotowca
</p>
<pre>
> :t iterate
iterate :: (a -> a) -> a -> [a]
</pre>
<p>
To będzie szło w nieskończoność dlatego mamy specjalny operator do określenia ile elementów nam potrzeba - <b>w ten sposób uniezależniliśmy się od wewnętrznej iteracji po pętli </b>
</p>
<pre>
> take 10 $ iterate (root 2) 1.0
[1.0,1.5,1.4166666666666665,1.4142156862745097,1.4142135623746899,
1.414213562373095,1.414213562373095,1.414213562373095,1.414213562373095,1.414213562373095]
*Learn> :t take
take :: Int -> [a] -> [a]
</pre>
<p>
Co więcej uniezależniliśmy się od sposobu określania "końca pętli"
</p>
<pre>
> :t takeWhile
takeWhile :: (a -> Bool) -> [a] -> [a]
*Learn> takeWhile (<10) $ iterate (+1) 1
[1,2,3,4,5,6,7,8,9]
</pre>
<p>
Ok do szczęścia brakuje nam już tylko jednej rzeczy. Na razie operujemy na pojedynczym elemencie a na przykład chcielibyśmy określić by pętla się skończyła gdy elementy przestaną się zmieniać - a do tego musimy jakoś je ze sobą porównywać.
</p>
<pre>
> let epsilon e (a,b) = abs (b-a) < e
*Learn> epsilon 0.1 (2,1)
False
*Learn> epsilon 0.1 (2,2.01)
True
</pre>
<p>
Czas na kolejny mindfuck - ponieważ nasza pętla jets teraz koncepcją wiec nie ma problemu by ja skomponować ...samą ze sobą. I do tego też jest sprzęt.
</p>
<pre>
> :t zip
zip :: [a] -> [b] -> [(a, b)]
</pre>
<p>
W zasadzie wszystkie części gotowe - to wio!
</p>
<pre>
Learn> let squareRootSeq=iterate (root 2) 1.0
*Learn> head $ dropWhile (not . (epsilon 0.01)) $ zip squareRootSeq (tail squareRootSeq)
(1.4166666666666665,1.4142156862745097)
*Learn> snd $ head $ dropWhile (not . (epsilon 0.01)) $ zip squareRootSeq (tail squareRootSeq)
1.4142156862745097
</pre>
<p>
Pierwsza uwaga dla hejterów, którzy będą płakać że tam się za dużo dzieje - ludzie... to jest REPL, w programie możecie sobie przy pomocy "where" albo "let .. in" porobić aliasy/zmienne i będzie czytelnie.
</p>
<p>
No a druga sprawa - rozwiązaliśmy problem iteracyjny bez użycia <i>kleju</i> komponując jedynie ze sobą poszczególne komponenty. Według autora wspominanego od czasu do czasu dokumenty "Why Functional Programming matters" taką klasyczną pętelką w jakichś kobolach wyglądało by tak :
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhANrKl4MeSfqK_rRMKTzPR5C3n4ozThtwQQjrVQerHz8fMp4dCDM4GSqX7hGAStj2vjYxUo80DppaM758bIkzNOlmle_kLpEcxwX_LurkXhQibKgsASg2T_eB0QToeNMLLbHDsbx1Z4uY/s1600/kobol.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhANrKl4MeSfqK_rRMKTzPR5C3n4ozThtwQQjrVQerHz8fMp4dCDM4GSqX7hGAStj2vjYxUo80DppaM758bIkzNOlmle_kLpEcxwX_LurkXhQibKgsASg2T_eB0QToeNMLLbHDsbx1Z4uY/s400/kobol.jpg" width="400" height="153" /></a></div>
<p>
W Javie po imperatywnemu na podstawie znalezionego w necie przykładu mamy cos takiego :
</p>
<pre style="background:#fff;color:#3b3b3b"><span style="color:#ff5600">public</span> <span style="color:#ff5600">class</span> <span style="color:#21439c">SqrtNewtonMethod</span> {
<span style="color:#ff5600">public</span> <span style="color:#ff5600">static</span> <span style="color:#ff5600">void</span> <span style="color:#21439c">main</span>(<span style="color:#ff5600">String</span>[] <span style="color:#0053ff;font-weight:700">args</span>) {
<span style="color:#ff5600">double</span> c <span style="color:#069;font-weight:700">=</span> <span style="color:#ff5600">Double</span><span style="color:#069;font-weight:700">.</span>parseDouble(args[<span style="color:#a8017e">0</span>]);
<span style="color:#ff5600">double</span> epsilon <span style="color:#069;font-weight:700">=</span> <span style="color:#a8017e">1e-15</span>; <span style="color:#af82d4">// relative error tolerance</span>
<span style="color:#ff5600">double</span> t <span style="color:#069;font-weight:700">=</span> c; <span style="color:#af82d4">// estimate of the square root of c</span>
<span style="color:#af82d4">// repeatedly apply Newton update step until desired precision is achieved</span>
<span style="color:#069;font-weight:700">while</span> (<span style="color:#ff5600">Math</span><span style="color:#069;font-weight:700">.</span>abs(t <span style="color:#069;font-weight:700">-</span> c<span style="color:#069;font-weight:700">/</span>t) <span style="color:#069;font-weight:700">></span> epsilon<span style="color:#069;font-weight:700">*</span>t) {
t <span style="color:#069;font-weight:700">=</span> (c<span style="color:#069;font-weight:700">/</span>t <span style="color:#069;font-weight:700">+</span> t) <span style="color:#069;font-weight:700">/</span> <span style="color:#a8017e">2.0</span>;
}
<span style="color:#af82d4">// print out the estimate of the square root of c</span>
<span style="color:#ff5600">System</span><span style="color:#069;font-weight:700">.</span>out<span style="color:#069;font-weight:700">.</span>println(t);
}
}
</pre>
<p>
Tyle, że te kawałki kodu to znowu monolityczna pętla tak jak ta z początku co rozwiązywała jeden niszowy problem!!!
</p>
<h2>Inny Problem</h2>
<p>
Aby pokazać siłę mechanizmu, którym dysponujemy pykniemy inny ciekawy problem - ciąg Fibonacciego. Każdy student wie, że są dwa rozwiązania : czytelne rekurencyjne, które wypierdala stos i drugie - nieczytelne iteracyjne z tymczasowym akumulatorem.
</p>
<p>
A tu proszę! Pojawia się trzecie, czytelne i bezpieczne dla stosu. Najpierw określamy minimum logiki specyficznej dla naszego problemu.
</p>
<pre>
let fibStep (a1,a2) = (a2,a1+a2)
</pre>
<p>
I KOMPOZYCJA!
</p>
<pre>
> map fst $ take 20 $ iterate fibStep (0,1)
[0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181]
</pre>
<p>
Oczywiście to jest czytelne jak się język choć trochę zna. No bo bez sensu mówić, że jest "nieczytelne" jak się języka nie zna. To tak jakby Stefan pod budką powiedział, że język Duński jest niezrozumiały bo Stefan go nie zna. Bo według Stefana to jest cecha języka Duńskiego, ze Stefan go nie rozumie a nie cecha samego Stefana.
</p>
<p>
W każdym razie może to dobry czas na rzucenie flary i przekierowanie nienawiści w inna stronę poprzez zacytowanie jak Diekstra krytykuje w 2001 "Budget Council of The University of Texas." za to, że zamienili na studiach Haskella na Jave <a href="http://chrisdone.com/posts/dijkstra-haskell-java">o pod tym linkiem</a>
</p>
<h2>I z klasami</h2>
<p>
Generalnie cały wywód z pętla w Scali wyprowadzał taką ułomna implementację Strumienia, który już jest w bibliotece standardowej zoptymalizowany i gotowy do użycia.
</p>
<pre style="background:#eee;color:#3b3b3b"> <span style="color:#af82d4">//iterate podobnie jak w HAskellu</span>
Stream.iterate(<span style="color:#a8017e">1.0</span>)(nextRoot(<span style="color:#a8017e">2</span>)).take(<span style="color:#a8017e">5</span>).toList
<span style="color:#af82d4">//List(1.0, 1.5, 1.4166666666666665, 1.4142156862745097, 1.4142135623746899)</span>
<span style="color:#069;font-weight:700">val</span> rootTwo: Stream[<span style="color:#ff5600">Double</span>] =Stream.iterate(<span style="color:#a8017e">1.0</span>)(nextRoot(<span style="color:#a8017e">2</span>))
<span style="color:#af82d4">//zip dwóch streamów</span>
rootTwo.zip(rootTwo.tail).take(<span style="color:#a8017e">5</span>)
<span style="color:#af82d4">//fibonacci</span>
<span style="color:#069;font-weight:700">val</span> fibStep: ((<span style="color:#ff5600">Int</span>,<span style="color:#ff5600">Int</span>)) => (<span style="color:#ff5600">Int</span>,<span style="color:#ff5600">Int</span>) = { <span style="color:#069;font-weight:700">case</span> (a1,a2) => (a2,a1+a2) }
Stream.iterate((<span style="color:#a8017e">0</span>,<span style="color:#a8017e">1</span>))(fibStep).take(<span style="color:#a8017e">20</span>).map(_._2).toList
<span style="color:#af82d4">//List(1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765)</span>
</pre>
<h1> Nawet w Javie </h1>
<p>
Otóż tak - można to zrobić nawet w Javie! (z domieszką javaslang)
</p>
<pre style="background:#eee;color:#3b3b3b"><span style="color:#ff5600">private</span> List<span style="color:#000"><<span style="color:#016cff">Integer</span>></span> fibonacci(int limit){
Tuple2<span style="color:#000"><<span style="color:#016cff">Integer</span>, Integer></span> seed = Tuple.of(<span style="color:#a8017e">0</span>, <span style="color:#a8017e">1</span>);
UnaryOperator<span style="color:#000"><<span style="color:#016cff">Tuple2</span><span style="color:#000"><<span style="color:#016cff">Integer</span>,Integer></span>></span> step=
t->Tuple.of(t._2,t._1+t._2);
<span style="color:#069;font-weight:700">return</span> Stream.iterate(seed, step)
.limit(limit)
.map(t -> t._1)
.collect(Collectors.toList());
}
</pre>
<p>
Także to już nie jest kwestia, który język lepszy-gorszy ale raczej krytyka pewnego sposobu myślenia. I to w sumie ciekawie nawiązuje do wstępu. Otóż okazuje się, iż kompozycja w Javie również ma charakter czaso-przestrzenny. Do 2014 są kompozycyjne wieki ciemne a później odrodzenie...
</p>
<h1> Praktyka</h1>
<p>
Teoria teorią ale bez ćwiczeń mięśnie nie rosną. Dlatego spróbojemy warsztat na podstawie artykułu "Why Functional Programming Matters" : <a href="https://www.meetup.com/Java-User-Group-Lodz/events/234399408/">"Functional Programming Matters" w Scali,Haskellu i Javie8</a> .
</p>
<p>
Plan jest taki by robić w Scali i Javie8 ćwiczenia inspirowane artykułem a później dla porównania i perspektywy edukacyjnej zobaczyć jak to będzie wyglądało w Haskellu. 13 października w czwartek o 17:30. Także zapraszam.
</p>
<h1>Mobilizacja</h1>
<p>
Konferencja <a href="http://2016.mobilization.pl/">Mobilization</a> już 22 października. Bilety można kupować tutaj --> <a href="http://mobilization-vi.evenea.pl/">o tutaj</a>
</p>
<br/>
<br/><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijIvPZrEUfo-OQdJhxjoGSXMKb2A0liOezwDwa2sQKnQp2CRdKVg-bzikRFJSQq1I2WXh7NM5sDIv_QAHjCeHCR1cyQeLPBZipdMNgb6kxWmu1YAiSUfZpYJvAhUwR0PP3p5rLchMeio0/s1600/20160721_130709.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijIvPZrEUfo-OQdJhxjoGSXMKb2A0liOezwDwa2sQKnQp2CRdKVg-bzikRFJSQq1I2WXh7NM5sDIv_QAHjCeHCR1cyQeLPBZipdMNgb6kxWmu1YAiSUfZpYJvAhUwR0PP3p5rLchMeio0/s640/20160721_130709.jpg" width="640" height="360" /></a></div>Paweł Włodarskihttp://www.blogger.com/profile/04891037231290616803noreply@blogger.com1tag:blogger.com,1999:blog-5047632037494901372.post-8626097188118868842016-09-14T16:44:00.000+02:002016-09-14T16:44:57.143+02:00Załamanie czasoprzestrzeni na styku paradygmatów - currying spotyka dziedziczenie<p class="akapit">
Inspiracją dla tego wpisu jest kilka pierwszych stron niezwykle ciekawego artykułu, który pojawił się w 1990 roku a tytuł jego: <a href="https://www.cs.kent.ac.uk/people/staff/dat/miranda/whyfp90.pdf">Why
Functional Programming Matters</a>. Jest to tez praca bardzo praktyczna bo wyśmiewa popularne podejście w dyskusjach, że "X jest lepsze bo nie można w nim robić Y" - "Programowanie funkcyjne jest lepsze bo nie ma przypisań" itd.
<div class="cytat">
It is a logical impossibility to make a language more powerful by omitting features, no matter how bad they may be
</div>
</p>
<p>
Autor natomiast odwołuje się do bardzo ogólnych zasad tworzenia kodu, który dzięki odpowiedniej modularyzacji umożliwia łatwe komponowanie nowych konstrukcji z tychże modułów.
Jest to rodzaj kleju, który zlepia kawałki kodu tak, że łatwo tworzyć nowe programy bez rozlewania własnego kleju w postaci dziesiątek pozagnieżdzanych ifów, które drutują dwa moduły ze sobą.
</p>
<p>
I w zasadzie cały dokument pokazuje na przykładach jak funkcje wyższego rzędu oraz "przetwarzanie leniwe" znacznie ułatwiają kompozycję kawałków kodu bez wspomnianego zewnętrznego kleju. Nie ma sensu tutaj powtarzać wszystkie bo dokument jest dostępny na necie i ma 20coś stron. Dlatego skupimy się na jednej ciekawostce. Co się dzieje gdy spróbujemy przemycić trochę obiektowości Scali do przykładów, które prezentują podejście czysto funkcyjne? Otóż dzieje się ciekawie.
</p>
<h1>Currying i foldr - dwa bratanki</h1>
<p class="akapit">
Albo się zna foldr i nie trzeba tłumaczyć jak to działa albo się nie zna i trzeba doczytać - ale nie tutaj tylko trzeba podążać za strzałką ---> <a href="http://perugini.cps.udayton.edu/teaching/books/PL/www/lecture_notes/currying.html">http://perugini.cps.udayton.edu/teaching/books/PL/www/lecture_notes/currying.html</a> . Rysunek jest tez pożyczony z tej strony także może ktoś szybko wizualnie ogarnie.
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjz3JY2IioaGgM5NuXvgEaQqG5gEsPt7VRP4_41cKGlqcwXbMv1vCE62w5dCrlMx6lpnyhhUqAS0-OHLVXznPYm10_sFY2OzTOkZnmmzXwnemmK135AJDPHOgpcfSozI_GiaUDQGben4TM/s1600/foldr.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjz3JY2IioaGgM5NuXvgEaQqG5gEsPt7VRP4_41cKGlqcwXbMv1vCE62w5dCrlMx6lpnyhhUqAS0-OHLVXznPYm10_sFY2OzTOkZnmmzXwnemmK135AJDPHOgpcfSozI_GiaUDQGben4TM/s400/foldr.png" width="400" height="219" /></a></div>
<p>
jak już foldr ogarnięty to najpierw zerkniemy na Haskella bo wspomniany we wstępnie dokument opisuje przykłady w haskellu. Chyba. Bo to jest pismo z 1990 a wtedy z komputerów to były chyba tylko te rosyjskie jajeczka na rynku dostępne.
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQq6-ul-mZA15hxVZsUqlFoWcc4SscHb_rHyPl0DtZ7lgXijCefyRk1G1_CcgWSy8CkViz-4y8GC8gfZMhTSq0hpwzv47idyuQwk-eUC7XqIL2S8WufEmmH4Vb-PfnUeiBugwAo5dws8E/s1600/jajeczka.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQq6-ul-mZA15hxVZsUqlFoWcc4SscHb_rHyPl0DtZ7lgXijCefyRk1G1_CcgWSy8CkViz-4y8GC8gfZMhTSq0hpwzv47idyuQwk-eUC7XqIL2S8WufEmmH4Vb-PfnUeiBugwAo5dws8E/s400/jajeczka.gif" width="400" height="251" /></a></div>
<p>
W każdym razie w samym <i>foldr</i> jedzie się od prawej (dlatego fold<b>r</b> ight) i zwija listę według przepisu podanego w funkcji dwuelementowej.
</p>
<pre style="background:#eee;color:#3b3b3b"><span style="color:#45ae34;font-weight:700">foldr</span> (<span style="color:#069;font-weight:700">\</span>x y<span style="color:#069;font-weight:700">-></span>x<span style="color:#069;font-weight:700">+</span>y) <span style="color:#a8017e">0</span> [<span style="color:#a8017e">1</span>,<span style="color:#a8017e">2</span>,<span style="color:#a8017e">3</span>,<span style="color:#a8017e">4</span>,<span style="color:#a8017e">5</span>]
<span style="color:#af82d4">--15</span>
</pre>
<p>
I własnie na tym polega bajer bo nie ma czegoś jak "funkcja dwuargumentowa". W każdym razie nie ma w Haskellu i chyba w takim czysto funkcyjnym programowaniu też nie ma.
Nie jest to jakaś wielka strata bo łatwo można ten sam efekt uzyskać zwracając funkcję jednoelementową, która przyjmie drugi argument. To podejście zagościło już w tytule tej sekcji i nazywa się : <a href="https://pl.wikipedia.org/wiki/Currying">currying</a> (i też do doczytania)
</p>
<p>
I napisane w ten sposób dodawanie będzie wyglądać tak :
<pre style="background:#eee;color:#3b3b3b"><span style="color:#21439c">add</span> <span style="color:#069;font-weight:700">::</span> <span style="color:#a535ae">Int</span><span style="color:#069;font-weight:700">-></span><span style="color:#a535ae">Int</span><span style="color:#069;font-weight:700">-></span><span style="color:#a535ae">Int</span>
add a b <span style="color:#069;font-weight:700">=</span> a <span style="color:#069;font-weight:700">+</span> b
</pre>
</p>
<p>
I nie jest to już tylko "taka ciekawostka" ale zastosowanie tego mechanizmu umożliwia nam zupełnie nowa formę kompozycji dwóch kawałków kodu! No bo zoba :
<pre style="background:#eee;color:#3b3b3b"><span style="color:#af82d4">-- dla wszystkich "Foldable"</span>
<span style="color:#21439c">foldr</span> <span style="color:#069;font-weight:700">::</span> <span style="color:#ff5600">Foldable</span> <span style="color:#0053ff;font-weight:700">t</span> <span style="color:#069;font-weight:700">=></span> (<span style="color:#0053ff;font-weight:700">a</span> <span style="color:#069;font-weight:700">-></span> <span style="color:#0053ff;font-weight:700">b</span> <span style="color:#069;font-weight:700">-></span> <span style="color:#0053ff;font-weight:700">b</span>) <span style="color:#069;font-weight:700">-></span> <span style="color:#0053ff;font-weight:700">b</span> <span style="color:#069;font-weight:700">-></span> <span style="color:#0053ff;font-weight:700">t</span> <span style="color:#0053ff;font-weight:700">a</span> <span style="color:#069;font-weight:700">-></span> <span style="color:#0053ff;font-weight:700">b</span>
<span style="color:#af82d4">--i prosciej dla listy</span>
<span style="color:#21439c">foldr</span> <span style="color:#069;font-weight:700">::</span> (<span style="color:#0053ff;font-weight:700">a</span> <span style="color:#069;font-weight:700">-></span> <span style="color:#0053ff;font-weight:700">b</span> <span style="color:#069;font-weight:700">-></span> <span style="color:#0053ff;font-weight:700">b</span>) <span style="color:#069;font-weight:700">-></span> <span style="color:#0053ff;font-weight:700">b</span> <span style="color:#069;font-weight:700">-></span> [<span style="color:#0053ff;font-weight:700">a</span>] <span style="color:#069;font-weight:700">-></span> <span style="color:#0053ff;font-weight:700">b</span>
</pre>
</p>
<p>
To jest sygnatura "foldr" ze standardowej biblioteki Haskella. I cały bajer polega na tej funkcji "dwuargumentowej" , która jest typu <b>a->b->b</b> a zwijana tablica jest typu <b>[a]</b> w związku z tym mogę sobie dowolnie komponować funkcje, które działają na elementach tablicy <b>a->a</b>. W praktyce oznacza to zajebistą, wręcz epicką kompozycję kawałeczków kodu bo mając :
</p>
<pre style="background:#fff;color:#3b3b3b"><span style="color:#21439c">timesTwo</span> <span style="color:#069;font-weight:700">::</span> <span style="color:#a535ae">Int</span> <span style="color:#069;font-weight:700">-></span> <span style="color:#a535ae">Int</span>
timesTwo x <span style="color:#069;font-weight:700">=</span> <span style="color:#a8017e">2</span> * x
<span style="color:#21439c">addOne</span> <span style="color:#069;font-weight:700">::</span> <span style="color:#a535ae">Int</span> <span style="color:#069;font-weight:700">-></span> <span style="color:#a535ae">Int</span>
addOne x <span style="color:#069;font-weight:700">=</span> x <span style="color:#069;font-weight:700">+</span> <span style="color:#a8017e">1</span>
<span style="color:#21439c">toString</span> <span style="color:#069;font-weight:700">::</span> <span style="color:#a535ae">Int</span> <span style="color:#069;font-weight:700">-></span> <span style="color:#a535ae">String</span>
toString i <span style="color:#069;font-weight:700">=</span> <span style="color:#45ae34;font-weight:700">show</span> i
<span style="color:#21439c">joinString</span> <span style="color:#069;font-weight:700">::</span> <span style="color:#a535ae">String</span><span style="color:#069;font-weight:700">-></span><span style="color:#a535ae">String</span><span style="color:#069;font-weight:700">-></span><span style="color:#a535ae">String</span>
joinString s1 s2 <span style="color:#069;font-weight:700">=</span> s1 <span style="color:#069;font-weight:700">++</span> <span style="color:#666">"~"</span> <span style="color:#069;font-weight:700">++</span>s2
</pre>
<p>
Można teraz przetwarzać dowolnie elementy przed zwinięciem :
</p>
<pre style="background:#eee;color:#3b3b3b">*Learn<span style="color:#069;font-weight:700">></span> <span style="color:#45ae34;font-weight:700">foldr</span> joinString <span style="color:#666">"END"</span> [<span style="color:#a8017e">1</span>,<span style="color:#a8017e">2</span>,<span style="color:#a8017e">3</span>,<span style="color:#a8017e">4</span>,<span style="color:#a8017e">5</span>]
<span style="color:#069;font-weight:700"><</span>interactive<span style="color:#069;font-weight:700">>:</span><span style="color:#a8017e">38</span><span style="color:#069;font-weight:700">:</span><span style="color:#a8017e">25</span><span style="color:#069;font-weight:700">:</span>
No <span style="color:#069;font-weight:700">instance</span> <span style="color:#0053ff;font-weight:700">for</span> (<span style="color:#ff5600">Num</span> <span style="color:#a535ae">String</span>) <span style="color:#0053ff;font-weight:700">arising</span> <span style="color:#0053ff;font-weight:700">from</span> <span style="color:#0053ff;font-weight:700">the</span> <span style="color:#0053ff;font-weight:700">literal</span> ‘1’
<span style="color:#069;font-weight:700">...</span>
<span style="color:#af82d4">-- i szybko naprawiamy konwersją do string</span>
*Learn<span style="color:#069;font-weight:700">></span> <span style="color:#45ae34;font-weight:700">foldr</span> (joinString <span style="color:#069;font-weight:700">.</span> toString ) <span style="color:#666">"END"</span> [<span style="color:#a8017e">1</span>,<span style="color:#a8017e">2</span>,<span style="color:#a8017e">3</span>,<span style="color:#a8017e">4</span>,<span style="color:#a8017e">5</span>]
<span style="color:#666">"1~2~3~4~5~END"</span>
<span style="color:#af82d4">-- a dalej jak tylko typy się zgadzają można łączyć i w lewo i w prawo</span>
*Learn<span style="color:#069;font-weight:700">></span> <span style="color:#45ae34;font-weight:700">foldr</span> (joinString <span style="color:#069;font-weight:700">.</span> toString <span style="color:#069;font-weight:700">.</span> addOne ) <span style="color:#666">"END"</span> [<span style="color:#a8017e">1</span>,<span style="color:#a8017e">2</span>,<span style="color:#a8017e">3</span>,<span style="color:#a8017e">4</span>,<span style="color:#a8017e">5</span>]
<span style="color:#666">"2~3~4~5~6~END"</span>
*Learn<span style="color:#069;font-weight:700">></span> <span style="color:#45ae34;font-weight:700">foldr</span> (joinString <span style="color:#069;font-weight:700">.</span> toString <span style="color:#069;font-weight:700">.</span> addOne <span style="color:#069;font-weight:700">.</span> timesTwo ) <span style="color:#666">"END"</span> [<span style="color:#a8017e">1</span>,<span style="color:#a8017e">2</span>,<span style="color:#a8017e">3</span>,<span style="color:#a8017e">4</span>,<span style="color:#a8017e">5</span>]
<span style="color:#666">"3~5~7~9~11~END"</span>
*Learn<span style="color:#069;font-weight:700">></span> <span style="color:#45ae34;font-weight:700">foldr</span> (joinString <span style="color:#069;font-weight:700">.</span> toString <span style="color:#069;font-weight:700">.</span> timesTwo ) <span style="color:#666">"END"</span> [<span style="color:#a8017e">1</span>,<span style="color:#a8017e">2</span>,<span style="color:#a8017e">3</span>,<span style="color:#a8017e">4</span>,<span style="color:#a8017e">5</span>]
<span style="color:#666">"2~4~6~8~10~END"</span>
*Learn<span style="color:#069;font-weight:700">></span> <span style="color:#45ae34;font-weight:700">foldr</span> (joinString <span style="color:#069;font-weight:700">.</span> toString <span style="color:#069;font-weight:700">.</span> timesTwo <span style="color:#069;font-weight:700">.</span> addOne ) <span style="color:#666">"END"</span> [<span style="color:#a8017e">1</span>,<span style="color:#a8017e">2</span>,<span style="color:#a8017e">3</span>,<span style="color:#a8017e">4</span>,<span style="color:#a8017e">5</span>]
<span style="color:#666">"4~6~8~10~12~END"</span>
</pre>
<p>
Z <b>foldLeft</b> czy po haskellowemu <b>foldl</b> tak łatwo się chyba nie da bo tam zwijanie idzie od drugiej strony <b>b->a->b</b>
</p>
<h1>Funkcyjnie ale trochę niefunkcyjnie</h1>
<p>
A jak to wyjdzie w Scali? Też jest <b>foldRight</b> i jak przystało na język, który ma "wszystko", foldRight jest funkcją wyższego rzędu "na obiekcie". Jest ona funkcją wyższego rzędu, która przyjmują funkcja, która nie jest funkcją bo ma dwa parametry i zaczyna się robić ciekawie.
</p>
<pre style="background:#eee;color:#3b3b3b">scala> :t List(<span style="color:#a8017e">1</span>,<span style="color:#a8017e">2</span>,<span style="color:#a8017e">3</span>).foldRight(<span style="color:#666">"End"</span>) _
((<span style="color:#ff5600">Int</span>, <span style="color:#ff5600">String</span>) => <span style="color:#ff5600">String</span>) => <span style="color:#ff5600">String</span>
</pre>
<p>
W scali Funkcja dwuargumentowa to oczywiście nic innego jak instancja klasy <b>Function2</b> czyli funkcja jest obiektem i faktycznie jest bardzo hybrydowo. Problem z <i>Function2</i> jest taki, że tego nie da się łatwo skomponować z inną funkcją bo <i>"andThen"</i> i <i>"compose"</i> są jedynie na <b>Function1</b>, która jak na funkcje przystało jest klasą.
</p>
<p>
Mamy jednakże do dyspozycji pewien most bo <i>Function2</i> dostarcza nam metody na obiekcie funkcji (w końcu programowanie funkcyjne) do zmiany wersji dwuargumentowej w "currying" , "skuringowaną" funkcję jednoelementową (czy jak to tam nazwać)
</p>
<pre style="background:#eee;color:#3b3b3b"><span style="color:#af82d4"> /** Creates a curried version of this function.
*
* <span style="color:#069;font-weight:700">@return </span> a function `f` such that `f(x1)(x2) == apply(x1, x2)`
*/</span>
@annotation.unspecialized <span style="color:#069;font-weight:700">def</span> <span style="color:#21439c">curried</span>: T1 => T2 => R = {
(<span style="color:#0053ff;font-weight:700">x1</span>: T1) => (<span style="color:#0053ff;font-weight:700">x2</span>: T2) => apply(x1, x2)
}
</pre>
<p>
I dzięki temu możemy powrócić do świata jedno-argumentowych funkcji dzięki czemu kompozycja znów działa
</p>
<pre style="background:#eee;color:#3b3b3b"><span style="color:#069;font-weight:700">val</span> joinString:(<span style="color:#ff5600">String</span>,<span style="color:#ff5600">String</span>)=><span style="color:#ff5600">String</span>=(s1,s2)=>s1+<span style="color:#666">"~"</span>+s2
<span style="color:#069;font-weight:700">val</span> asString:<span style="color:#ff5600">Int</span>=><span style="color:#ff5600">String</span>= _.toString
<span style="color:#af82d4">//joinString compose toString -- to nie pomalujesz to je Function2</span>
joinString.curried <span style="color:#af82d4">//String => (String => String) = <function1></span>
<span style="color:#069;font-weight:700">val</span> convertAndJoin=joinString.curried compose asString <span style="color:#af82d4">//Int => (String => String) = <function1></span>
</pre>
<p>
I prawie jest fajnie ale niestety foldRight w Scali wygląda tak : <b>def foldRight[B](z: B)(op: (A, B) => B): B</b> - czyli znowu trzeba wrócić od wersji jedno-argumentowej do dwuargumentowej. I żeby zachować spójność to tym razem dla odmiany mamy funkcję w "companion object" <b>Function.uncurried</b>
</p>
<pre style="background:#eee;color:#3b3b3b"><span style="color:#af82d4">//List(1,2,3,4,5).foldRight("END")(convertAndJoin) //tez sie nie kompiluje bo jednoelementowa</span>
List(<span style="color:#a8017e">1</span>,<span style="color:#a8017e">2</span>,<span style="color:#a8017e">3</span>,<span style="color:#a8017e">4</span>,<span style="color:#a8017e">5</span>).foldRight(<span style="color:#666">"END"</span>)(Function.uncurried(convertAndJoin))
<span style="color:#af82d4">//res1: String = 1~2~3~4~5~END</span>
</pre>
<p>
No i z odrobiną dodatkowego kleju (ale kleju już gotowego w bibliotece standardowej) możemy uzyskać podobną kompozycję jak ta omawiana we wspomnianym na początku dokumencie
</p>
<pre style="background:#fff;color:#3b3b3b">List(<span style="color:#a8017e">1</span>,<span style="color:#a8017e">2</span>,<span style="color:#a8017e">3</span>,<span style="color:#a8017e">4</span>,<span style="color:#a8017e">5</span>).foldRight(<span style="color:#666">"END"</span>)(uncurried(convertAndJoin compose addOne))
<span style="color:#af82d4">//res2: String = 2~3~4~5~6~END</span>
List(<span style="color:#a8017e">1</span>,<span style="color:#a8017e">2</span>,<span style="color:#a8017e">3</span>,<span style="color:#a8017e">4</span>,<span style="color:#a8017e">5</span>).foldRight(<span style="color:#666">"END"</span>)(uncurried(convertAndJoin compose addOne compose timesTwo))
<span style="color:#af82d4">//res3: String = 3~5~7~9~11~END</span>
List(<span style="color:#a8017e">1</span>,<span style="color:#a8017e">2</span>,<span style="color:#a8017e">3</span>,<span style="color:#a8017e">4</span>,<span style="color:#a8017e">5</span>).foldRight(<span style="color:#666">"END"</span>)(uncurried(convertAndJoin compose timesTwo compose addOne))
<span style="color:#af82d4">//res4: String = 4~6~8~10~12~END</span>
</pre>
<p>
Czyli w sumie spoko, trzeba trochę konwersji porobić ale da się ładnie funkcje w foldzie komponować tak? Taki chu... znaczy taka ciekawostka... teraz taka ciekawostka będzie... bo zobaczymy co się dzieje gdy następuje kolizja paradygmatów.
</p>
<h1>Taka ciekawostka</h1>
<p>
Ciekawie zaczyna się dziać kiedy dorzuci my do równania tzw. "typy wyższego rzędu" czyli np Listę.
</p>
<pre style="background:#fff;color:#3b3b3b"><span style="color:#069;font-weight:700">val</span> append:<span style="color:#ff5600">Int</span>=>List[<span style="color:#ff5600">Int</span>]=>List[<span style="color:#ff5600">Int</span>]= i => l=> i ::l
</pre>
<p>
Cały czas spelnia to warunek dla foldr <b>a->b->b</b> gdzie <i>a::Int</i> a <i>b::List[Int]</i> . No czyli tylko trzeba trzasnąć <i>uncurring</i> i działamy tak? To byłoby zbyt proste ponieważ w wyniku wcale nie otrzymamy funkcji dwuargumentowej
</p>
<pre style="background:#fff;color:#3b3b3b">Function.uncurried(append)
<span style="color:#af82d4">//res5: (Int, List[Int], Int) => Int = <function3></span>
</pre>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHnaXtAwx5I3DpZF5KwRNz5bjAiACgCl10oWooz7YS3q5lDXzOPwxPpz8Xye2P50rvMCvQNrBrYQK6k073aSTAQPv5EByl2kvvKfdRGeFIw0hwH_F7y2cmaf9Szo9Q4Te-SENOozzoVrg/s1600/woow.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHnaXtAwx5I3DpZF5KwRNz5bjAiACgCl10oWooz7YS3q5lDXzOPwxPpz8Xye2P50rvMCvQNrBrYQK6k073aSTAQPv5EByl2kvvKfdRGeFIw0hwH_F7y2cmaf9Szo9Q4Te-SENOozzoVrg/s400/woow.gif" width="400" height="283" /></a></div>
<p>
Czyżby jakiś BUG? Nie Nie, nic z tych rzeczy - to jak najbardziej FICZER!!! Otóż jak na dobry hybrydowy język przystało scala ma dziedziczenie - a szczególnie w przypadku <i>List</i> oj mamy dużo tego dziedziczenia... I tak <b>List[A]</b> rozszerza <b>Seq[A]</b> , które rozszerza <b> PartialFunction[Int,A] </b> co ostatecznie rozszerza <b> Int=>A </b>
</p>
<p>
No i ostatecznie <b>List[Int]</b> jest typu <b>Int=>Int</b> czyli nasza funkcja o sygnaturze <b>Int=>List[Int]=>List[Int]</b> może być przekazana tam gdzie spodziewany jest typ <b>Int=>List[Int]=>Int=>Int</b>
</p>
<p>
Do tego dodajmy kolejny obiektowy super mechanizm do zaciemniania co się naprawdę dzieje zwany "method overloading" i już mamy rozwiązanie tajemnicy
</p>
<pre style="background:#eee;color:#3b3b3b"><span style="color:#af82d4"> /** Uncurrying for functions of arity 2. This transforms a unary function
* returning another unary function into a function of arity 2.
*/</span>
<span style="color:#069;font-weight:700">def</span> <span style="color:#21439c">uncurried</span>[a1, a2, b](<span style="color:#0053ff;font-weight:700">f</span>: a1 => a2 => b): (a1, a2) => b = {
(x1, x2) => f(x1)(x2)
}
<span style="color:#af82d4"> /** Uncurrying for functions of arity 3.
*/</span>
<span style="color:#069;font-weight:700">def</span> <span style="color:#21439c">uncurried</span>[a1, a2, a3, b](<span style="color:#0053ff;font-weight:700">f</span>: a1 => a2 => a3 => b): (a1, a2, a3) => b = {
(x1, x2, x3) => f(x1)(x2)(x3)
}
</pre>
<p>
Były takie zasady overloadingu na certyfikat SCJP i zdaje się, że wybierana była bardziej specjalizowana metoda - no cóż sytuacja gdzie jeden typ będący częścią typu funkcji rozszerza kolejną funkcje wydaje zajebistym tematem na kolejne super praktyczne zadania na rozmowie kwalifikacyjnej (zaraz po klasycznym left-joinie i "jak zbudowana jest hashmapa") : #HurraHurraFPplusOOP
</p>
<p>
Wspomniany efekt dosyć fajnie opisany jest tutaj w tymże wątku : <a href="https://groups.google.com/forum/#!topic/scala-user/_XW739goTw4">Jakiś wątek na forum z 2015</a>
</p>
<div class="dygresja">
<h2>Największe gunwo </h2>
<p>
Największe gówno jakie widziałem w scali wygląda niepozornie bardzo :
<pre style="background:#eee;color:#3b3b3b">List(<span style="color:#a8017e">1</span>,<span style="color:#a8017e">2</span>,<span style="color:#a8017e">2</span>,<span style="color:#a8017e">3</span>).toSet()
</pre>
Ale co tutaj jest dziwnego? "toSet()" na liście pewnie wyrzuci powtarzające się elementy i skończmy z <i>Set(1,2,3)</i>. Otóż nie bo wynik tej operacji to... <b>false</b>. Otóż toSet() na liście zwróci false -hmmm czy ta metoda nie powinna nazywać się "isSet()" ? kurwa. Nie w tym rzecz bo tam są tak naprawdę dwie metody.
</p>
<pre style="background:#eee;color:#3b3b3b"><span style="color:#af82d4">//co się dzieje</span>
<span style="color:#069;font-weight:700">val</span> set: Set[Any] =List(<span style="color:#a8017e">1</span>,<span style="color:#a8017e">2</span>,<span style="color:#a8017e">2</span>,<span style="color:#a8017e">3</span>).toSet
set.apply(())
set.apply ()
set apply ()
set()
<span style="color:#af82d4">//teraz zastap set wyrazeniem</span>
List(<span style="color:#a8017e">1</span>,<span style="color:#a8017e">2</span>,<span style="color:#a8017e">2</span>,<span style="color:#a8017e">3</span>).toSet.apply(())
List(<span style="color:#a8017e">1</span>,<span style="color:#a8017e">2</span>,<span style="color:#a8017e">2</span>,<span style="color:#a8017e">3</span>).toSet.apply ()
List(<span style="color:#a8017e">1</span>,<span style="color:#a8017e">2</span>,<span style="color:#a8017e">2</span>,<span style="color:#a8017e">3</span>).toSet apply ()
List(<span style="color:#a8017e">1</span>,<span style="color:#a8017e">2</span>,<span style="color:#a8017e">2</span>,<span style="color:#a8017e">3</span>).toSet ()
List(<span style="color:#a8017e">1</span>,<span style="color:#a8017e">2</span>,<span style="color:#a8017e">2</span>,<span style="color:#a8017e">3</span>).toSet()
</pre>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSP6ntm8BqIkWuGPDSJOxeriXXf5jh1sf-SyvEjY5YyCNMSUv7-CG2_FOhaMj6QKAf6gIZ0TSjbNIXOe5BAIrwW6TRs4Llf6bWvUztM4R0Mx6rwZwbhaf_Huslk2hqR2cKRAEBVqmbXK8/s1600/aleeecoooo.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSP6ntm8BqIkWuGPDSJOxeriXXf5jh1sf-SyvEjY5YyCNMSUv7-CG2_FOhaMj6QKAf6gIZ0TSjbNIXOe5BAIrwW6TRs4Llf6bWvUztM4R0Mx6rwZwbhaf_Huslk2hqR2cKRAEBVqmbXK8/s320/aleeecoooo.gif" width="320" height="315" /></a></div>
<p>
Dokładne wytłumaczenie jest w scala-puzzlersie : <a href="http://scalapuzzlers.com/#pzzlr-040">http://scalapuzzlers.com/#pzzlr-040</a> . To jest zło. Była kiedyś taka gra "Świątynia pierwotnego zła" - to była gra gdzie magiem i druidką walczyło się własnie z takimi konstrukcjami kodu.
</p>
</div>
<br/>
<br/>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4VxHS_LyFUHAQdodlLtWTu1pDEDCEtK2RXwlQDPH_F-mOmR5qEIJG5UdwYrQ5qNk3gsGftOK47raxsujxmQG41CCefBVx2BdoWwjzatqjVTgWaMbHVSgYKsbDSCJi4D1fIW3zfHKsTPM/s1600/siklawa3.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4VxHS_LyFUHAQdodlLtWTu1pDEDCEtK2RXwlQDPH_F-mOmR5qEIJG5UdwYrQ5qNk3gsGftOK47raxsujxmQG41CCefBVx2BdoWwjzatqjVTgWaMbHVSgYKsbDSCJi4D1fIW3zfHKsTPM/s640/siklawa3.jpg" width="360" height="640" /></a></div>
Paweł Włodarskihttp://www.blogger.com/profile/04891037231290616803noreply@blogger.com2tag:blogger.com,1999:blog-5047632037494901372.post-21882330503310116802016-08-31T18:16:00.000+02:002016-08-31T18:16:08.229+02:00Program jako funkcja całkowita - czyli kiedy naprawdę nie ma błędów<p class="akapit">
<i>"Litr czystej poproszę"</i> - to zdanie wypowiedziane w całodobowym sklepie branżowym niesie ze sobą wystarczająca ilość informacji aby było wiadomo "o co chodzi". A wiadomo o co chodzi gdyż kontekst już definiuje pewne pojęcia jak to, że chodzi o napój w tym sklepie, że ma się to odbyć teraz i że popłynie hajs. Te rzeczy są oczywiste.
</p>
<p>
Wynik 2+2=4 także jest oczywisty. Jeśli zapytamy o rezultat porównania <b>2 + 2 == 4</b> to czytelnik o ponadprzeciętnej podejrzliwości może szukać podstępu w definicji operatora <b>+</b> (tak, w niektórych językach można go zdefiniować jak się chce) albo widzi spisek w tym jak operator <b>==</b> porównuje wartości, a może jest tu jakiś "Boxing" a może porównuje referencje? Raczej mało komu przyjdzie do głowy, że może mechanika działa prawidłowo ale 2+2 to wcale nie 4? eeee ... że co? Brzmi to z pozoru absurdalnie ale jednak są ludzie, którym oczywistość nie wystarcza i wyprowadzili wcale niebanalny dowód że <a href="http://www.cs.yale.edu/homes/as2446/224.pdf">2+2 to faktycznie 4</a>
</p>
<p>
Teraz inna sytuacja - słyszysz zdanie : <i>"W moim programie jest Błąd"</i> a jeśli ma być światowo to <i>"W moim programie jest Bug"</i> i zazwyczaj rzeczą, na której koncentruje się sytuacja jest ten <b>Bug</b>. Raczej nie usłyszysz w odpowiedzi "W twoim programie jest Bug, a jak zdefiniowałeś pojęcie programu?" albo "zdefiniuj warunki wymagane do stwierdzenia <b>jest Błąd</b>" czy wyjątek to błąd , czy sam fakt, że może polecieć wyjątek ale nie poleciał to błąd? Czy jeśli nie leci wyjątek a jest zły rezultat to jest to błąd? No i w końcu czy jeśli wszystko działa to w programie jest błąd czy go nie ma?
</p>
<p>
Po tym dowodzie na dwie strony, że <i>2+2=4</i> ostatnie zdanie nie powinno być takie oczywiste - <i>Czy jeśli program działa i zwraca poprawny wynik to jest w nim błąd?</i>.Zagłębmy się w ten ciekawy problem i zdefiniujmy <i>"Program"</i> i <i>"Błąd"</i>.
</p>
<h1>Korzenie</h1>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkbnJPHEpRkMY8kI5dm75ikue_xataTxjQifVMH8rVg3NLf1S6PQE2n0QvWHj8z_CVTjWC24aMG0ZwtAReAWPFXX_nVqG6wKyjeLj8pVUUUDBIvOGj1_mCDUpCi7CmP1wldjENTdigTdM/s1600/humancomputer.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkbnJPHEpRkMY8kI5dm75ikue_xataTxjQifVMH8rVg3NLf1S6PQE2n0QvWHj8z_CVTjWC24aMG0ZwtAReAWPFXX_nVqG6wKyjeLj8pVUUUDBIvOGj1_mCDUpCi7CmP1wldjENTdigTdM/s400/humancomputer.jpg" width="400" height="313" /></a></div>
<p>
Powyższy obrazek jest skopiowany ze strony na wikipedii : <a href="https://en.wikipedia.org/wiki/Human_computer">Human Computer</a>. Bo oto okazuje się, że komputery istniały jeszcze zanim powstały ...komputery.
<div class="cytat" style="padding:10px">
The term "computer", in use from the early 17th century (the first known written reference dates from 1613), meant <b>"one who computes"</b>: a person performing mathematical calculations, before electronic computers became commercially available.
</div>
</p>
<p>
Ha! Czyli nie dość, że trzeba zdefiniować co to jest program to jeszcze nie jest jasne co to jets ten "komputer". I teraz sformułowanie <i>"Babcia kupiła mi na komunie komputer"</i> może nawet zakończyć się sprawą w sądzie na skutek uprawiania niezgodnego z prawem niewolnictwa!
</p>
<p>
Ciekawy jest fragment o tym co oni robili "a person performing mathematical calculations". Pewnie nie jeden profesorek rzuci teraz we mnie cyrklem ale teoretycznie coś takiego :
<pre>
fun czyProstokątny(a:Integer,b:Integer,c:Integer):Boolean = pow(a,2)+pow(b,2) == pow(c,2)
</pre>
to też jest jakieś tam "mathematical calculations" i przy założeniu, że "a" i "b" to przyprostokątne a "c" to zawsze przeciwprostokątna to ta funkcja sprawdza czy trójkąt jest prostokątny. Ale czy sprawdza? Tego nie wiadomo. Bo co robi funkcja <i>"pow"</i>? Być może wydaje z głośnika na płycie głównej dźwięki <i>"POWPOW"</i> ?
</p>
<p>
Przydałoby się tutaj jakieś twierdzenie w stylu <i>Dla każdego x należącego do zbioru liczb całkowitych pow(x,2)=x * x </i> . Oczywiście można tak jechać dalej ze znaczkiem <b>"*"</b> ale tutaj założymy, że to mnożenie, które działa "dobrze" bez wnikania w definicję "dobrze" bo to jest tylko wstep do ciekawszych rzeczy.
</p>
<h1>Czy coś może pójść nie tak?</h1>
<p class="akapit">
Wydaje się, że pierwszym problemem może być przekroczenie zakresu Integera. Jaki jest zakres Integera ? <i>"Ja wiem!Ja wiem! W javadocu jest , że 2 <sup>31</sup> - 1"</i>
</p>
<p>
I to jest właśnie takie myślenie językiem programowania. Czasem niestety jednocześnie pierwszym i jedynym jaki dana osoba napotka w życiu. No bo zobacz - taki Haskell wydaje się mieć trochę na zakresy wyjebane :
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRRQ21xMuvxIv3EDmkLrCsyHwgbyMLNprTCRLfRDsUrnZ6vqUrBbZnF_zE6KSTz7JOBtg4dgKasTo2LB60rWm9SXekxoHi5OnZrs3Z-oKUir1FXFNNHY3jhg8i1WX9BBUMITZFicYz5bg/s1600/duzaliczba.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRRQ21xMuvxIv3EDmkLrCsyHwgbyMLNprTCRLfRDsUrnZ6vqUrBbZnF_zE6KSTz7JOBtg4dgKasTo2LB60rWm9SXekxoHi5OnZrs3Z-oKUir1FXFNNHY3jhg8i1WX9BBUMITZFicYz5bg/s640/duzaliczba.jpg" width="640" height="214" /></a></div>
<h2>Dowód na czytanie z pliku?</h2>
<p class="akapit">
Ciekawie zaczyna się robić kiedy zaczniemy drążyć "skąd dokładnie brane jest a,b i c"? Niechże to będzie plik CSV z jedną linią by było prościej
<pre>
3,4,5
</pre>
I teraz np mamy dwie dodatkowe funkcje
<pre>
fun czytaj(plik:File):String
fun parsuj(linia:String):(a:Integer,b:Integer,c:Integer)
</pre>
Ba i nawet teraz można zrobić kompozycję bezpośrednio z pliku w wynik sprawdzania czy trójkąt jest prostokątny
<pre>
czytaj andThen parsuj andThen czyProstokątny
</pre>
</p>
<p>
<i>- Łooołooołooołoo łooooo chwila chwila chwillllla a co jak się wyjebie?" <br/>
- ale co?<br/>
- no to czytanie z pliku?<br/>
- ale ... ale jak?<br/>
- no jak pliku nie będzie?<br/>
- no.. no.. to może załóżmy, że zawsze jest...<br/>
</i></p>
<p>
Wydaje mi się, że powyższy problem jest przedstawiony bardziej fachowo (i bez słowa "wyjebie" które może zgorszyć niejednego przedstawiciela zblazowanej klasy średniej) w poniższym abstrakcie.
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJlM4wpxAEo-bRqe-Ql2bFrRanoRNJXj8a4ReXUrOUNlUIurKroc9yuS8O7T-QcMjnHtyHLBDiPgpUmeOzZm8KOradXUQ4WZLTxfPBF9mC7M56IvZqEFikxOaf6vLb9XiiyUeyjphp20I/s1600/abstract.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJlM4wpxAEo-bRqe-Ql2bFrRanoRNJXj8a4ReXUrOUNlUIurKroc9yuS8O7T-QcMjnHtyHLBDiPgpUmeOzZm8KOradXUQ4WZLTxfPBF9mC7M56IvZqEFikxOaf6vLb9XiiyUeyjphp20I/s640/abstract.jpg" width="640" height="200" /></a></div>
</p>
<p>
Otóż takie teoretyczne rozważania rypią się gdy mamy do czynienia z czymś co dosyć trudno przedstawić "matematycznie" jak na przykład czytanie z bazy czy przesyłanie danych po sieci - no bo jak , no jak wygląda teoretycznie poprawna funkcja "<i>zaciągnijLegalnieFilmZTorrenta</i>". No i dopiero wyjście z tej sytuacji znalazł <b>Eugenio Moggi</b> a smaczku dodaje, że abstrakt pochodzi z jego pracy zatytułowanej <a href="https://core.ac.uk/download/files/145/21173011.pdf">Notions of computation and monads</a> (moooooooooooooooonads!!!)
</p>
<h1>Definicja BUGa jako funkcji</h1>
<p class="akapit">
Tak dla przypomnienia - funkcja całkowita to na przykład dodawanie bo co byśmy tam nie podali to i tak zadziała. Funkcja częściowa to dzielenie bo dla argumentu gdzie dzielimy przez zero nie jest ona określona. Jeśli zastosujemy dzielenie z założeniem, ze zadziała dla każdej liczby - wtedy mamy błąd.
</p>
<p>
funkcja <b>FormularzRejestracyjny=>User</b> jest określona dla każdego poprawnie wypełnionego formularza ale nieokreślona dla Formularza, który w polu wiek ma wartość <i>"DaaaajKamienia"</i>
</p>
<p>
funkcja <b>Plik=>String</b> jest określona jedynie dla zbioru poprawnie zdefiniowanych i plików.
</p>
<p>
funkcja <b>IdZamowienia=>Zamowienie</b> jest określona jedynie dla istniejących zamówień.
</p>
<p>
funkcja <b>OdpytanieZewnętrznegoAPI => Wynik</b> też jest częściowa bo określona tylko dla sytuacji kiedy otrzymamy jakiś wynik.
</p>
<p>
Nie wiem czy ktoś z was podchodizł do tego od tej strony - ja kiedyś nie. Zazwyczaj po prostu chodziło o obsługę wyjątków. Tymczasem na obsługę wyjątków można trochę tak patrzeć jak na taki zewnętrzny hak, który umożliwia nam używanie funkcji częściowych tak jakby one były całkowite. Czyli poza standardowym znaczeniem BUGa kiedy to funkcja zwraca po prostu zły wynik (f(a,b)=a+b+1 - funkcja czysta ale zjebana) dochodzi dodatkowy rodzaj Błędu.
</p>
<p>
<b>Błąd - sytuacja w której, funkcja częściowa jest używana tak jakby była całkowita</b>. Np takie coś
<pre>
sprawdzLinie:String=>Boolean = parsujLinie and Then czyProstokątny
</pre>
można zdefiniować jako błąd gdyż funkcja parsujLinie w kontekście naszego przykładu jest zdefiniowana jedynie dla takiej formy gdzie w linii jest<i>a,b,c</i> i to nawet może przejść wszystkie testy i chodzić na produkcji 5 lat. Cały czas kwalifikuje się to jako błąd.
</p>
<p>
Jak sprawdzić czy funkcja jest całkowita? - scalacheck.
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtdTbVwzvghCdxIarBQLQTBzp3EBT5LZluXifLS2TohU9eWvNHZ-x0uNb9gydnZjTFt3jBAYtZERHfH2Osl31alI9GgD9wrVknp525yj_Qo8vkRYNFAxBwXylMN1yBAOHmrRRcEokOXfk/s1600/partialfunction.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtdTbVwzvghCdxIarBQLQTBzp3EBT5LZluXifLS2TohU9eWvNHZ-x0uNb9gydnZjTFt3jBAYtZERHfH2Osl31alI9GgD9wrVknp525yj_Qo8vkRYNFAxBwXylMN1yBAOHmrRRcEokOXfk/s640/partialfunction.png" width="640" height="253" /></a></div>
<div class="podpis" style="font-size: 12px;">
Wizualizacja funkcji częściowej. Czerwona Kulka może symbolizować zapytanie do bazy danych, które zakończyło się niepowodzeniem.
</div>
<h1>Kompozycje i efekty </h1>
<p class="akapit">
Cały problem z wyjątkami polega na tym, że przeszkadzają one w kompozycji a kompozycja to "Reusage (Rejusedż)" czyli święta gral programowania. No bo jak mam funkcję <b>String=>(Int,Int,Int)</b>, która mówi mi, że zwraca trzy elementowego Tupla (z polskeigo krotkę) a tak naprawde zwraca tego Tupla albo ch.. wie jaki wyjątek to ja nie moge sobie prosto tej funkcji skomponować z <b>(Int,Int,Int) => Boolean</b> bo na wejściu wcale nie muszą pojawić się trzy inty!!!
</p>
<p>
No dobra ponarzekalimy ale gdzie jest SOLUSZYN? Zamiast udawać, że funkcja częściowa to funkcja całkowita i try-catchem łapać pokemony może da rade zamienić jakoś te funkcję częściową w całkowitą? I to zaproponował właśnie Eugenio Moggi - chyba to zaproponował bo połowy jego pracy nie rozumiem ale poznaje rysunki, podobne do tych które są na stronie wiki o monadach (te takie ze strzałkami).
</p>
<p>
Klasycznie jest coś takiego :
<pre style="background:#eee;color:#3b3b3b"><span style="color:#069;font-weight:700">val</span> divide:(<span style="color:#ff5600">Int</span>,<span style="color:#ff5600">Int</span>)=><span style="color:#ff5600">Int</span> = (a,b) => a/b
<span style="color:#069;font-weight:700">try</span>{
divide(<span style="color:#a8017e">4</span>,<span style="color:#a8017e">0</span>)
}<span style="color:#069;font-weight:700">catch</span>{
<span style="color:#069;font-weight:700">case</span> e:ArithmeticException => println(<span style="color:#666">"Kalwi & Remi - EXPLOSION"</span>)
}
</pre>
I naprawdę ważne jest aby zrozumieć, że tutaj to try, jest takim zewnętrznym klejem który utrudnia kompozycję.
</p>
<p>
Dalej mamy dedykowany typ dla funkcji częściowej:
<pre style="background:#eee;color:#3b3b3b"><span style="color:#069;font-weight:700">val</span> partialDivide : PartialFunction[(<span style="color:#ff5600">Int</span>,<span style="color:#ff5600">Int</span>),<span style="color:#ff5600">Int</span>] = {
<span style="color:#069;font-weight:700">case</span> (a,b) <span style="color:#069;font-weight:700">if</span> b!=<span style="color:#a8017e">0</span> => a/b
}
println(partialDivide.isDefinedAt(<span style="color:#a8017e">4</span>,<span style="color:#a8017e">0</span>)) <span style="color:#af82d4">//false</span>
</pre>
Tutaj już plus jest taki, że nie udajemy, iż każdy argument ma jakiś wynik.
</p>
<h2>I teraz następuje zamiana funkcji częściowej na całkowitą</h2>
<pre style="background:#eee;color:#3b3b3b"><span style="color:#069;font-weight:700">val</span> totalDivide: ((<span style="color:#ff5600">Int</span>, <span style="color:#ff5600">Int</span>)) => Option[<span style="color:#ff5600">Int</span>] =partialDivide.lift
println(totalDivide(<span style="color:#a8017e">4</span>,<span style="color:#a8017e">0</span>)) <span style="color:#af82d4">//None</span>
println(totalDivide(<span style="color:#a8017e">4</span>,<span style="color:#a8017e">2</span>)) <span style="color:#af82d4">//Some(2)</span>
</pre>
<p>
"totalDivide" jest funkcją całkowitą i dla każdego argumentu zwraca ona rezultat. Tam gdzie dzielenie ma sens będzie to <b>Some</b> tam gdzie nie ma będzie <b>None</b> ale będzie!
Może powstać pytanie ale co z tego jak w wyniku dostajemy jakiś <i>"twór"</i>? Ów twór jest tzw. Typem wyższego rzędu (po javowemu "klasa z generykiem") i obsługuje się go przy pomocy funkcji wyższego rzędu oraz pattern matchingu. Drugiego mechanizmu w Javie nie ma a pierwszy jest od niedawna dlatego w półswiatku javowym owe podejście może wydawać się bardzo egzotyczne.
</p>
<p>
Co z kompozycją? Jest cała teoria opisująca jak to się komponuje i ze zwykłymi funkcjami jak i z innymi tworami. Jedno popularne nazewnictwo używa na twory słów Funktor, Monada itd ale też spotkałem się z podejściem do tego jako do <b>Efektu</b> i np. Option to <i>Efekt braku czegoś</i> a Future <i>Efekt czasu w obliczeniach</i>.
<p>Owy efekt spełnia pewne prawa i aby się przekonać, że na pewno je spełnia możemy użyć scalacheck. Ba! ScalaZ ma nawet gotowy zestaw testów Scalachecka by sprawdzić czy aby na pewno wiemy z czym mamy do czynienia : <a href="http://eed3si9n.com/learning-scalaz/Functor+Laws.html">Functor Laws</a> </p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd_l2HDHweUP_Rw033ym3JysV1GIMxcE4q8MwYf3BhEx03raLx3yQfOQLOPflp7V8y9lBd3-ThZn6iUaQtCBaq8PEGs4o93uMoXqmWTzGe5Vi3QQfSErhWthlyexsuBKkU_fdfriL7lqM/s1600/funktor.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd_l2HDHweUP_Rw033ym3JysV1GIMxcE4q8MwYf3BhEx03raLx3yQfOQLOPflp7V8y9lBd3-ThZn6iUaQtCBaq8PEGs4o93uMoXqmWTzGe5Vi3QQfSErhWthlyexsuBKkU_fdfriL7lqM/s640/funktor.jpg" width="640" height="132" /></a></div>
</p>
<p>
No i jak nasz efekt spełnia prawa Funktora to możemy śmiało pisać z założeniem, <i>Option(x).map(f).map(g)</i> to to samo co <i>Option(x).map(f andThen g)</i>
</p>
<h2>Tyle w temacie</h2>
<p>
Celem tego wpisu nie jest brnięcie dalej ale własnie zatrzymanie się w tym miejscu. Temat jest jak rzeka a za węgłem czekają Funktory,Monady, Monoidy, Foldable,Kleisli, Transformatory Monad czy inne potężne narzędzia kompozycji efektów. Zazwyczaj na co dzień nie mamy czasu/ochoty zatrzymać się na chwilę i poddać kontemplacji nad tym co my właściwie robimy. Jednak należy pamiętać, że nasze obecne wnioski budowane są na dogmatycznych założeniach - jeśli czasem im się bliżej nie przyjrzymy to wiele ciekawych dróg i perspektyw może być dla nas na zawsze zamkniętych :(
</p>
<div class="dygresja">
<h2>Anegdota o .Necie </h2>
<p>Zazwyczaj na początku nauki instaluje się jakiś kompilator , pisze hello world i dalej jakieś tam proste przykłady. Ponieważ bez ogólnych podstaw teoretycznych mechanizmy konkretnego języka staną się jedynymi ilustracjami tychże mechanizmów to istnieje niebezpieczeństwo, że ludzie zaczną utożsamiać implementacje z koncepcjami. W javie to będzie na przykład "polimorfizm - aha czyli dziedziczenie klas" albo powtarzanie bez głębszego zastanowienia, że wszystkie pola w klasie (bo przecież nie może być poza klasą nie?) muszą być private bo..bo.. bo enkapsulacja i ch*j. </p>
<p>
No i raz było w Łodzi spotkanie grupy devs@lodz, która wykształciła się z grupy dot netowej. No i jest to spotkanie i gostek gada o MVC ale tak gada jakby używał cały czas słowa samochód ale chodziło mu o jedynie o Poloneza. Od słowa do słowa zrozumiałem, że Microsoft im tam potworzył po jednej implementacji wszystkiego i MVC to po prostu nazwa frameworka i też w moim odczuciu, trochę zdziwili się, że jak w Javie chcesz mieć MVC to myślisz o koncepcji i wybierasz sobie dopiero jedno z narzędzi, które to realizuje.
</p>
<p>
Innym analogicznym przykładem rozmowa o systemie operacyjnym gdy znasz tylko windowsa - "dobra znajomość systemu operacyjnego wymaga płynnej obsługi menu start" - czy coś w tym stylu.
</p>
<p>
Studiowanie to gorący temat w IT zwłaszcza, że w jakimś tam rankingu ostatnio dwie polskie uczelnie były w 5 setce a żadna Łódzka się nawet nie załapała ale polecam pogrzebać na edx czy courserze i można znaleźć naprawdę ciekawe kursy online dostarczane przez uczelnie z samej czołówki. Do tego wiele z tych uczelni ma swoje własne portale jak <a href="http://ocw.mit.edu/index.htm">http://ocw.mit.edu/index.htm</a>
</p>
</div>
<br/><br/>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbCFHI_ctem_Rb_yLbDzmsclsKz_r-iBRF_fK4b1JAmhe-HQIYyE2mhhyphenhypheno-9TcjfI8x9EHTthyyAzt7Vchr5X0-A2xLAXNZuwz61l63Byn20cO6ZyggGc0SOEZRP0WP2EyB-EanapqVUY/s1600/nakrzyzne.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbCFHI_ctem_Rb_yLbDzmsclsKz_r-iBRF_fK4b1JAmhe-HQIYyE2mhhyphenhypheno-9TcjfI8x9EHTthyyAzt7Vchr5X0-A2xLAXNZuwz61l63Byn20cO6ZyggGc0SOEZRP0WP2EyB-EanapqVUY/s640/nakrzyzne.jpg" width="640" height="360" /></a></div>
Paweł Włodarskihttp://www.blogger.com/profile/04891037231290616803noreply@blogger.com0tag:blogger.com,1999:blog-5047632037494901372.post-16313528125078874762016-08-18T13:47:00.000+02:002016-08-18T13:47:08.843+02:00Historia Kulki Animowanej<p class="akapit">
Jest to wpis o historii pewnej Kulki. Nie jest to jednak zwykła kulka bo to historia kulki animowanej i to animowanej javascriptem. I nawet ona spada według jakichś tam praw fizyki i nawet za sobą zostawia ślad (rysowany też pośrednio javascriptem). Jest to kulka w javascripcie ale bez pisania w javascripcie.
</p>
<p>
Podążając za poprzednim dającym (na opewno mnie) nadzieję na łeba wpisem <a href="http://pawelwlodarski.blogspot.com/2016/08/i-nawet-dla-ciebie-jest-nadzieja-w-webie.html">"Scala.js taka piękna"</a> cały javascript jest wygenerowany przy pomocy Scala.js. I (jak dla mnie) kod jest fajnie. Bo są typy. I Jest fajnie.
</p>
<h1>Kino 8D</h1>
<p>Czcionka na gifach jest mała dlatego trzeba w nie kliknąć albo skrolem powiększyć. Na pierwszym przeźroczu widać, że wielkość kulki można konfigurować i ona tak rośnie i maleje wtedy od razu. Do tego na bieżąco liczona jest masa tejże kulki z założeniem, że gęstość to średnia gęstość meteorytu czyli <b>3.4 g/cm^3</b> </p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5UVISJ3oP_ZdNTV7i3EpIRx-l_ttJg3AelmnC3FZ471cSzRDYKGzZ77ZWaoz7kXHtOktl0EYhIF8vm1XWHhWYowh06-VF0HvOAfWa61LYkM2QLUbySGiPWYsP3XfX340B3SUnjoWPw3I/s1600/kulka-config.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5UVISJ3oP_ZdNTV7i3EpIRx-l_ttJg3AelmnC3FZ471cSzRDYKGzZ77ZWaoz7kXHtOktl0EYhIF8vm1XWHhWYowh06-VF0HvOAfWa61LYkM2QLUbySGiPWYsP3XfX340B3SUnjoWPw3I/s640/kulka-config.gif" width="640" height="353" /></a></div>
<p>
Jest tam także validacja pola gdzie można wprowadzić promień kulki. A, że <i>rrrr</i> to nie jest najlepsza wartość dla promienia dlatego warto ją sprawdzić. Tutaj dla podkreślenia możliwości Scali.js do validacji została użyta <i>Monada</i>. Jest to tylko <i>Try</i> ale zawsze Monoada®© Zawsze można się (nie)znajomością teorii kategorii popisać przed kolegami od front-endu.
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgs5sVZDyKIib8S0Qd6_rOenQFFkSnitcfRYPKWdnxJkatdAeRxzfalhlzSivKz-3UjcbLETEBjFpN_X0beyqbSWETL2M1hWSrTFd5L4qVRkTAj9xR0eF2E_4zXCiPSstXDM5v5jtrVsB0/s1600/validacja.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgs5sVZDyKIib8S0Qd6_rOenQFFkSnitcfRYPKWdnxJkatdAeRxzfalhlzSivKz-3UjcbLETEBjFpN_X0beyqbSWETL2M1hWSrTFd5L4qVRkTAj9xR0eF2E_4zXCiPSstXDM5v5jtrVsB0/s640/validacja.gif" width="640" height="353" /></a></div>
<p>
No i w końcu "leć Adam leć". Zwróćcie uwagę, że wraz z czasem odległość pomiędzy czerwonymi kropkami się zwiększa a to dlatego, że działa przyspieszenie i składowa <b>y</b> prędkość się także powiększa z czasem co obrazuje wydłużająca się pionowa strzałka symbolizująca pionowa składową wektora prędkości.Dokładnie tak. W symulacji użyte jest przyśpieszenie księżyca <b>1.6 m/s</b> aby kulka za szybko nie spadła i aby spektakl się za szybko nie zakończył.
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFoYNJI64vgld8sLPM2khUcrCuTCLO-zBGNgA_fum3kYYSioZVopcal0FCgQz3lpqdNJHBVCoafUaQOhwrOuzT_bvqERiPitqEPujAsJLNyiTLQM3L3IF2uX-bKs5ruaIYJ5Hv5x-IFQs/s1600/kulka-run.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFoYNJI64vgld8sLPM2khUcrCuTCLO-zBGNgA_fum3kYYSioZVopcal0FCgQz3lpqdNJHBVCoafUaQOhwrOuzT_bvqERiPitqEPujAsJLNyiTLQM3L3IF2uX-bKs5ruaIYJ5Hv5x-IFQs/s640/kulka-run.gif" width="640" height="353" /></a></div>
<h1>"Z życia programisty front-endu"</h1>
<p class="akapit">
Cały eksperyment miał za zadanie sprawdzenie <b>"Jak się w tym pisze"</b>. Pierwsza ważna rzecz na jaką należy zwrócić uwagę przy zasiadaniu do nowej technologii to czy na StackOverflow są już odpowiedzi do wszystkich zadań
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1fGz3ZZVfJayzmcWWtI8GZrdikmxj2roC7byJ5XsjdhgCz6PVzQ5nTf0J_DmHwSVIy-YRNakbK950EBPMM5KjhSYVwxU5g5rRZNhF5cNW3PBE_Qs6jMNeUvB7MjbbgQCkDMddRp39NfY/s1600/stackoverflow.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1fGz3ZZVfJayzmcWWtI8GZrdikmxj2roC7byJ5XsjdhgCz6PVzQ5nTf0J_DmHwSVIy-YRNakbK950EBPMM5KjhSYVwxU5g5rRZNhF5cNW3PBE_Qs6jMNeUvB7MjbbgQCkDMddRp39NfY/s400/stackoverflow.jpg" width="305" height="400" /></a></div>
<p>
Generalnie te strzałki w symulacji moje nie są jeśli za "moje" uznać napisane własnoręcznie. Po wpisaniu w google <i>arrow canvas javascript</i> mamy ten link :
<div>
<a href="http://stackoverflow.com/questions/808826/draw-arrow-on-canvas-tag">Już ktoś to zrobił na Stacku</a>
</div>
</p>
<p>
I na przykład tak to wygląda w javascript (kim czym - jawaskrypcie?)
</p>
<pre style="background:#2a211c;color:#bdae9d"><span style="color:#06f;font-style:italic">//Javascript</span>
<span style="color:#43a8ed;font-weight:700">function</span> <span style="color:#ff9358;font-weight:700">canvas_arrow</span>(context, fromx, fromy, tox, toy){
<span style="color:#43a8ed;font-weight:700">var</span> headlen <span style="color:#687687">=</span> <span style="color:#44aa43">10</span>; <span style="color:#06f;font-style:italic">// length of head in pixels</span>
<span style="color:#43a8ed;font-weight:700">var</span> angle <span style="color:#687687">=</span> <span style="color:#6d79de;font-weight:700">Math</span>.<span style="color:#7290d9;font-weight:700">atan2</span>(toy<span style="color:#687687">-</span>fromy,tox<span style="color:#687687">-</span>fromx);
context.<span style="color:#7290d9;font-weight:700">moveTo</span>(fromx, fromy);
context.lineTo(tox, toy);
context.lineTo(tox<span style="color:#687687">-</span>headlen<span style="color:#687687">*</span><span style="color:#6d79de;font-weight:700">Math</span>.<span style="color:#7290d9;font-weight:700">cos</span>(angle<span style="color:#687687">-</span><span style="color:#6d79de;font-weight:700">Math</span>.<span style="color:#00af0e;font-weight:700">PI</span>/<span style="color:#44aa43">6</span>),
toy<span style="color:#687687">-</span>headlen<span style="color:#687687">*</span><span style="color:#6d79de;font-weight:700">Math</span>.<span style="color:#7290d9;font-weight:700">sin</span>(angle<span style="color:#687687">-</span><span style="color:#6d79de;font-weight:700">Math</span>.<span style="color:#00af0e;font-weight:700">PI</span>/<span style="color:#44aa43">6</span>));
context.<span style="color:#7290d9;font-weight:700">moveTo</span>(tox, toy);
context.lineTo(tox<span style="color:#687687">-</span>headlen<span style="color:#687687">*</span><span style="color:#6d79de;font-weight:700">Math</span>.<span style="color:#7290d9;font-weight:700">cos</span>(angle<span style="color:#687687">+</span><span style="color:#6d79de;font-weight:700">Math</span>.<span style="color:#00af0e;font-weight:700">PI</span>/<span style="color:#44aa43">6</span>),
toy<span style="color:#687687">-</span>headlen<span style="color:#687687">*</span><span style="color:#6d79de;font-weight:700">Math</span>.<span style="color:#7290d9;font-weight:700">sin</span>(angle<span style="color:#687687">+</span><span style="color:#6d79de;font-weight:700">Math</span>.<span style="color:#00af0e;font-weight:700">PI</span>/<span style="color:#44aa43">6</span>));
}
</pre>
<p>
i naprawdę niewiele trzeba by ten kod zadziałał w Scala.js
</p>
<pre style="background:#2a211c;color:#bdae9d"><span style="color:#06f;font-style:italic">// Scala.js</span>
<span style="color:#43a8ed;font-weight:700">def</span> <span style="color:#ff9358;font-weight:700">canvas_arrow</span>(fromx:<span style="color:#43a8ed;font-weight:700">Int</span>, fromy:<span style="color:#43a8ed;font-weight:700">Int</span>, tox:<span style="color:#43a8ed;font-weight:700">Int</span>, toy:<span style="color:#43a8ed;font-weight:700">Int</span>){
<span style="color:#43a8ed;font-weight:700">val</span> headlen = <span style="color:#44aa43">10</span> <span style="color:#06f;font-style:italic">// length of head in pixels</span>
<span style="color:#43a8ed;font-weight:700">val</span> angle = Math.atan2(toy-fromy,tox-fromx)
ctx.moveTo(fromx, fromy)
ctx.lineTo(tox, toy)
ctx.lineTo(tox-headlen*Math.cos(angle-Math.PI/<span style="color:#44aa43">6</span>),
toy-headlen*Math.sin(angle-Math.PI/<span style="color:#44aa43">6</span>))
ctx.moveTo(tox, toy)
ctx.lineTo(tox-headlen*Math.cos(angle+Math.PI/<span style="color:#44aa43">6</span>),
toy-headlen*Math.sin(angle+Math.PI/<span style="color:#44aa43">6</span>))
}
</pre>
<h1> Jestem w DOMu</h1>
<p>
Generalnie jedyna niedogodność do jakiej można się doczepić, to że używając "zwykłego DOM" pobieramy generyczne elementy HTML, które trzeba mapowac na konkretne Typy
</p>
<pre style="background:#2a211c;color:#bdae9d"><span style="color:#06f;font-style:italic">//Scala.js</span>
<span style="color:#06f;font-style:italic">//jest troche więcej rzutowania przy pobieraniu elementów</span>
<span style="color:#43a8ed;font-weight:700">val</span> canvas=document.getElementById(<span style="color:#049b0a">"canvas"</span>).asInstanceOf[Canvas]
<span style="color:#43a8ed;font-weight:700">val</span> context=canvas.getContext(<span style="color:#049b0a">"2d"</span>).asInstanceOf[dom.CanvasRenderingContext2D]
<span style="color:#06f;font-style:italic">//ale dalej jest już w zasadzie to samo</span>
context.fillStyle=<span style="color:#049b0a">"#FF0000"</span>
context.fillRect(<span style="color:#44aa43">0</span>,<span style="color:#44aa43">0</span>,<span style="color:#44aa43">150</span>,<span style="color:#44aa43">75</span>)
</pre>
<p>
Ktoś przyzwyczajony do Javascript może narzekać, że to jakiś dodatkowy wysiłek ale to jest inwestycja, która zwraca się w dalszej części pracy z tymi elementami kiedy zabezpieczają nas te właśnie typy typy. (No chyba, że ktoś źle zrzutuje wtedy boli)
</p>
<pre style="background:#2a211c;color:#bdae9d"><span style="color:#06f;font-style:italic">//Javascript </span>
<span style="color:#43a8ed;font-weight:700">var</span> canvas <span style="color:#687687">=</span> <span style="color:#6d79de;font-weight:700">document</span>.<span style="color:#7290d9;font-weight:700">getElementById</span>(<span style="color:#049b0a">"myCanvas"</span>);
<span style="color:#43a8ed;font-weight:700">var</span> ctx <span style="color:#687687">=</span> canvas.getContext(<span style="color:#049b0a">"2d"</span>);
ctx.fillStyle <span style="color:#687687">=</span> <span style="color:#049b0a">"#FF0000"</span>;
ctx.fillRect(<span style="color:#44aa43">0</span>,<span style="color:#44aa43">0</span>,<span style="color:#44aa43">150</span>,<span style="color:#44aa43">75</span>);
</pre>
<p>Generalnie można pisać w Scala.js korzystając z dokumentacji do javascript. Ot choćby mechanizmy z tej stronki działają w Scali jak najbardziej : <a href="http://www.w3schools.com/html/html5_canvas.asp">http://www.w3schools.com/html/html5_canvas.asp</a></p>
<h1>Troski o jednostki</h1>
<p>
Na razie Scala.js goni javascript ale czy może zaoferować coś czego tam nie ma? (ewentualnie jest ale ja nie wiem, że jest). Otóż jak już ogarniemy przyciski i inputy to jest pewien problem poniżej bo trzeba nam np. wyliczyć masę ze wzoru <b>m=ρ * (4/3) * π * r<sup>3</sup></b> gdzie <i>ρ - to gęstość</i>. I teraz weź to wszystko licz przy pomocy double gdy gęstość to <b>g/cm<sup>3</sup></b> a promień jest w metrach. Czy też licz drogę w kilometrach gdy prędkość <b>metr/sekunda</b> a czas symulacji jest w milisekundach by się to jakoś odświeżało.
</p>
<p>
I w scali np moge stworzyć sobie odpowiednie typy, które będą kontrolowały jednostki. To poniżej nie jest jakimś szczytem modelowania domenowego bo <b>Centy,Mili,Kilo</b> trzeba powtarzać dla każdej jednostki ale generalnie chodzi o eksperyment jak to się sprawdzi w Scala.js (No i dla porównania zmienię formatowanie kodu bo nie mogę się zdecydować czy lepsze jest jaśniejsze czy ciemniejsze.)
</p>
<pre style="background:#eee;color:#3b3b3b"><span style="color:#069;font-weight:700">object</span> Distance{
<span style="color:#069;font-weight:700">case</span> <span style="color:#069;font-weight:700">class</span> Centimeter(v:<span style="color:#ff5600">Double</span>) <span style="color:#069;font-weight:700">extends</span> AnyVal {
<span style="color:#069;font-weight:700">def</span> <span style="color:#21439c">meters</span> = Meter(v/<span style="color:#a8017e">100</span>)
}
<span style="color:#069;font-weight:700">case</span> <span style="color:#069;font-weight:700">class</span> Meter(v:<span style="color:#ff5600">Double</span>) <span style="color:#069;font-weight:700">extends</span> AnyVal{
<span style="color:#069;font-weight:700">def</span> <span style="color:#21439c">centimeters</span>=Centimeter(v*<span style="color:#a8017e">100.0</span>)
}
<span style="color:#069;font-weight:700">case</span> <span style="color:#069;font-weight:700">class</span> KiloMeter(v:<span style="color:#ff5600">Double</span>) <span style="color:#069;font-weight:700">extends</span> AnyVal{
<span style="color:#069;font-weight:700">def</span> <span style="color:#21439c">meters</span>=Meter(v*<span style="color:#a8017e">1000.0</span>)
}
<span style="color:#ff5600">implicit</span> <span style="color:#069;font-weight:700">def</span> <span style="color:#21439c">meterToDouble</span>(m:Meter):<span style="color:#ff5600">Double</span>=m.v
}
</pre>
<p>
Pierwsza rzecz to kontrola przy liczeniu objętości kuli. Chcemy utrzymać czyste jednostki bez żadnego przedrostka.
</p>
<pre style="background:#eee;color:#3b3b3b"><span style="color:#069;font-weight:700">case</span> <span style="color:#069;font-weight:700">class</span> Volume(v:<span style="color:#ff5600">Double</span>) <span style="color:#069;font-weight:700">extends</span> AnyVal
<span style="color:#069;font-weight:700">def</span> <span style="color:#21439c">sphereVolume</span>(r:Meter):Volume=Volume(<span style="color:#a8017e">4.0</span>/<span style="color:#a8017e">3.0</span> * PI * pow(r,<span style="color:#a8017e">3.0</span>))
</pre>
<p>
No i drogi czytelniku/czytelniczko mam nadzieję, że zauważyłeś/aś tam ciekawą rzecz, że podajemy bezpośrednio promień który przecież jest typu <i>"Meter"</i> do <i>Math.pow</i>. A to dlatego, że zaimportowaliśmy konwersję z modułu Distance
</p>
<pre style="background:#eee;color:#3b3b3b"><span style="color:#ff5600">implicit</span> <span style="color:#069;font-weight:700">def</span> <span style="color:#21439c">meterToDouble</span>(m:Meter):<span style="color:#ff5600">Double</span>=m.v
</pre>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCdhZGgqAeeAuDyXEna8dClwsLuL9tU-JJecZED12zIZeUp9GMedl7OzPQony6hmN_0L9YKyWxB-iZrrOHNiFr1fVU2OEnd3UKYppKZPCVl2vtBZ0WCQk8j4zkN_Ci6GniuuFzU2htttY/s1600/pass.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCdhZGgqAeeAuDyXEna8dClwsLuL9tU-JJecZED12zIZeUp9GMedl7OzPQony6hmN_0L9YKyWxB-iZrrOHNiFr1fVU2OEnd3UKYppKZPCVl2vtBZ0WCQk8j4zkN_Ci6GniuuFzU2htttY/s200/pass.png" width="100" height="100" /></a></div>
<p>No i jeszcze jedna rzecz - AnyVal. W Scali kompilator rozpakuje prymitywa i w runtime nie ma żadnego narzutu a w trakcie kompilacji typy zabezpieczają. (to tak jak wypić wódkę i mieć wódkę czy coś takiego)
</p>
<p>
No i z tego kodu już po kompilacji do js wynika, że to też działa bo bez AnyVal jest wersja gdzie wartość z promienia trzeba dopiero wydobyć (czyli to tak jak mieć ciastko i zjeść ciastko albo tak jak nie płacić abonamentu a i tak oglądać telewizję).
</p>
<pre style="background:#eee;color:#3b3b3b"><span style="color:#af82d4">//Z valueclass</span>
<span style="color:#a535ae">$c_Lcom_wlodar_physics_Geometry$</span>.<span style="color:#b7734c">prototype</span>.<span style="color:#21439c">sphereVolume__D__D</span> <span style="color:#069;font-weight:700">=</span> (function(r) {
<span style="color:#069;font-weight:700">return</span> (<span style="color:#a8017e">4.1887902047863905</span> <span style="color:#069;font-weight:700">*</span> <span style="color:#069;font-weight:700">$</span>uD(<span style="color:#069;font-weight:700">$</span>g.<span style="color:#a535ae">Math</span>.<span style="color:#45ae34;font-weight:700">pow</span>(r, <span style="color:#a8017e">3.0</span>)))
});
<span style="color:#af82d4">//bez value class</span>
<span style="color:#a535ae">$c_Lcom_wlodar_physics_Geometry$</span>.<span style="color:#b7734c">prototype</span>.<span style="color:#21439c">sphereVolume__Lcom_wlodar_physics_Distance$Meter__D</span> <span style="color:#069;font-weight:700">=</span> (function(r) {
<span style="color:#ff5600">var</span> a <span style="color:#069;font-weight:700">=</span> r.v<span style="color:#069;font-weight:700">$</span><span style="color:#a8017e">1</span>;
<span style="color:#069;font-weight:700">return</span> (<span style="color:#a8017e">4.1887902047863905</span> <span style="color:#069;font-weight:700">*</span> <span style="color:#069;font-weight:700">$</span>uD(<span style="color:#069;font-weight:700">$</span>g.<span style="color:#a535ae">Math</span>.<span style="color:#45ae34;font-weight:700">pow</span>(a, <span style="color:#a8017e">3.0</span>)))
});
</pre>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPcid8eoTnveDj2a9eRVHTxcjVY4iiXAzqhSH2F2j3v1mnN1pdjR8KrROFgReeMne4UWq4uhYzbkp8WfwXlnM-YMnSzqCj9usJwrruKnfZPJiEUYc7xzpDrn9VAzw8inTOn6ClL0ASxv4/s1600/pass.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPcid8eoTnveDj2a9eRVHTxcjVY4iiXAzqhSH2F2j3v1mnN1pdjR8KrROFgReeMne4UWq4uhYzbkp8WfwXlnM-YMnSzqCj9usJwrruKnfZPJiEUYc7xzpDrn9VAzw8inTOn6ClL0ASxv4/s200/pass.png" width="100" height="100" /></a></div>
<h1>Rzeczy nowe </h1>
<p class="akapit">
Przy okazji takiego programu pojawia się kilka ciekawych wyzwań, których w zwykłych CRUDach nie ma. No bo tam jest taki stan, który wydaje sie wygodny czyli np. aktualne położenie kulki i jakoś monady mnie się tu nie widzą. Można by zawczasu "obliczyć" sumylację i później ją odpalić wtedy niejako kolejne klatki byłyby kolejną wersją niemutowalnego stanu na stosie czy czymś takim i w sumie tak historia ruchu (te czerwone kropki) jest wyliczana.
</p>
<p>
Ale z drugiej strony na courserze przy okazji zeszłorocznego kursu o Reactive Application było coś o sygnałach i "Functional Reactive Programming". Także też ciekawe.
</p>
<h1>Testowanie</h1>
<p class="akapit">
Tę część z jednostkami to nawet i zwykłym ScalaTestem da się pojechać bo to zwykła taka Scala-Scala. Można Scalachecka użyć do Property Based Testing no i są specjalne narzędzia które testy tłumacza na javascript i odpalają je już na takim "RuntimeDom"
</p>
<h1>Kulka</h1>
<p>
Jest pod adresem : <br/><br/>
<a href="https://dl.dropboxusercontent.com/u/102254064/gravity.html">adres kulki</a>.
<br/><br/>Niestety jak wstawiłem iframe to blogger mi powiedział, że nie ma tego ficzeru. Generalnie chyba najfajniej wygląda jak wpisze się 100 w promień i 150 w prędkość poziomą. Mozna tez sobie potestować podawanie złych wartości - Try daje radę przy podawaniu liter zamiast cyfr a dalej już nie testowałem.
</p>
<p>
Jak na kogoś kto ostatni raz javascripta robił w 2013 i teraz taka kulka... no czuję się taki szcześliwy...
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmDCUTjJOkUNbMyQmaI5Cya_EoIf9OEXWYGyV_TW1d3dtr1mY5kiG-_5ZFbmw7PIhEKYUPTVtaHuEM6Kks077rMl0mxUa8H0TE-3xMGapNnbe4_pGIxJlQcXGoKem1DdP55RoS-HsLV1c/s1600/wchmurach.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmDCUTjJOkUNbMyQmaI5Cya_EoIf9OEXWYGyV_TW1d3dtr1mY5kiG-_5ZFbmw7PIhEKYUPTVtaHuEM6Kks077rMl0mxUa8H0TE-3xMGapNnbe4_pGIxJlQcXGoKem1DdP55RoS-HsLV1c/s640/wchmurach.jpg" width="640" height="360" /></a></div>Paweł Włodarskihttp://www.blogger.com/profile/04891037231290616803noreply@blogger.com0tag:blogger.com,1999:blog-5047632037494901372.post-63725341510635813382016-08-04T17:12:00.001+02:002016-08-04T17:12:40.351+02:00I nawet dla ciebie jest nadzieja w webie<p class="akapit">
Już na samym początku - aby uniknąć niepotrzebnych dyskusji o tym, który młotek jest najlepszy - przywołamy magiczne słowo "warunkowe".
Z matematki taki zapis : <b>P(B|A)=...</b> , określa, że będziemy liczyć wystąpienie prawdopodobieństwa B pod warunkiem, że zaszło zdarzenie A. I dalej idąc w bardzo luźną analogie rozpatrzymy dzisiaj sytuację : <b>U(scala.js|scala)</b> czyli
<pre>
U - szansa, że uda ci się coś zrobić w scala.js jeśli już robisz w scali
i nie masz czasu co trzy godziny uczyć się nowego frameworka javascriptowego.
</pre>
</p>
<h1>Czas i (mała) przestrzeń </h1>
<p>
Czasem w niektórych firmach istnieje niewidzialny klej, który przytwierdza ludzi do jednego projektu na całe ich życie (a w kontrakcie jest zapisane, że po śmierci ich prace będą kontynuować ich dzieci bo nikt inny nie skuma tego kodu). Często poletko, którym się zajmują ma 1 metr kwadratowy i pomija wiele ciekawych aspektów programowania. I tak jak ktoś bijący się z przeglądarką może znać wątki ale tylko te z mody na sukces. A ktoś działający na back-endzie widzi javascript jako doskonałe narzędzie do wyświetlania alertów.
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDf7uSSnaGLxeOzYRoiYM_Cy5Tlhjmbs3z6xwrF2IkCobqk4DAJSXvnNMW6OvRvF3DWHw9S40t1r-Yt7yF15vlRHQB14Yn01Uj_jp22f7SoFzmsSdfQKlKKyMLlA0P4mFrkpen8f9xKEs/s1600/Time_Chamber.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDf7uSSnaGLxeOzYRoiYM_Cy5Tlhjmbs3z6xwrF2IkCobqk4DAJSXvnNMW6OvRvF3DWHw9S40t1r-Yt7yF15vlRHQB14Yn01Uj_jp22f7SoFzmsSdfQKlKKyMLlA0P4mFrkpen8f9xKEs/s400/Time_Chamber.jpg" width="400" height="224" /></a></div>
<p>
Ponieważ sam ostatnie półtora roku miałem takie, że główny kontakt z webem był gdy dokumentacje do sparka otwierałem w przeglądarce także jeśli istnieje szansa na robienie weba przy pomocy ekosystemu, który jako tako znam to zamiast ogarniać całą osobną gałąź przemysłu od początku (jakieś grunty srunty) to takiej możliwości warto się przyjrzeć.
</p>
<p>
To nie jest tutorial bo tutorial już jest : <a href="http://www.lihaoyi.com/hands-on-scala-js/">http://www.lihaoyi.com/hands-on-scala-js/</a>. Chodzi bardziej o wrażenia. Wrażenia i odczucia a może nawet i uczucia. To nieprawda, że programiści nie mają uczuć. ja np. często czuję, że coś nie zadziała.
</p>
<h1>robić Łeba </h1>
<p class="akapit">
Bardzo dobry tutorial na wstęp jest tutaj : <a href="https://www.scala-js.org/tutorial/basic/">https://www.scala-js.org/tutorial/basic/</a> i jak to tutorial - działa dopóki robi się wszystko według tutoriala. Ale warto trochę zbaczać i psuć bo wtedy można zrozumieć to co się robi w szerszym kontekście.
</p>
<p>
Ten tutorial tworzy prostą stronkę z javascriptem. Może i warto na początek za dużo nie kombinować i go po prostu zrobić ale dalszą ciekawsza wariacją będzie próba takiego para-produkcyjnego użycia <i>scala.js</i> w aplikacji webowej. Do tworzenia <b>war</b>a użyjemy <a href="http://scalatra.org/">scalatry</a>. Scalatra jest bardzo przyjemnym narzędziem bo już chyba ku*wa prostszego frameworku do tworzenia aplikacji webowej wymyślić nie można.
</p>
<p>Dodatkowy zysk edukacyjny pracy na scalatrze jest taki, że łatwiej zrozumieć jak współdziałają te wszystkie pluginy SBT. W Playu wszystko jest takie od razu scalone - "which is good" - ale można przez tę fasadę nie dojrzeć wielu szczegółów. </p>
<p>
Scala.js ma swój plugin, który kompiluje do "targetu" a Scalatra siedzi na XSBT-WEB, który zbiera javascript z katalogu "src/main/webapp". Jest kilka szablonów na necie, które pokazują jak zgrać prawidłowo te dwa narzędzia (na przykład : <a href="https://github.com/takezoe/scalatra-scalajs-template"></a>) zazwyczaj w postaci dwóch niezależnych modułów.
</p>
<p>
Na potrzeby bloga wybiorę prostsze podejście czyli kopiowanie plików na pałę.
</p>
<pre style="background:#2a211c;color:#bdae9d"><span style="color:#43a8ed;font-weight:700">val</span> kopiujNaPałę<span style="font-style:italic">Javascript</span>: TaskKey[<span style="color:#43a8ed;font-weight:700">String</span>] =taskKey[<span style="color:#43a8ed;font-weight:700">String</span>](<span style="color:#049b0a">"compileJavascript"</span>)
kopiujNaPałęJavascript := {
<span style="color:#43a8ed;font-weight:700">val</span> jsHome = sourceDirectory.value / <span style="color:#049b0a">"main"</span> / <span style="color:#049b0a">"webapp"</span> / <span style="color:#049b0a">"js"</span>
<span style="color:#43a8ed;font-weight:700">val</span> dependenciesFileName = <span style="color:#049b0a">"scalatra-js-jsdeps.js"</span>
<span style="color:#43a8ed;font-weight:700">val</span> generatedFile: File =(fastOptJS in Compile).value.data
<span style="color:#43a8ed;font-weight:700">val</span> generatedDepFile=<span style="color:#43a8ed;font-weight:700">new</span> File(generatedFile.getParent,dependenciesFileName)
<span style="color:#43a8ed;font-weight:700">val</span> destinationFile = jsHome / generatedFile.getName
<span style="color:#43a8ed;font-weight:700">val</span> dependenciesFile = jsHome / dependenciesFileName
IO.copyFile(generatedFile,destinationFile)
IO.copyFile(generatedDepFile,dependenciesFile)
jsHome.getAbsolutePath
}
</pre>
<p>
<i>"scalatra-js-jsdeps.js"</i> to plik z wszyskimi zależnościami takimi jak <b>jquery</b>. A no bo właśnie - można sobie zainstalować fasadę na jquery i mieć takie "w-pół" statyczne typowanie w tym jakże wygodnym frameworku.
</p>
<pre style="background:#2a211c;color:#bdae9d">jQuery(<span style="color:#049b0a">"#demoButton"</span>).click(processInput _)
<span style="color:#43a8ed;font-weight:700">def</span> <span style="color:#ff9358;font-weight:700">processInput</span>():<span style="color:#43a8ed;font-weight:700">Unit</span>={
....
}
</pre>
<p>No i to też się do testowania przyda później. Apropo JQuery to jeszcze taka dygresja</p>
<div style="border:1px dotted black;padding:10px;background-color:#f2f2f2">
<h2>Dygresja o rzeczach niefizycznych</h2>
<p>
W arcy ciekawej książce <a href="https://en.wikipedia.org/wiki/Antifragile">Antifragile</a> Nicholas Taleb opisuje koncepcję żywotności rzeczy niematerialnych, która wybiega trochę na przeciw naszej intuicji. Dzieje się tak gdyż w przypadku rzeczy materialnych im dłużej dana rzecz istnieje tym prawdopodobnie będzie istnieć krócej. I tak np. mamy 1 letni i 10 letni samochód tej samej marki - intuicja nam podpowiada, że - wyłączając zdarzenia losowe - ten starszy szybciej pójdzie na złom.
</p>
<p>
Teraz weźmy rzecz niematerialną jak choćby język programowania. Mamy dwa języki - jeden wydany rok temu a drugi przed 10ciu laty. Pytanie, który wcześniej się rozpłynie w nicości. No i tutaj może być trudniej to ogarnąć bo generalnie język jako koncept nie rdzewieje, nie wpieprzają go korniki ani nic takiego. żywotność konceptu jest zależna tylko od nośnika i jeśli jakieś nośniki od 10 lat przenoszą ten koncept to oznacza, że z jakiegoś powodu wygrał w ruletce "selekcji naturalnej" języków programowania. A ten co ma rok czy nawet miesiąc - nie wiadomo.
</p>
<p>
No i mamy takie JQuery, które już ma 10 latek i przetrwało selekcje a 10 lat temu był w użyciu też inny wynalazek - <a href="https://en.wikipedia.org/wiki/Prototype_JavaScript_Framework">prototype.js</a>. Na przełomie 2006/2007 był jednym z niewielu szczepionek na popularną w webdeveloperce chorobę zwaną IE6 (gimby nie znajo i ich kurwa szczęście...). A teraz według wiki używa go 2,2% stron czyli pewnie twórca, jego sąsiad i kilka korpo z miód-maintenecem. Na wiki możecie sobie poczytać co poszło nie tak.
</p>
<p>
Także jak z dnia na dzień zobaczysz jakiś super nowy hiper frejmowrk weź wdech, dokończ robote i w wolnej chwili na spokojnie się temu przyjrzysz.
</p>
</div>
<h1>Moje pole</h1>
<iframe width="420" height="315" src="https://www.youtube.com/embed/UvRsDiOFdzA" frameborder="0" allowfullscreen></iframe>
<p>
Celem laboratorium będzie walidacja jednego pola po stronie klienta, wysłanie go na serwer , ponowna validacja i odesłanie jakiejś odpowiedzi.
</p>
<p>
Nie ma sensu wklejać całego kodu bo to luźno zwisający HTML i kilka instrukcji scali także skoncentrujemy się na najważniejszych fragmentach. No i tak na poniższym wycinku rejestrujemy "onklika" , po którym zgarniemy wartość z pola i przy pomocy scalowego (a jakże) pattern matchingu sparsujemy wartość i podążymy jedną z dwóch ścieżek : błędu lub szczęścia.
</p>
<pre style="background:#2a211c;color:#bdae9d">
jQuery(<span style="color:#049b0a">"#demoButton"</span>).click(processInput _)
<span style="color:#43a8ed;font-weight:700">def</span> <span style="color:#ff9358;font-weight:700">processInput</span>():<span style="color:#43a8ed;font-weight:700">Unit</span>={
jQuery(<span style="color:#049b0a">"#wynik"</span>).remove()
<span style="color:#43a8ed;font-weight:700">val</span> mojePole: Dynamic =jQuery(<span style="color:#049b0a">"#mojePole"</span>).value()
Try(mojePole.toString.trim.toInt) <span style="color:#43a8ed;font-weight:700">match</span> {
<span style="color:#43a8ed;font-weight:700">case</span> Success(v) => validInput(v)
<span style="color:#43a8ed;font-weight:700">case</span> Failure(e) => wrongInput(e)
}
}
</pre>
<p>
Jak sie popsuło to będzie na czerwono :
</p>
<pre style="background:#2a211c;color:#bdae9d"> <span style="color:#43a8ed;font-weight:700">def</span> <span style="color:#ff9358;font-weight:700">wrongInput</span>(<span style="font-style:italic">e</span>: Throwable)= {
jQuery(<span style="color:#049b0a">"body"</span>).prepend(s<span style="color:#049b0a">"""
|<div class="alert alert-danger" role="alert" id="wynik">ERROR : ${e}</div>
"""</span>.stripMargin)
}
</pre>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihM7HYqdh0T6jZmuVSIJ6IwiUQGFsexq_6Cy8T5aLwPF4WH67CA3S5aWv3NpIr3bKyaiDpLV17gK8Lq3Zbcwe459kedofCZwprcF_hxBPoBLlT-mTi1PCP3rydpvxzC5Iv4Q6UYEqNWfs/s1600/zle.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihM7HYqdh0T6jZmuVSIJ6IwiUQGFsexq_6Cy8T5aLwPF4WH67CA3S5aWv3NpIr3bKyaiDpLV17gK8Lq3Zbcwe459kedofCZwprcF_hxBPoBLlT-mTi1PCP3rydpvxzC5Iv4Q6UYEqNWfs/s640/zle.jpg" width="640" height="211" /></a></div>
<h2>Do serwera</h2>
<p>
I oto dwa kawałki kodu napisane w jednym i tym samym silnie typowanym języku siedzące w dwóch różnych miejscach internetu (w teorii bo w praktyce w tym przykładzie oba są na moim kompie) komunikują się ze sobą!
</p>
<pre style="background:#2a211c;color:#bdae9d"><span style="color:#06f;font-style:italic">//scala.js - browser</span>
Ajax.post(s<span style="color:#049b0a">"/validate?value=$v"</span>).onComplete{
<span style="color:#43a8ed;font-weight:700">case</span> Success(xhr) => prependResponse(xhr.responseText)
<span style="color:#43a8ed;font-weight:700">case</span> Failure(e) => prependResponse(s<span style="color:#049b0a">"zjebało się : $e"</span>)
}
<span style="color:#06f;font-style:italic">//scalatra-serwer</span>
post(<span style="color:#049b0a">"/validate"</span>){
Try(params(<span style="color:#049b0a">"value"</span>)).map(v=>
Ok(s<span style="color:#049b0a">"z serwera $v"</span>)
) getOrElse halt(BadRequest()) <span style="color:#06f;font-style:italic">//400</span>
}
</pre>
<p>
Scalatra jak mówiłem prosta i przyjemna także taki prosty kodzik obsługuje post. No i wynik :
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJr7fsj8D7wF1QIlkjjHmwLB86F_L_vFQYWyIzSSmmzaFmswZ3Qocu3fcZb6swJNqFWZTu20d5D-XoFJCt8h-fMr-4Wu3hHQ3ihCWYg6wb2HsE1HLww6Yz4KHHtZLbsqfBwork1U2W_ek/s1600/zserwera.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJr7fsj8D7wF1QIlkjjHmwLB86F_L_vFQYWyIzSSmmzaFmswZ3Qocu3fcZb6swJNqFWZTu20d5D-XoFJCt8h-fMr-4Wu3hHQ3ihCWYg6wb2HsE1HLww6Yz4KHHtZLbsqfBwork1U2W_ek/s640/zserwera.jpg" width="640" height="189" /></a></div>
<h2>I działa </h2>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVvxJ1xBmIHN5GeooUvnY9_K9qQs1MDC5lSg3jfK0aDJ6EA_BiOuoEMZFnVzuHyJvY9MzPrsHpRneDayFIW3pwDdQ3Ok8BC8PJ1CMkIUeTS_EZO5GAL1FsyPS-y31_5cyN0Ovz-20uMmk/s1600/yeeeeeeeeeaaaaaaaaa.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVvxJ1xBmIHN5GeooUvnY9_K9qQs1MDC5lSg3jfK0aDJ6EA_BiOuoEMZFnVzuHyJvY9MzPrsHpRneDayFIW3pwDdQ3Ok8BC8PJ1CMkIUeTS_EZO5GAL1FsyPS-y31_5cyN0Ovz-20uMmk/s400/yeeeeeeeeeaaaaaaaaa.gif" width="400" height="299" /></a></div>
<h1>Błędy w runtime</h1>
<p>
W runtime działa już sobie javascript, który w teorii powinien być dobry jeśli tylko został wygenerowany z kompilującej się scali (plus pewnie bliżej nieokreślone N nieprzewidzianych bugów). Natomiast nic się nie dzieje gdy wyszukuję nieistniejący element na stronie i coś tam działam - w sensie nie dzieje się na chromie bo w testach ładnie się wywala. A testy pisze się np. w tym : <a href="https://github.com/lihaoyi/utest">https://github.com/lihaoyi/utest</a> czyli narzędzia są.
</p>
<p>
Wygląda obiecująco
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWHmItvFeGvZUbNMfRjTjRRH5wVhbnXAfmBOtwFZXK49yZ9clsZeqTzqJ0je4SDuuAjRVmW3douOEcCQk4lhG8znX4fWo8F5T7C2eZw4EaHKnvQl666SgYkZ5i8k4CuRllig0i1X6tVcQ/s1600/ostry_rochacz.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWHmItvFeGvZUbNMfRjTjRRH5wVhbnXAfmBOtwFZXK49yZ9clsZeqTzqJ0je4SDuuAjRVmW3douOEcCQk4lhG8znX4fWo8F5T7C2eZw4EaHKnvQl666SgYkZ5i8k4CuRllig0i1X6tVcQ/s640/ostry_rochacz.jpg" width="640" height="360" /></a></div>
Paweł Włodarskihttp://www.blogger.com/profile/04891037231290616803noreply@blogger.com0tag:blogger.com,1999:blog-5047632037494901372.post-25414873932059516062016-07-28T15:23:00.000+02:002016-07-28T15:23:17.718+02:00Scala 2.12 - laborki
<p class="akapit">
Scala 2.12 ma wyjść jakoś już zaraz niedługo niebawem i jak tu nie lepiej posprawdzać co nas czeka jak nie pokompilować sobie próbek kodu. Tak jak na laborkach w technikum. Tyle, że tam sprawozdanie było od razu gotowe, wnioski spisane i w zasadzie mierzyło się do czasu aż wykres namalował się zgodnie z oczekiwaniem. A tak to w zasadzie podobnie.
</p>
<p>
Sprawdzimy faktycznie co się dzieje kompilując sobie scalę <b>2.12-M5</b> , którą to wersję można sobie ściągnąć tutaj --> <a href="http://www.scala-lang.org/download/2.12.0-M5.html">http://www.scala-lang.org/download/2.12.0-M5.html</a> oraz <b>javap</b> i innych takich narzędzi do roz-kompilowywania kodu.
</p>
<h1> Świat po kompilacji - Prosta Klasa z Funkcją </h1>
<p>
Według zapowiedzi kod ma być kompilowany do BAJTkodu javy 8 czyli funkcje już nie powinny zamieniać się w klasy anonimowe.
</p>
<h3>Mamy taki prosty kod w Scali</h3>
<pre style="background:#2a211c;color:#bdae9d"><span style="color:#43a8ed;font-weight:700">class</span> Lib{
<span style="color:#43a8ed;font-weight:700">val</span> fun:<span style="color:#43a8ed;font-weight:700">Int</span>=><span style="color:#43a8ed;font-weight:700">Int</span>=_+<span style="color:#44aa43">1</span>
}
</pre>
<h3>Scala 2.11</h3>
<p>Po kompilacji mamy takie oto wygenerowane pliki.Uwagę zapewne przyciąga to takie długie coś - o tym za chwilkę</p>
<pre style="background:#2a211c;color:#bdae9d">ls
Lib<span style="color:#318495">$$</span>anonfun<span style="color:#318495">$1</span>.class Lib.class lib.scala
</pre>
<b>Najpierw : <i>Lib.class</i> - tutaj w sumie nic nadzwyczajnego.</b>
<pre style="background:#2a211c;color:#bdae9d">javap -private Lib.class
Compiled from <span style="color:#049b0a">"lib.scala"</span>
public class Lib {
private final scala.Function<span style="color:#43a8ed;font-weight:700">1<</span>java.lang.Object, java.lang.Object<span style="color:#43a8ed;font-weight:700">></span> fun<span style="color:#43a8ed;font-weight:700">;</span>
public scala.Function<span style="color:#43a8ed;font-weight:700">1<</span>java.lang.Object, java.lang.Object<span style="color:#43a8ed;font-weight:700">></span> <span style="color:#ff9358;font-weight:700">fun</span>();
public <span style="color:#ff9358;font-weight:700">Lib</span>();
}
</pre>
<p>
Scala 2.11 kompiluje się do bytecodu Javy 6 a jako, że w Javie 6 lambd nie ma to mamy dodatkowa tę oto wcześniej wspomnianą dziwną klasę
</p>
<i>Lib$$anonfun$1.class</i>
<pre style="background:#2a211c;color:#bdae9d">javap Lib<span style="color:#2fe420">\$</span><span style="color:#2fe420">\$</span>anonfun<span style="color:#2fe420">\$</span>1.class
Compiled from <span style="color:#049b0a">"lib.scala"</span>
public final class Lib<span style="color:#318495">$$</span>anonfun<span style="color:#318495">$1</span> extends scala.runtime.AbstractFunction1<span style="color:#318495">$mcII</span><span style="color:#318495">$sp</span> implements scala.Serializable {
public static final long serialVersionUID<span style="color:#43a8ed;font-weight:700">;</span>
public final int apply(int)<span style="color:#43a8ed;font-weight:700">;</span>
public int apply<span style="color:#318495">$mcII</span><span style="color:#318495">$sp</span>(int)<span style="color:#43a8ed;font-weight:700">;</span>
public final java.lang.Object apply(java.lang.Object)<span style="color:#43a8ed;font-weight:700">;</span>
public Lib<span style="color:#318495">$$</span>anonfun<span style="color:#318495">$1</span>(Lib)<span style="color:#43a8ed;font-weight:700">;</span>
}
</pre>
<p>
Przykład jest prosty i dostaliśmy tylko jedną anonimową klasę ale jak polecimy z nim trochę dalej i trochę mocniej
</p>
<pre style="background:#2a211c;color:#bdae9d"><span style="color:#43a8ed;font-weight:700">class</span> Lib{
<span style="color:#43a8ed;font-weight:700">val</span> fun:<span style="color:#43a8ed;font-weight:700">Int</span>=><span style="color:#43a8ed;font-weight:700">Int</span>=_+<span style="color:#44aa43">1</span>
<span style="color:#43a8ed;font-weight:700">val</span> fun2:<span style="color:#43a8ed;font-weight:700">Int</span>=><span style="color:#43a8ed;font-weight:700">Int</span>=_+<span style="color:#44aa43">1</span>
<span style="color:#43a8ed;font-weight:700">val</span> fun3:<span style="color:#43a8ed;font-weight:700">Int</span>=><span style="color:#43a8ed;font-weight:700">Int</span>=_+<span style="color:#44aa43">1</span>
<span style="color:#43a8ed;font-weight:700">val</span> fun4:<span style="color:#43a8ed;font-weight:700">Int</span>=><span style="color:#43a8ed;font-weight:700">Int</span>=_+<span style="color:#44aa43">1</span>
<span style="color:#43a8ed;font-weight:700">val</span> fun5:<span style="color:#43a8ed;font-weight:700">String</span> => BigDecimal = s => BigDecimal(s)
}
</pre>
<p>
To generuje się tego wincyj i wincyj
</p>
<pre style="background:#2a211c;color:#bdae9d">ls
Lib$$anonfun$1.class Lib$$anonfun$2.class Lib$$anonfun$3.class
Lib$$anonfun$4.class Lib$$anonfun$5.class Lib.class lib.scala
</pre>
<p>
A klasa bohaterka wygląda ostatecznie tak :
</p>
<pre style="background:#2a211c;color:#bdae9d">public class Lib {
private final scala.Function1<span style="color:#43a8ed"><<span style="font-weight:700">java</span>.lang.Object, java.lang.Object></span> fun;
private final scala.Function1<span style="color:#43a8ed"><<span style="font-weight:700">java</span>.lang.Object, java.lang.Object></span> fun2;
private final scala.Function1<span style="color:#43a8ed"><<span style="font-weight:700">java</span>.lang.Object, java.lang.Object></span> fun3;
private final scala.Function1<span style="color:#43a8ed"><<span style="font-weight:700">java</span>.lang.Object, java.lang.Object></span> fun4;
private final scala.Function1<span style="color:#43a8ed"><<span style="font-weight:700">java</span>.lang.String, scala.math.BigDecimal></span> fun5;
public scala.Function1<span style="color:#43a8ed"><<span style="font-weight:700">java</span>.lang.Object, java.lang.Object></span> fun();
public scala.Function1<span style="color:#43a8ed"><<span style="font-weight:700">java</span>.lang.Object, java.lang.Object></span> fun2();
public scala.Function1<span style="color:#43a8ed"><<span style="font-weight:700">java</span>.lang.Object, java.lang.Object></span> fun3();
public scala.Function1<span style="color:#43a8ed"><<span style="font-weight:700">java</span>.lang.Object, java.lang.Object></span> fun4();
public scala.Function1<span style="color:#43a8ed"><<span style="font-weight:700">java</span>.lang.String, scala.math.BigDecimal></span> fun5();
public Lib();
}
</pre>
<p>
No dobra ale to już pomału odchodzi w przeszłość bo oto (pamparampampam):
</p>
<h3> Scala 2.12</h3>
<p>Klas anonimowych w 2.12 nima : </p>
<pre style="background:#2a211c;color:#bdae9d">ls
Lib.class lib.scala
</pre>
<p>Klasa z funkcjami wygląda podobnie do 2.11 </p>
<pre style="background:#2a211c;color:#bdae9d"><span style="color:#43a8ed;font-weight:700">public</span> <span style="color:#43a8ed;font-weight:700">class</span> <span style="text-decoration:underline">Lib</span> {
<span style="color:#43a8ed;font-weight:700">public</span> <span style="color:#43a8ed;font-weight:700">scala.Function1<<span style="color:#43a8ed;font-weight:700">java.lang<span style="color:#43a8ed;font-weight:700">.</span>Object</span>, <span style="color:#43a8ed;font-weight:700">java.lang<span style="color:#43a8ed;font-weight:700">.</span>Object</span>></span> <span style="color:#ff9358;font-weight:700">fun</span>();
<span style="color:#43a8ed;font-weight:700">public</span> <span style="color:#43a8ed;font-weight:700">scala.Function1<<span style="color:#43a8ed;font-weight:700">java.lang<span style="color:#43a8ed;font-weight:700">.</span>Object</span>, <span style="color:#43a8ed;font-weight:700">java.lang<span style="color:#43a8ed;font-weight:700">.</span>Object</span>></span> <span style="color:#ff9358;font-weight:700">fun2</span>();
<span style="color:#43a8ed;font-weight:700">public</span> <span style="color:#43a8ed;font-weight:700">scala.Function1<<span style="color:#43a8ed;font-weight:700">java.lang<span style="color:#43a8ed;font-weight:700">.</span>Object</span>, <span style="color:#43a8ed;font-weight:700">java.lang<span style="color:#43a8ed;font-weight:700">.</span>Object</span>></span> <span style="color:#ff9358;font-weight:700">fun3</span>();
<span style="color:#43a8ed;font-weight:700">public</span> <span style="color:#43a8ed;font-weight:700">scala.Function1<<span style="color:#43a8ed;font-weight:700">java.lang<span style="color:#43a8ed;font-weight:700">.</span>Object</span>, <span style="color:#43a8ed;font-weight:700">java.lang<span style="color:#43a8ed;font-weight:700">.</span>Object</span>></span> <span style="color:#ff9358;font-weight:700">fun4</span>();
<span style="color:#43a8ed;font-weight:700">public</span> <span style="color:#43a8ed;font-weight:700">scala.Function1<<span style="color:#43a8ed;font-weight:700">java.lang<span style="color:#43a8ed;font-weight:700">.</span>String</span>, <span style="color:#43a8ed;font-weight:700">scala.math<span style="color:#43a8ed;font-weight:700">.</span>BigDecimal</span>></span> <span style="color:#ff9358;font-weight:700">fun5</span>();
<span style="color:#43a8ed;font-weight:700">public</span> <span style="color:#43a8ed;font-weight:700">static</span> <span style="color:#43a8ed;font-weight:700">final</span> int $anonfun$fun$<span style="color:#ff9358;font-weight:700">1</span>(<span style="color:#43a8ed;font-weight:700">int</span>);
<span style="color:#43a8ed;font-weight:700">public</span> <span style="color:#43a8ed;font-weight:700">static</span> <span style="color:#43a8ed;font-weight:700">final</span> int $anonfun$fun2$<span style="color:#ff9358;font-weight:700">1</span>(<span style="color:#43a8ed;font-weight:700">int</span>);
<span style="color:#43a8ed;font-weight:700">public</span> <span style="color:#43a8ed;font-weight:700">static</span> <span style="color:#43a8ed;font-weight:700">final</span> int $anonfun$fun3$<span style="color:#ff9358;font-weight:700">1</span>(<span style="color:#43a8ed;font-weight:700">int</span>);
<span style="color:#43a8ed;font-weight:700">public</span> <span style="color:#43a8ed;font-weight:700">static</span> <span style="color:#43a8ed;font-weight:700">final</span> int $anonfun$fun4$<span style="color:#ff9358;font-weight:700">1</span>(<span style="color:#43a8ed;font-weight:700">int</span>);
<span style="color:#43a8ed;font-weight:700">public</span> <span style="color:#43a8ed;font-weight:700">static</span> <span style="color:#43a8ed;font-weight:700">final</span> scala.math.BigDecimal $anonfun$fun5$<span style="color:#ff9358;font-weight:700">1</span>(<span style="color:#43a8ed;font-weight:700">java.lang<span style="color:#43a8ed;font-weight:700">.</span>String</span>);
<span style="color:#43a8ed;font-weight:700">public</span> <span style="color:#ff9358;font-weight:700">Lib</span>();
}
</pre>
<p>I to wszystko! Jak to możliwe zapytacie!?! Ano</p>
<pre style="background:#2a211c;color:#bdae9d" >javap <span style="color:#43a8ed;font-weight:700">-</span>c <span style="color:#43a8ed;font-weight:700">Lib</span><span style="color:#43a8ed;font-weight:700">.</span>class
<span style="color:#43a8ed;font-weight:700">public</span> Lib();
<span style="color:#43a8ed;font-weight:700">Code</span><span style="color:#43a8ed;font-weight:700">:</span>
<span style="color:#44aa43">0</span><span style="color:#43a8ed;font-weight:700">:</span> aload_0
<span style="color:#44aa43">1</span><span style="color:#43a8ed;font-weight:700">:</span> invokespecial #<span style="color:#44aa43">67</span> <span style="color:#06f;font-style:italic">// Method java/lang/Object."<init>":()V</span>
<span style="color:#44aa43">4</span><span style="color:#43a8ed;font-weight:700">:</span> aload_0
<span style="color:#44aa43">5</span><span style="color:#43a8ed;font-weight:700">:</span> invokedynamic #<span style="color:#44aa43">87</span>, <span style="color:#44aa43">0</span> <span style="color:#06f;font-style:italic">// InvokeDynamic #0:apply$mcII$sp:()Lscala/runtime/java8/JFunction1$mcII$sp;</span>
<span style="color:#44aa43">10</span><span style="color:#43a8ed;font-weight:700">:</span> putfield #<span style="color:#44aa43">24</span> <span style="color:#06f;font-style:italic">// Field fun:Lscala/Function1;</span>
<span style="color:#44aa43">13</span><span style="color:#43a8ed;font-weight:700">:</span> aload_0
<span style="color:#44aa43">14</span><span style="color:#43a8ed;font-weight:700">:</span> invokedynamic #<span style="color:#44aa43">91</span>, <span style="color:#44aa43">0</span> <span style="color:#06f;font-style:italic">// InvokeDynamic #1:apply$mcII$sp:()Lscala/runtime/java8/JFunction1$mcII$sp;</span>
<span style="color:#44aa43">19</span><span style="color:#43a8ed;font-weight:700">:</span> putfield #<span style="color:#44aa43">28</span> <span style="color:#06f;font-style:italic">// Field fun2:Lscala/Function1;</span>
<span style="color:#44aa43">22</span><span style="color:#43a8ed;font-weight:700">:</span> aload_0
<span style="color:#44aa43">23</span><span style="color:#43a8ed;font-weight:700">:</span> invokedynamic #<span style="color:#44aa43">95</span>, <span style="color:#44aa43">0</span> <span style="color:#06f;font-style:italic">// InvokeDynamic #2:apply$mcII$sp:()Lscala/runtime/java8/JFunction1$mcII$sp;</span>
<span style="color:#44aa43">28</span><span style="color:#43a8ed;font-weight:700">:</span> putfield #<span style="color:#44aa43">30</span> <span style="color:#06f;font-style:italic">// Field fun3:Lscala/Function1;</span>
</pre>
<p>
Ten byte kod należy czytać <i>"costam costam <b>InvokeDynamic</b> costam costam"</i> czyli oto lambdy z java 8 właśnie widzimy. No czyli jest ładnie i działa i nie ma sensu się dalej rozpisywać bo jest ładnie i działa.
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiV43EDdFvBMOdtMTfkxpy5Ef4HnnDio0FemtdwjY7CsgAYnLv4aTUjmnuxOw2j567w58sblaw_A_fw5rGheR153nXamX08FZcbxip7GYe9ZsOaZbkwR4Ugng8s_cq5pa7nkgJL2YDMoi0/s1600/compok.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiV43EDdFvBMOdtMTfkxpy5Ef4HnnDio0FemtdwjY7CsgAYnLv4aTUjmnuxOw2j567w58sblaw_A_fw5rGheR153nXamX08FZcbxip7GYe9ZsOaZbkwR4Ugng8s_cq5pa7nkgJL2YDMoi0/s400/compok.gif" width="400" height="300" /></a></div>
<h1>Traity i interfejsy</h1>
<p>
Od Javy 8 interfejsy mogą mieć metody statyczne oraz domyślne implementacje zwykłych metod. W ciekawym artykule o Scali 2.12 <a href="http://www.scala-lang.org/blog/2016/07/08/trait-method-performance.html">http://www.scala-lang.org/blog/2016/07/08/trait-method-performance.html</a> możemy wyczytać, że :
<div class="cytat">
"2.12.0-M5: trait method bodies are emitted in static methods in the interface classfile. The default methods forward to the static methods."
</div>
</p>
<h3>Kod wyjściowy w Scali</h3>
<pre style="background:#2a211c;color:#bdae9d"><span style="color:#43a8ed;font-weight:700">trait</span> A{
<span style="color:#43a8ed;font-weight:700">def</span> <span style="color:#ff9358;font-weight:700">m</span>()
}
<span style="color:#43a8ed;font-weight:700">trait</span> B{
<span style="color:#43a8ed;font-weight:700">def</span> <span style="color:#ff9358;font-weight:700">m</span>()
<span style="color:#43a8ed;font-weight:700">def</span> <span style="color:#ff9358;font-weight:700">m2</span>(arg:<span style="color:#43a8ed;font-weight:700">Int</span>) :<span style="color:#43a8ed;font-weight:700">Int</span> = arg+<span style="color:#44aa43">20</span>
}
<span style="color:#43a8ed;font-weight:700">trait</span> C{
<span style="color:#43a8ed;font-weight:700">val</span> field=<span style="color:#44aa43">15</span>
<span style="color:#43a8ed;font-weight:700">def</span> <span style="color:#ff9358;font-weight:700">m</span>()
<span style="color:#43a8ed;font-weight:700">def</span> <span style="color:#ff9358;font-weight:700">m2</span>(arg:<span style="color:#43a8ed;font-weight:700">Int</span>) :<span style="color:#43a8ed;font-weight:700">Int</span> = arg+field
}
</pre>
<h3>Scala 2.11</h3>
<p>Poza traitem <b>A</b>, który ma tylko deklaracje metody - resztę traitów nie da się przedstawić przy pomocy zwykłego interfejsu z Javy6 dlatego też generowane są dodatkowe klasy z implementacjami metod</p>
<pre style="background:#2a211c;color:#bdae9d">ls
A.class B.class B$class.class C.class C$class.class lib.scala
</pre>
<h3>Scala 2.12</h3>
<p>Tutaj wygenerowanych plików jest mniej właśnie dzięki nowym patentom w interfejsie Javy8</p>
<pre style="background:#2a211c;color:#bdae9d">ls
A.class B.class C.class lib.scala
</pre>
<p>I nawet to <b>C</b> z definicją wartości w polu traitu da się przedstawić jako interfejs w Javie8 </p>
<pre style="background:#2a211c;color:#bdae9d">javap <span style="color:#43a8ed;font-weight:700">C</span><span style="color:#43a8ed;font-weight:700">.</span>class
<span style="color:#43a8ed;font-weight:700">Compiled</span> from <span style="color:#049b0a">"lib.scala"</span>
<span style="color:#43a8ed;font-weight:700">public</span> <span style="color:#43a8ed;font-weight:700">interface</span> <span style="text-decoration:underline">C</span> {
<span style="color:#43a8ed;font-weight:700">public</span> <span style="color:#43a8ed;font-weight:700">abstract</span> void C$_setter_$field_$<span style="color:#ff9358;font-weight:700">eq</span>(<span style="color:#43a8ed;font-weight:700">int</span>);
<span style="color:#43a8ed;font-weight:700">public</span> <span style="color:#43a8ed;font-weight:700">abstract</span> <span style="color:#43a8ed;font-weight:700">int</span> <span style="color:#ff9358;font-weight:700">field</span>();
<span style="color:#43a8ed;font-weight:700">public</span> <span style="color:#43a8ed;font-weight:700">abstract</span> <span style="color:#43a8ed;font-weight:700">void</span> <span style="color:#ff9358;font-weight:700">m</span>();
<span style="color:#43a8ed;font-weight:700">public</span> <span style="color:#43a8ed;font-weight:700">static</span> int m2$(C, int);
<span style="color:#43a8ed;font-weight:700">public</span> <span style="color:#43a8ed;font-weight:700">int</span> <span style="color:#ff9358;font-weight:700">m2</span>(<span style="color:#43a8ed;font-weight:700">int</span>);
<span style="color:#43a8ed;font-weight:700">public</span> <span style="color:#43a8ed;font-weight:700">static</span> void $init$(C);
}
</pre>
<h1>Wołanie javy 8</h1>
<h3> Scala Lambdy Jako Java Lambdy </h3>
<p>wywołajmy sobie Streamy z Javy8 </p>
<pre style="background:#2a211c;color:#bdae9d"><span style="color:#43a8ed;font-weight:700">object</span> Main <span style="color:#43a8ed;font-weight:700">extends</span> <span style="font-style:italic">App</span>{
java.util.Arrays.asList(<span style="color:#44aa43">1</span>,<span style="color:#44aa43">2</span>,<span style="color:#44aa43">3</span>,<span style="color:#44aa43">4</span>,<span style="color:#44aa43">5</span>).stream().map(e=>e+<span style="color:#44aa43">1</span>).forEach(i=>println(s<span style="color:#049b0a">"INFO : $i"</span>))
}
</pre>
<p>I wynik</p>
<pre style="background:#2a211c;color:#bdae9d">scala2.12 lib.scala
INFO : 2
INFO : 3
INFO : 4
INFO : 5
INFO : 6
</pre>
<p>Czyli poooszło ładnie!</p>
<h3> Funkcje Scali zamiast Lambd </h3>
<pre style="background:#2a211c;color:#bdae9d"><span style="color:#43a8ed;font-weight:700">object</span> Main <span style="color:#43a8ed;font-weight:700">extends</span> <span style="font-style:italic">App</span>{
<span style="color:#43a8ed;font-weight:700">val</span> increment:<span style="color:#43a8ed;font-weight:700">Int</span>=><span style="color:#43a8ed;font-weight:700">Int</span>=e=>e+<span style="color:#44aa43">1</span>
<span style="color:#43a8ed;font-weight:700">val</span> display: <span style="color:#43a8ed;font-weight:700">Int</span>=><span style="color:#43a8ed;font-weight:700">Unit</span> = i=>println(s<span style="color:#049b0a">"INFO : $i"</span>)
java.util.Arrays.asList(<span style="color:#44aa43">1</span>,<span style="color:#44aa43">2</span>,<span style="color:#44aa43">3</span>,<span style="color:#44aa43">4</span>,<span style="color:#44aa43">5</span>).stream().map(increment).forEach(display)
}
</pre>
<p>To niestety nie zadziałało. Być może trzeba jakieś konwersje zaimportować. </p>
<pre style="background:#2a211c;color:#bdae9d">scala2.12 lib.scala
/home/pawel/projects/scalaeksperymenty/212/212/lib.scala:14: error: type mismatch;
found : Int => Int
required: java.util.function.Function[_ >: Int, _]
java.util.Arrays.asList(1,2,3,4,5).stream().map(increment).forEach(display)
^
one error found
</pre>
<p>
Także ogólnie jeśli nie będzie żadnego globalnego kataklizmu to przyszłość programowania zapowiada się wspaniale.
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPUb0qB-LMRT8Wo3dRhwg_w0MDHN1nW-LL8ehtA5wd6P_wURu8mFxhIRPCLG5D_wpPPX8N8cdIpPlnS45nye7jDMcmTEWn0dM89Z52GPbyYVJFqr6KPasRb0eKHjUxrzTL8a2R3HVMfQo/s1600/starobocinski_wierch.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPUb0qB-LMRT8Wo3dRhwg_w0MDHN1nW-LL8ehtA5wd6P_wURu8mFxhIRPCLG5D_wpPPX8N8cdIpPlnS45nye7jDMcmTEWn0dM89Z52GPbyYVJFqr6KPasRb0eKHjUxrzTL8a2R3HVMfQo/s640/starobocinski_wierch.jpg" width="640" height="360" /></a></div>Paweł Włodarskihttp://www.blogger.com/profile/04891037231290616803noreply@blogger.com0tag:blogger.com,1999:blog-5047632037494901372.post-62114653225070918582016-07-06T22:21:00.000+02:002016-07-06T22:21:08.530+02:00Einstellung Effect<div class="cytat" style="margin : 20px;font-size : 20px">
"The difficulty lies, not in the new
ideas, but in escaping from the old
ones, which ramify ... into every
corner of our minds."
</div>
<p>
To był taki krótki, fajny i wymowny cytat na wstęp a teraz jeszcze jeden dłuższy ale równie fajny i przepełniony niebagatelną informacją :
</p>
<div class="cytat" style="margin : 10px">
The Einstellung Effect refers to the human tendency to repeat a known solution, even if it no longer is the optimium solution. It represents the negative value of experience. The Einstellung Effect kicks in when new solutions have developed or become available but we do not look for them or adopt them even if we know of them. This can happen because we believe we already know the best solution, hence do not fully evaluate the new ways. Or simply because we are set in our ways and do not wish to undertake the “pain” of learning new ways unless forced to by others or market events.
</div>
<p>
Jeszcze metaforyczny rysunek i można zaczynać.
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh28ChZVcT9RjtOwvBBoJqjEoZ5qiKGtQHhOq3eodF91CiOm-OHYdJt4T6gb0LIaunP_Qb8sYgFwp9qOPMur_mB6UsEsR53Ka0YLVYW6AIH6TRuwykBLvgdFMFcR3J-WDH9oIRPH3CB9JY/s1600/ein.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh28ChZVcT9RjtOwvBBoJqjEoZ5qiKGtQHhOq3eodF91CiOm-OHYdJt4T6gb0LIaunP_Qb8sYgFwp9qOPMur_mB6UsEsR53Ka0YLVYW6AIH6TRuwykBLvgdFMFcR3J-WDH9oIRPH3CB9JY/s400/ein.jpg" width="350" height="400" /></a></div>
<h1>"Don't be blind,"</h1>
<p class="akapit">
Na wzmianka o tym efekcie natrafiłem w fajnym kursie o tym "jak się uczyć" - <b>Learning How to Learn</b>, który jest w tej chwili dostępny na courserze. Efekt ten jest tam jest przedstawiony jako jedna z większych przeszkód w nabieraniu nowych umiejętności - no bo jeśli wciąż powtarzamy te same schematy to trudno zaadoptować się do nowych podejść.
</p>
<p>
Żeby było bardziej naukowo wspomnimy o jednym z eksperymentów, który zademonstrował ów efekt. Generalnie była to scena ze szklanej pułapki 3 gdzie trzeba było odpowiednio przelewać wodę z jednego pojemnika do drugiego i do trzeciego.<br/><br/>
<iframe width="560" height="315" src="https://www.youtube.com/embed/BVtQNK_ZUJg" frameborder="0" allowfullscreen></iframe>
<br/><br/>Były dwie serie ćwiczeń gdzie jedna grupa rozwiązywała tylko drugą serię, w której istniało szybkie rozwiązywanie "równania" z użyciem tylko 2 z 3 zbiorników lub dłuższe z użyciem wszystkich trzech. Ta grupa bez problemów znalazła efektywne rozwiązanie z dwoma zbiornikami.
</p>
<p>
Druga grupa wcześniej robiła jeszcze inne ćwiczenie gdzie trzeba zawsze było użyć wszystkich trzech zbiorników i oni niestety w drugiej części eksperymentu zawsze używali wszystkich trzech zbiorników chociaż prostsze rozwiązanie z dwoma zbiornikami było w zasięgu reki.
</p>
<p>
Więcej info i dokładniejszy opis znajduje się w linku wikipedi poniżej - jest tam również wzmianka, iż uwaga od prowadzącego <b>"nie bądźcie ślepi"</b> pomagała znacznej ilość uczestników z grupy "z doświadczeniem" znajdować bardziej efektywne rozwiązanie.
<div style="10px">
<a href="https://en.wikipedia.org/wiki/Einstellung_effect">https://en.wikipedia.org/wiki/Einstellung_effect</a>
</div>
</p>
<p>
Na końcu będzie więcej linków ale pewnie i tak nikt ich nie przeczyta także tutaj jest dobre miejsce na jeden najbardziej wyczerpujący : <br/>
<div>
<a href="http://dspace.brunel.ac.uk/bitstream/2438/2276/1/Einstellung-Cognition.pdf">http://dspace.brunel.ac.uk/bitstream/2438/2276/1/Einstellung-Cognition.pdf</a>
</div>
<br/>
I Kilka fajnych zeń cytatów bo jak mówiłem pewnie i tak nikt tych linków czytać nie będzie :
<p class="cytat">
"When people test a theory, they look for evidence that is consistent with what they already believe
rather than objectively assessing any evidence even if it might disconfirm their previously held belief"
</p>
<p class="cytat">
"Einstellung refers to a person's predisposition to solve a given problem in a specific manner even though better or more appropriate methods of solving the problem exist. The Einstellung effect is the negative effect of previous experience when solving new problems. "
</p>
<p class="cytat">
"The most famous example (...) is the Luchins' water jar experiment, in which subjects were asked to solve a series of water jar problems. After solving many problems which had the same solution, subjects applied the same solution to later problems even though a simpler solution existed"
</p>
</p>
<h1>ObjectAbstractFactoryBean</h1>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg66QlOsSqUqKIE3XPEJNuhpP-IGj6bSSX57HUxE53nd01prEBqq9Khj_FCBAJrqAkLlBKMxDB7ZVU8a1W9pAABh_-3X3R6OrASI5LPhWqck1KdOskmyrX1MPBJz49WyYRLwyATCnCFjS4/s1600/bean.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg66QlOsSqUqKIE3XPEJNuhpP-IGj6bSSX57HUxE53nd01prEBqq9Khj_FCBAJrqAkLlBKMxDB7ZVU8a1W9pAABh_-3X3R6OrASI5LPhWqck1KdOskmyrX1MPBJz49WyYRLwyATCnCFjS4/s400/bean.jpg" width="400" height="236" /></a></div>
<p>
(a aktor nazywa się Sean Bean - czajcie jaki zajebisty się dowcip udał!!!)
</p>
<p class="akapit">
Taka sytuacja - ktoś robi w Javie 6 od 5 lat. Ma masę przyzwyczajeń i wytrenowany mózg przez konkretną sytuację. Narysujmy sobie jak to może wyglądać koncepcyjnie na poziomie neuronów. Oczywiście słowo <i>"koncepcyjnie"</i> jest tu ważne i użyłem go po to aby uratować się od potrzeby dokładnego trzymania się jak te rzeczy wyglądają w rzeczywistości bo tego sam nie wiem - ale koncepcyjnie może wyglądać to tak :
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1fvRVIkYya_k2uvFrCpFKx4rztEYx21u0gY1dIZj-vqvKZWxINHZfZdvVsx1iFok_Rer249VufMuhMaDx2lveBuV-r4mFtgtzms2AFHelhapeqIJfeO9qcxLygc08ZDHZVwpG4qAoBGw/s1600/neurony1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1fvRVIkYya_k2uvFrCpFKx4rztEYx21u0gY1dIZj-vqvKZWxINHZfZdvVsx1iFok_Rer249VufMuhMaDx2lveBuV-r4mFtgtzms2AFHelhapeqIJfeO9qcxLygc08ZDHZVwpG4qAoBGw/s400/neurony1.png" width="400" height="263" /></a></div>
<p class="akapit">
I te trzy kuleczki mogą być siecią neuronową* (* - czytałem ostatnio, że nie neurony są ważne a komórki gleiste - czy jakoś tak - ale to wszystko co tutaj opisuję jest "koncepcyjne" także bez znaczenia), która została zbudowana przez wspomniane 5 lat programowania w Javie. I teraz Np. mamy sytuację, że trzeba zaimplementować zakup w sklepie. Siec neuronowa od razu podsunie ścieżkę rozwiązania "jak nazwać ten obiekt" - bo oczywiście TO musi być obiekt. A jak do tego używa się FRAMEWORKA to musi to być (Sean) Bean.
</p>
<p class="akapit">
Jak z poziomu rozwiązywania problemów przejdziemy do bardziej ogólnego problemy nauki to zauważymy, <i>EINsztellung</i> stwarza wiele problemów bo mamy relatywnie ograniczone możliwości łączenia się nowych neuronów ze starą strukturą. I tak np. w konkretnym przykładzie <b>uczymy</b> się nowej koncepcji jaką jest <i>Stream</i> w Javie8 oraz jego zastosowania. Ponieważ nasz "arsenał poznawczy" składa się głównie z "Seana Beana Framework, Hibernate i Obiektów" to w ich kontekście będziemy definiować nowe pojęcie.
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDWmMvjdjfOsp_KxDYsAV5IVTR1h8yvzQ3KRrS3yIWNeqahxvQCSNHsOzkf58TgTEkseo0_EBAc1twsw9Murfs6Y3cbksmEDxkpZOTfcHIxZVE0W60OXFtVuPfUw7NrjG7jIAeVenGsgU/s1600/neurony2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDWmMvjdjfOsp_KxDYsAV5IVTR1h8yvzQ3KRrS3yIWNeqahxvQCSNHsOzkf58TgTEkseo0_EBAc1twsw9Murfs6Y3cbksmEDxkpZOTfcHIxZVE0W60OXFtVuPfUw7NrjG7jIAeVenGsgU/s400/neurony2.png" width="343" height="400" /></a></div>
<p>
połączenie (koncepcyjne) jest jedno i jest słabe. Jest jedno bo mamy jedną (obiektowo-beanową) wizję świata. Tutaj pojawiają się takie koncepcje jak pamięć krótkotrwała, długotrwała itd ale w uproszczeniu z punktu widzenia nauki to jedno słabe połączenie może szybko zaniknąć przez co zapomnimy jak tego Streama używać i nauka pójdzie w las.A z punktu widzenia zastosowania praktycznego widzimy Stream jako nową "Kolekcję Obiektów" i tylko w tym kontekście nasz mózg będzie generował rozwiązania. Widziałem już kilka prezentacji ludzi z Oracla gdzie napominają by traktować Streamy jako "Strumienie wartości" a nie "Kolekcje obiektów".
</p>
<p>
Teraz bliżej przyjrzymy się tym trzem zielonym neuronom gdyż tworzą one pewien spójny zbiór uzupełniających się informacji - taki zbiór pojęciowy w naszej głowie nazywamy <b>Chunk</b>iem.
</p>
<h1>Chunk</h1>
<p>
Czym jest chunk : <a href="https://www.quora.com/What-is-chunk-or-chunking-in-learning">https://www.quora.com/What-is-chunk-or-chunking-in-learning</a>
</p>
<p>
<b>Chunk</b> - Zbiór informacji, który tworzy jakąś pojęciową całość. Nasze <i>koncepcyjne</i> neurony wyhodowane przez 5 lat Javy stworzyły takiego właśnie pięknego Chunka. Obiekt,Klasa,Enkapsulacja,Getter,DAO - to wszystko w ramach tego chunka jest spójne i gotowe do obrony swoich granic (co często widać na forach). I teraz pytanie co jeśli mam inne <b>chunki</b> do których TAKŻE mogę odnieść nowe informacje? Czy to dobrze czy źle? Czy to pomoże czy przez zamieszanie przeszkodzi?
</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidGQ4mHPUoS9xB7EPaMsmqARmP2z4Cde2CDhIdzsXYCBtNIv2PbE4TAELs5QYp3fIKy7frgBJkfLYhBqkxN3HdNTCkptuRbjkukAk2aMnHv2kDcXJPN9twOt0cioGfqQJISPAJhLxphWU/s1600/twochunks.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidGQ4mHPUoS9xB7EPaMsmqARmP2z4Cde2CDhIdzsXYCBtNIv2PbE4TAELs5QYp3fIKy7frgBJkfLYhBqkxN3HdNTCkptuRbjkukAk2aMnHv2kDcXJPN9twOt0cioGfqQJISPAJhLxphWU/s400/twochunks.png" width="316" height="400" /></a></div>
<p>
Z tego jak zrozumiałem ten cały mechanizm to jeśli jakąś nową koncepcję można połączyć z dwoma lub więcej niezależnymi chunkami to bardzo bardzo dobrze!. Raz, że powstaje więcej połączeń od nowej idei (ta niebieska kuleczka) a dwa, że następuje połączenie pomiędzy dwoma chunkami jako takimi, które były niezależne ponieważ okazuje się, że maja teraz ze sobą coś wspólnego. I wracając do przykładu ze Stream'ami - można je jednocześnie widzieć jako leniwa kolekcję obiektów jak i z drugiej strony jako abstrakcyjną formułę danych (w większości języków funkcyjnych podawany jest przykład z obliczeniem ciągu Fibonacciego przy pomocy streamów, które po prostu opisują w sposób jasny formułę obliczeń kolejnych elementów i to od użytkownika zależy gdzie w tej formule się zatrzyma). I teraz te koncepcje mogą zacząć się ze sobą łączyć. Czy Stream obiektów to Stream danych? Co musi się stać by obiekty nazwać Danymi? Same takie rozważania będą efektywnie utrwalać informacje w pamięci a do tego rozszerzać pole potencjalnych interpretacji nowych wiadomości.
</p>
<p>
Inny bardzo ciekawy przykład. Z mojego doświadczenia programiści C# często dużo szybciej łapią scalę niż programiści maintenance Javy 7,6,5.
W C# lambdy mieli od dawna. Jak pokazywałem flatMapy to często słyszałem "a tak tak, u nas jest takie LINQ bardzo podobne do tego".
Tymczasem gdy programista Javy widzi po raz pierwszy w życiu jak metoda przyjmuje funkcje i zwraca funkcje to czasami mu pęka mózg (w sensie głowa robi się bardzo czerwona i tak drga nerwowo dolna warga czyli chyba jakiś wylew)
</p>
<p>
W kontekście nauki po raz kolejny dobra wydaje się formuła CR (CR to Code Retreat a nie Chrystian Ronaldo) gdzie po prostu zabrania się rozwiązywania zadań w pewien sposób aby uczestnicy poznali przez to nowe sposoby podejść. I nie jest to prosty process bo nie raz uczestnicy fakt - że nie zdążyli z implementacją - odbierali bardzo osobiście i po to usuwa się ten kod aby ludzie odczepili ego od implementacji.
</p>
<p>
Aby nie było tak bardzo abstrakcyjnie poniżej kilka pomysłów na rozbudowę niezależnych <b>programistycznych chunków</b>
</p>
<h1>"Rozbuduj swą sieć z paleta języków"</h1>
<p>
Podobnie do Code Retreat niektóre języki usuwając pewne mechanizmy nadają ciekawe ograniczenia, które mogą nas zmusić do szukania nowych podejść.
</p>
<h2>Ocaml</h2>
<p>
Niedługo startuje kurs online: <a href="https://www.fun-mooc.fr/courses/parisdiderot/56002S02/session02/about">Ocaml Mooc</a>. Jest to druga sesja i z tego co zrozumiałem z pierwszej to w Ocaml mamy do czynienia z pewnym negatywem Javy. <br/></br>
Koncepcyjnie w OCamlu kod wygląda tak
<pre>
kod immutable
[DANGER DANGER DANGER ZONE]
kod mutable
[KONIEC DANGER ZONE]
</pre>
<br/><br/>
W Javie w zasadzie zmiana wartości wszystkiego dookoła (nawet enkapsulowanego) jest (niekwestionowaną przez niektórych) codziennością także to by bardziej wyglądało w ten sposób :
<pre>
[DANGER ZONE]
poczatek programu
[SAFE ZONE]
Zaimplementowane 15 mechanizmów z "Effective Java"
[KONIEC SAFE ZONE]
koniec programu
[DANGER ZONE]
</pre>
<br/>
No i jest zabawa "zaimplementuj rozwiązanie w sytuacji gdy kosztowne rytuały w kodzie wiążą się z mutowalnością".
</p>
<h2>Go</h2>
<p>
Podobno nie ma generyków. Jest to bardzo ciekawe dlaczego w 2016 jedna z przodujących firm IT na świecie reklamuje język bez generyków.
Czy programowanie Go wygląda jak programowanie w Javie 4? A może poza javą ta koncepcja sprawdziła się lepiej?
</p>
<h2>Kotlin</h2>
<p>
Żeby nie było, że tylko programiści Javy mogą się czegoś nauczyć z innych języków. Jak chcesz w Scali pokazać na poziomie typów, że czegoś może nie być
to Option,Option,Option... które i tak samo może być nullem. Tymczasem Kotlin ma bardzo wygodne zabezpieczenie przed nullem na poziomie typów bez wchodzenia w Monady i inne takie tam.
</p>
<h2>Haskell </h2>
<p>
Tu nima obiektów i wielu rzeczy nima - <i>Ultimate Code Retreat</i> dla programistów Javy.
</p>
<p>
Na jesieni ma być kurs : <a href="https://www.futurelearn.com/courses/functional-programming-haskell">https://www.futurelearn.com/courses/functional-programming-haskell</a>
</p>
<h1>myślenie lateralne</h1>
<p>
Przy okazji tego artykułu można poruszyć ten temat. Autorem koncepcji jest Bono ale nie ten z U2 bo Edward de Bono. Generalnie tutaj kompletnie zrywamy z rutyną mechanicznego myślenia.
Np:
<br/>
<ul>
<li>Jest problem z deploymentem</li>
<li>Jak byś go rozwiązał przy pomocy <b>gabki, mikrofali i wody?</b> (dokładnie tak) </li>
<li>Gabka coś wchłania i potem to gdzies można wycisnąć - może coś rozlazłego da się zebrać w kupę i przenieść w inne miejsce. </li>
<li>Mikrofala zwieksza temeperaturę i wysyła fale, zmienia naturę tego co w środku. Może kawałek aplikacji przenieść w miejsce gdzie będzie lepiej monitorowane </li>
<li>Woda zmywa brud. Może warto niepotrzebną cześć aplikacji usunąć przed deploymentem? </li>
<li>itd. </li>
</ul>
<a href="https://pl.wikipedia.org/wiki/My%C5%9Blenie_lateralne">https://pl.wikipedia.org/wiki/My%C5%9Blenie_lateralne</a>
</p>
<h1>Linki</h1>
<ul>
<li><a href="http://dspace.brunel.ac.uk/bitstream/2438/2276/1/Einstellung-Cognition.pdf">http://dspace.brunel.ac.uk/bitstream/2438/2276/1/Einstellung-Cognition.pdf</a> </li>
<li><a href="https://en.wikipedia.org/wiki/Einstellung_effect">https://en.wikipedia.org/wiki/Einstellung_effect</a> </li>
<li><a href="http://www.alleydog.com/glossary/definition.php?term=Einstellung%20Effect">
http://www.alleydog.com/glossary/definition.php?term=Einstellung%20Effect</a> </li>
<li><a href="https://www.edge.org/response-detail/11166">https://www.edge.org/response-detail/11166</a> </li>
<li><a href="http://randymatusky.com/2015/02/25/the-hidden-learning-potential-behind-the-einstellung-effect/">
http://randymatusky.com/2015/02/25/the-hidden-learning-potential-behind-the-einstellung-effect/</a> </li>
</ul>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhb52j1YqrA2mxnBXR7yy6i1y_IeKziFPVgv4agHhMX4ehl8WJAbOwCBdx9YBv_kUHWRcsz9rK2BL9bof_bMHGd4k_vIjR0vqk5R7Vv31nRkv-LXWHgFsDgwthtoDvt7FSYmvPl1GDsS9w/s1600/droga.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhb52j1YqrA2mxnBXR7yy6i1y_IeKziFPVgv4agHhMX4ehl8WJAbOwCBdx9YBv_kUHWRcsz9rK2BL9bof_bMHGd4k_vIjR0vqk5R7Vv31nRkv-LXWHgFsDgwthtoDvt7FSYmvPl1GDsS9w/s640/droga.jpg" width="640" height="360" /></a></div>Paweł Włodarskihttp://www.blogger.com/profile/04891037231290616803noreply@blogger.com2