На днях вышла 1.0.0.alpha, решил наконец приобщиться. Почитал онлайн книжку. Если она не слишком много скрывает, язык довольно маленький и простой, это хорошо. Для начала сделал вариант для недавнего микробенчмарка про маленький интерпретатор. В тот раз добрые люди помогли ускорить наивные решения, так что все времена опустились ниже 1 секунды, что делает замеры менее осмысленными. Тем не менее, вот текущие результаты:
D - 0.40 s (при использовании LDC)
Rust - 0.44 s
OCaml - 0.57 s
Haskell - 0.85 s
(с одной закавыкой - Rust тут 64-битный, все остальные 32-битные, так уж получилось)
Т.к. опыт с Rust'ом у меня пока минимальный, впечатления смутные. Одной фразой - "ML в руках плюсовиков". Видишь знакомый набор из алгебраиков, паттерн-матчинга, лямбд, expression-based syntax, начинаешь писать как на ML, и тут на тебя выпрыгивает наследие С++: а ты здесь это значение насовсем передал (у нас move-семантика по-умолчанию, уж больно нам эта фича из С++ понравилась) или хотел лишь по указателю? Ах по указателю, тогда так и напиши везде, и где принимаешь, и где передаешь. А еще и писать туда хотел? Тогда не забудь при передаче &mut дописать. И это же выскакивает при паттерн-матчинге: вот тут ты поле алгебраика заматчил, тебе его так отдать или по ссылке? А обращаться хорошо с ней будешь?
Причем как-то странно сделано, вот есть структуры и есть туплы, разница между ними довольно косметическая, так? Можем пару значений передать как тупл, а можем как структуру. Сделаем пару одинаковых функций, складывающих два поля:
Обе получают аргумент по значению.
Теперь попробуем их повызывать:
И получаем ошибку:
Оказывается, когда мы структуру передали в ту функцию, мы ее отдали насовсем, это был move. А вот тупл скопировался, передача по значению, оригинал остается у вызывающей ф-ии. Неожиданно.
Еще занятный момент. В растовском варианте, что по ссылке выше, есть такое выражение:
1 + (if a[i] > a[j] { evalBlock(a, b1) } else { evalBlock(a, b2) })
Казалось бы, его, как в ML вариантах, можно заменить более простым:
1 + evalBlock(a, if a[i] > a[j] { b1 } else { b2 })
Но не тут-то было. Rust считает, что в первом аргументе evalBlock происходит мутабельное заимствование массива а, а при вычислении второго аргумента имеет место иммутабельное заимствование этого же массива. И хотя аргументы должны быть вычислены до вызова функции, и по времени эти два использования массива не пересекаются никак, Rust считает, что тут два параллельных заимствования, одно из которых мутабельное, что недопустимо.
Буду продолжать наблюдения. В целом штука занятная.
D - 0.40 s (при использовании LDC)
Rust - 0.44 s
OCaml - 0.57 s
Haskell - 0.85 s
(с одной закавыкой - Rust тут 64-битный, все остальные 32-битные, так уж получилось)
Т.к. опыт с Rust'ом у меня пока минимальный, впечатления смутные. Одной фразой - "ML в руках плюсовиков". Видишь знакомый набор из алгебраиков, паттерн-матчинга, лямбд, expression-based syntax, начинаешь писать как на ML, и тут на тебя выпрыгивает наследие С++: а ты здесь это значение насовсем передал (у нас move-семантика по-умолчанию, уж больно нам эта фича из С++ понравилась) или хотел лишь по указателю? Ах по указателю, тогда так и напиши везде, и где принимаешь, и где передаешь. А еще и писать туда хотел? Тогда не забудь при передаче &mut дописать. И это же выскакивает при паттерн-матчинге: вот тут ты поле алгебраика заматчил, тебе его так отдать или по ссылке? А обращаться хорошо с ней будешь?
Причем как-то странно сделано, вот есть структуры и есть туплы, разница между ними довольно косметическая, так? Можем пару значений передать как тупл, а можем как структуру. Сделаем пару одинаковых функций, складывающих два поля:
#[derive(Show)]
struct S { x : i32, y : i32 }
fn eat_struct(s : S) -> i32 {
s.x + s.y
}
fn eat_tuple(t : (i32, i32)) -> i32 {
let (x,y) = t;
x + y
} Обе получают аргумент по значению.
Теперь попробуем их повызывать:
fn main() {
let s = S { x: 1, y : 2 };
let t = (1, 2);
let rs = eat_struct(s);
let rt = eat_tuple(t);
println!("{} {} {:?} {:?}", rs, rt, s, t);
}И получаем ошибку:
hi.rs:18:39: 18:40 error: use of moved value: `s`
hi.rs:18 println!("{} {} {:?} {:?}", rs, rt, s, t);
^Оказывается, когда мы структуру передали в ту функцию, мы ее отдали насовсем, это был move. А вот тупл скопировался, передача по значению, оригинал остается у вызывающей ф-ии. Неожиданно.
Еще занятный момент. В растовском варианте, что по ссылке выше, есть такое выражение:
1 + (if a[i] > a[j] { evalBlock(a, b1) } else { evalBlock(a, b2) })
Казалось бы, его, как в ML вариантах, можно заменить более простым:
1 + evalBlock(a, if a[i] > a[j] { b1 } else { b2 })
Но не тут-то было. Rust считает, что в первом аргументе evalBlock происходит мутабельное заимствование массива а, а при вычислении второго аргумента имеет место иммутабельное заимствование этого же массива. И хотя аргументы должны быть вычислены до вызова функции, и по времени эти два использования массива не пересекаются никак, Rust считает, что тут два параллельных заимствования, одно из которых мутабельное, что недопустимо.
Буду продолжать наблюдения. В целом штука занятная.
no subject
Date: 2015-01-14 08:21 am (UTC)no subject
Date: 2015-01-14 08:24 am (UTC)no subject
Date: 2015-01-14 09:18 am (UTC)no subject
Date: 2015-01-14 10:36 am (UTC)Стобы понять с++ные перемещения, надо знать предысторию. С их велосипедами народ трахался пятнадцать лет, пока не пришёл к пониманию ценности, цены, области применения и стандарта.
С передачей ссылок и значений, кстати, народ также натрахался вволю, но ещё в фортране.
no subject
Date: 2015-01-14 10:36 am (UTC)Были адовы горы строк с подсчётом ссылок. Но при этом, иногда их надо было просто передавать куда-то для вывода или обработки, не дёргая попусту всю эту мишуру с механизмом подсчёта. Поэтому была какая-то припарка, вспомогательный объект, через который в функцию передавался объект, без пересчёта ссылок. Очень это геморно было, и от ошибок не защищёно.
Не понимаю как в си раньше до такого нужного механизма не додумались. В Rust, я так понимаю, он более развит, хотя не все проблемы решает.
no subject
Date: 2015-01-14 10:37 am (UTC)Йес ыт ыз!
За углоскобки отдельное фи. На ровном месте усложнили жизнь парсеру.
no subject
Date: 2015-01-14 10:41 am (UTC)сколько классов строк было в вашем самом большом проекте?
no subject
Date: 2015-01-14 11:19 am (UTC)no subject
Date: 2015-01-14 11:28 am (UTC)no subject
Date: 2015-01-14 11:32 am (UTC)no subject
Date: 2015-01-14 11:35 am (UTC)Тэг пропал, ахаха. < T > надо было.
А как в расте с двойной закрывающей скобкой, это одна лексема или две?
no subject
Date: 2015-01-14 11:39 am (UTC)По сравнению с си без крестов.
В плюсах есть спецтанцы с бубном для устранения неоднозначностей, и жутко контекстнозависимый парсер. А двойную закрывающую скобку сколько лет фиксили, 15 или 18?
no subject
Date: 2015-01-14 11:45 am (UTC)Нормальный быстрый escape-анализ + сборщик мусора + арены для особо исключительных случаев.
Контроллеры с весьма маленькой (4М, например) памятью.
Всё хорошо.
no subject
Date: 2015-01-14 12:09 pm (UTC)Плюсовых проблем с закрытием > в расте нет, пробел не нужен. Сколько лексем - не знаю.
no subject
Date: 2015-01-14 12:16 pm (UTC)А если без сборщика?
Со сборщиком всегда можно быть довольно консервативным: не уверен, что можно положить на стек, - пихай в кучу. А вот чтобы без лишней консервативности, это надо или глобальный анализ делать по всей программе и библиотекам, или таки в типы пометки совать.
no subject
Date: 2015-01-14 12:30 pm (UTC)У жж движок разметки странноватый, часть неоднозначностей он исправляет, часть игнорирует.
no subject
Date: 2015-01-14 12:32 pm (UTC)no subject
Date: 2015-01-14 12:33 pm (UTC)no subject
Date: 2015-01-14 01:35 pm (UTC)Глобальный анализ по всей программе и библиотекам, с аннотациями и всем таким. Без поливариантных типов, поэтому достаточно быстро. Может не покрывать какой-нибудь специфический "декларативный" код, но мы за это и не боролись никогда. В кровавой эмбеддщине так никто не пишет.
no subject
Date: 2015-01-14 02:10 pm (UTC)no subject
Date: 2015-01-14 04:25 pm (UTC)no subject
Date: 2015-01-14 04:27 pm (UTC)О времена, о нравы!
В моем понимании, весьма маленькая память - это 128 байт (сим-карты) :)
no subject
Date: 2015-01-14 04:37 pm (UTC)У них вообще от 32 байт памяти.
no subject
Date: 2015-01-14 05:07 pm (UTC)Nim - тоже довольно занятный экземпляр, делающий успехи сейчас. Но я пока для него не созрел, чем-то он мне противен.
no subject
Date: 2015-01-14 08:32 pm (UTC)Ещё буквально пару недель назад это было не так: структуры тоже обладали Copy, если нет деструктора, и все её члены Copy =) Теперь нужно либо явно указывать #[derive(Copy)], либо #[allow(missing_copy_implementations)] (иначе компилятор нервничает).