Projektowanie, Programowanie, Codzienność – BeniaminZaborski.com

4 marca 2014

Poszukiwacze kamieni szlachetnych – lambda

Filed under: Poszukiwacze kamieni szlachetnych — Tagi: , , , — Beniamin Zaborski @ 20:08

W C# mamy wyrażenia lambda, które są anonimowymi funkcjami za pomocą których można tworzyć np. delegaty. Raczej powinny być znane każdemu programiście C# szczególnie, że dość intensywnie używamy ich w LINQ. Spójrzmy na przykład:

delegate bool AreEqualDelegate(int a, int b);
AreEqualDelegate AreEqual = (a, b) => a == b;
bool result = AreEqual(7, 4);

Wywołanie AreEqual z parametrami 7 i 4 zwróci nam oczywiście wartość false.

Jak się sprawa ma w Ruby? A no jak się domyślacie w Ruby także są wyrażenia lambda. Spróbujmy napisać analogiczny do powyższego kod w Ruby:

are_equal = lambda {|a, b| a == b }
result = are_equal.call(7, 4)

are_equal jest tutaj odpowiednikiem delegatu AreEqualDelegate w C# i jak wszystko w Ruby jest obiektem. Ale jakim obiektem? Sprawdźmy to:

are_equal.class

metoda class zwróci nam Proc. Proc to klasa reprezentująca blok kodu w Ruby, gdyż to {|a, b| a == b } to jest właśnie blok kodu.

Do czego nam te lambdy? A no właściwie możemy ich używać w takim samym zakresie jak w C#. Dzięki wyrażeniom lambda możemy np. wprowadzić pewien dodatkowy poziom abstrakcji w naszym kodzie. Spójrzmy na przykład:

class Customer
 attr_accessor :name, :number

 def validate(validator)
   validator.call(self)
 end
end
c = Customer.new
c.name = "Rubers Company"
c.number = "CUST000001"
validator = lambda {|customer| customer.name.length < 50 }
result = c.validate(validator)

Mamy tutaj prostą klasę Customer posiadającą dwie właściwości name i number oraz metodę validate. Metoda ta sama w sobie nie określa jak ma wyglądać walidacja, a jest ona dostarczana z zewnątrz właśnie dzięki wyrażeniom lambda/blokom kodu. W dalszej części widać walidator który weryfikuje długość pola name w klasie Customer i jest on przekazany do metody validate.

Tu muszę wspomnieć o ciekawym rozwiązaniu w Ruby, a mianowicie yield. Dzięki yield metoda validate w klasie Customer może wyglądać tak:

def validate
  yield(self)
end

a wywołanie metody validate tak:

result = c.validate {|customer| customer.name.length < 50 }

Jak widzimy yield wywołuje blok kodu przekazany z zewnątrz w sposób mniej jawny dzięki czemu mogliśmy się pozbyć parametru metody validate i bezpośredniej referencji do walidatora. Oba przedstawione warianty kodu z validator.call i yield są równoważne. Podkreślić należy jednak to, że wersja z yield zawsze będzie wydajniejsza.

Na koniec dodam, że istnieje alternatywny zapis bloku kodu w Ruby do {} z użyciem słów kluczowych do … end. Oto przykład:

are_equal = lambda do |a, b|
  a == b
end
Reklamy

1 marca 2014

Poszukiwacze kamieni szlachetnych – wszystko jest obiektem

Filed under: Poszukiwacze kamieni szlachetnych — Tagi: , , — Beniamin Zaborski @ 17:48

Ruby to język obiektowy, bardzo obiektowy:). Ruby jest tak bardzo obiektowy, że dosłownie wszystko tutaj jest obiektem, nawet liczba 1. Przyjrzyjmy się temu bliżej. Skoro 1 jest obiektem to można przypuszczać, że posiada jakieś metody. A i owszem. Nasza jedynka potrafi nawet nam powiedzieć jakie posiada metody. Spróbujmy czegoś takiego (najlepiej w IRB):

1.methods

Otrzymamy listę wszystkich metod naszego obiektu. methods to nic innego jak metoda, która zwraca listę dostępnych metod na obiekcie. Tak wygląda wywołanie metody bez parametrów w Ruby.

