Pull to refresh
khim @khim read⁠-⁠only

User

Send message

Уж так прям и нормой? А ничего, что Raspberry PI выпускается тиражом меньше десяти миллионов штук в год, а рынок микроконтроллеров - это больше десяти миллиардов штук в год?

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

Вы бы лучше про MicroPython вспомнили. У него требования полегче, можно где-нибудь на 5-10% встраиваемых систем запустить.

Но как только мы выходим за рамки штучных поделок — так сразу смысл его использования теряется. Так как платформы, способные запустить что-то на MicroPython всё равно в разы дороже, чем те, которые поддерживают C/C++/Rust.

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

Если хочется обсудить проблемы с UB, то приводить realloc в пример — так себе идея.

А почему, собственно?

Уже и не помню, когда в последний раз им пользовался.

А какая разница? Нам же важно понять: имеет ли смысл та логика, которой руководствуются компиляторы или нет.

В математике для этого обычно берутся вырожденные примеры. realloc — как раз такой. Подробно описан в стандарте, но редко пользуется, потому сослаться на то, что эта горе-оптимизация ломает важну программу нельзя.

А вот это — корректно:

intptr_t p1 = static_cast<intptr_t>(p);
void* q = realloc(p, newsize);
if (p1 == static_cast<intptr_t>(q)) { ... }

Ух ты, прелесть какая. А вот совершенно неясно - оно корректно или нет. Нет, clang считает, что так тоже нельзя. Хотя тут мы вообще не используем ужасный, кошмарный, “отравленный” указатель и сравниваем просто числа.

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

Ровно по этой же причине, кстати, не удаётся и добавить pointer provenance в стандарт с 2004го года. Просто никому не удаётся придумать такие правила, которые бы, с одной стороны, позволяли разработчикам компиляторов производить все те оптимизации (ну или большинство, хотя бы) , которые они напридумывали, а с другой — не приводили бы к тому, что масса ну совершенно очевидно правильных программ не оказались бы поставлены “вне закона”.

Чаще пользуюсь или своими обёртками, или фреймворками, или функциями ОС.

О! У меня для вас хорошая новость! В соотвествии с “креативным” прочтением стандарта у вас вообще не может быть такой функции, как mmapили munmap. Совсем. Никогда.

Потому, собственно, описание malloc/calloc/realloc/free и оказалось частью стандарта, что их написать на стандартном C в принципе нельзя.

Ибо только вот первые три функции могут создавать области памяти, к которым может обращаться корректная программа, а последние две — удалять.

Они могут это делать потому, что являются частью стандарта и, соотвественно, могут делать то, что никакие другие функции делать не могут.

А никакие другие способы, не сводящиеся к этой четвёрке, невозможны и, соотвественно, функции map/unmap (и их аналоги в Windows) — вызывать, в корректной, программе, нельзя.

Правда, как великая уступка разработчикам, компиляторы реальные программы, вызываеющие эти функции стараются не ломать. Но это так — подачка “немытой толпе” (вернее боязнь того, что уж настолько безумный компилятор всё-таки люди не захотят использовать), стандарт позволяет безвозбранно любые подобные программы крушить.

Вы счастливы?

Да не держат они в уме всякие Эльбрусы. Забудьте.

Оптимизация, которая там делается (превратить *q в 1, а *p в 2) в некотором смысле напрашивается. Но она опасна. Валидна только тогда, когда можно доказать, что *p и *q укаывают в разные места памяти.

И, разумеется, это не новая проблема. Ещё во время первоначальной стандартизации C была сделана попытка добавить ключевое слово noalias, чтобы эту проблему решить.

Возражения некоего частного лица привели к тому, что эту затею, в тот раз отставили.

В C99 к этой затее вернулись и добавили в язык __restrictсо слегка другой семантикой.

Однако это тоже, особо не сработало: люди редко исползуют __restrict и ещё реже — правильно.

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

