Pull to refresh
46

Типострадалец

12
Subscribers
Send message

Понимаю, что это, возможно, первый код автора на Rust, но всё-таки хочется указать на некоторые недочёты.


Непонятен выбор библиотек. Почему generic-matrix вместо ndarray или nalgebra? Почему именно reed-solomon? Так вышло, что я знаком с автором reed-solomon, и он говорит, что эта библиотека была в своё время его упражнением в Rust и не предназначена для серьёзного использования.


Теперь непосредственно по коду.


impl Module {
    pub fn set_module(&mut self, new_module: Module) {
        *self = new_module;
   }

Этот метод просто не нужен и целиком заменяется на оператор присваивания по месту.


   pub fn is_fun(&self) -> bool {
       match self {
           Module::Function(_) => return true,
           _ => return false,
       }
   }

Можно написать короче:


    pub fn is_fun(&self) -> bool {
        matches!(self, Self::Function(..))
    }

    pub fn flip_module(&mut self) {
        match self {
            Self::Data(true) => *self = Self::Data(false),
            Self::Data(false) => *self = Self::Data(true),
            _ => (),
        }
    }

Опять-таки, можно написать короче и заодно не расписывать все варианты:


    pub fn flip_module(&mut self) {
        if let Self::Data(data) = self {
            *data = !*data;
        }
    }

pub fn set_square(&mut self, size: usize, cordinate: (usize, usize), matrix_module: &mut Matrix<Module>) {
        let start_width: usize = cordinate.1;
        let start_height: usize = cordinate.0;

        for i in 0..size {
            for j in 0..size {
                let new_module = matrix_module.index_mut((i, j));
                self.set_module((i + start_height, j + start_width), *new_module);
            }
        }
   }

    pub fn set_module(&mut self, cordinate: (usize, usize), new_module: Module) {
        let mut _module: &mut Module = self.get_mut_module(cordinate);
        _module.set_module(new_module);
}

К этим функциям у меня хватает вопросов:


  1. Зачем отдельным параметром передается size, если, насколько я понимаю, можно вынуть размер из matrix_module?
  2. Зачем matrix_module передаётся по мутабельной ссылке, если он не меняется?
  3. Зачем используется index_mut вместо оператора индексации?
  4. Почему в set_module выносится отдельная переменная _module, да ещё и с прочерком в начале? В Rust так принято именовать неиспользуемые переменные, поскольку по умолчанию на них не срабатывает предупреждение о мёртвом коде.

(и, кстати, почему cordinate с одной o?)


И да, библиотеки рулят. С какой-нибудь nalgebra весь метод можно было бы свести к


pub fn set_square(&mut self, at: (usize, usize), square: &DMatrix<Module>) {
    self.module.view_mut(at, square.shape()).copy_from(square);
}

Далее, функцию create_reed_solomon_encoder можно без ущерба для кода заменить на Encoder::new. Это даже короче.


pub fn create_error_corrections_blocks(data: Vec<u8>, num_error_correction_blocks: usize) -> Vec<u8> {
        let reed_encoder: Encoder = Self::create_reed_solomon_encoder(num_error_correction_blocks);

        let data_copy = reed_encoder.encode(&data).to_vec();

        return data_copy;
}

Разнесено на три строчки то, что можно уместить в одну:


pub fn create_error_corrections_blocks(data: &[u8], num_error_correction_blocks: usize) -> Vec<u8> {
    Encoder::new(num_error_correction_blocks).encode(data).to_vec()
}

И да, функция зачем-то принимает на вход Vec<u8>, вынуждая вызывающую сторону безусловно выделять память, в то время как просто слайса (&[u8]) было бы достаточно (собственно, это именно то, что принимает на вход Encoder::encode).


В функции move_horizontaly есть число 6. Мне, как человеку со стороны, вообще непонятно, откуда оно взялось.


В функции move_vertical есть вот такой странный фрагмент:


