Ruby 2.4: ujednolicony Integer i szybsze hashe
Ruby 2.4.0 przybywa w Boże Narodzenie z dawno spóźnionym porządkiem — Fixnum i Bignum scalone w jeden Integer — plus szybszy Hash, Enumerable#sum, Regexp#match? i binding.irb. Praktyczny przegląd.
Ruby 2.4.0 przybyło zgodnie z planem na Boże Narodzenie i jest wydaniem z satysfakcjonującą mieszanką dawno spóźnionego porządku i cichej pracy nad wydajnością. Nagłówkiem jest uproszczenie, które docenisz koncepcyjnie, nawet jeśli mało zmienia w twoim kodzie, a pod nim są realne przyspieszenia i garść naprawdę użytecznych nowych metod. Oto przegląd.
Fixnum i Bignum stają się Integer
Przez całą swoją historię Ruby miało dwie klasy liczb całkowitych: Fixnum dla małych
liczb mieszczących się w słowie maszynowym i Bignum dla większych, z Ruby przezroczyście
promującym między nimi. Rzadko zauważałeś — 2 + 2 i 10**100 po prostu działały — ale
podział był przeciekającą abstrakcją, która czasem wychodziła w mylące sposoby (klasa
wartości zmieniająca się, gdy rosła, sprawdzenia is_a?(Fixnum) psujące się na dużych
liczbach). 2.4 ujednolica je w pojedynczą klasę Integer:
1.class # => Integer (było Fixnum)
(10**100).class # => Integer (było Bignum)
Zachowanie jest identyczne — Ruby wciąż używa wydajnej reprezentacji wewnętrznie dla małych
liczb — ale model koncepcyjny jest teraz czysty: liczba całkowita to Integer, kropka.
Fixnum i Bignum pozostają jako deprecjonowane aliasy, by stary kod się nie psuł, ale
właściwym modelem myślowym i właściwą rzeczą do odwoływania się jest teraz po prostu
Integer. To rodzaj porządku, który czyni język łatwiejszym do nauczania i ogarniania,
usuwając rozróżnienie, które nigdy nie powinno być widoczne dla użytkowników.
Szybsze hashe
Hashe są wszędzie w Ruby — opcje, JSON, każdy argument nazwany, wnętrzności samego języka — więc uczynienie ich szybszymi to szeroka wygrana. Ruby 2.4 przerabia implementację Hash, by używała otwartego adresowania, bardziej przyjaznej dla cache struktury wewnętrznej poprawiającej wydajność wyszukiwania i wstawiania, zwłaszcza dla małych-do-średnich hashy dominujących w realnym kodzie. Nie zmieniasz nic, a twój mocno hashowy kod robi się szybszy, co na typowym żądaniu Rails — zbudowanym na górze hashy — jest darmową, szeroką poprawą dokładnie tego rodzaju, który czyni aktualizację wartą jej.
Enumerable#sum: nareszcie
Mały dodatek usuwający maleńkie codzienne tarcie. Sumowanie kolekcji oznaczało kiedyś
inject(:+) albo reduce(0, :+) — w porządku, ale lekko zagadkowe i wolniejsze, niż
musiało być. 2.4 dodaje porządne Enumerable#sum:
[1, 2, 3, 4].sum # => 10
items.sum(&:price) # => łączna cena
[1.0, 2.0].sum(100) # => 103.0 (z wartością początkową)
Czyta się lepiej i jest zaimplementowane w C, więc jest szybsze niż inject, który
zastępuje. Trywialna metoda, po którą mimo to będziesz sięgać nieustannie.
Regexp#match? : szybsze dopasowanie boolean
Gdy chcesz tylko wiedzieć, czy łańcuch pasuje do wzorca — nie przechwytując niczego —
stare idiomy (=~, match) wykonują dodatkową pracę: ustawiają globalne zmienne
dopasowania ($~, $1, …) i alokują obiekt MatchData. Regexp#match? po prostu zwraca
boolean i nie robi nic z tego:
if /\A\d+\z/.match?(input) # bez alokacji MatchData, bez ustawiania globali
# ...
end
W gorącej pętli albo walidacji uruchamianej na każdym żądaniu pominięcie alokacji i księgowości zmiennych globalnych to mierzalna oszczędność. To właściwe narzędzie, ilekroć chcesz odpowiedzi tak/nie, a nie szczegółów dopasowania.
binding.irb: REPL gdziekolwiek
Urocze dodanie do debugowania. Możesz teraz wrzucić binding.irb do swojego kodu, by
otworzyć pełną sesję IRB w tym punkcie, z dostępem do wszystkich zmiennych lokalnych — jak
binding.pry z popularnego gemu, ale wbudowane w samo Ruby:
def calculate(order)
binding.irb # wykonanie zatrzymuje się tu; inspekcjonuj `order` interaktywnie
# ...
end
Nie jest tak bogate w funkcje jak Pry, ale posiadanie prawdziwego REPL-w-breakpoincie w bibliotece standardowej, bez gemu do dodania, jest naprawdę użyteczne — zwłaszcza w środowiskach, gdzie wolałbyś nie dodawać zależności tylko po to, by pogrzebać w wartości.
Mniejsze dodatki
Dopełniając wydanie: Comparable#clamp ogranicza wartość do zakresu (n.clamp(0, 100)); Integer#digits zwraca cyfry liczby jako tablicę (123.digits →
[3, 2, 1]); String#unpack1 zwraca tylko pierwszą rozpakowaną wartość zamiast
tablicy; i są udoskonalenia Float#round oraz obsługi wielkości liter (w tym lepsze
mapowanie wielkości Unicode). Niedramatyczna runda deprecjacji trwa jak zwykle.
Czy aktualizować?
Tak — to niskoryzykowne, szeroko korzystne wydanie. Ujednolicenie Integer jest głównie
koncepcyjne i wstecznie zgodne (aliasy trzymają stary kod działającym), więc nic cię nie
kosztuje i porządkuje model myślowy. Szybsze hashe to darmowa, szeroka wygrana wydajności
dla dowolnego programu Ruby, podwójnie dla mocno hashowych aplikacji Rails. A nowe metody —
sum, match?, clamp, binding.irb — to małe usprawnienia ergonomii, które przyjmiesz
naturalnie, pisząc kod.
Wzorzec ostatnich wydań Ruby trzyma się stabilnie: posprzątaj brodawkę, która nigdy nie powinna być widoczna, uczyń wspólne struktury danych szybszymi za darmo i dodaj kilka ostrych metodek, które czynią codzienny kod lepiej czytelnym. 2.4 to nieefektowna, łatwa aktualizacja — najlepszy rodzaj.