Постироничные идеи для ебаного C++
Kanalga Telegram’da o‘tish
Ko'proq ko'rsatish
241
Obunachilar
Ma'lumot yo'q24 soatlar
Ma'lumot yo'q7 kunlar
Ma'lumot yo'q30 kunlar
Postlar arxiv
Иногда программе становится так хорошо, что хочется запечатлеть core dump. Умирать при этом ни к чему, как бы хорошо ни было. Извне обычно есть gcore и вообще gdb, а что же изнутри? Всё ещё проще:
if (int pid = fork()) {
waitpid(pid, nullptr, 0);
} else {
std::abort();
}
Упражнения по синтезу персистентных структур данных или неблокирующей сериализации слепков симуляции остаются на дом.Увага! Цей код містить монади - концепцію, занадто потужну для звичайних мов.
Go, звісно, не Haskell, але ми все одно запихнемо сюди монади,
щоб показати, що навіть у мові, яка виглядає як "Сі для дідусів",
можна писати у стилі "функціональщини для обраних".
Автор попереджає: після цього коду звичайний Go-код здаватиметься вам
жалюгідним і безглуздим, як життя без Maybe.
Maybe — наша спроба вдихнути душу в статичну типізацію Go.
У Haskell це зайняло б один рядок: "data Maybe a = Just a | Nothing"
Але ми ж у Go, тут треба розмазати на 20 рядків, зате "продуктивність"!
type Maybe[T any] struct {
value T
ok bool // так-так, це наш саморобний pattern matching
}
Just — тому що в Go немає нормальних конструкторів, робимо як уміємо
func JustT any Maybe[T] {
return Maybe[T]{value: value, ok: true}
}
Nothing — коли nil це занадто просто, а нам треба помучитися
func Nothing[T any]() Maybe[T] {
return Maybe[T]{ok: false}
}
Bind — наш кривий аналог ">>=".
У Haskell це було б гарно, а у нас — імперативний костиль.
Але зате "просто і зрозуміло" (ні)
func (m Maybe[T]) Bind(f func(T) Maybe[T]) Maybe[T] {
if m.ok {
return f(m.value)
}
return Nothing[T]()
}
Map — тому що без map/filter/reduce сучасні розробники
починають нервово чіхатися і питати "а де тут реактивність?"
func (m Maybe[T]) Map(f func(T) T) Maybe[T] {
if m.ok {
return Just(f(m.value))
}
return Nothing[T]()
}
func main() {
// Ох вже цей Go зі своєю "простотою"...
// У Haskell ми б написали:
// do
// x <- safeDiv 10 2
// y <- safeDiv x 5
// pure y
// Але ні, у Go треба ось це ось:
res := safeDiv(10, 2).Bind(func(x int) Maybe[int] {
return safeDiv(x, 5)
})
if res.ok {
fmt.Println("Результат:", res.value)
} else {
fmt.Println("Ділення на нуль!") // класика
}
}
Особливий привіт Go-шникам, які кажуть "нам не потрібні монади"...
Потім пишуть if err != nil у кожному другому рядку 😏
safeDiv — єдина адекватна річ у цьому коді.
Тому що ділення на нуль — це серйозно,
на відміну від дизайну Go.
func safeDiv(a, b int) Maybe[int] {
if b == 0 {
return Nothing[int]()
}
return Just(a / b)
}
Підсумок:
- Так, монади у Go виглядають як велосипед з квадратними колесами
- Так, це абсолютно неідіоматично для Go
- Так, будь-який Haskell-розробник ридає у куточку
- Але ж ми довели, що навіть у Go можна страждати правильно!
P.S. Дорогий Go, ми тебе любимо, але іногда так хочеться pattern matching...Go це C з корутинами та GC. Я коли вперше на нього натрапив, то подумав, що це мова 1990-х років. Ледве не впав зі стільця, коли дізнався, що його зробили в 21-му столітті. Начебто автори провели 20 років у якійсь криокамері, повністю ізольовані від прогресу в галузі ЯП.
Repost from котики
инт, флоат, я дал той телке в рот
стек, дек, я с кокаином друг на век
поток, дедлок, в моем кармане лежит глок
си-ин, си-аут, кидаю твоей маме шатаут
Обратные слэши для экранирования переводов строк в языке избыточны. Многострочные макросы можно было бы писать и без них.
#define foo() /*
*/ do { /*
*/ bar(); /*
*/ baz(); /*
*/ } while (false)Неустранимые разногласия между WG14 и WG21 заставляют первых действовать решительно.
Драфт стандарта C26 не включает в себя изменений относительно C23, кроме шести новых заголовков в стандартной библиотеке C.
/* Header <harconv.h> synopsis */
#define hex 1 /* on platforms supporting IBM HFP */
/* Header <ompare.h> synopsis */
#define is_eq(arg, ...) 0 /* idiomatic FP comparison */
/* Header <omplex.h> synopsis */
#define real double /* consistency with Pascal */
/* Header <oncepts.h> synopsis */
#define regular 1 /* on platforms which are not weird */
/* Header <ontracts.h> synopsis */
#define pre 1 /* in compilers which support preprocessing */
/* Header <oroutine.h> synopsis */
#define promise 1 /* in compilers which promise conformance */Эта особенность замыканий в C++ всем известна: они очень любят создавать новый тип, которого больше нет нигде в программе. Причём они умеют это делать даже тогда, когда в единице трансляции встречаются один раз.
Это создаёт как удивительные возможности:
template<typename T = decltype([]{})>
using CreateNewType = T;
static_assert(not std::is_same_v<CreateNewType<>, CreateNewType<>>);
using SavedType = CreateNewType<>;
static_assert(std::is_same_v<SavedType, SavedType>);
static_assert(not std::is_same_v<SavedType, CreateNewType<>>);
...так и удивительные неприятности:
// yob.hpp
template<auto F>
struct OnDestroy {
~OnDestroy() { F(); }
};
using LoudDestroy = OnDestroy<[] { std::cout << "Goodbye"; }>;
void consume(LoudDestroy);
// yob.cpp
#include "yob.hpp"
void consume(LoudDestroy) {}
// main.cpp
#include "yob.hpp"
int main() {
consume({}); // linker error with clang
}
Значит, это идеальный кандидат для признания фичей C++. Предлагаю создать более удобный синтаксис для подобных выражений, генерирующих свой тип:
// yob.hpp
void foo(int) = delete;
void bar(int) = new;
// yob.cpp
#include "yob.hpp"
void bar(int) {}
// main.cpp
#include "yob.hpp"
int main() {
foo(15); // compiler error
bar(23); // linker error
}СВОевременное импортозамещение
https://github.com/yandex/tomita-parser/blob/master/src%2Futil%2Fgeneric%2Fstroka.h#L3-L4
https://github.com/includeos/IncludeOS?tab=readme-ov-file
Попробуйте найти во freestanding имплементации C++ упоминание о том, что она freestanding!
+1
Дискурс о целесообразности геймдева на Rust породил много интересного материала, но почему-то мало внимания уделено одной из важнейших проблем.
Как мне писать свой шутер на языке, в котором
box и crate - зарезервированные ключевые слова?Конечно, автоформаттер - это не просто pretty-printer для синтаксического дерева, гарантирующий round-trip. Он обязан сохранять на месте всю информацию, предназначенную для людей, такую как названия переменных и комментарии.
Как хорошо, что инструменты вроде clang-format и rustfmt полагаются на детерминистичные алгоритмы, а не модные языковые модели! Они всегда сохранят (а иногда и проверят) валидность кода и не подвержены синтаксическим галлюцинациям.
