Rust 1.0.0-alpha

6

Zacznę od zacytowania Niklausa Wirtha:

I would love to see somebody tackle the challenge of demonstrating that you can create a portable systems language (meaning that it has performance equal to C, C++, Fortran) that is portable, type safe, and also memory safe. To add that on top of classes and templates and the portability of C, to add strong type safety (which requires a form of garbage collection) and not leave performance on the table – that would be something.

No i można powiedzieć, że wszystkie te "cele" są w trakcie realizacji przez Rusta. Oczywiście wiąże się to z pewnymi kosztami:

  • nie jest to język dla początkujących (mimo w miarę intuicyjnych podpowiedzi kompilatora)
  • lifetime i ownership potrafi przysporzyć trochę problemów nawet bardziej zaawansowanym programistom
  • jak na razie dość długie czasy kompilacji
  • mocne typowanie potrafi przysporzyć problemów (np. fn add2<T>(a: T) -> T where T: Float { a + 2.0 } nie zadziała, trzeba użyć [o zgrozo] fn add2<T>(a: T) -> T where T: Float { a + cast(2.0).unwrap() }, jednak mam nadzieję, że to niedługo poprawią)
  • łatwo napisać kod, który niespecjalnie będzie wydajny, przez multum wywołań clone

Jednak w przeciwieństwie do innych ostatnio "nowych" języków (jak Go czy D) ma wiele usprawnień:

  • brak null, zamiast tego mamy enum, który działa podobnie jak type w Haskellu
  • proste FFI
  • bezpieczeństwo pamięci w czasie kompilacji (brak GC)
  • wbudowane wsparcie dla wielowątkowości i SIMD
  • typy Hindley-Milner'a, przy których auto z C++ jest śmieszne
  • aktywne budowanie społeczności już w czesnych stadach rozwoju (via Reddit, Discourse i Cargo - manager paczek i build tool)
  • szybkość (wiadomo, idealnie nie jest, ale patrząc na wersję języka to i tak można powiedzieć, że jest nieźle)
  • brak dziedziczenia, w zamian dostajemy system traits, który działa podobnie jak w Scali
  • szablony z constraintsami
  • makra składniowe i rozszerzenia kompilatora (zaczerpnięte z Lispów)
  • wbudowane krotki
  • destructive assignment
  • immutability by default
  • pattern matching

Hello World (bo być musi, potem napiszę jakiś dłuższy przykład):

fn main() {
  println!("Hello World!");
}

Co o tym sądzicie? Ma ten język szansę na zajęcie swojego miejsca w niszy gdzie teraz jest C/C++? IMHO ma szansę na ograniczenie roli C++, bo C zawsze będzie jako uniwersalny język do FFI.

Materiały:

1

Opis wygląda zachęcająco. Pobawię się tym językiem przy wolnej chwili i napiszę później jakie mam spostrzeżenia.

0

Koncepcje mają fajne, ale bez dziedziczenia (i interfejsów) to ja temu projektowi nie wróżę długiej kariery.
No i jeśli nie null to powinien być przynajmniej jakiś optional:
http://docs.oracle.com/javase/8/docs/api/java/util/Optional.html

