LINUX.ORG.RU

«Rust by Example» и «Rust for C++ programmers»

 


6

9

Привет лор. Это опять я и опять с Ржавчиной, точнее с парочкой ссылок по этой теме :) .

http://rustbyexample.com - изучение языка на основе очень коротких примеров с минимумом комментариев (очевидно влияние gobyexample.com).

Rust for C++ programmers - постепенно растущий цикл статей для С++ программистов.

На данный момент 7 статей:

Вооот, вдруг кто из интересующихся Ржавчиной пропустил эти две прекрасные ссылки. На первый взгляд, примеры по обоим ссылкам должны собираться ночной сборкой компилятора Ржавчины.

P.S.: и между делом упомяну, что все-таки решили добавить оптимизацию хвостовых вызовов, но уже после выпуска стабильной версии:

Rust, tail call optimization (комментарий)


И вот ещё — http://www.reddit.com/r/rust ;)

специально для лоровцев «Нафигааа?!»

C++: Java, Scala, Haskell, Python

По идее верно, то есть Rust в этом смысле ближе к C++ (D?), но, например, http://benchmarksgame.alioth.debian.org/u64q/code-used-time-used-shapes.php (Python разве что где-то там).

memory leaks, accessing un-initialised memory, dangling pointers - all are impossible in Rust

В unsafe наверно возможно? В C++ нет unsafe, но там есть my_composable_things_for_dummies::.

all array indexing is bounds checked

container::at тоже проверяет.

The `println!` macro is safer than printf - the number of arguments is statically checked against the number of 'holes' in the string and the arguments are type checked.

Нынешние компиляторы (не говоря уж про статический анализ) разве не делают эти же проверки для printf?

quasimoto ★★★★
()
Ответ на: комментарий от nanoolinux

закопаться! ...

Это же выражение радости, а не приказ, да?

Вообще здорово, конечно, что llvm развивается.

ozkriff
() автор топика
Ответ на: комментарий от quasimoto

Нынешние компиляторы (не говоря уж про статический анализ) разве не делают эти же проверки для printf?

Если я делаю новую функцию (или макрос), аналогичную printf в том, что тип параметров задаётся форматной строкой, но другую, то в Rust я смогу написать свою проверку, а в плюсах не получится.

anonymous
()

и между делом упомяну, что все-таки решили добавить оптимизацию хвостовых вызовов

Хорошо. А с дефолтной иммутабельностью что-то надумали делать?

DarkEld3r ★★★★★
()
Ответ на: комментарий от quasimoto

Нынешние компиляторы (не говоря уж про статический анализ) разве не делают эти же проверки для printf?

Во первых, не обязаны. Во вторых, всё-таки не все «современные» это делают. В третьих, ошибка лучше предупреждения.

DarkEld3r ★★★★★
()
Ответ на: комментарий от quasimoto

И вот ещё — http://www.reddit.com/r/rust ;)

Это само собой

C++: Java, Scala, Haskell, Python

По идее верно, то есть Rust в этом смысле ближе к C++ (D?), но, например, http://benchmarksgame.alioth.debian.org/u64q/code-used-time-used-shapes.php (Python разве что где-то там).

Чего-то я не понял твою мысль.

В unsafe наверно возможно?

Там вообще много чего возможно, на то он и unsafe.

container::at тоже проверяет.

Да, но компилятор С++ не запретит тебе пользоваться обычными массивами и адресной арифметикой. Это просто пример того, что в Ржавчине проще писать безопасный код и компилятор тебе больше помогает в этом, пока ты его не заткнешь _явным_указанием_ unsafe-а.

Нынешние компиляторы (не говоря уж про статический анализ) разве не делают эти же проверки для printf?

Многие делают, но это костыль все-таки. Плюс это не работает с другими штуками, использующими форматную строку, как написал аноним.

ozkriff
() автор топика
Ответ на: комментарий от DarkEld3r

А с дефолтной иммутабельностью что-то надумали делать?