Na liście metod możemy znaleźć np. metodę o nazwie equal?. Ten znak zapytania może wygląda nieco dziwnie dla programisty C#, ale to tylko część nazwy metody. Taka jest konwencja nazewnicza dla metod zwracających wartość typu logicznego true/false. Wywołajmy zatem tą metodę z parametrem:

1.equal?(1)

W rezultacie dostaniemy true. Jest OK, lecimy dalej.

Może się zastanawiacie czemu nazwy metod są poprzedzone znakiem „:” ? Nie zastanawiajcie się i na razie przyjmijmy dla uproszczenia że tak musi być (dla ciekawskich rzucam hasło symbole).

Na liście metod zwróconych przez metodę methods zapewne zauważyliście kilka dziwnie wyglądających i może nie do końca tam pasujących, np. +, -, [], itp. Wszystko jest OK. Ruby to język bardzo obiektowy, pamiętacie? „+” to metoda realizująca dodawanie. Użyjmy jej:

1.+(2)

Na pierwszy rzut oka (dla programisty C#) wygląda dziwacznie, ale „+” to tylko specyficzna nazwa metody, równie dobra jak add.

Dzięki cukrowi syntaktycznemu można powyższe zapisać także następująco:

1+2

Dotyczy to nie tylko metody „+”, ale także kilku innych.

Ciągi znaków w Ruby to także obiekty. Zdefiniować je możemy na kilka sposobów, np.:

"Z Ruby jest przednia zabawa"
'Z Ruby jest przednia zabawa'

Obie powyższe instrukcje spowodują utworzenie obiektu string. Jest jednak między nimi pewna różnica. Ogólnie można powiedzieć, że wersja z apostrofami jest nieco uboższa, tj. nie obsługuje escape-owania i interpolacji. W wersji z cudzysłowami możemy zatem zrobić tak:

name = 'Jan'
"Cześć #{name}"

Jak to wygląda w C#? C# to także język obiektowy, ale np. typ int (będący referencją do System.Int32) jest de facto strukturą, która nie posiada tylu metod co klasy Fixnum czy Integer w Ruby. Listę metod dostępną dla danego obiektu można w C# pobrać za pomocą mechanizmu refleksji, a typ string w C# także jest obiektem jak w Ruby.

Oczywiście C# nie jest wcale „gorszym” językiem programowania, gdyż wszystko to co w Ruby da się zrealizować w C# tylko po prostu czasami trochę inaczej. Jeśli miałbym to jakoś podsumować, to chyba nie rozminę się zbytnio z prawdą jak powiem że Ruby koncepcyjnie jest nieco „bardziej obiektowy” niż C#.

15 lutego 2014

Poszukiwacze kamieni szlachetnych – Początek

Filed under: Poszukiwacze kamieni szlachetnych — Tagi: , , — Beniamin Zaborski @ 18:05

W ramach samorozwoju jak i dywersyfikacji skillsów – czytaj uniezależnienia się od M$ – postanowiłem spróbować czegoś z innej bajki … innej niż .NET. W związku z tym, że nikt mnie do tego nie przymusza, a wręcz przeciwnie robię to w ramach hobby więc podstawowe założenie jest proste – ma być FUN! Duuuużo FUN-u!

Padło na RUBY!

Tak Ruby! A czemu nie?

Postanowiłem napisać cykl postów o Ruby. Ale żeby nie powielać masy informacji jakie są na temat tego języka/środowiska/platformy* (*niepotrzebne skreślić) w sieci moim założeniem jest pokazanie go z perspektywy programisty C#/.NET.

Ruby to język programowania, ale wszystkim od razu na myśl przychodzi framework do tworzenia aplikacji Web-owych Ruby on Rails. Jest wiele analogii pomiędzy C# a Rubym, a także chociażby pomiędzy ASP.NET MVC a Rails-ami. Właśnie to będę się starał przedstawić w serii moich wpisów.

Zacznijmy od razu, już teraz … oczywiście od podstaw.

Język Ruby został stworzony w 1995 roku (czyli dość dawno) przez Yukihiro Matsumoto znanego też jako Matz. Jak twierdzi autor „Ruby to dynamiczny język programowania skupiający się na prostocie i wydajności”. Ruby jest językiem interpretowanym w odróżnieniu do kompilowanego do IL języka C# na platformie .NET. Podobnie jak C# Ruby jest językiem obiektowym. Składnia Ryby-ego jest zwięzła i oparta na słowach języka angielskiego.

Jeśli to dla Was za mało i potrzebujecie intensywniejszej motywacji to fani tego języka nazywają go „pięknym i pełnym sztuki”. Chyba coś w tym jest, a może to tylko wstępne zauroczenie (?).

Jak zacząć?

Najlepiej pobrać Ruby-ego i użyć interaktywnego interpretera IRB.

Co dalej? No oczywiście nie może zabraknąć HelloWorld:). Zacznijmy od C#:

