LINUX.ORG.RU

Rewrite it in Rust - что бы ещё переписать?

 , ,


0

5

Мой кот спрашивает: «Привет, ЛОР овец! Надоело давиться питоном, стал пересаживаться на Растишку. Что бы такое небольшое Переписать на Расте™ для начала? О чём ни подумаешь, всё уже есть на crates.io! Кому-нибудь случайно не хватает некой либы или утилиты в пределах 5 KLOC? Есть шанс, что вы её получите бесплатно под GPL! Спасибо.»



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

Перепиши окамл на расте

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

Да я уже всё понял. Очередной свидетель сишки отрицающий абстракции.

Не отрицающий, но не всегда и везде в них есть смысл. Вот, например, простая задача. Есть массив чисел, нужно его упростить - сложить рядом стоящие числа с одинаковым знаком. Вот код на С:

#include <stdio.h>

void print_array(int *a, int count) {
   for(int *p = a, *e = a + count; p != e; ++p)
        printf("%d\n", *p);
}

int main() {
    int a[] = { -1, 3, -1, -3, 2, 4 };
    int *e = a + sizeof(a) / sizeof(*a); 
    int *t = a;

    for(int *p = a + 1; p < e; ++p)
        (*p<0 == *t<0) ? (*t += *p) 
                       : (*++t = *p);

    print_array(a, t - a + 1);
}

Который выведет: -1 3 -4 6. Просто, быстро, понятно, все на виду. А на итераторах?

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

Хорошо, как можно ошибиться при работе с индексами? Сделать механическую очипятку?

Очепятку, неверное вычисление границ, неверное вычисление индекса.

Тут уже ничто не спасет, можно и с итераторами не то взять и не потому

Выйти за границу - нельзя. Ни взять, ни положить.

Опять же - итераторы не панацея, и даже больше, возможно надо будет менять контейнер, и тогда итераторы не вариант.

Поэтому давайте переписывать на индексы даже те случаи, в которых итераторы подходят. Как это сделал ты.

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

Причем упростить - это обновить существующий массив, а не просто вывести на экран.

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

Очепятку, неверное вычисление границ, неверное вычисление индекса.

Если речь идет именно о вычислениях границ, то итераторы тут не помогут, ты в них точно так будешь передавать эти границы. А если это 0..len, то надо страдать паранойей, чтоб бояться ошибиться в таких случаях.

Взять - можно. Положить за границу - нельзя.

Где-то взяли не то и куда-то положили не то, тоже критическая ошибка, только без паники.

Поэтому давайте переписывать на индексы даже те случаи, в которых итераторы подходят. Как это сделал ты.

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

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

Он адски неудобный и нефункциональный.

Написал пару прототипов на нем проверить концепцию перед переписыванием на Hyper, что-то делается удобнее и быстрее, но мощности Hyper там в в помине нет.

И оно всё еще не умеет работать асинхронно, несмотря как основу в виде Hyper 1.1

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

Если речь идет именно о вычислениях границ, то итераторы тут не помогут, ты в них точно так будешь передавать эти границы.

Куда?

for (i, value) in current.iter_mut().enumerate()

Какая передача границ, о чем ты вообще?

Где-то взяли не то и куда-то положили не то, тоже критическая ошибка

То есть один класс критических ошибок устранен.

Поэтому давайте переписывать на индексы даже те случаи, в которых итераторы подходят. Как это сделал ты.

Нет, мой вариант - проще, и в написании, и в чтении, и в реализации

Он очевидно проще в одном - там проще сделать ошибку.

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

Куда?
Какая передача границ, о чем ты вообще?

Точно, я ж забыл, что код не пишешь и только по копипастам ориентирешься. Вот так: .skip(2).take(10)

То есть один класс критических ошибок устранен.

Проигнорирован, а не устранен.

Он очевидно проще в одном - там проще сделать ошибку

Наверное потому ты и не пишешь код, слишком опасно, ведь просто допустить ошибку даже в обычном счетчике.

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

.skip(2).take(10)

То есть один класс критических ошибок устранен.

Проигнорирован, а не устранен.

Доо. Ну, запиши мне за границу массива при помощи итераторов. В Rust.

ты и не пишешь код

Ты меня разоблачил.

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

Бгг.

Что именно вызывает затруднения? Возможность допустить ошибку? Хочешь об этом поговорить?

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

Кто-то говорил, что на итераторах надо писать всё и всегда? Не слышал такого.

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

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

Что именно вызывает затруднения?

Какие такие затруднения? Кислое хихикание вызывает то, что вот это бессмысленное дрочево:

    for(int *p = a + 1; p < e; ++p)
        (*p<0 == *t<0) ? (*t += *p) 
                       : (*++t = *p);

