Size: a a a

2020 April 25
Блог*
> - ничего этого не делать, ведь и так все работает, а никто про эту ссылку все равно не узнает

Узнает, узнает. #prog #math
источник
Блог*
Category Theory for Programmers
Вот тут исходники сборщика: https://github.com/kana-sama/rumilewski

Многие знают что тут (https://henrychern.wordpress.com/2017/07/17/httpsbartoszmilewski-com20141028category-theory-for-programmers-the-preface/) можно скачать полный перевод этой книги на русский. Но каждая глава там в отдельном файле, а ссылки на всю книгу нет. Переводы же иногда обновляются, поэтому разово собранный файл со временем устаревает.

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

В планах:
- прикрутить нормальный домен
- добавить какой-то интерфейс
- возможно сделать бота вместо сайта
- ничего этого не делать, ведь и так все работает, а никто про эту ссылку все равно не узнает

Скачать полную русскую версию книги (всегда актуальную)
источник
Блог*
dereference_pointer_there
#prog

Leetcode проводит челлендж: 30 дней задач по программированию, из числа тех, что задают на интервью. Обещают простые задачи. Для тех, кто хорошо решает, разыгрываются призы.

Только, это... Уже неделю как идёт.

leetcode.com/explore/featured/card/30-day-leetcoding-challenge/
До конца осталось меньше недели
источник
Блог*
Кажется, мы стали забывать, что означает настоящий clip art
источник
Блог*
#prog #rust #article

Инженеры Dropbox рассказывают про переписывание движка синхронизации файлов. Первая статья скорее обзорная, перечисляет причины, подвигнувшие команду на этот шаг. А вот вторая, про тестирование этого самого движка, уже гораздо богаче на технические детали. В частности, представлен отличный случай, когда оправдано использование собственного экзекутора
источник
2020 April 26
Блог*
#quotes
источник
Блог*
Переслано от Dr. Friedrich von Ne...
Говорят, что Бог, когда увидел YAML, послал на Землю ангелов, чтобы они сожгли тут всё нахер.
источник
2020 April 27
Блог*
Интересный вопрос. Хотя я не уверен, что и после карантина маски останутся столь же массовыми
источник
Блог*
Когда закончится корона, станут ли маски новым массовым предметом одежды по всему миру?
Анонимный опрос
30%
Да
47%
Нет
23%
Хз
Проголосовало: 168
источник
2020 April 28
Блог*
#prog #article

Конец эпохи, можно сказать. Дедфуд официально объявил, что устал от C++ и вообще выгорел.

It's RESF time!

habr.com/ru/post/497114/
источник
Блог*
dereference_pointer_there
#prog #article

Конец эпохи, можно сказать. Дедфуд официально объявил, что устал от C++ и вообще выгорел.

It's RESF time!

habr.com/ru/post/497114/
#prog #article

(По ссылке из статьи)
Может ли апгрейд gcc с gcc-9 до gcc-10 сломать софт? Разумеется, может. Как ни странно, больше всего проблем принёс сам факт инкремента версии... Но об этом подробнее в самой статье.

trofi.github.io/posts/213-gcc-10-in-gentoo.html
источник
Блог*
источник
Блог*
#prog #meme
источник
Блог*
Нет.
источник
2020 April 29
Блог*
#prog #моё

Люди, которые пишут на Go, в качестве преимущества этого ЯП выставляют его простоту. Согласно аргументации сторонников Go, отсутствие навёрнутых возможностей приводит к тому, что все программисты пишут понятный код. Ну, с тем, что Go простой, действительно спорить не приходится, а вот вывод из этого факта лично мне кажется сомнительным. Почему же? Что ж, начну издалека.

У меня есть один знакомый (попросивший его не называть), который говорил мне, что является программистом средней руки и большую часть времени пишет весьма приземлённый код. В качестве доказательства он прислал кусок своего кода:

func getIDsForTextSearch(sortedIDs []string, spottedIDsWithDocCount map[string]int, paging paging) ([]string, int) {
 var countDocsNeedForRequest int
 var countIDsNeedToShow int
 
 sortedByDateSpottedIDs := []string{}
 IDsForSearch := []string{}
 
 for _, k := range sortedIDs {
   if _, wasSpotted := spottedIDsWithDocCount[k]; wasSpotted {
     sortedByDateSpottedIDs = append(sortedByDateSpottedIDs, k)
   }
 }
 
 if len(sortedByDateSpottedIDs) < paging.Offset + paging.Limit {
   countIDsNeedToShow = len(sortedByDateSpottedIDs)
 } else {
   countIDsNeedToShow = paging.Offset + paging.Limit
 }
 
 for i := paging.Offset; i < countIDsNeedToShow; i++ {
   id := sortedByDateSpottedIDs[i]
   IDsForSearch = append(IDsForSearch, id)
   countDocsNeedForRequest += spottedIDsWithDocCount[id]
 }
 
 return IDsForSearch, countDocsNeedForRequest
}

Конечно, имена по энтерпрайзной моде усложняют понимание этого кода, но я смог уловить его суть — другое дело, что для этого мне потребовалось переписать его на Rust (место для вашего саркастического комментария о моих умственных способностях). Как оказалось, смысл этого кода таков: взять из sortedIDs строки, содержащиеся в spottedIDsWithDocCount, и выделить из этой последовательности окно длиной paging.Limit, начиная с paging.Offset-го элемента, попутно просуммировав связанные с этими id количества. Код достаточно прямолинейный и неисправимо последовательный, так что киллер-фича Go — горутины — здесь не пригодится. Не буду утомлять вас промежуточными версиями переписывания и покажу сразу конечный результат:

fn get_ids_for_text_search(
   sorted_ids: &[String],
   spotted_ids_with_doc_count: &HashMap<String, usize>,
   paging: Paging,
) -> (Vec<String>, usize) {
   sorted_ids
       .iter()
       .filter_map(|s| {
           let &count = spotted_ids_with_doc_count.get(s)?;
           Some((s, count))
       })
       .skip(paging.offset)
       .take(paging.limit)
       .fold((Vec::with_capacity(paging.limit), 0), |(mut ids, total), (s, count)| {
           ids.push(s.clone());
           (ids, total + count)
       })
}


В оригинальной программе на Go не так уж и много сущностей, и все из них можно выучить, пройдя официальный тур по языку. Rust же, как язык, безусловно сложнее, чем Go, и в моём варианте куда больше элементов:

* ссылки (в том числе и ссылки на String)
* различие между Vec<String> и &[String]
* замыкания
* четыре различных комбинатора итераторов (включая fold, понимание которого у многих новичков почему-то вызывает проблему)
* тип Option
* оператор ?
* явно обозначенная мутабельность
* явное копирование строк

С другой стороны, этот вариант куда лучше (на мой безусловно пристрастный взгляд) передаёт смысл функции. В нём построчно записано следующее: взять строки из sorted_ids, выделить из них те, которые лежат в spotted_ids_with_doc_count, пропустить первые paging.offset из них, взять первые paging.limit из них (выделив, таким образом, интересующий нас диапазон) и затем неразборчивое бормотание, получив список всех строк и сумму всех связанных с ними значений. Здесь практически нет явных изменений переменных, процесс описан скорее в терминах трансформации потока данных.
источник
Блог*
Является ли это единственным достоинством нового варианта? Отнюдь.

Оригинальный код собирает промежуточный слайс — в моём варианте собирается только конечный результат (причём память выделяется заранее).
Оригинальный код дважды делает поиск в мапе по итоговым строкам — здесь же поиск осуществляется единожды.
Оригинальный код проходит по всему слайсу sortedIDs — в ржавом варианте обход заканчивается, когда набирается достаточно подходящих строк.
Оригинальный код рассчитывает на то, что в sortedByDateSpottedIDs будет как минимум countIDsNeedToShow строк — в варианте ниже итоговый вектор просто будет содержать меньше paging.limit строк, если их не хватает (это, кстати, можно считать как плюсом, так и минусом, но надо отметить, что нарушение этого ожидания в оригинальном варианте вызовет панику из-за некорректного индекса, а в моём варианте можно постфактум проверить длину возвращённого вектора).

Все эти итераторы в итоге успешно компилируются в единый цикл, так что эффективность в рантайме не страдает. Можно ли применить те же техники оптимизации для Go? Конечно. Вот код, вторично переведённый на другой язык:

func getIDsForTextSearch(
 sortedIDs []string,
 spottedIDsWithDocCount map[string]int,
 paging paging,
) ([]string, int) {
 idsForSearch := make([]string, 0, paging.Limit)
 skip := paging.Offset
 iterated := 0
 total := 0
 
 for _, id := range sortedCallIDs {
   if iterated >= paging.Limit {
     break
   }
   count, spotted := spottedIDsWithDocCount[id]
   if !spotted {
     continue
   }
   if skip > 0 {
     skip--
     continue
   }
   iterated++
   idsForSearch = append(idsForSearch, id)
   total += count
 }
 return idsForSearch, total
}

Всё при нём: единственный цикл, один слайс с предварительно выделенной памятью, ранний выход из цикла при достижении нужного количества строк... Что же не так? А вот что: наглядность отсутствует напрочь.  Помимо двух возвращаемых значений, есть две технические переменные, которые нужно менять, и три условных оператора, которые нужно расставить в правильном порядке — или получить странные баги. Также тут есть пара мест для того, чтобы сделать ошибку на единицу. Но технически это всё ещё достаточно простой код. Вот только с запашком. Я бы на код-ревью подумал бы, стоит ли такой код пускать в прод.

Подведём итоги. У множества задач есть сложность, которую нельзя просто убрать. При дизайне языка программирования можно на него выделить разный бюджет сложности. Создатели Go намеренно этот бюджет урезали, создатели Rust сильно ограничивать не стали (что логично, учитывая, что Rust долго развивался эволюционно, без изначального видения идеального ЯП — и развивается и по сей день). Последствия этих выборов достаточно ожидаемы: в Go сложность задачи размазывается по достаточно объёмному коду, в то время как Rust позволяет использовать сложность языка для того, чтобы получить в итоге относительно простое решение. Кто-то может сказать, что перемещения сложности туда-сюда погоды не делают, и итоговая сложность остаётся той же. Я не могу с этим согласится. Да, Rust относительно сложен (уж точно сложнее Go — и это не хвастовство, а просто констатация факта), но язык, равно как и стандартная библиотека для него, учится один раз, в то время как последствия излишней простоты дизайна языка приходится разгребать в коде постоянно. Лично для меня подобная однократная инвестиция, которая впоследствии пригодится множество раз, видится более разумным выбором — но вы, разумеется, вольны со мной не согласиться.

Спасибо, что пришли на мою лекцию TED
источник
Блог*
dereference_pointer_there
#prog #моё

Люди, которые пишут на Go, в качестве преимущества этого ЯП выставляют его простоту. Согласно аргументации сторонников Go, отсутствие навёрнутых возможностей приводит к тому, что все программисты пишут понятный код. Ну, с тем, что Go простой, действительно спорить не приходится, а вот вывод из этого факта лично мне кажется сомнительным. Почему же? Что ж, начну издалека.

У меня есть один знакомый (попросивший его не называть), который говорил мне, что является программистом средней руки и большую часть времени пишет весьма приземлённый код. В качестве доказательства он прислал кусок своего кода:

func getIDsForTextSearch(sortedIDs []string, spottedIDsWithDocCount map[string]int, paging paging) ([]string, int) {
 var countDocsNeedForRequest int
 var countIDsNeedToShow int
 
 sortedByDateSpottedIDs := []string{}
 IDsForSearch := []string{}
 
 for _, k := range sortedIDs {
   if _, wasSpotted := spottedIDsWithDocCount[k]; wasSpotted {
     sortedByDateSpottedIDs = append(sortedByDateSpottedIDs, k)
   }
 }
 
 if len(sortedByDateSpottedIDs) < paging.Offset + paging.Limit {
   countIDsNeedToShow = len(sortedByDateSpottedIDs)
 } else {
   countIDsNeedToShow = paging.Offset + paging.Limit
 }
 
 for i := paging.Offset; i < countIDsNeedToShow; i++ {
   id := sortedByDateSpottedIDs[i]
   IDsForSearch = append(IDsForSearch, id)
   countDocsNeedForRequest += spottedIDsWithDocCount[id]
 }
 
 return IDsForSearch, countDocsNeedForRequest
}

Конечно, имена по энтерпрайзной моде усложняют понимание этого кода, но я смог уловить его суть — другое дело, что для этого мне потребовалось переписать его на Rust (место для вашего саркастического комментария о моих умственных способностях). Как оказалось, смысл этого кода таков: взять из sortedIDs строки, содержащиеся в spottedIDsWithDocCount, и выделить из этой последовательности окно длиной paging.Limit, начиная с paging.Offset-го элемента, попутно просуммировав связанные с этими id количества. Код достаточно прямолинейный и неисправимо последовательный, так что киллер-фича Go — горутины — здесь не пригодится. Не буду утомлять вас промежуточными версиями переписывания и покажу сразу конечный результат:

fn get_ids_for_text_search(
   sorted_ids: &[String],
   spotted_ids_with_doc_count: &HashMap<String, usize>,
   paging: Paging,
) -> (Vec<String>, usize) {
   sorted_ids
       .iter()
       .filter_map(|s| {
           let &count = spotted_ids_with_doc_count.get(s)?;
           Some((s, count))
       })
       .skip(paging.offset)
       .take(paging.limit)
       .fold((Vec::with_capacity(paging.limit), 0), |(mut ids, total), (s, count)| {
           ids.push(s.clone());
           (ids, total + count)
       })
}


В оригинальной программе на Go не так уж и много сущностей, и все из них можно выучить, пройдя официальный тур по языку. Rust же, как язык, безусловно сложнее, чем Go, и в моём варианте куда больше элементов:

* ссылки (в том числе и ссылки на String)
* различие между Vec<String> и &[String]
* замыкания
* четыре различных комбинатора итераторов (включая fold, понимание которого у многих новичков почему-то вызывает проблему)
* тип Option
* оператор ?
* явно обозначенная мутабельность
* явное копирование строк

С другой стороны, этот вариант куда лучше (на мой безусловно пристрастный взгляд) передаёт смысл функции. В нём построчно записано следующее: взять строки из sorted_ids, выделить из них те, которые лежат в spotted_ids_with_doc_count, пропустить первые paging.offset из них, взять первые paging.limit из них (выделив, таким образом, интересующий нас диапазон) и затем неразборчивое бормотание, получив список всех строк и сумму всех связанных с ними значений. Здесь практически нет явных изменений переменных, процесс описан скорее в терминах трансформации потока данных.
Последовал советам профессионалов, так сказать
источник
Блог*
#prog #article

Дежурное напоминание, что C — не "близкий к железу" язык.

queue.acm.org/detail.cfm?id=3212479
источник
2020 April 30
Блог*
#prog #article

В истории этого бага прекрасно решительно всё.

lwn.net/Articles/342330/
источник
Блог*
Количество подписчиков моего блога медленно, но неуклонно растёт. Я начал подумывать о том, чтобы дать своему каналу какое-то более выделяющееся имя, ибо из опыта общения с людьми, знающих о канале, я понял, что астериск в названии канала ("Блог*") многие не считают частью названия, а скорее индикатором исправления опечатки. В связи с этим я бы хотел у вас узнать...
источник