Szczerze mówiąc to przydałby mi się jakiś język do HPC który by nie wymagał stosowania 5-ciu paradygmatów (C++), byłby spójny (trochę jak Java) i nie okraszony setką słów kluczowych (C#).

2

To coś jest nawet mniej czytelne niż C++. Już nawet podstawowe typy są całkowicie nieczytelne. To spore osiągnięcie. Wymyślił to chyba jakiś miłośnik skrótów, który dalej myśli, że pracujemy na terminalach z 80 znakami w wierszu. fn i8, str, pub, wtf?

Tu jest jeszcze kilka setek innych epokowych wynalazków: http://en.wikipedia.org/wiki/List_of_programming_languages Tylko jakoś... nie wyszło im. Z tym będzie tak samo, jak z każdym innym od dawna. Ja nie jestem przekonany, czy potrzebujemy 6 nowych, nikomu niepotrzebnych, przełomowych języków na rok. Nie prościej się skupić na ewolucji tych, które już są? Wiadomo, że nie można mieć jednego języka do wszystkiego. Ale wydaje się, że mamy już kilka (-naście?), które pokrywają zdecydowaną większość potrzeb. Reszta to egzotyka. :-)

xkcd napisał(a)

Situation: There are 14 competing standards.
Cueball: 14?! Ridiculous! We need to develop one universal standard that covers everyone's use cases.
Ponytail: Yeah!
Soon:
Situation: There are 15 competing standards.
(http://xkcd.com/927/)

PS. Tak, jestem pesymistą. Tak, jestem marudą. :-P

0

@Endrju tylko problem polega na tym, że jak Ruby i Python są w większości wobec siebie redundantne, Go vs OCaml też można by tak określić. Jednak Rust wprowadza parę konceptów do programowania systemowego, o których nikt wcześniej nie myślał (pattern matching i HMTS). Choćby to może spowodować pewne zainteresowanie. Co do typów to trochę się zgodzę, ale nie do końca. IMHO zbytnio różnicy między uint32 a u32 nie ma, zwłaszcza jak masz podświetlanie składni. Kolejną rzeczą jest to iż nie za często używa się typów, bo w większości przypadków kompilator sam potrafi określić potrzebny typ (poza deklaracją funkcji praktycznie się tego nie używa).

vpiotr napisał(a):

Koncepcje mają fajne, ale bez dziedziczenia (i interfejsów) to ja temu projektowi nie wróżę długiej kariery.
No i jeśli nie null to powinien być przynajmniej jakiś optional

Ma typ Option. Jest on zdefiniowany mniej więcej tak:

pub enum Option<T> {
  Some(T),
  None
}

I jest używany np. w iteratorach (iteracja trwa tak długo, aż nie zostanie zwrócone None).

Co do "interfejsów" to są traitsy, które działają w taki sam sposób, i.e.:

trait Foo {
  fn foo(&self);
}

struct Boo;

impl Foo for Boo {
  fn foo(&self) {
    println!("Boo#foo");
  }
}

Kolejną rzeczą, o której zapomniałem jest brak wyjątków. Zamiast tego mamy kolejny typ wyliczeniowy (monadę) Result:

enum Result<T, E> {
  Ok(T),
  Err(E)
}

I dzięki pattern matchingowi mamy emulowany try {} catch() {}:

fn try(i: i32) -> Result<i32, String> {
  if i < 0 {
    Err("Less than 0")
  } else {
    Ok(i)
  }
}

let val = match try(10) {
  Ok(v) => v,
  Err(s) => {
    println!("{}", s);
    0
  }
};

assert_eq!(val, 10);

let val = match try(-10) {
  Ok(v) => v,
  Err(s) => {
    println!("{}", s);
    0
  }
};

assert_eq!(val, 0);
0

Krótkie słowa kluczowe (no może nie aż tak krótkie) to nie nowość: let, var, def, dim - to już gdzieś tam było.
Dwu-literowe może same w sobie nie są trudne do zrozumienia, tylko raczej łatwe do przeoczenia.

0

@vpiotr w Ruscie IMHO nie ma z tym problemu, bo dwuliterowych słów kluczowych używa się praktycznie tylko w deklaracjach funkcji. W pozostałych przypadkach dobrą praktyką jest pomijanie typów tam gdzie mogą być rozpoznane przez kompilator, więc nie za często się spotyka te słowa.

2

Krótkie nazwy typów znacznie utrudniają stosowanie dwuznakowych nazw zmiennych.
Chyba już wiemy, komu ten język najbardziej się nie spodoba. ;)

3

Rust ma jeden killer feature, którego nie ma nic innego: bezpieczeństwo pamięci bez GC. Natomiast jeśli chodzi o funkcyjnosc czy wygodę programowania, to raczej ze Scalą nie ma szans, ale to inne zastosowania
.

0

Myślę, że będzie jak z każdym innym językiem, czyli będą narzędzia/frameworki/biblioteki to i znajdzie się ktoś kto będzie tego używał.

0
winerfresh napisał(a):

Kolejną rzeczą, o której zapomniałem jest brak wyjątków. Zamiast tego mamy kolejny typ wyliczeniowy (monadę) Result:

enum Result<T, E> {
  Ok(T),
  Err(E)
}

I dzięki pattern matchingowi mamy emulowany try {} catch() {}:

fn try(i: i32) -> Result<i32, String> {
  if i < 0 {
    Err("Less than 0")
  } else {
    Ok(i)
  }
}

let val = match try(10) {
  Ok(v) => v,
  Err(s) => {
    println!("{}", s);
    0
  }
};

assert_eq!(val, 10);

let val = match try(-10) {
  Ok(v) => v,
  Err(s) => {
    println!("{}", s);
    0
  }
};

assert_eq!(val, 0);

Skoro jest monada Result, to czy jest do tego jakieś do-notation? Co jeśli wywołam w jednej funkcji po kolei kilka funkcji, które mogą rzucać wyjątki i nie chcę tych wyjątków zignorować, a np obsłużyć gdzieś wyżej w hierarchii wywołań? Jak będzie wyglądał kod?

0

map, a jeśli to nie styka to zawsze można napisać własne makro, które to obsłuży. Na razie najpopularniejszą metodą jest używanie unwrap, które panikuje w momencie wywołania na obiekcie, z którego nie da się wyłuskać wartości lub makro try!, które zwraca wartość lub wywołuje return Err(e) jeśli się nie powiedzie.

type MyResult<T> = Result<T, String>;

fn foo(i: i32) -> MyResult<i32> {
  if i < 0 {
    Err("Less than 0".to_owned())
  } else {
    Ok(i)
  }
}

fn try_example(i: i32) -> MyResult<i32> {
  let a = try!(foo(i)); // Równoważne zapisowi
  // let a = match foo(i) {
  //   Ok(x) => x,
  //   Err(x) => return Err(x)
  // };

  Ok(a + 10)
}

fn map_example(i: i32) -> MyResult<i32> {
  foo(i).map(|x| -x)
}

fn unwrap_example(i: i32) -> i32 {
  let a = foo(i).unwrap(); // wywoła makro `panic!` z wartością `Err(x)` jeśli `foo(i)` zwróci `Err`

  a - 10
}

Jeśli by chodziło o dokładne naśladowanie do notation to jest https://github.com/TeXitoi/rust-mdo

PS są jeszcze inne metody jak np. unwrap_or, opis w dokumentacji

0

C i C++ prawdopodobnie nigdy nie umrze, ponieważ jest dużo softu w tym napisanego i nie da się tego od tak wyrzucić przez okno.

Ale czy myślicie, że pojawi się jakiś nowy gracz, który sprawi, że od X momentu zacznie się w nim pisać, nowe projekty?
Mam na myśli miejsca gdzie wymaga się low level, high performance itp.

Póki co to chyba tylko Rust jako tako odpowiedzieć na podobne problemy co C i C++.
Mimo to każdy nowy język może zaliczyć faila z powodu braku marketingu, niezależnie jaki bylby dobry.

1

C nie umrze. Nie znam nikogo, kto by twierdził inaczej. Za to C i Rust są bardzo dobrą parą, IMHO znacznie lepszą niż tandem C/C++.

Osobiście jednak marzy mi się świat bez C++. Byłby znacznie piękniejszy.

Co do marketingu, to Rustowi idzie całkiem nieźle:

Poza tym powstaje całkiem sporo ciekawych projektów, które przyciągają uwagę społeczności:

  • Glium - bezpieczny wrapper na OpenGLa. Szybkość: szybszy od większości kodu pisanego w C, wolniejszy o ok 10-15% niż na maksa wyśrubowany kod w C, ale za to działa za pierwszym podejściem (większość błędów jest wyłapywana już w czasie kompilacji)
  • ring - bezpieczny wrapper na BoringSSL z fragmentami przepisanymi do Rusta
  • mio - Event Loop

Wydajnościowo też sobie radzi całkiem nieźle (yay, microbenchmarking):

I mówimy tu o języku, który na rynku jest (na chwilę obecną) 9 miesięcy (wersja 1.6.0), nie posiada wszystkich oczekiwanych features w wersji stabilnej (np. SIMD), która jest wersją testowaną w Benchmark Game, ani nie posiada na maksa wyśrubowanych programów testowych. Dodatkowo jak BurntSushi tylko wykombinuje jak zrobić, by makro regex! osiągało taką samą wydajność jak Regex::new (zapewne przyjdzie nam poczekać aż rozszerzenia kompilatora staną się stabilne) to część benchmarków wyciśnie parę dodatkowych procent.

0

Dzieki za fajny post. Faktycznie, C po prostu nie moze umrzec ;] Jesli bedzie apokalipsa kiedys to zycie powstanie na nowo dzięki C ;)
Faktycznie jak na tak mlody język to wyglada, ze radzi sobie bardzo dobrze. I swietnie, ze jakas duza firma placi za jego rozwoj.
Wiec moze cos Rust zawojuje.

