środa, 20 listopada 2013

Drugi tydzień z rekaktywnym programowaniem

Dzisiaj minął pierwszy deadline na zadania z drugiego tygodnia z kursu Principles of Reactive Programming. Niestety nie udało mi się zdobyć maksa, a jedynie 8.15 z 10.00 punktów. Nie ma sensu dalej walczyć z tymi zadaniami, gdyż i tak maksymalna ocena za wysłanie rozwiązania dzień po terminie jest o 20% mniejsza, więc nic tym sposobem nie zyskam. Lepiej zabrać się za nowe wykłady i zadania, a z tego co słyszałem, to są one jeszcze obszerniejsze niż te z drugiego tygodnia.

Czemu poszło mi tak słabo? Dużo czasu straciłem na w pełni poprawną implementację Demultiplexera. Przeglądałem trochę forum kursu, widziałem tam kłótnie, co do tego w jakiej kolejności powinny być uporządkowane piny wyjściowe, a jednoznacznej odpowiedzi i wyjaśnienia nie było. Błąd, jaki popełniłem, to to, że za mało testów napisałem. Ba, nawet nie trzeba by było ich pisać, a jedynie zaadaptować te, które był dostępne na forum. Po skorzystaniu z takiego jednego testu, od razu udało mi się znaleźć błąd i zaimplementować poprawnie damultipleksera. Nie wystarczało naiwnie sprawdzać pin, na którym miał się generować oczekiwany stan wysoki, ale należało sprawdzać wszystkie piny!

W drugiej części zadania również nie do końca było jak dla mnie jasne, od czego należy zacząć i jak są generowane następne stany gry. Jakoś ta główna pętla symulacji była dla mnie zbyt zaciemniona. Ostatecznie nie udało mi się zaimplementować poprawnie na czas wszystkich reguł gry, gdyż nie chciałem nocki zarywać - wolałem się wyspać. No i też wymagania nie były dla mnie do końca jasne. Coś tam działa, kod przeszedł część testów, kilka punktów wpadło. Dla potomnych screenshot z symulacji.


Na cale szczęście limit 5ciu pierwszych punktowanych rozwiązań został zniesiony. Inaczej pewnie nie udałoby mi się osiągnąć takiego wyniku z tego zadania.

No nic, idziemy dalej, nie poddajemy się, miejmy nadzieję, że następnym razem pójdzie łatwiej.

piątek, 15 listopada 2013

Pierwszy tydzień kursu Principles of Reactive Programming na Coursera

Mija właśnie pierwszy (a właściwie to już drugi) tydzień kursu Principles of Reactive Programming na portalu coursera.org. Jest to kontynuacja wcześniejszego kursu (Functional Programming Principles in Scala) na tymże samym portalu, który również był prowadzony przez twórcę Scali: Martina Oderskiego.

Za pierwszy tydzień oczywiście zgarnąłem komplet punktów, mimo że żadnego video z kursu nie widziałem (to tak jakbym nie chodził na wykłady;)). Wystarczyły mi slajdy ze spotkań i trochę dokumentacji ze ScalaCheck. Jednakże nie jestem zadowolony z rozwiązań, jakie wysłałem. Nie można ich publikować, bo zabrania tego Code Honor, ale mam nieodpartą chęć zobaczenia i przedyskutowania innych rozwiązań. 

I tutaj pojawia się pytanie do Was: Czy ktoś byłby chętny na wspólną ustawkę na Google Hangouts, aby podzielić się swoimi rozwiązaniami i je przedyskutować? 

Ostatnio brałem udział (więcej o tym we wpisie: Remote Scalania 7 in Javart) zdalnie w spotkaniu organizowanym przez Jacka Laskowskiego, Scalani i ta forma (tj. Hangout) bardzo dobrze się sprawdziła. Coś podobnego (aczkolwiek bardziej skromnego) i tylko zdalnego chciałbym zorganizować, aby omawiać rozwiązania kolejnych zadań. Są chętni? Jeśli tak, to proszę o informację na priv (mstachniuk gmail com). Oczywiście spotkania muszą się odbywać po Hard Deadlinie, aby nie wpływać na wyniki rozwiązań. 

Czekam na odzew i życzę pomyślności w rozwiązywaniu zadań z kursu.

czwartek, 7 listopada 2013

Błędne użycie Listy w Javie

Ostatnio natrafiłem na ciekawą "zagadkę" związaną z kolekcjami w Javie. Czy jest to coś nowego, czy już gdzieś było w Java Puzzlers - nie wiem. Prezentowałem ten kod kolegom z zespołu i oni nie wpadli na właściwe rozwiązanie, więc postanowiłem je tutaj opublikować.

Co zostanie wyświetlone na konsoli przez poniższy kod? Dla utrudnienia nie podaję możliwych odpowiedzi.

public class ListTest {

    public static void main(String[] args) {
        List<String> planets = new ArrayList<String>();
        planets.add("Mercury");
        planets.add("Venus");
        planets.add("Earth");
        planets.add("Mars");
        for (String p : planets) {
            if (p.startsWith("V")) {
                print(planets);
            }
        }
    }

    private static void print(final List<String> planets) {
        Collections.sort(planets);
        for (String p : planets) {
            System.out.print(p + " ");
        }
        System.out.println("");
    }
}

Aby zobaczyć odpowiedź, zaznacz tekst w poniższym bloku:

Earth Mars Mercury Venus
Earth Mars Mercury Venus 

Dlaczego tak się dzieje? Problem leży w dwóch miejscach.

Standardowo kolekcje (w tym ArrayList) zwierają pole modCount. Jest ono inkrementowane, za każdym razem, gdy modyfikujemy naszą kolekcję. Ten kod: for (String p : planets) zostanie natomiast zamieniony na coś takiego:

Iterator<String> iterator = planets.iterator();
while (iterator.hasNext()) {
    String p = iterator.next();

Czyli zostanie utworzony Iterator, po którym będziemy iterować, aż do końca Listy. Podczas tworzenia takiego Iteratora, zapamiętywany jest aktualny licznik modyfikacji w iteratorze, który później, podczas wywołania metody next(), jest porównywany z obecną wartością. Gdybyśmy zamiast sort() wywoływali add() lub remove() to poleciałby ConcurrentModificationException. Niestety metoda sort() nie powoduje modyfikacji tego licznika! Nie pomaga nawet Collections.synchronizedList()!

Jest to "piękny" przykład efektów ubocznych, które mogą się zdarzyć w naszym kodzie, a których znalezienie może zająć sporo czasu. A może czas na niemodyfikowalne kolekcje w Javie tak jak w Scali?