Проблема в том, что Страуструп не то что не знает, а просто не понимает проблему. А проблема не в том, насколько просто писать безбажный код (хинт: сложно, что бы там Страуструп ни говорил). Проблема в том, что писать бажный, падающий, дырявый код просто.
Страуструп — в первую очередь учитель, поэтому задачи и проблемы, которые он видит — это чтобы «ученикам» можно было легко и просто показывать примеры простого, безбажного кода (и поэтому его характерная реакция сводится к «правильно показывайте пишите, неправильно не показывайте пишите»). Добавили там какой-нибудь std::span — всё, его проблема решена, потому что в учебных примерах можно им пользоваться (а плохим не пользоваться). То, что в продакшен-коде есть легаси, которое этим не пользуется, есть люди с разным бекграундом, с разным состоянием выспанности, в конце концов — это всё неважно. Страуструп смотрит на наличие способов не выстрелить себе в ногу, а не на отсутствие способов выстрелить.
Все эти сильные стороны неважны и не исправляют ситуацию, покуда есть слабые.
поэтому важно улучшать инструменты и процессы разработки
Самый лучший вариант в моём опыте — улучшить инструмент разработки через смену ЯП.
data State
= Building
| Finalized
| Paid
| Shipped
BillingAddressType :: State → Type
BillingAddressType Paid = BillingAddress
BillingAddressType Shipped = BillingAddress
BillingAddress _ = ()
data Order state = Order
{ shippingAddress :: ShippingAddress
, goods :: [Item]
, billingAddress :: BillingAddressType state
}
createOrder :: ShippingAddress → Order Building
addItems :: [Item] → Order Building → Order Building
finalizeOrder :: Order Building → Order Finalized
payOrder :: PaymentInfo → Order Finalized → Either PaymentError (Order Paid)
shipOrder :: Order Paid → Order Shipped
Можно набросать соответствующую стейтмашину на чистом ООП?
(это было в ответ на
fsm и ООП никоим образом не противоречат друг другу, а наоборот, очень гармонично взаимно дополняют
а замечательный новый редактор комментариев не даёт добавить ньюлайны в начало комментария с кодовым листингом, по крайней мере, в FF — веб, который мы заслужили)
Людей, способных заниматься сексом, стоя в гамаке и на сноуборде тоже мало, и что за business value в этой наркомании с выкрутасами?
Это всё происходит во время компиляции, поэтому компилятор лучше оптимизирует то, что получается, поэтому перф выходит сильно лучше, чем если писать «просто». В некоторых задачах это ценят куда больше, чем поддерживаемость кода широким кругом лиц (тогда б изначально на плюсах не писали).
Можно просто сложный язык и/или сложную предметную область. Современный C++ — сложный. Людей, могущих в выкрутасы на темплейтах и оптимизированный код, мало. Разрабатывать свои языки — сложно. Людей, могущих сформулировать систему типов и доказать её хорошие свойства (или найти в ней проблемы), мало.
Во всех этих случаях не обязательно быть совсем уж ассенизатором-специалистом по легаси.
Рынок ит за границей очень сильно поменялся за 2 года.
Причём тут два года? Это с ближайшей осени, несколько месяцев назад.
Но реально эти деньги никто не поставит в офер)))
А если поставить больше смайликов, то это будет ещё истиннее и универсальнее.
Я же прямо написал, что эти цифры в офферах вполне дают, и это мой личный опыт. Более того, при некоторых условиях дают чуть выше вилки, чтобы скомпенсировать некоторые неожиданные налоговые вопросы.
Будут прогибать, и прогнут очень сильно....ибо рынок работодателя.
Опять же, смотря на какие позиции. В интересных мне позициях (HFT-клоунада по верхней грани описанных в моём изначальном комментарии зарплат на руки или разработка компиляторов, тайпчекеров, и так далее, по нижней) как-то и не прогибают, и рынок едва ли работодателя.
Как мне хороший знакомый после 6 месяцев поиска сказал - я с позиции тимлида гугла (откуда его уволили после 4 лет работы ибо все направление закрыли а общий стаж в ит 17 лет) ушел на позицию синьера разраба в теслу на деньги мидла.
Гугл, наверное, призван был произвести впечатление, но я нему отношусь резко негативно что по уровню тамошних спецов, что по некоторым другим причинам, поэтому, ну, ок, ушёл и ушёл. Бывает. Люди вон на интервью тоже всякое говорят.
И повторюсь, в нормальную контору вас никто не возмет без разрешения на работу, в стране оформления. Могут взять только через прокладку на краткосрочный контракт в стране где вы сидите, но денег будет принципиально меньше.
Не обязательно. Просто отправляете инвойс в фирму каждый месяц, и всё.
Учитывая разницу в налогах, денег будет даже больше (по крайней мере, это мой опыт работы не на W2, находясь изнутри США — там, во-первых, даже I-9 не спрашивают, а, во-вторых, эффективная налоговая ставка становится меньше 10%, и работодателю это выгодно, потому что он не должен заморачиваться со своей половиной FICA/SS/чётам).
Это не социализм, который в любом существующему на данный момент варианте отлично работает с монополиями (например в стиле «будете выпендриваться — посадим верхушку»).
Кто именно эти самые «мы», которые «посадим», в случае, когда соцгосударство и есть корпорация-монополист в худшем смысле этого слова?
import Data.Unrestricted.Linear qualified as L
import Data.Vector.Mutable.Linear qualified as VL
import Prelude.Linear qualified as L
fillVec :: Int → VL.Vector Int %1→ VL.Vector Int
fillVec n = go 0
where
go :: Int → VL.Vector Int %1→ VL.Vector Int
go v vec
| v == n = vec
| otherwise = go (v + 1) L.$ VL.push (v + 1) vec
swap :: Int → Int → VL.Vector a %1→ VL.Vector a
swap p1 p2 vec =
let %1 (L.Ur v1, vec¹) = VL.get p1 vec
%1 (L.Ur v2, vec²) = VL.get p2 vec¹
in VL.set p1 v2 L.$ VL.set p2 v1 vec²
main :: IO ()
main = do
let L.Ur vec = VL.empty (VL.freeze L.. swap 0 (n - 1) L.. fillVec n)
print vec
where n = 5
> :main
[5,2,3,4,1]
Или идрис:
import Data.Linear
import Data.Linear.Array
run : Int -> IO ()
run size = newArray size (\1 arr : _ => toIArray (swap 0 (size - 1) $ fill 0 arr) printArr)
where
fill : Int -> LinArray Int -@ LinArray Int
fill n arr = if n == size
then arr
else let _ # arr = write arr n (n + 1) in fill (n + 1) arr
swap : Int -> Int -> LinArray Int -@ LinArray Int
swap p1 p2 arr =
let mv1 # arr = mread arr p1
mv2 # arr = mread arr p2
in case (mv1, mv2) of
(Just v1, Just v2) => let _ # arr = write arr p1 v2
_ # arr = write arr p2 v1
in arr
_ => arr
printArr : IArray Int -> IO ()
printArr arr = for_ [0..size - 1] $ \i => case read arr i of
Just v => printLn v
Nothing => pure ()
т.е. всё-таки мы получаем ссылку на другую область памяти, а не изменяем данные in-place?
Нет, почему? Область памяти та же, просто имя другое.
Условно, в хаскеле с линейными типами операция записи в массив выглядит как
write :: Int → a → Array a %1→ Array a
где вот это вот %1→ означает, что переданным именем после вызова этой функции пользоваться нельзя, и надо пользоваться тем, что функция вернула (несмотря на то, что и старое, и новое имя ссылаются на один и тот же адрес).
По аналогичным причинам чтение выглядит как, несколько упрощая,
read :: Int → Array a %1→ (a, Array a)
и старым именем пользоваться нельзя, хотя чтение-то уж точно ничего не копирует.
Если вы хотите эти данные как-то поменять снаружи, вы вызываете лишь выставленные наружу функции, а не меняете его прямо, ровно как работает инкапсуляция в классах.
Да. Только это означает, что я пользовался инкапсуляцией. Говорить, что у ООП монополия на понятие инкапсуляции — это перебор (а мы до этого дойдём через несколько итераций).
у вас там тоже есть штука "Encoder" которая описывает набор функций, в точности как интерфейс в C++
Только Encoder — это просто алиас для типа. Мне не нужно особое понятие «интерфейс», оно становится частным случаем «любое значение, удовлетворяющее типу». Как обычно.
но в виде общего Encoder в точности как фабричный метод.
Да, только в ООП вам зачем-то нужен отдельный термин для этого, а в ФП у вас просто функции, возвращающие функции. Как обычно.
В точности как полиморфизм в ООП.
Нет, потому что в ООП навешаны какие-то принципы подстановки лисков (которые не работают), виртуальные функции, рантайм-диспатчинг, и так далее, а в ФП я просто передаю функции в функции, и полиморфизма здесь не больше, чем полиморфизма в функции int foo(int n) { return n + 2; }. которая игнорирует конкретное значение n. Как обычно.
Вы точно также добавили бы DumpingEncoder для сливания данных в файл, если он нужен.
Только это была бы просто функция, возвращающая функцию. Никакого наследования, никаких дум «а мне тут наследоваться или агрегировать? или, может, CRTP?» Просто работа как с обычными значениями. Снова и как обычно.
Вы отказались от class/instance потеряв какую-то часть проверок, ведь теперь вы можете в коде в качестве Encoder использовать и условное замыкание для шифрования пикселей, у которого по случайности и недосмотру главный метод также обозвали Encode().
Нет, не могу. Имена и их совпадения важны только для class/instance. Если я от них отказался, то важны только типы.
Ну, называются эти штуки не классы, а замыкания. Общий дизайн системы точно такой же. Это суть ООП подхода.
Только смысл в том, что ФП позволяет выражать сильно больше и проще, чем это позволяет ООП. Там, где в ООП нужны какие-то особые отдельные паттерны, про которые пишут книжки и спрашиввают на интервью, в ФП вы просто используете функции, как ни в чём не бывало. Ну, прямо как в том меме,
И говорить, что «дизайн системы в ФП отражает концепции из ООП» — ну да, а чего вы хотели, если там есть инъекция? Это как говорить, что «чего вы говорите, что вещественные числа полнее целых, если при решении 2x = 4 вы не пользовались вещественными числами?»
Но как это работает, когда у вас есть "интерфейс" Encoder? У вас же mkEncoder имеет конкретный тип - он возвращает Encoder.
Тогда mkEncoder возвращает Encoder и его «метаданные» через Σ-тип (то есть, пару, где тип второго компонента зависит от значения первого), например:
где я даже не указываю явно значение первого компонента пары, потому что тайпчекер его успешно выводит из второго. И, кстати, здесь же используется mkFallbackEncoder:
где эти смешные значки ⊓ и ⊔ — это решёточные greatest lower bound и least upper bound, которые для количества кейфреймов сводятся к минимуму двух значений, а для минимального размера фрейма — к максимуму из двух.
И, кстати, если я, например, ошибусь, и случайно напишу, что минимальный размер комбинированного энкодера — минимальный (а не максимальный, как это должно быть) из двух индивидуальных ограничений, то у меня просто не получится написать тело функции mkFallbackEncoder, потому что я не смогу тайпчекеру доказать, что размер фрейма для комбинированного энкодера подходит каждому из размеров фреймов отдельных энкодеров.
Мне даже тестировать ничего не надо. Типы помогают ловить ошибки на этапе описания самих типов и помогают убедиться, что описываемая логика внутренне консистентна.
В штатах сейчас в очередь в офис стоят за 10к. Просто очень в теме со стороны работодателя)
Я не сомневаюсь, что на какие-то вакансии [например, джунов-фронтендеров] стоит очередь за 10к [например, выпускников буткампов]. Собсна, я даже таких людей видел тоже со стороны работодателя: правда, они хэшмапу от sha1-хэша отличить не могут и на ремоут-собеседовании бегают глазками и думают перед ответом по 10 секунд, а потом выдают без запинки словарные определения. Если человек не может на их фоне выделиться, то мои ему искренние соболезнования.
Тем временем мне достаточно регулярно приходят подобные вакансии:
(нижние две — это база, там такой же бонус предлагают). Подсчитать долю Remote вы можете сами, думаю. И это реальные офферы, которые можно получить.
Плюс нормальная белая контора хочет рабочую визу сша, даже если удаленка.
Знакомые мне конторы готовы брать также канадцев, мексиканцев, бразильцев, и так далее — только б часовые пояса не сильно мешали.
Де-юре там предпочитают американцев, де-факто даже на зарплаты выше тяжело найти достаточно прошаренных людей, поэтому конкретная страна не является проблемой.
Даже 450 в год даст 360 после налогов, если их оптимизировать по полной. Если не оптимизировать — получите столько на руки с примерно 530 (или с 480, если у вас неработающая жена).
От того, что вы их формулируете скорее как «я хочу, чтобы удалёнка кончилась», а не «конкретно вы должны меня развлекать на работе», это требованием не перестаёт быть.
Я просто прошу апологетов удаленки подсказать рабочую альтернативу, но получаю либо нерабочие советы, либо слив с темы и оскорбления.
Рабочую в каком смысле и по каким критериям? Найти друзей? Совершенно очевидно, что ваш метод (офисная работа) тоже не работает, потому что друзья после выхода на удалёнку, судя по вашим словам, у вас отвалились. Чтобы зеркальные нейроны приятно теребились? Общайтесь с людьми в интернете или, не знаю, вебкамщицы там к вашим услугам.
Почему советы нерабочие? Полноценное неситуативное общение находится именно там, где интересны вы, а не там, где вы отыгрываете роль винтика с другими такими же винтиками, и где весь смысл рабочего общения сводится к попытке убедить себя, что ты не просто этот самый винтик, а у тебя есть какая-то роль, миссия и восприятие тебя окружающими как человека.
Мне разумеется не нужно, чтобы со мной общались из под палки.
Математическая теория — лет 40+. Clean — изначально там были, Idris — с ЕМНИП 0.9.15 (лет 8 уже), GHC — 9.0.1 (года четыре как).
и как там у них с мутабельностью?
Берёшь и мутируешь. Правда, код в несколько необычном стиле писать приходится (так как старым именем переменной после мутации пользоваться нельзя), но к этому привыкаешь.
Ну автор же просил реальный пример где ООП нужно, я его привел.
Так ведь не нужно. Я вон без всяких ООП написал, и даже без смущающего слова class. Просто функции, функции, композиции функций. Классика ФП.
Но если вы пишите не число дробилку - это не так уж и часто.
Компиляторы — числодробилки? Их парсерная часть? Или те же перекладывалки жсонов уровня «запуститься по крону, взять данные из трёх БД, заджойнить по хитрой бизнес-логике и сложить в четвёртую»?
А как вы тут запишите, например
Начну с конца, с самого скучного.
И что у вас в системе не более 3 HW encoder создается.
Просто возвращая Maybe Encoder (или Either EncoderCreationError Encoder), а не Encoder. Это существенно нелокальное свойство, и создание энкодера может навернуться по куче других причин (включая софтварные): три HW encoder'а, или видяха из слота вытащилась (PCIe же поддерживает hotplug?), или для софтваре энкодера dlopen для x264 чё-т не работает. Я не вижу смысла выражать конкретно тройку конкретно в типах (но если вам очень хочется, то могу показать, как это делать).
А у второго HW енкодера надо обязательно хотя бы раз 100 Encode вызывать RequestKeyFrame.
С зависимыми типами можно выразить что угодно.
data State
= ...
| CanFeedNonKeyFrameCounted Nat -- параметр — оставшееся число не-кейфреймов
data EncoderMetadata = EncoderMetadata
{ maxNonKeyframes :: Maybe Nat
}
-- есть более изящные способы, чем таскать `md` в типе,
-- но для маленького примера они не нужны
data Encoder md st = ...
loadVP9hwEncoder : IO (Encoder (EncoderMetadata (Just 100)) Initialized)
loadVP8hwEncoder : IO (Encoder (EncoderMetadata Nothing) Initialized)
feedNonKeyframe : Frame
→ Encoder md (CanFeedNonKeyframe (suc n))
→ Encoder md (CanFeedNonKeyframe n)
feedKeyframe : CanFeedKeyframeAt st
⇒ Frame
→ (e : Encoder md st)
→ Encoder md (case maxNonKeyframes md of Just n ⇒ CanFeedNonKeyframeCounted n
Nothing ⇒ CanFeedNonKeyframe)
-- или, если это решается динамически, тогда `Maybe` у maxNonKeyframes не нужен
-- и возвращаем тип-сумму из двух вариантов, по которым надо будет сделать рантайм-матч:
→ Encoder md (CanFeedNonKeyframeCounted (maxNonKeyframes md)) ∨ Encoder md CanFeedNonKeyframe
И что в оба HW encoder нельзя передавать видео фреймы размера меньше 240x180?
у H264HWEncoder (и только его из всех 4) нельзя 2 раза подряд кодировать key-frame (нельзя иметь последовательность request kf, encode, request kf, encode, и нельзя иметь request kf перед вторым вызовом encode)
Совершенно аналогично (только в моём словаре нет encode, поэтому в виде кода я выражать не буду, но смысл понятен, надеюсь).
А если все енкодеры во время работы что-то пишут в общий логгер?
Значит, они должны будут жить в IO, и будет сразу ясно, что с многопоточностью может быть ерунда.
Ну и заодно стимул не писать в общий логгер, кольцевой буфер, и так далее. Почему бы не писать в отдельные буферы, а потом объединять их при выводе на экран?
Запустил gcc под профайлером памяти на TUшке, которая компилируется пару минут и жрёт при этом гигов восемь памяти в пике — чуть больше терабайта аллокаций.
Я никогда не говорил, что математика не нужна для постижения X или Y. Я говорил (и говорю, и буду говорить), что математическое образование вне чуть-более-чем-школьного не нужно для ≈99% программистских задач и вакансий.
А в данном конкретном случае — ну не понял чего-то человек, ну и что? Разве он будет от этого хуже жить? Меньше есть? Чаще просыпаться по ночам? Станет ли он менее счастливым?
Проблема в том, что Страуструп не то что не знает, а просто не понимает проблему. А проблема не в том, насколько просто писать безбажный код (хинт: сложно, что бы там Страуструп ни говорил). Проблема в том, что писать бажный, падающий, дырявый код просто.
Страуструп — в первую очередь учитель, поэтому задачи и проблемы, которые он видит — это чтобы «ученикам» можно было легко и просто показывать примеры простого, безбажного кода (и поэтому его характерная реакция сводится к «правильно
показывайтепишите, неправильно непоказывайтепишите»). Добавили там какой-нибудьstd::span— всё, его проблема решена, потому что в учебных примерах можно им пользоваться (а плохим не пользоваться). То, что в продакшен-коде есть легаси, которое этим не пользуется, есть люди с разным бекграундом, с разным состоянием выспанности, в конце концов — это всё неважно. Страуструп смотрит на наличие способов не выстрелить себе в ногу, а не на отсутствие способов выстрелить.Все эти сильные стороны неважны и не исправляют ситуацию, покуда есть слабые.
Самый лучший вариант в моём опыте — улучшить инструмент разработки через смену ЯП.
Можно набросать соответствующую стейтмашину на чистом ООП?
(это было в ответ на
а замечательный новый редактор комментариев не даёт добавить ньюлайны в начало комментария с кодовым листингом, по крайней мере, в FF — веб, который мы заслужили)
Это всё происходит во время компиляции, поэтому компилятор лучше оптимизирует то, что получается, поэтому перф выходит сильно лучше, чем если писать «просто». В некоторых задачах это ценят куда больше, чем поддерживаемость кода широким кругом лиц (тогда б изначально на плюсах не писали).
Можно просто сложный язык и/или сложную предметную область.
Современный C++ — сложный. Людей, могущих в выкрутасы на темплейтах и оптимизированный код, мало.
Разрабатывать свои языки — сложно. Людей, могущих сформулировать систему типов и доказать её хорошие свойства (или найти в ней проблемы), мало.
Во всех этих случаях не обязательно быть совсем уж ассенизатором-специалистом по легаси.
А кто посадит Иосифа Виссарионовича, когда тот начнёт зарываться?
Кто проверит, что его посадки действительно делают лучше, а не хуже? А то там, знаешь, потом было всякое, пересмотры, реабилитации…
Ты в этом проблему видишь, я — нет. Что с этим делать будем? Сажать, если проигнорируют намёки, или нет?
Причём тут два года? Это с ближайшей осени, несколько месяцев назад.
А если поставить больше смайликов, то это будет ещё истиннее и универсальнее.
Я же прямо написал, что эти цифры в офферах вполне дают, и это мой личный опыт. Более того, при некоторых условиях дают чуть выше вилки, чтобы скомпенсировать некоторые неожиданные налоговые вопросы.
Опять же, смотря на какие позиции. В интересных мне позициях (HFT-клоунада по верхней грани описанных в моём изначальном комментарии зарплат на руки или разработка компиляторов, тайпчекеров, и так далее, по нижней) как-то и не прогибают, и рынок едва ли работодателя.
Гугл, наверное, призван был произвести впечатление, но я нему отношусь резко негативно что по уровню тамошних спецов, что по некоторым другим причинам, поэтому, ну, ок, ушёл и ушёл. Бывает. Люди вон на интервью тоже всякое говорят.
Не обязательно. Просто отправляете инвойс в фирму каждый месяц, и всё.
Учитывая разницу в налогах, денег будет даже больше (по крайней мере, это мой опыт работы не на W2, находясь изнутри США — там, во-первых, даже I-9 не спрашивают, а, во-вторых, эффективная налоговая ставка становится меньше 10%, и работодателю это выгодно, потому что он не должен заморачиваться со своей половиной FICA/SS/чётам).
Кто именно эти самые «мы», которые «посадим», в случае, когда соцгосударство и есть корпорация-монополист в худшем смысле этого слова?
Да. конечно. Вот хаскель:
Или идрис:
Нет, почему? Область памяти та же, просто имя другое.
Условно, в хаскеле с линейными типами операция записи в массив выглядит как
где вот это вот
%1→означает, что переданным именем после вызова этой функции пользоваться нельзя, и надо пользоваться тем, что функция вернула (несмотря на то, что и старое, и новое имя ссылаются на один и тот же адрес).По аналогичным причинам чтение выглядит как, несколько упрощая,
и старым именем пользоваться нельзя, хотя чтение-то уж точно ничего не копирует.
Да. Только это означает, что я пользовался инкапсуляцией. Говорить, что у ООП монополия на понятие инкапсуляции — это перебор (а мы до этого дойдём через несколько итераций).
Только
Encoder— это просто алиас для типа. Мне не нужно особое понятие «интерфейс», оно становится частным случаем «любое значение, удовлетворяющее типу». Как обычно.Да, только в ООП вам зачем-то нужен отдельный термин для этого, а в ФП у вас просто функции, возвращающие функции. Как обычно.
Нет, потому что в ООП навешаны какие-то принципы подстановки лисков (которые не работают), виртуальные функции, рантайм-диспатчинг, и так далее, а в ФП я просто передаю функции в функции, и полиморфизма здесь не больше, чем полиморфизма в функции
int foo(int n) { return n + 2; }. которая игнорирует конкретное значениеn. Как обычно.Только это была бы просто функция, возвращающая функцию. Никакого наследования, никаких дум «а мне тут наследоваться или агрегировать? или, может, CRTP?» Просто работа как с обычными значениями. Снова и как обычно.
Нет, не могу. Имена и их совпадения важны только для
class/instance. Если я от них отказался, то важны только типы.Только смысл в том, что ФП позволяет выражать сильно больше и проще, чем это позволяет ООП. Там, где в ООП нужны какие-то особые отдельные паттерны, про которые пишут книжки и спрашиввают на интервью, в ФП вы просто используете функции, как ни в чём не бывало. Ну, прямо как в том меме,
И говорить, что «дизайн системы в ФП отражает концепции из ООП» — ну да, а чего вы хотели, если там есть инъекция? Это как говорить, что «чего вы говорите, что вещественные числа полнее целых, если при решении 2x = 4 вы не пользовались вещественными числами?»
Тогда
mkEncoderвозвращаетEncoderи его «метаданные» через Σ-тип (то есть, пару, где тип второго компонента зависит от значения первого), например:где я даже не указываю явно значение первого компонента пары, потому что тайпчекер его успешно выводит из второго. И, кстати, здесь же используется
mkFallbackEncoder:где эти смешные значки ⊓ и ⊔ — это решёточные greatest lower bound и least upper bound, которые для количества кейфреймов сводятся к минимуму двух значений, а для минимального размера фрейма — к максимуму из двух.
И, кстати, если я, например, ошибусь, и случайно напишу, что минимальный размер комбинированного энкодера — минимальный (а не максимальный, как это должно быть) из двух индивидуальных ограничений, то у меня просто не получится написать тело функции
mkFallbackEncoder, потому что я не смогу тайпчекеру доказать, что размер фрейма для комбинированного энкодера подходит каждому из размеров фреймов отдельных энкодеров.Мне даже тестировать ничего не надо. Типы помогают ловить ошибки на этапе описания самих типов и помогают убедиться, что описываемая логика внутренне консистентна.
Нет, проблема объективно существует. В тех же gcc и clang те же ADT переизобретены явно, насколько это можно сделать в C++.
Я не сомневаюсь, что на какие-то вакансии [например, джунов-фронтендеров] стоит очередь за 10к [например, выпускников буткампов]. Собсна, я даже таких людей видел тоже со стороны работодателя: правда, они хэшмапу от sha1-хэша отличить не могут и на ремоут-собеседовании бегают глазками и думают перед ответом по 10 секунд, а потом выдают без запинки словарные определения. Если человек не может на их фоне выделиться, то мои ему искренние соболезнования.
Тем временем мне достаточно регулярно приходят подобные вакансии:
(нижние две — это база, там такой же бонус предлагают). Подсчитать долю
Remoteвы можете сами, думаю. И это реальные офферы, которые можно получить.Знакомые мне конторы готовы брать также канадцев, мексиканцев, бразильцев, и так далее — только б часовые пояса не сильно мешали.
Де-юре там предпочитают американцев, де-факто даже на зарплаты выше тяжело найти достаточно прошаренных людей, поэтому конкретная страна не является проблемой.
Даже 450 в год даст 360 после налогов, если их оптимизировать по полной. Если не оптимизировать — получите столько на руки с примерно 530 (или с 480, если у вас неработающая жена).
Это удалёнка в Штатах на штатовские же компании.
В ваших комментариях.
От того, что вы их формулируете скорее как «я хочу, чтобы удалёнка кончилась», а не «конкретно вы должны меня развлекать на работе», это требованием не перестаёт быть.
Рабочую в каком смысле и по каким критериям?
Найти друзей? Совершенно очевидно, что ваш метод (офисная работа) тоже не работает, потому что друзья после выхода на удалёнку, судя по вашим словам, у вас отвалились.
Чтобы зеркальные нейроны приятно теребились? Общайтесь с людьми в интернете или, не знаю, вебкамщицы там к вашим услугам.
Почему советы нерабочие? Полноценное неситуативное общение находится именно там, где интересны вы, а не там, где вы отыгрываете роль винтика с другими такими же винтиками, и где весь смысл рабочего общения сводится к попытке убедить себя, что ты не просто этот самый винтик, а у тебя есть какая-то роль, миссия и восприятие тебя окружающими как человека.
Не стоит вскрывать эту тему.
Математическая теория — лет 40+. Clean — изначально там были, Idris — с ЕМНИП 0.9.15 (лет 8 уже), GHC — 9.0.1 (года четыре как).
Берёшь и мутируешь. Правда, код в несколько необычном стиле писать приходится (так как старым именем переменной после мутации пользоваться нельзя), но к этому привыкаешь.
«Есть поле — делай» — это же row polymorphism, и там всё вполне строго (очень хороший папир).
Так ведь не нужно. Я вон без всяких ООП написал, и даже без смущающего слова
class. Просто функции, функции, композиции функций. Классика ФП.Компиляторы — числодробилки? Их парсерная часть? Или те же перекладывалки жсонов уровня «запуститься по крону, взять данные из трёх БД, заджойнить по хитрой бизнес-логике и сложить в четвёртую»?
Начну с конца, с самого скучного.
Просто возвращая
Maybe Encoder (или Either EncoderCreationError Encoder), а неEncoder. Это существенно нелокальное свойство, и создание энкодера может навернуться по куче других причин (включая софтварные): три HW encoder'а, или видяха из слота вытащилась (PCIe же поддерживает hotplug?), или для софтваре энкодераdlopenдля x264 чё-т не работает. Я не вижу смысла выражать конкретно тройку конкретно в типах (но если вам очень хочется, то могу показать, как это делать).С зависимыми типами можно выразить что угодно.
Совершенно аналогично:
Совершенно аналогично (только в моём словаре нет
encode, поэтому в виде кода я выражать не буду, но смысл понятен, надеюсь).Значит, они должны будут жить в IO, и будет сразу ясно, что с многопоточностью может быть ерунда.
Ну и заодно стимул не писать в общий логгер, кольцевой буфер, и так далее. Почему бы не писать в отдельные буферы, а потом объединять их при выводе на экран?
Запустил gcc под профайлером памяти на TUшке, которая компилируется пару минут и жрёт при этом гигов восемь памяти в пике — чуть больше терабайта аллокаций.
Не, память освобождать надо.
Я никогда не говорил, что математика не нужна для постижения X или Y. Я говорил (и говорю, и буду говорить), что математическое образование вне чуть-более-чем-школьного не нужно для ≈99% программистских задач и вакансий.
А в данном конкретном случае — ну не понял чего-то человек, ну и что? Разве он будет от этого хуже жить? Меньше есть? Чаще просыпаться по ночам? Станет ли он менее счастливым?
Нет.