Aktywne Wpisy
m__b +108
Cześć Wykopowicze!
Od początku istnienia Wykopu staramy się, żeby to miejsce było wszystkich przestrzenią do swobodnej dyskusji, gdzie każdy z nas może wyrazić swoje zdanie bez obaw o cenzurę. To dla nas niezwykle ważne, bo to właśnie nasza niezależność sprawia, że Wykop jest takim wyjątkowym miejscem.
Jednocześnie, chcemy aby każdy mógł czuć się dobrze w przestrzeni jaką jest Wykop. Uważamy, że wolność człowieka kończy się tam, gdzie zaczyna się wolność drugiego człowieka. Dajemy każdemu swobodę wypowiedzi, ale zależy nam na tym, aby używane w dyskusji słowa nie raziły niczyich uczuć.
W związku z tym zdecydowaliśmy się wprowadzić pewne ograniczenia widoczności słów, które uważane są za kontrowersyjne. Mamy nadzieję, że dzięki temu, nawet najbardziej gorąca wymiana zdań nie sprawi, że ktoś poczuje się źle.
Od początku istnienia Wykopu staramy się, żeby to miejsce było wszystkich przestrzenią do swobodnej dyskusji, gdzie każdy z nas może wyrazić swoje zdanie bez obaw o cenzurę. To dla nas niezwykle ważne, bo to właśnie nasza niezależność sprawia, że Wykop jest takim wyjątkowym miejscem.
Jednocześnie, chcemy aby każdy mógł czuć się dobrze w przestrzeni jaką jest Wykop. Uważamy, że wolność człowieka kończy się tam, gdzie zaczyna się wolność drugiego człowieka. Dajemy każdemu swobodę wypowiedzi, ale zależy nam na tym, aby używane w dyskusji słowa nie raziły niczyich uczuć.
W związku z tym zdecydowaliśmy się wprowadzić pewne ograniczenia widoczności słów, które uważane są za kontrowersyjne. Mamy nadzieję, że dzięki temu, nawet najbardziej gorąca wymiana zdań nie sprawi, że ktoś poczuje się źle.
Wynoszony +22
Czy w twoim mieście, dzielnicy zieleń jest też tak zaniedbana jak na moim zdjęciu?
Czy miasto nie powinno czegoś z tym zrobić?
Nie da się w dwie osoby czasem normalnie przejść, albo w tym wypadku ta dzika łąka zasłania człowieka na przejściu dla pieszych.
#polska #warszawa #trojmiasto #wroclaw #poznan #krakow #lublin #szczecin #bialystok #
Czy miasto nie powinno czegoś z tym zrobić?
Nie da się w dwie osoby czasem normalnie przejść, albo w tym wypadku ta dzika łąka zasłania człowieka na przejściu dla pieszych.
#polska #warszawa #trojmiasto #wroclaw #poznan #krakow #lublin #szczecin #bialystok #
Część 1. Po kiego chu… grzyba, czyli co wyróżnia Rusta z pośród reszty.
Już jakiś czas temu napisałem wpis na Mirko gdzie porównywałem Rusta i parę innych "nowoczesnych" języków, tutaj się trochę rozpiszę i przy okazji dam małe wprowadzenie co i jak.
Rozdział 1. Niezmienność jest domyślna
W językach takich jak C, C++, C#, Java niezmienność jest wyborem. Wszystkie zmienne są w domyśle mutowalne. Ma to swoje zalety jako, że nasz mózg przyzwyczajony jest do tego iż zmienną można zmieniać od momentu jej powstania. Jest parę języków, które tego nie wspierają i są to głównie języki funkcyjne (z wyjątkiem - Scalą). W Ruscie to, że zmienna ma być mutowalna jest kwestią wyboru, nie na odwrót.
Przykład:
let a = 10;
a = 20; // błąd
let mut a = 10; // absolutnie legalne w Ruscie, można przesłonić zmienną w tym samym bloku
a = 20; // OK
Takie założenie pozwala w teorii kompilatorowi na trochę większą optymalizację kodu, a dodatkowo wymusza lepsze przemyślenie programu przez programistę.
Rozdział 2. Bezpieczeństwo pamięci
Do dnia dzisiejszego były 2 wybory jeśli chodziło o zarządzanie pamięcią w programie (jeśli się mylę to niech ktoś mnie oświeci a odszczekam):
+ ręczne - uciążliwe z wiadomych powodów: łatwo o wyciek, słabo współpracuje z wątkami i wyjątkami, dość niebezpieczne (patrz GHOST/Heartbleed)
+ GC - wygodne, ale problemy z wydajnością (global lock przy załączeniu się czyszczenia) czy wielowątkowością (jak uruchomić GC na wielowątkowym procesie)
Świętym Graalem hakerów było jednoczesne uzyskanie wydajności i "niskopoziomowych" zabawek przy jednoczesnym zapewnieniu bezpieczeństwa pamięci. C++11 jako tako próbuje sobie z tym poradzić przy pomocy nowych *inteligentnych*
(inaczej) wskaźników jednak ma to ten problem, że wymaga dalej uwagi programisty (trzeba ręcznie pozmieniać wszystkie wskaźniki na te wynalazki) oraz słabo współpracuje z istniejącymi bibliotekami.
Rust wpadł na rozwiązanie: lifetime. Jest to dodatkowy atrybut przypinany do każdej referencji, który określa kiedy kończy się "czas życia" zmiennej. Ten system pozwala na określenie w czasie kompilacji czy istnieje możliwość, by dana referencja wskazywała na zwolnioną pamięć.
Zagadka: Czy dany program w C++ jest poprawny?
#include
#include
int main() {
std::vector vec{};
vec.pushback(42);
int& ref = vec[0];
vec.pushback(69);
std::cout << ref;
}
Odpowiedź i wyjaśnienie (o ile nie będzie w komentarzach) przeczytacie w kolejnej części, gdzie postaram się przybliżyć lifetime i resztę zarządzania pamięcią z Rusta.
Rozdział 3. Typowanie
Typy w językach kompilowanych są dość istotną sprawą - w końcu zapewniają nam bezpieczeństwo kodu. Nie inaczej jest w Ruscie. Z pewnymi wyjątkami.
Wyjątek 1 - naprawdę silne typowanie.
C czy C++ mimo iż mają namiastki silnego typowania to są absolutnie szczęśliwe w przypadku takiego kodu (nie ma nawet upomnienia):
#include
int main() {
int a = 10;
unsigned int b = a;
printf("%d\n", b);
return 0;
}
Czemu brak upomnienia jest tutaj zły? Bo ani C ani C++ nie określają w jaki sposób obsłużyć moment kiedy
a < 0
. Możliwe, że większość z was teraz mi powie, że U2, ale standard nigdzie nie zapewnia, że liczby mają być kodowane w U2. Mogąbyć zakodowane w dowolny sposób. Rust nie dopuści do takiej profanacji, co więcej, nie dopuści nawet do sytuacji, która w teorii nie jest szkodliwa:
fn main() {
let a: i64 = 10;
let b: i32 = a; // błąd kompilacji, mimo iż w teorii nie tracimy żadnych
// danych (standard zapewnia kodowanie U2)
println!("{}", b);
}
Wyjątek 2 - system typów Henleya-Milnera.
Jest to taki sam system typów jak w np. Haskellu. Czym on się różni od
auto
(C++) lubvar
(C#/Scala)? Ano tym, że w przypadku tamtych języków typ jest definiowany w miejscu, tzn. że w momencie deklaracji cały typ zmiennej musi być znany.Przykład (tym razem C#):
var list = new List();
list.Add(10);
list.Add(20);
Gdzie
T
musi być znane w momencie wywołania tej linii. Kompilator nie potrafi sam "wydedukować" typu zmiennej.Przykład w Ruscie:
let mut vec = Vec::new(); // nie określamy typu zmiennych w wektorze
vec.push(10); // tutaj jest on określany jako typ całkowity
vec.push(20);
println!("{:?}", vec); // => [10, 20]
// z racji, że nie ma dokładnego określenia jaki to ma być typ zmiennej całkowitej
// to kompilator przyjmuje, że jest to
isize
czyli domyślny typ całkowitoliczbowy// dla danej platformy
Typy zmiennych są dedukowane w czasie kompilacji na bazie całego życia zmiennej. W ten sposób programista nie musi się martwić wyjątkiem 1. (w większości przypadków).
Rozdział 4. Brak dziedziczenia i system
traits
ówRust nie wspiera dziedziczenia. Jakiegokolwiek. W dowolnej postaci. Kropka.
Zawsze można użyć kompozycji.
W zamian mamy system traitsów, który jest formą interfejsów (i działa podobnie jak w Scali). By się nie rozpisywać, przykładzik:
struct Foo(u32); // Struktura zawierająca tylko 1 anonimowe pole o typie
u32
impl Add for Foo { // operator +
type Output = Foo;
fn add(self, other: Foo) -> Foo {
let Foo(this) = self;
let Foo(other) = other;
Foo(this + other) // (prawie) każde wyrażenie w Ruscie zwraca wartość, brak
;
na końcu funkcji oznacza, że to jest wartość zwracana}
}
println!("{:?}", Foo(10) + Foo(20)); // => Foo(30)
Rozdział 5. Pattern matching, typy wyliczeniowe, monady i obsługa błędów
Jeśli ktoś z was bawił się kiedyś językami funkcyjnymi to jest świadomy opcji pattern matchingu w takowych językach. Jest to swoistego rodzaju odpowiednik bloku
switch
dla ludzi z C/C++. Przykładenum Foo {
Bar,
Baz(u32) // w Ruscie typy wiliczeniowe mogą nieść wartość (mogą być monadami)
}
let a = Foo::Baz(10);
match a {
Foo::Bar => println!("Take me to the Gay Bar"),
Foo::Baz(val) => println!("Nuke Bar with {} nukes", val)
};
Z racji, że Rust nie posiada wyjątków obsługa błędów jest obsługiwana przez monadę
Result
:let num = -1.0;
let sqrt = match num.sqrt() {
Ok(val) => val,
Err(err) => panic!("{}", err)
}
Epilog części 1.
To by było chyba na tyle. Najważniejsze różnice zostały przedstawione. Oczywiście, z racji, że Rust jest mocno funkcyjny, nie mogło w nim zabraknąć lambd, ale to omówię innym razem (najprawdopodobniej a propos wielowątkowości).
#programowanie #rustlang #naukaprogramowania
Ciąg dalszy będzie pod tagiem #haulethuczyrusta
I wołam zainteresowanych @Acrene, @siepet, @yonah, @kuhar, @pp555, @sosnnaa, @kao3991, @tytyryty, @Aysorth, @Felonious_Gru, @Existanza, @kornik20082, @GlenPL, @notauser, @Analityk, @mpisz, @Seima, @Pietrek558, @gress
Jak kogoś zapomniałem to trudno.
potem przeczytam, może nawet spróbuję ( ͡°( ͡° ͜ʖ( ͡° ͜ʖ ͡°)ʖ ͡°) ͡°)
@Hauleth:
implementation defined
;)N3797, §4.7/2 [conv.integral]
:tl;dr: dodajesz lub odejmujesz 2^bitów tyle razy aƶ wejdziesz w zakres unsigned typu.
Standard
Co do liczb, to rzeczywiście, zwracam honor. C++ musiał jak zwykle s--------ć.
O "braku dziedziczenia" rozpiszę się później i wtedy dasz znać czy to taka wada. Bo rozwiązane jest to na tyle sprytnie, że ciężko to uznać za wadę ;) Chyba, że opiszesz, czemu to aż taka wada.
@dziedziczenie: jutro opiszę mój use-case, moƶe źle na to patrzę i moƶna to ładniej zrobić (inna sprawa, ƶe nie wiem jak to wygląda w ruście, więc moƶe faktycznie jest dostatecznie sprytne)