Я пока не видел публичных заявлений по этому поводу. Наверное, читают потихоньку тонны ненависти и предложений, которые народ вывалил в реддит, и размышляют.

ozkriff
() автор топика

Еще на днях увидел интересный макрос bindgen!, который парсит хедер и тут же прямо генерирует соотвествующий rust код :)

https://github.com/crabtw/rust-bindgen/pull/81

Пример использования:

#[allow(dead_code, uppercase_variables, non_camel_case_types)]
mod bindings {
    bindgen!("header.h", "another_header.h", allow_bitfields=true, link="somelib"
             match="file.h", abi="C", allow_unknown_types=false, emit_builtins=false,
             clang_args="-I /usr/local/include")
}
ozkriff
() автор топика
Ответ на: комментарий от ozkriff

Лор такой лор. Всё поймёт по своему )) Уже и порадоваться нельзя.

nanoolinux ★★★★
()
Ответ на: комментарий от ozkriff

Чего-то я не понял твою мысль.

Если это было как <any-language> for C++ programmers, то ок, для какого-то класса задач. Если это «вместо», то есть как замена C++ для системного и прикладного программирования — тогда бы я ожидал увидеть его на шутауте рядом с C++ (это типа как минимум — должен позволять так писать). * Реализацию рядом с реализацией, разумеется.

Да, но компилятор С++ не запретит тебе пользоваться обычными массивами и адресной арифметикой.

Это как-то в сторону психологии и стиля — никто же не запрещает не пользоваться обычными массивами и адресной арифметикой.

Многие делают, но это костыль все-таки. Плюс это не работает с другими штуками, использующими форматную строку, как написал аноним.

В плюсах тоже есть возможность делать вещи типа http://www.boost.org/doc/libs/1_55_0/libs/format/doc/format.html.

Это просто пример того, что в Ржавчине проще писать безопасный код и компилятор тебе больше помогает в этом, пока ты его не заткнешь _явным_указанием_ unsafe-а.

Ок, наверно тут надо пробовать, а не обсуждать :)

quasimoto ★★★★
()
Последнее исправление: quasimoto (всего исправлений: 1)
Ответ на: комментарий от quasimoto

тогда бы я ожидал увидеть его на шутауте рядом с C++

Я посмотрел результаты на шутауте - самые большие проигрыши Си++ за счет bigint и неиспользования векторизации.

это типа как минимум — должен позволять так писать

Как «так»?

В плюсах тоже есть возможность делать вещи типа http://www.boost.org/doc/libs/1_55_0/libs/format/doc/format.html.

В плюсах Тюринг-полные шаблоны - на них можно сделать вообще всё. Даже вышеприведенный макрос bindgen.

tailgunner ★★★★★
()
Ответ на: комментарий от quasimoto

В плюсах тоже есть возможность делать вещи типа http://www.boost.org/doc/libs/1_55_0/libs/format/doc/format.html.

На этапе компиляции бустовый формат не проверяет форматную строку.

Это как-то в сторону психологии и стиля — никто же не запрещает не пользоваться обычными массивами и адресной арифметикой.

Не могу согласиться. Такими темпами можно дойти до динамически типизированных языков - «при должной аккуратности и наличии тестов» там тоже «никаких проблем нет». В общем, разница в том насколько легко написать код, который скомпилится (как вариант - не выдаст предупреждений), но потом всё завалит.

DarkEld3r ★★★★★
()
Последнее исправление: DarkEld3r (всего исправлений: 1)

есть подозрение, что кроме мозиллы, он нигде не будет использоваться

kto_tama ★★★★★
()
Ответ на: комментарий от tailgunner

http://github.com/mozilla/rust/blob/master/src/test/bench/shootout-pidigits.rs — num::bigint::BigInt.

http://benchmarksgame.alioth.debian.org/u64q/program.php?test=pidigits&la... — gmpxx.

Большие числа и отсутствие векторизации в обоих случаях.

