Обновить
232
Всеволод@torkve

Пользователь

1
Рейтинг
38
Подписчики
Отправить сообщение
Всё просто, либо вы тащите с собой этот патч до скончания веков — накладываете его на новые версии библиотеки, чините мерж-конфликты — либо держите устаревшую версию с возможными багами, уязвимостями и проблемами совместимости с новыми системами, героически превозмогая ещё и это.
Обычно хорошие разработчики стараются всего этого избежать, поэтому пропихивание патча в апстрим решает чисто ваши собственные проблемы.
Ехал я как-то на машине в Москву через Минск, всё там хорошо у людей с представлениями.
> В свои 60- мне хватает сил ровно на 3 дня. Например, за июнь я сделал 10 новых игр.
Зависть. Понимаю, что опыт и фантазия, но всё равно зависть.
Вообще, partial в питоне — это не каррирование, а частичное применение, это разные вещи.
Например, вот каррирование в OCaml:
# let add x y = x + y;;
val add : int -> int -> int = <fun>
# let add2 = add 2;;
val add2 : int -> int = <fun>
# let sum = add2 3;;
val sum : int = 5

А вот частичное применение в питоне:
>>> add = lambda x, y: x + y
>>> add    
<function <lambda> at 0x7f78aba64aa0>
>>> add2 = partial(add, 2)
>>> add2 
<functools.partial object at 0x7f78aba57520>
>>> sum = partial(add2, 3)
>>> sum
<functools.partial object at 0x7f78aba577e0>
>>> sum()
5

Т.е. мы получаем всё ещё функцию, а не результат, более того, мы можем навесить ещё один partial с какими-нибудь аргументами на функцию sum и узнаем об ошибке только в момент вызова полученной новой функции.

А нужно это во многих местах: например, если у какого-нибудь объекта (кнопки, сокета, whatever) подписка на событие требует передать функцию-обработчик, принимающую один аргумент, например, событие, а у вас более сложный обработчик, которому вы хотите передавать больше информации:
def complex_handler(obj, logger_name, times_to_log, event):
    for _ in range(times_to_log):
        logging.getLogger(logger_name).info("got event from %s: %s", obj, event)
obj1.subscribe(partial(complex_handler, obj1, "incoming", 3))
obj2.subscribe(partial(complex_handler, obj2, "outgoing", 5))
Забавно, не знал.
И касательно времени жизни, вам должно помочь оборачивание if-блока в фигурные скобки:
fn get<T>(&mut self, key: &T) -> &u32 {
    {
        if let Some(v) = self.find(key) {
            return v;
        }
    }
    self.insert(key, 0)
}

Не так красиво, но время жизни закончится там, где надо.
Посмотрите, как это делается в стандартной библиотеке:
https://doc.rust-lang.org/src/core/option.rs.html#667
https://doc.rust-lang.org/std/collections/hash_map/enum.Entry.html#method.or_insert
откуда об этом может знать компилятор?

Он умный, такие проверки уже сто лет как есть.

там даже есть реальный выход из функции

Вероятно, это баг или разработчики ещё не оптимизировали это место в компиляторе. Попробуйте им зарепортить.
Я тоже ненастоящий сварщик, но в моём понимании у функции должно быть место, в котором она говорит ret и вызывающему коду возвращается то, что лежит в соответствующем регистре. При TCO бесконечного цикла в коде просто не остаётся ret, который можно было бы позвать. Можно пытаться его как-то эмулировать, воткнув никогда не вызываемый ret после джампа, но это нелегально, потому что у нас нет никакого значения заявленного типа (CowVM), которое можно положить в регистр для возврата.

При этом можно явно заявить функцию, как не возвращающую значение:
#[no_mangle]
pub fn test(a: i32) -> ! {
    println!("a");
    test(a + 1)
}


И тогда компилятор штатно сгенерирует в конце функции:
...
  %6 = add i32 %0, 1
  tail call void @test(i32 %6)
  unreachable


И при этом компилятор как раз предупредит о проблеме:
warning: function cannot return without recurring
 --> a.rs:2:1
  |
2 | / pub fn test(a: i32) -> ! {
3 | |     println!("a");
4 | |     test(a + 1)
5 | | }
  | |_^
  |
  = note: #[warn(unconditional_recursion)] on by default
note: recursive call site
 --> a.rs:4:5
  |
4 |     test(a + 1)
  |     ^^^^^^^^^^^
  = help: a `loop` may express intention better if this is on purpose
Конкретно у этого примера, как вам правильно заметили, нет никакого условия выхода. Если на него внимательно посмотреть, то получается, что такой код завязан на переполнение i32 (не помню, есть ли в Rust про это какой-то стандарт, а в C это называлось бы UB), т.е. ваш код выйдет, когда мы переполним i32 и дойдём до 0 с отрицательной стороны. При таких условиях компилятор имеет право нарисовать на экране котика вместо заданного кода. Например, если убрать ваш println!, то вся функция при компиляции превратится в одну строчку: ret i32 1.

Если же говорить о вашем цикле из статьи, то вероятно, что ему тоже просто необходимо корректное условие выхода из цикла, потому что в функции execute его вообще нет. Мне лень лезть в код, но я подозреваю, что у вас предполагается, что в какой-то момент получение следующей инструкции выкинет панику или прямо сделает abort(), но это как раз плохой и нефункциональный подход.
В Rust конечно же есть оптимизация хвостовой рекурсии, вот простейший пример (no_mangle исключительно для читаемости):
0 ➜ cat a.rs 
#[no_mangle]
pub fn test(a: i32) -> i32 {
    if a == 0 {
        42
            
    } else if a == 7 {
        43
    } else {
        test(a - 1)
    }
}
0 ➜ rustc --crate-type dylib --emit llvm-ir -O a.rs

