czwartek, 19 listopada 2009

myObject.IsOneOf(value1, value2, value3)

Człowiek nie ma czasu na dokończenie swoich zadań i wali na łeb terminy. Zdrową reakcją jest wtedy wyszukanie sobie jakiegoś gównianego problemu, którym nikt normalny nie zawracałby sobie głowy, za to którego rozwiązanie na chwile nada sens smutnemu życiu programisty.

Przykładowy taki numer: porównanie obiektu z kilkoma wartościami w ifie. Dajmy dla prostoty, że to enum:


enum JakisEnum

{

Field1,

Field2,

Field3,

Field4,

Field5,

Field6,

}


Teraz mamy wartość którą chcemy sprawdzić czy nie jest jedną z kilku wartości enuma, czyli odpalić taką logikę:


if (mojEnum == JakisEnum.Field1 || mojEnum == JakisEnum.Field2 || mojEnum == JakisEnum.Field3 || mojEnum == JakisEnum.Field6)

{

// rób coś

}


Ale wygląda to dla mnie jak kupa. Trzeba przejrzeć cały warunek porównania, żeby się upewnić, że to sprawdzenie czy obiekt ma jedną z kilku wartości (że tam wszędzie jest "mojEnum", "==" i "||"). Niby niewielka, ale kupa. Można by dać komentarz, ale to znowu kupa. Boli, że tak prostą operację trzeba by jeszcze komentować.

Pierwszy pomysł był więc, żeby wykorzystać metodę Contains kolekcji a najprzyjemniejsza kolekcja do zbudowania w takim przypadku, to tablica i wtedy wyglądałoby to tak:


if (new[] {JakisEnum.Field1, JakisEnum.Field2, JakisEnum.Field3, JakisEnum.Field6}.Contains(mojEnum))

{

// rób coś

}


I byłoby fajnie, ale normalny człowiek (z całym szacunkiem dla Arabów) czyta od lewej i czyta: "jeśli zbuduję tablicę kilku elementów i będzie ona zawierała mój element, to będzie zajebiście", a zboczyło mnie, że kod ma na pierwszy rzut oka wyglądać na to co robi, więc ma się go czytać tak: "jeśli mój obiekt jest jednym z: a, b, c, to jest zajebiście". Można by więc powyższy przypadek odwrócić, żeby obiekt był pierwszy. Zamarzyło mi się żeby dodać jakiś lewostronny operator "zawierania" do kolekcji, ale extension to tylko methods a nie operators czy inne cuda. No i oświeciło mnie, czemu nie rozszerzyć dowolnego obiektu o sprawdzenie czy zawiera się w kolekcji. Dodałem więc taki extension:


public static class ObjectExtensions

{

public static bool IsIn<T>(this T item, IEnumerable collection)

{

return collection.Contains(item);

}

}


Dzięki czemu porównanie wyglądało teraz tak:


if (mojEnum.IsIn(new[] {JakisEnum.Field1, JakisEnum.Field2, JakisEnum.Field3, JakisEnum.Field6}))

{

// rób coś

}


Co byłoby już fajne, gdyby nie to tworzenie tablicy. Z przedszkola pamiętamy na szczęście "params", metodę nazywamy "IsOneOf" żeby było ładniej i wygląda to tak:


public static bool IsOneOf<T>(this T item, params T[] values)

{

return values.Contains(item);

}


A if ostatecznie jest zadowalająco ładny:


if (mojEnum.IsOneOf(JakisEnum.Field1, JakisEnum.Field2, JakisEnum.Field3, JakisEnum.Field6))

{

// rób coś

}


No i jest vixa.

Oczywista, taki extension umożliwia zabawę nie tylko enumem, np..:

var nameIsStupid = name.IsOneOf("foka", "bizon");

Dlaczego goto nie jest złe

Studia, świat i moda każe mówić, że goto, to gówno totalne i nie ma racji bytu. Idąc pod prąd chcemy udowodnić, że tak nie zawsze jest. Myślę, że każde narzędzie języka może prowadzić to spaghetti code, trudności w jego języku i nieporozumień. Tak samo jak użycie wielu poziomów klas i polimorfizmu w niewłaściwy sposób, extension methody czy genericsy. Wszystko jest dla ludzi, tylko trzeba z tego kurwa umieć korzystać.

Poniżej kilka przykładów.

1. Wyjście z bardzo wielokrotnie zagnieżdżonej pętli.
  
