И в этой статье какое-то произвольное манипулирование исходными условиями. Почему-то создавать новые "рога" можно "неограниченно". А петля с чего-то вдруг обязательно должна коснуться поверхности сферы, как будто у нас куда-то пропала возможность бесконечно делить любое пространство на более мелкие, но тем не менее не пустые пространства. И видимо у обсуждаемой петли есть толщина, из-за которой мы не сможем протолкнуть её через некую, бесконечно далёкую пару "рогов".
Я не специалист в топологии, но очень странно в её контексте выглядят в этой статье обсуждения расстояний и их соотношение. Какое это имеет значение? Как захотели так и растянули кривую/поверхность/область. Конкретные величины расстояний и их взаимное отношение не имеют значения, главное что бы выполнялись ограничения накладываемые на трансформации.
А вот если бы у нас была сфера, вместо плоскости. Тогда указанное утверждение можно считать верным. Любая петля на сфере делила бы её поверхность на две одинаково устроенные области.
Внешняя область имеет отверстие, образованное областью С, поэтому она уже отличается по своим свойствам от С. Тем не менее она, по моему, односвязная, т.к. любые две точки этой области можно соединить непрерывной кривой, которая не пересекает границы области.
Какой-то странный контрпример (или его описание в этой статье). Мы не можем стянуть петлю в точку потому что: "Ааааа, вы только поглядите какой сложный и страшный рисунок! Зуб даю, что нельзя петлю стянуть!". Апелляция к бесконечности выглядит как какой-то шарлатанский трюк.
Исправьте ваш собственный рисунок "рогов" от руки. Он не соответствует вашему описанию и тем более не соответствует дальнейшим изображениям "рогатой" сферы. У вас красные рога не скрещиваются с зелёными "замком". Они просто находятся перед ними.
Интересно, почему изначально была выбрана MongoDB, если у неё, по сути, есть только один достаточно существенный плюс - это простое шардирование из коробки? Но, как указано в статье, никто в самом начале даже не думал про шардирование.
Я конечно понимаю, что вероятно в приведённом коде практически нечего оптимизировать, но можно же было, хотя бы для порядка, собирать релизную версию бинарного файа, а не отладочную.
Дааа-с, завернуть в gather() отправку запросов на сервер вы догадались, а сделать то же самое с получением тела ответа от сервера - нет. В результате ответы на свои запросы вы по прежнему вычитываете последовательно, один за другим.
А на что вы намекаете, говоря, что на С точно так же можно написать? Типа зачем тогда нужен Rust?
Написание программ состоит не только из написания списков. То что оптимальная (по скорости) реализация списков в Rust, посути копирует реализацию из C, не означает, что Rust безполезен и в нём в принципе нельзя писать быстрый код без сырых указателей, unsafe и обхода borrow-чекера.
Рантайм ошибка? Т.к. очевидно что компилятор тут ничем не поможет - тип ноды не изменяется от того, что её добавили в список.
В принципе это тоже вариант, но он мне не очень нравится. Зачем перекладывать эту проверку в рантайм, если можно на этапе компиляции гарантировать отсутствие попытки добавить ноду во второй список.
А от куда node будет знать из какого именно списка надо удалиться? Судя по API ничто не мешает добавить его в несколько разных списков (и даже несколько раз в один и тот же).
Разве что list.push_back(node) будет "съедать" node и возвращать какой-то враппер вокруг него, тогда у враппера может быть метод remove().
Я в принципе не понимаю зачем вы полезли в реализацию Box::new(), зачем решили использовать в своём коде box. И после этого сделали выводы как в анекдоте про сибирских лесорубов, которые засунули стальной лом в японскую лесопилку.
Почему нельзя было использовать Box::new()? Вам что-ли принципильно хотелось с самого начала оперировать только указателями, что бы "всё как в С"?
Я лично уже запутался, какие у вас претензии к тому, что box не работает в пользовательсокм коде в стабильной версии Rust?
Вроде всё очевидно - интерфейс этого "оператора" ещё не стабилизирован. Всё ещё есть вероятность, что его могут поменять (например решат, что он должен возвращать Result<Box<T>>, вместо Box<T>).
Но это не означает, что стандартная библиотека не может его использовать. Если бы это был не "оператор" языка, а функция, то её могли бы сделать приватной, и у вас точно так же не получилось бы её использовать в своём коде.
Вектор он и в африке вектор, отличаться может только название (например массивом могут называть) - "плоская" коллекция однотипных структур. Моя мысль была в том что однопоточность это не гарантия отсутствия проблем которые предотвращает borrow-чекер. Причём это зачастую не очень очевидные проблемы (как переаллокация вектора при добавлении в него элементов).
Даже в однопоточном коде можно получить аналоги рейсов. Например добавлять новые элементы в вектор при итерации по нему же. В общем случае это может привести переаллокации куска памяти под вектор и дальнейшей итерации по уже освобождённому куску памяти. Borrow чекер просто не позволит реализвовать такое незаметно. Придётся поприседать, что бы сделать это.
но вместо реализации HATEOAS имеют спецификацию типов полей/ответов, под которую пишутся/генерируются клиенты.
Оригинальный REST по сути ближе всего к тому, как классический веб с его HTML-страничками, переходами и формами работает.
А как по вашему браузер понимает как правильно показывать странички, как рисовать формы и отправлять их на сервер?
Он делает это как раз за счёт "типа документа" + "спецификации для этого типа". Первое передаётся в заголовке Content-Type (в случае HTTP), а второе содержит описание того какие "поля" могут быть в документе этого типа и что с ними надо делать клиенту (или серверу).
HATEOAS предполагается использовать для изменения состояния приложения, не зашивая в клиент каждый переход между этими состояниями. HATEOAS не отменяет наличие какой-то спецификации на "тип документа", которая бы описывала в том числе и то, как найти в документе нужные клиенту ссылки. Плюс такого решения в том, что клиенту достаточно знать только "поле" в котором хранится ссылка, а сама ссылка в этом поле может меняться со временем или в зависимости от других условий. Второй механизм - наличие или отсутствие нужной ссылки в документе. Если ссылки нет - значит соответствующие "действие" не доступно для клиента. Это тоже позволяет со стороны сервера управлять поведением клиента, без необходимости зашивать в него какие-то жёсткие алгоритмы.
Но я согласен, что в большинстве случаев мало кто использует разные "типы" документов. Обычно делают один, например application/json, а как именно обрабатывать данные с таким типом в клиенте - определяют на основе каких-то зашитых в клиенте эвристик. Наверное более правильно было бы использовать разные типы данных для реально разных ресурсов. Например application/product+json, application/order+json. Но как правило это не используют, т.к., в отличии от браузера, у самописного клиента несколько больше состояний. В зависимости от текущего состояния, клиент определяет каким образом ему обрабатывать получнный от сервера application/json.
Зашитые в клиент "эвристики", вместо повсеместного использования HATEOAS, могут компенсироваться использованием REST принципа "code-on-demand". Оно позволит обновлять и дополнять код клиента, что бы он мог корректно работать после каких-то изменений на сервере.
Современные "App Store" в мобилках и десктопах - это фактически этот самый code-on-demand. Только с ними есть "проблема" - пользователи могут отключить автоматическое обновление. И если это критично для приложения, тогда надо более широко использовать HATEOAS (и даже code-on-demand) внутри самого клиента. Тогда он сможет лучше работать в условиях изменения приложения на стороне сервера. В этом плане веб-браузеры - это наиболее гибкие клиенты для распределённых клиент-серверных приложений, которые у нас сейчас имеются.
Если есть достпу через ssh, то что мешает пробросить тунель с ноды на котроллер и подключаться к постгрессу со стороны контроллера? Тогда достаточно будет только на контроллере один раз установить psycopg2 любым способом и не тащить его на ноды.
PS: Я сам с Ansible не работал, поэтому не знаю на сколько моя идея "запускать код на контролере" вписывается в его концепцию.
Надо по осторожнее с формулировками вида "код, который не падает" и с противопоставлением С++ на котором сервисы "аварийно завершаются". А то создаётся ощущение, что Rust гарантирует отсутствие падений и аварийных завершений. Падений и аварий с точки зрения пользователя, для которого любое неожиданное завершение приложения - это падение.
Rust ничего такого не гарантирует - достаточно просто поделить число на 0 и приложение "упадёт" как и в других языках программирования. Практически все гарантии Rust связанны только с безопасной работой с памятью. А про "падения" надо всегда пояснять, что имеется ввиду корректное завершение приложения, при возникновении необработанных ошибок. Без вредных сайд-эффектов, вроде выполнения стороннего кода или утечки наружу каких-то приватных данных (но это неточно, т.к. через unsafe и указатели скорее всего можно поковыряться в стеке).
Подобные, необдуманные "обещания" создают негативный фон вокруг Rust. Выглядит как втюхивание непримечательного товара маркетологами.
Как работает автомат?
Очень просто. Тра-та-та, и вы убиты.
Почему линии в тексте называются "строками"? Это какой-то кривой перевод слова lines?
А как устроено голосование за пиксели? У них есть предвыборная программа, дебаты? При голосовании используется ДЭГ или другая система?
И в этой статье какое-то произвольное манипулирование исходными условиями. Почему-то создавать новые "рога" можно "неограниченно". А петля с чего-то вдруг обязательно должна коснуться поверхности сферы, как будто у нас куда-то пропала возможность бесконечно делить любое пространство на более мелкие, но тем не менее не пустые пространства. И видимо у обсуждаемой петли есть толщина, из-за которой мы не сможем протолкнуть её через некую, бесконечно далёкую пару "рогов".
Я не специалист в топологии, но очень странно в её контексте выглядят в этой статье обсуждения расстояний и их соотношение. Какое это имеет значение? Как захотели так и растянули кривую/поверхность/область. Конкретные величины расстояний и их взаимное отношение не имеют значения, главное что бы выполнялись ограничения накладываемые на трансформации.
А вот если бы у нас была сфера, вместо плоскости. Тогда указанное утверждение можно считать верным. Любая петля на сфере делила бы её поверхность на две одинаково устроенные области.
Внешняя область имеет отверстие, образованное областью С, поэтому она уже отличается по своим свойствам от С. Тем не менее она, по моему, односвязная, т.к. любые две точки этой области можно соединить непрерывной кривой, которая не пересекает границы области.
Какой-то странный контрпример (или его описание в этой статье). Мы не можем стянуть петлю в точку потому что: "Ааааа, вы только поглядите какой сложный и страшный рисунок! Зуб даю, что нельзя петлю стянуть!".
Апелляция к бесконечности выглядит как какой-то шарлатанский трюк.
Исправьте ваш собственный рисунок "рогов" от руки. Он не соответствует вашему описанию и тем более не соответствует дальнейшим изображениям "рогатой" сферы. У вас красные рога не скрещиваются с зелёными "замком". Они просто находятся перед ними.
Думаю что этот текст был сгенерирован чем-то вроде СhatGPT.
Интересно, почему изначально была выбрана MongoDB, если у неё, по сути, есть только один достаточно существенный плюс - это простое шардирование из коробки? Но, как указано в статье, никто в самом начале даже не думал про шардирование.
Я конечно понимаю, что вероятно в приведённом коде практически нечего оптимизировать, но можно же было, хотя бы для порядка, собирать релизную версию бинарного файа, а не отладочную.
Дааа-с, завернуть в gather() отправку запросов на сервер вы догадались, а сделать то же самое с получением тела ответа от сервера - нет. В результате ответы на свои запросы вы по прежнему вычитываете последовательно, один за другим.
А на что вы намекаете, говоря, что на С точно так же можно написать? Типа зачем тогда нужен Rust?
Написание программ состоит не только из написания списков. То что оптимальная (по скорости) реализация списков в Rust, посути копирует реализацию из C, не означает, что Rust безполезен и в нём в принципе нельзя писать быстрый код без сырых указателей, unsafe и обхода borrow-чекера.
Рантайм ошибка? Т.к. очевидно что компилятор тут ничем не поможет - тип ноды не изменяется от того, что её добавили в список.
В принципе это тоже вариант, но он мне не очень нравится. Зачем перекладывать эту проверку в рантайм, если можно на этапе компиляции гарантировать отсутствие попытки добавить ноду во второй список.
А от куда node будет знать из какого именно списка надо удалиться? Судя по API ничто не мешает добавить его в несколько разных списков (и даже несколько раз в один и тот же).
Разве что list.push_back(node) будет "съедать" node и возвращать какой-то враппер вокруг него, тогда у враппера может быть метод remove().
Я в принципе не понимаю зачем вы полезли в реализацию Box::new(), зачем решили использовать в своём коде
box
. И после этого сделали выводы как в анекдоте про сибирских лесорубов, которые засунули стальной лом в японскую лесопилку.Почему нельзя было использовать Box::new()? Вам что-ли принципильно хотелось с самого начала оперировать только указателями, что бы "всё как в С"?
Я лично уже запутался, какие у вас претензии к тому, что
box
не работает в пользовательсокм коде в стабильной версии Rust?Вроде всё очевидно - интерфейс этого "оператора" ещё не стабилизирован. Всё ещё есть вероятность, что его могут поменять (например решат, что он должен возвращать Result<Box<T>>, вместо Box<T>).
Но это не означает, что стандартная библиотека не может его использовать. Если бы это был не "оператор" языка, а функция, то её могли бы сделать приватной, и у вас точно так же не получилось бы её использовать в своём коде.
Вектор он и в африке вектор, отличаться может только название (например массивом могут называть) - "плоская" коллекция однотипных структур. Моя мысль была в том что однопоточность это не гарантия отсутствия проблем которые предотвращает borrow-чекер. Причём это зачастую не очень очевидные проблемы (как переаллокация вектора при добавлении в него элементов).
Даже в однопоточном коде можно получить аналоги рейсов. Например добавлять новые элементы в вектор при итерации по нему же. В общем случае это может привести переаллокации куска памяти под вектор и дальнейшей итерации по уже освобождённому куску памяти. Borrow чекер просто не позволит реализвовать такое незаметно. Придётся поприседать, что бы сделать это.
А как по вашему браузер понимает как правильно показывать странички, как рисовать формы и отправлять их на сервер?
Он делает это как раз за счёт "типа документа" + "спецификации для этого типа". Первое передаётся в заголовке Content-Type (в случае HTTP), а второе содержит описание того какие "поля" могут быть в документе этого типа и что с ними надо делать клиенту (или серверу).
HATEOAS предполагается использовать для изменения состояния приложения, не зашивая в клиент каждый переход между этими состояниями. HATEOAS не отменяет наличие какой-то спецификации на "тип документа", которая бы описывала в том числе и то, как найти в документе нужные клиенту ссылки. Плюс такого решения в том, что клиенту достаточно знать только "поле" в котором хранится ссылка, а сама ссылка в этом поле может меняться со временем или в зависимости от других условий. Второй механизм - наличие или отсутствие нужной ссылки в документе. Если ссылки нет - значит соответствующие "действие" не доступно для клиента. Это тоже позволяет со стороны сервера управлять поведением клиента, без необходимости зашивать в него какие-то жёсткие алгоритмы.
Но я согласен, что в большинстве случаев мало кто использует разные "типы" документов. Обычно делают один, например application/json, а как именно обрабатывать данные с таким типом в клиенте - определяют на основе каких-то зашитых в клиенте эвристик. Наверное более правильно было бы использовать разные типы данных для реально разных ресурсов. Например application/product+json, application/order+json. Но как правило это не используют, т.к., в отличии от браузера, у самописного клиента несколько больше состояний. В зависимости от текущего состояния, клиент определяет каким образом ему обрабатывать получнный от сервера application/json.
Зашитые в клиент "эвристики", вместо повсеместного использования HATEOAS, могут компенсироваться использованием REST принципа "code-on-demand". Оно позволит обновлять и дополнять код клиента, что бы он мог корректно работать после каких-то изменений на сервере.
Современные "App Store" в мобилках и десктопах - это фактически этот самый code-on-demand. Только с ними есть "проблема" - пользователи могут отключить автоматическое обновление. И если это критично для приложения, тогда надо более широко использовать HATEOAS (и даже code-on-demand) внутри самого клиента. Тогда он сможет лучше работать в условиях изменения приложения на стороне сервера. В этом плане веб-браузеры - это наиболее гибкие клиенты для распределённых клиент-серверных приложений, которые у нас сейчас имеются.
Если есть достпу через ssh, то что мешает пробросить тунель с ноды на котроллер и подключаться к постгрессу со стороны контроллера? Тогда достаточно будет только на контроллере один раз установить psycopg2 любым способом и не тащить его на ноды.
PS: Я сам с Ansible не работал, поэтому не знаю на сколько моя идея "запускать код на контролере" вписывается в его концепцию.
Надо по осторожнее с формулировками вида "код, который не падает" и с противопоставлением С++ на котором сервисы "аварийно завершаются". А то создаётся ощущение, что Rust гарантирует отсутствие падений и аварийных завершений. Падений и аварий с точки зрения пользователя, для которого любое неожиданное завершение приложения - это падение.
Rust ничего такого не гарантирует - достаточно просто поделить число на 0 и приложение "упадёт" как и в других языках программирования. Практически все гарантии Rust связанны только с безопасной работой с памятью. А про "падения" надо всегда пояснять, что имеется ввиду корректное завершение приложения, при возникновении необработанных ошибок. Без вредных сайд-эффектов, вроде выполнения стороннего кода или утечки наружу каких-то приватных данных (но это неточно, т.к. через unsafe и указатели скорее всего можно поковыряться в стеке).
Подобные, необдуманные "обещания" создают негативный фон вокруг Rust. Выглядит как втюхивание непримечательного товара маркетологами.