0 ➜ cat a.ll
; ModuleID = 'a.cgu-0.rs'
source_filename = "a.cgu-0.rs"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

; Function Attrs: nounwind readnone uwtable
define i32 @test(i32) unnamed_addr #0 {
start:
  br label %tailrecurse

tailrecurse:                                      ; preds = %bb4, %start
  %.tr = phi i32 [ %0, %start ], [ %1, %bb4 ]
  switch i32 %.tr, label %bb4 [
    i32 0, label %bb7.loopexit
    i32 7, label %bb7.loopexit2
  ]

bb4:                                              ; preds = %tailrecurse
  %1 = add i32 %.tr, -1
  br label %tailrecurse

bb7.loopexit2:                                    ; preds = %tailrecurse
  br label %bb7

bb7.loopexit:                                     ; preds = %tailrecurse
  br label %bb7

bb7:                                              ; preds = %bb7.loopexit, %bb7.loopexit2
  %_0.0 = phi i32 [ 43, %bb7.loopexit2 ], [ 42, %bb7.loopexit ]
  ret i32 %_0.0
}

attributes #0 = { nounwind readnone uwtable }


Другое дело, что из вашего кода непонятно, то ли вы его неправильно написали, так как первоначальный вариант функции execute содержит точку с запятой в самом конце, что подразумевает, что последняя инструкция не новый execute(...), а просто (), пустая инструкция, такой код вообще по идее не должен скомпилироваться, потому что возвращаемое значение не совпадает с сигнатурой функции. То ли по какой-то иной причине не отработала оптимизация.
Спасибо, интересно.
Разумеется, Вы неправы, и тому есть одна простая фундаментальная причина.
Пушкин гений и великий классик не потому, что он как-то особенно точно выбирал слова. Это следствие. А причина заключается в том, что именно Пушкин изобрёл весь тот современный литературный язык, которым стали писать после него. Его до него просто не было.
Сравните. Вот поэзия XVII века:
Что ся ныне в нашему веку сотворило,-
то много ся злых дел расплодило.
Яко едва ж ести и нам у бога милости место,
коль тяшко от бояр народу и тесно.
Только умножися гордость и кривды.
яко ж и отнюдь не знают суда и правды.
Древних бо княжат уставы отвергоша
и вся древния судебники обругаша,
новые ж своя вся суетне поставляют,
и тем бесчисленно народу укривжают.

Вспомните, например, Ломоносова (всего полвека до Пушкина) с его идеей штилей и тяжёлым нечитаемым языком:
К словесным знаниям прехвальная охота.
Природный видит твой и просвещенный ум,
Где мысли важные и где пустых слов шум.
Мне нужен твоего рассудок тонкий слуха,
Чтоб слабость своего возмог признать я духа,
Когда под бременем поникну утомлен,
Вниманием твоим восстану ободрен.

И Пушкин, которого можно читать как обычный современный разговорный текст:
Мать и сын теперь на воле;
Видят холм в широком поле,
Море синее кругом,
Дуб зеленый над холмом.
Сын подумал: добрый ужин
Был бы нам, однако, нужен.

До Пушкина такого слога не существовало.
Удивительный мир виндовых разработчиков :)
Набор .exe, .dll и .bat-файл для упаковки как исходники. Круто)
Это всё демон i2p, а не браузер. И исходники, и сборка.
Тема сборки браузера (и где вообще его исходники) не раскрыта.
Вы серьёзно? Прямо на главную постите картинку со словом «БезопасТность»? :)

image
Ну ок, давайте на этом и остановимся. Я правда в этом треде кажется нигде не говорил про «плюсы плохие», но да, они разрешают стрелять в ногу, поэтому сделали не так.
Есть ещё варианты в стиле «человек с опытом паскаля решил помочь в опенсорс-проекте или на работе перекинули за отсутствием других возможностей», вполне себе типичная ситуация, не раз видел. Синтаксис знакомый, общие принципы можно по-быстрому где-то прочитать, сел и пошёл писать. Или этот ваш «начинающий профессионал» профукал и забыл этот момент в учебнике, не все же отличники.
> Это уже не для новчика.
Ну, не знаю, мне кажется, что новичок вполне может сразу гуй писать. Это студенту такое не дадут, а заставят до посинения писать алгоритмы сортировки, но студент != новичок.

> Это, конечно, может быть проблемой
Главная на самом деле проблема — это то, что такое знание энфорсится в программиста. Т.е. это правило написано в каких-то книжках, на любом форуме вам авторитетно объяснят, что вы идиот и должны сначала были читать учебник, но в лучших традициях C++ требование не прописано в стандарте, программисту разрешается стрелять в ногу «и так тоже», и вся надежда на добрую волю IDE и компилятора с их подсказками (которые программист конечно же не факт, что прочитает или не проигнорирует).

> Ресурсов это не сожрет.
Как же не сожрёт, когда сожрёт? :) И размер объекта вырастет:
0 ➜ compileOnce 'class A { public: ~A(){}}; class B { public: virtual ~B(){}}; std::cout << sizeof(A) << std::endl << sizeof(B) << std::endl;'
1
8

И производительность ухудшится (накладные расходы на походы в vtable). Другое дело, что важным это замедление станет ещё хрен знает когда, но факт есть :)
А ещё я видел библиотеку, где объявление реализации интерфейсного метода с virtual приводило к сегфолту! (т.е. в интерфейсе он был не virtual). Но это уже совсем другая история.

Информация

В рейтинге
1 990-й
Откуда
Москва, Москва и Московская обл., Россия
Зарегистрирован
Активность