(http://benchmarksgame.alioth.debian.org/u64q/program.php?test=pidigits&la... :))

http://github.com/mozilla/rust/blob/master/src/test/bench/shootout-mandelbrot.rs — не вижу больших чисел, вижу simd (future).

http://benchmarksgame.alioth.debian.org/u64q/program.php?test=pidigits&la... — sse (openmp).

https://github.com/mozilla/rust/blob/master/src/test/bench/shootout-k-nucleot... — future/spawn, hash table implementation.

http://benchmarksgame.alioth.debian.org/u64q/program.php?test=knucleotide&amp... — future/async, __gnu_pbds::cc_hash_table.

Но эта — в основном дереве же, пусть пишут «так» и догоняют хацкель :)

quasimoto ★★★★
()
Последнее исправление: quasimoto (всего исправлений: 1)
Ответ на: комментарий от quasimoto

num::bigint::BigInt.

gmpxx.

Спасибо, Капитан, я говорю именно об этом.

Большие числа и отсутствие векторизации в обоих случаях.

Кхм. Итак, Rust позорно слил 2 бенчмарка: pidigits и n-body; один из них - на gmp, другой - на векторизации. Остальные сливы вполне ожидаемы от компилятора языка, находящегося в стадии проектирования.

Но эта — в основном дереве же, пусть пишут «так» и догоняют хацкель :)

ЯННП, ну да ладно.

tailgunner ★★★★★
()
Ответ на: комментарий от quasimoto

... тогда бы я ожидал увидеть его на шутауте рядом с C++ ...

В самом языке ничего принципиально мешающего нет. Думаю, просто вопрос времени, допилят и компилятор, и библиотеки и сам код бенчмарков.

ozkriff
() автор топика
Ответ на: комментарий от tailgunner

В плюсах Тюринг-полные шаблоны - на них можно сделать вообще всё. Даже вышеприведенный макрос bindgen.

Эээм, там же надо внешний файл прочитать О.о .

ozkriff
() автор топика
Ответ на: комментарий от DarkEld3r

Cтрашненько. Хотелось бы более вменяемых средств метапрограммирования. Можно, конечно, лелеять надежды на будущие версии стандарта.

anonymous
()
Ответ на: комментарий от DarkEld3r

На этапе компиляции бустовый формат не проверяет форматную строку.

Да, я перепутал, у них там исключения, у Александреску тоже (чтобы в compile-time это ж constexpr строки нужны, рекурсивный variadic struct вместо функций, рекурсивный обход строк с использованием информации о типах аргументов).

quasimoto ★★★★
()
Последнее исправление: quasimoto (всего исправлений: 1)
Ответ на: комментарий от tailgunner

Спасибо, Капитан, я говорю именно об этом.

То есть ты говоришь, что реализация BigInt хуже GMP (оба используются в pidigits) и simd::f64x2 хуже -mfpmath=sse -msse2? (у меня там вторая ссылка на pidigits должна быть ссылкой на mandelbrot — тоже оба).

Итак, Rust позорно слил 2 бенчмарка: pidigits и n-body

Не так:

 fasta               ±
 binary-trees        ±
 reverse-complement  2×
 n-body              3×
 fannkuch-redux      3×
 spectral-norm       4×
 k-nucleotide        4×
 pidigits            5×
 mandelbrot          9×

mandelbrot использует simd у обоих, pidigits — большие числа там и там, про k-nucleotide я уже сказал (тоже подобно), n-body не так плох — в C++ sse3 и интринсики, в Rust «просто» (если автоматически что-то не делается, я не знаю).

Общая картинка (+ u64, u32, u32q).

Остальные сливы вполне ожидаемы от компилятора языка, находящегося в стадии проектирования.

Эм, ну я об этом и говорю (об ожидаемых сливах, а не кто там какую векторизацию использует).

ЯННП

Как же так? GHC (u64q):

 binary-trees        1/3
 reverse-complement  ±
 n-body              ±
 fasta               ±
 k-nucleotide        2×
 spectral-norm       2×
 mandelbrot          5×
 pidigits            5×
 fannkuch-redux      5×
quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

mandelbrot использует simd у обоих

Только что заметил, что ты смотришь результаты бенчмарков 0.10, а исходники на master... тогда вопросов нет.

GHC (u64q):

Я спрашивал, что ты имеешь в виду, когда говоришь «пусть пишут „так“». Достижения Хаскеля в бенчмарках мне безразличны.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Ткнул на 0.10 — pidigits такой же (BigInt), k-nucleotide без future (а на u64 приемлем, так что тут тоже можно ожидать лучших результатов на следующей версии), mandelbrot без simd::f64x2, ок.

Я спрашивал, что ты имеешь в виду, когда говоришь «пусть пишут „так“»

Дык я не отвечал на этот вопрос. Просто говорю — если брать те бенчмарки, то что там C++, Scala и Haskell ито более чем за стадией проектирование в сравнении.

quasimoto ★★★★
()

remember from last time that if the last expression in a block is not terminated by a semi-colon, then it becomes the value of the block

надеюсь, в каком-то минорном релизе это с кишками вырвут оттуда.

anonymous
()
Ответ на: комментарий от tailgunner

можно сделать [...] все

Мало Тьюринг-полных write-only-языков, что ли?

anonymous
()
Ответ на: комментарий от anonymous

remember from last time that if the last expression in a block is not terminated by a semi-colon, then it becomes the value of the block

надеюсь, в каком-то минорном релизе это с кишками вырвут оттуда.

Очень сомневаюсь. Вполне удобная штука, что с ней не так по-твоему?

Старая статейка, но, вроде, актуальная: http://lucumr.pocoo.org/2012/10/18/such-a-little-thing

ozkriff
() автор топика
Ответ на: комментарий от DarkEld3r

А с дефолтной иммутабельностью что-то надумали делать?

Надеюсь, что нет.

V_L_A_D ★★
()
Ответ на: комментарий от ozkriff

Вполне удобная штука, что с ней не так по-твоему?

Что от одного символа (разделителя выражений), меняется поведение. Пример с z в сабже лично у меня вызывает стойкий WUT.

anonymous
()
Ответ на: комментарий от tailgunner

В плюсах Тюринг-полные шаблоны - на них можно сделать вообще всё. Даже вышеприведенный макрос bindgen.

Интереса радия, а как прочесть файл с данными на этапе компиляции в крестах?

Norgat ★★★★★
()
Ответ на: комментарий от anonymous

Что от одного символа (разделителя выражений), меняется поведение.

И это плохо, потому чтооо...?

';' никакие выражения точно не разделяет. В Ржавчине, как и в Си, ';' является терминатором операторов (которые statement). Как разделитель ';' используется, например, в Паскалях и других Виртовских языках.

Возможность опустить ';' есть только для опционального финального выражения в блоке:

block_expr : '{' [ view_item ] *
                 [ stmt ';' | item ] *
                 [ expr ] '}' ;

И к каким ошибкам это может привести? Это не питон, тут статическая типизация. Компилятор тебе поможет :) .

Пример с z в сабже лично у меня вызывает стойкий WUT.

Дело привычки. Я в коде return ...; почти и не использую, только в паре мест, где нужно выйти из функции заранее.

ozkriff
() автор топика
Ответ на: комментарий от anonymous

руст тебе не даст скомпилячить некорректный вариант.

anonymous
()
Ответ на: комментарий от anonymous

Получится на variadic templates. У Александреску и Страуструпа было.

И все проверки как-то происходят во время компиляции, а не выполнения? Можно ссылку?

ozkriff
() автор топика
Ответ на: комментарий от ozkriff

Нет, в рантайме(хотя там не все так просто, сначала будет разворот шаблона функции, но проверка будет в рантайме с исключением). Во время компиляции тоже можно, но сложнее и через constexpr и, скорее всего, свои литералы для строк=)

anonymous
()

Хотеть «Раст для растаманов»

