- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
public class Main {
public static void uh() {
try {
} catch (Exception e) {
throw e;
}
}
// <no errors>
public static void oh() {
try {
throw new RuntimeException();
} catch (Exception e) {
throw e;
}
}
// <no errors>
public static void snap() {
try {
throw new Exception();
} catch (Exception e) {
throw e;
}
}
// /tmp/Main.java:8: error: unreported exception Exception; must be caught or declared to be thrown
// throw e;
// ^
// 1 error
}
Где-то посередке между хорошим inference и остутствием интуитивности
Fike 20.03.2020 19:53 # +1
хоть бы раз без ошибок пост оформил, пидор ёбаный
Janycz 20.03.2020 23:26 # 0
3.14159265 20.03.2020 19:54 # 0
Fike 20.03.2020 22:12 # 0
3.14159265 20.03.2020 23:12 # 0
А дальше уже этот метод (без throws) используется по коду.
Janycz 20.03.2020 20:28 # 0
Я кста взглянув на код, подумал что это C#.
Вот что в нашем C# хорошо - так это то, что нам не нада писать implements, extends, throws.
Хотя я когда выполнял лабораторки в унике по Java, в throws писал throws Throwable() - а че, мне ваша ява нафиг не сдалась, но нада тупа сдать.
guest8 20.03.2020 20:33 # −999
Janycz 20.03.2020 20:36 # 0
Fike 20.03.2020 22:20 # 0
Самое смешное, что делать внятный хендлинг ошибок в каждом методе конечно никто не будет. Поэтому гоферы без какой-либо застенчивости возвращают ошибку на уровень выше, типа там выше есть конечный юзер, пусть сам на своем сервере ебаном разбирается чойта мы забыли файл перед обновлением залочить.
https://awalterschulze.github.io/blog/monads-for-goprogrammers/bartiferr.png
3.14159265 20.03.2020 23:14 # +1
Go старые сишники пилили.
И всё бы ничего, да только из-за gc вся его сишность насмарку.
Janycz 20.03.2020 23:30 # 0
gostinho 20.03.2020 23:34 # 0
Janycz 20.03.2020 23:36 # 0
guest8 21.03.2020 00:24 # −999
Fike 21.03.2020 01:34 # 0
да, но и еще многие языки, и даже шарп тебе без проблем соберет единый бинарник (джава сосатб), но об этом еженощно не заливают одни макаки в уши другим
> Так же слышал, что там нет обобщенного программирования. Это правда? Как же они делают контейнеры объектов?
Переписывая один и тот же код под разные типы. И это норма.
kak 21.03.2020 01:56 # 0
Fike 21.03.2020 02:30 # 0
ну привет
https://docs.microsoft.com/en-us/dotnet/core/deploying/deploy-with-cli#self-contained-deployment
https://github.com/dotnet/core/blob/master/Documentation/prereqs.md
тут вообще недавно постили статью, где чувак шарповую прогу ужал до восьмикилобайтного экзешника
guest8 21.03.2020 02:47 # −999
kak 21.03.2020 14:54 # 0
Впрочем, мокрософт заботливо доставит этот рантайм через automatic updates и даже перезагрузит пека для тебя.
> all required .NET Core files to run your app but it doesn't include the native dependencies of .NET Core. These dependencies must be present on the system before the app runs.
kak 21.03.2020 14:59 # 0
Fike 21.03.2020 15:19 # 0
kak 21.03.2020 18:36 # 0
Такой-то перевод стрелок. Как будто .NOT сможет работать со строкой "Hello world!" без кучи предустановленного барахла, но которое к счастью поставляется из коробки вместе с windows analytics.
guest8 21.03.2020 02:47 # −999
Fike 21.03.2020 04:32 # 0
guest8 21.03.2020 04:34 # −999
Fike 21.03.2020 04:39 # 0
kak 21.03.2020 15:01 # 0
3.14159265 21.03.2020 16:33 # 0
Обычно занимающий сотни мегабайт.
Fike 20.03.2020 22:16 # 0
Извините, накипело.
Janycz 20.03.2020 22:28 # 0
x?.Some() ?? None
guest8 20.03.2020 22:43 # −999
Fike 20.03.2020 22:52 # 0
Janycz 20.03.2020 22:59 # 0
Fike 20.03.2020 23:19 # 0
guest8 21.03.2020 00:12 # −999
Fike 21.03.2020 01:35 # 0
А когда начинают совать всё подряд, их становится до пизды
guest8 21.03.2020 02:48 # −999
bormand 21.03.2020 15:52 # 0
А что в них плохого? Это же обычные свободные функции с псевдо-ООП'шным сахарком для их вызова...
guest8 20.03.2020 22:33 # −999
3.14159265 20.03.2020 23:15 # +1
Подтверждаю.
Причём бойлерплейтное.
Монада есть, а трансформеры не завезли.
guest8 21.03.2020 00:15 # −999
Desktop 21.03.2020 16:13 # 0
gost 21.03.2020 16:50 # +1
Desktop 21.03.2020 20:51 # 0
gost 21.03.2020 23:59 # +1
Разумеется, в некоторых случаях «Optional» может быть полезным: например, какому-нибудь методу поиска элемента в коллекции действительно удобнее возвращать «Optional». Но попытки использовать его в более сложных случаях (что-нибудь вроде «db.getUser(username, password) -> Optional<User>») приводят именно к тому, о чём я и сказал: к невразумительным ошибкам и большим сложностям в рефакторинге.
3.14159265 22.03.2020 00:01 # 0
Питушарская, тупая обёртка для анскилябр.
>например, какому-нибудь методу поиска элемента в коллекции действительно удобнее возвращать «Optional»
indexOf до сих пор возвращает -1. И никто не жалуется. И не городит вместо int сложных типов c позицией и флагом ошибки.
Тем более что абстракция «Optional» пока что не zero-cost.
gost 22.03.2020 00:23 # 0
Error-prone питушня.
Optional с компайл-тайп проверками гораздо надёжнее. Что-то вроде такого псевдокода:
Разумеется, это только набросок, чтобы дать общее представление о функционале.
3.14159265 22.03.2020 00:36 # 0
Не-не-не-не. Вы что??? If это параша, для императивных старпёров.
Уже лет 5 как западло писать if, for, while.
Сейчас модно писать функциональненько
https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html#ifPresent-java.util.function.Consumer-
>Optional с компайл-тайп проверками гораздо надёжнее.
Возможно. Только лямбды и обёртки снижают скорость кода. А пользы особой не дают.
gost 22.03.2020 00:45 # 0
Лямбды — возможно. Обёртки в крестовом зерокост стиле — настолько несущественно и в настолько экзотических случаях, что этим можно пренебречь, поскольку выбор небезопасных интов только из-за скорости в 99.95% случаях будет классической и вредной premature optimization.
> А пользы особой не дают.
Они дают гарантию того, что полученный -1 не будет где-нибудь ниже по коду засунут в индекс. В анскильной питушне с bounds-checking это будет неожиданное исключение, а вот в крестосях — UB, что гораздо печальнее.
3.14159265 22.03.2020 00:53 # 0
Ну я же за Царcкий режим топлю.
В общем я считаю Optional частным видом списка из 0 или 1 элемента.
А сам список можно представить в виде массива.
>Они дают гарантию того, что полученный -1 не будет где-нибудь ниже по коду засунут в индекс.
Ну не проверять код возврата indexOf, это уж совсем для анскильных лохов.
gost 22.03.2020 01:03 # 0
Он и есть.
> Ну не проверять код возврата indexOf, это уж совсем для анскильных лохов.
Любые программы по определению пишутся невнимательными анскильными лохами (степень анскильности, конечно, варьируется). Одна из главных задач языка программирования высокого уровня — снизить количество ошибок, вызванных анскильностью и невнимательностью. В этом смысле Optional с жёсткими компайл-тайм проверками гораздо лучше простого инта.
3.14159265 22.03.2020 01:11 # 0
>Они дают гарантию того, что полученный -1 не будет где-нибудь ниже по коду засунут в индекс.
Это редкая ошибка.
А вот гораздо более частая ошибка, когда к полученному в indexOf значению (предварительно прочеканному на -1) приплюсовывают что-то эдакое и снова лезут с ним в массив/строку.
И её хер обойдёшь возвращая Optionalы.
>Одна из главных задач языка программирования высокого уровня — снизить количество ошибок, вызванных анскильностью и невнимательностью.
И поэтому вообще нужны типы, которые я описывал в предыдущих дискуссиях. А именно: целые с диапазонами.
indexOf по строке должен возвращать
строго тип int[0,length-searchString.length-1].
А substrы должны принимать строго тип int[0,length-1]
И компилятор при инкременте int[0,length-1] должен возвращать тип int[1,length]. А при добавлении 42 тип будет int[42,length-41]
Соответственно при желании полезть в строку/массив с таким типом программа просто не соберётся.
gost 22.03.2020 01:21 # 0
Да. Нужен полностью компайл-тайм Optional, а не всякая анскиллушня.
> И её хер обойдёшь возвращая Optionalы.
Очень даже обойдёшь. Нет индексов — нет ошибок с приплюсовыванием.
> indexOf по строке должен возвращать строго тип int[0,length-searchString.length-1].
А как быть со строками, которые вводит пользователь?
3.14159265 22.03.2020 01:28 # 0
А компилятор может считать длину строки за некий N. И типы делать [0,N-1]
var i=s.indexOf("koko") //[0,N-1-4]
//к i можно прибавить число не больше 4, чтобы не вылезти за пределы.
Как только вылазим за тип — выдавать ошибку.
>Да. Нужен полностью компайл-тайм Optional, а не всякая анскиллушня.
Да. См. ниже. Паттерн-матчинг.
gost 22.03.2020 01:41 # 0
> Да. См. ниже. Паттерн-матчинг.
Для самых простых вещей, вроде collection.find(), это оверинжиниринг.
3.14159265 22.03.2020 01:48 # 0
Значит нужно допиливать автовывод типов.
>или из глубины вызовов
С индексной арифметикой, да ещё разбросанной по глубине вызовов можно страшно налажать. Уж лучше иметь ошибку компиляции, чем хрупкий код-пиздец.
В одном месте поменяли, в другом забыли. Another buffer overflow CVE.
>или из прошедшего проверку пользовательского ввода
Проверку он пройдёт только конверсией в нужный тип.
В принципе по объёму кода это одно и то же.
> При этом правила, когда компилятор может автоматически проверить индекс, а когда не может, будут настолько сложны и запутаны
Ничего сложного там нет. Просто buffer overflow говно больше никогда не скомпилится и не попадёт в продакшн.
>просто проверять индексы везде, что перфоманса не добавит.
В случае анскильного отброса с руками из жопы — безусловно.
Положительным моментом будет опять-таки то что buffer overflow говно больше никогда не скомпилится и не попадёт в продакшн.
gost 22.03.2020 01:58 # 0
Полностью это сделать невозможно.
> buffer overflow
Про эти страшные слова забыли в любых языках с проверками границ.
> Проверку он пройдёт только конверсией в нужный тип.
Как именно? Как нужно будет переписать, например, такой код:
?
> Ничего сложного там нет.
Крестокомпилятор до сих пор и компайл-тайм деление на ноль отловить не всегда может, а ты замахиваешься на настолько грандиозные вещи.
> В случае анскильного отброса с руками из жопы — безусловно.
Неанскильный неотброс с руками из плеч тоже ничего не сможет сделать в случае, когда компилятор не сможет правильно доказать корректность индекса.
> buffer overflow говно больше никогда не скомпилится и не попадёт в продакшн
Для этого достаточно просто избавиться от индексов, как от тяжёлого наследия ассемблера.
3.14159265 22.03.2020 02:51 # 0
>print(string[3]); //здесь будет runtime error
Во-первых этот код — опасное говно. И хорошо, что он не скомпилится.
>когда компилятор не сможет правильно доказать корректность индекса
Не надо писать уебанский код. Я не могу представить каких-то мудрённых задач, чтобы их нельзя было решить в этой парадигме
>Про эти страшные слова забыли в любых языках с проверками границ
И расплатились 2-4 кратным снижением пирфоманса.
gost 22.03.2020 02:59 # 0
Хорошо, давай так:
Это достаточно реальный пример. Как его переписать так, чтобы
>>> buffer overflow говно больше никогда не скомпилится и не попадёт в продакшн
?
> И расплатились 2-4 кратным снижением пирфоманса.
Даже в теории, даже для самого плохого случая вида «for i in 0..len(arr): arr[i] += 1» никаких x2 и в помине не будет.
3.14159265 22.03.2020 03:18 # 0
Где-то на ГК неоднократно публиковались эти цифры.
Там в сишке включали какой-то режим bounds checking и емнип пирфоманс садился в 2-4 раза.
Я сам охуел когда увидел.
>def capitalize(string):
В этом коде в любом случае придётся написать if string.len>0
Теперь наш capitalize не принимает строки нулевой длины.
И проблема перезжает в вызов:
gost 22.03.2020 03:32 # 0
Очевидно, это был простой наброс на хреновый bounds checking. С нормальным чекером и нормальным компилятором, например, такого точно не будет.
Реальный пример: https://gcc.godbolt.org/z/DdP-Qj. «Gcc» достаточно умён, чтобы доказать нинужность лишних проверок границ. В данных случаях получился идеальный зерокост.
> typedef NotEmpty
Не нужно, это лишнее усложнение примеров. Я хочу понять, как программист должен будет говорить компилятору, что данный индекс проверен и точно не вылезет за границы рантайм-массива/строки.
> //здесь оно отвалится
Нужно сделать так, чтобы не отвалилось.
3.14159265 22.03.2020 03:35 # 0
Это никак невозможно, если придёт пустая строка.
> string[0] = to_upper(string[0])
Либо отвалится здесь, с out of bounds.
>Я хочу понять, как программист должен будет говорить компилятору, что данный индекс проверен и точно не вылезет за границы рантайм-массива/строки.
Явно сконвертировать этот индекс в тип [0..N].
Если конверсия будет неудачной — произойдёт runtime ошибка.
Но т.к. программист уверен в годности индекса, в теории ошибок быть не должно.
gost 22.03.2020 03:40 # 0
Я написал код с ошибкой (выхода за границы массива), которую предложил исправить.
>>> Я хочу понять, как программист должен будет говорить компилятору, что данный индекс проверен и точно не вылезет за границы рантайм-массива/строки.
Просто переведи на «систему типов с диапазонами»:
3.14159265 22.03.2020 03:42 # 0
В случае неявных преобразований типов вторую строчку можно убрать и мы автоматом получим язык с runtime bounds checking.
gost 22.03.2020 03:50 # 0
Стоп, стоп, стоп. Это статический или динамический тип?
Ну и в любом случае, для правильного перевода не хватает ручной проверки на пустоту строки, поскольку приведённый мной в последнем комментарии отрывок на ней не упадёт.
3.14159265 22.03.2020 03:56 # 0
Такое можно накрестячить даже на современных шаблонах.
>Ну и в любом случае, для правильного перевода не хватает ручной проверки на пустоту строки,
Ага. Ниже пример.
gost 22.03.2020 04:12 # 0
Тем не менее, я всё ещё не вижу никаких реальных преимуществ такой системы даже по сравнению с обычным неявным bounds checking. Абсолютное большинство индексаций в реальном коде происходит на рантайм-массивах либо же с рантайм-индексами. Доступ по компайл-тайм-вычислимому индексу к компайл-тайм-вычислимому массиву, который такая система может проверить в компайл-тайме, крайне редок.
Всё остальное переходит в рантайм-проверки («cast()»).
Более того, как я показывал выше (https://gcc.godbolt.org/z/DdP-Qj), мощные компиляторы вполне способны проводить индексные доказательства и выкидывать лишние проверки даже без диапазонных (хотя, конечно, в данном случае правильнее будет «предикатных») типов.
3.14159265 22.03.2020 04:22 # 0
Нет. cast нужен только для абсолютных чисел (42) по рандомным строкам полученным извне. Поскольку юзер всегда может ввести строку длиной меньше 42.
В cast не переходят
Srting x="kokoko";
x[3];
В cast не переходят штуки с indexOf/substring, завязанные на строку.
>Абсолютное большинство индексаций в реальном коде происходит на рантайм-массивах либо же с рантайм-индексами.
Поправочка. На рантайм-массивах либо же вместе с рантайм-индексами.
А тип рантайм-индекса, у нас всегда завязан на рантайм-размер рантайм-массива.
Обычная задача парсинга: найти начало подстроки, найти конец подстроки. Вырезать нужное.
indexOfы будут возвращать тип [O..N] которым можно будет индексировать строку без всяких кастов.
> мощные компиляторы вполне способны проводить индексные доказательства и выкидывать лишние проверки
Даже ява с 7ой версии научилась.
Но для примера сложнее тестового, компилер без подсказок в виде предлагаемой диапазонной типизации может обосраться с их выпиливанием.
gost 22.03.2020 12:31 # 0
А также для индексов, полученных из рантайма.
> Поправочка.
Неверная поправка. Реальный пример:
И совершенно неважно, известно ли содержимое pages на этапе компиляции. Здесь в любом случае потребуются рантайм-проверки, либо через неявную проверку границ, либо через явный if.
> Обычная задача парсинга: найти начало подстроки, найти конец подстроки. Вырезать нужное.
> indexOfы будут возвращать тип [O..N] которым можно будет индексировать строку без всяких кастов.
И это прекрасно доказывается компилятором безо всяких бойлерплейтных [0..N] (ну, в теории: на практике, поскольку в «C++» строк нет, компилятор объёбывается).
Факт в том, что вот эти вот «[0..N]» в контексте проверок индексов не несут никакой полезной информации. Компилятор сам прекрасно знает, что если переменная используется для индексации, то её значение должно лежать в пределах [0..N). Ничего нового программист компилятору не говорит.
Более того, и не может сказать, потому что программист не может достоверно знать, что введёт пользователь. Ему, программисту, всё равно придётся явно писать «if idx < len(arr) ...» — и из этого компилятор прекрасно выводит все предикаты.
3.14159265 22.03.2020 20:28 # 0
>Здесь в любом случае потребуются рантайм-проверки, либо через неявную проверку границ, либо через явный if.
Да. И компилятор нам об этом сообщит что их НУЖНО написать.
Таким образом, не дав собрать плохой код.
>И это прекрасно доказывается компилятором безо всяких бойлерплейтных [0..N] (ну, в теории: на практике, поскольку в «C++» строк нет, компилятор объёбывается).
Ок. Раз всё так прекрасно, это всё говно и бойлерплейт, непонятно почему по-прежнему десятки-сотни CVE по переполнению буфера?
gost 22.03.2020 20:46 # 0
Компилятор об этом может сообщить и без [0..N]-бойлерплейта. Он и так это знает.
> непонятно почему по-прежнему десятки-сотни CVE по переполнению буфера?
Потому что «C».
В «Java», «Python» и прочих анскильных языках переполнение буфера приведёт только к падению приложения — в самом худшем случае.
А почему конпелятор знает об этом, но не предупреждает? Видимо, разработчики посчитали, что игра не стоит свеч, а излишнее количество ворнингов сделает только хуже.
Перейдём к реальным примерам. Возьмём произвольную достаточно объёмную опенсорсную прогу и проверим: https://github.com/microsoft/vcpkg. Я прошёлся по её коду грепом findstr'ом и обнаружил занимательную вещь: индексирования массивов/векторов там практически нет, в среднем на один файл встречается по паре-тройке примитивных индексирований (вида «return &data[0]»). [To be continued…]
3.14159265 22.03.2020 21:03 # 0
Ничего он не знает.
Если из глубины вызовов пришёл обычный int, компилятор не может точно сказать нужна проверка или нет.
Как уже сказано ранее:
>>>Крестокомпилятор до сих пор и компайл-тайм деление на ноль отловить не всегда может, а ты замахиваешься на настолько грандиозные вещи.
>В «Java», «Python» и прочих анскильных языках переполнение буфера приведёт только к падению приложения
Есть две крайности:
1. всовывать runtime-проверки на каждом обращение.
2. не делать никаких проверок в принципе
Того что предлагаю я: сообщать об ошибке и требовать ручной каст в правильный тип, только при условнии невозможности доказательства корректности кода (индексы типа 42 по массивам известным в runtime)
То есть безопасные случаи без проверок будут работать как и раньше. А весь пользовательский ввод придётся валидировать.
gost 22.03.2020 21:18 # 0
А так из глубины вызовов придёт int[0..N] с неопределённым диапазоном, привязанным к какому-то левому массиву.
> сообщать об ошибке и требовать ручной каст в правильный тип, только при условнии невозможности доказательства корректности кода
Я предлагаю абсолютно то же самое. Только без бойлерплейта в виде int[0..N], который никакой новой информации не несёт.
> 1. всовывать runtime-проверки на каждом обращение.
Я уже показал, что, например, «gcc» может доказать, что переменная никогда не выйдет за границы массива, и выкинуть ненужные проверки. Значит, для реализации надёжной индексации достаточно развить его систему доказательств и сделать ворнинг, когда для доказательства недостаточно информации.
gost 22.03.2020 20:47 # 0
Как видно, здесь нет ни одного индексирования, которое компилятор не сможет проверить без дополнительных подсказок программиста.
3.14159265 22.03.2020 21:10 # 0
А они тут и не нужны. Кроме вот этих мест:
Хотя с такой системой типов можно просто писать auto и компилер сам догадается. Цикл for — самое простое, где нужна такая типизация.
Подсказки программиста нужны в случае работы с массивом через функции.
Всякие find, rfind, find_first_of, find_last_of получающие индексы
А за ним substr, принимающие эти индексы.
Как С++ компилятор что-то может доказать в этом случае?
У меня godbolt висит, пока не могу продемонстрировать.
gost 22.03.2020 21:23 # 0
Зачем? Зачем? Такой вид цикла — это самый простой кейс для компилятора. Корректно вывести эти вот [0:7] ([1:7], кстати говоря) сможет даже пхп-обезьяна.
> Цикл for — самое простое, где нужна такая типизация.
Как раз в цикле for она вообще не нужна.
> Всякие find, rfind, find_first_of, find_last_of получающие индексы
А их в любом случае надо проверять в рантайме на std::string::npos. По моим экспериментам, пока что «gcc» не догадывается, что «str.find(...) != npos» эквивалентно «find(...) < str.size()». Но для доказательства конкретно этого факта никакие явные «[0..N]» не нужны.
3.14159265 22.03.2020 21:29 # 0
Мы уже говорили, что это должны делать паттерн-матчинг и продвинутая типизация.
Я о другом твержу.
Если мы передали в substr(int [0:N],int [0:N]) рандомный int — программа выдаёт ворнинг/ошибку
Если мы передали результат find, rfind, find_first_of, find_last_of, программа компилируется без дополнительных проверок.
>Корректно вывести эти вот [0:7] ([1:7], кстати говоря) сможет даже пхп-обезьяна.
Может пхп-обезьяна и сможет, а gcc, как видим не способен.
И clang тоже
gost 22.03.2020 21:34 # 0
Это в любом случае будут явные рантайм-проверки. Абсолютно в любом — пока в поиске участвуют строки, не известные на момент компиляции.
> Может пхп-обезьяна и сможет, а gcc, как видим не способен.
Значит надо выкинуть «gcc» с «clang» и написать нормальный компилятор, который будет способен. Явное обозначение [1:7] не даст компилятору никакой новой информации.
gost 22.03.2020 21:38 # 0
Как видно, тут внутри у компилятора происходят какие-то диапазонные проверки, очень похожие на то, что ты предлагаешь реализовать явно.
3.14159265 22.03.2020 21:48 # 0
Нет. В этом вся идея. Это герметичная система, для произвольного N.
find вернёт [0,N], а substr примет этот же диапазон [0,N].
Это инвариант для строк произвольной длины.
Потому явные проверки в данном случае НЕ НУЖНЫ.
>Я, кстати, за «std::array»
Я тоже :)
https://govnokod.ru/26515#comment535136
Я же говорю: кресты уже довольно близки к такой типизации. Думаю на шаблонах можно сделать эти диапазоны. Для статических строк уж точно.
gost 22.03.2020 21:49 # 0
3.14159265 22.03.2020 21:52 # 0
Уже говорили выше (https://govnokod.ru/26515#comment535141)
Если не найдено возвращается тип NotFound.
В случае если найдено: тип int[0,N-M].
Где M — длина искомой подстроки.
Это логическое продолжение идеи жёстких компайл-тайм проверок.
gost 22.03.2020 21:54 # 0
3.14159265 22.03.2020 22:00 # 0
Смешиваются 2 разные ситуации:
* ситуация ненайденной подстрокой
* ситуация с некорректно вычисленным индексом, вылазящим за границы
>Принципиально это ничем не отличается от текущей ситуации, когда в результате find может быть либо npos, либо [0, N - M]
Отличается. Т.к. в случае когда подстрока найдена и будет дальнейший substr компилятор не даст нам вылезти за пределы строки.
А разрешит только использовать только легальные индексы с типом вмещающимся в [0, N].
>find может быть либо npos, либо [0, N - M].
Проверка индекса на npos не гарантирует, что мы не прибавим к нему чего-то лишнего и не вылезем за пределы массива.
gost 22.03.2020 22:09 # 0
А зачем нам для этого явная предикатная система типов?
Компилятор и так знает, что find() может вернуть либо npos, либо [0, N - M]. Ему для этого не надо явно что-то указывать.
Компилятор и так знает, проверили ли мы результат find() на npos, или нет. Ему для этого не надо явно что-то указывать.
На основании этих джвух знаний компилятор уже может доказать, что мы помещаем в substr() валидный/невалидный индекс.
> Проверка индекса на npos не гарантирует, что мы не прибавим к нему чего-то лишнего и не вылезем за пределы массива.
А это должен гарантировать компилятор. Он знает, что если мы проверили индекс на npos, то в индексе будет [0, N - M] — потому что ничего другого там быть уже не может. Из этого он может вывести всё то же самое, что он смог бы вывести из явной предикатной системы типов.
3.14159265 22.03.2020 22:12 # 0
Она должна быть как минимум под капотом.
Нам же она нужна для определения своих типов.
Вроде typedef UserName String<[1..32]> означающего что имя пользователя содержит хотя бы один символ, но не более 32х (например у нас в бд поле nchar(32)).
Тогда пример с capitalize не будет требовать никаких доп. проверок.
Т.к. сам тип гарантирует наличие первого символа.
gost 22.03.2020 22:23 # 0
Разумеется, я не говорю, что предикатная система вообще не нужна — это мощный инструмент, позволяющий делать крутые вещи. Моя позиция в том, что она (в явном виде) не требуется конкретно для создания языка, в котором невозможен выход за границу массива. Я вообще против того, чтобы писать что-то, что за меня спокойно может написать компилятор.
> typedef UserName String<[1..32]>
Да, это реальный и нужный пример.
3.14159265 22.03.2020 22:37 # +1
Наоборот, я повторяю что вся концепция должна быть на 90% под капотом (https://govnokod.ru/26502#comment533594).
Согласен что в большинстве случаев эти типы никак не должны себя проявлять, пока не случится ошибка. Большинству людей хватит обычного for (auto x:[0..7]).
>для создания языка, в котором невозможен выход за границу массива
Тогда непонятно как собирать вместе различные модули, связанные интерфейсами и заголовочными файлами.
В сигнатурах apiшек таки придётся их указать.
gost 22.03.2020 22:44 # 0
Да, вот это реальная проблема. В этом случае без специальных сигнатур никак не обойтись.
3.14159265 22.03.2020 22:16 # 0
Проблемы начнутся при линковке модулей.
Когда некая функция описанная в .h файле принимает какой-то массив размера N, и возвращает int.
Без указания явной связи компилятор ничего не сможет сделать.
3.14159265 22.03.2020 22:08 # 0
У меня 9ый gcc, и 9й шланг.
Никаких ворнингов они не выдают.
> очень похожие на то, что ты предлагаешь реализовать явно
То есть тот ворнгинг самый писк прогресса, который gcc начал поддерживать только в trunke. Раньше такого не было.
https://gcc.godbolt.org/z/juLVXg
gost 22.03.2020 22:10 # 0
3.14159265 22.03.2020 22:19 # 0
https://xkcd.com/927
Нужно быть реалистом.
Но хорошо что Аллах услышал мои молитвы, и они наконец-то начали пилить range проверки, пусть даже под капотом.
gost 22.03.2020 22:24 # 0
> и они наконец-то начали пилить range проверки, пусть даже под капотом.
Вот, я тоже целиком и полностью за это.
3.14159265 22.03.2020 21:20 # 0
https://ideone.com/d2i4Ft
> здесь нет ни одного индексирования, которое компилятор не сможет проверить без дополнительных подсказок программиста
Компилирую. Получаю ровно 1 ворнинг, никак не связанный с кривым индексом.
Почему-то даже в самом тривиальном примере (статический массив фиксированного размера и цикл в том же скоупе) компилятор не смог найти неверную индексацию за пределами массива.
Какой анскилл )))
gost 22.03.2020 21:30 # 0
К сожалению, крестовый стандарт наоборот противодействует созданию подобной надёжной системы: с формальной точки зрения, ты написал UB, а потому компилятор имеет право делать абсолютно что угодно, в том числе и молчать как рыба.
gost 22.03.2020 04:22 # +1
3.14159265 22.03.2020 04:26 # 0
gost 22.03.2020 10:57 # 0
BECEHHuu_nemyx 07.04.2020 10:15 # 0
MAuCKuu_nemyx 07.04.2020 10:46 # 0
BECEHHuu_nemyx 07.04.2020 11:03 # 0
Не знаешь, почему тут так тихо?
KOPOHABuPYC 08.04.2020 00:43 # 0
3.14159265 22.03.2020 03:52 # 0
А с ifом наверное будет так:
3.14159265 22.03.2020 04:06 # 0
3.14159265 22.03.2020 02:52 # 0
Проблема в другом.
В современных ЯВУ нет краеугольного камня для этой системы: целых типов с диапазонами.
Остальное дело техники.
Любая вложенность по сути сводится к тому что на уровне каждой функции мы передаём вниз аргументом строку, получаем связанный индекс.
Или передаём связанный индекс и строку.
int[0..N] indexOf(string[0..N] str);
substring(string[0..N] str, int[0..N] from);
Сишники 40 лет, как Моисей, таскают за массивами их размеры и ничего.
В крестах тоже везде торчит размер std:array<int,size_t>.
gost 22.03.2020 03:03 # 0
Потому что такая система проверки индексов прекрасно работает для строк и индексов, известных во время компиляции. Как только в неё попадает рантайм — всё рушится и сводится к обычному коду.
> Любая вложенность по сути сводится к тому
Это всё частные случаи. Проблема останова никуда не девается.
> Сишники 40 лет, как Моисей, таскают за массивами их размеры и ничего.
Ну, не совсем ничего. Благодаря этому мы эти же самые 40 лет имеем максимально опасные уязвимости.
3.14159265 22.03.2020 03:27 # 0
Это да. Однако я имел ввиду проблему синтаксиального оверхеда подобной затеи. Во всех местах придётся указывать диапазоны возвращаемых интов.
>Как только в неё попадает рантайм — всё рушится и сводится к обычному коду.
Ничего не рушится. Тип индекса привязан к типу размера массива. Для произвольных N. Неважно какой длины строка.
Подобное предикативное доказательство проделывают в продвинутых функциональных языках типа. wvxvw очень давно пояснял.
gost 22.03.2020 03:42 # 0
В результате для 99% методов это будет «int[0..N]» с ручными проверками. Зачем? Зачем?
> Тип индекса привязан к типу размера массива.
Мы говорим о статической или динамической типизации? Я так понял, что о статической. Тогда типы что массивов, что индексов, будут равны «*[0..N]», и смысл всей этой затеи ускользает.
Можно всё проделать гораздо проще: заставить компилятор доказывать, что любая индексация корректна. Не может доказать — показывает ошибку/предупреждение. По своей сути это ничем не будет отличаться от системы типов с диапазонами, доказывать надо будет абсолютно то же самое, зато программисту не надо будет плодить плохочитаемый бойлерплейт.
3.14159265 22.03.2020 01:22 # 0
И соответственно ifPresent с ебаными лямбдами нахуй не нужен.
Есть же (ну или скоро будет) в шарпе/яве/крестах паттерн матчинг.
https://openjdk.java.net/jeps/305
Вот возвращать подтипы
А Optional — говнище ебаное.
gost 22.03.2020 01:26 # 0
Это не поможет, если indexOf вернёт индекс последнего элемента. Или ты предлагаешь запретить вообще любой непроверенный доступ к массиву (изменил индекс — изволь делать if idx < arr.len)?
> Вот возвращать подтипы
А это уже то, о чём гуест8 и я писали в самом начале ветке.
3.14159265 22.03.2020 01:32 # 0
Не совсем.
Любой вылезший за тип и недоказанный компилером.
> var i=s.indexOf("koko") //[0,N-1-4]
> //к i можно прибавить число [0,4], чтобы не вылезти за пределы.
Другой пример
var i=arr.indexOf(3) //[0,N-1]
//к i можно безопасно прибавить тип [0,0]. То есть сложить с нулём.
>Это не поможет, если indexOf вернёт индекс последнего элемента
Длина строки N.
indexOf() возвращает последний элемент N-1, это значение находится в диапазоне [0, N-1] — соответственно если индекс не менять, то по нему смело можно обращаться к массиву.
>изменил индекс — изволь делать if idx < arr.len
Не if а скорее явный clamp-каст в тип [0,N-1]
3.14159265 22.03.2020 00:46 # 0
Плюс это расширябельно. Завтра могут быть 2 картинки с одинаковым именем, и все вызовы метода придётся переписывать.
Хипстеры тоже будут довольны:
gost 22.03.2020 00:53 # 0
Вдобавок, в некоторых случаях это нарушает семантику. Метод, по определению возвращающий ноль или один элементов (какой-нибудь «getById»), и при этом в сигнатуре имеющий Iterable, выглядит крайне странно и запутывает читающего.
3.14159265 22.03.2020 00:56 # 0
Ээээ. Ну неправда же.
В жабе их полно. Кост у них такой же как у Optional.
Навскидку:
https://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#singletonList(T)
https://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#singletonList(T)
gost 22.03.2020 00:59 # 0
Дык я не про жабовское анскильное гуано, а про гипотетический зерокост (в крестовом стиле) Optional с жёсткими компайл-тайм проверками (конпелятор выдаёт ошибку, если не может доказать, что на момент доступа к содержимому оно было явно проверено на существование).
3.14159265 22.03.2020 01:00 # 0
Ну в крестовом стиле и гипотетические коллекции могут быть зеро-кост.
Горячо любимый мною std::array довольно близок к этому.
gost 22.03.2020 01:09 # 0
А это и есть обобщённый Optional, и главный* его недостаток — необходимость многость рефакторить при изменении количества возвращаемых элементов — никуда не девается. Даже в случае с List[0,10].
А вот обобщённая коллекция потребует либо кучи, либо дополнительных проверок, что уже не зерокост и вообще тормозная питушня.
gostinho 22.03.2020 00:57 # +1
Перепесал, проверь.
3.14159265 22.03.2020 00:58 # 0
Но я уже сказал выше:
https://govnokod.ru/26515#comment535130
>А сам список можно представить в виде массива.
Впрочем for~each и на массивах работает
3.14159265 22.03.2020 00:05 # 0
Ну блядь верни List, Collection, Iterable наконец. С одним элементом или пустой.
Не хочу, хочу жрать «Optional»
Уже есть все нужные абстракции.
Iterable — тот же ленивый список из Хасцеля. С поддержкой for~each из коробки.
gost 22.03.2020 00:16 # 0
Впрочем, возврат коллекции тут совершенно избыточен и ничем не отличается от Optional: мы в любом случае теряем информацию о том, что пошло не так. Узнать, ввёл ли пользователь неправильный пароль или неправильный логин, не получится. Разумеется, это синтетический пример, и в реальности проверку пароля следует вынести в отдельное место.
3.14159265 22.03.2020 00:20 # 0
Именно! Я о том, что в жабе уже был один тип, покрывавший все эти нужды. Зачем что-то ещё — непонятно.
А жавашкам анскильные обёрточки nullов иногда бывают нужны. Некоторые либы, например guava-кеш не переваривает nullы в качестве значений.
Но с Iterable хотя бы можно унифицировать код, и при необходимости возвращать несколько юзеров не придётся ебать мозги рефакторингом и конверсией с Optional и в глисты и коллекции.
gost 22.03.2020 00:25 # +1
guest8 22.03.2020 23:00 # −999
gost 22.03.2020 23:07 # 0
3.14159265 22.03.2020 23:38 # 0
Возможностью положить его в некоторые мапы/кеши, которые не поддерживают null-values.
А реально ничем.
gost 22.03.2020 23:50 # +3
Ну или так, да. Хотя, честно говоря, это выглядит как проблема в соответствующих мапах/кешах, а не в null-е.
Кстати, в «C++» нельзя положить в вектор ссылку:
Такой код генерирует простую и понятную ошибку на жалких 20000 символов: https://pastebin.com/SGeh4X19.
Чтобы исправить это досадное упущение, в Стандарт запихнули некий «std::reference_wrapper», находящийся — что очевидно любому здравомыслящему человеку — в заголовочном файле <functional>:
Удобно, правда?
MAPTOBCKuu_nemyx 22.03.2020 23:54 # 0
3.14159265 23.03.2020 00:03 # +1
Пастбин не открылся. Но поверю на слово :)
Какой пиздец )))
PS Воистину пиздец:
KOPOHABuPYC 25.03.2020 12:49 # 0
Desktop 22.03.2020 02:04 # 0
Не ебашьте Optional там, где вам важна ошибка
gost 22.03.2020 02:11 # 0
Optional опасен тем, что он подталкивает программиста писать говно. Точно так же, например, как пресловутое goto, которое тоже в очень редких и специфических случаях полезно и нужно, а во всех остальных приводит к нечитаемой лапше.
Optional — это инструмент, который может использовать только человек с сильной волей и железной дисциплиной. Иначе получается говно.
Desktop 22.03.2020 02:17 # 0
Ну так нахуй петухов, в общем-то.
gost 22.03.2020 02:19 # 0
> Ну так нахуй петухов, в общем-то.
До тех пор, пока тебе не придётся иметь дело с кодом, написанным другим человеком.
Desktop 22.03.2020 02:23 # +1
gost 22.03.2020 02:25 # 0
Desktop 22.03.2020 02:28 # +1
gost 22.03.2020 02:38 # 0
В дополнение, есть рациональные причины выкинуть Optional из новых языков программирования (о чём мы тут и развели дискуссию). Именно поэтому я за «Go».
Это ничем не отличается от ситуации c goto.
phpBidlokoder2 20.03.2020 23:38 # 0
Janycz 20.03.2020 23:40 # 0
phpBidlokoder2 20.03.2020 23:39 # 0
KOPOHABuPYC 21.03.2020 00:09 # 0