0

Tylko jedno pytanie. Jakie myslisz beda glowne use casy dla Rust?

4

TL;DR Jeśli chcesz zacząć pisać nowy, niskopoziomowy kod, to wybierz Rusta.

Czyli w skrócie: wszędzie tam gdzie do tej pory używano C/C++ to będzie można w większości zastąpić Rustem.

0

Haiku OS jest pisany w C++, ale Linus Torvalds powiedział że jądro Linux nie będzie pisane w C++ ponieważ wie jakie w nim ludzie potworki z kodu potrafią tworzyć.
Co tam jeszcze zostało z kompilowanych języków poza C, C++ i Pascal, jedynie ten Rust i D. Są systemy pisane w Asemblerze i nawet w Javie.

1

Krzywy Młot, twoja wypowiedź ma czemuś dowieść? Bo nie rozumiem jej znaczenia w dyskusji?

Co do języków kompilowanych to oprócz wymienionych masz jeszcze Nim, Scheme, Crystal, Fortran, Ada, Eiffel, Go, OCaml, Haskell, Objective-C, Swift, ALGOL i pewnie parę bardziej ezoterycznych by się znalazło.

0

Dziś wyszło już wydanie stabilne 1.7.0 :)

0

A jak się ma sprawa rust vs go?

0
Wybitny Orzeł napisał(a):

A jak się ma sprawa rust vs go?

Te dwa języki mają kompletnie różne zastosowania, więc nijak.

0

To fajnie.
Czyli w sumie Rust wydaje się czymś wyjątkowym w ostatnich latach.

1 użytkowników online, w tym zalogowanych: 0, gości: 1