List<MainElement> mainElements = new List<MainElement>();
bool breakForeach = false;
foreach (MainElement mainElement in mainElements)
{
  foreach (SecondaryElement secondaryElement in mainElement.SeconaryElements)
  {
    foreach (UnimportantElement unimportantElement in secondaryElement.UnimportantElements)
    {
      // warunek, który wymaga od nas wyjścia z bardzo zagnieżdzonej pętli
      // i ruszenia dalej do reszyt funkcji
      if (ComplicateCondition(mainElement, secondaryElement, unimportantElement))
      {
         SomeOperation(mainElement, secondaryElement, unimportantElement);
         breakForeach = true;
         break;
      }
    }
    if (breakForeach)
    break;
  }
  if (breakForeach)
  break;
}
// reszta funkcji
Funkcja ma 25 linii kodu i jeśli dołoży się do niej więcej logiki, to zupełnie przestanie być czytelna.
To samo w wersji z goto:
List<MainElement> mainElements = new List<MainElement>();
bool breakForeach = false;
foreach (MainElement mainElement in mainElements)
{
  foreach (SecondaryElement secondaryElement in mainElement.SeconaryElements)
  {
    foreach (UnimportantElement unimportantElement in secondaryElement.UnimportantElements)
    {
      // warunek, który wymaga od nas wyjścia z bardzo zagnieżdzonej pętli
      // i ruszenia dalej do reszyt funkcji
      if (ComplicateCondition(mainElement, secondaryElement, unimportantElement))
      {
         SomeOperation(mainElement, secondaryElement, unimportantElement);
         goto EndForeach;
      }
    }
  }
}
EndForeach:
Console.Out.WriteLine("jade dalej");
// reszta funkcji
Podejście z goto ma tą przewagę, że nie musimy sie martwić o dodatkową logikę, która może sie pojawić przy wychodzeniu z naszych pętli wewnętrznych. Możemy dowolnie zaciemnić kod, a dalej wyjdziemy z wszystkich trzech pętli od razu. Sprawa jest kurewsko prosta. Wyskakujemy i tyle. Resharper nam pomoże, bo po kliknięciu z ctrl przeskakuje jak należy na właściwe miejsce.

2. Wykonanie operacji aż do skutku.
Powiedzmy, że chcemy usunąć plik, ale może sie okazać, że ktoś go jeszcze blokuje. Więc czekamy chwile i próbujemy znowu. Zobaczmy przykład wykonania tego z goto i bez goto

public void Move1(string fileName, string destination)
{
  if (File.Exists(fileName))
  {
     int tries = 0;
     do
     {
       try
       {
          File.Move(fileName, destination);
          break;
       }
       catch (IOException)
       {
          tries++;
          Thread.Sleep(2000);
       }
     }
     while (tries < 5);
  }
}


I przykład z goto:

public void Move2(string fileName, string destination)
{
  if (File.Exists(fileName))
  {
     int tries = 0;
  move:
     try
     {
        File.Move(fileName, destination);
     }
     catch (IOException)
     {
        Thread.Sleep(2000);
        tries++;
        if (tries < 5) goto move;
     }
  }
}

Dużej różnicy nie widać, ale logika funkcji ulega zajebistej zmianie. Czytając pierwszy przykład trafiamy na pętle, która kieruje nasze myślenie na to, że będziemy coś robić kurewsko kilka razy, przy czym w 99% przypadków wszystko wykona się raz. Tylko jak coś się spierdoli pętla wykona się jeszcze raz. Czytając kod nasze myślenie jest kierowane na zjebane tory.
W przypadku z Goto. Widzimy labelke „move”, która zwraca naszą uwagę, ale nic nam nie przeszkadza, jest tylko ozdobnikiem. Czytając dalej trafiamy na najważniejszą funkcję „move” i dopiero w bloku catach widząc obsługę wyjątku. Jak coś się nie uda widzimy, że próbujemy 5 razy wyskakiwać do wcześniejszej labelki.

Podsumowując chciałbym powiedzieć, że wszystko kurwa jest dla ludzi i czasem jedno goto w funkcji sprawi, że algorytm będzie bardziej zajebisty. Oczywiście więcej goto może zadziałać odwrotnie.


całusy dla wszystkich. Szczególnie dla foki.


bizon



czwartek, 12 listopada 2009

Foka: czas zaczac pisac bloga o programowaniu i zyc z tego

foka

13:07:36

czas zaczac pisac bloga o programowaniu i zyc z tego

13:07:50

gadanie o programowaniu to jedyny moment kiedy myslisz o tym co robisz


bizon

13:08:00

i co byś dzisiaj napisal na blogu?


foka

13:08:04

jak sie robi zadanie to sie je po prostu robi byle dzialalo, zeby dali spokoj i zeby byla pensja :)

13:08:14

dzisiaj? cos hakerskiego


bizon

13:08:20

np?


foka

13:08:20

czy lepiej uzywac "" czy string.Empty ;)


bizon

13:09:13

i co lepiej używać?


foka

13:09:37

jeden huj. to nie powinno miec znaczenia

13:09:41

pointa bedzie taka:

13:09:53

jesli czytales ten artykul to cie chyba pojebalo, programisto

13:10:13

ale tip mozna dac: uzywaj "" bo tak szybciej i spierdalaj

13:10:23

mysle ze wulgaryzmy dodalyby kolorytu blogowi

13:10:35

wszyscy pisza tak ladnie albo sila sie na jakies poetyckie zarty i porownania

13:10:41

za malo jest wulgaryzmow na tych blogach

13:12:00



BONUS


o kurwa. dostalem od jednej firmy katalog produktow w pliku csv. bez naglowka. i ja nie wiem ktore pole co znaczy :(

13:12:06

czemu to wszystko nie moze byc takie latwe