А как такое работает? ptr это что? Обычно массив это внтуренний примитив и ссылку на место где лежит элемент взять так просто нельзя. Или язык должен предоставлять специальный примитив для этого, который поидее и будет содержать ссылку на сам массив. Иначе как гц узнает связь между (ptr+i) и аллокацией c началом ptr?
Получается Vector это вью для последовательной аллокации? Тогда его всё равно нельзя использовать как параметр для ренжа с O(1) доступом, потому что за iota нету никакой аллокации. Зачем вы мне его предлагали?
Зачем для этого тайпкласс? Композицию функций уже отменили? transform :: (Int -> a) -> (a -> b) -> (Int -> b)
Не вижу как сюда передать объект типа Range, или какой вы там создали?
toList
В тот момент когда надо писать такие явные преобразования код перестаёт быть женерик.
А как вы там в типах отличаете ограниченные и неограниченные рейнджи?
По наличию перегрузки size()
auto x = zip_transform(std::plus{}, iota(3, 10), iota(3, 20));
static_assert(sized_range<decltype(x)>);
std::println("{}", x.size());
auto y = zip_transform(std::plus{}, iota(100), iota(200));
static_assert(!sized_range<decltype(y)>);
Потому что контейнер тегирован s, которая должна иметь возможность быть произвольной во всём скоупе runST (об этом говорит тип runST). Как только вы его куда-то кладёте, оно больше не может быть произвольным.
Т.е. у меня контейнер создаётся и умирает вместе с runST? Или создаётся мутабельный вью?
Я хочу взять например вектор, мутировать его в одном потоке, потом мувнуть его в другой поток и продолжить мутировать там.
А подёргать STM внутри runST тоже нельзя, потому что STM дёргается через atomically , которая живёт в IO, и которую нельзя поэтому дёргать внутри runST.
А как мне писать код который одновременно и читает что то из тред-сейф объекта расшареного и на основе этого модифицирует тред-локальный стейт?
Нет разницы между своей и чужой аллокацией. GC, все дела.
а как это тогда работает? Я представлял себе класс слайса как набор из (otherVector, begin, end) и оператор[i] который возвращает otherVector[begin+i]. Сам otherVector держится/очищается через GC, а не вручную.
Что не смог? Я вам миллион примеров уже привёл под каждую из ваших уточнённых задач согласно каждому из ваших пожеланий
Ну я же просил в самом начале, целостный пример который все задачи обобщенно решает, а не какие-то отрывки.
of — это кусок case, ; разделяет бранчи, чтобы написать в одну строчку в репле. Можно было бы
фух, в новом виде наконец хаскель можно прочитать. спасибо
Зачем отдельный тайпкласс для метода, когда можно, блин, просто передать метод?
Что бы трансформ сделать
transform :: Range k a -> a - > b -> Range k b
и сохранить operator[] после трансформа.
Можно сравнить со страхолюдием из плюсов в темплейтах, кстати.
Первая часть это же просто определение двух конструкторов структур которые ничего не делают. В С++ такое писать особо не надо. Что делает deriving Functor мне не понятно.
А хотя я немного подумал и понял, что скорее всего теперь это класс можно через fmap оттрансформировать но нельзя запихнуть в метод который ожидает [a]. Так что вопрос про transform отменяется.
Система типов запрещает и rank-2 polymorphism. Попробуйте, короче, сами.
Т.е. у нас контекст runSTM который берёт лок на все STM контейнеры? Всё еще не понял почему я не могу ST контейнер передать между потоками, как вообще что то в поток передать? Если через IORef будет уб то как без уб? Как с этим разобраться новичку.
Много компиляторов продублирует load из атомика после проверки?
Так если load() один то всё хорошо, я специально явно два раза его запросил в примере. В сложных примерах вы такую проблему не заметите сразу. Как раз дублировать лоад это будет баг компилятора.
его компиляторы и так не делают кучу оптимизаций, которые они могли бы делать, поэтому более безопасные языки в безопасности!
Оптимизаций которые они делают достаточно чтобы синхронизировать память через атомики и ставить мемори барьеры было обязательным.
А думать о том, куда надо get делать, вперёд или назад, не надо?
Не надо, это закрытое множество вариантов.
Вообще интуитивно у меня будет отдельно контроллер списка, и отдельно несколько способов его вызывать. Скорее всего из разных диалогов. Например, какой-то общий диалог поиска писем и спец кнопка перейти к следующиму непрочитаному во фрейме отображения письма. И тут иметь готовый findNext(pred), который я могу переиспользовать лучше чем findAndSelect.
Плюс, theorems for free и всё такое.
Во-перых это не имеет никакого отношения к С++. Во-вторых что тут это даёт?
Вариативность вперёд-назад уже достаточна, как по мне.
как по мне для того чтобы объединить две строчки (find_if + select) в новый метод этого не достаточно.
Читать одинаково нормально. Использовать getPrev() как одну сущность проще чем писать get, а потом думать какой итератор надо туда вставить. Решение с ренжем в качестве аргумента даёт большую гибкость тому кто будет использовать код, с другой стороны накладывает больше мыслительной работы. Абстрагировать надо в точках где ожидается вариативность. Если там prev/next/left/right/up/down/diagonal/whatever то это другое дело.
Читайте еще раз. Вы привели одну фразу про ГЦ, и пол фразы про другие языки. Одна цитата как раз про контроль качества зависимостей.
Даже если бы в ветке было бы в основном про гц, в чем проблема ответить на ту часть сообщение которую я считаю нужным прокоментировать?
Ага, бороться с зоопарком систем сборки, когда половина зависимостей настроена на динамическую линковку. Реально, но очень долго.
Не знаю о чём вы, у меня такого нету.
И все же что вы будете делать с dll от вендора?
Давайте начнём с того как вендор создаст dll на раст и что вы будете делать с ней?
Пробелмы поставки библиотек в бинарном формате это отдельная проблема. То что в расте это сделать нельзя говорит лишь об ограниченности раста и что он неприменим для вендоров блобов. Хотя скорее всего можно за сишным интерфейсом спрятать реализацию на расте, тогда возвращаемся к той же проблеме.
Будет ссылка на область памяти, которая будет удерживать GC от её удаления, даже если исходный вектор сдохнет
т.е. это таки некий тайпкласс у которого может быть несколько реализаций? Ссылка на другой вектор или ссылка на какую-то свою аллокацию?
У меня вопрос не про владение, можно как одну из реализаций сделать слайс который в отличие от std::span делает рефкаунт (например растовый hyper::Bytes).
Тогда юзайте списки и делайте по ним map, потому что ваш трансформатор, скорее всего, не random access
В цпп сделано, в раст сделано, а хаскель не смог поэтому ненужно. Понятно..
Так вам примитивы писать или целевой прикладной код, их использующий?
И то и то. Что мне запрещает расшарить ST вектор между потоками вместо STM? Как я для своего контейнера могу определить можно его шарить или нет?
Где здесь ub?
Значение поменяется из другого потока и в getUnchecked будет уже не тот индекс который прошёл проверку строчкой выше, n это например длина контейнера.
Это который ...
Да это тот самый ллвм который вы использовали чтобы хоть как то сравнятся по скорости с цпп в своих экспериментах. И тот самый который растеры взяли потому что сами сделать свой не смогли.
можете трансформать обычным fmap после этого
Распарсить что делает of и ; я не смог, но идею понял. Хотя вместо Functor нужно иметь тайпкласс который умеет как раз в метод который даёт Int -> a. Т.е. вот это вот всё надо спроектировать и т п. Не рокет сайнс конечно, но и выдавать однострочники за какие то решения это слишком.
По порядку величин то же самое. Я прочел ваше сообщение и подумал что вы противопоставляете полдюжины аспирантов с сотней разработчиков на зарпалтах у апл и гугла...
Имхо в таком примере это преждевременное создание абстракций, получается усложнение. getNext/getPrev выглядит проще и понятнее. К тому же это ближе к реальному функционалу юай - там есть кнопки prev/next и у вас в программе будут такие методы, a не какой-то findAndSelect(forward).
Такой задачи нету. For/while строго мощнее любого другого специального сахарка. А если хотите свое, то с++ это легко позваляет сделать, хоть for(auto i : iota(a,b)), хоть boost::irange хоть что угодно с какими захотите проверками и азертами.
Так этот старый-добрый как раз и не является нормальным циклом. Не каждый осилит с первого раза правильно написать цикл от a до b включительно с итератором того же типа, особенно если шаг цикла больше 1. В то время как даже в древнем паскале это не проблема вообще.
Больше троих на что? Там у аппл есть и swift и obj-c и куча задач по интерации платформы и своего железа. Но допустим даже трое от аппла на шланг фронтенд, еще трое от гугла. Майкрософт не берём у них свой. Итого шесть. Мне сообщили что в кланг фултайм мейнтейнеров около пяти. Выходит что вложения весьма скромные.
То как было использована иота в изначальном примере - это явно усложнение потому что там рэнж создавался отдельно от логики его использования. Это дополнительная абстракция. Если не нравятся операторы сравнения напишите for (auto i : iota(0, n))
По поводу свёртки мапов, если компилятор может ходить в тело функций и анализировать/оптимизировать цепочку трансформаций, то это хорошо.
По поводу Vector всё же я не очень понял. Что значит создать из чего угодно за О(1)? Если это был слайс другого вектора, то что будет? Или допустим вообще из MVector? Трюкам с ленивостью и иммутабельностью я не доверяю после примера с qsort.
Вы как-то на ходу меняете условие. То вам нужно было создать из списка с известной длиной, то длина неизвестна. Можно как-то определиться?
Оба нужно. Я хочу заучить один collect<> или ranges::to<> и не думать когда там в коде у меня известна длина а когда неизвестна. Хочу сделать какой то трансформатор из ренж в ренж, который будет сохранять эту информацию. В вашем же примере мне надо писать каждый раз теперь
EIther (Int -> a) (Int, Int -> a)
матчить его при каждом использовании, а потом заворачивать обратно в Either. В итоге весь код превращается в такой бойлерплейт, с потенциальными проблемами при оптимизации.
STM в вашем мире не существует?
Выглядит как просто примитивы завёрнутые в мутекс, но не как инструмент для определения самих примитив и ограничений на их многопоточное использование. Поправте если он позволяет добится Send/Sync из раста.
Так мы хаскель-код компилятором хаскеля компилируем, если что, а не плюсов.
Во-первых есть ллвм бэкенд. Во-вторых уб легко получить если завязать какую то дополнительную логику на использование этой переменной
case (readIOref x < n)
true => getUnchecked v $ readIOref x
false => _
(пвсевдо код)
Апд.: подправил, случайно раньше времени отправилось
Отлично. А в одной крупной компании, где я работал, ровно поэтому было рекомендовано не использовать unsigned-типы (и они были забанены в основных библиотеках) — потому что при оставлении >= там легко получить бесконечный цикл.
отвратительно. Как раз unsigned выражает в типах что число неотрицательное и не содержит уб на переполнение, всё как вы любите. А на >= выдаст варн "expression is always true".
А как такое работает? ptr это что? Обычно массив это внтуренний примитив и ссылку на место где лежит элемент взять так просто нельзя. Или язык должен предоставлять специальный примитив для этого, который поидее и будет содержать ссылку на сам массив. Иначе как гц узнает связь между (ptr+i) и аллокацией c началом ptr?
Получается Vector это вью для последовательной аллокации? Тогда его всё равно нельзя использовать как параметр для ренжа с O(1) доступом, потому что за iota нету никакой аллокации. Зачем вы мне его предлагали?
Не вижу как сюда передать объект типа
Range, или какой вы там создали?В тот момент когда надо писать такие явные преобразования код перестаёт быть женерик.
По наличию перегрузки
size()Т.е. у меня контейнер создаётся и умирает вместе с runST? Или создаётся мутабельный вью?
Я хочу взять например вектор, мутировать его в одном потоке, потом мувнуть его в другой поток и продолжить мутировать там.
А как мне писать код который одновременно и читает что то из тред-сейф объекта расшареного и на основе этого модифицирует тред-локальный стейт?
а как это тогда работает? Я представлял себе класс слайса как набор из (otherVector, begin, end) и оператор[i] который возвращает otherVector[begin+i]. Сам otherVector держится/очищается через GC, а не вручную.
Ну я же просил в самом начале, целостный пример который все задачи обобщенно решает, а не какие-то отрывки.
фух, в новом виде наконец хаскель можно прочитать. спасибо
Что бы трансформ сделать
и сохранить operator[] после трансформа.
Первая часть это же просто определение двух конструкторов структур которые ничего не делают. В С++ такое писать особо не надо. Что делает deriving Functor мне не понятно.
А хотя я немного подумал и понял, что скорее всего теперь это класс можно через fmap оттрансформировать но нельзя запихнуть в метод который ожидает
[a]. Так что вопрос про transform отменяется.Т.е. у нас контекст runSTM который берёт лок на все STM контейнеры? Всё еще не понял почему я не могу ST контейнер передать между потоками, как вообще что то в поток передать? Если через IORef будет уб то как без уб? Как с этим разобраться новичку.
Так если load() один то всё хорошо, я специально явно два раза его запросил в примере. В сложных примерах вы такую проблему не заметите сразу. Как раз дублировать лоад это будет баг компилятора.
Оптимизаций которые они делают достаточно чтобы синхронизировать память через атомики и ставить мемори барьеры было обязательным.
А аргументация будет?
Не надо, это закрытое множество вариантов.
Вообще интуитивно у меня будет отдельно контроллер списка, и отдельно несколько способов его вызывать. Скорее всего из разных диалогов. Например, какой-то общий диалог поиска писем и спец кнопка перейти к следующиму непрочитаному во фрейме отображения письма. И тут иметь готовый findNext(pred), который я могу переиспользовать лучше чем findAndSelect.
Во-перых это не имеет никакого отношения к С++. Во-вторых что тут это даёт?
как по мне для того чтобы объединить две строчки (find_if + select) в новый метод этого не достаточно.
Читать одинаково нормально. Использовать getPrev() как одну сущность проще чем писать get, а потом думать какой итератор надо туда вставить. Решение с ренжем в качестве аргумента даёт большую гибкость тому кто будет использовать код, с другой стороны накладывает больше мыслительной работы. Абстрагировать надо в точках где ожидается вариативность. Если там prev/next/left/right/up/down/diagonal/whatever то это другое дело.
Читайте еще раз. Вы привели одну фразу про ГЦ, и пол фразы про другие языки. Одна цитата как раз про контроль качества зависимостей.
Даже если бы в ветке было бы в основном про гц, в чем проблема ответить на ту часть сообщение которую я считаю нужным прокоментировать?
Не знаю о чём вы, у меня такого нету.
Давайте начнём с того как вендор создаст dll на раст и что вы будете делать с ней?
Пробелмы поставки библиотек в бинарном формате это отдельная проблема. То что в расте это сделать нельзя говорит лишь об ограниченности раста и что он неприменим для вендоров блобов. Хотя скорее всего можно за сишным интерфейсом спрятать реализацию на расте, тогда возвращаемся к той же проблеме.
Люблю комментарии на Хабре за их точность )))
Лучше вы сами внимательно перечитайте. В ветке было про сборку раст и с++.
В чем проблема в С++ делать компиляцию всего дерева из исходников со статической линковкой и нужными флагами санитайзера?
А как в ней "грепнуть по unsafe" ?
т.е. это таки некий тайпкласс у которого может быть несколько реализаций? Ссылка на другой вектор или ссылка на какую-то свою аллокацию?
У меня вопрос не про владение, можно как одну из реализаций сделать слайс который в отличие от std::span делает рефкаунт (например растовый
hyper::Bytes).В цпп сделано, в раст сделано, а хаскель не смог поэтому ненужно. Понятно..
И то и то. Что мне запрещает расшарить ST вектор между потоками вместо STM? Как я для своего контейнера могу определить можно его шарить или нет?
Значение поменяется из другого потока и в
getUncheckedбудет уже не тот индекс который прошёл проверку строчкой выше,nэто например длина контейнера.Да это тот самый ллвм который вы использовали чтобы хоть как то сравнятся по скорости с цпп в своих экспериментах. И тот самый который растеры взяли потому что сами сделать свой не смогли.
Распарсить что делает
ofи;я не смог, но идею понял. Хотя вместо Functor нужно иметь тайпкласс который умеет как раз в метод который даётInt -> a. Т.е. вот это вот всё надо спроектировать и т п. Не рокет сайнс конечно, но и выдавать однострочники за какие то решения это слишком.Но опять же вот этот Bounded/Unbounded флаг это рантайм флаг. Афаик в расте тоже было раньше
fn size_hint(), а потом решили еще добавить специализацию https://doc.rust-lang.org/std/iter/trait.ExactSizeIterator.html.Кстати тут сразу возникает вопрос с ансейф, можно ли доверять хинту len() для создания аллокаций? В хаскель вопрос будет аналогичный.
По порядку величин то же самое. Я прочел ваше сообщение и подумал что вы противопоставляете полдюжины аспирантов с сотней разработчиков на зарпалтах у апл и гугла...
Имхо в таком примере это преждевременное создание абстракций, получается усложнение. getNext/getPrev выглядит проще и понятнее. К тому же это ближе к реальному функционалу юай - там есть кнопки prev/next и у вас в программе будут такие методы, a не какой-то findAndSelect(forward).
Лучше с такими не работать
Я же объяснил, потому что eigen не выразим на расте.
Такой задачи нету. For/while строго мощнее любого другого специального сахарка. А если хотите свое, то с++ это легко позваляет сделать, хоть
for(auto i : iota(a,b)), хотьboost::irangeхоть что угодно с какими захотите проверками и азертами.И где тут решили шаг больше 1?
Больше троих на что? Там у аппл есть и swift и obj-c и куча задач по интерации платформы и своего железа. Но допустим даже трое от аппла на шланг фронтенд, еще трое от гугла. Майкрософт не берём у них свой. Итого шесть. Мне сообщили что в кланг фултайм мейнтейнеров около пяти. Выходит что вложения весьма скромные.
То как было использована иота в изначальном примере - это явно усложнение потому что там рэнж создавался отдельно от логики его использования. Это дополнительная абстракция. Если не нравятся операторы сравнения напишите
for (auto i : iota(0, n))По поводу свёртки мапов, если компилятор может ходить в тело функций и анализировать/оптимизировать цепочку трансформаций, то это хорошо.
По поводу Vector всё же я не очень понял. Что значит создать из чего угодно за О(1)? Если это был слайс другого вектора, то что будет? Или допустим вообще из MVector? Трюкам с ленивостью и иммутабельностью я не доверяю после примера с qsort.
Оба нужно. Я хочу заучить один
collect<>илиranges::to<>и не думать когда там в коде у меня известна длина а когда неизвестна. Хочу сделать какой то трансформатор из ренж в ренж, который будет сохранять эту информацию. В вашем же примере мне надо писать каждый раз теперьматчить его при каждом использовании, а потом заворачивать обратно в Either. В итоге весь код превращается в такой бойлерплейт, с потенциальными проблемами при оптимизации.
Выглядит как просто примитивы завёрнутые в мутекс, но не как инструмент для определения самих примитив и ограничений на их многопоточное использование. Поправте если он позволяет добится Send/Sync из раста.
Во-первых есть ллвм бэкенд. Во-вторых уб легко получить если завязать какую то дополнительную логику на использование этой переменной
(пвсевдо код)
Апд.: подправил, случайно раньше времени отправилось
отвратительно. Как раз unsigned выражает в типах что число неотрицательное и не содержит уб на переполнение, всё как вы любите. А на
>=выдаст варн "expression is always true".Имхо такой вариант самый простой