называют «простым и понятным». Хотя да, всё на виду, согласен.

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

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

Поверх гипера есть только Iron со схожими возможностями, но он мертв

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

гипер де-факто стандарт + позволяет сделать всё, что угодно,

Ну, если надо именно «всё, что угодно», тогда конечно.

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

Таки бомбануло тебя от недоязычка, у которого даже пример из оффдоки не компилируется.

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

Доо. Ну, запиши мне за границу массива при помощи итераторов. В Rust.

Если это про изначальный пример с индексом, то такое может быть, только если во время итерации контейнер поменялся, причем так, что индекс вышел за границы. Что это значит, что из него был удален минимум один элемент. А теперь смотрим как сработает в такой ситуации итератор:

Начальный список: 'a', 'b', 'c'. Нужно добавить индекс и получить пары, шаг первый:

('a', 1)

Все хорошо, и тут мы удаляем первый элемент, получаем список: 'b', 'c', идем итератором дальше:

('a', 1), ('c', 2)

Закончили. Ура мы не вышли за границу, зашибись. Хотя результат совсем не тот, что надо. Даже если забить на удаленный 'a', то мы пропустили 'b' и потеряли данные. Ну и если ты сошлешься на искусственность примера, то пусть это будет моя паранойя, как и у тебя с простым циклом.

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

запиши мне за границу массива при помощи итераторов. В Rust.

Если это про изначальный пример с индексом

фейспалм

А теперь смотрим как сработает в такой ситуации итератор:

Смотрю. Кода на Rust не вижу.

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

Какие такие затруднения? Кислое хихикание вызывает то, что вот это бессмысленное дрочево называют «простым и понятным».

Покажи пальцем, что тебе непонятно, я тебе расскажу.

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

Смотрю. Кода на Rust не вижу.

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

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

Эталонный сишный говнокод.

Вот пример без модификации:

    let arr = [-1i32, 3, -1, -3, 2, 4];
    
    for v in arr.windows(2) {
        if v[0].signum() == v[1].signum() {
            println!("{:?}", v);
        }
    }

Модификация будет развесистие, но правильнее чем у вас, ибо у вас в пустых «ячейках» мусор остался. И длина хранится в отдельной переменной. Что и есть «эталонный сишный говнокод».

RazrFalcon ★★★★★
()

Ничего не пиши. Это бесполезная трата ресурсов и война с ветряными мельницами. У нас такой переписыватель работал. Он сервис один переписывать пытался, который 15 лет честно пахал и не просил есть. Сначала он героически боролся со всеми местами, которые вываливались в панику с остановкой обслуживания, из-за чего весь код стал новогодней елкой, изготовленной в интернате для душевнобольных, потом боролся с тем, что после 2000 коннектов время откликов увеличивалось в 500-600 раз, а потом боролся с распуханием процесса в памяти. 2 суток + 8 гигов. Конечно «раст не виноват», это все «сторонние либы» и вообще Петя умный, он на конференциях ... он на канале в гиттере пра раст... уважаемый человек в раст сообществе. Но как-то попросили мы Петю в общем. Привет, Петя, если читаешь.

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

Вот пример без модификации:

Это какая-то другая задача.

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

Моя модификация не требует ни дополнительных аллокаций, ни перемещения больше чем одного элемента за раз, ни работы с кучей. А «правильно» я и сам могу на другом языке сделать.

Ибо у вас в пустых «ячейках» мусор остался. И длина хранится в отдельной переменной. Что и есть «эталонный сишный говнокод».

Можно завести структуру, если отдельная переменная так претит. А то, что «мусор остался», так это ты видно считаешь, что если он останется у тебя где-то в Vec и ты его не видишь, то его и нет.

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

Что и есть «эталонный сишный говнокод

Ну и спасибо конечно, но я не сишник, и гарантированно можно было бы лучше сделать. Может царь зайдет и покажет.

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

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

Это не я делаю космического масщтаба заявления. Ты фактически сказал, что нашел unsoundness в Rust - такие заявления принято доказывать.

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

Это не я делаю космического масщтаба заявления. Ты фактически сказал, что нашел unsoundness в Rust - такие заявления принято доказывать.

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

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

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

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

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

Но тем не менее, вот код для остальных, кто читает топик:

struct Container {
    items: Vec<i32>
}

impl Container {
    fn at(&mut self, index: usize) -> i32 {
        let r = self.items[index];
        if index == 1 {
            self.items.remove(index);
        }
        r
    }

    fn iter(&mut self) -> ContainerIterator {
        ContainerIterator { container: self, index: 0 }
    }
}

struct ContainerIterator<'a> {
    container: &'a mut Container,
    index: usize,
}