И вот тут-то кому-то из разработчиков компиляторов в голову пришла мысля (скорее всего не одному): у нас же в языке имеются десятки разных интересных UB (которые там появились по совсем другому поводу) и у нас есть разрешение в случае возникновения UB делать что угодно (такое разрешение, кстати, тоже появилось в C99, не в C89, некоторые даже приписывают соотвествующему изменению злой умысел, хотя на самом деле, почти наверняка, просто потому что ограничения на то, что такое UB, прописанные в C89, опираются на понятия, в нём не описанные и, конечно, гораздо проще их снять, чем формализовать). давайте их активно находить и тот факт, что они не выполняются — использовать (программа же их не исполняет, ей запрещено, значит код, вещущий к UB, тоже не исполняется, значит его можно выкинуть).

Начавшаяся после этого борьба брони и снаряда — почти привела к катастрофе: оказалось, что люди, в общем, когда программы пишут решают прикладные задачи и тесты гоняют, а не ребусы на тему “а нет ли у нас тут UB? а если покреативней поинтерпретировать — всё равно нет? а если воображение напрячь?”.

Оказалось, что, в общем, воображение у разработчиков компиляторов посильнее, чем у остальных программистов (см. обоснование безумия с realloc в C99).

Но настоящая катастрофа произошла тогда, когда разработчикам компиляторов оказалось и этого мало, они выбили себе разрешение прописать себе в стандарт дополнительные UB (читаем внимательно: it would be desirable for the Standard to mean это ни разу не mean, это всего лишь позволение изменить стандарт, не признание того, что стандарт что-то там кому-то позволяет), но не сделав этого, начали этим фиговым листком прикрываться.

В результате мы получили язык для которого не существует ни одного современного компилятора! Да, вот так, просто: ни одного!

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

Кстати ваш пример с преобразованием указателей в intptr_t и обратно как раз и является одним из камней предкновения. Ибо в соотвествии с буквой стандарта он валиден, а объявить его невалидным и сказать, что какой-нибудь XOR-связный список — невалидная конструкция у них наглости пока не хватает. А без этого у них никак не получается (уже второй десяток лет не получается!) придумать непротиворечивые правила работы с указателями, которые позволили бы им ломать программы и дальше делать те оптимизации, которые они уже делают.

Вот такая вот ужасная драма, где никто, вроде, не виноват, а убытки исчисляются миллиардами (хорошо если не триллионами).

