Это уже отмазки пошли. Я сказал, зачем нужно делать new const T, вы сказали, что чаще бывает static T, я привёл сценарии - более чем рабочие! - а вы отделываетесь какой-то совершенно пустой фразой "главное, чтобы программист знал..."
Ну вот пусть программист и знает, что константы на куче размещать можно и нужно.
Если некий тип задуман как состоящий из константной (ключевой) и неконстантной частей, то лучше эти неконстантные части объявить как mutable.
Или вообще переделать дизайн программы, а то начинается "в этом контексте мы можем ломать константность только для этих полей, в другом контексте - только для тех полей, а в третьем ломать константность нельзя вовсе..." - и потом где-нибудь что-нибудь напутать и сломать.
const_cast, снимающий константность - это всегда звонкий колокол.
В ней просто названы несколько взятых наобум мусорных языков и показаны случайные примеры на них.
Что мы видим? Что это write-only языки, код на которых больно читать. И больше ничего не видим.
Какие идеи заложены в эти языки, помимо минимального синтаксиса и нечитаемости? Можете рассказать?
Давайте-ка я сделаю это за вас. Начну с "традиционных" вырвиглазок.
Старый добрый брейнфак. Это - разновидность машины Тьюринга. (В которую добавили бесконечное количество состояний ячеек и откуда убрали goto).
Unlambda. Комбинаторная логика на традиционном базисе SKI.
Йот. Довели КЛ до абсурда-и-предела, базис из единственного комбинатора i.
APL, J, K, Q. Это промышленные языки, которые работают с произвольными тензорами, а синтаксис упрощён в пользу тацитной (безымянной) нотации. Упор там сделан на очень быстрый парсер и очень быстрый интерпретатор.
Лисп. Лямбда-исчисление, код-как-данные, сам себя интерпретатор.
Форт. Стековая машина, ПОЛИЗ, и опять же сам себя интерпретатор.
А теперь посмотрим на то, что в статье.
Malbolge. Просто упоротая машина Тьюринга. (Но не брейнфак).
Whitespace. Брейнфакнутая версия форта.
Chef. Коболизированная версия форта с множеством стеков.
INTERCAL. Коболизированная версия бейсика.
Коболизированная версия брейнфака.
Скушно! Просто потрахать мозг. Никакой красивой математической идеи за ними не стоит.
Большое количество больших константных объектов в принципе не создают в статической памяти.
А если эти константы времени исполнения?
Например, строки. Например, содержимое конфиг-файла.
Или сообщения для обмена внутри одного процесса. Или даже сообщения для обмена между процессами через общую память (нужен соответствующий аллокатор, естественно).
1 клетка принимает 3 состояния и влезает в 2 разряда.
2 клетки - 3^2 = 9 состояний, 4 разряда.
3 клетки - 3^3 = 27 состояний, 5 разрядов.
Это значит, мы можем построить функции
using table = unsigned short; // 15 bit
using row = unsigned char; // 5 bit
using cell = unsigned char; // 2 bit
row encode_row(cell c0, cell c1, cell c2) {
return c0 + (c1 + c1*2) + (c2 + c2*8);
// на сдвигах, если хочется умножения экономить
}
const cell decode_row[27][3] = {
{0,0,0},{1,0,0},{2,0,0},
{0,1,0},...............,
...............,{2,2,2},
};
// что-то сходу лень думать, можно ли арифметическим колдовством
// обойтись без деления и при этом - без таблицы
В общем, дальше лень писать :)
Что будет быстрее работать, - деления или нудная работа с таблицами, - хз. Бенчмарки тоже лень писать.
Каждый раз, когда мне звонит робот-спамер, я оставляю заявку. Пусть холодный звонок превратится в горячий. В очень горячий для ушей живого оператора, который думал, что работать второй линией спамеров - это легко и приятно.
Кодировка UTF-16:он состоит издвух байтов (то есть 16 бит). Это означает что один символ весит 16 бит. В данную кодировку вмещается 2 ^ 16 = 65536 различных символов.
Ну вот нет. UTF-16 и UCS-2 - это разные кодировки. И та и другая используют двухбайтные слова, только у UCS-2 - на один символ ровно одно слово, поэтому она вмещает 65536 символов, а UTF-16 - это кодировка переменной длины! Почитайте про суррогатные пары самостоятельно, пожалуйста.
До кучи, ещё есть UTF-7.
Практический смысл разных UTF-n в том, что для ASCII (наиболее расхожий набор символов) UTF-8 кодируется 1 байтом, и для европейских алфавитов и всякой популярной графики UTF-16 кодируется одним словом (но китайцы уже страдают!), а UTF-32 хватит для всего UCS-4 - и вот это уже кодировка фиксированной длины.
Этак при желании можно ломануть и зеркало дистрибутива, и даже сам дистрибутив. Потом будет скандал, но это когда ещё будет...
Кроме того, сторонний софт на то и сторонний, что в дистрибутив не вошёл. И что теперь, исповедовать подход эппла, "чего нет в нашем апсторе, то вам и не нужно!"
Пользователи линукса - это не исключительно красноглазики, у которых всё труъ из сырцов и потрошёные дебы.
А практика ставить недостающий софт (которого не положили в репу дистрибутива) из сторонних реп - это нормально. Репа производителя - куда уж официальнее-то?
И сырцы не панацея. Автор прекрасно может насрать в свои собственные сырцы - на гитхабе такие истории уже были.
Вы каждый пакет вычитываете и верифицируете? Вам делать больше нечего?
Вы ради браузера поднимаете докер? Ну вы-то, допустим, можете...
Вот именно. Вы знаете про ленивый и энергичный фолды. Собственно, любой хаскельщик это вынужден знать. Но это как раз императивная сторона языка, понимание того, в каком порядке что вычисляется, и указание вычислять именно в таком порядке.
Но если уж писать об этом, - то надо не вскользь, а раскрыть тему. Почему в энергичных языках правый фолд плохой, и его надо переписать на левый над перевёрнутым списком, например.
Я привёл чисто декларативный код: "первый (или любой) элемент из последовательности многократных применений f к x, такой, что удовлетворяет заданному условию".
Причём эта формулировка позволяет делать всякие улучшения.
Например, обнаруживать зацикливание. Хоть самое простое, когда функция попала в неподвижную точку, fx = x. Хоть когда попала в цикл произвольной длины, f^n(x) = x.
Или обнаруживать ошибки в коде. Мы утверждаем, что функция монотонная (на каждом шаге мы уточняем игровое поле). То есть, x <= fx. И из этого следует, что возможны только циклы длиной 1 - неподвижные точки. Но если это не так, то пара смежных элементов x1, x2 с нарушением порядка, x1>x2, говорит, что ой всё.
Потому что мы исследуем последовательности как структуры данных.
А код "вызывать функцию и проверять условие, вызывать и проверять..." - это та самая императивность. Записанная посредством функционального языка. На языке с переменными и циклами это просто контракт - постусловие. "Если программа останавливается, то из этого следует, что постусловие выполнено". Очень даже декларативно, не? Если не накрутить макарон внутри цикла. Ну так макароны и в функциональном коде можно накрутить.
Сидящий в кофейне разработчик вполне может подключиться к интрасети своей конторы через VPN своей конторы. И это будет то же самое, что сидеть непосредственно в конторе. Всякая там жира, почта, панели управления... которые наружу в принципе не торчат.
И всё было бы хорошо, но у него оказывается есть кейлоггер в лице любимого хромчика или ёжика.
"Мы вставили абстракцию цикл Ц-слово, но мы не хотим, чтобы про неё думали, как про Ц-слово, поэтому давайте напишем на концевой рекурсии, расскажем сказку про контракт (процедурщики и так знают, что такое постусловие Ц-слова), а чтобы уж наверняка, назовём нашу функцию высшего порядка Ц-словом! чтоб никто не догадался"
Цикл он и есть цикл.
Хотелось бы функциональщины, - ввели бы
1) генератор многократных применений функции: проекция типа T на T* (бесконечный список)
2) фильтр по предикату
iterate f x = x : iterate f (f x)
filter p xs = [x | x <- xs, p x]
until p f x = head (filter p (iterate f x))
и вуаля, мы тут мыслим в терминах данных (бесконечный ленивый список и его элементы), а не в терминах процессов (вызывать f раз за разом)
А насчёт того, что "этот код писал императивщик", так как раз императивщик и задумается о плане вычислений, и о том, что концевая рекурсия лучше обычной, как раз потому, что не жрёт память (и потому что реализуется через Ц-слово).
А вот декларативщик, который говорит "нам пофиг, как оно вычислится, мы выдвинули требования к результату" может отхватить люлей. Причём в хаскелле с его ленивостью он эти люли отхватит, если перепутает направления свёртки. Вы ведь знаете, почему правый фолд предпочтителен ленивый, а левый - предпочтителен энергичный (хотя и ленивый тоже есть для комплектности) Казалось бы какая разница, ленивый-энергичный, итог-то один, а? А императивщик сразу руками замашет.
Это уже отмазки пошли. Я сказал, зачем нужно делать new const T, вы сказали, что чаще бывает static T, я привёл сценарии - более чем рабочие! - а вы отделываетесь какой-то совершенно пустой фразой "главное, чтобы программист знал..."
Ну вот пусть программист и знает, что константы на куче размещать можно и нужно.
Это читерство и антипаттерны.
Если некий тип задуман как состоящий из константной (ключевой) и неконстантной частей, то лучше эти неконстантные части объявить как mutable.
Или вообще переделать дизайн программы, а то начинается "в этом контексте мы можем ломать константность только для этих полей, в другом контексте - только для тех полей, а в третьем ломать константность нельзя вовсе..." - и потом где-нибудь что-нибудь напутать и сломать.
const_cast, снимающий константность - это всегда звонкий колокол.
Плохая статья.
В ней просто названы несколько взятых наобум мусорных языков и показаны случайные примеры на них.
Что мы видим? Что это write-only языки, код на которых больно читать. И больше ничего не видим.
Какие идеи заложены в эти языки, помимо минимального синтаксиса и нечитаемости? Можете рассказать?
Давайте-ка я сделаю это за вас. Начну с "традиционных" вырвиглазок.
Старый добрый брейнфак. Это - разновидность машины Тьюринга. (В которую добавили бесконечное количество состояний ячеек и откуда убрали goto).
Unlambda. Комбинаторная логика на традиционном базисе SKI.
Йот. Довели КЛ до абсурда-и-предела, базис из единственного комбинатора i.
APL, J, K, Q. Это промышленные языки, которые работают с произвольными тензорами, а синтаксис упрощён в пользу тацитной (безымянной) нотации. Упор там сделан на очень быстрый парсер и очень быстрый интерпретатор.
Лисп. Лямбда-исчисление, код-как-данные, сам себя интерпретатор.
Форт. Стековая машина, ПОЛИЗ, и опять же сам себя интерпретатор.
А теперь посмотрим на то, что в статье.
Malbolge. Просто упоротая машина Тьюринга. (Но не брейнфак).
Whitespace. Брейнфакнутая версия форта.
Chef. Коболизированная версия форта с множеством стеков.
INTERCAL. Коболизированная версия бейсика.
Коболизированная версия брейнфака.
Скушно! Просто потрахать мозг. Никакой красивой математической идеи за ними не стоит.
А ещё есть const_cast и его помощники - функции std::move и std::as_const.
Большое количество больших константных объектов в принципе не создают в статической памяти.
А если эти константы времени исполнения?
Например, строки. Например, содержимое конфиг-файла.
Или сообщения для обмена внутри одного процесса. Или даже сообщения для обмена между процессами через общую память (нужен соответствующий аллокатор, естественно).
1 клетка принимает 3 состояния и влезает в 2 разряда.
2 клетки - 3^2 = 9 состояний, 4 разряда.
3 клетки - 3^3 = 27 состояний, 5 разрядов.
Это значит, мы можем построить функции
В общем, дальше лень писать :)
Что будет быстрее работать, - деления или нудная работа с таблицами, - хз. Бенчмарки тоже лень писать.
В функции set_cell ошибка, там сигнатура должна быть `void set_cell(state* s, .....)`
Элементарно! Если объект достаточно велик, чтобы жить на стеке.
Каждый раз, когда мне звонит робот-спамер, я оставляю заявку. Пусть холодный звонок превратится в горячий. В очень горячий для ушей живого оператора, который думал, что работать второй линией спамеров - это легко и приятно.
Интегральные схемы - это не совсем рассыпуха :))
У светодиодов нет инерции, надо бы её добавить - чтобы было какое-никакое послесвечение. Может быть, rc-цепочки на каждый столбец?
Ну вот нет. UTF-16 и UCS-2 - это разные кодировки. И та и другая используют двухбайтные слова, только у UCS-2 - на один символ ровно одно слово, поэтому она вмещает 65536 символов, а UTF-16 - это кодировка переменной длины! Почитайте про суррогатные пары самостоятельно, пожалуйста.
До кучи, ещё есть UTF-7.
Практический смысл разных UTF-n в том, что для ASCII (наиболее расхожий набор символов) UTF-8 кодируется 1 байтом, и для европейских алфавитов и всякой популярной графики UTF-16 кодируется одним словом (но китайцы уже страдают!), а UTF-32 хватит для всего UCS-4 - и вот это уже кодировка фиксированной длины.
Этак при желании можно ломануть и зеркало дистрибутива, и даже сам дистрибутив. Потом будет скандал, но это когда ещё будет...
Кроме того, сторонний софт на то и сторонний, что в дистрибутив не вошёл. И что теперь, исповедовать подход эппла, "чего нет в нашем апсторе, то вам и не нужно!"
Пользователи линукса - это не исключительно красноглазики, у которых всё труъ из сырцов и потрошёные дебы.
А практика ставить недостающий софт (которого не положили в репу дистрибутива) из сторонних реп - это нормально. Репа производителя - куда уж официальнее-то?
И сырцы не панацея. Автор прекрасно может насрать в свои собственные сырцы - на гитхабе такие истории уже были.
Вы каждый пакет вычитываете и верифицируете? Вам делать больше нечего?
Вы ради браузера поднимаете докер? Ну вы-то, допустим, можете...
Осталось главной интригой - какие люди-Х и как инфицировали сайт FDM? Засланные казачки, или извне ломанули?
Вот именно. Вы знаете про ленивый и энергичный фолды. Собственно, любой хаскельщик это вынужден знать. Но это как раз императивная сторона языка, понимание того, в каком порядке что вычисляется, и указание вычислять именно в таком порядке.
Но если уж писать об этом, - то надо не вскользь, а раскрыть тему. Почему в энергичных языках правый фолд плохой, и его надо переписать на левый над перевёрнутым списком, например.
Я привёл чисто декларативный код: "первый (или любой) элемент из последовательности многократных применений f к x, такой, что удовлетворяет заданному условию".
Причём эта формулировка позволяет делать всякие улучшения.
Например, обнаруживать зацикливание. Хоть самое простое, когда функция попала в неподвижную точку, fx = x. Хоть когда попала в цикл произвольной длины, f^n(x) = x.
Или обнаруживать ошибки в коде. Мы утверждаем, что функция монотонная (на каждом шаге мы уточняем игровое поле). То есть, x <= fx. И из этого следует, что возможны только циклы длиной 1 - неподвижные точки. Но если это не так, то пара смежных элементов x1, x2 с нарушением порядка, x1>x2, говорит, что ой всё.
Потому что мы исследуем последовательности как структуры данных.
А код "вызывать функцию и проверять условие, вызывать и проверять..." - это та самая императивность. Записанная посредством функционального языка. На языке с переменными и циклами это просто контракт - постусловие. "Если программа останавливается, то из этого следует, что постусловие выполнено". Очень даже декларативно, не? Если не накрутить макарон внутри цикла. Ну так макароны и в функциональном коде можно накрутить.
Сидящий в кофейне разработчик вполне может подключиться к интрасети своей конторы через VPN своей конторы. И это будет то же самое, что сидеть непосредственно в конторе. Всякая там жира, почта, панели управления... которые наружу в принципе не торчат.
И всё было бы хорошо, но у него оказывается есть кейлоггер в лице любимого хромчика или ёжика.
"Мы вставили абстракцию
циклЦ-слово, но мы не хотим, чтобы про неё думали, как про Ц-слово, поэтому давайте напишем на концевой рекурсии, расскажем сказку про контракт (процедурщики и так знают, что такое постусловие Ц-слова), а чтобы уж наверняка, назовём нашу функцию высшего порядка Ц-словом! чтоб никто не догадался"Цикл он и есть цикл.
Хотелось бы функциональщины, - ввели бы
1) генератор многократных применений функции: проекция типа T на T* (бесконечный список)
2) фильтр по предикату
и вуаля, мы тут мыслим в терминах данных (бесконечный ленивый список и его элементы), а не в терминах процессов (вызывать f раз за разом)
А насчёт того, что "этот код писал императивщик", так как раз императивщик и задумается о плане вычислений, и о том, что концевая рекурсия лучше обычной, как раз потому, что не жрёт память (и потому что реализуется через Ц-слово).
А вот декларативщик, который говорит "нам пофиг, как оно вычислится, мы выдвинули требования к результату" может отхватить люлей. Причём в хаскелле с его ленивостью он эти люли отхватит, если перепутает направления свёртки. Вы ведь знаете, почему правый фолд предпочтителен ленивый, а левый - предпочтителен энергичный (хотя и ленивый тоже есть для комплектности) Казалось бы какая разница, ленивый-энергичный, итог-то один, а? А императивщик сразу руками замашет.
Не просто и не всё. Утечка из браузера происходит мимо роботса.
Это уже потом ИБшники будут удивляться, какого фига гугловский паукан пытается обращаться по внутренним урлам (и ему за это иногда дают по хелицерам).
И натравление паукана на внутренние сайты - лишь одна из проблем. Пример другой проблемы показан в статье. Где там роботс? Нигде.