А тогда остаётся бесплатно кодить собственный поисковик (возможно, в опенсорсе с помощью других желающих) и надеяться, что ему хватит локальных мощностей и не придётся опять же платить деньги за арендованный сервер. Какие-то проекты уже существуют, но я не пользовался и не в курсе, хорошая ли там выдача и сколько ресурсов требуется
Есть платные поисковики в духе kagi, без рекламы и с очень гибкими настройками выдачи (см. мой другой комментарий). Испортится ли со временем - поживём, увидим
В зависимости от природы сайта, проблему иногда может смягчить RSS. Чтобы хотя бы существующим пользователям обновления сами прилетали, без необходимости специально заходить на сайт или попадать в него из поисковика
Проблема Go не в отсутствии исключений, а в отсутствии sum types и сахара для пробрасывания, по типу ? в Rust или do notation в Haskell. Пробрасывание по значению не обязательно должно быть вербозным. В том же расте высокоуровневый код выглядит так же, как аналогичный на языке с эксепшнами, только приправленный парочкой ?. Особенно если используется anyhow. И при этом отсутствуют все недостатки эксепшнов. Код легко композируется и для каждой функции по сигнатуре понятно, может ли она вернуть ошибку.
Sum types в Go правда тоже не планируются, но это уже упрямость и ошибка авторов. Такая же, как отсутствие дженериков (до недавних пор) и повторение the billion dollar mistake.
"Возвращают errno" это оксюморон. errno в C это глобальная переменная, которая неявно модифицируется функцией, а не возвращаемое значение. И даже если воспринимать "errno" в широком смысле как "код ошибки", то вы неправы, потому что в Go в качестве ошибки можно возвращать (и на практике возвращаются) не только числа, а любые произвольные объекты с детальной информацией.
Про многие типы файлов это дискуссионный и локальный вопрос, но есть и такие, которым реально место в .gitignore в 100% случаев. Пример - папка __pycache__, которая должна быть обычной скрытой папкой с артефактами, но её создатели питона не занеймили скрытой и по умолчанию гит в неё заглядывает
Обидно бывает, но это всё равно уже более гибкая ситуация, чем в плюсах, где для сторонних типов нельзя реализовать вообще никакой новый интерфейс. В этом посте хорошо описаны причины ограничений и возможные альтернативы.
Чуть-чуть прикопаюсь, newtype pattern некорректно сравнивать с typedef. Первое это новый тип-обёртка, а второе это просто алиас, аналог слова type в расте.
Ну и в примере стоило бы написать чуть более сложный/обобщённый код для использования этого трейта. А то в текущем виде от трейта нет никакой выгоды и проще написать свободную функцию, что и на плюсах можно сделать.
Через трейты можно расширять поведение уже существующих типов, код объявления которых ты не контролируешь. В том числе примитивов. И за это платишь (передаёшь vtable pointer) только в тех местах, где по факту используется dynamic dispatch. А в С++ dynamic dispatch бывает только у классов. Причём класс будет реализовывать только закрытый набор абстрактных классов, от которых автор класса унаследовался, объявляя его. Причём инстансы всегда будут таскать в себе vtable pointer, даже если используются только мономорфно.
К тому же, трейты можно использовать и для dynamic dispatch (абстрактный базовый класс в C++), и как type constraint для дженериков (Concepts из C++20). Очень удобно, что не требуется объявлять две этих отдельных сущности, как в C++. И это позволяет при неоходимости превратить любую шаблонную функцию в не-шаблонную, принимающую динамический trait object. Например, если хочется избавиться от пробрасывания type parameter для шаблона, ускорить компиляцию или уменьшить размер бинарника.
Я мог перечислить не все нюансы, можете дополнительно загуглить, чем traits и typeclasses (похожее понятие из Haskell) отличаются от OOP interfaces.
По сути просто потому что нравится раст) Рисков особых нет: у нас нет каких-то больших/экзотических требований к экосистеме, и пресловутого снижения продуктивности по прошлому личному опыту тоже не заметно. Нанимать большую команду планов пока нет, а маленькая набралась без проблем
Я докажу вам что компилятор раста ничего заранее не проверяет
Вы доказали только то, что он не проверяет возможность получить бесконечный рекурсивный тип. Это интересный кейс, и да, я пересмотрел своё прошлое мнение, что в расте не бывает ошибок внутри инстанцирования. Мой обновлённый тейк: в расте не бывает ошибок внутри инстанцирования, связанных с несоответствием лайфтайму или констрейнту (а это большинство ошибок с дженериками).
только на этапе подстановки реально проверяется что происходит и код "тайпчекается"
Код просто подставляется, не тайпчекаясь. Ошибка, которую выдаёт ваш пример, это не ошибка проверки типов, а ошибка рекурсии при выполнении "тупой" безусловной подстановки. Хотя разумеется можно сказать, что к ней приводит дыра в системе типов или их проверке при объявлении шаблона. Возможно, потом починят.
Про кодогенерацию я ничего не говорил. Там работы одинаково много в обоих языках. Но про "всё проверить" вы объективно неправду говорите сейчас. Проверяется только, соответствуют ли входные типы констрейнтам и соотносятся ли у этих типов лайфтаймы как надо. За счёт проверки лайфтаймов работы на этом этапе больше чем в плюсах, тут вы правы. Но типы и лайфтаймы в теле шаблона и вызываемых им шаблонах повторно не проверяются. Это абсолютно точно. Если не согласны, аргументируйте с хоть одним примером ошибки инстанцирования в расте, которая происходит в теле шаблона.
Вы имеете в виду объекты с ссылками внутрь самих себя? Если я правильно помню, то в расте сами эти объекты невозможны, потому что алиасинг. Или у вас на уме был какой-то другой пример? Можно подробности?
Генерировать код эти реализации не будут, потому что они всё ещё обобщённые по Iterator. Пользователь их будет инстанцировать только для конкретных используемых пар Iterator и T.
Вы правы, что даже эти обобщённые реализации требуют время компилятора (на раскрытие макросов и проверку типов). Но есть важный нюанс: это актуально, только если вы сами собираете стандартную библиотеку раста. Обычно она уже собранная. Так что на пользователе это никак не отражается. Наоборот, за него уже сделана вся работа по тайпчекингу тела шаблона. А тело плюсового шаблона будет тайпчекаться для каждого инстанцирования, и при большом количестве инстанцирований это будет медленнее. Тайпчекнутые шаблоны рулят. Тело шаблона должно быть корректным для любого инстанцирования. Надо сразу прописывать нужные constraints в сигнатуре шаблона. Substitution failure is an error! В расте ошибка инстанцирования это обычная ошибка типов в месте инстанцирования, а не монструозная непонятная простыня куда-то внутрь шаблона. В плюсах только в 20 стандарте с концептами взялись за эту проблему
Простите мою педантичность, но нет, в общем случае не ведёт. Компилятор не сделает что угодно (как при UB), он сделает именно то, что написано в реализации конкретной стандартной библиотеки для этого контейнера. Если в реализации написано занулить мувнутый вектор, значит с этой библиотекой читать его size абсолютно безопасно и всегда вернётся 0. UB может произойти только косвенно, например если попытаться прочитать элемент, не проверив size. Но это не зависит от того, вектор мувнутый или просто пустой. Просто надо проверять состояние объекта после мува. Не обязательно делать unconditional переинициализацию. Но с духом поста я согласен, unspecified мутация это хуже, чем просто мутация.
А тогда остаётся бесплатно кодить собственный поисковик (возможно, в опенсорсе с помощью других желающих) и надеяться, что ему хватит локальных мощностей и не придётся опять же платить деньги за арендованный сервер. Какие-то проекты уже существуют, но я не пользовался и не в курсе, хорошая ли там выдача и сколько ресурсов требуется
Есть платные поисковики в духе kagi, без рекламы и с очень гибкими настройками выдачи (см. мой другой комментарий). Испортится ли со временем - поживём, увидим
В зависимости от природы сайта, проблему иногда может смягчить RSS. Чтобы хотя бы существующим пользователям обновления сами прилетали, без необходимости специально заходить на сайт или попадать в него из поисковика
Бизнес-ориентированность бизнес-ориентированности рознь. Тот же kagi.com зарабатывает не на рекламе, а на платной подписке в обмен как раз за гибкую качественную выдачу. Там есть вещи в духе настройки приоритета отдельных сайтов в выдаче или кнопки "результаты только с маленьких блогов/форумов".
Проблема Go не в отсутствии исключений, а в отсутствии sum types и сахара для пробрасывания, по типу
?
в Rust или do notation в Haskell. Пробрасывание по значению не обязательно должно быть вербозным. В том же расте высокоуровневый код выглядит так же, как аналогичный на языке с эксепшнами, только приправленный парочкой?
. Особенно если используется anyhow. И при этом отсутствуют все недостатки эксепшнов. Код легко композируется и для каждой функции по сигнатуре понятно, может ли она вернуть ошибку.Sum types в Go правда тоже не планируются, но это уже упрямость и ошибка авторов. Такая же, как отсутствие дженериков (до недавних пор) и повторение the billion dollar mistake.
"Возвращают errno" это оксюморон. errno в C это глобальная переменная, которая неявно модифицируется функцией, а не возвращаемое значение. И даже если воспринимать "errno" в широком смысле как "код ошибки", то вы неправы, потому что в Go в качестве ошибки можно возвращать (и на практике возвращаются) не только числа, а любые произвольные объекты с детальной информацией.
https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels
Про многие типы файлов это дискуссионный и локальный вопрос, но есть и такие, которым реально место в
.gitignore
в 100% случаев. Пример - папка__pycache__
, которая должна быть обычной скрытой папкой с артефактами, но её создатели питона не занеймили скрытой и по умолчанию гит в неё заглядываетОбидно бывает, но это всё равно уже более гибкая ситуация, чем в плюсах, где для сторонних типов нельзя реализовать вообще никакой новый интерфейс. В этом посте хорошо описаны причины ограничений и возможные альтернативы.
Чуть-чуть прикопаюсь, newtype pattern некорректно сравнивать с typedef. Первое это новый тип-обёртка, а второе это просто алиас, аналог слова
type
в расте.Ну и в примере стоило бы написать чуть более сложный/обобщённый код для использования этого трейта. А то в текущем виде от трейта нет никакой выгоды и проще написать свободную функцию, что и на плюсах можно сделать.
Через трейты можно расширять поведение уже существующих типов, код объявления которых ты не контролируешь. В том числе примитивов. И за это платишь (передаёшь vtable pointer) только в тех местах, где по факту используется dynamic dispatch. А в С++ dynamic dispatch бывает только у классов. Причём класс будет реализовывать только закрытый набор абстрактных классов, от которых автор класса унаследовался, объявляя его. Причём инстансы всегда будут таскать в себе vtable pointer, даже если используются только мономорфно.
К тому же, трейты можно использовать и для dynamic dispatch (абстрактный базовый класс в C++), и как type constraint для дженериков (Concepts из C++20). Очень удобно, что не требуется объявлять две этих отдельных сущности, как в C++. И это позволяет при неоходимости превратить любую шаблонную функцию в не-шаблонную, принимающую динамический trait object. Например, если хочется избавиться от пробрасывания type parameter для шаблона, ускорить компиляцию или уменьшить размер бинарника.
Я мог перечислить не все нюансы, можете дополнительно загуглить, чем traits и typeclasses (похожее понятие из Haskell) отличаются от OOP interfaces.
По сути просто потому что нравится раст) Рисков особых нет: у нас нет каких-то больших/экзотических требований к экосистеме, и пресловутого снижения продуктивности по прошлому личному опыту тоже не заметно. Нанимать большую команду планов пока нет, а маленькая набралась без проблем
Всё так. Пишем сейчас CRUD на расте, кайфуем от точного моделирования данных и отсутствия багов, но местами натыкаемся на сырость библиотек
Вы доказали только то, что он не проверяет возможность получить бесконечный рекурсивный тип. Это интересный кейс, и да, я пересмотрел своё прошлое мнение, что в расте не бывает ошибок внутри инстанцирования. Мой обновлённый тейк: в расте не бывает ошибок внутри инстанцирования, связанных с несоответствием лайфтайму или констрейнту (а это большинство ошибок с дженериками).
Код просто подставляется, не тайпчекаясь. Ошибка, которую выдаёт ваш пример, это не ошибка проверки типов, а ошибка рекурсии при выполнении "тупой" безусловной подстановки. Хотя разумеется можно сказать, что к ней приводит дыра в системе типов или их проверке при объявлении шаблона. Возможно, потом починят.
Объясните пожалуйста, как по-вашему компилятор может во время инстанцирования выявить и кинуть ошибку типов, не выполняя собственно проверку типов?
Объясните пожалуйста, как по-вашему компилятор может во время инстанцирования выявить и кинуть ошибку типов, не выполняя собственно проверку типов?
Про кодогенерацию я ничего не говорил. Там работы одинаково много в обоих языках. Но про "всё проверить" вы объективно неправду говорите сейчас. Проверяется только, соответствуют ли входные типы констрейнтам и соотносятся ли у этих типов лайфтаймы как надо. За счёт проверки лайфтаймов работы на этом этапе больше чем в плюсах, тут вы правы. Но типы и лайфтаймы в теле шаблона и вызываемых им шаблонах повторно не проверяются. Это абсолютно точно. Если не согласны, аргументируйте с хоть одним примером ошибки инстанцирования в расте, которая происходит в теле шаблона.
Вы имеете в виду объекты с ссылками внутрь самих себя? Если я правильно помню, то в расте сами эти объекты невозможны, потому что алиасинг. Или у вас на уме был какой-то другой пример? Можно подробности?
Генерировать код эти реализации не будут, потому что они всё ещё обобщённые по Iterator. Пользователь их будет инстанцировать только для конкретных используемых пар Iterator и T.
Вы правы, что даже эти обобщённые реализации требуют время компилятора (на раскрытие макросов и проверку типов). Но есть важный нюанс: это актуально, только если вы сами собираете стандартную библиотеку раста. Обычно она уже собранная. Так что на пользователе это никак не отражается. Наоборот, за него уже сделана вся работа по тайпчекингу тела шаблона. А тело плюсового шаблона будет тайпчекаться для каждого инстанцирования, и при большом количестве инстанцирований это будет медленнее. Тайпчекнутые шаблоны рулят. Тело шаблона должно быть корректным для любого инстанцирования. Надо сразу прописывать нужные constraints в сигнатуре шаблона. Substitution failure is an error! В расте ошибка инстанцирования это обычная ошибка типов в месте инстанцирования, а не монструозная непонятная простыня куда-то внутрь шаблона. В плюсах только в 20 стандарте с концептами взялись за эту проблему
Простите мою педантичность, но нет, в общем случае не ведёт. Компилятор не сделает что угодно (как при UB), он сделает именно то, что написано в реализации конкретной стандартной библиотеки для этого контейнера. Если в реализации написано занулить мувнутый вектор, значит с этой библиотекой читать его size абсолютно безопасно и всегда вернётся 0. UB может произойти только косвенно, например если попытаться прочитать элемент, не проверив size. Но это не зависит от того, вектор мувнутый или просто пустой. Просто надо проверять состояние объекта после мува. Не обязательно делать unconditional переинициализацию. Но с духом поста я согласен, unspecified мутация это хуже, чем просто мутация.