        else {
            if self.upward { self.row_cordinate -= 1 }
            else if !self.upward { self.row_cordinate += 1 }
            self.column_cordinate += 1;
        }

Зачем тут else if? Условия self.upward и !self.upward взаимно исключают друг друга.


В любом случае, не смотря на недочёты, видно, что автор программировать всё же умеет — что правда впечатляет с учётом его возраста. Правда, у меня сложилось впечатление, что хоть это и первая программа на Rust, но не первый опыт программирования у автора в принципе. Судя по косвенным признакам (аннотации типов, геттеры, сеттеры, ненужные return), я бы сделал ставку на Java. Я угадал?


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

А как эта задача решается, кстати?

При этом код на Rust — очень часто вообще нечитабелен из-за переизбытка Rc/Box и времён жизни

Очень странное заявление. Rc — это потоконебезопасный счётчик ссылок. У него есть свои области применения, но всё же он обладает меньшей универсальностью, чем Arc — атомарный счётчик ссылок. Arc используется в реальных программах куда чаще.


Ну а Box — это аналог std::unique_ptr, который используется примерно тогда же, когда unique_ptr используется в C++. И что-то мне подсказывает, что про код на C++ вы не скажете "переизбыток уникальных указателей".

Столько громких заявлений — и ни одного аргумента, кроме ятаксказал

А ничего, что даже сама Microsoft отказалась от поддержки всех этих версий?

То есть вы предлагает руками вызывать функции для экранирования подставляемых параметров? Извините, но это ненадёжно: рано или поздно пользователь библиотеки забудет это сделать и подвергнется опасности SQL injection.


Ну и тот факт, что экранируются только кавычки, как-то не внушает доверия.

… Или можно просто вызвать arr.reverse() и не думать об индексах вообще /s

Хотелось бы больше деталей. Или там NDA?

В данном конкретном примере даункаст по enum'у эффективнее, но можно и dynamic_cast использовать, концептуально это ничего не изменит.

Ну, вообще-то изменит: не нужно следить за соответствием тегов и типа, в который кастуется общий указатель.

Дело в том, что на С пишут "достаточно специфические люди". Которые примерно знают во что превратится их код на ассемблере (не до строчки, но примерено представляют).

Ага, а потом очень обижаются, когда их столетний говнокод перестаёт работать из-за того, что новая версия компилятора начинает абузить UB в их коде.


И да, они почти наверняка не знают.


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

Надо же, совсем как в C!


(и сам не раз с этим сталкивался когда ++-й код не проходит по быстродействию, а написанное на чистом С проходит ...)

Это очень странная ситуация, потому что (почти) всё, что можно написать на C, можно написать и на C++. И, к слову, C++ не заставляет использовать динамическую аллокацию памяти.

В Rust необходим unsafe контекст для работы с C, что накладывает свои требования к написанию кода.

В Rust необходимо явно обозначать, как непроверяемый, код, корректность которого компилятор не может проверить

Удивительно!

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


И этой действительно проблема. Скажем, если в окружение добавить факт, что имя "y" имеет тип "int", то для такого выражения:


(\x.x)(y)

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


(\y.y)(y)

выводит неправильный Variable(TypeVariable(1)).

Что такое сознание, "трудная проблема сознания", "китайская комната", "философский зомби"

Кстати, философский зомби — понятие абсолютно бесполезное. Именно потому, что по определению такой объект неотличим от человека.


А насчёт китайской комнаты — их современным аналогом можно считать языковые модели (в том числе нашумевшую ChatGPT). И детектировать искусственность их вывода вполне возможно на практике.

Как человек, который эти самые ЕГЭ сдавал — то, что учёба в 11 классе выхолащивается в подготовку к ЕГЭ. Натаскивая этим самым на наработку навыка, который после сдачи ЕГЭ становится бесполезным, ведь сдаётся ЕГЭ только один раз.

Я в детстве Авантой+ зачитывался, они прикольные.

Всячески поддерживаю. Вот только конкретно по биологии не советую, она так себе.

Как-то однажды знаменитый учитель Кх Ан вышел на прогулку с учеником Антоном. Надеясь разговорить учителя, Антон спросил: "Учитель, слыхал я, что объекты — очень хорошая штука — правда ли это?" Кх Ан посмотрел на ученика с жалостью в глазах и ответил: "Глупый ученик! Объекты — всего лишь замыкания для бедных."

Пристыженный Антон простился с учителем и вернулся в свою комнату, горя желанием как можно скорее изучить замыкания. Он внимательно прочитал все статьи из серии "Lambda: The Ultimate", и родственные им статьи, и написал небольшой интерпретатор Scheme с объектно-ориентированной системой, основанной на замыканиях. Он многому научился, и с нетерпением ждал случая сообщить учителю о своих успехах.

Во время следующей прогулки с Кх Аном, Антон, пытаясь произвести хорошее впечатление, сказал: "Учитель, я прилежно изучил этот вопрос, и понимаю теперь, что объекты — воистину замыкания для бедных." Кх Ан в ответ ударил Антона палкой и воскликнул: "Когда же ты чему-то научишься? Замыкания — это объекты для бедных!" В эту секунду Антон обрел просветление.

На C с нестандартными расширениями от GCC

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

Если вы про Linux, то он по факту и не на C написан.

Если операция свёртки энергичная (как в набившем оскомину примере суммы списка через свёртку), то левая свёртка эффективнее, потому что не плодит thunk-и.

Information

Rating
Does not participate
Registered
Activity