impl<'a> Iterator for ContainerIterator<'a> {
    type Item = i32;
    fn next(&mut self) -> Option<i32> {
        if self.index >= self.container.items.len() {
            return None;
        }
    
        let r = self.container.at(self.index);
        self.index += 1;
        Some(r)
    }
}

fn main() {
    let mut p = Container { items: vec![1, 2, 3] };
    
    println!("Enumerated:");
    for (i, item) in p.iter().enumerate() {
        println!("{} {}", i, item)
    }
    
    println!("But:");
    for n in p.items {
        println!("{}", n);
    }
}

Выведет:

Enumerated:
0 1
1 2
But:
1
3

Т.е. удалится двойка, но при этом из результата пропадет тройка, хотя в изначальном контейнере она осталась. И это не претензия к Rust, это камень в огород tailgunner, который настолько не знает Rust, что даже простые вещи считает «космического масщтаба заявлениями». Хотя не удивлюсь, если он опять начнет юлить и кривляться.

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

Так а в чём проблема? Вы реализовали определённое поведение контейнера, а виноваты итераторы?

Да никто ни в чем не виноват. Я лишь обратил внимание, что если менять контейнер, то итераторы тоже могут поломаться, как и в случае со счетчиком. А tailgunner сказал, что зато индекс не выйдет за пределы, типа это плюс. А я ответил, что если удалить уже пройденный элемент (текущий или предыдущий), то выхлоп итератора может не совпадать даже с оставшимися данными, а не только пройдеными. Что явная логическая ошибка. Причем ошибка погромиста, а не Rust или цикла на индексах.

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

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

fn main() {                              // 1
    let mut a = vec!(1, 2, 3, 4, 5);     // 2
    for (n, i) in a.iter().enumerate() { // 3
        println!("{:?}", i);             // 4
        if n == 1 {a.remove(n);}         // 5
    }                                    // 6
}                                        // 7

[Running: cargo run --bin ex --message-format=json]
   Compiling ex v0.1.0 (file:///home/virtuos86/rust/ex)
error: src/main.rs:5: cannot borrow `a` as mutable because it is also borrowed as immutable
error: src/main.rs:5: mutable borrow occurs here
error: src/main.rs:3: immutable borrow occurs here
error: src/main.rs:6: immutable borrow ends here
error: Could not compile `ex`.

А снаружи ломать не получается. А если итератор захватывает мутабельное владение, то ССЗБ, будь осторожен, что ли.

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

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

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

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

Ну чисто формально можно сделать так, чтоб ломалось и снаружи

А точно ли можно? Мне кажется, borrowing по рукам надает при попытке одновременно иметь два мутабельных владения. Если только через указатели, но это точно не идиоматичный Rust. Можешь пример рабочий изобразить?

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

А точно ли можно? Мне кажется, borrowing по рукам надает при попытке одновременно иметь два мутабельных владения. Если только через указатели, но это точно не идиоматичный Rust. Можешь пример рабочий изобразить?

А зачем два?

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

А как ты одним обойдешься? В цикле точно не получится изменить контейнер, потому что цикл сам по себе захватывает владение объектом.

Но лично я говорил про сам принцип, контейнер сам по себе может обновляться, например, если внутри ленивая логика по вычитке данных.

Если контейнер хитровыдуманный, это заботы программиста, а не ЯП. Или ты хочешь специальную опцию, которая бы запрещала изменяться контейнеру вообще во время итерации? Это надо изображать самому.

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

А как ты одним обойдешься? В цикле точно не получится изменить контейнер, потому что цикл сам по себе захватывает владение объектом.

Так как раз контейнер и не надо, надо те самые данные. Может конечно я чего простого не вижу, сильно хочу спать. Завтра, если будет время, попробую изобразить свою идею.

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

Если контейнер хитровыдуманный, это заботы программиста, а не ЯП

Так я не раз писал, что к ЯП у меня претензий нет, все хорошо. Вопрос в погромистах, и в том, что накосячить можно везде, Кто-то пишет хитрые контейнеры или итераторы, кто-то лепит unwrap и unsafe, а кто-то не осиливает сделать цикл 0..len на одну строку. И лично я оцениваю последнее как наименее вероятный источник ошибок. Ну вот ни разу я не попадал на такие ошибки, может просто очень везло.

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

А как ты одним обойдешься? В цикле точно не получится изменить контейнер, потому что цикл сам по себе захватывает владение объектом.

Так как раз контейнер и не надо, надо те самые данные

Ага, посмотрел твой пример, понял. Это какой-то специальный кейс. Надо ветку перечитать, а то я перестал понимать, о чем вообще спор вышел у вас.

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