Нашли или выдавили из себя код, который нельзя назвать нормальным,
на который без улыбки не взглянешь?
Не торопитесь его удалять или рефакторить, — запостите его на
говнокод.ру, посмеёмся вместе!
enum DaError: Error {
case some(Int)
}
func testThrow(value: Int) throws {
do {
throw DaError.some(value)
} catch {
switch error {
case let DaError.some(value) where value < 4:
print("SMALL")
case let DaError.some(value) where value == 4:
print("DA GOOD")
case let DaError.some(value) where value > 4:
print("BIG")
default:
throw error
}
}
}
for val in [1, 4, 100500] {
try? testThrow(value: val)
}
Борманд, знаешь загадку про лес хуёв и море говна?
Вот тут тоже самое.
JSONException'ов и RPCExceptionов я наобрабатывал всласть, но приведенный гостом пример, к сожалению, не юзабелен: ничто не заставит клиента функции GetPetuhByHttp() написать эту цепочку. А джава могла бы заставить
Ну что за жабья философия... Программист - это ребёнок, которого надо водить за ручку и заставлять есть кашу?
Есть куча вполне разумных кейсов, когда исключения достаточно "обработать" в одной точке - цикле обработки сообщений, main'е и т.п. И я не хочу обмазывать все функции этими throws Exception, только чтобы дотащить этот сраный JSONException до этой точки. Даже в крестах это уже осознали и выкинули все спецификации исключений помимо "не кидает ничего" и "что-то может кинуть".
>которого надо водить за ручку и заставлять есть кашу?
Эмм.. ты против того, чтобы компилятор заставлял тебя проверять ошибки?
Тогда тебе должен нравится PHP: там вообще ничего проверять не обязательно.
>Есть куча вполне разумных кейсов, когда исключения достаточно "обработать" в одной точке
Да.
>я не хочу обмазывать весь код этими throws Exception
Я же сказал: говно и то, и другое.
Засирать весь код "throws PetuhException, ScriptuhException" -- плохо.
Разрешать пользовтаелю не проверять эксепшены -- тоже плохо, потому что как тогда ошибку вернуть?
"Этот метод возвращает или ответ, или одну из вот этих трех ошибок. Не забудьте их проверить пожалуйста. А если забудете -- то программа просто упадет, а комплиятор вам не поможет, потому что мы не в жабе". Так чтоли?
Этот метод возвращает ответ либо кидает исключение. В документации к методу описано какие исключения вы можете захотеть обработать чтобы улучшить user experience. Однако этот список не исчерпывающий и метод может кинуть и другие исключения в зависимости от реализации.
Всё. Если программист хочет сделать что-то полезное для юзера при каких-то конкретных исключениях - он прочитает о них в документации и обработает (какие-нибудь FileNotFound или NetworkIsDown, к примеру).
Остальные исключения обрабатывать нет никакого смысла - либо catch all + log либо terminate.
> компилятор вам не поможет
Он уже помог разделить код на успешный путь (вернули результат) и неуспешный путь (вернули исключение). И даже прокинул неуспешный путь через весь коллстек, в отличие от той же сишки где каждый вызов надо обмазывать проверками. И даже дал возможность прикрепить какую-то полезную инфу и строчку для лога. Что ещё надо то?
Да, я против проверки конкретных типов исключений компилятором. Разраб либы не знает, в каком контексте её будут юзать, поэтому он не должен принимать решение за других. Ошибочный путь от успешного он отделил, инфу о проблеме он приложил, дальше - не его дело.
> что должна делать программа если NetworkIsDown
А я ебу? Это конкретная программа решает. Выйти с ошибкой, попросить юзера подключить сеть если мы на мобиле, отложить в очередь до появления сети и т.п.
Вся засада в том, что чем больше ты обрабатываешь конкретные ошибки, тем больше приходится обрабатывать конкретные ошибки... А в итоге юзер всё равно не поймёт их. Да и даже ты сам не поймёшь без ковыряния в логах. Поэтому, имхо, лучше вложиться в логи чем в этот сизифов труд.
Важен факт ошибки, и конпелятор не даёт его проебать.
Важны простые и популярные ошибки, которые юзер реально может исправить. А они, внезапно, обычно находятся в самом первом исключении - "нет доступа", "файл не найден", "неожиданный символ {". И чем меньше ты заворачиваешь эти исключения, тем легче их выловить на верхнем уровне и показать на понятном для юзера языке, возможно даже с локализацией.
А для автономных сервисов выбор между логами и обмазыванием трайкетчами вообще очевиден.
> тупо передать ошибку наверх
Именно так. Если сразу с ошибкой ничего придумать не удалось - значит пусть с ней разбирается generic обработчик аля Залогировать и Сдохнуть™. В середине цепочки вызовов она нахуй никому не нужна.
> We went to lunch afterward, and I remarked to Dennis that easily half the code I was writing in Multics was error recovery code. He said, "We left all that stuff out. If there's an error, we have this routine called panic(), and when it is called, the machine crashes, and you holler down the hall, 'Hey, reboot it.'"
А то пишут, пишут... исключения, трайкетчи какие-то... Голова пухнет. Взять всё, да и завершить...
Иногда я могу хотеть передать их наверх, иногда -- обработать сразу, иногда вообще хочу "залогировать и сдохнуть", потому что знаю, что такого не может быть (ну или я не знаю как это обработать).
Но CheckExceptions мне права выбора не дают, их надо явно заворачивать в RunTime или засирать ими все сигнатуры по стеку вызова.
var petuh = getPetuh("c://pethu.json") ignore (InvalidJson, FileNotFound);
тут я явно отказался от обработки эксепшенов. По сути они стали RunTime, улетели на верх стека, и там завалили программу с трейсом, или их поймал местный доктор вацон, или они выдали 500-ю ошибку итд.
То-есть компилятор мне говорит: "чувак, вот эти три ошибки может вернуть фукнция"
А я ему: "вот эти две хочу обработать, а на эту пойху, можеш упасть".
Х.з., во-первых ignore - не самый подходящий кейворд, больше о собачке напоминает чем о перевбросе.
Во-вторых - это же просто сахар для try-с-перевбросом.
Лучше уж возвращать Either с паттерн-матчингом в тех случаях, где это реально надо. И да, IoException и JsonException - это не те случаи, где это реально надо.
Ну и что теперь из-за редких случаев, где такая обработка нужна, заставлять всех, вообще всех её делать?
Хочешь ли ты показывать юзеру на какой строке сломан жсон в твоём описании пакета обновлений или ответе от сервера. Да нет конечно, он все равно ничего не сможет с этим сделать. Записать по catch-all в лог да и всё.
А JsonException примечателен тем, что полезный кейс у него ровно один. В момент парсинга. Во всех остальных местах, откуда его кидают, это просто ошибка программиста, которая не должна быть checked. В этом и вред cheched исключений.
Ну это ж не сишка - солнце не потухнет, луна не наебнётся. Ну задаст тебе юзер вопрос о "неизвестной ошибке", ну разберёшь её по логу и добавишь обработчик.
Х.з., имхо фича, которая заставляет писать и поддерживать бойлерплейт, должна приносить в замен очень много пользы. Иначе она тупо вредна и её не надо включать в язык.
Однажды я спросил питониста: как ему живется с утиной типизацией и отсутствием статической типизации? Не страдает ли он от проблем с неверными типами в рантайме?
Не плохо ли ему от того, что IDE не может подсказать все методы объекта?
Не напрягает ли его то, что "age + 2" может упасть в рантайме от того, что age это строка?
Он ответил:
Ну это ж не сишка - солнце не потухнет, луна не наебнётся. Ну задаст тебе юзер вопрос о "неизвестной ошибке", ну разберёшь её по логу и добавишь явный int().
Х.з., имхо фича, которая заставляет писать и поддерживать бойлерплейт (явные касты, кучу интерфейсов, адаптеры итд), должна приносить в замен очень много пользы. Иначе она тупо вредна и её не надо включать в язык.
Ну собственно поэтому языки без статической типизации вполне себе живы и популярны. Если бы всё было так однозначно - их бы уже давно обоссали и сожгли.
Но ты слишком высоко замахнулся.
Checked exceptions - это мелкая фича на уровне "а давайте выкинем из крестов auto и и будем писать все типы явно, вдруг функция вернёт не тот тип, что мы ожидали". В общем-то порядок пользы и бойлерплейта совпадает.
Если бы всё плохое обссыкали и сжигали, то кругом был бы сплошной ocaml, а не электрон с джаваскриптом.
Вывод типов -- не оч удачный пример, всё таки он проверяется статически: нельзя получить char, и вызвать у него метод foo();
Да и IDE скорее всего выведет тебе тип.
А где я могу узнать список возможных исключений? А как я убеждюсь, что я всё проверил?
По документации?
Это всё равно, как узнавать список методов по документации в скриптовых языках
> unchecked
ИМХО, такой подход не исправляет Фатальный Недостаток checked-исключений: если вдруг вызываемый метод отрефакторится и начнёт кидать ещё одно исключение, тебе придётся лазить по всем цепочкам вызовов и править все методы из цепочек. Это, мягко говоря, неудобно.
Вот есть метод A, который кидает TyHujException, есть метод B, который вызывает метод B:
A() throws TyHujException:
...
B():
a = A()
Тогда при checked-исключениях программист обязан либо поймать TyHujException на моменте вызова A(), либо не ловить, но добавить к сигнатуре B() «throws TyHujException». А как предлагаешь ты?
То есть проигнорированные («ignore (InvalidJson, FileNotFound)») исключения улетают наверх, но при этом в сигнатуру метода их добавлять не нужно? Как-то смысл тогда теряется: любой метод в итоге может выкинуть любое исключение, а чтобы понять какое — надо читать его код.
>Как-то смысл тогда теряется
Почитай примеры из моего коммента.
При вызове метода я могу выбрать одно из трех:
* Передать обработку ошибок выше (написать throws)
* Обработать их на месте (написать catch)
* Сказать, что такой ошибки быть не может при нормальной работае программы. А если она случилась, то надо залогировать и сдохнуть. Для меня эта ошибка ничем не отличается от NPE. Это ignore.
Такие ошибки ловить не нужно.
>юбой метод в итоге может выкинуть любое исключение, а чтобы понять какое
Не надо этого понимать. Если метод не сообщил через throws что он кидает -- то и ловить это отдельно не нужно.
Не знаю, голова плохо работает. С поверхностной точки зрения действительно выглядит как бойлерплейт. К тому же, малость туманны перспективы написания устойчивого кода, который вообще никогда не должен падать.
Задачи разные бывают. К тому же, падать тоже можно по-разному: показать пользователю красивое окошко с телефоном саппорта и диагностической информацией, например. То есть нужен механизм, который бы позволял отлавливать все исключения, включая проигнорированные.
Тогда такая система разрушает основное преимущество checked исключений: мы не знаем, какая ошибка может вылететь из очередного getPetuh(): это может быть либо то, что у него в throws, либо какое-то внутреннее исключение, которое он проигнорировал. Чтобы понять какое — надо копать либо исходники, либо документацию.
> getPetuh разумеется сообщает о вылетающих ошибках посредством "throws", а его клиент может их тут же задавать через ignore.
Я рассматриваю не два уровня, а три. getPetuh() сообщает об ошибке InternalPetuhError посредством throws, getKuryatnik() вызывает getPetuh() и игнорирует InternalPetuhError (не засирая им свою сигнатуру), doWork() вызывает getKuryatnik() и не может понять, откуда ему прилетело InternalPetuhError.
Весь смысл check-исключений можно свести к двум утверждениям:
1) Для любого вызова гарантируется, что он не приведёт к аварийному завершению работы программы;
2) Для любого вызова гарантируется, что программист рассмотрел все возможные ошибки и решил, что с ними делать.
Таким образом, сочетание двух этих гарантий позволяет создавать максимально надёжный код: любая возможная ошибка в конце концов будет где-то обработана программистом. При этом благодаря второму утверждению программисту удобнее обработать ошибку как можно раньше.
А с возможностью проигнорировать какие-то исключения получается, что обе этих гарантии перестают работать: любой вызов может выкинуть какую-то левую фигню, не указанную в throws.
> А вдруг ему прилетит NPE? Он тоже должен его как-то особо обрабатывать?
Конечно, почему нет?
> Не все ошибки. Например, ошибку OutOfMemory программист не рассматривает. И NPE Тоже.
А не надо решать за программиста, что ему нужно рассматривать, а что не нужно. Программа вполне может при получении OOM попытаться, например, снизить разрешение текстур.
> Любая функция может их выкинуть.
А какой вообще тогда смысл в checked исключениях? Зачем писать весь этот бойлерплейт, если получившаяся программа ничем не отличается от таковой без бойлерплейта? Что первая, что вторая могут рандомно упасть из-за рандомной необработанной ошибки. Информацию о типах выбрасываемых исключений спокойно можно найти в доке (если это нормальная дока, а не говно) либо вообще заставить это делать конпелятор.
То-есть ты всегда пишешь catch(NPE) вокруг каждого метода?
>А не надо решать за программиста, что ему нужно рассматривать, а что не нужно.
Ради бога, лови всё, что угодно. Важно, что checked ты должен или явно поймать, или явно сказать, что это не являетчся для тебя проблемой. Что там будут делать наверху не важно.
>А какой вообще тогда смысл в checked исключениях?
Я вижу, что ты меня вообще не понимаешь((
Видимо, у меня проблемы с объяснением идеи (при том что Борманд, кажется, понял)
Почитай еще раз https://govnokod.xyz/_26533/#comment-519175
* Функция для парсинга JSON может вернуть ошибку что JSON невалиден
* Пользователь функции обязан ее обработать или явно сказать, что обрабатывать ее не хочет (потому что json он до этого проверил, например)
* Не обработанные исключения ловятся где-то наверху, и приводят к сообщениям об ошибке, записи в логи итд
* Но есть так же ошибки, которые обычно не обрабатывают, потому что знают, что в нормальной программе их нет (NPE)
* Такие ошибки называютися Runtime
* Я утверждаю, что тип (checked или runtime) должен определяться не классом, а использованием.
* реальный пример https://govnokod.xyz/_26533/#comment-519209
> То-есть ты всегда пишешь catch(NPE) вокруг каждого метода?
Когда нужно — я и векторные исключения ставлю, чтобы «сегфолты» ловить.
Да, я понял, что «одноуровневые» исключения хорошо ложатся на такую систему. Однако уже для двухуровневых (A() вызывает B(), который вызывает C(), который кидает исключение) её смысл по большей части исчезает, и она становится простым бойлерплейтом.
>>> getPetuh() сообщает об ошибке InternalPetuhError посредством throws, getKuryatnik() вызывает getPetuh() и игнорирует InternalPetuhError (не засирая им свою сигнатуру), doWork() вызывает getKuryatnik() и не может понять, откуда ему прилетело InternalPetuhError.
В этом случае нет абсолютно никакой разницы: что есть checked исключения, что их нет. А бойлерплейт есть.
И ты никак, без чтения сорцов, не узнаешь, что автор какой-то говнолибы решил проигнорить какое-нибудь ConnectionTimeout.
Беда checked исключений с ignore() в том, что они заставляют писать столько же бойлерплейта, что и checked исключения без ignore(), но при этом обеспечивают гораздо меньше безопасности.
З.Ы. В сишке необработанная ошибка вызывала UB, продолжала исполнять код успешной ветки и творить хуйню. Поэтому там все дрочат на обработку ошибок.
В языках с исключениями, в отличие от сишки, нельзя забыть обработать ошибку - необработанное исключение не триггерит UB. Поэтому пользы от checked exceptions, имхо, меньше чем вреда.
> То-есть компилятор мне говорит: "чувак, вот эти три ошибки может вернуть фукнция"
Если компилятор вычислит это, сам, будет очень хорошо.
Я не хочу читать весь список ошибок, а потом ещё сверять его с ошибками, которые могут добавлять внешними питухами.
Например, если мы передаём в фукнцию другую функцию или объект, то при вызове этой функции или метода объекта может вылезти исключение, которое функция не бросает. И набор исключений зависит не от того, что написал автор, а от того, что написали автор с пользователем, а также от питушни вроде кодовставок внутри #ifdef.
приведенный тобою пример не решается на той системе, которая есть у джавы, потому что нельзя сказать, что выбрасываемое методом исключение зависит от параметра. А если бы можно было например так
(псевдокод)
runOnBackground(runnable: [Runnable throws T]) throws T
хуйни какой-то написал. короче, в джаве дженерики можно использовать и для выбрасываемых исключений. но всё равно это нихуя не работает, потому что дженерик-то один, а выбрасываешь ты какие-нибудь IOException, OrderException, AdminPetuhException. в юнион-тайпы еще не научились.
Было бы прикольно иметь удобный список типов ошибок, которые могут прилететь (и я сейчас не про документацию, которой обычно нет). А заставлять проверять на каждый чих это конечно странно.
З.Ы. Меня тут больше беспокоит, что не заставили написать ToString() для исключения. В итоге в логе будет какая-нибудь хуйня вместо HttPException(500). Или шарп умный и сам все поля исключения вываливает в трейс?
namespace dotnent_test
{
class MyException : Exception
{
public String Name { get; }
public MyException(String name)
{
this.Name = name;
}
public override string ToString()
{
return base.ToString() + Name;
}
}
public class MyClass
{
public static void Main(string[] args)
{
throw new MyException("Foo");
}
}
}
Unhandled Exception: dotnent_test.MyException: Exception of type 'dotnent_test.MyException' was thrown.
at dotnent_test.MyClass.Main(String[] args) in C:\Users\petuz\source\repos\dotnent_test\dotnent_test\Program.cs:line 23
> Унылая хуйня этот ваш c#.
Вот сейчас обидно было. В приведенном выше примере сообщение не залогировалось, потому что никакого сообщения в исключении нет. В консоль вываливается содержимое проперти «Message», ToString() тут вообще никаким боком. Кастомное исключение можно сделать примерно так:
using System;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
throw new MyException("Foo", "Bar");
}
class MyException : Exception
{
public MyException(string name, string myMessage) : base($"Name: {name}, message: {myMessage}") { }
}
}
}
Вывод в сосноль:
Unhandled exception. ConsoleApp.Program+MyException: Name: Foo, message: Bar
at ConsoleApp.Program.Main(String[] args) in C:\Users\user\source\repos\ConsoleApp\Program.cs:line 9
Почитал тред, и мне как-то больше стал нравиться подход C.
Исключения либо ещё слишком мало понятны народу (как табы), либо могут использоваться только в очень хорошо спроектированном коде, и не каждый проект может быть того масштаба, когда исключения действительно помогают, а не запутывают.
Это же банальное нарушение структурного и процедурного программирований, нарушение инкапсуляции. Внутренняя питушня может легальным образом произвольно повлиять на все слои абстракции над ней. Какое-то говно.
А потом приходят полуборманды и говорят, что не будут ловить исключения, пусть пользователи их библиотек разгребают то, что было кинуто питушнями, которые использовали использованные полубормандами библиотеки.
А потом приходят борманды и говорят, что не будут ловить эту питушню и попросят уже конечного пользователя сообщить о проблеме 0xCCD3208EF Invalid call.
То ли дело сишка, где имеем либо кривое говно, либо корректный код, который не может вернуть что-то, что не указано в документации или в определении функции.
А в языках с исключениями кривое говно называют библиотеками.
Обработай ещё раз этот ебучий код возврата да верни его.
Что с исключениями что без них код работает совершенно одинаково. Просто в варианте с исключениями не надо обмазывать каждый вызов бойлерплейтом. И можно приложить чуть больше инфы, чем просто инт.
Можно забыть проверить, но это сразу воспринимается как грех.
А вот исключения постоянно забывают проверить, поэтому наружу лезет какая-то питушня из кишок библиотек. И это считается нормальным.
Вариант с монадами отличный. Там и пердолиться руками надо много меньше, и забыть проверить невозможно. Ты точно знаешь, что возвращает функция, нет никакого протыкания инкапсуляции.
Подтверждаю. Вообще, ситуация, когда я вызываю метод библиотеки A, а мне в ответ прилетают кишки библиотеки B, которую я даже не устанавливал явно — это какое-то ненормальное поведение.
Потому что это детали реализации библиотеки A, которые меня ну вообще никак не касаются.
Более того, если завтра авторы библиотеки A поменяют библиотеку B на библиотеку C — всем клиентам придётся менять catch (B_Exception) на catch (C_Exception) — при том, что публичный интерфейс библиотеки A не меняется никак, меняются детали реализации. И это пиздец.
UPD: я, как клиент библиотеки A, вообще не должен знать об особенностях её реализации (в частности, какие она там использует библиотеки) ничего. А пробрасываемые исключения этот принцип успешно похеривают.
> Более того, если завтра авторы библиотеки A поменяют библиотеку B на библиотеку C — всем клиентам придётся менять catch (B_Exception) на catch (C_Exception) — при том, что публичный интерфейс библиотеки A не меняется никак, меняются детали реализации.
О_о ну вообще-то публичный интерфейс поменялся. То, что этого тебе не скажет компилятор, говорит просто о том, что компиляторам стоит в этом плане ещё есть куда расти. А так - документация, которая, на мой взгляд, тоже является частью публичного интерфейса.
> я, как клиент библиотеки A, вообще не должен знать об особенностях её реализации
- это очень смелое заявление.
> Поменялся не публичный интерфейс, поменялись детали реализации.
- у тебя другие исключения могут прилетать. Повторюсь: дока, где это должно быть описано, это тоже часть публичного интерфейса.
> Или я что-то пропустил, и банальная инкапсуляция вышла из моды?
- это уже не инкапсуляция, это уже изоляция какая-то. Допустим, по поводу обычных типов и методов я с тобой соглашусь. Но исключения они на то и исключения, что они демонстрируют исключительную ситуацию. Зачем мне затенять то место, откуда стрельнуло что-то исключительное?
> Авторы нормальных либ
> нормальных
- пошла вкусовщина.
> Повторюсь: дока, где это должно быть описано, это тоже часть публичного интерфейса.
Значит, в публичный интерфейс пролезли детали реализации. Это тоже эталонное говно.
> это уже не инкапсуляция, это уже изоляция какая-то
Нет, это в точности инкапсуляция. Сокрытие деталей реализации, алло, это пишут в любой книжке «ООП за 20 минут»!
> Зачем мне затенять то место, откуда стрельнуло что-то исключительное?
Затем, что это место никак не касается клиентов библиотеки. Если из метода A::F() мне прилетело исключение — это значит, что в исключительную ситуацию попал метод A::F(). Именно A::F(), метод из библиотеки A!
> пошла вкусовщина
Это не вкусовщина, это реальный пример правильно сделанных исключений.
> Значит, в публичный интерфейс пролезли детали реализации. Это тоже эталонное говно.
- значит, почти любая документация состоит на 90% из эталонного говна (по мнению gost'а).
> это место никак не касается клиентов библиотеки.
- откуда ты знаешь, касается оно или нет? Ты в курсе тонкостей всех охулиардов проектов на матушке Земле? Ну камон, не будь таким Нарциссом
> почти любая документация
> на 90%
[citation needed]
> откуда ты знаешь, касается оно или нет?
Оттуда, что это самые основы ООП. Оттуда же, откуда знаю, что нельзя дёргать приватные члены чужих классов.
> Ты в курсе тонкостей всех охулиардов проектов на матушке Земле?
Мне не нужно быть в курсе тонкостей всех охулиардов проектов, чтобы понимать, что раскрытие деталей реализации — это говно. В любом случае говно.
If the implementation cannot parallelize or vectorize (e.g. due to lack of resources), all standard execution policies can fall back to sequential execution.
Чо, не деталь реализации?
> Оттуда же, откуда знаю, что нельзя дёргать приватные члены чужих классов.
- а чего ты вдруг заговорил про приватные члены, если типы исключений у нас публичные?
> раскрытие деталей реализации — это говно
- даже если это не противоречит здравому смыслу, но противоречит книжке "ООП за двадцать минут"?
> деталь реализации? Деталь.
Вовсе нет. Это описание публичного интерфейса элементов, который ожидает эта функция. С тем же успехом деталью реализации можно назвать типы входных параметров.
> Чо, не деталь реализации?
И опять нет. Здесь описывается наблюдаемое поведение политик.
Впрочем, ладно: детали реализации действительно могут быть добавлены в документацию. Однако это должны быть просто справочные материалы, на которые никак нельзя опираться при разработке программы-клиента. Например, как здесь: https://en.cppreference.com/w/cpp/algorithm/for_each (раздел «Possible implementation»).
> а чего ты вдруг заговорил про приватные классы, если типы исключений у нас публичные?
Потому что приватные члены класса — это детали его реализации, и используемые внутренние библиотеки — тоже детали реализации библиотеки.
> даже если это не противоречит здравому смыслу
Это противоречит здравому смыслу. Чем больше деталей реализации раскрывается клиентам библиотеки (причём раскрывается так, что клиенты становятся зависимы от них) — тем труднее становится детали реализации поменять. А простота смены внутренней реализации — это самое главное преимущество, которое обеспечивает инкапсуляция.
> Вовсе нет. Это описание публичного интерфейса элементов, который ожидает эта функция.
- это ты сам придумал, в доке такого нет. Там написано, что сравнение происходит при помощи такого-то оператора и гуляйте.
> наблюдаемое поведение
- поведение это не реализация?
Библиотека может оборачивать исключения, а может не оборачивать. Вызывающий код может лучше знать, что ему делать с исключением конкретного типа из конкретной библиотеки, потому что мы живём в неидеальном мире хаков, костылей и всяких трюков, а ты его такой возможности своими обёртками лишаешь. Противоречит здравому смыслу слепое следование мантрам.
А безболезненная смена внутренней реализации, при которой мы кишки поменяли и никто не заметил, бывает только на проектах на 10 файлов.
> это ты сам придумал, в доке такого нет. Там написано, что сравнение происходит при помощи такого-то оператора и гуляйте.
В мире «C++» это и есть описание публичного интерфейса, потому что перегруженные операторы — это его часть.
> поведение это не реализация?
Поведение — это не реализация.
> Библиотека может оборачивать исключения
Хорошая библиотека.
> а может не оборачивать
Говно.
> Вызывающий код может лучше знать, что ему делать с исключением конкретного типа из конкретной библиотеки
И таким образом он намертво себя прикручивает к деталям реализации библиотеки.
> мы живём в неидеальном мире хаков, костылей и всяких трюков
Да. Хаки, костыли и «всякие трюки» — это говно. Говно, от которого надо избавляться и которое уж точно не надо плодить. В точности следуя твоей логике, все члены любых классов должны быть публичными — ведь мы же живём в неидеальном мире хаков, костылей и всяких трюков, и своей приватностью их все ломаем!
Проводя аналогии, мы живём в неидеальном мире фастфуда, колы и всяких чипсов. Означает ли это, что здоровое питание нинужно?
> А безболезненная смена внутренней реализации, при которой мы кишки поменяли и никто не заметил, бывает только на проектах на 10 файлов.
Нет. Если внутренняя реализация не пролазит в публичный интерфейс — её можно спокойно менять. В таком случае, даже если какой-то говнокодер завязал на неё свой код — это будут исключительно его проблемы, у нормальных людей всё будет работать.
> И таким образом он намертво себя прикручивает к деталям реализации библиотеки.
- ну и хер с ним. Мне сидеть дрожать 10 лет над тем, что у моих зависимостей сменятся зависимости, или иметь ништяки уже сегодня?
Ну и так-то конечный код всё равно придётся перекомпилировать, если речь про кресты etc.
Культ карго какой-то.
> Проводя аналогии
- не надо, пожалуйста, проводить аналогии, потому что обычно, как и в этом случае, они хуёвы и абсолютно неуместны. Здоровое питание это такая же маркетинговая хуета, как и оопэшные мантры про повсеместную инкапсуляцию.
> все члены любых классов должны быть публичными
- да, потому что инкапсуляция должна быть на уровне модулей, а не типов, но это отдельный разговор.
> Нет.
- хватит троллировать. Ладно бы ты был каким-то рандомным неосилятором, а серьёзному кабальеро писать такую ересь должно быть стыдно.
> Ну и так-то конечный код всё равно придётся перекомпилировать, если речь про кресты etc.
- ну хотя тут я немного напиздел для случаев динамической линковки.
> ну и хер с ним. Мне сидеть дрожать 10 лет над тем, что у моих зависимостей сменятся зависимости, или иметь ништяки уже сегодня?
То есть ты за написание неподдерживаемого говнокода, главное — шоб побыстрее? Ну ок, предлагаю тебе переехать на «PHP» и писать перед каждым методом собачку.
> Ну и так-то конечный код всё равно придётся перекомпилировать, если речь про кресты etc.
Зачем? Зачем? В случае крестов придумали «pimpl».
> не надо, пожалуйста, проводить аналогии, потому что обычно, как и в этом случае, они хуёвы и абсолютно неуместны
Нет, это абсолютно точная аналогия.
Поведение основано на реализации, оно и есть реализация.
Да, диетологи это по большей части хуета (но не все, разумеется). ВОЗ шаражкина контора про отмывание бабла в глобальных масштабах. Инкапсуляция без повода это культ карго. PHP - говно, сам на него переходи 🙂
> А, ну понятно.
- нет, не понятно, потому что комментарии лучше читать целиком. На этом откланиваюсь, потому что разговор потерял последние остатки конструктива.
> оно и есть реализация
Нет. Наблюдаемое поведение зависит от реализации, но не является ею. Точно так же, как результат выполнения функции зависит от её реализации, но не является ею.
> Да, диетологи это по большей части хуета (но не все, разумеется). ВОЗ шаражкина контора про отмывание бабла в глобальных масштабах.
Ну то есть ты считаешь, что рацион человека никак не сказывается на его, человека, здоровье?
> Инкапсуляция без повода это культ карго.
Не бывает «повода» для инкапсуляции. Бывают детали реализации, их надо скрывать — всё. Детали реализации, просачивающиеся в публичный интерфейс — априори говно, такого надо избегать.
Ну да, разумеется, в нашем неидеальном мире не всегда получается делать всё так, как надо. Однако это совсем не означает, что к этому не надо стремиться. Если есть выбор между говном и не говном — нужно выбирать не говно. Нет выбора — увы, придётся писать говно. Только говно от этого не станет нормой.
Как можно остыть и выкинуть в мусорку инкапсуляцию?
Допустим, все наши познания - предрассудки. Но тогда нужен хотя бы хороший пример того, как написали успешную программу без инкапсуляции, которая пережила все правки, и вообще поддерживается без проблем.
Я (говнокодер-с) только недавно правил питушню, которая была более-менее инкапсулирована, но всё равно вылезла в 3 дополнительных места. Только попердолился больше с кодом, никаких плюсов от недостатка инкапсуляции не получил.
>> ВОЗ шаражкина контора про отмывание бабла в глобальных масштабах.
> Ну то есть ты считаешь, что рацион человека никак не сказывается на его, человека, здоровье?
Кстати, может быть два варианта сразу.
1. Бабло массово отмывается на питушне, которая на 0.0001% полезнее обычного питухания.
2. Если кто-то жрёт радий или регулярно пьёт колу, умирает от неправильного питания.
> Ну то есть ты считаешь, что рацион человека никак не сказывается на его, человека, здоровье?
- я тебе так отвечу: Стив Джобс был лучший диетолог ЕВПОЧЯ
Это несколько из другой оперы. Какой мне нужен телефон — это чистый субъективизм, какой хочу — такой и нужен. А вот человеческое тело нифига не субъективно. Человек — это сложный биологический механизм, который, тем не менее, вполне себе подчиняется определённым физическим, химическим, биологическим и так далее законам. И вот над выведением этих самых законов и работают биологи, диетологи, анатомы, патологоанатомы и прочие хорошие люди. Работают они достаточно успешно, например, как говорит нам «Википедия»,
Первым полномасштабным исследованием, подтвердившим, что
здоровое питание может значительно снизить проблемы с
сердечно-сосудистыми заболеваниями, ожирением и диабетом,
стал проект «Северная Карелия», проведение которого стартовало
в Финляндии в 1973 году. За 35 лет у населения области Северной
Карелии смертность от сердечно-сосудистых заболеваний снизилась
в 7 раз. Этот результат лёг в основу общеевропейской Стратегии
по здравоохранению 2020.
— ссылку на подробное описание этого проекта я кидал выше.
Но в общем-то да, никто не может сказать тебе, какое питание тебе нужно. Зато вполне успешно могут сказать, что если (условный) ты будешь регулярно кушать жареное мясо на ночь, то в итоге получишь определённые… осложнения.
Помнишь, тут была недавно история про rust-ера, который выпилил свою репу из-за травли? Вот твой безапелляционный спич мне напоминает тех растофанатиков, которые его доебали. Потому что надо делать не так, чтобы оно работало, а так, как кому-то нравится, правда?
> Потому что надо делать не так, чтобы оно работало, а так, как кому-то нравится, правда?
В идеале, надо делать так, чтобы было правильно. В реальности — правильно настолько, чтобы уложиться в сроки.
Инкапсуляцию, SOLID и вот эти вот все «баззворды» придумали не просто так. Их проектировали умные люди специально для того, чтобы менее умные люди (или просто те, кому лень тратить время на переизобретение одного и того же) могли писать корректный, расширяемый и поддерживаемый код. Увы, но попытки забить на всё и говнокодить как придётся, «шоб работало», приводят только к созданию неподдерживаемого говнокода.
Если код не писать, а только делать кодревью и умничать, то все баззворды конечно принимают новое звучание. А так-то умные люди сначала спроектировали инкапсуляцию, а потом решили добавить friend classes, а другие умные люди решили, что вообще ничего проектировать не надо, а достаточно naming convention добавить 😀 А вы мне ещё насыпьте, пожалуйста, этих французских булок, потому что я смотрю бинарное мышление достигло апогея и теперь выражается как "как сказал gost, то есть, правильно" - "как gost не говорил, то есть, говно и шоб работало".
Одно дело - инкапсуляция, которая в большем количестве случаев полезна и действует не только с C и Java, но и в JS. Она действует и в ПП, и в ФП, и в ООП. Это общий принцип. И он проверен настолько же хорошо, насколько закон Ома.
Другое дело - конкретная реализация в языке, где держат обратную совместимость, вставляют фичи средним арифметическим разумом комитета.
Честно говоря, я крайне удивлён, что мне приходится кому-то объяснять, что нарушение инкапсуляции — это плохо. Это же самые базовые принципы проектирования систем. Дальше-то что — доказывать вред god-object'ов? Или магических констант? Или на реальных примерах показывать, что нужно писать тесты?
И не надо во всём обвинять бедного Госта. Инкапсуляцию придумали совсем другие люди — я тогда ещё не родился.
Хз, я тоже не понимаю, зачем ты уже два десятка комментариев настрочил вместо того, чтобы просто согласиться, что пробрасывать исключения наверх это ок.
А остальной снобизм свой оставь пожалуйста для учеников на уроке информатики или первокурсников, которым ты возможно втираешь эту дичь.
Проброс наверх чужих исключений, являющихся частью внутренней либы — это нарушение инкапсуляции. Нарушение инкапсуляции — это плохо. Проброс наверх чужих исключений, являющихся частью внутренней либы — это плохо.
По-моему, это достаточно очевидная цепочка.
Ты правда считаешь, что перечисленные мной god-object'ы и магические константы — это ОК, тесты писать не нужно, а кто утверждает обратное — тот сноб?
Что ты будешь делать, если не все исключения из зависимости надо пробрасывать 1-в-1? Городить какой-то ArbitraryException? А как ты будешь передавать метаданные туда? Напишешь на каждом уровне, где добавляется обёртка, по дополнительной структуре? А что, если у тебя глубина дерева зависимостей больше единицы? Ты построишь целый фреймворк, который будет обёртывать исключения?
И потом ты собираешься это поддерживать, правда?
> Ты правда считаешь, что перечисленные мной god-object'ы и магические константы — это ОК, тесты писать не нужно, а кто утверждает обратное — тот сноб?
- нет, я так не считаю. God object это плохо, магические константы это тоже плохо, тесты писать конечно нужно, но тут уж как получается. Объясни только, пожалуйста, какое отношение это имеет к инкапсуляции? Она от констант и богообъектов вроде никак не спасает.
> Что ты будешь делать, если не все исключения из зависимости надо пробрасывать 1-в-1?
Их не надо «пробрасывать». Их надо обрабатывать согласно логике моего кода. Потому что если в моём методе появилось исключение, то это значит, что какая-то часть моего метода работает неправильно, и сообщить клиенту нужно именно об этом — соответствующим исключением, со всеми нужными метаданными.
> А что, если у тебя глубина дерева зависимостей больше единицы? Ты построишь целый фреймворк, который будет обёртывать исключения?
Нет, я буду обрабатывать исключительные ситуации в моём коде. В этом и состоит сила инкапсуляции: мне совершенно безразлично, какая там у используемой мной библиотеки глубина зависимостей. Я обращаюсь к библиотеке за каким-то результатом — и абсолютно не важно, как она его считает и какие либы вызывает. С исключительными ситуациями должна быть та же картина: я обращаюсь к библиотеке и ожидаю, что именно она мне скажет, что у неё произошла ошибка. А произошедшую ошибку я обработаю и выдам своему клиенту уже свою ошибку, которая будет описывать исключительную ситуацию в моём коде.
Да, это идеальная картина. В реальности же авторы либ* зачастую нарушают инкапсуляцию, в результате чего их клиентам приходится городить хаки и костыли, пихая в код совершенно ненужную для решения задачи информацию. *И я тоже не безгрешен, разумеется, и тоже пишу говнокод. Увы, идеала не бывает — но это не значит, что к нему не надо стремиться.
> Объясни только, пожалуйста, какое отношение это имеет к инкапсуляции?
God-object'ы, магические константы, нарушения инкапсуляции — это сущности одного порядка, антипаттерны.
> Потому что если в моём методе появилось исключение, то это значит, что какая-то часть моего метода работает неправильно
- почему это неправильно работает часть твоего метода? Эксепшн-то кинул не он. Ну, то есть, наверное, в условном идеальном ФП без побочек виноват будет твой метод, но обычно стрелять может откуда угодно и кто угодно.
Я правильно понимаю, что ты рассматриваешь любую исключительную ситуацию как исключительную ситуацию в твоём коде? Ну, это тоже подход, наверное.
> мне совершенно безразлично, какая там у используемой мной библиотеки глубина зависимостей.
- вопрос был скорее про случай, когда ты сам и есть автор этих зависимостей. То есть, когда из цепочки A <- B <- C <- D ты автор A, B и C.
> почему это неправильно работает часть твоего метода?
Потому что если мой метод получил исключение и не может продолжать нормальную работу, то это значит, что он оказался в исключительной ситуации и должен сообщить о ней клиенту. К ФП и чистоте такой подход малость отношение имеет: его практиковали ещё наши деды, которые в «C» код возврата проверяли.
> вопрос был скорее про случай, когда ты сам и есть автор этих зависимостей. То есть, когда из цепочки A <- B <- C <- D ты автор A, B и C.
Тут, в принципе, не особо важно, кто автор этих библиотек. Если я соблюдаю принцип DRY, то каждая библиотека из этой цепочке делает разные вещи. Соответственно, и исключения у них тоже будут разными. С другой стороны, если библиотеки A, B и С — это части единого целого, какой-то более общей библиотеки, и их использование по отдельности не предполагается, то, думаю, вполне разумно будет ввести для них какой-либо общий набор исключений. Впрочем, такое решение само по себе пованивает, так что it depends.
А что по их поводу пояснять? «Friend class» — это просто костыль, появившийся из-за того, что мы живём в несовершенном мире (ну и потому что ООП в крестах весьма кривое само по себе). А в «Питоне» инкапсуляция обеспечивается не языком, а конвенцией (причём как на уровне классов, так и на уровне модулей) — и не то чтобы я был против такого подхода.
Но в исключительную-то ситуацию попал метод именно этой библиотеки. Это он не смог выполнить задачу, которую я ему поручил — и он же и должен объяснить мне, почему.
Разумеется, такая обёртка будет говном. Возникшее в коде исключение должно быть осмысленно обработано, преобразовано в исключение, описывающее, что пошло не так, в него должны быть добавлены соответствующие метаданные — и уже в таком его можно отдавать клиентам.
Вся эта энциклопедичность, конечно, на словах прелестна, но по факту приводит к оверинжинирингу и горьким слезам, когда все написанные красоты приходится выпиливать уже в следующем релизе из-за изменившихся требований.
Один из важнейших принципов, который приходит с опытом: не делать больше работы, чем требуется.
Если тебе сейчас не нужен 100% loose coupling, то и не нужно сидеть и задрачивать его, у бизнеса есть требования, да и технический долг растёт не только в этом месте.
Это не энциклопедичность и не оверинжиниринг. Это всего лишь избегание антипаттернов: то, что всегда должен иметь в виду любой разработчик (если он пишет не на «PHP», конечно[/color]). Более того, грамотная инкапсуляция приводит к уменьшению количества слёз после изменения требований, поскольку чем меньше зацепление в проекте — тем меньше приходится перелопачивать навоза. И, разумеется, от необходимости выпиливать написанное не застрахован никакой код.
YAGNI — хороший принцип, и тоже придуман умными людьми. А вот применение этого принципа на практике, увы, хромает, поскольку точного определения «лишней функциональности» нет и вряд ли появится. В результате, при чрезмерно усердном его применении мы можем придти к отказу от, например, форматирования кода или грамотного именования переменных — ведь это же лишняя работа, программа прекрасно работает, даже если в ней названия всех переменных состоят из одной буквы!
Я о том и говорю: лихорадочное избегание антипаттернов приводит к избыточному коду (если конечно это не какие-то примитивные вещи вроде всем известной проверки индекса в цикле).
Если кодом пользуешься только ты, то можешь его и не форматировать и переменные называть huiPizda. И что, мало такого кода? Сам же знаешь, что есть такое понятие, как write-and-throw скрипты.
> Сравни, например, вот эти два исходника
- второй выглядит попричёсаннее, но я не настолько хорошо понимаю здоровые портянки на си, а потому на вопрос, какой из исходников я бы раскурил быстрее, ответить не могу.
…А столь же лихорадочное отрицание их существования приводит к тому, что write-and-throw код оказывается в продакшене.
Да, разумеется, код, который кроме тебя никто не увидит, можно писать вообще как угодно, и сам я тоже такое делаю. Главное в этом — чтобы такой код внезапно не начал на постоянной основе решать задачи бизнеса.
Да, причёсан, оформлен, декомпозирован и снабжён подробными комментариями (хотя казалось бы — вот где абсолютно бессмысленная работа, никак не помогающая задачам бизнеса!). И благодаря этому даже человек, не знакомый с портянками, сможет достаточно быстро понять, о чём там идёт речь (конечно, если ему это будет нужно, я ни к чему не призываю :-). А вот первый код, который писался олимпиадниками в их фирменном говностиле, понять и, главное, проститьизменить смогут только его авторы (и то только в первые пару недель/месяцев). И тому несчастному, которого посадят разгребать эти конюшни, останется только дунуть, плюнуть и переписать всё с нуля. И это печально.
> Потому что надо делать не так, чтобы оно работало, а так, как кому-то нравится, правда?
Интересные вопли, но лабу не приму. Приходите на пересдачу.
Вот реально вся эта питушня про маркетинговое здоровое питание инкапсуляцией и питушню уровня "работает - значит сделано" напоминает бугурт школьника, которого пытаются обучить чему-то, а он думает, что печальный многолетний опыт и просьбы не кормить орланов с рук, чтобы предотвратить новые случаи - лишь брюзжание стариков.
Ну так расскажи про свой печальный многолетний опыт. Как, например, из-за автора библиотеки, автор которой пренебрегал инкапсуляцией, ты лишился месячной премии. А то может там действительно какая-то катастрофа, которую за гулом брюзжания легко не заметить?
Я просто трачу больше времени на лишнее обсасывание своего кода, когда надо что-то изменить. Если там недостаток инкапсуляции, код разлагается и превращается в растекающуюся кашицу. Потом её нужно долго соскребать в баночки и тратить на это время вместо того, чтобы сделать что-то полезное.
Функции, процедуры, методы, операторы - это операции над своими аргументами. В ООП операции и первые аргументы слили вместе, сделав набор операций интерфейсом значений типа первых аргументов.
> Ну, сделать как в Go, в Си нельзя, потому что Си не Go
Можно, реальный пример я привёл перед примером с «Go». Да, синтаксис отличается, но суть — одна и та же.
Вообще не одна и та же суть. В Go err это не сраный int, во-первых, а, во-вторых, компилятор форсит проверку.
> Как деды ещё до нашего рождения возвращали
- а где здесь метаинформация?
Вот есть у тебя функция
int innerFunction(sometype value)
И есть
int outerFunction()
, которая в цикле обрабатывает пачку value при помощи innerFunction и которая должна, когда innerFunction возвращает что-то не то, вернуть код возврата с метаинформацией про объект, на котором всё сломалось (представим, что это, например, имя файла). И куда мне эту метаинформацию записать?
> В Go err это не сраный int, во-первых, а, во-вторых, компилятор форсит проверку.
Мелкие детали. Разве что с компайл-тайм проверками — да, беда. Но, повторюсь, сама суть подхода — явный возврат ошибки — абсолютно одинакова.
> И куда мне эту метаинформацию записать?
Куда хочешь. Можешь в отдельный выходной параметр, можешь вообще в какую-нибудь глобальную переменную.
errno is defined by the ISO C standard to be a modifiable lvalue of
type int, and must not be explicitly declared; errno may be a macro.
errno is thread-local; setting it in one thread does not affect its
value in any other thread.
gost # 0
MAPTOBCKuu_nemyx # 0 ⇈
gost # 0 ⇈
Fike # 0 ⇈
bormand # 0 ⇈
- оператор ветвления
- оператор цикла (желателен опыт работы с коллекциями)
- оператор возврата
- оператор обработки исключений
guest # 0 ⇈
* оператор собачки
* оператор одинарных кавычек
* реальный оператор
phpBidlokoder2 # 0 ⇈
phpBidlokoder2 # 0 ⇈
kak # 0 ⇈
KOPOHABuPYC # 0 ⇈
3.14159265 # 0 ⇈
А в жабе есть матч по ИЛИ catch (HttpException|AnotherException ex).
Вот бы скрестить жабу с# гадюкой.
Desktop # 0
https://ideone.com/yaYl9Y
А ваш язык так что, не умеет?
guest # 0
говно!
bormand # 0 ⇈
Обработай ещё этих ебучих JSONException'ов да выпей джавы.
guest # 0 ⇈
Вот тут тоже самое.
JSONException'ов и RPCExceptionов я наобрабатывал всласть, но приведенный гостом пример, к сожалению, не юзабелен: ничто не заставит клиента функции GetPetuhByHttp() написать эту цепочку. А джава могла бы заставить
Так что оба хуже.
bormand # 0 ⇈
Ну что за жабья философия... Программист - это ребёнок, которого надо водить за ручку и заставлять есть кашу?
Есть куча вполне разумных кейсов, когда исключения достаточно "обработать" в одной точке - цикле обработки сообщений, main'е и т.п. И я не хочу обмазывать все функции этими throws Exception, только чтобы дотащить этот сраный JSONException до этой точки. Даже в крестах это уже осознали и выкинули все спецификации исключений помимо "не кидает ничего" и "что-то может кинуть".
guest # 0 ⇈
Эмм.. ты против того, чтобы компилятор заставлял тебя проверять ошибки?
Тогда тебе должен нравится PHP: там вообще ничего проверять не обязательно.
>Есть куча вполне разумных кейсов, когда исключения достаточно "обработать" в одной точке
Да.
>я не хочу обмазывать весь код этими throws Exception
Я же сказал: говно и то, и другое.
Засирать весь код "throws PetuhException, ScriptuhException" -- плохо.
Разрешать пользовтаелю не проверять эксепшены -- тоже плохо, потому что как тогда ошибку вернуть?
"Этот метод возвращает или ответ, или одну из вот этих трех ошибок. Не забудьте их проверить пожалуйста. А если забудете -- то программа просто упадет, а комплиятор вам не поможет, потому что мы не в жабе". Так чтоли?
bormand # 0 ⇈
Всё. Если программист хочет сделать что-то полезное для юзера при каких-то конкретных исключениях - он прочитает о них в документации и обработает (какие-нибудь FileNotFound или NetworkIsDown, к примеру).
Остальные исключения обрабатывать нет никакого смысла - либо catch all + log либо terminate.
> компилятор вам не поможет
Он уже помог разделить код на успешный путь (вернули результат) и неуспешный путь (вернули исключение). И даже прокинул неуспешный путь через весь коллстек, в отличие от той же сишки где каждый вызов надо обмазывать проверками. И даже дал возможность прикрепить какую-то полезную инфу и строчку для лога. Что ещё надо то?
guest # 0 ⇈
Еще раз: ты против проверки компилятором?
И что должна делать программа если NetworkIsDown?
bormand # 0 ⇈
> что должна делать программа если NetworkIsDown
А я ебу? Это конкретная программа решает. Выйти с ошибкой, попросить юзера подключить сеть если мы на мобиле, отложить в очередь до появления сети и т.п.
guest # 0 ⇈
В итоге будет как в винде: "ошибка 0xDEADBEEF, обратитесь к системному адменистратору". Очень прекрасно.
bormand # 0 ⇈
Важен факт ошибки, и конпелятор не даёт его проебать.
Важны простые и популярные ошибки, которые юзер реально может исправить. А они, внезапно, обычно находятся в самом первом исключении - "нет доступа", "файл не найден", "неожиданный символ {". И чем меньше ты заворачиваешь эти исключения, тем легче их выловить на верхнем уровне и показать на понятном для юзера языке, возможно даже с локализацией.
А для автономных сервисов выбор между логами и обмазыванием трайкетчами вообще очевиден.
> тупо передать ошибку наверх
Именно так. Если сразу с ошибкой ничего придумать не удалось - значит пусть с ней разбирается generic обработчик аля Залогировать и Сдохнуть™. В середине цепочки вызовов она нахуй никому не нужна.
j123123 # 0 ⇈
> We went to lunch afterward, and I remarked to Dennis that easily half the code I was writing in Multics was error recovery code. He said, "We left all that stuff out. If there's an error, we have this routine called panic(), and when it is called, the machine crashes, and you holler down the hall, 'Hey, reboot it.'"
А то пишут, пишут... исключения, трайкетчи какие-то... Голова пухнет. Взять всё, да и завершить...
KOPOHABuPYC # 0 ⇈
3.14159265 # 0 ⇈
guest # 0 ⇈
Но CheckExceptions мне права выбора не дают, их надо явно заворачивать в RunTime или засирать ими все сигнатуры по стеку вызова.
Потому я предлагаю такой синтаксис.
Допусти, есть
Вот использование
тут я явно отказался от обработки эксепшенов. По сути они стали RunTime, улетели на верх стека, и там завалили программу с трейсом, или их поймал местный доктор вацон, или они выдали 500-ю ошибку итд.
А может это вообще write and throw script.
А вот тут другое дело
Я явно выразил желание обработать исключения.
То-есть компилятор мне говорит: "чувак, вот эти три ошибки может вернуть фукнция"
А я ему: "вот эти две хочу обработать, а на эту пойху, можеш упасть".
Как тебе идея?
guest # 0 ⇈
Упростил логику, проверь.
guest # 0 ⇈
guest # 0 ⇈
guest # 0 ⇈
ты заедушный анскилябр, который до такой степени не может в программирование, что даже не опнял, о чем тут речь
иди на ответы мейл ру, маня
https://otvet.mail.ru/question/67424596
guest # 0 ⇈
guest # 0 ⇈
Вероятно ты опять перепутал щеку своей мамы с моей щекой
bormand # 0 ⇈
Во-вторых - это же просто сахар для try-с-перевбросом.
Лучше уж возвращать Either с паттерн-матчингом в тех случаях, где это реально надо. И да, IoException и JsonException - это не те случаи, где это реально надо.
guest # 0 ⇈
да
>Лучше уж возвращать Either с паттерн-матчингом
возможно, но мы же про эксепшены
>IoException и JsonException - это не те случаи,
да ну? и вот тут не надо? а как надо?
bormand # 0 ⇈
Хочешь ли ты показывать юзеру на какой строке сломан жсон в твоём описании пакета обновлений или ответе от сервера. Да нет конечно, он все равно ничего не сможет с этим сделать. Записать по catch-all в лог да и всё.
А JsonException примечателен тем, что полезный кейс у него ровно один. В момент парсинга. Во всех остальных местах, откуда его кидают, это просто ошибка программиста, которая не должна быть checked. В этом и вред cheched исключений.
guest # 0 ⇈
Потому знание о том, должен-ли быть exception checked это не свойство класса, а семантика использования.
Сегодня он checked, завтра -- нет. Всё зависит от использования.
Вот тут это НЕ чекд эксепшен, а ошибка программиста
А вот тут очень даже checked
Потому-то я и предложил определять это на уровне вызова функции посредством слова ignored.
Ну ок, давай назовём его unchecked.
bormand # 0 ⇈
Вот именно 🙂
Если я поставил try - значит мне интересно это исключение. Если не поставил - значит нет.
И тут мы приходим к выводу, что спецификации исключений не нужны.
guest # 0 ⇈
И вот тут-то как раз спецификация нужна: нет ничего плохого в том, что я явно заигнорю неитересные мне исключения. А могу и не игнорить, а прокинуть
bormand # 0 ⇈
Ну это ж не сишка - солнце не потухнет, луна не наебнётся. Ну задаст тебе юзер вопрос о "неизвестной ошибке", ну разберёшь её по логу и добавишь обработчик.
Х.з., имхо фича, которая заставляет писать и поддерживать бойлерплейт, должна приносить в замен очень много пользы. Иначе она тупо вредна и её не надо включать в язык.
guest # 0 ⇈
Не плохо ли ему от того, что IDE не может подсказать все методы объекта?
Не напрягает ли его то, что "age + 2" может упасть в рантайме от того, что age это строка?
Он ответил:
Ну это ж не сишка - солнце не потухнет, луна не наебнётся. Ну задаст тебе юзер вопрос о "неизвестной ошибке", ну разберёшь её по логу и добавишь явный int().
Х.з., имхо фича, которая заставляет писать и поддерживать бойлерплейт (явные касты, кучу интерфейсов, адаптеры итд), должна приносить в замен очень много пользы. Иначе она тупо вредна и её не надо включать в язык.
bormand # 0 ⇈
Но ты слишком высоко замахнулся.
Checked exceptions - это мелкая фича на уровне "а давайте выкинем из крестов auto и и будем писать все типы явно, вдруг функция вернёт не тот тип, что мы ожидали". В общем-то порядок пользы и бойлерплейта совпадает.
guest # 0 ⇈
Вывод типов -- не оч удачный пример, всё таки он проверяется статически: нельзя получить char, и вызвать у него метод foo();
Да и IDE скорее всего выведет тебе тип.
А где я могу узнать список возможных исключений? А как я убеждюсь, что я всё проверил?
По документации?
Это всё равно, как узнавать список методов по документации в скриптовых языках
bormand # 0 ⇈
Да, по документации. Как и кучу других констрейнтов на аргументы, результаты и сайд-эффекты которые большинство систем типов не позволяют описать.
guest # 0 ⇈
И это плохо. Я мечтаю, например, о языке с системой эффектов.
О языках с явной обработкой ThreadSafe итд.
Но если этого нет, то это не повод отказываться от того, что есть.
Типа у нас и так нассано в подъезде, давайте я суда и насру еще?
gost # 0 ⇈
bormand # 0 ⇈
/thread
Пойду в дум ебашить.
gost # 0 ⇈
guest # 0 ⇈
gost # 0 ⇈
ИМХО, такой подход не исправляет Фатальный Недостаток checked-исключений: если вдруг вызываемый метод отрефакторится и начнёт кидать ещё одно исключение, тебе придётся лазить по всем цепочкам вызовов и править все методы из цепочек. Это, мягко говоря, неудобно.
guest # 0 ⇈
зачем?
если я пометил unchecked, то вызывающий его метод может вообще ничего о нем не знать
gost # 0 ⇈
Вот есть метод A, который кидает TyHujException, есть метод B, который вызывает метод B:
Тогда при checked-исключениях программист обязан либо поймать TyHujException на моменте вызова A(), либо не ловить, но добавить к сигнатуре B() «throws TyHujException». А как предлагаешь ты?
guest # 0 ⇈
https://govnokod.ru/26533#comment536558
Там видно, што я предлагаю
gost # 0 ⇈
guest # 0 ⇈
>Как-то смысл тогда теряется
Почитай примеры из моего коммента.
При вызове метода я могу выбрать одно из трех:
* Передать обработку ошибок выше (написать throws)
* Обработать их на месте (написать catch)
* Сказать, что такой ошибки быть не может при нормальной работае программы. А если она случилась, то надо залогировать и сдохнуть. Для меня эта ошибка ничем не отличается от NPE. Это ignore.
Такие ошибки ловить не нужно.
>юбой метод в итоге может выкинуть любое исключение, а чтобы понять какое
Не надо этого понимать. Если метод не сообщил через throws что он кидает -- то и ловить это отдельно не нужно.
gost # 0 ⇈
guest # 0 ⇈
Боманду вон всё равно лениво писать везде "ignores"
gost # 0 ⇈
guest # 0 ⇈
Ну там жеж был пример.
У меня в ресурах .jar файла лежит файл petuh.json.
Я в коде пишу:
Ты реально считаешь, что я должен обрабатывать как-то ошибку отсутсвия в моем джарнике файла?
Может, мне еще и ClassNotFound обработать?
gost # 0 ⇈
guest # 0 ⇈
Ты можешь сделать catch(Exception) наверху стека или явно зарегистрировать хендлер исключений у потока.
И там показать 500ю, или красивое завершение программы с телефоном суппорта, или писнуть в лог, или упасть со стектрейсой если это твой райт-н-сроу.
Как моя идея этому мешает?
ignores это просто сахар для оборачивания checked в Runtime без засирания cause
gost # 0 ⇈
guest # 0 ⇈
getPetuh разумеется сообщает о вылетающих ошибках посредством "throws", а его клиент может их тут же задавать через ignore.
Генеральная мысль такая: любое checked исключение в любой момент можно начать считать НЕ checked не засирая им сигнатуры по стеку вызовов)
> либо какое-то внутреннее исключение, которое он проигнорировал.
зачем? зачем это знать?
не надо этого знать
если проигнорировал -- значит он считает, что как-то особо обрабатывать это не надо
ты всегда читаешь код метода в поисках NPE чтобы его поймать?
admin # 0 ⇈
gost # 0 ⇈
Я рассматриваю не два уровня, а три. getPetuh() сообщает об ошибке InternalPetuhError посредством throws, getKuryatnik() вызывает getPetuh() и игнорирует InternalPetuhError (не засирая им свою сигнатуру), doWork() вызывает getKuryatnik() и не может понять, откуда ему прилетело InternalPetuhError.
Весь смысл check-исключений можно свести к двум утверждениям:
1) Для любого вызова гарантируется, что он не приведёт к аварийному завершению работы программы;
2) Для любого вызова гарантируется, что программист рассмотрел все возможные ошибки и решил, что с ними делать.
Таким образом, сочетание двух этих гарантий позволяет создавать максимально надёжный код: любая возможная ошибка в конце концов будет где-то обработана программистом. При этом благодаря второму утверждению программисту удобнее обработать ошибку как можно раньше.
А с возможностью проигнорировать какие-то исключения получается, что обе этих гарантии перестают работать: любой вызов может выкинуть какую-то левую фигню, не указанную в throws.
guest # 0 ⇈
Зачем ему это понимать?
А вдруг ему прилетит NPE? Он тоже должен его как-то особо обрабатывать?
>Для любого вызова гарантируется, что программист рассмотрел все возможные ошибки и решил, что с ними делать
Не все ошибки. Например, ошибку OutOfMemory программист не рассматривает. И NPE Тоже.
Любая функция может их выкинуть.
Понимаешь?
gost # 0 ⇈
Конечно, почему нет?
> Не все ошибки. Например, ошибку OutOfMemory программист не рассматривает. И NPE Тоже.
А не надо решать за программиста, что ему нужно рассматривать, а что не нужно. Программа вполне может при получении OOM попытаться, например, снизить разрешение текстур.
> Любая функция может их выкинуть.
А какой вообще тогда смысл в checked исключениях? Зачем писать весь этот бойлерплейт, если получившаяся программа ничем не отличается от таковой без бойлерплейта? Что первая, что вторая могут рандомно упасть из-за рандомной необработанной ошибки. Информацию о типах выбрасываемых исключений спокойно можно найти в доке (если это нормальная дока, а не говно) либо вообще заставить это делать конпелятор.
guest # 0 ⇈
То-есть ты всегда пишешь catch(NPE) вокруг каждого метода?
>А не надо решать за программиста, что ему нужно рассматривать, а что не нужно.
Ради бога, лови всё, что угодно. Важно, что checked ты должен или явно поймать, или явно сказать, что это не являетчся для тебя проблемой. Что там будут делать наверху не важно.
>А какой вообще тогда смысл в checked исключениях?
Я вижу, что ты меня вообще не понимаешь((
Видимо, у меня проблемы с объяснением идеи (при том что Борманд, кажется, понял)
Почитай еще раз
https://govnokod.xyz/_26533/#comment-519175
* Функция для парсинга JSON может вернуть ошибку что JSON невалиден
* Пользователь функции обязан ее обработать или явно сказать, что обрабатывать ее не хочет (потому что json он до этого проверил, например)
* Не обработанные исключения ловятся где-то наверху, и приводят к сообщениям об ошибке, записи в логи итд
* Но есть так же ошибки, которые обычно не обрабатывают, потому что знают, что в нормальной программе их нет (NPE)
* Такие ошибки называютися Runtime
* Я утверждаю, что тип (checked или runtime) должен определяться не классом, а использованием.
* реальный пример
https://govnokod.xyz/_26533/#comment-519209
gost # 0 ⇈
Когда нужно — я и векторные исключения ставлю, чтобы «сегфолты» ловить.
Да, я понял, что «одноуровневые» исключения хорошо ложатся на такую систему. Однако уже для двухуровневых (A() вызывает B(), который вызывает C(), который кидает исключение) её смысл по большей части исчезает, и она становится простым бойлерплейтом.
guest # 0 ⇈
>трехуровневые
и что? ну пиши везде throws, и будет точно так же, как и раньше.
Если ты хочешь, что бы клиент твоей функции как-то обработал исключение -- ставь throws.
Если не хочешь -- не ставь.
Клиент может обработать и без throws, но со throws он обязан или обработать или явно от этого отказаться.
Приведи реальный прмиер, где моя система не работает
gost # 0 ⇈
В этом случае нет абсолютно никакой разницы: что есть checked исключения, что их нет. А бойлерплейт есть.
И ты никак, без чтения сорцов, не узнаешь, что автор какой-то говнолибы решил проигнорить какое-нибудь ConnectionTimeout.
Беда checked исключений с ignore() в том, что они заставляют писать столько же бойлерплейта, что и checked исключения без ignore(), но при этом обеспечивают гораздо меньше безопасности.
guest # 0 ⇈
Зачем ему это понимать?
Он ничего не знает о питухах: Он дергает getKuryatnik.
Его вообще не должно ебать что там и откуда прилетает.
>только же бойлерплейта
нет, не столько же.
Ладно, мы по кругу ходим. Видимо мне надо более подробно объяснить мысль, либо дождаться Борманда, и попросить его перевести (раз уж он понял)
gost # 0 ⇈
ДОБРОЕ ИМЯ ДОБРАЯ СЛАВА В ЧЕСТИ 1024--, тебе тоже.
1024-- # 0 ⇈
bormand # 0 ⇈
В языках с исключениями, в отличие от сишки, нельзя забыть обработать ошибку - необработанное исключение не триггерит UB. Поэтому пользы от checked exceptions, имхо, меньше чем вреда.
1024-- # 0 ⇈
Если компилятор вычислит это, сам, будет очень хорошо.
Я не хочу читать весь список ошибок, а потом ещё сверять его с ошибками, которые могут добавлять внешними питухами.
Например, если мы передаём в фукнцию другую функцию или объект, то при вызове этой функции или метода объекта может вылезти исключение, которое функция не бросает. И набор исключений зависит не от того, что написал автор, а от того, что написали автор с пользователем, а также от питушни вроде кодовставок внутри #ifdef.
guest # 0 ⇈
но увы
приведенный тобою пример не решается на той системе, которая есть у джавы, потому что нельзя сказать, что выбрасываемое методом исключение зависит от параметра. А если бы можно было например так
(псевдокод)
было бы классно, но увы.
Fike # 0 ⇈
выше ветку не читал, но
https://ideone.com/CcDVzm
Fike # 0 ⇈
Desktop # 0 ⇈
bormand # 0 ⇈
guest # 0 ⇈
bormand # 0 ⇈
guest # 0 ⇈
Я не шарпей так-то
eukaryote # 0 ⇈
Вот сейчас обидно было. В приведенном выше примере сообщение не залогировалось, потому что никакого сообщения в исключении нет. В консоль вываливается содержимое проперти «Message», ToString() тут вообще никаким боком. Кастомное исключение можно сделать примерно так:
Вывод в сосноль:
guest # 0 ⇈
Спасибо, что исправил.
хотя было бы логично выволить туда toString
MAKAKA # 0 ⇈
всё верно, держи плюск
1024-- # 0
Исключения либо ещё слишком мало понятны народу (как табы), либо могут использоваться только в очень хорошо спроектированном коде, и не каждый проект может быть того масштаба, когда исключения действительно помогают, а не запутывают.
Это же банальное нарушение структурного и процедурного программирований, нарушение инкапсуляции. Внутренняя питушня может легальным образом произвольно повлиять на все слои абстракции над ней. Какое-то говно.
А потом приходят полуборманды и говорят, что не будут ловить исключения, пусть пользователи их библиотек разгребают то, что было кинуто питушнями, которые использовали использованные полубормандами библиотеки.
А потом приходят борманды и говорят, что не будут ловить эту питушню и попросят уже конечного пользователя сообщить о проблеме 0xCCD3208EF Invalid call.
То ли дело сишка, где имеем либо кривое говно, либо корректный код, который не может вернуть что-то, что не указано в документации или в определении функции.
А в языках с исключениями кривое говно называют библиотеками.
bormand # 0 ⇈
Что с исключениями что без них код работает совершенно одинаково. Просто в варианте с исключениями не надо обмазывать каждый вызов бойлерплейтом. И можно приложить чуть больше инфы, чем просто инт.
guest # 0 ⇈
1024-- # 0 ⇈
А вот исключения постоянно забывают проверить, поэтому наружу лезет какая-то питушня из кишок библиотек. И это считается нормальным.
Вариант с монадами отличный. Там и пердолиться руками надо много меньше, и забыть проверить невозможно. Ты точно знаешь, что возвращает функция, нет никакого протыкания инкапсуляции.
gost # 0 ⇈
Desktop # 0 ⇈
gost # 0 ⇈
Более того, если завтра авторы библиотеки A поменяют библиотеку B на библиотеку C — всем клиентам придётся менять catch (B_Exception) на catch (C_Exception) — при том, что публичный интерфейс библиотеки A не меняется никак, меняются детали реализации. И это пиздец.
UPD: я, как клиент библиотеки A, вообще не должен знать об особенностях её реализации (в частности, какие она там использует библиотеки) ничего. А пробрасываемые исключения этот принцип успешно похеривают.
Desktop # 0 ⇈
О_о ну вообще-то публичный интерфейс поменялся. То, что этого тебе не скажет компилятор, говорит просто о том, что компиляторам стоит в этом плане ещё есть куда расти. А так - документация, которая, на мой взгляд, тоже является частью публичного интерфейса.
> я, как клиент библиотеки A, вообще не должен знать об особенностях её реализации
- это очень смелое заявление.
gost # 0 ⇈
> это очень смелое заявление.
И совершенно верное. Или я что-то пропустил, и банальная инкапсуляция вышла из моды?
Авторы нормальных либ, кстати, эту проблему прекрасно понимают, и исключения из своих кишок не пробрасывают:
Но сама возможность такого — говно.
Desktop # 0 ⇈
- у тебя другие исключения могут прилетать. Повторюсь: дока, где это должно быть описано, это тоже часть публичного интерфейса.
> Или я что-то пропустил, и банальная инкапсуляция вышла из моды?
- это уже не инкапсуляция, это уже изоляция какая-то. Допустим, по поводу обычных типов и методов я с тобой соглашусь. Но исключения они на то и исключения, что они демонстрируют исключительную ситуацию. Зачем мне затенять то место, откуда стрельнуло что-то исключительное?
> Авторы нормальных либ
> нормальных
- пошла вкусовщина.
gost # 0 ⇈
Значит, в публичный интерфейс пролезли детали реализации. Это тоже эталонное говно.
> это уже не инкапсуляция, это уже изоляция какая-то
Нет, это в точности инкапсуляция. Сокрытие деталей реализации, алло, это пишут в любой книжке «ООП за 20 минут»!
> Зачем мне затенять то место, откуда стрельнуло что-то исключительное?
Затем, что это место никак не касается клиентов библиотеки. Если из метода A::F() мне прилетело исключение — это значит, что в исключительную ситуацию попал метод A::F(). Именно A::F(), метод из библиотеки A!
> пошла вкусовщина
Это не вкусовщина, это реальный пример правильно сделанных исключений.
Desktop # 0 ⇈
- значит, почти любая документация состоит на 90% из эталонного говна (по мнению gost'а).
> это место никак не касается клиентов библиотеки.
- откуда ты знаешь, касается оно или нет? Ты в курсе тонкостей всех охулиардов проектов на матушке Земле? Ну камон, не будь таким Нарциссом
gost # 0 ⇈
> на 90%
[citation needed]
> откуда ты знаешь, касается оно или нет?
Оттуда, что это самые основы ООП. Оттуда же, откуда знаю, что нельзя дёргать приватные члены чужих классов.
> Ты в курсе тонкостей всех охулиардов проектов на матушке Земле?
Мне не нужно быть в курсе тонкостей всех охулиардов проектов, чтобы понимать, что раскрытие деталей реализации — это говно. В любом случае говно.
Desktop # 0 ⇈
https://en.cppreference.com/w/cpp/algorithm/sort
деталь реализации? Деталь.
заходишь, а там
Чо, не деталь реализации?
> Оттуда же, откуда знаю, что нельзя дёргать приватные члены чужих классов.
- а чего ты вдруг заговорил про приватные члены, если типы исключений у нас публичные?
> раскрытие деталей реализации — это говно
- даже если это не противоречит здравому смыслу, но противоречит книжке "ООП за двадцать минут"?
gost # 0 ⇈
Вовсе нет. Это описание публичного интерфейса элементов, который ожидает эта функция. С тем же успехом деталью реализации можно назвать типы входных параметров.
> Чо, не деталь реализации?
И опять нет. Здесь описывается наблюдаемое поведение политик.
Впрочем, ладно: детали реализации действительно могут быть добавлены в документацию. Однако это должны быть просто справочные материалы, на которые никак нельзя опираться при разработке программы-клиента. Например, как здесь: https://en.cppreference.com/w/cpp/algorithm/for_each (раздел «Possible implementation»).
> а чего ты вдруг заговорил про приватные классы, если типы исключений у нас публичные?
Потому что приватные члены класса — это детали его реализации, и используемые внутренние библиотеки — тоже детали реализации библиотеки.
> даже если это не противоречит здравому смыслу
Это противоречит здравому смыслу. Чем больше деталей реализации раскрывается клиентам библиотеки (причём раскрывается так, что клиенты становятся зависимы от них) — тем труднее становится детали реализации поменять. А простота смены внутренней реализации — это самое главное преимущество, которое обеспечивает инкапсуляция.
Desktop # 0 ⇈
- это ты сам придумал, в доке такого нет. Там написано, что сравнение происходит при помощи такого-то оператора и гуляйте.
> наблюдаемое поведение
- поведение это не реализация?
Библиотека может оборачивать исключения, а может не оборачивать. Вызывающий код может лучше знать, что ему делать с исключением конкретного типа из конкретной библиотеки, потому что мы живём в неидеальном мире хаков, костылей и всяких трюков, а ты его такой возможности своими обёртками лишаешь. Противоречит здравому смыслу слепое следование мантрам.
А безболезненная смена внутренней реализации, при которой мы кишки поменяли и никто не заметил, бывает только на проектах на 10 файлов.
gost # 0 ⇈
В мире «C++» это и есть описание публичного интерфейса, потому что перегруженные операторы — это его часть.
> поведение это не реализация?
Поведение — это не реализация.
> Библиотека может оборачивать исключения
Хорошая библиотека.
> а может не оборачивать
Говно.
> Вызывающий код может лучше знать, что ему делать с исключением конкретного типа из конкретной библиотеки
И таким образом он намертво себя прикручивает к деталям реализации библиотеки.
> мы живём в неидеальном мире хаков, костылей и всяких трюков
Да. Хаки, костыли и «всякие трюки» — это говно. Говно, от которого надо избавляться и которое уж точно не надо плодить. В точности следуя твоей логике, все члены любых классов должны быть публичными — ведь мы же живём в неидеальном мире хаков, костылей и всяких трюков, и своей приватностью их все ломаем!
Проводя аналогии, мы живём в неидеальном мире фастфуда, колы и всяких чипсов. Означает ли это, что здоровое питание нинужно?
> А безболезненная смена внутренней реализации, при которой мы кишки поменяли и никто не заметил, бывает только на проектах на 10 файлов.
Нет. Если внутренняя реализация не пролазит в публичный интерфейс — её можно спокойно менять. В таком случае, даже если какой-то говнокодер завязал на неё свой код — это будут исключительно его проблемы, у нормальных людей всё будет работать.
Desktop # 0 ⇈
- а что тогда?
> И таким образом он намертво себя прикручивает к деталям реализации библиотеки.
- ну и хер с ним. Мне сидеть дрожать 10 лет над тем, что у моих зависимостей сменятся зависимости, или иметь ништяки уже сегодня?
Ну и так-то конечный код всё равно придётся перекомпилировать, если речь про кресты etc.
Культ карго какой-то.
> Проводя аналогии
- не надо, пожалуйста, проводить аналогии, потому что обычно, как и в этом случае, они хуёвы и абсолютно неуместны. Здоровое питание это такая же маркетинговая хуета, как и оопэшные мантры про повсеместную инкапсуляцию.
> все члены любых классов должны быть публичными
- да, потому что инкапсуляция должна быть на уровне модулей, а не типов, но это отдельный разговор.
> Нет.
- хватит троллировать. Ладно бы ты был каким-то рандомным неосилятором, а серьёзному кабальеро писать такую ересь должно быть стыдно.
Desktop # 0 ⇈
- ну хотя тут я немного напиздел для случаев динамической линковки.
gost # 0 ⇈
Поведение.
> ну и хер с ним. Мне сидеть дрожать 10 лет над тем, что у моих зависимостей сменятся зависимости, или иметь ништяки уже сегодня?
То есть ты за написание неподдерживаемого говнокода, главное — шоб побыстрее? Ну ок, предлагаю тебе переехать на «PHP» и писать перед каждым методом собачку.
> Ну и так-то конечный код всё равно придётся перекомпилировать, если речь про кресты etc.
Зачем? Зачем? В случае крестов придумали «pimpl».
> не надо, пожалуйста, проводить аналогии, потому что обычно, как и в этом случае, они хуёвы и абсолютно неуместны
Нет, это абсолютно точная аналогия.
> Здоровое питание это такая же маркетинговая хуета
Что, прости?! То есть все вот эти вот биологи с диетологами, которые занимаются темой здорового питания — маркетинговая хуета? И рекомендации ВОЗ — тоже? И даже, например, https://thl.fi/documents/189940/1496849/north_karelia_project.pdf/bb7ba7aa-1dc2-4319-90b9-d2c3ddc10d5e?
> да
А, ну понятно. Тогда тебе точно стоит перейти на «PHP».
> хватит троллировать
По-моему, троллирую тут не я, а человек, называющий инкапсуляцию культом карго.
Desktop # 0 ⇈
Да, диетологи это по большей части хуета (но не все, разумеется). ВОЗ шаражкина контора про отмывание бабла в глобальных масштабах. Инкапсуляция без повода это культ карго. PHP - говно, сам на него переходи 🙂
> А, ну понятно.
- нет, не понятно, потому что комментарии лучше читать целиком. На этом откланиваюсь, потому что разговор потерял последние остатки конструктива.
gost # 0 ⇈
Да.
> оно и есть реализация
Нет. Наблюдаемое поведение зависит от реализации, но не является ею. Точно так же, как результат выполнения функции зависит от её реализации, но не является ею.
> Да, диетологи это по большей части хуета (но не все, разумеется). ВОЗ шаражкина контора про отмывание бабла в глобальных масштабах.
Ну то есть ты считаешь, что рацион человека никак не сказывается на его, человека, здоровье?
> Инкапсуляция без повода это культ карго.
Не бывает «повода» для инкапсуляции. Бывают детали реализации, их надо скрывать — всё. Детали реализации, просачивающиеся в публичный интерфейс — априори говно, такого надо избегать.
Ну да, разумеется, в нашем неидеальном мире не всегда получается делать всё так, как надо. Однако это совсем не означает, что к этому не надо стремиться. Если есть выбор между говном и не говном — нужно выбирать не говно. Нет выбора — увы, придётся писать говно. Только говно от этого не станет нормой.
Desktop # 0 ⇈
1024-- # 0 ⇈
Допустим, все наши познания - предрассудки. Но тогда нужен хотя бы хороший пример того, как написали успешную программу без инкапсуляции, которая пережила все правки, и вообще поддерживается без проблем.
Я (говнокодер-с) только недавно правил питушню, которая была более-менее инкапсулирована, но всё равно вылезла в 3 дополнительных места. Только попердолился больше с кодом, никаких плюсов от недостатка инкапсуляции не получил.
1024-- # 0 ⇈
> Ну то есть ты считаешь, что рацион человека никак не сказывается на его, человека, здоровье?
Кстати, может быть два варианта сразу.
1. Бабло массово отмывается на питушне, которая на 0.0001% полезнее обычного питухания.
2. Если кто-то жрёт радий или регулярно пьёт колу, умирает от неправильного питания.
Desktop # 0 ⇈
- я тебе так отвечу: Стив Джобс был лучший диетолог ЕВПОЧЯ
gost # 0 ⇈
Desktop # 0 ⇈
Но вообще это который всем рассказал, какой телефон им нужен и как правильно его держать.
gost # 0 ⇈
— ссылку на подробное описание этого проекта я кидал выше.
Но в общем-то да, никто не может сказать тебе, какое питание тебе нужно. Зато вполне успешно могут сказать, что если (условный) ты будешь регулярно кушать жареное мясо на ночь, то в итоге получишь определённые… осложнения.
KOPOHABuPYC # 0 ⇈
1024-- # 0 ⇈
f(x) = 2*x
f(x) = x+x
f(2) == 4 - это поведение? Если да, то поведение одно, а реализации две, поведение отходит к интерфейсу, реализация забивается в угол.
Desktop # 0 ⇈
- это вореции.
Поведение у двух функций разное, разумеется. Иначе тебе придётся доказывать, что сложение и умножение это одно и то же.
Desktop # 0 ⇈
gost # 0 ⇈
В идеале, надо делать так, чтобы было правильно. В реальности — правильно настолько, чтобы уложиться в сроки.
Инкапсуляцию, SOLID и вот эти вот все «баззворды» придумали не просто так. Их проектировали умные люди специально для того, чтобы менее умные люди (или просто те, кому лень тратить время на переизобретение одного и того же) могли писать корректный, расширяемый и поддерживаемый код. Увы, но попытки забить на всё и говнокодить как придётся, «шоб работало», приводят только к созданию неподдерживаемого говнокода.
Desktop # 0 ⇈
1024-- # 0 ⇈
Другое дело - конкретная реализация в языке, где держат обратную совместимость, вставляют фичи средним арифметическим разумом комитета.
gost # 0 ⇈
И не надо во всём обвинять бедного Госта. Инкапсуляцию придумали совсем другие люди — я тогда ещё не родился.
Desktop # 0 ⇈
А остальной снобизм свой оставь пожалуйста для учеников на уроке информатики или первокурсников, которым ты возможно втираешь эту дичь.
gost # 0 ⇈
По-моему, это достаточно очевидная цепочка.
Ты правда считаешь, что перечисленные мной god-object'ы и магические константы — это ОК, тесты писать не нужно, а кто утверждает обратное — тот сноб?
Desktop # 0 ⇈
И потом ты собираешься это поддерживать, правда?
> Ты правда считаешь, что перечисленные мной god-object'ы и магические константы — это ОК, тесты писать не нужно, а кто утверждает обратное — тот сноб?
- нет, я так не считаю. God object это плохо, магические константы это тоже плохо, тесты писать конечно нужно, но тут уж как получается. Объясни только, пожалуйста, какое отношение это имеет к инкапсуляции? Она от констант и богообъектов вроде никак не спасает.
gost # 0 ⇈
Их не надо «пробрасывать». Их надо обрабатывать согласно логике моего кода. Потому что если в моём методе появилось исключение, то это значит, что какая-то часть моего метода работает неправильно, и сообщить клиенту нужно именно об этом — соответствующим исключением, со всеми нужными метаданными.
> А что, если у тебя глубина дерева зависимостей больше единицы? Ты построишь целый фреймворк, который будет обёртывать исключения?
Нет, я буду обрабатывать исключительные ситуации в моём коде. В этом и состоит сила инкапсуляции: мне совершенно безразлично, какая там у используемой мной библиотеки глубина зависимостей. Я обращаюсь к библиотеке за каким-то результатом — и абсолютно не важно, как она его считает и какие либы вызывает. С исключительными ситуациями должна быть та же картина: я обращаюсь к библиотеке и ожидаю, что именно она мне скажет, что у неё произошла ошибка. А произошедшую ошибку я обработаю и выдам своему клиенту уже свою ошибку, которая будет описывать исключительную ситуацию в моём коде.
Да, это идеальная картина. В реальности же авторы либ* зачастую нарушают инкапсуляцию, в результате чего их клиентам приходится городить хаки и костыли, пихая в код совершенно ненужную для решения задачи информацию.
*И я тоже не безгрешен, разумеется, и тоже пишу говнокод. Увы, идеала не бывает — но это не значит, что к нему не надо стремиться.
> Объясни только, пожалуйста, какое отношение это имеет к инкапсуляции?
God-object'ы, магические константы, нарушения инкапсуляции — это сущности одного порядка, антипаттерны.
Desktop # 0 ⇈
- почему это неправильно работает часть твоего метода? Эксепшн-то кинул не он. Ну, то есть, наверное, в условном идеальном ФП без побочек виноват будет твой метод, но обычно стрелять может откуда угодно и кто угодно.
Я правильно понимаю, что ты рассматриваешь любую исключительную ситуацию как исключительную ситуацию в твоём коде? Ну, это тоже подход, наверное.
> мне совершенно безразлично, какая там у используемой мной библиотеки глубина зависимостей.
- вопрос был скорее про случай, когда ты сам и есть автор этих зависимостей. То есть, когда из цепочки A <- B <- C <- D ты автор A, B и C.
gost # 0 ⇈
Потому что если мой метод получил исключение и не может продолжать нормальную работу, то это значит, что он оказался в исключительной ситуации и должен сообщить о ней клиенту. К ФП и чистоте такой подход малость отношение имеет: его практиковали ещё наши деды, которые в «C» код возврата проверяли.
> вопрос был скорее про случай, когда ты сам и есть автор этих зависимостей. То есть, когда из цепочки A <- B <- C <- D ты автор A, B и C.
Тут, в принципе, не особо важно, кто автор этих библиотек. Если я соблюдаю принцип DRY, то каждая библиотека из этой цепочке делает разные вещи. Соответственно, и исключения у них тоже будут разными. С другой стороны, если библиотеки A, B и С — это части единого целого, какой-то более общей библиотеки, и их использование по отдельности не предполагается, то, думаю, вполне разумно будет ввести для них какой-либо общий набор исключений. Впрочем, такое решение само по себе пованивает, так что it depends.
Desktop # 0 ⇈
- тогда всё же прошу пояснить мне по поводу friend class и пистона, а то вот непонятно, как умные дядьки и так обосрались.
gost # 0 ⇈
Desktop # 0 ⇈
- так если она произошла не у неё?
gost # 0 ⇈
Desktop # 0 ⇈
gost # 0 ⇈
Desktop # 0 ⇈
Один из важнейших принципов, который приходит с опытом: не делать больше работы, чем требуется.
Если тебе сейчас не нужен 100% loose coupling, то и не нужно сидеть и задрачивать его, у бизнеса есть требования, да и технический долг растёт не только в этом месте.
gost # 0 ⇈
YAGNI — хороший принцип, и тоже придуман умными людьми. А вот применение этого принципа на практике, увы, хромает, поскольку точного определения «лишней функциональности» нет и вряд ли появится. В результате, при чрезмерно усердном его применении мы можем придти к отказу от, например, форматирования кода или грамотного именования переменных — ведь это же лишняя работа, программа прекрасно работает, даже если в ней названия всех переменных состоят из одной буквы!
Сравни, например, вот эти два исходника (оба всплывали на ГК, кстати): https://github.com/vk-com/kphp-kdb/blob/master/bayes/bayes-data.c и https://github.com/openbsd/src/blob/master/sys/netinet/ipsec_input.c. Как думаешь, который из них был написан людьми, не считавшими нужным стараться делать правильно, как пишут в умных книжках? И в который из них будет легче вносить изменения, когда понадобится рисовать не синию линию в виде кота, а оранжевый овал в виде кролика?
Desktop # 0 ⇈
Если кодом пользуешься только ты, то можешь его и не форматировать и переменные называть huiPizda. И что, мало такого кода? Сам же знаешь, что есть такое понятие, как write-and-throw скрипты.
> Сравни, например, вот эти два исходника
- второй выглядит попричёсаннее, но я не настолько хорошо понимаю здоровые портянки на си, а потому на вопрос, какой из исходников я бы раскурил быстрее, ответить не могу.
gost # 0 ⇈
Да, разумеется, код, который кроме тебя никто не увидит, можно писать вообще как угодно, и сам я тоже такое делаю. Главное в этом — чтобы такой код внезапно не начал на постоянной основе решать задачи бизнеса.
Да, причёсан, оформлен, декомпозирован и снабжён подробными комментариями (хотя казалось бы — вот где абсолютно бессмысленная работа, никак не помогающая задачам бизнеса!). И благодаря этому даже человек, не знакомый с портянками, сможет достаточно быстро понять, о чём там идёт речь (конечно, если ему это будет нужно, я ни к чему не призываю :-). А вот первый код, который писался олимпиадниками в их фирменном говностиле, понять и, главное, простить изменить смогут только его авторы (и то только в первые пару недель/месяцев). И тому несчастному, которого посадят разгребать эти конюшни, останется только дунуть, плюнуть и переписать всё с нуля. И это печально.
1024-- # 0 ⇈
Интересные вопли, но лабу не приму. Приходите на пересдачу.
Вот реально вся эта питушня про маркетинговое здоровое питание инкапсуляцией и питушню уровня "работает - значит сделано" напоминает бугурт школьника, которого пытаются обучить чему-то, а он думает, что печальный многолетний опыт и просьбы не кормить орланов с рук, чтобы предотвратить новые случаи - лишь брюзжание стариков.
Desktop # 0 ⇈
1024-- # 0 ⇈
gost # 0 ⇈
1024-- # 0 ⇈
Desktop # 0 ⇈
1024-- # 0 ⇈
Я просто трачу больше времени на лишнее обсасывание своего кода, когда надо что-то изменить. Если там недостаток инкапсуляции, код разлагается и превращается в растекающуюся кашицу. Потом её нужно долго соскребать в баночки и тратить на это время вместо того, чтобы сделать что-то полезное.
KOPOHABuPYC # 0 ⇈
Desktop # 0 ⇈
gost # 0 ⇈
Desktop # 0 ⇈
Как это потом оформляется на performance review?
Desktop # 0 ⇈
- сепульки и вореции.
1024-- # 0 ⇈
Функции, процедуры, методы, операторы - это операции над своими аргументами. В ООП операции и первые аргументы слили вместе, сделав набор операций интерфейсом значений типа первых аргументов.
Desktop # 0 ⇈
? 🙂
gost # 0 ⇈
Или, в идеале,
Или вообще как в «Go»:
Desktop # 0 ⇈
- и как ты метаинформацию об ошибке будешь возвращать, если она тебе нужна?
gost # 0 ⇈
Можно, реальный пример я привёл перед примером с «Go». Да, синтаксис отличается, но суть — одна и та же.
> - и как ты метаинформацию об ошибке будешь возвращать, если она тебе нужна?
Как деды ещё до нашего рождения возвращали: http://man7.org/linux/man-pages/man3/errno.3.html. Да, это «подход C».
Desktop # 0 ⇈
> Как деды ещё до нашего рождения возвращали
- а где здесь метаинформация?
Вот есть у тебя функция
И есть , которая в цикле обрабатывает пачку value при помощи innerFunction и которая должна, когда innerFunction возвращает что-то не то, вернуть код возврата с метаинформацией про объект, на котором всё сломалось (представим, что это, например, имя файла). И куда мне эту метаинформацию записать?
gost # 0 ⇈
Мелкие детали. Разве что с компайл-тайм проверками — да, беда. Но, повторюсь, сама суть подхода — явный возврат ошибки — абсолютно одинакова.
> И куда мне эту метаинформацию записать?
Куда хочешь. Можешь в отдельный выходной параметр, можешь вообще в какую-нибудь глобальную переменную.
EINVAL хватит всем.
Desktop # 0 ⇈
- https://govnokod.ru/26533#comment536727
Профессор, я смущён. Зачем вы проваливаете тест Тьюринга?))) Ладно, мир дружба жвачка респиратор.
gost # 0 ⇈
А здесь int — это не возвращаемое значение функции, а номер ошибки? Тогда да, всё правильно.
Rooster # 0 ⇈
admin # 0 ⇈
bormand # 0 ⇈
guest # 0 ⇈
gost # 0 ⇈
MAKAKA # 0 ⇈
https://docs.microsoft.com/en-us/cpp/c-runtime-library/errno-constants?view=vs-2019
найди тут слово thread
gost # 0 ⇈
Де-факто, кстати, на винде оно (разумеется) thread-local, а вот де-юре им быть не обязано.
bormand # 0 ⇈
И это жопа. Из-за этого rand() превратился в неюзабельную хуйню - где-то его стейт тред-локал, а где-то - тормозная глобалка под лочкой.
MAPTOBCKuu_nemyx # 0 ⇈
1024-- # 0 ⇈
BETEPOK # 0 ⇈
gost # 0 ⇈
kak # 0 ⇈
guest # 0
gost # 0 ⇈
KOPOHABuPYC # 0 ⇈