Проблема в том, что долгое время никто не мог придумать: что же, всё-таки, с этим делать. Понятно, что хочется как-то сделать так, чтобы в языке UB не было совсем (во многих других языках их нет: C#, Java, JavaScript и так далее), но было непонятно как удалить UB из языка без GC: у вас же, в таком языке, можно удалить объект, на который, где-то там ещё, есть “живые ссылки”! А можно ведь, ко всему прочему, из разных потоков, параллельно, память менять, там тоже разные процессоры много разного интересного может насчитать.

Решение Swift было промежуточным, почти как у языков с GC: а давайте мы сделаем малоинвазивный GC на счётчиках, тяжёлый рантайм ему не нужен, но безопасность можно обеспечить. А все опасные конструкции вынесем в стандартную бибиотеку.

Такой себе недо-managed язык. Если компилятор сможет, в некоторых местах, манипуляции со счётчиками извести — он может даже достаточно быстрым оказаться. Вроде как проблемы скорости всё равно не решились, впрочем (Apple, по итогу, сделала аппаратное ускорение в свои процессорах, но такое могут себе позволить себе не все).

А вот Rust сделал куда более интересную вещь: предложил отдельно пометить все места в программе, где ипользуются конструкции, которые могут вести к UB! И оказалось, что, при должном упорстве, можно сделать так, чтобы в большой программе так было пемечено где-то 1% года!

А в остальной программе пусть UB не будет (утечка памяти — это не UB).

Это было смелое решение, в которое, если честно, я много лет не очень верил. Смотрел на то, как они барахтаются, но не верил, что они могут сделать язык, близкий по выразительности и скорости к C++, но без UB (ну Ok, “почти без” UB, “минное поле” в 1% кода это куда лучше, чем “минное поле” в 100% кода).

Но судя по тому что происходит в последние год-два (поддержка крупными компаниями, попытки переписать драйвера в Linux на Rust и так далее) — они смогли.

Оперевшись на весьма интересное наблюдение: программисты на “современном C++” и без того очень часто используют std::unique_ptr и часто действуют в парадигме блокировки-чтения записи, когда у вас в программе есть, у каждого объекта, либо один писатель, либо много читателей (но писателей тогда нет ни одного, XOR а не OR).

Это позволяет решить проблему с UB, но некоторые конструкции оказываются невозможными (например банальную очередь создать уже нельзя).

С другой стороны — так ли часто вы пишите неблокирующие стеки и очереди? Я наблюдал как-то за этим увлекательным процессом. Там на примерно 100 строк кода ушло две недели написания, а количество строк с описанием было примерно на порядок больше, чем кода. И это после того, как описание сильно упорядочили и порезали (добавив ссылок на несколько статей).

Уж если вам что-то такое захочется ещё раз сделать — добавить туда немного меток unsafe проблемой явно не будет.

В примере с q = realloc(p, …) вы не имеете права использовать p после успешного вызова, т.е. когда q != NULL: ни разыменовывать, ни сравнивать.

С какого такого перепугу?

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

А вот фиг. Вы же сами привели цитату правильного места и даже выделили, просто не захотели в неё вчитаться. Вот про разименование указателия:

until the space is explicitly freed or reallocated

Использовать указатель нельзя в двух случаях: когда память освобождена и когда она реаллоцирована.

А вот и про испольование самого значения указателя:

The value of a pointer that refers to freed space is indeterminate

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

И кстати, то же самое даже в C18. Там это правило вообще в другом месте, но звучит оно так: The behavior is undefined in the following circumstances: … the value of a pointer that refers to space deallocated by a call to the free or realloc function is used.

Обратите внимание: тут снова идет не речь об указателе на исчезнувший объект, а об указателе, указывающем на освобождённую память. А вот сравнить два указателя (чтобы понять, указывают один из них на освобождённую памяти или нет) нам разрешили явно: The realloc function returns a pointer to the new object (which may have the same value as a pointer to the old object), or a null pointer if the new object has not been allocated.

Вот это вот самое замечание в скобочках явно разрешает нам эти указатели сравнивать. Если бы их сравнение приводило бы к UB, то замечание в скобках не имело бы смысла. Собственно оно и было добавлено, чтобы эти указатели можно было сравнивать, в C89 этого было не нужно (ещё раз читаем о том, когда указатели можно сравнивать, а когда разименовывать).

Освобождённый указатель не «указывает на место в памяти один-после-конца массива», а равнозначен неинициализированному.

Нет. Сравнивать нам эти два указателя разрешили явно, а это значит, что вступет в игру правила сравнения указателей:

Two pointers compare equal if and only if both are null pointers, both are pointers to the same object (including a pointer to an object and a subobject at its beginning) or function,both are pointers to one past the last element of the same array object, or one is a pointer to one past the end of one array object and the other is a pointer to the start of a different array object that happens to immediately follow the first array object in the address space.

Тут у нас появился очень-очень интересный момент, которого в C89 не было. Там правило было другое:

If two pointers to object or incomplete types compare equal. they both are null pointers. or both point to the same object. or both point one past the last element of the same array object.

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

А в C99, да, поскольку обращаться к объекту, который был уничтожен нельзя (этого момента в C89 тоже нет, как и уничтожения и создания нового объекта в realloc), и у нас резрешён невозможный в C89 случай, когда два указателя равны, но один из них валиден, а другой невалиден, то можно попробовать сову на глобус натянуть и объяснить, что, поскольку объект-таки удалён, а на его месте теперь новый, то даже если два указателя равны, то одним можно пользоваться, а другим нельзя. Ну, типа объект схлопнулся, память мы не освободили, но объект уничтожили, потому это — теперь вот такой вот one past the end of one array object указатель.

Мне эта интерпретация кажется несколько, как бы это сказать, безумной, но ещё раз повторяю: в C89 она вообще невозможна. Так как там не бывает такого, что указатели равны, но один валиден, а другой — нет. И объекты в realloc не удаляются и не создаются. А всего лишь перемещаются: The realloс function changes the size of the object pointed to by ptr to the size specified by size. и The realloс function returns either a null pointer or a pointer to the possibly moved allocated space.

Увы, нет никакого способа придумать как сделать эту программу невалидной в C89. Я с разработчиками компиляторов общался и некоторым количеством людей, которые в комитете по стандартизации заседают — никто не смог. Они честно пытались.

Максимум, чего удалось добиться — упоминания того, что C89 это очень старый стандарт (а ничего что ещё пару лет назад один очень распространённый компилятор ничего новее не поддерживал?) и сегодня не актуален, а для C99, видите, мы какую шнягу красивую придумали.

Поэтому пожелания «описать все случаи неопределённого поведения» абсурдны — примерно как попытка описать число через его неописуемость.

Это что за идиотизм? Открываете любой стандарт C (не C++!), смотрите в приложение J. Там все случаи описаны.

В C++ они не сгруппированы в одном месте, а разбросаны по тексту, но тоже все описаны.

Неопределённое поведение не означает, что ситуация, в которой оно возникает не определено. Вот последствия — да, не определены. А действия, совершаемые программой для того, чтобы мы могли заявить “да, у нас-таки случилось UB” все описаны, в противном случае мы не могли бы вообще, в принципе, определить — приводит программа к UB или нет, определено её поведение или может быть любым.

Другими словами: это не какие-то особые запрещённые случаи, прихотливо разбросанные по пространству допустимых программ.

Это особо запрещённые случаи, прихотливо разбросанные по множеству допустимых действий. И то, что они не определены в стандарте не означает, что они совсем никак и никем не определены.

Пример: разименование нулевого указателя. В разных системах это может привести к разным последствиям (скажем в MS DOS вы обратитесь к адресу обработчика нулевого перерывания и можете его испортить, а в Linux или Windows x64 система отдиагностирует ошибку и вашу программу остановит… хотя ошибку можно перехватить и обработать).

Я не знаю вообще ни одной системы, где бы это поведение не было бы описано! Да, не в стандарте C или C++, а в стандарте POSIX или в даташите на SOC… но оно таки описано!

Но разработчикам копиляторов пофиг: раз стандарт C++ говорит, что это неопределённое поведение — значит у нас карт-бланш, будем крушить всё, до чего сможем дотянуться.

Или другая “типа оптимизация”, превращающая i || !i не в true (что было бы понятно и логично), но в false. Это не так-то просто было сделать, закон исключённого третьего, вроде бы, должен бы подобные вещи отсекать. Но… напряглись! Смогли! Ура, товарищи, теперь программисты получили ещё один способ выстрелить себе в ногу!

И я не знаю ни одного случая, когда поведение, определённое более старым стандартом языка, в более новом становилось бы неопределённым.

Врёте. Вот в том самом примере с realloc, вокруг которого столько копий ломали никто так и не придумал как можно найти UB, интерпретируя программу с точки зрения C89. Ибо “гениальная” интепретация “когда realloc вернул тот же указатель, что и до вызова realloc, то это всё равно другой объект” можно вычитать из C99 и последующих стандартов, но не из C89.

Да и то — их нужно невероятно “креативно” читать, чтобы в этой программу UB углядеть. Нормальному программисту никогда в жизни не придёт в голову идея, что вот такой вот код: p = realloc(q, …); делает q, внезапно, указывающим на место в памяти один-после-конца массива (нулевого размера, видимо)! А только такая, “креативная”, интерпретация позволяет заявить, что в этой программе имеется UB.

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

Ни то, ни другое, увы. Окройте же, наконец, пропозал, почитайте и ужаснитесь: там целая куча примеров того, как разные компиляторы ломают валидные программы — с предложением вот всё вот то безобразие, которое компиляторы вытворяют объявить валидным, а стандарт изменить, чтобы эти прораммы перестали быть валидными программами на C++.

Примерно как это уже произошло с realloc ом. А потому что в 2004м году было решение комитета по стандартизации, в стандарт ничего протащить не удалось (а ведь 17 лет прошло!), но компиляторы уже считают, что некоторые “плохие” (но не нарушающие стандарт, заметим!) программы можно ломать. И ломают. Красота?

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

Пока неясно — будет ли он развиваться или повторит судьбу бесконечных диалектов Nim, Oberon и прочей экзотики.

Rust сегодня поддерживают Amazon, Facebook, Google и Microsoft — то есть практически все крупные игроки, кроме Apple (у которых свой Swift есть и который они, конечно, не будут на Rust менять).

При этом, насколько я знаю, никто из них не решился пока перейти с C++ на Rust, но все они, по крайней мере, думают о такой возможности (а некоторые уже и планы перехода строят).

А для успеха языка поддержка его “большими” игроками очень много значит.

Потому практически, как я сказал, выбор между Rust и Swift сегодня. Завтра (образно: лет через 10, на практике-то) ситуация может и измениться.

Языки, способные заменить C/C++ хотя бы в теории.

Это довольно много ограничений: например C/C++ популярны в embedded, где невозможно использовать большую стандартную библиотеку или, тем более, GC.

Также, разумеется, туда не лезет JIT, а интерпретатор не годится из-за потребления ресурсов.

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

То есть речь идёт даже не просто о компилируемых языках, но о каком-то ограниченном подмножестве.

Долгое время сколько-нибудь популярных альтернатив для C/C++ просто не было (почему, собственно, разработчики компиляторов и могли вытворять то безобразие, которое они вытворяли: типа, всё равно ж будете жрать кактус, куда вы денетесь?).

Сейчас они появились, но их, мягко скажем, немного.

P.S. Строго говоря Rust и Swift не являются единственной альтернативой. Есть ещё D, Zig и внушительное количество ещё более экзотических языков. Но в случае с D такая возможность остаётся чистой теорий (теоретически без GC можно обойтись, практически же вы, в этом случае, не сможете использовать почти ничего из уже написанного кода), а больше в первой сотне языков на TIOBE я таких языков не вижу (хотя может чего и упустил, там есть много языков, о которых я мало чего знаю).

При этом от эпох комитет пренебрежительно отмахивается.

Если бы они только от эпох отмахивались. Они даже от предложений не ломать существующие программы, написанные в соответвествии с существующими стандартами (типа такого) отмахиваются.

Сложно, говорят, нам такой компилятор написать. Мы уже заложились на то, что разработчики правил pointer provenance не нарушают. А ну и что, что мы уже 20 лет не можем придти к единому мнению о том, как эти правила, всё-таки, должны работать.

Пофиг. Пусть машину времени купят, слетают в 2050й (или таки в 2100й?) год, узнают, что там мы таки, в конце-концов, придумали, вернутся назад и соблюдают.

Что? С покупкой машины времени затык? Не наши проблемы.

ЕМНИП там везде принудительный подсчёт ссылок. Любой системщик мгновенно поднимет на вилы. Плюс за пределами экосистемы эппла распространение стремится к нулю.

Со счётчиком ссылок компилятор неплохо борется. Со временем будет лучше. C++ так же развивался. Но то, что никто, кроме Apple, Swift не поддерживает — проблема, да.

Google немного поигрался, но забил, в конце концов.

Но это древняя традиция, ещё с прошлого века. Когда все переходили с C на C++ у Apple тоже был свой язычок — Objective C. Многие решения в Swift вызваеы необходимостью сосуществования с модулями на Objective C, а вне экосистемы Apple это никому не нужно, так что так и получается: у Apple — Swift, у всех остальных — Rust.

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

О том как и почему появилось это понятие я сам когда давно писал.

Когда неопределённое поведение появилось другой альтернативы этому всему, в общем, не было.

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

Лет десять назад это правило начало, довольно-таки грубо, нарушаться: компиляторы начали целенаправленно ломать программы, которые, формально приводили к неопределённому поведению, однако, при этом, работали годами и десятилетиями.

Более того: как сейчас выясняется ещё в 2004м году разработчики компиляторов выбили себе карт-бланш на UB, которые они до сих пор не могут описать!

Вдумайтесь в уровень этого идиотизма: правила, нарушение которых позволяет вашему компилятору сломать, к чёртовой матери, вашу программу до сих пор не описаны в стандарте потому что их никак не могут разработать (ибо там противоречия воникают), ни в одном стандарте их нет (одна из последних попыток их добавить), но если вы их нарушаете — то получаете проблемы. Класс, да? Как таким языком вообще можно пользоваться? Это ж минное поле получается!

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

Фишка же в том, что ровно это и предполагалось делать с C. Это было даже явно прописано в соответствующем документе: Undefined behavior gives the implementor license not to catch certain program errors that are difficult to diagnose. It also identifies areas of possible conforming language extension: the implementor may augment the language by providing a definition of the officially undefined behavior.

Выделение моё, но и первая часть тоже важна: неопределённое поведение, изначально, рассматривалось как что-то, что хорошие компиляторы могут отлавливать — но не обязаны. И со временем планировалось количество этих чудес уменьшать и делать язык более предсказуемым.

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

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

Можно долго обсуждать причины этого явления (вот, например, хорошая статья), но в сухом остатке: жалкие попытки вернуться к тому пути, который намечался в прошлом веке окончились ничем. К сожалению.

Раньше были архитектуры с 9-битными байтами, и не с комплементарным представлением отрицательных чисел.

Дык фишка вот в чём: сейчас таких архитектур нету и современные версии C++ их не поддерживают, однако компиляторам по прежнему разрешено ломать программы, которые пользуются тем, что в современных процессорах комплемендарное представление отрицательных чисел не используется!

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

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

Совершенно идиотское сочетание двух правил:

  1. Любая синтаксически корректоная программа, написанная пусть даже и 20 лет назад обязана компилироваться.

  2. Если при этом, во время исполненения, программа приводит к неопределённому поведению (в том числе не существовавшему на момент написания оной программы!) — то программу можно ломать.

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

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

Практически таковых есть два: Swift (у Apple) и Rust (для всех остальных).

Как с этим у С∀ — но, подозреваю, что ещё хуже, чем у C и C++.

Но зачем выбирать плюсы сегодня?

Не “зачем”, а “почему”. Потому что C++ можно использовать там, где все эти новомодные C#, JavaScript и прочие “пожиратели ресурсов” использовать нельзя.

Сейчас в любом автомобиле куча чипов (именно поэтому их нехватка так сильно бьёт по автопроизводителям), в любой кофеварке чип (а то и не один) и так далее и тому подобное.

И это, на сегодня, C++, вариантов нету: есть ещё Rust, конечно, но он пока ещё молод, если он C++ и вытеснит, так это лет через 10 будет.

На C# есть, конечно, и поддержка старых Windows-приложений, но в основном, думаю, это бекенд, Unity и немного Xamarin. И соотношение новых и старых проектов там сравнимо с другими языками.

C# это не только старые, но и новые Windows приложения. Всякие аддоны для Visual Studio можно только на C#, по большому счёту, писать. И да, это — это большой такой “континент”.

Java живёт за счёт “сурового Enterprise” и мобильной разработки (однако менее популярна среди разрабочиков на Linkedin).

JavaScript — это огромный Web-“континент”.

Однако вы не напишите операционку и не запрограммируете робота ни на C#, ни на Haskell. И на JavaScript — тоже.

Нет, разово, для себя, можно на чём угодно, даже на Python.

Но как только вам станет небезразличен BOM — вы снова вернётесь к C++. Потому C++ — это океан, где все эти континенты расположены.

И потому C++ — никуда не денется в ближайшее время.

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

Теоретически мог бы ещё Swift, то там политика вмешалась: Apple жёстко контролирует развитие Swift и меняет его так и тогда, когда это нужно для увеличения продаж iPhone, так что вряд ли его кто-то, кроме Apple, будет активно использовать.

P.S. Собственно это всё прямо на LinkedIn можно увидитеть: если смотреть чуть шире и посмотреть не на разработчиков C++/C#/Python/Java, а на вакансии, где требуется и что-то ещё, то тут уже C# окажется далеко позади, Python, Java, JavaScript уйдут вперёд, C++ слегка отстанет (но всё равно будет втрое более популярен, чем C#).

Вот и получается, что языки типа Rust, Scala, C++ или Haskell со всей их абстрактностью не являются “мейнстримными”.

Ну ладно: Haskell, Scala, Rust… но C++? Те же самые 77000 предложений, что и для C#.

Вы, вообще, по каким критериям “мэйнстриймовость” определяете?

Зачем Райт делал какой-то аэроплан, когда и на лошадях можно доехать ?

Главный-то вопрос не зачем, но как. Вот ключевой отрывок из книжки:

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

Братья соорудили свою “этажерку”, так как чётко знали что за проблемы они и решают и понимали, что “узкое место” — именно там. Проведя сотни опытов и набрав статистику.

Вы же пытаетесь что-то такое “творить” особо не разобравшись в том что ж вы такое творите, зачем, и, главное, не выяснив что является проблемой, а что — нет.

Что позволило сохранить страну и вам не пришлось искать работу сборщиком клубники в Польше или строителем в России.

Так или это плохо?

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

Тут, как бы, либо крестик, либо трусы.

Если банки могут о вас всё узнать, так и налоговая — тем более. Со всеми вытекающими.

А с другой стороны, если вы так законспирировались, что банки ничего понять не могут — так и с ипотекой у вас таки будут проблемы.

Бояться того, что налоговая вами заинтересуется, если у вас ипотека — не стоит. Масса знакомых с серой ЗП, платящих ипотеку и ни ни к кому налоговая не проявляла интерес.

А когда-то с подобным же подходом люди брали в валюте ипотеку, да. Шоб платить поменьше. Помните, что с ними случилось, да?

Хочу заметить, что налоговая, на основании ваших данных о выплате ипотеки, может обвинить вас в неуплате налогов и через 10 лет и через 20. Там нет срока давности, после которого вас нельзя в суд вызвать.

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

Так что играя в эту игру вы играете в лотерею и делаете ставку на то, что при вашей жизни у налоговой до этого всего руки не дойдут.

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

Давно пора отходить от этого совкового левацкого отношения.

А почему, собственно?

А с какого рожна, я, например должен оплачивать обучение ваших детей в школе, садике, фигурном катании?

С того, что альтернатива хуже.

@0xd34df00dможет сколько угодно рассказывать сказки про то, что в “правильных” странах за школы платят родителей (через налоги на недвижимость), но это же ни разу не так: в благополучных районах — да, это так, качество школ зачастую определяет и цену на недвигу, но в негополучных… всё равно ведь правительству приходится оплачивать.

Только при этом ведь ещё и нормальных работников из гетто вы не получаете, всё равно. Получаете миллионы потомственных безработных, которых вам, так или иначе, приходится содержать.

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

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

Если кеша много, а таких бизнесов есть и видимо будет все больше

С чего вдруг? Это в 90е чемоданами наличку возили (в буквальном смысле, не в переносном). В последние лет 20 бизнесов с наличкой становится как раз всё меньше и меньше.

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

P.S. Если вы устраиваетесть в фирму, которая наркотиками за нал торгует, то там, наверное, другие правила, это уже совсем другой мир.

Например где я сейчас работаю — принято, что если реально недомогаешь — можешь 1-2-3 дня полечиться дома, при необходимости поработать удалённо.

А причём тут вообще больничный? 1-2-3 дня в год проще сотруднику “простить”, даже если зарплата белая.

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

Как я уже выше писал: серая зарплата — для работодателя это даже не столько экономия на зарплате, сколько возможность не нести на себе риски.

Они все оказываются на вас.

а оно стоит того ?

Конечно стоит. Фактически вы свои риски перекладываете на работника. Когда у фирмы дела идут хорошо и деньги есть — вы ему платите столько же, сколько и вбелую.

А вот как начались проблемы и когда вам нужно искать что бы такое заложить, чтобы кредит на выплату “отпускных” выплатить — тут-то вы и вспоминаете, что можно просто людям реально платить МРОТ, а зарпату в конверте не платить.

А если потребуется — можно попробовать их уговорить за этот МРОТ отработать несколько месяцев.

Поди плохо: перевесить свои риски на кого-то ещё?

Мне кажется можно отложить и на отпуск, и на лечение, и на внезапное увольнение, и еще на черный день

А вот не получится. Да, если у вас нервы, как стальные канаты, и вы влёгкую зарабатываете на рулетке в казино, то это возможно.

Но у 90% работников нервы — ни разу не такие (те, кто в такое умеет, обычно организовывают своё собственное дело и там уже совсем другие суммы фигурируют).

Дополнительные 30% с лёгкостью “куда-то расходятся”, “на бобах” вы оказываетесь ровнёхонько тогда, когда начинается очередной кризис, вам отчаянно нужны деньги, а работы для вас нету.

Как это “не пахнет”? Вы же сами и являетесь контрпримером: не захотев заключать договор на тех условиях, которое предлагает Российское госудраство, заключили его на других условиях и с другим государством.

Information

Rating
Does not participate
Registered
Activity