Я думаю, имеется ввиду выкинуть iostreams на мороз именно в текущем виде. Просто ради примера, в Rust абстракции байтовых потоков ввода-вывода требуют реализации по одной функции на чтение и запись, соответственно. Это в самой базовой форме. В С++ тщательно ковыряться с буфером потока и, возможно, самим классом потока.
Тогда могли бы через string_view. И возвращать тоже часть string_view. Увы, много рассказывают про "безопасные практики" — при этом периодически добавляя способов отстрелить себе ногу.
Многомегабайтные заголовки сами по себе не такая большая беда. Компиляторы довольно давно научились это дело кешировать. Две гораздо большие проблемы — война макросов и свалка определений.
Война макросов, как можно догадаться — конфликт и наложение эффектов от макросов, определённых в разных заголовках.
Свалка определений — тащим одну маленькую шаблонную функцию, а получаем в область видимости пол-буста вместе с MPL. К тому же, приводит к необходимости тащить вместе с библиотекой заголовки всех её зависимостей (и правильно их раскладывать по местам), которые отметились в заголовках самой библиотеки. И транзитивные в том числе.
На вход итераторы, а на выход — поинтер… Слов нет, одни выражения. А, ну и голый эррор код. С++ так и не смог нормальную единую обработку ошибок, сплошные костыли.
Рейсер сам по себе уже давно не разрабатывается.
Для VSCode — RLS и соответственно поставить RLS как компонент. Единственная проблема — пока что для этого надо ставить найтли тулчейн. Сижу и пишу частично под виндовс, проблем в целом не имею.
Уважаемый antoshkka, у вас случайно нет "человекочитаемого" описания текущего состояния по модулям — на каком уровне они существуют (грубо — единица трансляции или линковки), как предполагается существующий код с инклюдами приводить к модульному виду и т.п. Судя по https://habrahabr.ru/company/yandex/blog/336264/#comment_10449246, понимания, как оно должно быть, нет как минимум у меня.
Проблема ЕМНИП в том, что как только вы измеряете состояние одной частицы из пары, и получаете какой-то параметр для обоих, запутанность "сыпется", и у вас на руках 2 отдельных частицы. Поэтому данное явление на данный момент считается неприменимым для передачи информации быстрее скорости света. Более знающие да поправят.
Следствием второго принципа (и общенаучного принципа причинности) является невозможность движения физических тел и передачи информации со скоростью, превышающей скорость света в вакууме.
Так что квантовая запутанность "передаётся" мгновенно — но передать этим способом информацию нельзя.
Тогда я не понимаю, какой уровень призваны организовать модули. Если уровень юнитов трансляции — то где, действительно, возможность организовать приватные детали реализации, и зачем такие с мультифайловостью и отдельным именованием? Если же уровень единиц сборки — зачем отдельно декларировать везде имя модуля, и что будет, если несколько модулей лягут в один бинарь?
Да, придётся добавить к таким функциям export. Зато будет понятно, где что лежит. При описанном вами сценарии с модулем в 10К строчек, делённым на несколько файлов, придётся ещё выяснять где лежит каждый кусок — т.к. логическое имя модуля вообще никак не связано с его местоположением в исходниках.
Пример с обработкой ошибок просто самый наглядный. Во второй половине комментария описан чуть более сложный случай. Добавьте туда пункт 2.5:
Функции, возвращающие инстансы конкретных типов, используются в других местах модуля для получения этих инстансов, но без необходимости приводить указатели к единому интерфейсу.
Проблема именно в том, что в сколь-нибудь нетривиальном коде вполне можно получить "битый интерфейс" на ровном месте.
// Note: both FirstError and SecondError implement 'error' interface
// and use some data from value when their respective Error() is called
// May return non-nil error, if code fails
func first(arg MyData) *FirstError { /* some code here */ }
// May also return non-nil error, if code fails
func second(arg MyData) *SecondError { /* some other code here */ }
func third(arg MyHugeData) error {
if err := first(arg.DataField); err != nil {
return err
}
return second(arg.DataField)
}
func fourth(arg MyHugeData) {
if err := third(arg); err != nil {
fmt.Println(err.Error())
}
}
Такой код КМК вполне может случиться — "просто верни статус последней операции дальше по стеку". Во-первых, результат всегда будет трактоваться как неуспех. Во-вторых, при попытке узнать причину мы получим nil-pointer panic из по сути ниоткуда. Пример с обработкой ошибок КМК просто будет самый типичный. Я в своё время нарвался на такое поведение в другом контексте, подробностей уже не помню.
Но суть была именно такой:
Есть несколько типов, приводимых к одному интерфейсу.
Каждый из типов требует не-нулевой инстанс чтобы корректно реализовывать указанный интерфейс
В некоем коде, допустим при передаче через канал, указатель на объект какого-либо из конкретных типов приводится к интерфейсу. При этом для канала nil pointer является абсолютно корректным положением вещей и обрабатывается на принимающей стороне как положено.
На принимающей стороне не-нулевой указатель на интерфейс неожиданно оказывается очень даже нулевым, т.к. сам по себе vtable бесполезен. Результат — NPE где не ждали.
Мне в общем-то тоже понятно, почему так происходит. Мне даже понятно, для чего используется эта фича. Что мне, к сожалению, осталось непонятно — почему это разрешено в виде неявного преобразования. Как по мне, сильно повышает шансы наступить на грабли. Было бы в виде явного тайп каста, так что неявный приводит к fully nil interface pointer — вопросов бы не было. Впрочем, как реализовали так реализовали. Может в v2 поменяют. Или давно есть линт, о котором я не знаю.
Подскажите пожалуйста одну вещь. В своё время я задавал вопрос, почему существует такая вещь как not-so-nil interface pointers — ситуация, когда nil-указатель на переменную конкретного типа неявно приводится к указателю на интерфейс, который этот тип реализует. И, как результат, у нас получается fat pointer с nil data pointer и валидным vtable pointer. Следствие — nil pointer dereference в рантайме, где его не ждали. Но вопрос не в этом. Вопрос в том, что ответ тогда был "потому что в Go указатели, а не ссылки". Как раз этот ответ я и не понял.
Вместо того, чтобы сделать простой и понятный импорт по относительным путям
// <root>/src/Module1.cpp
import "Dir1/Module2"; // See below
// some code goes here
// ...
// <root>/src/Dir1/Module2.cpp
import "std/vector";
// some code with exports goes here
Это КМК решило бы сразу несколько проблем — не нужно явно указывать имя модуля, пути импорта понятны из кода, плюс естественная возможность приватных модулей. Если вы скажете "а как же многофайловые модули?" — а зачем они вообще нужны? Откровенно выглядит как костыль. Генерацию интерфейсной части из общего текста модуля можно как раз оставить на совести компилятора.
Глобальный модуль
В черновике упомянут некий "глобальный модуль", в который входит весь код до декларации module. Этот двойной пассаж мне честно говоря не понятен. Единственное подозрение — необходимость куда-то деть содержимое файла до декларации модуля.
Я думаю, имеется ввиду выкинуть
iostreamsна мороз именно в текущем виде. Просто ради примера, в Rust абстракции байтовых потоков ввода-вывода требуют реализации по одной функции на чтение и запись, соответственно. Это в самой базовой форме. В С++ тщательно ковыряться с буфером потока и, возможно, самим классом потока.Тогда могли бы через
string_view. И возвращать тоже частьstring_view. Увы, много рассказывают про "безопасные практики" — при этом периодически добавляя способов отстрелить себе ногу.Многомегабайтные заголовки сами по себе не такая большая беда. Компиляторы довольно давно научились это дело кешировать. Две гораздо большие проблемы — война макросов и свалка определений.
Война макросов, как можно догадаться — конфликт и наложение эффектов от макросов, определённых в разных заголовках.
Свалка определений — тащим одну маленькую шаблонную функцию, а получаем в область видимости пол-буста вместе с MPL. К тому же, приводит к необходимости тащить вместе с библиотекой заголовки всех её зависимостей (и правильно их раскладывать по местам), которые отметились в заголовках самой библиотеки. И транзитивные в том числе.
Меня больше бомбануло от
На вход итераторы, а на выход — поинтер… Слов нет, одни выражения. А, ну и голый эррор код. С++ так и не смог нормальную единую обработку ошибок, сплошные костыли.
Рейсер сам по себе уже давно не разрабатывается.
Для VSCode — RLS и соответственно поставить RLS как компонент. Единственная проблема — пока что для этого надо ставить найтли тулчейн. Сижу и пишу частично под виндовс, проблем в целом не имею.
Любопытно, спасибо. Вопрос в том, как сделать такое "слабое квантовое измерение". Посмотрим.
Если совсем коротко — линкуетесь с Qt динамически (фреймворк в отдельных DLL/SO) и творите что хотите. В своём коде конечно.
Уважаемый antoshkka, у вас случайно нет "человекочитаемого" описания текущего состояния по модулям — на каком уровне они существуют (грубо — единица трансляции или линковки), как предполагается существующий код с инклюдами приводить к модульному виду и т.п. Судя по https://habrahabr.ru/company/yandex/blog/336264/#comment_10449246, понимания, как оно должно быть, нет как минимум у меня.
Подозреваю, что этот и предыдущий комментарий — ответы на https://habrahabr.ru/company/technoserv/blog/339156/#comment_10449494
Проблема ЕМНИП в том, что как только вы измеряете состояние одной частицы из пары, и получаете какой-то параметр для обоих, запутанность "сыпется", и у вас на руках 2 отдельных частицы. Поэтому данное явление на данный момент считается неприменимым для передачи информации быстрее скорости света. Более знающие да поправят.
Скорость света — предельная скорость передачи любого взаимодействия, не только движения.
https://ru.wikipedia.org/wiki/%D0%A2%D0%B5%D0%BE%D1%80%D0%B8%D1%8F_%D0%BE%D1%82%D0%BD%D0%BE%D1%81%D0%B8%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE%D1%81%D1%82%D0%B8#.D0.A1.D0.BF.D0.B5.D1.86.D0.B8.D0.B0.D0.BB.D1.8C.D0.BD.D0.B0.D1.8F_.D1.82.D0.B5.D0.BE.D1.80.D0.B8.D1.8F_.D0.BE.D1.82.D0.BD.D0.BE.D1.81.D0.B8.D1.82.D0.B5.D0.BB.D1.8C.D0.BD.D0.BE.D1.81.D1.82.D0.B8
Предпоследний абзац
Так что квантовая запутанность "передаётся" мгновенно — но передать этим способом информацию нельзя.
Тогда я не понимаю, какой уровень призваны организовать модули. Если уровень юнитов трансляции — то где, действительно, возможность организовать приватные детали реализации, и зачем такие с мультифайловостью и отдельным именованием? Если же уровень единиц сборки — зачем отдельно декларировать везде имя модуля, и что будет, если несколько модулей лягут в один бинарь?
Да, придётся добавить к таким функциям export. Зато будет понятно, где что лежит. При описанном вами сценарии с модулем в 10К строчек, делённым на несколько файлов, придётся ещё выяснять где лежит каждый кусок — т.к. логическое имя модуля вообще никак не связано с его местоположением в исходниках.
Пример с обработкой ошибок просто самый наглядный. Во второй половине комментария описан чуть более сложный случай. Добавьте туда пункт 2.5:
Функции, возвращающие инстансы конкретных типов, используются в других местах модуля для получения этих инстансов, но без необходимости приводить указатели к единому интерфейсу.
Проблема именно в том, что в сколь-нибудь нетривиальном коде вполне можно получить "битый интерфейс" на ровном месте.
Эмм, просто поделить на несколько вложенных модулей? С указанным подходом это будет тривиально.
Вырожденный пример будет какой-то такой
Такой код КМК вполне может случиться — "просто верни статус последней операции дальше по стеку". Во-первых, результат всегда будет трактоваться как неуспех. Во-вторых, при попытке узнать причину мы получим nil-pointer panic из по сути ниоткуда. Пример с обработкой ошибок КМК просто будет самый типичный. Я в своё время нарвался на такое поведение в другом контексте, подробностей уже не помню.
Но суть была именно такой:
Мне в общем-то тоже понятно, почему так происходит. Мне даже понятно, для чего используется эта фича. Что мне, к сожалению, осталось непонятно — почему это разрешено в виде неявного преобразования. Как по мне, сильно повышает шансы наступить на грабли. Было бы в виде явного тайп каста, так что неявный приводит к fully nil interface pointer — вопросов бы не было. Впрочем, как реализовали так реализовали. Может в v2 поменяют. Или давно есть линт, о котором я не знаю.
Подскажите пожалуйста одну вещь. В своё время я задавал вопрос, почему существует такая вещь как
not-so-nil interface pointers— ситуация, когда nil-указатель на переменную конкретного типа неявно приводится к указателю на интерфейс, который этот тип реализует. И, как результат, у нас получается fat pointer с nil data pointer и валидным vtable pointer. Следствие — nil pointer dereference в рантайме, где его не ждали. Но вопрос не в этом. Вопрос в том, что ответ тогда был "потому что в Go указатели, а не ссылки". Как раз этот ответ я и не понял.Подскажите пожалуйста кто в курсе по поводу двух особенностей модулей:
Своя нотация именования
Вместо того, чтобы сделать простой и понятный импорт по относительным путям
Это КМК решило бы сразу несколько проблем — не нужно явно указывать имя модуля, пути импорта понятны из кода, плюс естественная возможность приватных модулей. Если вы скажете "а как же многофайловые модули?" — а зачем они вообще нужны? Откровенно выглядит как костыль. Генерацию интерфейсной части из общего текста модуля можно как раз оставить на совести компилятора.
Глобальный модуль
В черновике упомянут некий "глобальный модуль", в который входит весь код до декларации
module. Этот двойной пассаж мне честно говоря не понятен. Единственное подозрение — необходимость куда-то деть содержимое файла до декларации модуля.Я попытался спросить в общей гугл группе https://groups.google.com/a/isocpp.org/forum/?fromgroups#!topic/std-proposals/SdgWgJCR35s, но мне к сожалению так никто и не ответил.