public class HelloWorld
{
  public const string TypeOfHello = "Hello";

  public string SayHello(string name)
  {
    return TypeOfHello + string.Format(" {0}", name)
  }
}

a teraz to samo w Ruby:

class HelloWorld
  TYPE_OF_HELLO = 'Hello'
  def say_hello(name)
    TYPE_OF_HELLO + " #{name}"
 end
end

Porównajmy oba listingi kodu:

1. Składnia i notacja nazewnicza

Pierwsze co się rzuca w oczy to oczywiście różnice w składni. Kod Ruby-ego jest bardziej zwięzły brak tu wydaje się zbędnych znaków np. średników na końcu linii. Preferowana notacja nazewnicza dla klas to CamelCase, dla stałych (które nie do końca są stałymi, ale o tym może innym razem) wielkie litery z podkreśleniami, a dla pozostałych składników małe listery z podkreśleniami.  Ciągi znaków w Ruby możemy zapisywać z użyciem znaków cudzysłów jak i apostrof,  jednak są pewne różnice między tymi dwoma zapisami (o tym innym razem).

2. Hermetyzacja

W Ruby klasa i jej metody domyślnie są publiczne. Wyjątkiem od tej zasady są metody initialize (coś a’la konstruktor) oraz globalne metody zdefiniowane dla klasy Object. Jest to istotna różnica w porównaniu do C# gdyż tutaj klasa domyślnie jest internal, a jej „elementy składowe” są domyślnie prywatne.

3. Typy danych

W Ruby nie określa się jawnie typów danych – interpreter języka robi to za nas. Tu nie mogę nie wspomnieć o bardzo ważnej cesze języka Ruby, mianowicie Duck Typing. Jest to specyficzny sposób rozpoznawania typu obiektu na podstawie badania metod udostępnianych przez obiekt. Skąd taka nazwa? Pochodzi ona od stwierdzenia „jeśli chodzi jak kaczka i kwacze jak kaczka, to musi być kaczką”. Każdy obiekt w Ruby posiada metodę respond_to? która pozwoli nam określić czy obiekt posiada daną metodę, np. „Tekst”.respond_to?(„downcase”). W tym wypadku otrzymamy wynik true, a downcase to po prostu metoda zamieniająca znaki ciągu na małe litery.

4. Konkatenacja ciągów znaków

Jest taka jak w C#, tj. za pomocą znaku „+”. Inna ciekawa funkcjonalność to użycie ” #{name}” co oznacza, że ciąg #{name} zostanie zastąpiony wartością zmiennej o nazwie name. Zbliżone nieco do wywołania string.Format w C#, ale dużo bardziej zwięzłe.

5. Zwracanie wyniku metody

Hmm brak jakiegokolwiek return czy coś w tym rodzaju. Bo nie jest potrzebne! Aczkolwiek można użyć słowa kluczowego return opcjonalnie.

Jak  teraz instancjonować naszą klasę i wywołać metodę? W C# po prostu:

HelloWorld hw = new HelloWorld();
hw.SayHello("Bill Gates");

a w Ruby:

hw = HelloWorld.new
hw.say_hello('Yukihiro Matsumoto')

W tym wypadku też jest nieco zwięźlej.

Tyle na początek i do następnego razu z Ruby.

Blog na WordPress.com.