buddhist ★★★★★
()
Ответ на: комментарий от ozkriff

Это же костыль. На загнивающем западе такое обозначают словами bug-prone. Причем я еще не видел ни одного языка, где это как-то нормально было бы решено. В скале, например, практически все блоки возвращают результат вычисления своего последнего выражения, а если ты хочешь, чтобы функция его не возвращала, делаешь так:

def f(x: Any) {
  1 + 1
} // returns () (Unit)
vs
def f(x: Any) = {
  1 + 1
} // returns 2
А можно просто явно тип указывать:
def f(x: Any): Unit = {
  1 + 1
} // returns ()
Я редко явно указываю типы, когда пишу, и почти через раз возникает эта путаница с «=».

Я подозреваю, что здесь уместно было бы поговорить о чем-то вроде К-комбинаторов (ну, Кестрел типа, в попсовой литературе), но, пожалуй, сейчас не осилю развить идею.

anonymous
()
Ответ на: комментарий от anonymous

Причем я еще не видел ни одного языка, где это как-то нормально было бы решено.

Нормально - это как?

Кстати, а почему бы всегда не возвращать результат последнего выражения?

anonymous
()
Ответ на: комментарий от anonymous

Кстати, а почему бы всегда не возвращать результат последнего выражения?

Потому что тогда надо будет думать о внешнем контексте, всегда.

anonymous
()
Ответ на: комментарий от anonymous

Так, чтобы разработчик не ловил себя на мысли «бл@ть, {точка с запятой, равно}!»

По второму вопросу: в общем-то, так и делают, потому что это удобно, естественно/натурально и выразительно, когда statement == expression. Но иногда в силу каких-то причин этого пытаются избежать, поэтому изобретают разные точки с запятой и т.д., откуда вся путаница.

anonymous
()
Ответ на: комментарий от anonymous

Кстати, а почему бы всегда не возвращать результат последнего выражения?

Иногда оно бессмысленно?

Хотя я бы предпочел более явный (пусть и более громоздкий) вариант указания, что ничего возвращаться не будет.

DarkEld3r ★★★★★
()
Ответ на: комментарий от DarkEld3r

я бы предпочел более явный (пусть и более громоздкий) вариант указания, что ничего возвращаться не будет.

Так если всегда возвращать результат последнего выражения, то таким явным вариантом указания будет явное пустое выражение типа Unit или же вызов другой функции, возвращающей Unit.

def foo() {

    // ...

    ()  // или Unit() или еще как-нибудь
}

def bar() {

    // ...

    foo()
}
anonymous
()
Ответ на: комментарий от anonymous

В Ржавчине решили, что глобальный вывод типов - плохо, так что ты всегда обязан указывать возвращаемый тип функции. Тадааам! Проблема решена.

На загнивающем западе такое обозначают словами bug-prone.

Вот жеж пафосный, русских слов ему мало.

ozkriff
() автор топика
Ответ на: комментарий от DarkEld3r

Хотя я бы предпочел более явный (пусть и более громоздкий) вариант указания, что ничего возвращаться не будет.

Наличие и тип возвращаемого значения отлично видно по обязательной сигнатуре функции.

При возврате из замыкания (где сигнатура опциональна), тебя всегда спасет система типов.

Не вижу тут способов внезапно получить «бл@ть, {точка с запятой, равно}!», можно пример?

ozkriff
() автор топика
Ответ на: комментарий от ozkriff

Если финальное выражение в блоке опущено, то вместо него подставляется (). Все четыре компилятся и делают ровно одно и то же:

fn a(n: int)       { println!("{}", n);            }
fn b(n: int) -> () { println!("{}", n);            }
fn c(n: int) -> () { println!("{}", n); ()         }
fn d(n: int) -> () { println!("{}", n); return (); }
ozkriff
() автор топика
Ответ на: комментарий от ozkriff

А анонимные функции? И какой тогда вообще смысл в ; ? Всегда бы возвращали значение последнего выражения и все.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.